Merge "Move to Harfbuzz 1.7.4"
diff --git a/.ci/deploy-docs.sh b/.ci/deploy-docs.sh
index e4dbad4..a8a8523 100755
--- a/.ci/deploy-docs.sh
+++ b/.ci/deploy-docs.sh
@@ -3,6 +3,8 @@
 set -x
 set -o errexit -o nounset
 
+if test "x$TRAVIS_SECURE_ENV_VARS" != xtrue; then exit; fi
+
 BRANCH="$TRAVIS_BRANCH"
 if test "x$BRANCH" != xmaster; then exit; fi
 
@@ -16,18 +18,19 @@
 cd $DOCSDIR
 
 cp ../docs/html/* .
+#cp ../docs/CNAME .
 
 git init
 git config user.name "Travis CI"
 git config user.email "travis@harfbuzz.org"
 set +x
-echo "git remote add upstream \"https://\$GH_TOKEN@github.com/$TRAVIS_REPO_SLUG.git\""
-git remote add upstream "https://$GH_TOKEN@github.com/$TRAVIS_REPO_SLUG.git"
+echo "git remote add upstream \"https://\$GH_TOKEN@github.com/harfbuzz/harfbuzz.github.io.git\""
+git remote add upstream "https://$GH_TOKEN@github.com/harfbuzz/harfbuzz.github.io.git"
 set -x
 git fetch upstream
-git reset upstream/gh-pages
+git reset upstream/master
 
 touch .
 git add -A .
-git commit -m "Rebuild docs for $REVISION"
-git push -q upstream HEAD:gh-pages
+git commit -m "Rebuild docs for https://github.com/harfbuzz/harfbuzz/commit/$REVISION"
+git push -q upstream HEAD:master
diff --git a/.ci/run-coveralls.sh b/.ci/run-coveralls.sh
new file mode 100755
index 0000000..58b8311
--- /dev/null
+++ b/.ci/run-coveralls.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -x
+set -o errexit -o nounset
+
+if test "x$TRAVIS_SLUG" != x"harfbuzz/harfbuzz"; then exit; fi
+
+pip install --user nose
+pip install --user cpp-coveralls
+export PATH=$HOME/.local/bin:$PATH
+
+rm -f src/.libs/NONE.gcov
+touch src/NONE
+coveralls -e docs
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..2824bfd
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,125 @@
+version: 2
+
+jobs:
+
+  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 || 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_ICU=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
+      - run: make -Cbuild
+      - run: make -Cbuild test
+      - run: make -Cbuild install
+
+  fedora:
+    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 || true
+      - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 && make && make check
+
+  archlinux:
+    docker:
+      - image: base/devel
+    steps:
+      - checkout
+      - run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel
+      - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 && make && make check
+
+  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 && make
+
+  base:
+    docker:
+      - image: dockcross/base
+    steps:
+      - checkout
+      - run: apt update && apt install -y pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
+      - run: cmake -DHB_HAVE_FREETYPE=ON -DHB_HAVE_GRAPHITE2=ON -DHB_BUILTIN_UCDN=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_ICU=ON -DHB_BUILD_UTILS=ON -Bbuild -H. -GNinja
+      - run: ninja -Cbuild
+      - run: ninja -Cbuild test
+      - run: ninja -Cbuild install
+
+  distdir:
+    docker:
+      - image: dockcross/base
+    steps:
+      - checkout
+      - run: apt update && apt install -y pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
+      - run: ./autogen.sh && make distdir
+      - run: cd harfbuzz-* && ./configure && make && make check && make install
+
+  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: cmake -Bbuild -H. -GNinja -DCMAKE_TOOLCHAIN_FILE=/usr/local/vitasdk/share/vita.toolchain.cmake && ninja -Cbuild
+
+  android-arm:
+    docker:
+      - image: dockcross/android-arm
+    steps:
+      - checkout
+      - run: apt update && apt install ragel
+      - run: cmake -Bbuild -H. -GNinja && ninja -Cbuild
+
+  browser-asmjs:
+    docker:
+      - image: dockcross/browser-asmjs
+    steps:
+      - checkout
+      - run: apt update && apt install ragel
+      - run: cmake -Bbuild -H. -GNinja && ninja -Cbuild
+
+  linux-arm64:
+    docker:
+      - image: dockcross/linux-arm64
+    steps:
+      - checkout
+      - run: apt update && apt install ragel
+      - run: cmake -Bbuild -H. -GNinja && ninja -Cbuild
+
+  linux-mips:
+    docker:
+      - image: dockcross/linux-mips
+    steps:
+      - checkout
+      - run: apt update && apt install ragel
+      - run: cmake -Bbuild -H. -GNinja && ninja -Cbuild
+
+  windows-x64:
+    docker:
+      - image: dockcross/windows-x64
+    steps:
+      - checkout
+      - run: apt update && apt install ragel
+      - run: cmake -Bbuild -H. -GNinja && ninja -Cbuild
+
+workflows:
+  version: 2
+  build:
+    jobs:
+      - oracledeveloperstudio
+      - fedora
+      - archlinux
+      - freebsd9
+      - base
+      - distdir
+      - psvita
+      - android-arm
+      - browser-asmjs
+      - linux-arm64
+      - linux-mips
+      - windows-x64
diff --git a/.travis.yml b/.travis.yml
index 1b15058..5b5ae0e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,38 +1,54 @@
 # Build Configuration for Travis
-sudo: required # For Trusty beta
-os:
-  - linux
-  - osx
 dist: trusty
+
 language: cpp
-compiler:
-  - clang
-  - gcc
+
 env:
   global:
     - CPPFLAGS=""
     - CFLAGS="-Werror --coverage"
     - CXXFLAGS="-Werror -Wno-deprecated-register --coverage" # glib uses register and clang raises a warning
     - LDFLAGS="--coverage"
-install:
-  - if [ "$TRAVIS_OS_NAME" == "linux" ]; then pip install --user nose; fi
-  - if [ "$TRAVIS_OS_NAME" == "linux" ]; then pip install --user cpp-coveralls; fi # for coveralls.io code coverage tracking
-  - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export PATH=$HOME/.local/bin:$PATH; fi # Make sure we can find the above Python packages
-  - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; fi;
-  - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew uninstall libtool && brew install libtool; fi # Workaround Travis/brew bug
-  - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install ragel freetype glib gobject-introspection cairo icu4c graphite2; fi
-  - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew link --force icu4c; fi # icu4c is keg-only
-script:
-  - NOCONFIGURE=1 ./autogen.sh
-  - export CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
-  - if [ "$TRAVIS_OS_NAME" == "linux" -a "$CC" == "gcc" ]; then export CONFIGURE_OPTS="$CONFIGURE_OPTS  --enable-gtk-doc"; fi
-  - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export CONFIGURE_OPTS="$CONFIGURE_OPTS --with-coretext"; fi
-  - ./configure $CONFIGURE_OPTS
-  - make
-  - make check
-  - if [ "$TRAVIS_OS_NAME" == "linux" -a "$CC" == "gcc" -a "$TRAVIS_SLUG" == "behdad/harfbuzz" ]; then rm -f src/.libs/NONE.gcov; touch src/NONE; coveralls -e docs; fi
-after_success:
-  - if [ "$TRAVIS_OS_NAME" == "linux" -a "$CC" == "gcc" -a "$TRAVIS_SECURE_ENV_VARS" == "true" ]; then bash .ci/deploy-docs.sh; fi
+    - CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
+    - NOCONFIGURE=1
+
+matrix:
+  include:
+    - os: linux
+      compiler: gcc
+      script:
+        - ./autogen.sh
+        - ./configure $CONFIGURE_OPTS --enable-gtk-doc
+        - make
+        - make check || (cat */test-suite.log test/*/test-suite.log && false)
+      after_success:
+        - bash .ci/run-coveralls.sh # for coveralls.io code coverage tracking
+        - bash .ci/deploy-docs.sh
+
+    - os: linux
+      compiler: clang
+      script:
+        - ./autogen.sh
+        - ./configure $CONFIGURE_OPTS
+        - make
+        - make check || (cat */test-suite.log test/*/test-suite.log && false)
+
+    - os: osx
+      compiler: clang
+      install:
+          # https://github.com/harfbuzz/harfbuzz/issues/345
+        - export CXXFLAGS="$CXXFLAGS -Wno-deprecated-declarations"
+        - brew update;
+          # Workaround Travis/brew bug
+        - brew uninstall libtool && brew install libtool
+        - brew install ragel freetype glib gobject-introspection cairo icu4c graphite2
+        - brew link --force icu4c # icu4c is keg-only
+      script:
+        - ./autogen.sh
+        - ./configure $CONFIGURE_OPTS --with-coretext
+        - make
+        - make check || (cat */test-suite.log test/*/test-suite.log && false)
+
 notifications:
   irc: "irc.freenode.org#harfbuzz"
   email: harfbuzz@lists.freedesktop.org
diff --git a/BUILD.md b/BUILD.md
index 7518c2e..9e5a55b 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -5,7 +5,13 @@
 whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
 * sudo yum install gcc gcc-c++ freetype-devel glib2-devel cairo-devel
 
-on the Mac, using MacPorts:
+on Windows, consider using [vcpkg](https://github.com/Microsoft/vcpkg),
+provided by Microsoft, for building HarfBuzz and other open-source libraries
+but if you need to build harfbuzz from source, put ragel binary on your
+PATH and follow appveyor CI's cmake
+[build steps](https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml).
+
+on macOS, using MacPorts:
 * sudo port install freetype glib2 cairo
 
 or using Homebrew:
@@ -14,9 +20,7 @@
 If you are using a tarball, you can now proceed to running configure and make
 as with any other standard package. That should leave you with a shared
 library in src/, and a few utility programs including hb-view and hb-shape
-under util/.  From the tarball, NMake Makefiles are also provided in win32/,
-which supports building HarfBuzz using Visual Studio, with a README.txt that
-gives instructions on building using NMake.
+under util/.
 If you are bootstraping from git, you need a few more tools before you can
 run autogen.sh for the first time. Namely, pkg-config and ragel. Again,
 on Ubuntu / Debian:
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..24ccb6f
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,690 @@
+cmake_minimum_required(VERSION 2.8.0)
+project(harfbuzz)
+
+enable_testing()
+
+## Limit framework build to Xcode generator
+if (BUILD_FRAMEWORK)
+  # for a framework on macOS, use `cmake .. -DBUILD_FRAMEWORK:BOOL=true -G Xcode`
+  if (NOT "${CMAKE_GENERATOR}" STREQUAL "Xcode")
+    message(FATAL_ERROR
+      "You should use Xcode generator with BUILD_FRAMEWORK enabled")
+  endif ()
+  set(CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD_32_64_BIT)")
+  set(CMAKE_MACOSX_RPATH ON)
+  set(BUILD_SHARED_LIBS ON)
+endif ()
+
+
+## Disallow in-source builds, as CMake generated make files can collide with autotools ones
+if (NOT MSVC AND "${PROJECT_BINARY_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}")
+  message(FATAL_ERROR
+    "
+In-source builds are not permitted!  Make a separate folder for"
+    " building, e.g.,"
+    "
+  mkdir build; cd build; cmake .."
+    "
+Before that, remove the files created by this failed run with"
+    "
+  rm -rf CMakeCache.txt CMakeFiles")
+endif ()
+
+
+## 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)
+  option(HB_HAVE_CORETEXT "Enable CoreText shaper backend on macOS" ON)
+endif ()
+if (WIN32)
+  option(HB_HAVE_UNISCRIBE "Enable Uniscribe shaper backend 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)
+if (HB_BUILD_UTILS)
+  set(HB_HAVE_GLIB ON)
+  set(HB_HAVE_FREETYPE ON)
+endif ()
+
+option(HB_HAVE_GOBJECT "Enable GObject Bindings" OFF)
+if (HB_HAVE_GOBJECT)
+  set(HB_HAVE_GLIB ON)
+endif ()
+
+option(HB_HAVE_INTROSPECTION "Enable building introspection (.gir/.typelib) files" OFF)
+if (HB_HAVE_INTROSPECTION)
+  set(HB_HAVE_GOBJECT ON)
+  set(HB_HAVE_GLIB ON)
+endif ()
+
+include_directories(AFTER
+  ${PROJECT_SOURCE_DIR}/src
+  ${PROJECT_BINARY_DIR}/src
+  )
+
+add_definitions(-DHAVE_OT)
+add_definitions(-DHAVE_FALLBACK)
+
+if (BUILD_SHARED_LIBS)
+  add_definitions(-DHAVE_ATEXIT)
+endif ()
+
+if (MSVC)
+  add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS)
+endif ()
+
+if (WIN32 AND NOT MINGW AND BUILD_SHARED_LIBS)
+  add_definitions("-DHB_EXTERN=__declspec(dllexport) extern")
+endif ()
+
+
+## Detect if we are running inside a distribution or regular repository folder
+set(IN_HB_DIST FALSE)
+if (EXISTS "${PROJECT_SOURCE_DIR}/ChangeLog")
+  # perhaps we are on dist directory
+  set(IN_HB_DIST TRUE)
+  set(HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h")
+endif ()
+
+
+## Extract variables from Makefile files
+# http://stackoverflow.com/a/27630120/1414809
+function (prepend var prefix)
+  set(listVar "")
+  foreach (f ${ARGN})
+    list(APPEND listVar "${prefix}${f}")
+  endforeach ()
+  set(${var} "${listVar}" PARENT_SCOPE)
+endfunction ()
+
+function (extract_make_variable variable file prefix)
+  string(REGEX MATCH "${variable} = ([^$]+)\\$" temp ${file})
+  string(REGEX MATCHALL "[^ \n\t\\]+" list ${CMAKE_MATCH_1})
+  prepend(list ${prefix} ${list})
+  set(${variable} ${list} PARENT_SCOPE)
+endfunction ()
+
+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} "${PROJECT_SOURCE_DIR}/src/")
+extract_make_variable(HB_BASE_headers ${SRCSOURCES} "${PROJECT_SOURCE_DIR}/src/")
+extract_make_variable(HB_FALLBACK_sources ${SRCSOURCES} "${PROJECT_SOURCE_DIR}/src/")
+extract_make_variable(HB_OT_sources ${SRCSOURCES} "${PROJECT_SOURCE_DIR}/src/")
+extract_make_variable(HB_OT_headers ${SRCSOURCES} "${PROJECT_SOURCE_DIR}/src/")
+
+if (IN_HB_DIST)
+  set(RAGEL_GENERATED_DIR "${PROJECT_SOURCE_DIR}/src/")
+else ()
+  set(RAGEL_GENERATED_DIR "${PROJECT_BINARY_DIR}/src/")
+endif ()
+extract_make_variable(HB_BASE_RAGEL_GENERATED_sources ${SRCSOURCES} ${RAGEL_GENERATED_DIR})
+extract_make_variable(HB_OT_RAGEL_GENERATED_sources ${SRCSOURCES} ${RAGEL_GENERATED_DIR})
+
+extract_make_variable(HB_VIEW_sources ${UTILSOURCES} "${PROJECT_SOURCE_DIR}/util/")
+extract_make_variable(HB_SHAPE_sources ${UTILSOURCES} "${PROJECT_SOURCE_DIR}/util/")
+extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES} "${PROJECT_SOURCE_DIR}/util/")
+
+extract_make_variable(LIBHB_UCDN_sources ${UCDNSOURCES} "${PROJECT_SOURCE_DIR}/src/hb-ucdn/")
+
+file(READ configure.ac CONFIGUREAC)
+string(REGEX MATCH "\\[(([0-9]+)\\.([0-9]+)\\.([0-9]+))\\]" HB_VERSION_MATCH ${CONFIGUREAC})
+set(HB_VERSION ${CMAKE_MATCH_1})
+set(HB_VERSION_MAJOR ${CMAKE_MATCH_2})
+set(HB_VERSION_MINOR ${CMAKE_MATCH_3})
+set(HB_VERSION_MICRO ${CMAKE_MATCH_4})
+
+
+## Define ragel tasks
+if (NOT IN_HB_DIST)
+  find_program(RAGEL "ragel" CMAKE_FIND_ROOT_PATH_BOTH)
+
+  if (RAGEL)
+    message(STATUS "ragel found at: ${RAGEL}")
+  else ()
+    message(FATAL_ERROR "ragel not found, get it here -- http://www.complang.org/ragel/ or, use harfbuzz releases https://github.com/harfbuzz/harfbuzz/releases")
+  endif ()
+
+  foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources} ${HB_OT_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}
+  ${HB_OT_sources}
+  ${HB_OT_RAGEL_GENERATED_sources}
+  )
+
+set(project_extra_sources)
+
+set(project_headers
+  ${HB_VERSION_H}
+
+  ${HB_BASE_headers}
+  ${HB_OT_headers}
+  )
+
+
+## Find and include needed header folders and libraries
+if (HB_HAVE_FREETYPE)
+
+  include(FindFreetype)
+  if (NOT FREETYPE_FOUND)
+    message(FATAL_ERROR "HB_HAVE_FREETYPE was set, but we failed to find it. Maybe add a CMAKE_PREFIX_PATH= to your Freetype2 install prefix")
+  endif()
+
+  list(APPEND THIRD_PARTY_LIBS ${FREETYPE_LIBRARIES})
+  include_directories(AFTER ${FREETYPE_INCLUDE_DIRS})
+  add_definitions(-DHAVE_FREETYPE=1 -DHAVE_FT_FACE_GETCHARVARIANTINDEX=1)
+
+  list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ft.cc)
+  list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-ft.h)
+
+endif ()
+
+if (HB_HAVE_GRAPHITE2)
+  add_definitions(-DHAVE_GRAPHITE2)
+
+  find_path(GRAPHITE2_INCLUDE_DIR graphite2/Font.h)
+  find_library(GRAPHITE2_LIBRARY graphite2)
+
+  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})
+
+  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)
+
+  # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindGLIB.cmake
+  find_package(PkgConfig)
+  pkg_check_modules(PC_GLIB QUIET glib-2.0)
+
+  find_library(GLIB_LIBRARIES NAMES glib-2.0 HINTS ${PC_GLIB_LIBDIR} ${PC_GLIB_LIBRARY_DIRS})
+  find_path(GLIBCONFIG_INCLUDE_DIR NAMES glibconfig.h HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0/include)
+  find_path(GLIB_INCLUDE_DIR NAMES glib.h HINTS ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0)
+
+  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})
+
+  mark_as_advanced(GLIB_LIBRARIES GLIBCONFIG_INCLUDE_DIR GLIB_INCLUDE_DIR)
+endif ()
+
+if (HB_HAVE_ICU)
+  add_definitions(-DHAVE_ICU)
+
+  # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindICU.cmake
+  find_package(PkgConfig)
+  pkg_check_modules(PC_ICU QUIET icu-uc)
+
+  find_path(ICU_INCLUDE_DIR NAMES unicode/utypes.h HINTS ${PC_ICU_INCLUDE_DIRS} ${PC_ICU_INCLUDEDIR})
+  find_library(ICU_LIBRARY NAMES libicuuc cygicuuc cygicuuc32 icuuc HINTS ${PC_ICU_LIBRARY_DIRS} ${PC_ICU_LIBDIR})
+
+  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})
+
+  mark_as_advanced(ICU_INCLUDE_DIR ICU_LIBRARY)
+endif ()
+
+if (APPLE AND HB_HAVE_CORETEXT)
+  # 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)
+
+  find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
+  if (APPLICATION_SERVICES_FRAMEWORK)
+    list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
+  endif (APPLICATION_SERVICES_FRAMEWORK)
+  
+  mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
+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 ()
+
+if (HB_HAVE_GOBJECT)
+  include(FindPythonInterp)
+  include(FindPerl)
+  
+  # Use the hints from glib-2.0.pc to find glib-mkenums
+  find_package(PkgConfig)
+  pkg_check_modules(PC_GLIB QUIET glib-2.0)
+  find_program(GLIB_MKENUMS glib-mkenums
+    HINTS ${PC_glib_mkenums}
+    )
+  set(GLIB_MKENUMS_CMD)
+
+  if (WIN32 AND NOT MINGW)
+    # In Visual Studio builds, shebang lines are not supported
+    # in the standard cmd.exe shell that we use, so we need to
+    # first determine whether glib-mkenums is a Python or PERL
+    # script
+    execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${GLIB_MKENUMS}" --version
+      RESULT_VARIABLE GLIB_MKENUMS_PYTHON
+      OUTPUT_QUIET ERROR_QUIET
+      )
+    if (GLIB_MKENUMS_PYTHON EQUAL 0)
+      message("${GLIB_MKENUMS} is a Python script.")
+      set(GLIB_MKENUMS_CMD "${PYTHON_EXECUTABLE}" "${GLIB_MKENUMS}")
+    else ()
+      execute_process(COMMAND "${PERL_EXECUTABLE}" "${GLIB_MKENUMS}" --version
+        RESULT_VARIABLE GLIB_MKENUMS_PERL
+        OUTPUT_QUIET ERROR_QUIET
+        )
+      if (GLIB_MKENUMS_PERL EQUAL 0)
+        message("${GLIB_MKENUMS} is a PERL script.")
+        set(GLIB_MKENUMS_CMD "${PERL_EXECUTABLE}" "${GLIB_MKENUMS}")
+      endif ()
+      if (NOT GLIB_MKENUMS_PERL EQUAL 0 AND NOT GLIB_MKENUMS_PYTHON EQUAL 0)
+        message(FATAL_ERROR "Unable to determine type of glib-mkenums script")
+      endif ()
+	endif ()
+  else ()
+    set(GLIB_MKENUMS_CMD "${GLIB_MKENUMS}")
+  endif ()
+  if (NOT GLIB_MKENUMS_CMD)
+    message(FATAL_ERROR "HB_HAVE_GOBJECT was set, but we failed to find glib-mkenums, which is required")
+  endif()
+
+  pkg_check_modules(PC_GOBJECT QUIET gobject-2.0)
+
+  find_library(GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${PC_GLIB_LIBDIR} ${PC_GLIB_LIBRARY_DIRS})
+  find_path(GOBJECT_INCLUDE_DIR NAMES glib-object.h HINTS ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0)
+
+  include_directories(${GOBJECTCONFIG_INCLUDE_DIR} ${GOBJECT_INCLUDE_DIR})
+  mark_as_advanced(GOBJECT_LIBRARIES GOBJECT_INCLUDE_DIR)
+
+  list(APPEND hb_gobject_sources ${PROJECT_SOURCE_DIR}/src/hb-gobject-structs.cc)
+  list(APPEND hb_gobject_gen_sources
+    ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc
+    )
+  list(APPEND hb_gobject_structs_headers
+    ${PROJECT_SOURCE_DIR}/src/hb-gobject-structs.h
+    )
+  list(APPEND hb_gobject_headers
+    ${PROJECT_SOURCE_DIR}/src/hb-gobject.h
+    ${hb_gobject_structs_headers}
+    )
+  list(APPEND hb_gobject_gen_headers
+    ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h
+    )
+
+  add_custom_command (
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h
+    COMMAND ${GLIB_MKENUMS_CMD}
+      --template=${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.h.tmpl
+      --identifier-prefix hb_
+      --symbol-prefix hb_gobject
+      ${hb_gobject_structs_headers}
+      ${project_headers}
+      > ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h.tmp
+    COMMAND "${CMAKE_COMMAND}"
+      "-DENUM_INPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h.tmp"
+      "-DENUM_OUTPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h"
+      -P ${PROJECT_SOURCE_DIR}/replace-enum-strings.cmake
+    DEPENDS ${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.h.tmpl
+      ${hb_gobject_header}
+      ${project_headers}
+    )
+
+  add_custom_command (
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc
+    COMMAND ${GLIB_MKENUMS_CMD}
+      --template=${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.cc.tmpl
+      --identifier-prefix hb_
+      --symbol-prefix hb_gobject
+      ${hb_gobject_header}
+      ${project_headers}
+      > ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc.tmp
+    COMMAND "${CMAKE_COMMAND}"
+      "-DENUM_INPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc.tmp"
+      "-DENUM_OUTPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc"
+      -P ${PROJECT_SOURCE_DIR}/replace-enum-strings.cmake
+    DEPENDS ${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.cc.tmpl
+      ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h
+      ${hb_gobject_header}
+      ${project_headers}
+    )
+endif ()
+
+## Atomic ops availability detection
+file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c"
+"		void memory_barrier (void) { __sync_synchronize (); }
+		int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
+		int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
+		void mutex_unlock (int *m) { __sync_lock_release (m); }
+		int main () { return 0; }
+")
+try_compile(HB_HAVE_INTEL_ATOMIC_PRIMITIVES
+  ${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives
+  SOURCES ${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c)
+if (HB_HAVE_INTEL_ATOMIC_PRIMITIVES)
+  add_definitions(-DHAVE_INTEL_ATOMIC_PRIMITIVES)
+endif ()
+
+file(WRITE "${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c"
+"		#include <atomic.h>
+		/* This requires Solaris Studio 12.2 or newer: */
+		#include <mbarrier.h>
+		void memory_barrier (void) { __machine_rw_barrier (); }
+		int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
+		void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
+		int main () { return 0; }
+")
+try_compile(HB_HAVE_SOLARIS_ATOMIC_OPS
+  ${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops
+  SOURCES ${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c)
+if (HB_HAVE_SOLARIS_ATOMIC_OPS)
+  add_definitions(-DHAVE_SOLARIS_ATOMIC_OPS)
+endif ()
+
+
+## Define harfbuzz library
+add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_headers})
+target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
+
+## Define harfbuzz-gobject library
+if (HB_HAVE_GOBJECT)
+  add_library(harfbuzz-gobject
+    ${hb_gobject_sources}
+    ${hb_gobject_gen_sources}
+    ${hb_gobject_headers}
+    ${hb_gobject_gen_headers}
+    )
+  include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/src)
+  add_dependencies(harfbuzz-gobject harfbuzz)
+  target_link_libraries(harfbuzz-gobject harfbuzz ${GOBJECT_LIBRARIES} ${THIRD_PARTY_LIBS})
+endif ()
+
+# On Windows, g-ir-scanner requires a DLL build in order for it to work
+if (WIN32)
+  if (NOT BUILD_SHARED_LIBS)
+    message("Building introspection files on Windows requires BUILD_SHARED_LIBS to be enabled.")
+    set(HB_HAVE_INTROSPECTION OFF)
+  endif ()
+endif ()
+
+if (HB_HAVE_INTROSPECTION)
+
+  find_package(PkgConfig)
+  pkg_check_modules(PC_GI QUIET gobject-introspection-1.0)
+
+  find_program(G_IR_SCANNER g-ir-scanner
+    HINTS ${PC_g_ir_scanner}
+    )
+
+  find_program(G_IR_COMPILER g-ir-compiler
+    HINTS ${PC_g_ir_compiler}
+    )
+
+  if (WIN32 AND NOT MINGW)
+    # Note that since we already enable HB_HAVE_GOBJECT
+    # we would already have PYTHON_EXECUTABLE handy
+    set(G_IR_SCANNER_CMD "${PYTHON_EXECUTABLE}" "${G_IR_SCANNER}")
+  else ()
+    set(G_IR_SCANNER_CMD "${G_IR_SCANNER}")
+  endif ()
+
+  # We need to account for the varying output directories
+  # when we build using Visual Studio projects
+  if("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
+    set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
+  else ()
+    set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
+  endif ()
+
+  # Get the CFlags that we used to build HarfBuzz/HarfBuzz-GObject
+  set (hb_defines_cflags "")
+  foreach(hb_cflag ${hb_cflags})
+    list(APPEND hb_defines_cflags "-D${hb_cflag}")
+  endforeach(hb_cflag)
+
+  # Get the other dependent libraries we used to build HarfBuzz/HarfBuzz-GObject
+  set (extra_libs "")
+  foreach (extra_lib ${THIRD_PARTY_LIBS})
+    # We don't want the .lib extension here...
+    string(REPLACE ".lib" "" extra_lib_stripped "${extra_lib}")
+    list(APPEND extra_libs "--extra-library=${extra_lib_stripped}")
+  endforeach ()
+
+  set(introspected_sources)
+  foreach (f
+    ${project_headers}
+    ${project_sources}
+    ${hb_gobject_gen_sources}
+    ${hb_gobject_gen_headers}
+    ${hb_gobject_sources}
+    ${hb_gobject_headers}
+    )
+    if (WIN32)
+      # Nasty issue: We need to make drive letters lower case,
+      # otherwise g-ir-scanner won't like it and give us a bunch
+      # of invalid items and unresolved types...
+      STRING(SUBSTRING "${f}" 0 1 drive)
+      STRING(SUBSTRING "${f}" 1 -1 path)
+      if (drive MATCHES "[A-Z]")
+        STRING(TOLOWER ${drive} drive_lower)
+        list(APPEND introspected_sources "${drive_lower}${path}")
+      else ()
+        list(APPEND introspected_sources "${f}")
+      endif ()
+    else ()
+      list(APPEND introspected_sources "${f}")
+    endif ()
+  endforeach ()
+
+  # Finally, build the introspection files...
+  add_custom_command (
+    TARGET harfbuzz-gobject
+    POST_BUILD
+    COMMAND ${G_IR_SCANNER_CMD}
+      --warn-all --no-libtool --verbose
+      -n hb
+      --namespace=HarfBuzz
+      --nsversion=0.0
+      --identifier-prefix=hb_
+      --include GObject-2.0
+      --pkg-export=harfbuzz
+      --cflags-begin
+      -I${PROJECT_SOURCE_DIR}/src
+      -I${PROJECT_BINARY_DIR}/src
+      ${hb_includedir_cflags}
+      ${hb_defines_cflags}
+      -DHB_H
+      -DHB_H_IN
+      -DHB_OT_H
+      -DHB_OT_H_IN
+      -DHB_GOBJECT_H
+      -DHB_GOBJECT_H_IN
+      -DHB_EXTERN=
+      --cflags-end
+      --library=harfbuzz-gobject
+      --library=harfbuzz
+      -L${hb_libpath}
+      ${extra_libs}
+      ${introspected_sources}
+      -o ${hb_libpath}/HarfBuzz-0.0.gir
+    DEPENDS harfbuzz-gobject harfbuzz
+    )
+
+  add_custom_command (
+    TARGET harfbuzz-gobject
+    POST_BUILD
+    COMMAND "${G_IR_COMPILER}"
+      --verbose --debug
+      --includedir ${CMAKE_CURRENT_BINARY_DIR}
+      ${hb_libpath}/HarfBuzz-0.0.gir
+      -o ${hb_libpath}/HarfBuzz-0.0.typelib
+    DEPENDS ${hb_libpath}/HarfBuzz-0.0.gir harfbuzz-gobject
+    )
+endif ()
+
+## Additional framework build configs
+if (BUILD_FRAMEWORK)
+  set(CMAKE_MACOSX_RPATH ON)
+  set_target_properties(harfbuzz PROPERTIES
+    FRAMEWORK TRUE
+    PUBLIC_HEADER "${project_headers}"
+    XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
+  )
+  set(MACOSX_FRAMEWORK_IDENTIFIER "harfbuzz")
+  set(MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${HB_VERSION}")
+  set(MACOSX_FRAMEWORK_BUNDLE_VERSION "${HB_VERSION}")
+endif ()
+
+
+## Additional harfbuzz build artifacts
+if (HB_BUILD_UTILS)
+  # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindCairo.cmake
+  find_package(PkgConfig)
+  pkg_check_modules(PC_CAIRO QUIET cairo)
+
+  find_path(CAIRO_INCLUDE_DIRS NAMES cairo.h HINTS ${PC_CAIRO_INCLUDEDIR} ${PC_CAIRO_INCLUDE_DIRS} PATH_SUFFIXES cairo)
+  find_library(CAIRO_LIBRARIESNAMES cairo HINTS ${PC_CAIRO_LIBDIR} ${PC_CAIRO_LIBRARY_DIRS})
+
+  add_definitions("-DPACKAGE_NAME=\"HarfBuzz\"")
+  add_definitions("-DPACKAGE_VERSION=\"${HB_VERSION}\"")
+  include_directories(${CAIRO_INCLUDE_DIRS})
+
+  add_executable(hb-view ${HB_VIEW_sources})
+  target_link_libraries(hb-view harfbuzz ${CAIRO_LIBRARIESNAMES})
+
+  add_executable(hb-shape ${HB_SHAPE_sources})
+  target_link_libraries(hb-shape harfbuzz)
+
+  add_executable(hb-ot-shape-closure ${HB_OT_SHAPE_CLOSURE_sources})
+  target_link_libraries(hb-ot-shape-closure harfbuzz)
+
+  mark_as_advanced(CAIRO_INCLUDE_DIRS CAIRO_LIBRARIESNAMES)
+endif ()
+
+
+## Install
+if (NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL)
+  install(FILES ${project_headers} DESTINATION include/harfbuzz)
+  if (HB_HAVE_GOBJECT)
+    install(FILES ${hb_gobject_headers} ${hb_gobject_gen_headers} DESTINATION include/harfbuzz)
+  endif ()
+endif ()
+
+if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
+  install(TARGETS harfbuzz
+    ARCHIVE DESTINATION lib
+    LIBRARY DESTINATION lib
+    RUNTIME DESTINATION bin
+    FRAMEWORK DESTINATION Library/Frameworks
+    )
+  if (HB_BUILD_UTILS)
+    install(TARGETS hb-view
+      RUNTIME DESTINATION bin
+    )
+    install(TARGETS hb-view
+      RUNTIME DESTINATION bin
+    )
+
+    install(TARGETS hb-shape
+      RUNTIME DESTINATION bin
+    )
+
+    install(TARGETS hb-ot-shape-closure
+      RUNTIME DESTINATION bin
+    )
+  endif ()
+  if (HB_HAVE_GOBJECT)
+    install(TARGETS harfbuzz-gobject
+      ARCHIVE DESTINATION lib
+      LIBRARY DESTINATION lib
+      RUNTIME DESTINATION bin
+    )
+    if (HB_HAVE_INTROSPECTION)
+      if("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
+        set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
+      else ()
+        set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
+      endif ()
+
+      install(FILES "${hb_libpath}/HarfBuzz-0.0.gir"
+        DESTINATION share/gir-1.0
+        )
+
+      install(FILES "${hb_libpath}/HarfBuzz-0.0.typelib"
+        DESTINATION lib/girepository-1.0
+        )
+    endif ()
+  endif ()
+endif ()
+
+# Needs to come last so that variables defined above are passed to
+# subdirectories.
+add_subdirectory(test)
diff --git a/Makefile.am b/Makefile.am
index 8dc8a4b..fde5256 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,13 +4,16 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = src util test docs win32
+SUBDIRS = src util test docs
 
 EXTRA_DIST = \
 	autogen.sh \
 	harfbuzz.doap \
 	README.python \
 	BUILD.md \
+	RELEASING.md \
+	CMakeLists.txt \
+	replace-enum-strings.cmake \
 	$(NULL)
 
 MAINTAINERCLEANFILES = \
diff --git a/NEWS b/NEWS
index 43a3bac..7434bca 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,230 @@
+Overview of changes leading to 1.7.4
+Wednesday, December 20, 2017
+====================================
+
+- Fix collect_glyphs() regression caused by hb_set_t changes.
+
+
+Overview of changes leading to 1.7.3
+Monday, December 18, 2017
+====================================
+
+- hb_set_t performance tuning and optimizations.
+- Speed up collect_glyphs() and reject garbage data.
+- In hb_coretext_font_create() set font point-size (ptem).
+- Misc fixes.
+
+
+Overview of changes leading to 1.7.2
+Monday, December 4, 2017
+====================================
+
+- Optimize hb_set_add_range().
+- Misc fixes.
+- New API:
+hb_coretext_font_create()
+
+
+Overview of changes leading to 1.7.1
+Tuesday, November 14, 2017
+====================================
+
+- Fix atexit object destruction regression.
+- Fix minor integer-overflow.
+
+
+Overview of changes leading to 1.7.0
+Monday, November 13, 2017
+====================================
+
+- Minor Indic fixes.
+- Implement kerning and glyph names in hb-ot-font.
+- Various DSO optimization re .data and .bss sizes.
+- Make C++11 optional; build fixes.
+- Mark all other backends "unsafe-to-break".
+- Graphite fix.
+
+
+Overview of changes leading to 1.6.3
+Thursday, October 26th, 2017
+====================================
+
+- Fix hb_set_t some more.  Should be solid now.
+- Implement get_glyph_name() for hb-ot-font.
+- Misc fixes.
+
+
+Overview of changes leading to 1.6.2
+Monday, October 23nd, 2017
+====================================
+
+- Yesterday's release had a bad crasher; don't use it.  That's what
+  happens when one works on Sunday...
+  https://github.com/harfbuzz/harfbuzz/issues/578
+- Build fixes for FreeBSD and Chrome Android.
+
+
+Overview of changes leading to 1.6.1
+Sunday, October 22nd, 2017
+====================================
+
+- Don't skip over COMBINING GRAPHEME JOINER when ligating, etc.
+  To be refined: https://github.com/harfbuzz/harfbuzz/issues/554
+- Faster hb_set_t implementation.
+- Don't use deprecated ICU API.
+- Fix undefined-behavior in Myanmar shaper, introduced in 1.6.0
+- Deprecated API:
+  hb_set_invert()
+
+
+Overview of changes leading to 1.6.0
+Friday, October the 13th, 2017
+====================================
+
+- Update to Unicode 10.
+
+- Various Indic and Universal Shaping Engine fixes as a result of
+  HarfBuzz Hackfest with Jonathan Kew at Web Engines Hackfest at
+  the Igalia offices in A Coruña, Spain.  Thanks Igalia for having
+  us!
+
+- Implement Unicode Arabic Mark Ordering Algorithm UTR#53.
+
+- Implement optical sizing / tracking in CoreText backend, using
+  new API hb_font_set_ptem().
+
+- Allow notifying hb_font_t that underlying FT_Face changed sizing,
+  using new API hb_ft_font_changed().
+
+- More Graphite backend RTL fixes.
+
+- Fix caching of variable font shaping plans.
+
+- hb-view / hb-shape now accept following new arguments:
+
+  o --unicodes: takes a list of hex numbers that represent Unicode
+    codepoints.
+
+New API:
++hb_face_get_table_tags()
++hb_font_set_ptem()
++hb_font_get_ptem()
++hb_ft_font_changed()
+
+
+Overview of changes leading to 1.5.1
+Tuesday, September 5, 2017
+====================================
+
+- Fix "unsafe-to-break" in fallback shaping and other corner cases.
+  All our tests pass with --verify now, meaning unsafe-to-break API
+  works as expected.
+- Add --unicodes to hb-view / hb-shape.
+- [indic] Treat Consonant_With_Stacker as consonant.  This will need
+  further tweaking.
+- hb_buffer_diff() tweaks.
+
+
+Overview of changes leading to 1.5.0
+Wednesday, August 23, 2017
+====================================
+
+- Misc new API, for appending a buffer to another, and for comparing
+  contents of two buffers for types of differences.
+
+- New "unsafe-to-break" API.  Can be used to speed up reshaping
+  in line-breaking situations.  Essentially, after shaping, it returns
+  positions in the input string (some of the cluster boundaries) that
+  are "safe to break" in that if the text is segmented at that position
+  and two sides reshaped and concatenated, the shaping result is
+  exactly the same as shaping the text in one piece.
+
+  hb-view and hb-shape and hb-shape now take --verify, which verifies
+  the above property.
+
+  Some corner cases of the implementation are still not quite working.
+  Those will be fixed in subsequent releases.
+
+- New API:
+
+hb_buffer_append()
+
+hb_glyph_flags_t
+HB_GLYPH_FLAG_UNSAFE_TO_BREAK
+HB_GLYPH_FLAG_DEFINED
+hb_glyph_info_get_glyph_flags()
+
+HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS
+
+hb_buffer_diff_flags_t
+HB_BUFFER_DIFF_FLAG_EQUAL
+HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH
+HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH
+HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT
+HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
+HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH
+HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH
+HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH
+HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH
+hb_buffer_diff
+
+
+Overview of changes leading to 1.4.8
+Tuesday, August 8, 2017
+====================================
+
+- Major fix to avar table handling.
+- Rename hb-shape --show-message to --trace.
+- Build fixes.
+
+
+Overview of changes leading to 1.4.7
+Tuesday, July 18, 2017
+====================================
+
+- Multiple Indic, Tibetan, and Cham fixes.
+- CoreText: Allow disabling kerning.
+- Adjust Arabic feature order again.
+- Misc build fixes.
+
+
+Overview of changes leading to 1.4.6
+Sunday, April 23, 2017
+====================================
+
+- Graphite2: Fix RTL positioning issue.
+- Backlist GDEF of more versions of Padauk and Tahoma.
+- New, experimental, cmake alternative build system.
+
+
+Overview of changes leading to 1.4.5
+Friday, March 10, 2017
+====================================
+
+- Revert "Fix Context lookup application when moving back after a glyph..."
+  This introduced memory access problems.  To be fixed properly soon.
+
+
+Overview of changes leading to 1.4.4
+Sunday, March 5, 2017
+====================================
+
+- Fix Context lookup application when moving back after a glyph deletion.
+- Fix buffer-overrun in Bengali.
+
+
+Overview of changes leading to 1.4.3
+Saturday, February 25, 2017
+====================================
+
+- Route Adlam script to Arabic shaper.
+- Misc fixes.
+- New API:
+  hb_font_set_face()
+- Deprecate API:
+  hb_graphite2_font_get_gr_font()
+
+
 Overview of changes leading to 1.4.2
 Monday, January 23, 2017
 ====================================
@@ -243,7 +470,7 @@
 - CoreText: Drastically speed up font initialization.
 - CoreText: Fix tiny leak.
 - Group ZWJ/ZWNJ with previous syllable under cluster-level=0.
-  https://github.com/behdad/harfbuzz/issues/217
+  https://github.com/harfbuzz/harfbuzz/issues/217
 - Add test/shaping/README.md about how to add tests to the suite.
 
 
@@ -259,8 +486,8 @@
 - Allow GPOS cursive connection on marks, and fix the interaction with
   mark attachment.  This work resulted in some changes to how mark
   attachments work.  See:
-  https://github.com/behdad/harfbuzz/issues/211
-  https://github.com/behdad/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
+  https://github.com/harfbuzz/harfbuzz/issues/211
+  https://github.com/harfbuzz/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
 - Graphite2 shaper: improved negative advance handling (eg. Nastaliq).
 - Add nmake-based build system for Windows.
 - Minor speedup.
@@ -301,7 +528,7 @@
 ====================================
 
 - Fix badly-broken fallback shaper that affected terminology.
-  https://github.com/behdad/harfbuzz/issues/187
+  https://github.com/harfbuzz/harfbuzz/issues/187
 - Fix y_scaling in Graphite shaper.
 - API changes:
   * An unset glyph_h_origin() function in font-funcs now (sensibly)
@@ -323,11 +550,11 @@
 ====================================
 
 - Implement 'stch' stretch feature for Syriac Abbreviation Mark.
-  https://github.com/behdad/harfbuzz/issues/141
+  https://github.com/harfbuzz/harfbuzz/issues/141
 - Disable use of decompose_compatibility() callback.
 - Implement "shaping" of various Unicode space characters, even
   if the font does not support them.
-  https://github.com/behdad/harfbuzz/issues/153
+  https://github.com/harfbuzz/harfbuzz/issues/153
 - If font does not support U+2011 NO-BREAK HYPHEN, fallback to
   U+2010 HYPHEN.
 - Changes resulting from libFuzzer continuous fuzzing:
@@ -350,7 +577,7 @@
 - Revert default load-flags of fonts created using hb_ft_font_create()
   back to FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING.  This was changed in
   last release (1.0.5), but caused major issues, so revert.
-  https://github.com/behdad/harfbuzz/issues/143
+  https://github.com/harfbuzz/harfbuzz/issues/143
 
 
 Overview of changes leading to 1.0.5
@@ -358,7 +585,7 @@
 ====================================
 
 - Fix multiple memory access bugs discovered using libFuzzer.
-  https://github.com/behdad/harfbuzz/issues/139
+  https://github.com/harfbuzz/harfbuzz/issues/139
   Everyone should upgrade to this version as soon as possible.
   We now have continuous fuzzing set up, to avoid issues like
   these creeping in again.
@@ -629,7 +856,7 @@
   U+FFFD REPLACEMENT CHARACTER now.
 - With all changes in this release, the buffer will contain fully
   valid Unicode after hb_buffer_add_utf8/16/32 no matter how
-  broken the input is.  This can be overriden though.  See below.
+  broken the input is.  This can be overridden though.  See below.
 - Fix Mongolian Variation Selectors for fonts without GDEF.
 - Fix minor invalid buffer access.
 - Accept zh-Hant and zh-Hans language tags.  hb_ot_tag_to_language()
diff --git a/README b/README
index 69a1bdd..aa05516 100644
--- a/README
+++ b/README
@@ -1,6 +1,7 @@
-[![Build Status](https://travis-ci.org/behdad/harfbuzz.svg)](https://travis-ci.org/behdad/harfbuzz)
-[![Build Status](https://ci.appveyor.com/api/projects/status/4oaq58ns2h0m2soa?svg=true)](https://ci.appveyor.com/project/behdad/harfbuzz)
-[![Coverage Status](https://img.shields.io/coveralls/behdad/harfbuzz.svg)](https://coveralls.io/r/behdad/harfbuzz)
+[![Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg)](https://travis-ci.org/harfbuzz/harfbuzz)
+[![Build status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
+[![CircleCI](https://circleci.com/gh/harfbuzz/harfbuzz.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz)
+[![Coverage Status](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.
@@ -10,3 +11,5 @@
   http://harfbuzz.org/
 
 For license information, see the file COPYING.
+
+Documentation: https://harfbuzz.github.io
diff --git a/README.android b/README.android
new file mode 100644
index 0000000..1baa040
--- /dev/null
+++ b/README.android
@@ -0,0 +1,12 @@
+Harfbuzz
+
+HOW TO UPDATE
+* Check out external/harfbuzz to <checkout_dir>
+  ex: git clone https://android.googlesource.com/platform/external/harfbuzz_ng
+* Locate the commit you'd like to move.
+  ex: for 1.7.4: https://github.com/harfbuzz/harfbuzz/commit/007a2a4317227b8fb4c764c590203c85fc3da5fd
+* In <checkout_dir>, run git merge <commit_sha>
+  i.e. git merge 007a2a4317227b8fb4c764c590203c85fc3da5fd
+* Upload the changes.
+  ex: git push origin HEAD:refs/for/master
+* Gerrit will run the text related tests.
diff --git a/README.version b/README.version
index 93200ee..fc54c80 100644
--- a/README.version
+++ b/README.version
@@ -1,3 +1,3 @@
-URL: http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-1.4.2.tar.bz2
-Version: 1.4.2
+URL: https://github.com/harfbuzz/harfbuzz/commit/007a2a4317227b8fb4c764c590203c85fc3da5fd
+Version: 1.7.4
 BugComponent: 25699
diff --git a/RELEASING.md b/RELEASING.md
new file mode 100644
index 0000000..1863c6e
--- /dev/null
+++ b/RELEASING.md
@@ -0,0 +1,125 @@
+HarfBuzz release walk-through checklist:
+
+1. Open gitk and review changes since last release.
+
+   * `git diff $(git describe | sed 's/-.*//').. src/*.h` prints all public API
+     changes.
+
+     Document them in NEWS.  All API and API semantic changes should be clearly
+     marked as API additions, API changes, or API deletions.  Document
+     deprecations.
+
+     If there's a backward-incompatible API change (including deletions for API
+     used anywhere), that's a release blocker.  Do NOT release.
+
+2. Based on severity of changes, decide whether it's a minor or micro release
+   number bump,
+
+3. Make sure you have correct date and new version at the top of NEWS file,
+
+4. Bump version in configure.ac line 3,
+
+5. Do "make distcheck", if it passes, you get a tarball.
+   Otherwise, fix things and commit them separately before making release,
+
+6. "make release-files".  Enter your GPG password.  This creates a sha256 hash
+   and signs it.
+
+7. Now that you have release files built, commit NEWS and configure.ac changes.
+   The commit message is simply the release number.  Eg. "1.4.7"
+
+8. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7".  Enter your
+   GPG password again.
+
+9. Build win32 bundle.
+
+   a. Put contents of [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ) on your `~/.local/i686-w64-mingw32`,
+
+   b. Run `./MING32 --with-uniscribe` script (available below) 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.
+
+10. 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 2895619 Jul 18 11:34 harfbuzz-1.4.7-win32.zip
+```
+
+11. While doing that, quickly double-check the size of the .tar.bz2 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.
+
+12. Push the commit and tag out: "git push --follow-tags".  Make sure it's
+    pushed both to freedesktop repo and github.
+
+13. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases),
+    edit the tag, upload artefacts and NEWS entry and save.
+
+
+## MING32
+```bash
+#!/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
+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 "$@"
+```
+
+## 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/appveyor.yml b/appveyor.yml
index 2a0e7c5..9a34052 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -3,21 +3,21 @@
 environment:
   matrix:
     - compiler: msvc
-      ARCH: amd64
-      VCPKG_ARCH: x64-windows
-      CFG: release
+      generator: Visual Studio 14
+      platform: Win32
+      configuration: Debug
+      triplet: x86-windows
     - compiler: msvc
-      ARCH: x86
-      VCPKG_ARCH: x86-windows
-      CFG: release
+      generator: Visual Studio 14 Win64
+      platform: x64
+      configuration: Debug
+      triplet: x64-windows
+
     - compiler: msvc
-      ARCH: amd64
-      VCPKG_ARCH: x64-windows
-      CFG: debug
-    - compiler: msvc
-      ARCH: x86
-      VCPKG_ARCH: x86-windows
-      CFG: debug
+      generator: Visual Studio 14 ARM
+      platform: ARM
+      configuration: Debug
+
 
     - compiler: msys2
       MINGW_PREFIX: /c/msys2/mingw64/
@@ -31,22 +31,23 @@
 install:
   - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel"
 
-  - 'if "%compiler%"=="msvc" call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %ARCH%'
-  - 'if "%compiler%"=="msvc" git clone https://github.com/Microsoft/vcpkg'
-  - 'if "%compiler%"=="msvc" cd vcpkg'
-  - 'if "%compiler%"=="msvc" powershell -exec bypass scripts\bootstrap.ps1'
-  - 'if "%compiler%"=="msvc" vcpkg install freetype:%VCPKG_ARCH%'
-  - 'if "%compiler%"=="msvc" copy installed\%VCPKG_ARCH%\debug\lib\freetyped.lib installed\%VCPKG_ARCH%\lib'
-  - 'if "%compiler%"=="msvc" cd ..'
-
 build_script:
-  - 'if "%compiler%"=="msvc" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh; make distdir"'
-  - 'if "%compiler%"=="msvc" cd harfbuzz-*\win32'
-  - 'if "%compiler%"=="msvc" nmake /f Makefile.vc CFG=%CFG% UNISCRIBE=1 DIRECTWRITE=1 FREETYPE=1 FREETYPE_DIR=..\..\vcpkg\installed\%VCPKG_ARCH%\include ADDITIONAL_LIB_DIR=..\..\vcpkg\installed\%VCPKG_ARCH%\lib'
-  - 'if "%compiler%"=="msvc" nmake /f Makefile.vc CFG=%CFG% UNISCRIBE=1 DIRECTWRITE=1 FREETYPE=1 install'
+  - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet%'
+  - 'if "%compiler%"=="msvc" md build'
+  - 'if "%compiler%"=="msvc" cd build'
+  - 'if "%compiler%"=="msvc" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin;c:\msys64\mingw64\bin' # msys2 is added just for having "ragel" on PATH
+
+  - '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 -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake ../'
+
+  - 'if "%compiler%"=="msvc" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%'
+  - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest'
 
   - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-$MSYS2_ARCH-{freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config}"'
-  - '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 --build=$MINGW_CHOST --host=$MINGW_CHOST --prefix=$MINGW_PREFIX; make; make check"'
+  - '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 --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make; make check || (cat */test-suite.log test/*/test-suite.log && false)"'
+
+cache:
+  - c:\tools\vcpkg\installed\
 
 # disable automatic tests
 test: off
diff --git a/configure.ac b/configure.ac
index 31fa97d..7f24627 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [1.4.2],
-        [https://github.com/behdad/harfbuzz/issues/new],
+        [1.7.4],
+        [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
 
@@ -23,6 +23,7 @@
 AC_PROG_CC
 AM_PROG_CC_C_O
 AC_PROG_CXX
+AX_CXX_COMPILE_STDCXX(11, noext, optional)
 AC_SYS_LARGEFILE
 PKG_PROG_PKG_CONFIG([0.20])
 AM_MISSING_PROG([RAGEL], [ragel])
@@ -69,8 +70,8 @@
 ])
 
 # Functions and headers
-AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty)
-AC_CHECK_HEADERS(unistd.h sys/mman.h)
+AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l)
+AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h)
 
 # Compiler flags
 AC_CANONICAL_HOST
@@ -164,7 +165,7 @@
 
 AC_ARG_WITH(gobject,
 	[AS_HELP_STRING([--with-gobject=@<:@yes/no/auto@:>@],
-			[Use gobject @<:@default=auto@:>@])],,
+			[Use gobject @<:@default=no@:>@])],,
 	[with_gobject=no])
 have_gobject=false
 if test "x$with_gobject" = "xyes" -o "x$with_gobject" = "xauto"; then
@@ -353,6 +354,7 @@
 	save_libs=$LIBS
 	LIBS="$LIBS $FREETYPE_LIBS"
 	AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates)
+	AC_CHECK_FUNCS(FT_Set_Var_Blend_Coordinates)
 	LIBS=$save_libs
 fi
 AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
@@ -494,8 +496,6 @@
 test/shaping/Makefile
 docs/Makefile
 docs/version.xml
-win32/Makefile
-win32/config.h.win32
 ])
 
 AC_OUTPUT
diff --git a/docs/HarfBuzz.png b/docs/HarfBuzz.png
index d58d9fc..771d955 100644
--- a/docs/HarfBuzz.png
+++ b/docs/HarfBuzz.png
Binary files differ
diff --git a/docs/HarfBuzz.svg b/docs/HarfBuzz.svg
new file mode 100644
index 0000000..4e2df25
--- /dev/null
+++ b/docs/HarfBuzz.svg
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="svg2"
+   width="682.66669"
+   height="682.66669"
+   viewBox="0 0 682.66669 682.66669"
+   sodipodi:docname="harfbuzz2.svg"
+   inkscape:version="0.92.2 5c3e80d, 2017-08-06"
+   inkscape:export-filename="harfbuzz2.png"
+   inkscape:export-xdpi="72"
+   inkscape:export-ydpi="72">
+  <metadata
+     id="metadata8">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs6">
+    <g
+       id="g50">
+      <symbol
+         id="glyph0-0"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path26"
+           d="M 32,0 V -192 H 224 V 0 Z M 48,-16 H 208 V -176 H 48 Z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-1"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path29"
+           d="m 52.5,-64.875 c -0.08594,2.25 -0.9375,6.335938 -2.5625,12.25 -1.625,5.917969 -3.75,12.375 -6.375,19.375 -2.625,7 -4.9375,12.292969 -6.9375,15.875 -2,3.585938 -4.1875,6.3125 -6.5625,8.1875 -2.375,1.875 -6.210938,3.585938 -11.5,5.125 -5.292969,1.542969 -9.542969,2.585938 -12.75,3.125 -3.210938,0.542969 -5.230469,0.8125 -6.0625,0.8125 -0.832031,-0.082031 -1.332031,-0.414062 -1.5,-1 -0.164062,-0.582031 0.085938,-1.332031 0.75,-2.25 0.9179688,-1.414062 3.226562,-3.269531 6.9375,-5.5625 3.707031,-2.289062 8.019531,-5.164062 12.9375,-8.625 4.914062,-3.457031 8.414062,-6.476562 10.5,-9.0625 2.082031,-2.582031 4.4375,-6.457031 7.0625,-11.625 2.625,-5.164062 5,-10.375 7.125,-15.625 2.125,-5.25 3.644531,-8.832031 4.5625,-10.75 0.914062,-1.914062 1.914062,-2.832031 3,-2.75 0.914062,0.167969 1.375,1 1.375,2.5 z M 41.75,-117.75 c 0,-1.83203 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.64844 8,4.1875 3.5,3.54297 5.375,6.3125 5.625,8.3125 0,2.66797 -1.460938,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 -0.5,-0.25 -2.230469,-1.35156 -5.1875,-3.3125 -2.960938,-1.95703 -5.148438,-3.4375 -6.5625,-4.4375 -1.25,-0.83203 -1.875,-1.70703 -1.875,-2.625 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-2"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path32"
+           d="m 19.75,-47.125 c -0.167969,3.167969 -0.5,6.023438 -1,8.5625 -0.5,2.542969 -1.167969,4.710938 -2,6.5 -0.835938,1.792969 -1.898438,3.125 -3.1875,4 -1.292969,0.875 -2.855469,1.1875 -4.6875,0.9375 0.082031,-6.5 0.769531,-15.5625 2.0625,-27.1875 1.289062,-11.625 3.226562,-24.476562 5.8125,-38.5625 1.332031,-4.082031 4.039062,-11.28906 8.125,-21.625 0.414062,-1 0.851562,-1.41406 1.3125,-1.25 0.457031,0.16797 0.6875,0.58594 0.6875,1.25 -0.25,5.08594 -1.292969,14.792969 -3.125,29.125 -1.835938,14.335938 -2.960938,24.167969 -3.375,29.5 -0.417969,5.335938 -0.625,8.25 -0.625,8.75 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-3"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path35"
+           d="m -10.875,-27.25 c 1.667969,-7.164062 3.5625,-12.457031 5.6875,-15.875 2.125,-3.414062 3.855469,-5.289062 5.1875,-5.625 v 5.5 c 0,7 1.875,11.875 5.625,14.625 2.25,1.5 4.5,2 6.75,1.5 2.25,-0.5 3.976562,-1.664062 5.1875,-3.5 1.207031,-1.832031 2.226562,-3.976562 3.0625,-6.4375 0.832031,-2.457031 1.625,-3.6875 2.375,-3.6875 0.914062,0 1.289062,0.875 1.125,2.625 -0.08594,3 -1.023438,7.875 -2.8125,14.625 C 19.519531,-16.75 17.082031,-11.207031 14,-6.875 10.914062,-2.539062 7.164062,-0.25 2.75,0 c -4.5,-0.164062 -8,-2.707031 -10.5,-7.625 -2.25,-4.832031 -3.289062,-11.082031 -3.125,-18.75 z m 6.625,111.5 c 0,-1.835938 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.644531 8,4.1875 3.5,3.539062 5.375,6.3125 5.625,8.3125 0,2.664062 -1.460938,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 C 8.875,94.375 7.144531,93.269531 4.1875,91.3125 1.226562,89.351562 -0.957031,87.875 -2.375,86.875 -3.625,86.039062 -4.25,85.164062 -4.25,84.25 Z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-4"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path38"
+           d=""
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-5"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path41"
+           d="m 118.5,-33 c 15.33203,-3.914062 27.375,-8.289062 36.125,-13.125 7.5,-4.082031 11.25,-7.5 11.25,-10.25 0,-0.832031 -0.5625,-1.894531 -1.6875,-3.1875 -1.125,-1.289062 -1.9375,-1.9375 -2.4375,-1.9375 -0.83594,0 -2.02344,0.148438 -3.5625,0.4375 -1.54297,0.292969 -2.64844,0.4375 -3.3125,0.4375 -2.91797,0 -4.98047,-0.769531 -6.1875,-2.3125 -1.21094,-1.539062 -1.8125,-3.601562 -1.8125,-6.1875 0,-1.5 2.16406,-6.539062 6.5,-15.125 1.66406,-3.414062 3.0625,-5.8125 4.1875,-7.1875 1.125,-1.375 2.76953,-2.0625 4.9375,-2.0625 3.58203,0 6.91406,1.9375 10,5.8125 3.08203,3.875 4.625,8.855469 4.625,14.9375 0,6 -0.8125,11.4375 -2.4375,16.3125 -1.625,4.875 -4.14844,9.605469 -7.5625,14.1875 -3.41797,4.585938 -7.83594,9.042969 -13.25,13.375 -8.08594,6.085938 -17.625,11.230469 -28.625,15.4375 -11,4.210938 -23.83594,7.5 -38.5,9.875 C 72.082031,-1.1875 58.082031,0 44.75,0 37.082031,0 30.082031,-0.375 23.75,-1.125 17.414062,-1.875 12.582031,-3.289062 9.25,-5.375 3.082031,-8.789062 0.25,-14.5 0.75,-22.5 c 0.332031,-4.082031 0.832031,-8.4375 1.5,-13.0625 0.664062,-4.625 1.351562,-8.3125 2.0625,-11.0625 0.707031,-2.75 1.5625,-4.125 2.5625,-4.125 0.832031,0 1.332031,1.75 1.5,5.25 0.164062,3.5 0.6875,6.0625 1.5625,7.6875 0.875,1.625 2.207031,3 4,4.125 1.789062,1.125 4.6875,2.210938 8.6875,3.25 4,1.042969 8.6875,1.855469 14.0625,2.4375 5.375,0.585938 12.519531,0.875 21.4375,0.875 12.414062,0 23.019531,-0.4375 31.8125,-1.3125 C 98.726562,-29.3125 108.25,-30.832031 118.5,-33 Z m -38.75,-86.75 c 0,-1.83203 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.64844 8,4.1875 3.5,3.54297 5.375,6.3125 5.625,8.3125 0,2.66797 -1.46094,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 -0.5,-0.25 -2.230469,-1.35156 -5.1875,-3.3125 -2.960938,-1.95703 -5.148438,-3.4375 -6.5625,-4.4375 -1.25,-0.83203 -1.875,-1.70703 -1.875,-2.625 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-6"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path44"
+           d="m 78,-56.875 c -1.335938,2.25 -2.25,3.875 -2.75,4.875 -1.417969,2.335938 -2.875,4.210938 -4.375,5.625 -1.75,1.75 -4.042969,3.292969 -6.875,4.625 -6.085938,2.917969 -10.460938,5.75 -13.125,8.5 -1.75,1.75 -3.792969,4.960938 -6.125,9.625 -4.25,8.585938 -8.417969,14.292969 -12.5,17.125 -4.085938,2.917969 -11.417969,5 -22,6.25 C 9.414062,-0.0820312 8.414062,0 7.25,0 H 4.375 c -1.5,0 -2.25,-0.164062 -2.25,-0.5 0,-1.914062 2.539062,-4.5 7.625,-7.75 4,-2.414062 7,-4.207031 9,-5.375 6,-3.414062 10.414062,-6.125 13.25,-8.125 4,-2.914062 6.625,-5.75 7.875,-8.5 4.164062,-8.5 7.625,-14.414062 10.375,-17.75 3.082031,-3.664062 6.625,-6.5 10.625,-8.5 C 67.289062,-60.082031 71,-62.207031 72,-62.875 l 10,2.375 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-7"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path47"
+           d="m 13,-17.625 c -1,1.75 -2.0625,3.480469 -3.1875,5.1875 C 8.6875,-10.726562 7.539062,-9.082031 6.375,-7.5 5.207031,-5.914062 4.0625,-4.476562 2.9375,-3.1875 1.8125,-1.894531 0.832031,-0.832031 0,0 c -0.5,-2.582031 -0.832031,-5.125 -1,-7.625 -0.164062,-2.5 0.167969,-5.039062 1,-7.625 1.25,-0.75 2.207031,-1.414062 2.875,-2 1.664062,-1.5 5.375,-6.582031 11.125,-15.25 -0.667969,-0.664062 -2.585938,-1.601562 -5.75,-2.8125 -3.167969,-1.207031 -6.167969,-1.894531 -9,-2.0625 -2.582031,-0.164062 -4.726562,0.3125 -6.4375,1.4375 -1.707031,1.125 -3.25,2.710938 -4.625,4.75 -1.375,2.042969 -2.5625,2.980469 -3.5625,2.8125 -0.332031,-0.164062 -0.375,-0.851562 -0.125,-2.0625 0.25,-1.207031 0.625,-2.394531 1.125,-3.5625 2.085938,-4.832031 4.480469,-8.4375 7.1875,-10.8125 2.710938,-2.375 5.9375,-3.5625 9.6875,-3.5625 2.75,0 6.164062,0.667969 10.25,2 2.582031,0.917969 4.789062,1.375 6.625,1.375 3.832031,0 7.625,-1.375 11.375,-4.125 0.832031,0 1.125,0.542969 0.875,1.625 -0.25,1.085938 -0.605469,2.355469 -1.0625,3.8125 -0.460938,1.460938 -0.773438,2.4375 -0.9375,2.9375 -0.835938,2.585938 -1.5,4.085938 -2,4.5 -0.5,0.417969 -1.960938,1.5 -4.375,3.25 -1.335938,1 -2.480469,2.148438 -3.4375,3.4375 -0.960938,1.292969 -1.9375,2.835938 -2.9375,4.625 -1,1.792969 -2.292969,4.230469 -3.875,7.3125 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+    </g>
+    <g
+       id="g184">
+      <symbol
+         id="glyph0-0-3"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path163"
+           d=""
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-1-6"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path166"
+           d="m 79.625,-103.25 c -3.585938,22 -6.8125,38.417969 -9.6875,49.25 -2.875,10.835938 -5.480469,19.105469 -7.8125,24.8125 -2.335938,5.710938 -4.898438,10.0625 -7.6875,13.0625 -2.792969,3 -7.917969,5.855469 -15.375,8.5625 -7.460938,2.710938 -13.6875,4.605469 -18.6875,5.6875 -5,1.085938 -8.125,1.667969 -9.375,1.75 C 9.75,-0.207031 8.957031,-0.4375 8.625,-0.8125 8.289062,-1.1875 8.582031,-2.082031 9.5,-3.5 c 1.582031,-2.25 4.894531,-5.332031 9.9375,-9.25 5.039062,-3.914062 11,-8.789062 17.875,-14.625 6.875,-5.832031 12.019531,-10.976562 15.4375,-15.4375 3.414062,-4.457031 6.4375,-10.539062 9.0625,-18.25 C 64.4375,-68.769531 67,-76.832031 69.5,-85.25 c 2.5,-8.414062 4.3125,-14.125 5.4375,-17.125 1.125,-3 2.269531,-4.45703 3.4375,-4.375 1.332031,0.25 1.75,1.41797 1.25,3.5 z m 8.875,-68.625 c 0.664062,2.41797 0.644531,4.91797 -0.0625,7.5 -0.710938,2.58594 -2.023438,5.29297 -3.9375,8.125 -1.167969,1.91797 -2.398438,3.64844 -3.6875,5.1875 -1.292969,1.54297 -2.648438,3.02344 -4.0625,4.4375 -0.417969,0.5 -1.085938,1.125 -2,1.875 -0.917969,0.75 -1.875,1.46094 -2.875,2.125 -1,0.66797 -1.960938,1.14844 -2.875,1.4375 -0.917969,0.29297 -1.585938,0.1875 -2,-0.3125 -3,-2.41406 -5.960938,-4.875 -8.875,-7.375 -2.917969,-2.5 -6.125,-4.83203 -9.625,-7 -0.585938,-0.41406 -0.855469,-0.8125 -0.8125,-1.1875 0.03906,-0.375 0.269531,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.582031,-0.83203 1.164062,-1.22656 1.75,-1.1875 0.582031,0.043 1.207031,0.27344 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.60547 4.875,4.0625 1.5,1.46094 2.8125,3.04297 3.9375,4.75 1.125,1.71094 1.9375,3.60547 2.4375,5.6875 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-2-7"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path169"
+           d="m 29.625,-70.625 c -0.667969,8.335938 -2.542969,15.417969 -5.625,21.25 -3.085938,5.835938 -6.585938,8.75 -10.5,8.75 0,-3.164062 1.019531,-13 3.0625,-29.5 2.039062,-16.5 3.582031,-28.3125 4.625,-35.4375 1.039062,-7.125 2.226562,-14.6875 3.5625,-22.6875 1.332031,-8 2.625,-14.45703 3.875,-19.375 1.414062,-4.08203 2.9375,-8.20703 4.5625,-12.375 1.625,-4.16406 3.3125,-8.28906 5.0625,-12.375 1.164062,-1.83203 1.914062,-1.53906 2.25,0.875 -2.085938,13.83594 -4,28.1875 -5.75,43.0625 -1.75,14.875 -2.9375,25.52344 -3.5625,31.9375 -0.625,6.417969 -0.9375,10.167969 -0.9375,11.25 -0.417969,6.835938 -0.625,11.710938 -0.625,14.625 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-3-5"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path172"
+           d="m -16.125,-40.625 c 1.25,-5.332031 2.625,-10 4.125,-14 1.5,-4 2.960938,-7.3125 4.375,-9.9375 1.417969,-2.625 2.792969,-4.644531 4.125,-6.0625 1.335938,-1.414062 2.5,-2.25 3.5,-2.5 v 8.25 c 0,10.5 2.789062,17.835938 8.375,22 3.414062,2.25 6.8125,3 10.1875,2.25 3.375,-0.75 5.957031,-2.5 7.75,-5.25 1.789062,-2.75 3.3125,-5.976562 4.5625,-9.6875 1.25,-3.707031 2.457031,-5.5625 3.625,-5.5625 1.332031,0 1.875,1.335938 1.625,4 -0.08594,4.5 -1.480469,11.8125 -4.1875,21.9375 -2.710938,10.125 -6.375,18.4375 -11,24.9375 -4.625,6.5 -10.230469,9.917969 -16.8125,10.25 -6.75,-0.25 -12,-4.039062 -15.75,-11.375 -3.414062,-7.25 -4.914062,-16.625 -4.5,-28.125 z M 28.5,82.125 c 0.664062,2.414062 0.644531,4.914062 -0.0625,7.5 -0.710938,2.582031 -2.023438,5.289062 -3.9375,8.125 -1.167969,1.914062 -2.398438,3.64453 -3.6875,5.1875 -1.292969,1.53906 -2.648438,3.01953 -4.0625,4.4375 -0.417969,0.5 -1.085938,1.125 -2,1.875 -0.917969,0.75 -1.875,1.45703 -2.875,2.125 -1,0.66406 -1.960938,1.14453 -2.875,1.4375 C 8.082031,113.10156 7.414062,113 7,112.5 c -3,-2.41797 -5.960938,-4.875 -8.875,-7.375 -2.914062,-2.5 -6.125,-4.83594 -9.625,-7 -0.582031,-0.417969 -0.851562,-0.8125 -0.8125,-1.1875 0.04297,-0.375 0.273438,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.582031,-0.835938 1.164062,-1.230469 1.75,-1.1875 0.582031,0.03906 1.207031,0.269531 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.601562 4.875,4.0625 1.5,1.457031 2.8125,3.039062 3.9375,4.75 1.125,1.707031 1.9375,3.601562 2.4375,5.6875 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-4-3"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path175"
+           d=""
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-5-5"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path178"
+           d="M 72.125,0.125 C 58.039062,0.0390625 47.164062,-0.582031 39.5,-1.75 26.164062,-3.832031 16.664062,-7.832031 11,-13.75 5.914062,-18.332031 3.375,-24.582031 3.375,-32.5 c 0,-3.082031 0.289062,-7.5 0.875,-13.25 0.582031,-5.75 1.375,-11.5 2.375,-17.25 0.414062,-2.414062 0.789062,-4.582031 1.125,-6.5 0.25,-1.332031 0.582031,-2.414062 1,-3.25 0.414062,-0.832031 0.875,-1.3125 1.375,-1.4375 0.5,-0.125 0.976562,0.210938 1.4375,1 0.457031,0.792969 0.894531,2.148438 1.3125,4.0625 0.332031,2.085938 0.789062,4.25 1.375,6.5 1.332031,5.417969 4.957031,9.460938 10.875,12.125 15,6.417969 37.914062,9.75 68.75,10 12.75,-0.164062 24.58203,-0.625 35.5,-1.375 11.16406,-0.832031 23.75,-2.789062 37.75,-5.875 14,-3.082031 25.14453,-6.457031 33.4375,-10.125 8.28906,-3.664062 15.35156,-7.625 21.1875,-11.875 4.58203,-3.332031 6.875,-6.539062 6.875,-9.625 0,-1.25 -1.1875,-2.726562 -3.5625,-4.4375 -2.375,-1.707031 -3.9375,-2.5625 -4.6875,-2.5625 -1.41797,0.667969 -3.08594,1.1875 -5,1.5625 -1.91797,0.375 -3.66797,0.480469 -5.25,0.3125 -4.41797,-0.5 -7.71094,-1.875 -9.875,-4.125 -2.16797,-2.25 -3.25,-5.289062 -3.25,-9.125 0,-2.41406 3.20703,-10 9.625,-22.75 2.58203,-5.16406 4.85156,-8.76953 6.8125,-10.8125 1.95703,-2.03906 4.64453,-3.0625 8.0625,-3.0625 5.41406,0 10.4375,2.91797 15.0625,8.75 4.625,5.83594 6.9375,13.29297 6.9375,22.375 0,9 -1.21094,16.792969 -3.625,23.375 -3,9 -7.08594,17.335938 -12.25,25 -6.5,9.25 -13.625,16.5625 -21.375,21.9375 -7.75,5.375 -15.58594,9.648438 -23.5,12.8125 -7.08594,3.5 -16.23047,6.773438 -27.4375,9.8125 -11.21094,3.042969 -24.8125,5.523438 -40.8125,7.4375 -15.835938,1.917969 -29.960938,2.9140625 -42.375,3 z m 82.375,-172 c 0.66406,2.41797 0.64453,4.91797 -0.0625,7.5 -0.71094,2.58594 -2.02344,5.29297 -3.9375,8.125 -1.16797,1.91797 -2.39844,3.64844 -3.6875,5.1875 -1.29297,1.54297 -2.64844,3.02344 -4.0625,4.4375 -0.41797,0.5 -1.08594,1.125 -2,1.875 -0.91797,0.75 -1.875,1.46094 -2.875,2.125 -1,0.66797 -1.96094,1.14844 -2.875,1.4375 -0.91797,0.29297 -1.58594,0.1875 -2,-0.3125 -3,-2.41406 -5.96094,-4.875 -8.875,-7.375 -2.91797,-2.5 -6.125,-4.83203 -9.625,-7 -0.58594,-0.41406 -0.85547,-0.8125 -0.8125,-1.1875 0.0391,-0.375 0.26953,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.58203,-0.83203 1.16406,-1.22656 1.75,-1.1875 0.58203,0.043 1.20703,0.27344 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.60547 4.875,4.0625 1.5,1.46094 2.8125,3.04297 3.9375,4.75 1.125,1.71094 1.9375,3.60547 2.4375,5.6875 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+      <symbol
+         id="glyph0-6-6"
+         overflow="visible"
+         style="overflow:visible">
+        <path
+           id="path181"
+           d="m 115,-102.5 c -1.83594,3.25 -3.75,6.523438 -5.75,9.8125 -2,3.292969 -4.23047,6.398438 -6.6875,9.3125 -2.46094,2.917969 -5.167969,5.5625 -8.125,7.9375 -2.960938,2.375 -6.3125,4.273438 -10.0625,5.6875 -3.085938,1.25 -5.710938,2.648438 -7.875,4.1875 -2.167969,1.542969 -3.960938,3.1875 -5.375,4.9375 -2.167969,2.335938 -4.042969,5.5625 -5.625,9.6875 -1.585938,4.125 -3.230469,8.480469 -4.9375,13.0625 -1.710938,4.585938 -3.585938,9.0625 -5.625,13.4375 -2.042969,4.375 -4.605469,7.980469 -7.6875,10.8125 C 43,-9.125 36.707031,-6.082031 28.375,-4.5 L 5.5,-0.625 C 4.832031,-0.539062 4.019531,-0.476562 3.0625,-0.4375 2.101562,-0.394531 1.414062,-0.414062 1,-0.5 -0.914062,-1.082031 -1.5,-2.351562 -0.75,-4.3125 0,-6.269531 1.957031,-8.25 5.125,-10.25 c 6.414062,-4.25 11.539062,-7.6875 15.375,-10.3125 3.832031,-2.625 6.957031,-4.769531 9.375,-6.4375 2.414062,-1.664062 4.351562,-3.039062 5.8125,-4.125 1.457031,-1.082031 3.019531,-2.289062 4.6875,-3.625 6.75,-5.082031 11.414062,-10.414062 14,-16 1.5,-2.914062 2.875,-5.75 4.125,-8.5 1.25,-2.75 2.5625,-5.457031 3.9375,-8.125 1.375,-2.664062 2.851562,-5.3125 4.4375,-7.9375 1.582031,-2.625 3.414062,-5.269531 5.5,-7.9375 2.164062,-2.664062 5.082031,-5.269531 8.75,-7.8125 3.664062,-2.539062 8.082031,-5.0625 13.25,-7.5625 0.582031,-0.25 1.539062,-0.8125 2.875,-1.6875 1.332031,-0.875 2.95703,-2.26953 4.875,-4.1875 1.91406,-1.91406 4.10156,-4.51953 6.5625,-7.8125 2.45703,-3.28906 5.0625,-7.47656 7.8125,-12.5625 -1,-1 -3.875,-2.375 -8.625,-4.125 -4.75,-1.83203 -9.25,-2.875 -13.5,-3.125 -3.917969,-0.25 -7.148438,0.46094 -9.6875,2.125 -2.542969,1.66797 -4.855469,4.04297 -6.9375,7.125 -2.085938,3.08594 -3.875,4.5 -5.375,4.25 -0.5,-0.25 -0.585938,-1.28906 -0.25,-3.125 0.414062,-1.83203 1,-3.625 1.75,-5.375 3.164062,-7.25 6.75,-12.625 10.75,-16.125 4.082031,-3.58203 8.957031,-5.375 14.625,-5.375 4.08203,0 9.20703,1 15.375,3 3.83203,1.33594 7.125,2 9.875,2 5.75,0 11.45703,-2.03906 17.125,-6.125 1.25,0 1.6875,0.8125 1.3125,2.4375 -0.375,1.625 -0.9375,3.52344 -1.6875,5.6875 -0.66797,2.16797 -1.125,3.625 -1.375,4.375 -1.25,3.91797 -2.25,6.21094 -3,6.875 -0.75,0.58594 -2.91797,2.16797 -6.5,4.75 -2,1.5 -3.73047,3.23047 -5.1875,5.1875 -1.46094,1.96094 -2.9375,4.27344 -4.4375,6.9375 -1.5,2.66797 -3.41797,6.33594 -5.75,11 z m 0,0"
+           style="stroke:none"
+           inkscape:connector-curvature="0" />
+      </symbol>
+    </g>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="2560"
+     inkscape:window-height="1471"
+     id="namedview4"
+     showgrid="false"
+     inkscape:zoom="0.59454973"
+     inkscape:cx="-165.7731"
+     inkscape:cy="361.75575"
+     inkscape:window-x="0"
+     inkscape:window-y="55"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2" />
+  <path
+     id="path871"
+     d="m 205.59223,196.11402 c -5.97657,36.66667 -11.35417,64.02995 -16.14583,82.08333 -4.79167,18.0599 -9.13412,31.84245 -13.02084,41.35417 -3.89323,9.51823 -8.16406,16.77083 -12.8125,21.77083 -4.65495,5 -13.19661,9.75912 -25.625,14.27083 -12.43489,4.51823 -22.8125,7.67579 -31.14583,9.47917 -8.333331,1.8099 -13.541664,2.77995 -15.624997,2.91667 -2.083334,-0.13672 -3.404949,-0.52084 -3.958334,-1.14584 -0.559896,-0.625 -0.07161,-2.11588 1.458334,-4.47916 2.636718,-3.75 8.157551,-8.88672 16.562497,-15.41667 8.39844,-6.52344 18.33333,-14.64844 29.79167,-24.375 11.45833,-9.72005 20.03255,-18.29427 25.72916,-25.72916 5.69011,-7.42839 10.72917,-17.56511 15.10417,-30.41667 4.375,-12.84505 8.64583,-26.28255 12.8125,-40.3125 4.16667,-14.02343 7.1875,-23.54166 9.0625,-28.54166 1.875,-5 3.78255,-7.42839 5.72916,-7.29167 2.22006,0.41667 2.91667,2.36328 2.08334,5.83333 z M 220.38389,81.739028 c 1.10677,4.02995 1.07422,8.196616 -0.10416,12.5 -1.1849,4.309899 -3.3724,8.821612 -6.5625,13.541662 -1.94662,3.19662 -3.9974,6.08074 -6.14584,8.64584 -2.15494,2.57161 -4.41406,5.03906 -6.77083,7.39583 -0.69661,0.83333 -1.8099,1.875 -3.33333,3.125 -1.52995,1.25 -3.125,2.4349 -4.79167,3.54167 -1.66666,1.11328 -3.26823,1.91406 -4.79166,2.39583 -1.52995,0.48828 -2.64323,0.3125 -3.33334,-0.52083 -5,-4.02344 -9.93489,-8.125 -14.79166,-12.29167 -4.86329,-4.16667 -10.20834,-8.05338 -16.04167,-11.66667 -0.97656,-0.6901 -1.42578,-1.35416 -1.35417,-1.97916 0.0651,-0.625 0.44922,-1.5625 1.14584,-2.8125 l 33.33333,-50.833334 c 0.97005,-1.386717 1.9401,-2.044267 2.91667,-1.979167 0.97005,0.07167 2.01171,0.455734 3.125,1.145834 2.91666,1.666666 5.83333,3.541666 8.74999,5.624999 2.91667,2.083334 5.625,4.34245 8.125,6.770833 2.5,2.4349 4.6875,5.071617 6.5625,7.916667 1.875,2.851566 3.22917,6.009116 4.0625,9.479166 z m 0,0"
+     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
+     inkscape:connector-curvature="0" />
+  <path
+     inkscape:connector-curvature="0"
+     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
+     d="m 256.21722,250.48902 c -1.11328,13.89323 -4.23828,25.69662 -9.375,35.41667 -5.14323,9.72656 -10.97656,14.58333 -17.5,14.58333 0,-5.27344 1.69922,-21.66667 5.10417,-49.16667 3.39843,-27.49999 5.97005,-47.18749 7.70833,-59.06249 1.73177,-11.875 3.71094,-24.47917 5.9375,-37.8125 2.22005,-13.33333 4.375,-24.09505 6.45833,-32.29167 2.35677,-6.80338 4.89583,-13.67838 7.60417,-20.625 2.70833,-6.940096 5.52083,-13.815095 8.4375,-20.624995 1.9401,-3.053383 3.1901,-2.5651 3.75,1.458333 -3.47657,23.059902 -6.66667,46.979162 -9.58334,71.770832 -2.91666,24.79166 -4.89583,42.53906 -5.9375,53.22916 -1.04166,10.69662 -1.5625,16.94662 -1.5625,18.75 -0.69661,11.39323 -1.04166,19.51823 -1.04166,24.375 z m 0,0"
+     id="path875" />
+  <path
+     id="path945"
+     d="m 229.34222,300.48902 c 2.08333,-8.88672 4.375,-16.66667 6.875,-23.33333 2.5,-6.66667 4.9349,-12.1875 7.29167,-16.5625 2.36328,-4.375 4.65495,-7.74089 6.875,-10.10417 2.22656,-2.35677 4.16666,-3.75 5.83333,-4.16667 v 13.75 c 0,17.5 4.64844,29.72657 13.95833,36.66667 5.69011,3.75 11.35417,5 16.97917,3.75 5.625,-1.25 9.92838,-4.16667 12.91666,-8.75 2.98177,-4.58333 5.52084,-9.96094 7.60417,-16.14583 2.08333,-6.17839 4.09505,-9.27084 6.04167,-9.27084 2.22005,0 3.125,2.22657 2.70833,6.66667 -0.14323,7.5 -2.46745,19.6875 -6.97917,36.5625 -4.51823,16.875 -10.625,30.72916 -18.33333,41.5625 -7.70833,10.83333 -17.05078,16.52995 -28.02083,17.08333 -11.25,-0.41667 -20,-6.73177 -26.25,-18.95833 -5.6901,-12.08334 -8.1901,-27.70833 -7.5,-46.875 z"
+     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
+     inkscape:connector-curvature="0" />
+  <path
+     id="path943"
+     d="m 286.78334,583.03989 c 1.10677,4.02343 1.07422,8.1901 -0.10416,12.5 -1.1849,4.30338 -3.3724,8.8151 -6.5625,13.54167 -1.94662,3.1901 -3.9974,6.07421 -6.14584,8.64583 -2.15495,2.5651 -4.41406,5.03255 -6.77083,7.39583 -0.69662,0.83334 -1.8099,1.875 -3.33333,3.125 -1.52995,1.25 -3.125,2.42839 -4.79167,3.54167 -1.66667,1.10677 -3.26823,1.90755 -4.79167,2.39583 -1.52994,0.48177 -2.64323,0.3125 -3.33333,-0.52083 -5,-4.02995 -9.9349,-8.125 -14.79167,-12.29167 -4.85677,-4.16666 -10.20833,-8.0599 -16.04166,-11.66666 -0.97005,-0.69662 -1.41927,-1.35417 -1.35417,-1.97917 0.0716,-0.625 0.45573,-1.5625 1.14583,-2.8125 l 33.33334,-50.83333 c 0.97005,-1.39323 1.9401,-2.05078 2.91666,-1.97917 0.97006,0.0652 2.01172,0.44922 3.125,1.14584 2.91667,1.66666 5.83334,3.54166 8.75,5.625 2.91667,2.08333 5.625,4.33593 8.125,6.77083 2.5,2.42838 4.6875,5.0651 6.5625,7.91667 1.875,2.84505 3.22917,6.00259 4.0625,9.47916 z"
+     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
+     inkscape:connector-curvature="0" />
+  <path
+     id="path879"
+     d="M 303.71722,505.07234"
+     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
+     inkscape:connector-curvature="0" />
+  <path
+     inkscape:connector-curvature="0"
+     id="path925"
+     d="m 168.42167,500.82557 c -23.47656,-0.14323 -41.60156,-1.17838 -54.375,-3.125 -22.226562,-3.47005 -38.059894,-10.13671 -47.499997,-20 -8.476563,-7.63671 -12.708333,-18.05338 -12.708333,-31.24999 0,-5.13672 0.48177,-12.5 1.458333,-22.08334 0.970052,-9.58333 2.291667,-19.16666 3.958333,-28.75 0.690104,-4.02343 1.315104,-7.63671 1.875,-10.83333 0.416667,-2.22005 0.970052,-4.02344 1.666667,-5.41667 0.690103,-1.38671 1.458333,-2.1875 2.291666,-2.39583 0.833334,-0.20833 1.627604,0.35156 2.395834,1.66667 0.761718,1.32161 1.490885,3.58073 2.187499,6.77083 0.553385,3.47656 1.315104,7.08333 2.291667,10.83333 2.220052,9.02995 8.261718,15.76823 18.124999,20.20834 25.000002,10.69661 63.190102,16.25 114.583332,16.66666 21.25,-0.27343 40.97005,-1.04166 59.16666,-2.29166 18.60677,-1.38672 39.58333,-4.64844 62.91667,-9.79167 23.33333,-5.13672 41.90754,-10.76172 55.72916,-16.875 13.8151,-6.10677 25.58593,-12.70833 35.3125,-19.79167 7.63671,-5.55338 11.45833,-10.89843 11.45833,-16.04166 0,-2.08333 -1.97917,-4.54427 -5.9375,-7.39583 -3.95833,-2.84506 -6.5625,-4.27084 -7.8125,-4.27084 -2.36328,1.11328 -5.14323,1.97917 -8.33333,2.60417 -3.19662,0.625 -6.11328,0.80078 -8.75,0.52083 -7.36328,-0.83333 -12.85157,-3.125 -16.45833,-6.875 -3.61329,-3.75 -5.41667,-8.8151 -5.41667,-15.20833 0,-4.02343 5.34505,-16.66667 16.04167,-37.91667 4.30338,-8.60676 8.08593,-14.61588 11.35416,-18.02083 3.26172,-3.39843 7.74089,-5.10416 13.4375,-5.10416 9.02343,0 17.39583,4.86328 25.10417,14.58333 7.70833,9.72656 11.5625,22.15495 11.5625,37.29166 0,15 -2.01824,27.98828 -6.04167,38.95834 -5,14.99999 -11.8099,28.89322 -20.41667,41.66666 -10.83333,15.41667 -22.70833,27.60417 -35.62499,36.5625 -12.91667,8.95833 -25.97657,16.08073 -39.16667,21.35416 -11.8099,5.83334 -27.05078,11.28907 -45.72916,16.35417 -18.6849,5.07162 -41.35417,9.20573 -68.02083,12.39583 -26.39323,3.19662 -49.9349,4.85677 -70.625,5 z"
+     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
+  <path
+     inkscape:connector-curvature="0"
+     id="path923"
+     d="m 430.22191,133.16177 c 1.10676,4.02995 1.07421,8.19662 -0.10417,12.5 -1.1849,4.3099 -3.3724,8.82162 -6.5625,13.54167 -1.94661,3.19661 -3.9974,6.08073 -6.14583,8.64583 -2.15495,2.57162 -4.41407,5.03907 -6.77083,7.39583 -0.69662,0.83334 -1.8099,1.875 -3.33334,3.125 -1.52995,1.25 -3.125,2.4349 -4.79166,3.54167 -1.66667,1.11328 -3.26824,1.91407 -4.79167,2.39583 -1.52995,0.48829 -2.64323,0.3125 -3.33333,-0.52083 -5,-4.02343 -9.9349,-8.125 -14.79167,-12.29167 -4.86328,-4.16666 -10.20833,-8.05338 -16.04167,-11.66666 -0.97656,-0.6901 -1.42578,-1.35417 -1.35416,-1.97917 0.0652,-0.625 0.44921,-1.5625 1.14583,-2.8125 l 33.33333,-50.83333 c 0.97005,-1.38672 1.9401,-2.04427 2.91667,-1.97917 0.97005,0.0717 2.01172,0.45574 3.125,1.14584 2.91667,1.66666 5.83333,3.54166 8.75,5.625 2.91667,2.08333 5.625,4.34245 8.125,6.77083 2.5,2.4349 4.6875,5.07162 6.5625,7.91667 1.875,2.85156 3.22916,6.00911 4.0625,9.47916 z"
+     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
+  <path
+     inkscape:connector-curvature="0"
+     id="path883"
+     d="M 305.71333,214.15892"
+     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
+  <path
+     id="path887"
+     d="m 599.12998,319.78391 c -3.0599,5.41667 -6.25,10.8724 -9.58333,16.35417 -3.33334,5.48828 -7.05079,10.66406 -11.14584,15.52083 -4.10156,4.86328 -8.61328,9.27084 -13.54166,13.22917 -4.9349,3.95833 -10.52084,7.12239 -16.77084,9.47916 -5.14323,2.08334 -9.51823,4.41407 -13.125,6.97917 -3.61328,2.57162 -6.60156,5.3125 -8.95833,8.22917 -3.61328,3.89323 -6.73828,9.27083 -9.375,16.14583 -2.64323,6.875 -5.38411,14.13411 -8.22916,21.77083 -2.85157,7.64323 -5.97657,15.10417 -9.375,22.39583 -3.40495,7.29167 -7.67579,13.30079 -12.8125,18.02084 -7.08334,7.5 -17.57162,12.57161 -31.45834,15.20833 l -38.12499,6.45833 c -1.11329,0.14323 -2.46745,0.2474 -4.0625,0.3125 -1.60157,0.0716 -2.7474,0.0391 -3.4375,-0.10416 -3.19011,-0.97005 -4.16667,-3.08594 -2.91667,-6.35417 1.25,-3.26172 4.51172,-6.5625 9.79167,-9.89583 10.6901,-7.08334 19.23177,-12.8125 25.625,-17.1875 6.38671,-4.375 11.59505,-7.94922 15.62499,-10.72917 4.02344,-2.77343 7.25261,-5.0651 9.6875,-6.875 2.42839,-1.80338 5.03256,-3.8151 7.8125,-6.04166 11.25,-8.47006 19.02344,-17.35677 23.33334,-26.66667 2.5,-4.85677 4.79166,-9.58333 6.875,-14.16667 2.08333,-4.58333 4.27083,-9.09505 6.5625,-13.54166 2.29166,-4.44011 4.7526,-8.85417 7.39583,-13.22917 2.63672,-4.375 5.6901,-8.78255 9.16667,-13.22916 3.60677,-4.44011 8.47005,-8.78256 14.58333,-13.02084 6.10677,-4.23177 13.47005,-8.4375 22.08333,-12.60416 0.97005,-0.41667 2.5651,-1.35417 4.79167,-2.8125 2.22005,-1.45834 4.92838,-3.78255 8.125,-6.97917 3.1901,-3.1901 6.83593,-7.53255 10.9375,-13.02083 4.09505,-5.48177 8.4375,-12.46094 13.02083,-20.9375 -1.66667,-1.66667 -6.45833,-3.95833 -14.375,-6.875 -7.91667,-3.05338 -15.41667,-4.79167 -22.5,-5.20833 -6.52995,-0.41667 -11.91406,0.76823 -16.14583,3.54166 -4.23828,2.77995 -8.09245,6.73829 -11.5625,11.875 -3.47657,5.14323 -6.45833,7.5 -8.95833,7.08333 -0.83334,-0.41666 -0.97657,-2.14843 -0.41667,-5.20833 0.6901,-3.05338 1.66667,-6.04166 2.91667,-8.95833 5.27343,-12.08333 11.24999,-21.04167 17.91666,-26.875 6.80339,-5.97005 14.92839,-8.95833 24.375,-8.95833 6.80338,0 15.34505,1.66666 25.625,5 6.38672,2.22656 11.875,3.33333 16.45833,3.33333 9.58333,0 19.09505,-3.39843 28.54167,-10.20833 2.08333,0 2.8125,1.35416 2.1875,4.0625 -0.625,2.70833 -1.5625,5.8724 -2.8125,9.47916 -1.11329,3.61329 -1.875,6.04167 -2.29167,7.29167 -2.08333,6.52995 -3.75,10.35157 -5,11.45833 -1.25,0.97657 -4.86328,3.61329 -10.83333,7.91667 -3.33334,2.5 -6.21745,5.38411 -8.64584,8.64583 -2.43489,3.26823 -4.89583,7.1224 -7.39583,11.5625 -2.5,4.44662 -5.69661,10.5599 -9.58333,18.33333 z m 0,0"
+     style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
+     inkscape:connector-curvature="0" />
+  <use
+     style="fill:#000000;fill-opacity:1"
+     id="use62"
+     y="291"
+     x="119.25"
+     xlink:href="#glyph0-4"
+     width="100%"
+     height="100%"
+     transform="matrix(1.3333333,0,0,1.3333333,72.589732,-189.32751)" />
+  <use
+     style="fill:#000000;fill-opacity:1"
+     id="use196"
+     y="391"
+     x="168.375"
+     xlink:href="#glyph0-4-3"
+     width="100%"
+     height="100%"
+     transform="matrix(1.3333333,0,0,1.3333333,-861.41828,-631.73483)" />
+</svg>
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 3916801..79934d5 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -67,7 +67,8 @@
 # Images to copy into HTML directory.
 # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
 HTML_IMAGES=  \
-	HarfBuzz.png
+	HarfBuzz.png \
+	HarfBuzz.svg
 
 # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
 # e.g. content_files=running.sgml building.sgml changes-2.0.sgml
diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml
index 00113e9..9452a92 100644
--- a/docs/harfbuzz-docs.xml
+++ b/docs/harfbuzz-docs.xml
@@ -22,7 +22,7 @@
         source tree is available
         <ulink url="http://cgit.freedesktop.org/harfbuzz/">here</ulink>.
         Also available on
-        <ulink url="https://github.com/behdad/harfbuzz">github</ulink>.
+        <ulink url="https://github.com/harfbuzz/harfbuzz">github</ulink>.
         See <xref linkend="download" endterm="download.title"/> for release tarballs.
       </para>
       <para>
@@ -60,7 +60,7 @@
     </partinfo>
     <title>Reference manual</title>
       <chapter>
-        <title>Harfbuzz API</title>
+        <title>HarfBuzz API</title>
         <xi:include href="xml/hb.xml"/>
         <xi:include href="xml/hb-common.xml"/>
         <xi:include href="xml/hb-unicode.xml"/>
@@ -184,6 +184,22 @@
         <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-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-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-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-6-0" role="1.6.0">
+        <title>Index of new symbols in 1.6.0</title>
+        <xi:include href="xml/api-index-1.6.0.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>
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index a91eb4c..51ee56d 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -41,6 +41,7 @@
 hb_buffer_add_utf16
 hb_buffer_add_utf8
 hb_buffer_add_latin1
+hb_buffer_append
 hb_buffer_set_content_type
 hb_buffer_get_content_type
 hb_buffer_set_direction
@@ -77,9 +78,12 @@
 hb_buffer_serialize_list_formats
 hb_segment_properties_equal
 hb_segment_properties_hash
+hb_buffer_diff
 hb_buffer_set_message_func
 hb_buffer_t
+hb_glyph_info_get_glyph_flags
 hb_glyph_info_t
+hb_glyph_flags_t
 hb_glyph_position_t
 hb_buffer_content_type_t
 hb_buffer_flags_t
@@ -87,6 +91,7 @@
 hb_segment_properties_t
 hb_buffer_serialize_format_t
 hb_buffer_serialize_flags_t
+hb_buffer_diff_flags_t
 hb_buffer_message_func_t
 </SECTION>
 
@@ -146,10 +151,12 @@
 HB_SCRIPT_CANADIAN_ABORIGINAL
 hb_font_funcs_set_glyph_func
 hb_font_get_glyph_func_t
+hb_set_invert
 </SECTION>
 
 <SECTION>
 <FILE>hb-coretext</FILE>
+HB_CORETEXT_TAG_KERX
 HB_CORETEXT_TAG_MORT
 HB_CORETEXT_TAG_MORX
 hb_coretext_face_create
@@ -163,6 +170,7 @@
 hb_face_create_for_tables
 hb_face_destroy
 hb_face_get_empty
+hb_face_get_table_tags
 hb_face_get_glyph_count
 hb_face_get_index
 hb_face_get_upem
@@ -241,6 +249,7 @@
 hb_font_get_nominal_glyph_func_t
 hb_font_get_parent
 hb_font_get_ppem
+hb_font_get_ptem
 hb_font_get_scale
 hb_font_get_user_data
 hb_font_get_variation_glyph
@@ -251,10 +260,12 @@
 hb_font_is_immutable
 hb_font_make_immutable
 hb_font_reference
+hb_font_set_face
 hb_font_set_funcs
 hb_font_set_funcs_data
 hb_font_set_parent
 hb_font_set_ppem
+hb_font_set_ptem
 hb_font_set_scale
 hb_font_set_user_data
 hb_variation_t
@@ -283,6 +294,7 @@
 hb_ft_face_create_referenced
 hb_ft_font_create
 hb_ft_font_create_referenced
+hb_ft_font_changed
 hb_ft_font_get_face
 hb_ft_font_set_load_flags
 hb_ft_font_get_load_flags
@@ -302,6 +314,7 @@
 HB_GOBJECT_TYPE_BLOB
 HB_GOBJECT_TYPE_BUFFER
 HB_GOBJECT_TYPE_BUFFER_CONTENT_TYPE
+HB_GOBJECT_TYPE_BUFFER_DIFF_FLAGS
 HB_GOBJECT_TYPE_BUFFER_FLAGS
 HB_GOBJECT_TYPE_BUFFER_SERIALIZE_FLAGS
 HB_GOBJECT_TYPE_BUFFER_SERIALIZE_FORMAT
@@ -309,6 +322,7 @@
 HB_GOBJECT_TYPE_FACE
 HB_GOBJECT_TYPE_FONT
 HB_GOBJECT_TYPE_FONT_FUNCS
+HB_GOBJECT_TYPE_GLYPH_FLAGS
 HB_GOBJECT_TYPE_MEMORY_MODE
 HB_GOBJECT_TYPE_OT_LAYOUT_GLYPH_CLASS
 HB_GOBJECT_TYPE_OT_MATH_CONSTANT
@@ -328,6 +342,7 @@
 HB_GOBJECT_TYPE_USER_DATA_KEY
 hb_gobject_blob_get_type
 hb_gobject_buffer_content_type_get_type
+hb_gobject_buffer_diff_flags_get_type
 hb_gobject_buffer_flags_get_type
 hb_gobject_buffer_get_type
 hb_gobject_buffer_serialize_flags_get_type
@@ -336,6 +351,7 @@
 hb_gobject_face_get_type
 hb_gobject_font_funcs_get_type
 hb_gobject_font_get_type
+hb_gobject_glyph_flags_get_type
 hb_gobject_memory_mode_get_type
 hb_gobject_ot_layout_glyph_class_get_type
 hb_gobject_ot_math_constant_get_type
@@ -503,7 +519,6 @@
 hb_set_get_user_data
 hb_set_has
 hb_set_intersect
-hb_set_invert
 hb_set_is_empty
 hb_set_is_equal
 hb_set_next
diff --git a/docs/usermanual-buffers-language-script-and-direction.xml b/docs/usermanual-buffers-language-script-and-direction.xml
index 3a26c55..9eddb71 100644
--- a/docs/usermanual-buffers-language-script-and-direction.xml
+++ b/docs/usermanual-buffers-language-script-and-direction.xml
@@ -1,7 +1,7 @@
 <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 HarfBuzz 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.
@@ -15,7 +15,7 @@
       default values and ready to accept your Unicode strings.
     </para>
     <para>
-      Harfbuzz manages the memory of objects that it creates (such as
+      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>:
     </para>
@@ -27,7 +27,7 @@
     <para>
       This will destroy the object and free its associated memory -
       unless some other part of the program holds a reference to this
-      buffer. If you acquire a Harfbuzz buffer from another subsystem
+      buffer. If you acquire a HarfBuzz buffer from another subsystem
       and want to ensure that it is not garbage collected by someone
       else destroying it, you should increase its reference count:
     </para>
@@ -53,8 +53,8 @@
   <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
+      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)
     </para>
diff --git a/docs/usermanual-fonts-and-faces.xml b/docs/usermanual-fonts-and-faces.xml
index 01fcdc9..7de0f05 100644
--- a/docs/usermanual-fonts-and-faces.xml
+++ b/docs/usermanual-fonts-and-faces.xml
@@ -6,7 +6,7 @@
     </para>
   </section>
   <section id="using-harfbuzzs-native-opentype-implementation">
-    <title>Using Harfbuzz's native OpenType implementation</title>
+    <title>Using HarfBuzz's native OpenType implementation</title>
     <para>
     </para>
   </section>
diff --git a/docs/usermanual-hello-harfbuzz.xml b/docs/usermanual-hello-harfbuzz.xml
index 34db017..716b2f2 100644
--- a/docs/usermanual-hello-harfbuzz.xml
+++ b/docs/usermanual-hello-harfbuzz.xml
@@ -1,7 +1,7 @@
 <chapter id="hello-harfbuzz">
-  <title>Hello, Harfbuzz</title>
+  <title>Hello, HarfBuzz</title>
   <para>
-    Here's the simplest Harfbuzz that can possibly work. We will improve
+    Here's the simplest HarfBuzz that can possibly work. We will improve
     it later.
   </para>
   <orderedlist numeration="arabic">
@@ -91,23 +91,23 @@
   hb_font_destroy(hb_ft_font);
 </programlisting>
   <section id="what-harfbuzz-doesnt-do">
-    <title>What Harfbuzz doesn't do</title>
+    <title>What HarfBuzz doesn't do</title>
     <para>
       The code above will take a UTF8 string, shape it, and give you the
       information required to lay it out correctly on a single
       horizontal (or vertical) line using the font provided. That is the
-      extent of Harfbuzz's responsibility.
+      extent of HarfBuzz's responsibility.
     </para>
     <para>
       If you are implementing a text layout engine you may have other
-      responsibilities, that Harfbuzz will not help you with:
+      responsibilities, that HarfBuzz will not help you with:
     </para>
     <itemizedlist>
       <listitem>
         <para>
-          Harfbuzz won't help you with bidirectionality. If you want to
+          HarfBuzz won't help you with bidirectionality. If you want to
           lay out text with mixed Hebrew and English, you will need to
-          ensure that the buffer provided to Harfbuzz has those
+          ensure that the buffer provided to HarfBuzz has those
           characters in the correct layout order. This will be different
           from the logical order in which the Unicode text is stored. In
           other words, the user will hit the keys in the following
@@ -127,30 +127,30 @@
           (&quot;bidi&quot; is short for bidirectional), and there's an
           algorithm as an annex to the Unicode Standard which tells you how
           to reorder a string from logical order into presentation order.
-          Before sending your string to Harfbuzz, you may need to apply the
+          Before sending your string to HarfBuzz, you may need to apply the
           bidi algorithm to it. Libraries such as ICU and fribidi can do
           this for you.
         </para>
       </listitem>
       <listitem>
         <para>
-          Harfbuzz won't help you with text that contains different font
+          HarfBuzz won't help you with text that contains different font
           properties. For instance, if you have the string &quot;a
           <emphasis>huge</emphasis> breakfast&quot;, and you expect
           &quot;huge&quot; to be italic, you will need to send three
-          strings to Harfbuzz: <literal>a</literal>, in your Roman font;
+          strings to HarfBuzz: <literal>a</literal>, in your Roman font;
           <literal>huge</literal> using your italic font; and
           <literal>breakfast</literal> using your Roman font again.
           Similarly if you change font, font size, script, language or
           direction within your string, you will need to shape each run
-          independently and then output them independently. Harfbuzz
+          independently and then output them independently. HarfBuzz
           expects to shape a run of characters sharing the same
           properties.
         </para>
       </listitem>
       <listitem>
         <para>
-          Harfbuzz won't help you with line breaking, hyphenation or
+          HarfBuzz won't help you with line breaking, hyphenation or
           justification. As mentioned above, it lays out the string
           along a <emphasis>single line</emphasis> of, notionally,
           infinite length. If you want to find out where the potential
@@ -158,12 +158,12 @@
           could use the ICU library's break iterator functions.
         </para>
         <para>
-          Harfbuzz can tell you how wide a shaped piece of text is, which is
+          HarfBuzz can tell you how wide a shaped piece of text is, which is
           useful input to a justification algorithm, but it knows nothing
           about paragraphs, lines or line lengths. Nor will it adjust the
           space between words to fit them proportionally into a line. If you
           want to layout text in paragraphs, you will probably want to send
-          each word of your text to Harfbuzz to determine its shaped width
+          each word of your text to HarfBuzz to determine its shaped width
           after glyph substitutions, then work out how many words will fit
           on a line, and then finally output each word of the line separated
           by a space of the correct size to fully justify the paragraph.
@@ -171,12 +171,12 @@
       </listitem>
     </itemizedlist>
     <para>
-      As a layout engine implementor, Harfbuzz will help you with the
+      As a layout engine implementor, HarfBuzz will help you with the
       interface between your text and your font, and that's something
       that you'll need - what you then do with the glyphs that your font
       returns is up to you. The example we saw above enough to get us
-      started using Harfbuzz. Now we are going to use the remainder of
-      Harfbuzz's API to refine that example and improve our text shaping
+      started using HarfBuzz. Now we are going to use the remainder of
+      HarfBuzz's API to refine that example and improve our text shaping
       capabilities.
     </para>
   </section>
diff --git a/docs/usermanual-install-harfbuzz.xml b/docs/usermanual-install-harfbuzz.xml
index be8ac8d..37450d0 100644
--- a/docs/usermanual-install-harfbuzz.xml
+++ b/docs/usermanual-install-harfbuzz.xml
@@ -1,5 +1,5 @@
 <chapter id="install-harfbuzz">
-  <title>Install Harfbuzz</title>
+  <title>Install HarfBuzz</title>
   <section id="download">
     <title id="download.title">Download</title>
     <para>
@@ -12,7 +12,7 @@
     <para>
       The canonical source tree is available
       <ulink url="http://cgit.freedesktop.org/harfbuzz/">here</ulink>.
-      Also available on <ulink url="https://github.com/behdad/harfbuzz">github</ulink>.
+      Also available on <ulink url="https://github.com/harfbuzz/harfbuzz">github</ulink>.
     </para>
     <para>
       The API that comes with <filename class='headerfile'>hb.h</filename> will
diff --git a/docs/usermanual-what-is-harfbuzz.xml b/docs/usermanual-what-is-harfbuzz.xml
index 3574d75..38f40cf 100644
--- a/docs/usermanual-what-is-harfbuzz.xml
+++ b/docs/usermanual-what-is-harfbuzz.xml
@@ -1,7 +1,7 @@
 <chapter id="what-is-harfbuzz">
-  <title>What is Harfbuzz?</title>
+  <title>What is HarfBuzz?</title>
   <para>
-    Harfbuzz is a <emphasis>text shaping engine</emphasis>. It solves
+    HarfBuzz is a <emphasis>text shaping engine</emphasis>. It solves
     the problem of selecting and positioning glyphs from a font given a
     Unicode string.
   </para>
@@ -9,17 +9,17 @@
     <title>Why do I need it?</title>
     <para>
       Text shaping is an integral part of preparing text for display. It
-      is a fairly low level operation; Harfbuzz is used directly by
+      is a fairly low level operation; HarfBuzz is used directly by
       graphic rendering libraries such as Pango, and the layout engines
       in Firefox, LibreOffice and Chromium. Unless you are
       <emphasis>writing</emphasis> one of these layout engines yourself,
-      you will probably not need to use Harfbuzz - normally higher level
+      you will probably not need to use HarfBuzz - normally higher level
       libraries will turn text into glyphs for you.
     </para>
     <para>
       However, if you <emphasis>are</emphasis> writing a layout engine
       or graphics library yourself, you will need to perform text
-      shaping, and this is where Harfbuzz can help you. Here are some
+      shaping, and this is where HarfBuzz can help you. Here are some
       reasons why you need it:
     </para>
     <itemizedlist>
@@ -95,20 +95,20 @@
     <para>
       If this is something that you need to do, then you need a text
       shaping engine: you could use Uniscribe if you are using Windows;
-      you could use CoreText on OS X; or you could use Harfbuzz. In the
+      you could use CoreText on OS X; or you could use HarfBuzz. In the
       rest of this manual, we are going to assume that you are the
       implementor of a text layout engine.
     </para>
   </section>
   <section id="why-is-it-called-harfbuzz">
-    <title>Why is it called Harfbuzz?</title>
+    <title>Why is it called HarfBuzz?</title>
     <para>
-      Harfbuzz began its life as text shaping code within the FreeType
+      HarfBuzz began its life as text shaping code within the FreeType
       project, (and you will see references to the FreeType authors
       within the source code copyright declarations) but was then
       abstracted out to its own project. This project is maintained by
-      Behdad Esfahbod, and named Harfbuzz. Originally, it was a shaping
-      engine for OpenType fonts - &quot;Harfbuzz&quot; is the Persian
+      Behdad Esfahbod, and named HarfBuzz. Originally, it was a shaping
+      engine for OpenType fonts - &quot;HarfBuzz&quot; is the Persian
       for &quot;open type&quot;.
     </para>
   </section>
diff --git a/git.mk b/git.mk
index bd39ae1..6e2708f 100644
--- a/git.mk
+++ b/git.mk
@@ -48,7 +48,7 @@
 #
 # This file knows how to handle autoconf, automake, libtool, gtk-doc,
 # gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu, appdata,
-# appstream.
+# appstream, hotdoc.
 #
 # This makefile provides the following targets:
 #
@@ -86,6 +86,7 @@
 		ar-lib \
 		compile \
 		config.guess \
+		config.rpath \
 		config.sub \
 		depcomp \
 		install-sh \
@@ -120,6 +121,47 @@
 			lt~obsolete.m4 \
 		; do echo "$$MACRO_DIR/$$x"; done; \
 	 fi`
+#
+# Modules that use gettext and use  AC_CONFIG_MACRO_DIR() may also include this,
+# though it's harmless to include regardless.
+GITIGNORE_MAINTAINERCLEANFILES_M4_GETTEXT = \
+	`MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \
+	if test "x$$MACRO_DIR" != "x$(srcdir)/"; then	\
+		for x in				\
+			codeset.m4			\
+			extern-inline.m4		\
+			fcntl-o.m4			\
+			gettext.m4			\
+			glibc2.m4			\
+			glibc21.m4			\
+			iconv.m4			\
+			intdiv0.m4			\
+			intl.m4				\
+			intldir.m4			\
+			intlmacosx.m4			\
+			intmax.m4			\
+			inttypes-pri.m4			\
+			inttypes_h.m4			\
+			lcmessage.m4			\
+			lib-ld.m4			\
+			lib-link.m4			\
+			lib-prefix.m4			\
+			lock.m4				\
+			longlong.m4			\
+			nls.m4				\
+			po.m4				\
+			printf-posix.m4			\
+			progtest.m4			\
+			size_max.m4			\
+			stdint_h.m4			\
+			threadlib.m4			\
+			uintmax_t.m4			\
+			visibility.m4			\
+			wchar_t.m4			\
+			wint_t.m4			\
+			xsize.m4			\
+		; do echo "$$MACRO_DIR/$$x"; done; \
+	fi`
 
 
 
@@ -208,6 +250,15 @@
 				"*/*.omf.out" \
 			; do echo /$$x; done; \
 		fi; \
+		if test "x$(HOTDOC)" = x; then :; else \
+			$(foreach project, $(HOTDOC_PROJECTS),echo "/$(call HOTDOC_TARGET,$(project))"; \
+				echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-conf-path output)" ; \
+				echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-private-folder)" ; \
+			) \
+			for x in \
+				.hotdoc.d \
+			; do echo "/$$x"; done; \
+		fi; \
 		if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \
 			for lc in $(HELP_LINGUAS); do \
 				for x in \
@@ -235,6 +286,7 @@
 		fi; \
 		if test -f $(srcdir)/po/Makefile.in.in; then \
 			for x in \
+				ABOUT-NLS \
 				po/Makefile.in.in \
 				po/Makefile.in.in~ \
 				po/Makefile.in \
@@ -243,6 +295,7 @@
 				po/POTFILES \
 				po/Rules-quot \
 				po/stamp-it \
+				po/stamp-po \
 				po/.intltool-merge-cache \
 				"po/*.gmo" \
 				"po/*.header" \
@@ -274,7 +327,7 @@
 		if test "x$(am__dirstamp)" = x; then :; else \
 			echo "$(am__dirstamp)"; \
 		fi; \
-		if test "x$(LTCOMPILE)" = x -a "x$(LTCXXCOMPILE)" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
+		if test "x$(findstring libtool,$(LTCOMPILE))" = x -a "x$(findstring libtool,$(LTCXXCOMPILE))" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
 			for x in \
 				"*.lo" \
 				".libs" "_libs" \
diff --git a/harfbuzz.doap b/harfbuzz.doap
index d2896eb..0769969 100644
--- a/harfbuzz.doap
+++ b/harfbuzz.doap
@@ -13,7 +13,7 @@
   <!--download-page
   rdf:resource=""/-->
   <bug-database
-  rdf:resource="http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz"/>
+  rdf:resource="https://github.com/harfbuzz/harfbuzz/issues" />
 
   <maintainer>
     <foaf:Person>
diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4
new file mode 100644
index 0000000..5032bba
--- /dev/null
+++ b/m4/ax_cxx_compile_stdcxx.m4
@@ -0,0 +1,982 @@
+# ===========================================================================
+#  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the specified
+#   version of the C++ standard.  If necessary, add switches to CXX and
+#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)
+#   or '14' (for the C++14 standard).
+#
+#   The second argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The third argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline support for the specified C++ standard is
+#   required and that the macro should error out if no mode with that
+#   support is found.  If specified 'optional', then configuration proceeds
+#   regardless, after defining HAVE_CXX${VERSION} if and only if a
+#   supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+#   Copyright (c) 2015 Paul Norman <penorman@mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+#   Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 7
+
+dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl  (serial version number 13).
+
+AX_REQUIRE_DEFINED([AC_MSG_WARN])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+  m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
+        [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
+        [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$2], [], [],
+        [$2], [ext], [],
+        [$2], [noext], [],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+  AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+  ax_cv_cxx_compile_cxx$1,
+  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+    [ax_cv_cxx_compile_cxx$1=yes],
+    [ax_cv_cxx_compile_cxx$1=no])])
+  if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+    ac_success=yes
+  fi
+
+  m4_if([$2], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      switch="-std=gnu++${alternative}"
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                     $cachevar,
+        [ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXX="$ac_save_CXX"])
+      if eval test x\$$cachevar = xyes; then
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$2], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    dnl HP's aCC needs +std=c++11 according to:
+    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+    dnl Cray's crayCC needs "-h std=c++11"
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+        cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+        AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                       $cachevar,
+          [ac_save_CXX="$CXX"
+           CXX="$CXX $switch"
+           AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+            [eval $cachevar=yes],
+            [eval $cachevar=no])
+           CXX="$ac_save_CXX"])
+        if eval test x\$$cachevar = xyes; then
+          CXX="$CXX $switch"
+          if test -n "$CXXCPP" ; then
+            CXXCPP="$CXXCPP $switch"
+          fi
+          ac_success=yes
+          break
+        fi
+      done
+      if test x$ac_success = xyes; then
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+    fi
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX$1=0
+    AC_MSG_NOTICE([No compiler with C++$1 support was found])
+  else
+    HAVE_CXX$1=1
+    AC_DEFINE(HAVE_CXX$1,1,
+              [define if the compiler supports basic C++$1 syntax])
+  fi
+  AC_SUBST(HAVE_CXX$1)
+  m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])])
+])
+
+
+dnl  Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl  Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+)
+
+dnl  Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+]])
+
+
+dnl  Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+  namespace test_polymorphic_lambdas
+  {
+
+    int
+    test()
+    {
+      const auto lambda = [](auto&&... args){
+        const auto istiny = [](auto x){
+          return (sizeof(x) == 1UL) ? 1 : 0;
+        };
+        const int aretiny[] = { istiny(args)... };
+        return aretiny[0];
+      };
+      return lambda(1, 1L, 1.0f, '1');
+    }
+
+  }
+
+  namespace test_binary_literals
+  {
+
+    constexpr auto ivii = 0b0000000000101010;
+    static_assert(ivii == 42, "wrong value");
+
+  }
+
+  namespace test_generalized_constexpr
+  {
+
+    template < typename CharT >
+    constexpr unsigned long
+    strlen_c(const CharT *const s) noexcept
+    {
+      auto length = 0UL;
+      for (auto p = s; *p; ++p)
+        ++length;
+      return length;
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("x") == 1UL, "");
+    static_assert(strlen_c("test") == 4UL, "");
+    static_assert(strlen_c("another\0test") == 7UL, "");
+
+  }
+
+  namespace test_lambda_init_capture
+  {
+
+    int
+    test()
+    {
+      auto x = 0;
+      const auto lambda1 = [a = x](int b){ return a + b; };
+      const auto lambda2 = [a = lambda1(x)](){ return a; };
+      return lambda2();
+    }
+
+  }
+
+  namespace test_digit_separators
+  {
+
+    constexpr auto ten_million = 100'000'000;
+    static_assert(ten_million == 100000000, "");
+
+  }
+
+  namespace test_return_type_deduction
+  {
+
+    auto f(int& x) { return x; }
+    decltype(auto) g(int& x) { return x; }
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static constexpr auto value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static constexpr auto value = true;
+    };
+
+    int
+    test()
+    {
+      auto x = 0;
+      static_assert(is_same<int, decltype(f(x))>::value, "");
+      static_assert(is_same<int&, decltype(g(x))>::value, "");
+      return x;
+    }
+
+  }
+
+}  // namespace cxx14
+
+#endif  // __cplusplus >= 201402L
+
+]])
+
+
+dnl  Tests for new features in C++17
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
+
+// If the compiler admits that it is not ready for C++17, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus <= 201402L
+
+#error "This is not a C++17 compiler"
+
+#else
+
+#if defined(__clang__)
+  #define REALLY_CLANG
+#else
+  #if defined(__GNUC__)
+    #define REALLY_GCC
+  #endif
+#endif
+
+#include <initializer_list>
+#include <utility>
+#include <type_traits>
+
+namespace cxx17
+{
+
+#if !defined(REALLY_CLANG)
+  namespace test_constexpr_lambdas
+  {
+
+    // TODO: test it with clang++ from git
+
+    constexpr int foo = [](){return 42;}();
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+  namespace test::nested_namespace::definitions
+  {
+
+  }
+
+  namespace test_fold_expression
+  {
+
+    template<typename... Args>
+    int multiply(Args... args)
+    {
+      return (args * ... * 1);
+    }
+
+    template<typename... Args>
+    bool all(Args... args)
+    {
+      return (args && ...);
+    }
+
+  }
+
+  namespace test_extended_static_assert
+  {
+
+    static_assert (true);
+
+  }
+
+  namespace test_auto_brace_init_list
+  {
+
+    auto foo = {5};
+    auto bar {5};
+
+    static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
+    static_assert(std::is_same<int, decltype(bar)>::value);
+  }
+
+  namespace test_typename_in_template_template_parameter
+  {
+
+    template<template<typename> typename X> struct D;
+
+  }
+
+  namespace test_fallthrough_nodiscard_maybe_unused_attributes
+  {
+
+    int f1()
+    {
+      return 42;
+    }
+
+    [[nodiscard]] int f2()
+    {
+      [[maybe_unused]] auto unused = f1();
+
+      switch (f1())
+      {
+      case 17:
+        f1();
+        [[fallthrough]];
+      case 42:
+        f1();
+      }
+      return f1();
+    }
+
+  }
+
+  namespace test_extended_aggregate_initialization
+  {
+
+    struct base1
+    {
+      int b1, b2 = 42;
+    };
+
+    struct base2
+    {
+      base2() {
+        b3 = 42;
+      }
+      int b3;
+    };
+
+    struct derived : base1, base2
+    {
+        int d;
+    };
+
+    derived d1 {{1, 2}, {}, 4};  // full initialization
+    derived d2 {{}, {}, 4};      // value-initialized bases
+
+  }
+
+  namespace test_general_range_based_for_loop
+  {
+
+    struct iter
+    {
+      int i;
+
+      int& operator* ()
+      {
+        return i;
+      }
+
+      const int& operator* () const
+      {
+        return i;
+      }
+
+      iter& operator++()
+      {
+        ++i;
+        return *this;
+      }
+    };
+
+    struct sentinel
+    {
+      int i;
+    };
+
+    bool operator== (const iter& i, const sentinel& s)
+    {
+      return i.i == s.i;
+    }
+
+    bool operator!= (const iter& i, const sentinel& s)
+    {
+      return !(i == s);
+    }
+
+    struct range
+    {
+      iter begin() const
+      {
+        return {0};
+      }
+
+      sentinel end() const
+      {
+        return {5};
+      }
+    };
+
+    void f()
+    {
+      range r {};
+
+      for (auto i : r)
+      {
+        [[maybe_unused]] auto v = i;
+      }
+    }
+
+  }
+
+  namespace test_lambda_capture_asterisk_this_by_value
+  {
+
+    struct t
+    {
+      int i;
+      int foo()
+      {
+        return [*this]()
+        {
+          return i;
+        }();
+      }
+    };
+
+  }
+
+  namespace test_enum_class_construction
+  {
+
+    enum class byte : unsigned char
+    {};
+
+    byte foo {42};
+
+  }
+
+  namespace test_constexpr_if
+  {
+
+    template <bool cond>
+    int f ()
+    {
+      if constexpr(cond)
+      {
+        return 13;
+      }
+      else
+      {
+        return 42;
+      }
+    }
+
+  }
+
+  namespace test_selection_statement_with_initializer
+  {
+
+    int f()
+    {
+      return 13;
+    }
+
+    int f2()
+    {
+      if (auto i = f(); i > 0)
+      {
+        return 3;
+      }
+
+      switch (auto i = f(); i + 4)
+      {
+      case 17:
+        return 2;
+
+      default:
+        return 1;
+      }
+    }
+
+  }
+
+#if !defined(REALLY_CLANG)
+  namespace test_template_argument_deduction_for_class_templates
+  {
+
+    // TODO: test it with clang++ from git
+
+    template <typename T1, typename T2>
+    struct pair
+    {
+      pair (T1 p1, T2 p2)
+        : m1 {p1},
+          m2 {p2}
+      {}
+
+      T1 m1;
+      T2 m2;
+    };
+
+    void f()
+    {
+      [[maybe_unused]] auto p = pair{13, 42u};
+    }
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+  namespace test_non_type_auto_template_parameters
+  {
+
+    template <auto n>
+    struct B
+    {};
+
+    B<5> b1;
+    B<'a'> b2;
+
+  }
+
+#if !defined(REALLY_CLANG)
+  namespace test_structured_bindings
+  {
+
+    // TODO: test it with clang++ from git
+
+    int arr[2] = { 1, 2 };
+    std::pair<int, int> pr = { 1, 2 };
+
+    auto f1() -> int(&)[2]
+    {
+      return arr;
+    }
+
+    auto f2() -> std::pair<int, int>&
+    {
+      return pr;
+    }
+
+    struct S
+    {
+      int x1 : 2;
+      volatile double y1;
+    };
+
+    S f3()
+    {
+      return {};
+    }
+
+    auto [ x1, y1 ] = f1();
+    auto& [ xr1, yr1 ] = f1();
+    auto [ x2, y2 ] = f2();
+    auto& [ xr2, yr2 ] = f2();
+    const auto [ x3, y3 ] = f3();
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+#if !defined(REALLY_CLANG)
+  namespace test_exception_spec_type_system
+  {
+
+    // TODO: test it with clang++ from git
+
+    struct Good {};
+    struct Bad {};
+
+    void g1() noexcept;
+    void g2();
+
+    template<typename T>
+    Bad
+    f(T*, T*);
+
+    template<typename T1, typename T2>
+    Good
+    f(T1*, T2*);
+
+    static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+  namespace test_inline_variables
+  {
+
+    template<class T> void f(T)
+    {}
+
+    template<class T> inline T g(T)
+    {
+      return T{};
+    }
+
+    template<> inline void f<>(int)
+    {}
+
+    template<> int g<>(int)
+    {
+      return 5;
+    }
+
+  }
+
+}  // namespace cxx17
+
+#endif  // __cplusplus <= 201402L
+
+]])
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
index d90de34..5fbf9fe 100644
--- a/m4/ax_pthread.m4
+++ b/m4/ax_pthread.m4
@@ -1,5 +1,5 @@
 # ===========================================================================
-#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+#        https://www.gnu.org/software/autoconf-archive/ax_pthread.html
 # ===========================================================================
 #
 # SYNOPSIS
@@ -19,10 +19,10 @@
 #   is necessary on AIX to use the special cc_r compiler alias.)
 #
 #   NOTE: You are assumed to not only compile your program with these flags,
-#   but also link it with them as well. e.g. you should link with
+#   but also to link with them as well. For example, you might link with
 #   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
 #
-#   If you are only building threads programs, you may wish to use these
+#   If you are only building threaded programs, you may wish to use these
 #   variables in your default LIBS, CFLAGS, and CC:
 #
 #     LIBS="$PTHREAD_LIBS $LIBS"
@@ -30,8 +30,8 @@
 #     CC="$PTHREAD_CC"
 #
 #   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
-#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
-#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#   has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
+#   that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
 #
 #   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
 #   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
@@ -67,7 +67,7 @@
 #   Public License for more details.
 #
 #   You should have received a copy of the GNU General Public License along
-#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#   with this program. If not, see <https://www.gnu.org/licenses/>.
 #
 #   As a special exception, the respective Autoconf Macro's copyright owner
 #   gives unlimited permission to copy, distribute and modify the configure
@@ -82,35 +82,40 @@
 #   modified version of the Autoconf Macro, you may extend this special
 #   exception to the GPL to apply to your modified version as well.
 
-#serial 18
+#serial 24
 
 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
 AC_DEFUN([AX_PTHREAD], [
 AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AC_PROG_SED])
 AC_LANG_PUSH([C])
 ax_pthread_ok=no
 
 # We used to check for pthread.h first, but this fails if pthread.h
-# requires special compiler flags (e.g. on True64 or Sequent).
+# requires special compiler flags (e.g. on Tru64 or Sequent).
 # It gets checked for in the link test anyway.
 
 # First of all, check if the user has set any of the PTHREAD_LIBS,
 # etcetera environment variables, and if threads linking works using
 # them:
-if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
-        save_CFLAGS="$CFLAGS"
+if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
+        ax_pthread_save_CC="$CC"
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-        save_LIBS="$LIBS"
         LIBS="$PTHREAD_LIBS $LIBS"
-        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
-        AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
-        AC_MSG_RESULT($ax_pthread_ok)
-        if test x"$ax_pthread_ok" = xno; then
+        AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
+        AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
+        AC_MSG_RESULT([$ax_pthread_ok])
+        if test "x$ax_pthread_ok" = "xno"; then
                 PTHREAD_LIBS=""
                 PTHREAD_CFLAGS=""
         fi
-        LIBS="$save_LIBS"
-        CFLAGS="$save_CFLAGS"
+        CC="$ax_pthread_save_CC"
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
 fi
 
 # We must check for the threads library under a number of different
@@ -123,7 +128,7 @@
 # which indicates that we try without any flags at all, and "pthread-config"
 # which is a program returning the flags for the Pth emulation library.
 
-ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
 
 # The ordering *is* (sometimes) important.  Some notes on the
 # individual items follow:
@@ -132,68 +137,225 @@
 # none: in case threads are in libc; should be tried before -Kthread and
 #       other compiler flags to prevent continual compiler warnings
 # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
-# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
-# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
-# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
-# -pthreads: Solaris/gcc
-# -mthreads: Mingw32/gcc, Lynx/gcc
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
+#           (Note: HP C rejects this with "bad form for `-t' option")
+# -pthreads: Solaris/gcc (Note: HP C also rejects)
 # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
-#      doesn't hurt to check since this sometimes defines pthreads too;
-#      also defines -D_REENTRANT)
-#      ... -mt is also the pthreads flag for HP/aCC
+#      doesn't hurt to check since this sometimes defines pthreads and
+#      -D_REENTRANT too), HP C (must be checked before -lpthread, which
+#      is present but should not be used directly; and before -mthreads,
+#      because the compiler interprets this as "-mt" + "-hreads")
+# -mthreads: Mingw32/gcc, Lynx/gcc
 # pthread: Linux, etcetera
 # --thread-safe: KAI C++
 # pthread-config: use pthread-config program (for GNU Pth library)
 
-case ${host_os} in
+case $host_os in
+
+        freebsd*)
+
+        # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+        # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+
+        ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+        ;;
+
+        hpux*)
+
+        # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+        # multi-threading and also sets -lpthread."
+
+        ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+        ;;
+
+        openedition*)
+
+        # IBM z/OS requires a feature-test macro to be defined in order to
+        # enable POSIX threads at all, so give the user a hint if this is
+        # not set. (We don't define these ourselves, as they can affect
+        # other portions of the system API in unpredictable ways.)
+
+        AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
+            [
+#            if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+             AX_PTHREAD_ZOS_MISSING
+#            endif
+            ],
+            [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
+        ;;
+
         solaris*)
 
         # On Solaris (at least, for some versions), libc contains stubbed
         # (non-functional) versions of the pthreads routines, so link-based
-        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
-        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
-        # a function called by this macro, so we could check for that, but
-        # who knows whether they'll stub that too in a future libc.)  So,
-        # we'll just look for -pthreads and -lpthread first:
+        # tests will erroneously succeed. (N.B.: The stubs are missing
+        # pthread_cleanup_push, or rather a function called by this macro,
+        # so we could check for that, but who knows whether they'll stub
+        # that too in a future libc.)  So we'll check first for the
+        # standard Solaris way of linking pthreads (-mt -lpthread).
 
-        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
-        ;;
-
-        darwin*)
-        ax_pthread_flags="-pthread $ax_pthread_flags"
+        ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
         ;;
 esac
 
-if test x"$ax_pthread_ok" = xno; then
-for flag in $ax_pthread_flags; do
+# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
 
-        case $flag in
+AS_IF([test "x$GCC" = "xyes"],
+      [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
+
+# The presence of a feature test macro requesting re-entrant function
+# definitions is, on some systems, a strong hint that pthreads support is
+# correctly enabled
+
+case $host_os in
+        darwin* | hpux* | linux* | osf* | solaris*)
+        ax_pthread_check_macro="_REENTRANT"
+        ;;
+
+        aix*)
+        ax_pthread_check_macro="_THREAD_SAFE"
+        ;;
+
+        *)
+        ax_pthread_check_macro="--"
+        ;;
+esac
+AS_IF([test "x$ax_pthread_check_macro" = "x--"],
+      [ax_pthread_check_cond=0],
+      [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
+
+# Are we compiling with Clang?
+
+AC_CACHE_CHECK([whether $CC is Clang],
+    [ax_cv_PTHREAD_CLANG],
+    [ax_cv_PTHREAD_CLANG=no
+     # Note that Autoconf sets GCC=yes for Clang as well as GCC
+     if test "x$GCC" = "xyes"; then
+        AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
+            [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+#            if defined(__clang__) && defined(__llvm__)
+             AX_PTHREAD_CC_IS_CLANG
+#            endif
+            ],
+            [ax_cv_PTHREAD_CLANG=yes])
+     fi
+    ])
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+ax_pthread_clang_warning=no
+
+# Clang needs special handling, because older versions handle the -pthread
+# option in a rather... idiosyncratic way
+
+if test "x$ax_pthread_clang" = "xyes"; then
+
+        # Clang takes -pthread; it has never supported any other flag
+
+        # (Note 1: This will need to be revisited if a system that Clang
+        # supports has POSIX threads in a separate library.  This tends not
+        # to be the way of modern systems, but it's conceivable.)
+
+        # (Note 2: On some systems, notably Darwin, -pthread is not needed
+        # to get POSIX threads support; the API is always present and
+        # active.  We could reasonably leave PTHREAD_CFLAGS empty.  But
+        # -pthread does define _REENTRANT, and while the Darwin headers
+        # ignore this macro, third-party headers might not.)
+
+        PTHREAD_CFLAGS="-pthread"
+        PTHREAD_LIBS=
+
+        ax_pthread_ok=yes
+
+        # However, older versions of Clang make a point of warning the user
+        # that, in an invocation where only linking and no compilation is
+        # taking place, the -pthread option has no effect ("argument unused
+        # during compilation").  They expect -pthread to be passed in only
+        # when source code is being compiled.
+        #
+        # Problem is, this is at odds with the way Automake and most other
+        # C build frameworks function, which is that the same flags used in
+        # compilation (CFLAGS) are also used in linking.  Many systems
+        # supported by AX_PTHREAD require exactly this for POSIX threads
+        # support, and in fact it is often not straightforward to specify a
+        # flag that is used only in the compilation phase and not in
+        # linking.  Such a scenario is extremely rare in practice.
+        #
+        # Even though use of the -pthread flag in linking would only print
+        # a warning, this can be a nuisance for well-run software projects
+        # that build with -Werror.  So if the active version of Clang has
+        # this misfeature, we search for an option to squash it.
+
+        AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
+            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
+            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+             # Create an alternate version of $ac_link that compiles and
+             # links in two steps (.c -> .o, .o -> exe) instead of one
+             # (.c -> exe), because the warning occurs only in the second
+             # step
+             ax_pthread_save_ac_link="$ac_link"
+             ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+             ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+             ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+             ax_pthread_save_CFLAGS="$CFLAGS"
+             for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+                AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
+                CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+                ac_link="$ax_pthread_save_ac_link"
+                AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+                    [ac_link="$ax_pthread_2step_ac_link"
+                     AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+                         [break])
+                    ])
+             done
+             ac_link="$ax_pthread_save_ac_link"
+             CFLAGS="$ax_pthread_save_CFLAGS"
+             AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
+             ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+            ])
+
+        case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+                no | unknown) ;;
+                *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+        esac
+
+fi # $ax_pthread_clang = yes
+
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+        case $ax_pthread_try_flag in
                 none)
                 AC_MSG_CHECKING([whether pthreads work without any flags])
                 ;;
 
+                -mt,pthread)
+                AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
+                PTHREAD_CFLAGS="-mt"
+                PTHREAD_LIBS="-lpthread"
+                ;;
+
                 -*)
-                AC_MSG_CHECKING([whether pthreads work with $flag])
-                PTHREAD_CFLAGS="$flag"
+                AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
+                PTHREAD_CFLAGS="$ax_pthread_try_flag"
                 ;;
 
                 pthread-config)
-                AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
-                if test x"$ax_pthread_config" = xno; then continue; fi
+                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+                AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
                 PTHREAD_CFLAGS="`pthread-config --cflags`"
                 PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
                 ;;
 
                 *)
-                AC_MSG_CHECKING([for the pthreads library -l$flag])
-                PTHREAD_LIBS="-l$flag"
+                AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
+                PTHREAD_LIBS="-l$ax_pthread_try_flag"
                 ;;
         esac
 
-        save_LIBS="$LIBS"
-        save_CFLAGS="$CFLAGS"
-        LIBS="$PTHREAD_LIBS $LIBS"
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
 
         # Check for various functions.  We must include pthread.h,
         # since some functions may be macros.  (On the Sequent, we
@@ -204,7 +366,11 @@
         # pthread_cleanup_push because it is one of the few pthread
         # functions on Solaris that doesn't have a non-functional libc stub.
         # We try pthread_create on general principles.
+
         AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+#                       if $ax_pthread_check_cond
+#                        error "$ax_pthread_check_macro must be defined"
+#                       endif
                         static void routine(void *a) { a = 0; }
                         static void *start_routine(void *a) { return a; }],
                        [pthread_t th; pthread_attr_t attr;
@@ -213,16 +379,14 @@
                         pthread_attr_init(&attr);
                         pthread_cleanup_push(routine, 0);
                         pthread_cleanup_pop(0) /* ; */])],
-                [ax_pthread_ok=yes],
-                [])
+            [ax_pthread_ok=yes],
+            [])
 
-        LIBS="$save_LIBS"
-        CFLAGS="$save_CFLAGS"
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
 
-        AC_MSG_RESULT($ax_pthread_ok)
-        if test "x$ax_pthread_ok" = xyes; then
-                break;
-        fi
+        AC_MSG_RESULT([$ax_pthread_ok])
+        AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
 
         PTHREAD_LIBS=""
         PTHREAD_CFLAGS=""
@@ -230,76 +394,88 @@
 fi
 
 # Various other checks:
-if test "x$ax_pthread_ok" = xyes; then
-        save_LIBS="$LIBS"
-        LIBS="$PTHREAD_LIBS $LIBS"
-        save_CFLAGS="$CFLAGS"
+if test "x$ax_pthread_ok" = "xyes"; then
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
 
         # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
-        AC_MSG_CHECKING([for joinable pthread attribute])
-        attr_name=unknown
-        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
-            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
-                           [int attr = $attr; return attr /* ; */])],
-                [attr_name=$attr; break],
-                [])
-        done
-        AC_MSG_RESULT($attr_name)
-        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
-            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
-                               [Define to necessary symbol if this constant
-                                uses a non-standard name on your system.])
-        fi
+        AC_CACHE_CHECK([for joinable pthread attribute],
+            [ax_cv_PTHREAD_JOINABLE_ATTR],
+            [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+             for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+                 AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                                                 [int attr = $ax_pthread_attr; return attr /* ; */])],
+                                [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
+                                [])
+             done
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+               test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+               test "x$ax_pthread_joinable_attr_defined" != "xyes"],
+              [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
+                                  [$ax_cv_PTHREAD_JOINABLE_ATTR],
+                                  [Define to necessary symbol if this constant
+                                   uses a non-standard name on your system.])
+               ax_pthread_joinable_attr_defined=yes
+              ])
 
-        AC_MSG_CHECKING([if more special flags are required for pthreads])
-        flag=no
-        case ${host_os} in
-            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
-            osf* | hpux*) flag="-D_REENTRANT";;
-            solaris*)
-            if test "$GCC" = "yes"; then
-                flag="-D_REENTRANT"
-            else
-                flag="-mt -D_REENTRANT"
-            fi
-            ;;
-        esac
-        AC_MSG_RESULT(${flag})
-        if test "x$flag" != xno; then
-            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
-        fi
+        AC_CACHE_CHECK([whether more special flags are required for pthreads],
+            [ax_cv_PTHREAD_SPECIAL_FLAGS],
+            [ax_cv_PTHREAD_SPECIAL_FLAGS=no
+             case $host_os in
+             solaris*)
+             ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+             ;;
+             esac
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+               test "x$ax_pthread_special_flags_added" != "xyes"],
+              [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+               ax_pthread_special_flags_added=yes])
 
         AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
-            ax_cv_PTHREAD_PRIO_INHERIT, [
-                AC_LINK_IFELSE([
-                    AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
-                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
-                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            [ax_cv_PTHREAD_PRIO_INHERIT],
+            [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+                                             [[int i = PTHREAD_PRIO_INHERIT;]])],
+                            [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                            [ax_cv_PTHREAD_PRIO_INHERIT=no])
             ])
-        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
-            AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+               test "x$ax_pthread_prio_inherit_defined" != "xyes"],
+              [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
+               ax_pthread_prio_inherit_defined=yes
+              ])
 
-        LIBS="$save_LIBS"
-        CFLAGS="$save_CFLAGS"
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
 
-        # More AIX lossage: must compile with xlc_r or cc_r
-        if test x"$GCC" != xyes; then
-          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
-        else
-          PTHREAD_CC=$CC
+        # More AIX lossage: compile with *_r variant
+        if test "x$GCC" != "xyes"; then
+            case $host_os in
+                aix*)
+                AS_CASE(["x/$CC"],
+                    [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+                    [#handle absolute path differently from PATH based program lookup
+                     AS_CASE(["x$CC"],
+                         [x/*],
+                         [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+                         [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+                ;;
+            esac
         fi
-else
-        PTHREAD_CC="$CC"
 fi
 
-AC_SUBST(PTHREAD_LIBS)
-AC_SUBST(PTHREAD_CFLAGS)
-AC_SUBST(PTHREAD_CC)
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
 
 # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
-if test x"$ax_pthread_ok" = xyes; then
-        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+if test "x$ax_pthread_ok" = "xyes"; then
+        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
         :
 else
         ax_pthread_ok=no
diff --git a/replace-enum-strings.cmake b/replace-enum-strings.cmake
new file mode 100644
index 0000000..42fdbff
--- /dev/null
+++ b/replace-enum-strings.cmake
@@ -0,0 +1,21 @@
+# CMake script to replace items

+# in sources generated by glib-mkenums

+

+FILE(READ ${ENUM_INPUT_SRC} enum_in)

+

+STRING(REPLACE

+  "_t_get_type"

+  "_get_type"

+  enum_out_tmp

+  "${enum_in}"

+  )

+

+STRING(REPLACE

+  "_T ("

+  " ("

+  enum_out

+  "${enum_out_tmp}"

+  )

+

+FILE(WRITE ${ENUM_OUTPUT_SRC} "${enum_out}")

+FILE(REMOVE ${ENUM_INPUT_SRC})
\ No newline at end of file
diff --git a/src/Makefile.am b/src/Makefile.am
index d7420a0..6857182 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,11 +25,13 @@
 HBNONPCLIBS =
 HBDEPS =
 HBSOURCES =  $(HB_BASE_sources)
+HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
 HBHEADERS = $(HB_BASE_headers)
 HBNODISTHEADERS = $(HB_NODIST_headers)
 
 if HAVE_OT
 HBSOURCES += $(HB_OT_sources)
+HBSOURCES += $(HB_OT_RAGEL_GENERATED_sources)
 HBHEADERS += $(HB_OT_headers)
 endif
 
@@ -97,6 +99,9 @@
 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
 
@@ -120,7 +125,7 @@
 
 libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) $(HBNODISTHEADERS)
 libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
-libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) $(export_symbols) -no-undefined
+libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -lm -version-info $(HB_LIBTOOL_VERSION_INFO) $(export_symbols) -no-undefined
 libharfbuzz_la_LIBADD = $(HBLIBS)
 EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
 pkginclude_HEADERS = $(HBHEADERS)
@@ -133,9 +138,12 @@
 	-DHB_NDEBUG \
 	-DHB_MAX_NESTING_LEVEL=3 \
 	-DHB_SANITIZE_MAX_EDITS=3 \
-	-DHB_BUFFER_MAX_EXPANSION_FACTOR=3 \
+	-DHB_BUFFER_MAX_LEN_FACTOR=3 \
 	-DHB_BUFFER_MAX_LEN_MIN=8 \
 	-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
+	-DHB_BUFFER_MAX_OPS_FACTOR=8 \
+	-DHB_BUFFER_MAX_OPS_MIN=64 \
+	-DHB_BUFFER_MAX_OPS_DEFAULT=1024 \
 	$(NULL)
 EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
 libharfbuzz_fuzzing_la_LINK = $(libharfbuzz_la_LINK)
@@ -218,7 +226,7 @@
 	(cat $^ || echo 'hb_ERROR ()' ) | \
 	$(EGREP) '^hb_.* \(' | \
 	sed -e 's/ (.*//' | \
-	LANG=C sort; \
+	LC_ALL=C sort; \
 	echo LIBRARY libharfbuzz-0.dll; \
 	) >"$@"
 	@ ! grep -q hb_ERROR "$@" \
@@ -251,19 +259,13 @@
 .PHONY: unicode-tables arabic-table indic-table use-table built-sources
 
 RAGEL_GENERATED = \
-	$(srcdir)/hb-buffer-deserialize-json.hh \
-	$(srcdir)/hb-buffer-deserialize-text.hh \
-	$(srcdir)/hb-ot-shape-complex-indic-machine.hh \
-	$(srcdir)/hb-ot-shape-complex-myanmar-machine.hh \
-	$(srcdir)/hb-ot-shape-complex-use-machine.hh \
+	$(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \
+	$(patsubst %,$(srcdir)/%,$(HB_OT_RAGEL_GENERATED_sources)) \
 	$(NULL)
 BUILT_SOURCES += $(RAGEL_GENERATED)
 EXTRA_DIST += \
-	hb-buffer-deserialize-json.rl \
-	hb-buffer-deserialize-text.rl \
-	hb-ot-shape-complex-indic-machine.rl \
-	hb-ot-shape-complex-myanmar-machine.rl \
-	hb-ot-shape-complex-use-machine.rl \
+	$(HB_BASE_RAGEL_sources) \
+	$(HB_OT_RAGEL_sources) \
 	$(NULL)
 MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
 $(srcdir)/%.hh: $(srcdir)/%.rl
@@ -304,6 +306,7 @@
 dist_check_SCRIPTS = \
 	check-c-linkage-decls.sh \
 	check-defs.sh \
+	check-externs.sh \
 	check-header-guards.sh \
 	check-includes.sh \
 	check-libstdc++.sh \
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 8d7f1a0..5824055 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -5,13 +5,12 @@
 HB_BASE_sources = \
 	hb-atomic-private.hh \
 	hb-blob.cc \
-	hb-buffer-deserialize-json.hh \
-	hb-buffer-deserialize-text.hh \
 	hb-buffer-private.hh \
 	hb-buffer-serialize.cc \
 	hb-buffer.cc \
-	hb-cache-private.hh \
 	hb-common.cc \
+	hb-debug.hh \
+	hb-dsalgs.hh \
 	hb-face-private.hh \
 	hb-face.cc \
 	hb-font-private.hh \
@@ -26,12 +25,15 @@
 	hb-ot-head-table.hh \
 	hb-ot-hhea-table.hh \
 	hb-ot-hmtx-table.hh \
+	hb-ot-kern-table.hh \
 	hb-ot-maxp-table.hh \
 	hb-ot-name-table.hh \
 	hb-ot-os2-table.hh \
+	hb-ot-post-macroman.hh \
 	hb-ot-post-table.hh \
 	hb-ot-tag.cc \
 	hb-private.hh \
+	hb-set-digest-private.hh \
 	hb-set-private.hh \
 	hb-set.cc \
 	hb-shape.cc \
@@ -41,12 +43,22 @@
 	hb-shaper-impl-private.hh \
 	hb-shaper-private.hh \
 	hb-shaper.cc \
+	hb-string-array.hh \
 	hb-unicode-private.hh \
 	hb-unicode.cc \
 	hb-utf-private.hh \
 	hb-warning.cc \
 	$(NULL)
 
+HB_BASE_RAGEL_GENERATED_sources = \
+	hb-buffer-deserialize-json.hh \
+	hb-buffer-deserialize-text.hh \
+	$(NULL)
+HB_BASE_RAGEL_sources = \
+	hb-buffer-deserialize-json.rl \
+	hb-buffer-deserialize-text.rl \
+	$(NULL)
+
 HB_BASE_headers = \
 	hb.h \
 	hb-blob.h \
@@ -65,7 +77,9 @@
 	hb-version.h \
 	$(NULL)
 
-HB_FALLBACK_sources = hb-fallback-shape.cc
+HB_FALLBACK_sources = \
+	hb-fallback-shape.cc	\
+	$(NULL)
 
 HB_OT_sources = \
 	hb-ot-font.cc \
@@ -91,15 +105,12 @@
 	hb-ot-shape-complex-hangul.cc \
 	hb-ot-shape-complex-hebrew.cc \
 	hb-ot-shape-complex-indic.cc \
-	hb-ot-shape-complex-indic-machine.hh \
 	hb-ot-shape-complex-indic-private.hh \
 	hb-ot-shape-complex-indic-table.cc \
 	hb-ot-shape-complex-myanmar.cc \
-	hb-ot-shape-complex-myanmar-machine.hh \
 	hb-ot-shape-complex-thai.cc \
 	hb-ot-shape-complex-tibetan.cc \
 	hb-ot-shape-complex-use.cc \
-	hb-ot-shape-complex-use-machine.hh \
 	hb-ot-shape-complex-use-private.hh \
 	hb-ot-shape-complex-use-table.cc \
 	hb-ot-shape-complex-private.hh \
@@ -112,6 +123,18 @@
 	hb-ot-var-avar-table.hh \
 	hb-ot-var-fvar-table.hh \
 	hb-ot-var-hvar-table.hh \
+	hb-ot-var-mvar-table.hh \
+	$(NULL)
+
+HB_OT_RAGEL_GENERATED_sources = \
+	hb-ot-shape-complex-indic-machine.hh \
+	hb-ot-shape-complex-myanmar-machine.hh \
+	hb-ot-shape-complex-use-machine.hh \
+	$(NULL)
+HB_OT_RAGEL_sources = \
+	hb-ot-shape-complex-indic-machine.rl \
+	hb-ot-shape-complex-myanmar-machine.rl \
+	hb-ot-shape-complex-use-machine.rl \
 	$(NULL)
 
 HB_OT_headers = \
diff --git a/src/check-c-linkage-decls.sh b/src/check-c-linkage-decls.sh
index b10310f..cd55086 100755
--- a/src/check-c-linkage-decls.sh
+++ b/src/check-c-linkage-decls.sh
@@ -11,14 +11,14 @@
 
 
 for x in $HBHEADERS; do
-	test -f $srcdir/$x && x=$srcdir/$x
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	if ! grep -q HB_BEGIN_DECLS "$x" || ! grep -q HB_END_DECLS "$x"; then
 		echo "Ouch, file $x does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should"
 		stat=1
 	fi
 done
 for x in $HBSOURCES; do
-	test -f $srcdir/$x && x=$srcdir/$x
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	if grep -q HB_BEGIN_DECLS "$x" || grep -q HB_END_DECLS "$x"; then
 		echo "Ouch, file $x has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn't"
 		stat=1
diff --git a/src/check-defs.sh b/src/check-defs.sh
index 65a2467..480d499 100755
--- a/src/check-defs.sh
+++ b/src/check-defs.sh
@@ -21,7 +21,7 @@
 	lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
 	so=.libs/lib${lib}.so
 
-	EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
+	EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
 
 	if test -f "$so"; then
 
diff --git a/src/check-externs.sh b/src/check-externs.sh
new file mode 100755
index 0000000..a6de375
--- /dev/null
+++ b/src/check-externs.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+test -z "$srcdir" && srcdir=.
+stat=0
+
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$EGREP" = x && EGREP='grep -E'
+
+
+echo 'Checking that all public symbols are exported with HB_EXTERN'
+
+for x in $HBHEADERS; do
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
+	$EGREP -B1 -n '^hb_' /dev/null "$x" |
+	$EGREP -v '(^--|:hb_|-HB_EXTERN )' -A1
+done |
+grep . >&2 && stat=1
+
+exit $stat
diff --git a/src/check-header-guards.sh b/src/check-header-guards.sh
index 09c5ea8..355d81b 100755
--- a/src/check-header-guards.sh
+++ b/src/check-header-guards.sh
@@ -10,7 +10,7 @@
 test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
 
 for x in $HBHEADERS $HBSOURCES; do
-	test -f "$srcdir/$x" && x="$srcdir/$x"
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	echo "$x" | grep -q '[^h]$' && continue;
 	xx=`echo "$x" | sed 's@.*/@@'`
 	tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'`
diff --git a/src/check-includes.sh b/src/check-includes.sh
index 902f235..fd565da 100755
--- a/src/check-includes.sh
+++ b/src/check-includes.sh
@@ -13,7 +13,7 @@
 echo 'Checking that public header files #include "hb-common.h" or "hb.h" first (or none)'
 
 for x in $HBHEADERS; do
-	test -f "$srcdir/$x" && x="$srcdir/$x"
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	grep '#.*\<include\>' "$x" /dev/null | head -n 1
 done |
 grep -v '"hb-common[.]h"' |
@@ -26,7 +26,7 @@
 echo 'Checking that source files #include "hb-*private.hh" first (or none)'
 
 for x in $HBSOURCES; do
-	test -f "$srcdir/$x" && x="$srcdir/$x"
+	test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
 	grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1
 done |
 grep -v '"hb-.*private[.]hh"' |
@@ -34,7 +34,7 @@
 grep . >&2 && stat=1
 
 
-echo 'Checking that there is no #include <hb.*.h>'
+echo 'Checking that there is no #include <hb-*.h>'
 for x in $HBHEADERS $HBSOURCES; do
 	test -f "$srcdir/$x" && x="$srcdir/$x"
 	grep '#.*\<include\>.*<.*hb' "$x" /dev/null >&2 && stat=1
diff --git a/src/check-symbols.sh b/src/check-symbols.sh
index ba09ba1..d4d655d 100755
--- a/src/check-symbols.sh
+++ b/src/check-symbols.sh
@@ -20,7 +20,7 @@
 	so=.libs/libharfbuzz.$suffix
 	if ! test -f "$so"; then continue; fi
 
-	EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| ___gcov_flush\>\| llvm_\| _llvm_' | cut -d' ' -f3`"
+	EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| ___gcov_flush\>\| llvm_\| _llvm_' | cut -d' ' -f3`"
 
 	prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
 
diff --git a/src/gen-arabic-table.py b/src/gen-arabic-table.py
index 308435f..59bd760 100755
--- a/src/gen-arabic-table.py
+++ b/src/gen-arabic-table.py
@@ -134,7 +134,7 @@
 		for (start,end) in ranges:
 			if p not in [start>>page_bits, end>>page_bits]: continue
 			offset = "joining_offset_0x%04xu" % start
-			print "      if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
+			print "      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
 		print "      break;"
 		print ""
 	print "    default:"
diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py
index 3016cd0..a849db1 100755
--- a/src/gen-indic-table.py
+++ b/src/gen-indic-table.py
@@ -232,7 +232,7 @@
 	for (start,end) in zip (starts, ends):
 		if p not in [start>>page_bits, end>>page_bits]: continue
 		offset = "indic_offset_0x%04xu" % start
-		print "      if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
+		print "      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
 	for u,d in singles.items ():
 		if p != u>>page_bits: continue
 		print "      if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
diff --git a/src/gen-use-table.py b/src/gen-use-table.py
index a922c92..4ded542 100755
--- a/src/gen-use-table.py
+++ b/src/gen-use-table.py
@@ -44,6 +44,7 @@
 # TODO Characters that are not in Unicode Indic files, but used in USE
 data[0][0x034F] = defaults[0]
 data[0][0x2060] = defaults[0]
+data[0][0x20F0] = defaults[0]
 for u in range (0xFE00, 0xFE0F + 1):
 	data[0][u] = defaults[0]
 
@@ -117,6 +118,7 @@
 	'Top_And_Right',
 	'Top_And_Left',
 	'Top_And_Left_And_Right',
+	'Bottom_And_Left',
 	'Bottom_And_Right',
 	'Top_And_Bottom_And_Right',
 	'Overstruck',
@@ -153,7 +155,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 [0x104E, 0x2022]) or
+		(UGC == Po and not U in [0x104E, 0x2022, 0x11A3F, 0x11A45]) or
 		False # SPEC-DRAFT-OUTDATED! U == 0x002D
 		)
 def is_BASE_NUM(U, UISC, UGC):
@@ -177,6 +179,8 @@
 def is_CONS_SUB(U, UISC, UGC):
 	#SPEC-DRAFT return UISC == Consonant_Subjoined
 	return UISC == Consonant_Subjoined and UGC != Lo
+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]
 def is_HALANT_NUM(U, UISC, UGC):
@@ -198,9 +202,7 @@
 def is_Reserved(U, UISC, UGC):
 	return UGC == 'Cn'
 def is_REPHA(U, UISC, UGC):
-	#return UISC == Consonant_Preceding_Repha
-	#SPEC-OUTDATED hack to categorize Consonant_With_Stacker and Consonant_Prefixed
-	return UISC in [Consonant_Preceding_Repha, Consonant_With_Stacker, Consonant_Prefixed]
+	return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed]
 def is_SYM(U, UISC, UGC):
 	if U == 0x25CC: return False #SPEC-DRAFT
 	#SPEC-DRAFT return UGC in [So, Sc] or UISC == Symbol_Letter
@@ -210,11 +212,13 @@
 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
 	return (UISC == Pure_Killer or
-		(UGC != Lo and UISC in [Vowel, Vowel_Dependent]))
+		(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
 	return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
-		(UGC != Lo and UISC == Bindu))
+		(UGC != Lo and (UISC == Bindu or U in [0xAA29])))
 
 use_mapping = {
 	'B':	is_BASE,
@@ -227,6 +231,7 @@
 	'M':	is_CONS_MED,
 	'CM':	is_CONS_MOD,
 	'SUB':	is_CONS_SUB,
+	'CS':	is_CONS_WITH_STACKER,
 	'H':	is_HALANT,
 	'HN':	is_HALANT_NUM,
 	'ZWNJ':	is_ZWNJ,
@@ -250,7 +255,7 @@
 	},
 	'M': {
 		'Abv': [Top],
-		'Blw': [Bottom],
+		'Blw': [Bottom, Bottom_And_Left],
 		'Pst': [Right],
 		'Pre': [Left],
 	},
@@ -296,8 +301,16 @@
 		# the nasalization marks, maybe only for U+1CE9..U+1CF1.
 		if U == 0x1CED: UISC = Tone_Mark
 
-		evals = [(k, v(U,UISC,UGC)) for k,v in items]
-		values = [k for k,v in evals if v]
+		# 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
+
+		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]
 
@@ -449,7 +462,7 @@
 	for (start,end) in zip (starts, ends):
 		if p not in [start>>page_bits, end>>page_bits]: continue
 		offset = "use_offset_0x%04xu" % start
-		print "      if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
+		print "      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
 	for u,d in singles.items ():
 		if p != u>>page_bits: continue
 		print "      if (unlikely (u == 0x%04Xu)) return %s;" % (u, d[0])
diff --git a/src/harfbuzz.pc.in b/src/harfbuzz.pc.in
index b3e124a..661251c 100644
--- a/src/harfbuzz.pc.in
+++ b/src/harfbuzz.pc.in
@@ -8,6 +8,6 @@
 Version: %VERSION%
 
 Libs: -L${libdir} -lharfbuzz
-Libs.private: %libs_private%
+Libs.private: -lm %libs_private%
 Requires.private: %requires_private%
 Cflags: -I${includedir}/harfbuzz
diff --git a/src/hb-atomic-private.hh b/src/hb-atomic-private.hh
index 100ba53..9343840 100644
--- a/src/hb-atomic-private.hh
+++ b/src/hb-atomic-private.hh
@@ -89,9 +89,9 @@
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
 #else
 #if __ppc64__ || __x86_64__ || __aarch64__
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P))
 #else
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap32Barrier ((int32_t) (void *) (O), (int32_t) (void *) (N), (int32_t*) (P))
 #endif
 #endif
 
@@ -124,13 +124,13 @@
 #include <builtins.h>
 
 
-static inline int hb_fetch_and_add(volatile int* AI, unsigned int V) {
+static inline int _hb_fetch_and_add(volatile int* AI, unsigned int V) {
   __lwsync();
   int result = __fetch_and_add(AI, V);
   __isync();
   return result;
 }
-static inline int hb_compare_and_swaplp(volatile long* P, long O, long N) {
+static inline int _hb_compare_and_swaplp(volatile long* P, long O, long N) {
   __sync();
   int result = __compare_and_swaplp (P, &O, N);
   __sync();
@@ -139,10 +139,10 @@
 
 typedef int hb_atomic_int_impl_t;
 #define HB_ATOMIC_INT_IMPL_INIT(V) (V)
-#define hb_atomic_int_impl_add(AI, V)           hb_fetch_and_add (&(AI), (V))
+#define hb_atomic_int_impl_add(AI, V)           _hb_fetch_and_add (&(AI), (V))
 
 #define hb_atomic_ptr_impl_get(P)               (__sync(), (void *) *(P))
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)       hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)       _hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
 
 #elif !defined(HB_NO_MT)
 
diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index fb48f03..59c8333 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -30,6 +30,7 @@
 #endif
 
 #include "hb-private.hh"
+#include "hb-debug.hh"
 
 #include "hb-object-private.hh"
 
@@ -44,12 +45,6 @@
 #include <errno.h>
 
 
-
-#ifndef HB_DEBUG_BLOB
-#define HB_DEBUG_BLOB (HB_DEBUG+0)
-#endif
-
-
 struct hb_blob_t {
   hb_object_header_t header;
   ASSERT_POD ();
@@ -72,8 +67,8 @@
 {
   if (blob->destroy) {
     blob->destroy (blob->user_data);
-    blob->user_data = NULL;
-    blob->destroy = NULL;
+    blob->user_data = nullptr;
+    blob->destroy = nullptr;
   }
 }
 
@@ -128,6 +123,12 @@
   return blob;
 }
 
+static void
+_hb_blob_destroy (void *data)
+{
+  hb_blob_destroy ((hb_blob_t *) data);
+}
+
 /**
  * hb_blob_create_sub_blob:
  * @parent: Parent blob.
@@ -164,7 +165,7 @@
 			 MIN (length, parent->length - offset),
 			 HB_MEMORY_MODE_READONLY,
 			 hb_blob_reference (parent),
-			 (hb_destroy_func_t) hb_blob_destroy);
+			 _hb_blob_destroy);
 
   return blob;
 }
@@ -188,12 +189,12 @@
 
     true, /* immutable */
 
-    NULL, /* data */
+    nullptr, /* data */
     0, /* length */
     HB_MEMORY_MODE_READONLY, /* mode */
 
-    NULL, /* user_data */
-    NULL  /* destroy */
+    nullptr, /* user_data */
+    nullptr  /* destroy */
   };
 
   return const_cast<hb_blob_t *> (&_hb_blob_nil);
@@ -373,7 +374,7 @@
     if (length)
       *length = 0;
 
-    return NULL;
+    return nullptr;
   }
 
   if (length)
diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index bca308d..97bdc1b 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -35,8 +35,8 @@
 #include "hb-unicode-private.hh"
 
 
-#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
-#define HB_BUFFER_MAX_EXPANSION_FACTOR 32
+#ifndef HB_BUFFER_MAX_LEN_FACTOR
+#define HB_BUFFER_MAX_LEN_FACTOR 32
 #endif
 #ifndef HB_BUFFER_MAX_LEN_MIN
 #define HB_BUFFER_MAX_LEN_MIN 8192
@@ -45,11 +45,22 @@
 #define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
 #endif
 
-ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
-ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
+#ifndef HB_BUFFER_MAX_OPS_FACTOR
+#define HB_BUFFER_MAX_OPS_FACTOR 64
+#endif
+#ifndef HB_BUFFER_MAX_OPS_MIN
+#define HB_BUFFER_MAX_OPS_MIN 1024
+#endif
+#ifndef HB_BUFFER_MAX_OPS_DEFAULT
+#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
+#endif
+
+static_assert ((sizeof (hb_glyph_info_t) == 20), "");
+static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
 
 HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
 HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
+HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
 
 enum hb_buffer_scratch_flags_t {
   HB_BUFFER_SCRATCH_FLAG_DEFAULT			= 0x00000000u,
@@ -57,6 +68,8 @@
   HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES		= 0x00000002u,
   HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK		= 0x00000004u,
   HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT		= 0x00000008u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK		= 0x00000010u,
+
   /* Reserved for complex shapers' internal use. */
   HB_BUFFER_SCRATCH_FLAG_COMPLEX0			= 0x01000000u,
   HB_BUFFER_SCRATCH_FLAG_COMPLEX1			= 0x02000000u,
@@ -81,6 +94,7 @@
   hb_codepoint_t replacement; /* U+FFFD or something else. */
   hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
   unsigned int max_len; /* Maximum allowed len. */
+  int max_ops; /* Maximum allowed operations. */
 
   /* Buffer contents */
   hb_buffer_content_type_t content_type;
@@ -99,17 +113,6 @@
   hb_glyph_info_t     *out_info;
   hb_glyph_position_t *pos;
 
-  inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
-  inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
-
-  inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
-  inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
-
-  inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
-  inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
-
-  inline bool has_separate_output (void) const { return info != out_info; }
-
   unsigned int serial;
 
   /* Text before / after the main buffer contents.
@@ -129,6 +132,10 @@
 #ifndef HB_NDEBUG
   uint8_t allocated_var_bits;
 #endif
+
+
+  /* Methods */
+
   inline void allocate_var (unsigned int start, unsigned int count)
   {
 #ifndef HB_NDEBUG
@@ -165,8 +172,17 @@
 #endif
   }
 
+  inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
+  inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
 
-  /* Methods */
+  inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
+  inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
+
+  inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
+  inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
+
+  inline bool has_separate_output (void) const { return info != out_info; }
+
 
   HB_INTERNAL void reset (void);
   HB_INTERNAL void clear (void);
@@ -232,25 +248,31 @@
     for (unsigned int j = 0; j < len; j++)
       info[j].mask |= mask;
   }
-  HB_INTERNAL void set_masks (hb_mask_t value,
-			      hb_mask_t mask,
-			      unsigned int cluster_start,
-			      unsigned int cluster_end);
+  HB_INTERNAL void set_masks (hb_mask_t value, hb_mask_t mask,
+			      unsigned int cluster_start, unsigned int cluster_end);
 
-  HB_INTERNAL void merge_clusters (unsigned int start,
-				   unsigned int end)
+  inline void merge_clusters (unsigned int start, unsigned int end)
   {
     if (end - start < 2)
       return;
     merge_clusters_impl (start, end);
   }
-  HB_INTERNAL void merge_clusters_impl (unsigned int start,
-					unsigned int end);
-  HB_INTERNAL void merge_out_clusters (unsigned int start,
-				       unsigned int end);
+  HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end);
+  HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
   /* Merge clusters for deleting current glyph, and skip it. */
   HB_INTERNAL void delete_glyph (void);
 
+  inline void unsafe_to_break (unsigned int start,
+			       unsigned int end)
+  {
+    if (end - start < 2)
+      return;
+    unsafe_to_break_impl (start, end);
+  }
+  HB_INTERNAL void unsafe_to_break_impl (unsigned int start, unsigned int end);
+  HB_INTERNAL void unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end);
+
+
   /* Internal methods */
   HB_INTERNAL bool enlarge (unsigned int size);
 
@@ -282,9 +304,79 @@
     return ret;
   }
   HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
+
+  static inline void
+  set_cluster (hb_glyph_info_t &info, unsigned int cluster, unsigned int mask = 0)
+  {
+    if (info.cluster != cluster)
+    {
+      if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
+	info.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+      else
+	info.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+    }
+    info.cluster = cluster;
+  }
+
+  inline int
+  _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *info,
+				     unsigned int start, unsigned int end,
+				     unsigned int cluster) const
+  {
+    for (unsigned int i = start; i < end; i++)
+      cluster = MIN<unsigned int> (cluster, info[i].cluster);
+    return cluster;
+  }
+  inline void
+  _unsafe_to_break_set_mask (hb_glyph_info_t *info,
+			     unsigned int start, unsigned int end,
+			     unsigned int cluster)
+  {
+    for (unsigned int i = start; i < end; i++)
+      if (cluster != info[i].cluster)
+      {
+	scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK;
+	info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+      }
+  }
+
+  inline void
+  unsafe_to_break_all (void)
+  {
+    for (unsigned int i = 0; i < len; i++)
+      info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+  }
+  inline void
+  safe_to_break_all (void)
+  {
+    for (unsigned int i = 0; i < len; i++)
+      info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+  }
 };
 
 
+/* Loop over clusters. Duplicated in foreach_syllable(). */
+#define foreach_cluster(buffer, start, end) \
+  for (unsigned int \
+       _count = buffer->len, \
+       start = 0, end = _count ? _next_cluster (buffer, 0) : 0; \
+       start < _count; \
+       start = end, end = _next_cluster (buffer, start))
+
+static inline unsigned int
+_next_cluster (hb_buffer_t *buffer, unsigned int start)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+
+  unsigned int cluster = info[start].cluster;
+  while (++start < count && cluster == info[start].cluster)
+    ;
+
+  return start;
+}
+
+
 #define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
   b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
 	   sizeof (b->info[0].var))
diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc
index 63a0f34..ea62e9f 100644
--- a/src/hb-buffer-serialize.cc
+++ b/src/hb-buffer-serialize.cc
@@ -30,7 +30,7 @@
 static const char *serialize_formats[] = {
   "text",
   "json",
-  NULL
+  nullptr
 };
 
 /**
@@ -90,7 +90,7 @@
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:	return serialize_formats[0];
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:	return serialize_formats[1];
     default:
-    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:	return NULL;
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:	return nullptr;
   }
 }
 
@@ -104,9 +104,9 @@
 				  hb_font_t *font,
 				  hb_buffer_serialize_flags_t flags)
 {
-  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
-			     NULL : hb_buffer_get_glyph_positions (buffer, NULL);
+			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 
   *buf_consumed = 0;
   for (unsigned int i = start; i < end; i++)
@@ -145,10 +145,16 @@
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
-      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
-		     pos[i].x_offset, pos[i].y_offset);
-      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
-		     pos[i].x_advance, pos[i].y_advance);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
+			     pos[i].x_offset, pos[i].y_offset));
+      p += 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));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
@@ -156,9 +162,9 @@
       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",
-        extents.x_bearing, extents.y_bearing));
+		extents.x_bearing, extents.y_bearing));
       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
-        extents.width, extents.height));
+		extents.width, extents.height));
     }
 
     *p++ = '}';
@@ -188,9 +194,9 @@
 				  hb_font_t *font,
 				  hb_buffer_serialize_flags_t flags)
 {
-  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
   hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
-			     NULL : hb_buffer_get_glyph_positions (buffer, NULL);
+			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
 
   *buf_consumed = 0;
   for (unsigned int i = start; i < end; i++)
@@ -226,6 +232,12 @@
 	p += 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));
+    }
+
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
     {
       hb_glyph_extents_t extents;
@@ -311,6 +323,8 @@
   if (!buf_consumed)
     buf_consumed = &sconsumed;
   *buf_consumed = 0;
+  if (buf_size)
+    *buf = '\0';
 
   assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
 	  buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
@@ -408,8 +422,8 @@
 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
 			      const char *buf,
 			      int buf_len, /* -1 means nul-terminated */
-			      const char **end_ptr, /* May be NULL */
-			      hb_font_t *font, /* May be NULL */
+			      const char **end_ptr, /* May be nullptr */
+			      hb_font_t *font, /* May be nullptr */
 			      hb_buffer_serialize_format_t format)
 {
   const char *end;
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 3940a3d..7ead43b 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -31,10 +31,6 @@
 #include "hb-utf-private.hh"
 
 
-#ifndef HB_DEBUG_BUFFER
-#define HB_DEBUG_BUFFER (HB_DEBUG+0)
-#endif
-
 /**
  * SECTION: hb-buffer
  * @title: Buffers
@@ -124,8 +120,8 @@
   }
 
   unsigned int new_allocated = allocated;
-  hb_glyph_position_t *new_pos = NULL;
-  hb_glyph_info_t *new_info = NULL;
+  hb_glyph_position_t *new_pos = nullptr;
+  hb_glyph_info_t *new_info = nullptr;
   bool separate_out = out_info != info;
 
   if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
@@ -134,7 +130,7 @@
   while (size >= new_allocated)
     new_allocated += (new_allocated >> 1) + 32;
 
-  ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
+  static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
   if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
     goto done;
 
@@ -267,7 +263,7 @@
 
   memset (glyph, 0, sizeof (*glyph));
   glyph->codepoint = codepoint;
-  glyph->mask = 1;
+  glyph->mask = 0;
   glyph->cluster = cluster;
 
   len++;
@@ -550,12 +546,15 @@
 				  unsigned int end)
 {
   if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+  {
+    unsafe_to_break (start, end);
     return;
+  }
 
   unsigned int cluster = info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN (cluster, info[i].cluster);
+    cluster = MIN<unsigned int> (cluster, info[i].cluster);
 
   /* Extend end */
   while (end < len && info[end - 1].cluster == info[end].cluster)
@@ -568,10 +567,10 @@
   /* If we hit the start of buffer, continue in out-buffer. */
   if (idx == start)
     for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
-      out_info[i - 1].cluster = cluster;
+      set_cluster (out_info[i - 1], cluster);
 
   for (unsigned int i = start; i < end; i++)
-    info[i].cluster = cluster;
+    set_cluster (info[i], cluster);
 }
 void
 hb_buffer_t::merge_out_clusters (unsigned int start,
@@ -586,7 +585,7 @@
   unsigned int cluster = out_info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN (cluster, out_info[i].cluster);
+    cluster = MIN<unsigned int> (cluster, out_info[i].cluster);
 
   /* Extend start */
   while (start && out_info[start - 1].cluster == out_info[start].cluster)
@@ -599,14 +598,16 @@
   /* If we hit the end of out-buffer, continue in buffer. */
   if (end == out_len)
     for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
-      info[i].cluster = cluster;
+      set_cluster (info[i], cluster);
 
   for (unsigned int i = start; i < end; i++)
-    out_info[i].cluster = cluster;
+    set_cluster (out_info[i], cluster);
 }
 void
 hb_buffer_t::delete_glyph ()
 {
+  /* The logic here is duplicated in hb_ot_hide_default_ignorables(). */
+
   unsigned int cluster = info[idx].cluster;
   if (idx + 1 < len && cluster == info[idx + 1].cluster)
   {
@@ -619,9 +620,10 @@
     /* Merge cluster backward. */
     if (cluster < out_info[out_len - 1].cluster)
     {
+      unsigned int mask = info[idx].mask;
       unsigned int old_cluster = out_info[out_len - 1].cluster;
       for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
-	out_info[i - 1].cluster = cluster;
+	set_cluster (out_info[i - 1], cluster, mask);
     }
     goto done;
   }
@@ -638,6 +640,32 @@
 }
 
 void
+hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
+{
+  unsigned int cluster = (unsigned int) -1;
+  cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
+  _unsafe_to_break_set_mask (info, start, end, cluster);
+}
+void
+hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end)
+{
+  if (!have_output)
+  {
+    unsafe_to_break_impl (start, end);
+    return;
+  }
+
+  assert (start <= out_len);
+  assert (idx <= end);
+
+  unsigned int cluster = (unsigned int) -1;
+  cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
+  cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
+  _unsafe_to_break_set_mask (out_info, start, out_len, cluster);
+  _unsafe_to_break_set_mask (info, idx, end, cluster);
+}
+
+void
 hb_buffer_t::guess_segment_properties (void)
 {
   assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
@@ -694,6 +722,7 @@
     return hb_buffer_get_empty ();
 
   buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+  buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
 
   buffer->reset ();
 
@@ -721,6 +750,7 @@
     HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
     HB_BUFFER_SCRATCH_FLAG_DEFAULT,
     HB_BUFFER_MAX_LEN_DEFAULT,
+    HB_BUFFER_MAX_OPS_DEFAULT,
 
     HB_BUFFER_CONTENT_TYPE_INVALID,
     HB_SEGMENT_PROPERTIES_DEFAULT,
@@ -1380,6 +1410,23 @@
 }
 
 /**
+ * hb_glyph_info_get_glyph_flags:
+ * @info: a #hb_glyph_info_t.
+ *
+ * Returns glyph flags encoded within a #hb_glyph_info_t.
+ *
+ * Return value:
+ * The #hb_glyph_flags_t encoded within @info.
+ *
+ * Since: 1.5.0
+ **/
+hb_glyph_flags_t
+(hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info)
+{
+  return hb_glyph_info_get_glyph_flags (info);
+}
+
+/**
  * hb_buffer_reverse:
  * @buffer: an #hb_buffer_t.
  *
@@ -1666,6 +1713,58 @@
 }
 
 
+/**
+ * hb_buffer_append:
+ * @buffer: an #hb_buffer_t.
+ * @source: source #hb_buffer_t.
+ * @start: start index into source buffer to copy.  Use 0 to copy from start of buffer.
+ * @end: end index into source buffer to copy.  Use (unsigned int) -1 to copy to end of buffer.
+ *
+ * Append (part of) contents of another buffer to this buffer.
+ *
+ * Since: 1.5.0
+ **/
+HB_EXTERN void
+hb_buffer_append (hb_buffer_t *buffer,
+		  hb_buffer_t *source,
+		  unsigned int start,
+		  unsigned int end)
+{
+  assert (!buffer->have_output && !source->have_output);
+  assert (buffer->have_positions == source->have_positions ||
+	  !buffer->len || !source->len);
+  assert (buffer->content_type == source->content_type ||
+	  !buffer->len || !source->len);
+
+  if (end > source->len)
+    end = source->len;
+  if (start > end)
+    start = end;
+  if (start == end)
+    return;
+
+  if (!buffer->len)
+    buffer->content_type = source->content_type;
+  if (!buffer->have_positions && source->have_positions)
+    buffer->clear_positions ();
+
+  if (buffer->len + (end - start) < buffer->len) /* Overflows. */
+  {
+    buffer->in_error = true;
+    return;
+  }
+
+  unsigned int orig_len = buffer->len;
+  hb_buffer_set_length (buffer, buffer->len + (end - start));
+  if (buffer->in_error)
+    return;
+
+  memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
+  if (buffer->have_positions)
+    memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
+}
+
+
 static int
 compare_info_codepoint (const hb_glyph_info_t *pa,
 			const hb_glyph_info_t *pb)
@@ -1736,7 +1835,8 @@
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
 {
   assert (buffer->have_positions);
-  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS ||
+	  (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
 
   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
@@ -1775,6 +1875,98 @@
   }
 }
 
+
+/*
+ * Comparing buffers.
+ */
+
+/**
+ * hb_buffer_diff:
+ *
+ * If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
+ * and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned.  This should be used by most
+ * callers if just comparing two buffers is needed.
+ *
+ * Since: 1.5.0
+ **/
+hb_buffer_diff_flags_t
+hb_buffer_diff (hb_buffer_t *buffer,
+		hb_buffer_t *reference,
+		hb_codepoint_t dottedcircle_glyph,
+		unsigned int position_fuzz)
+{
+  if (buffer->content_type != reference->content_type && buffer->len && reference->len)
+    return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;
+
+  hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;
+  bool contains = dottedcircle_glyph != (hb_codepoint_t) -1;
+
+  unsigned int count = reference->len;
+
+  if (buffer->len != count)
+  {
+    /*
+     * we can't compare glyph-by-glyph, but we do want to know if there
+     * are .notdef or dottedcircle glyphs present in the reference buffer
+     */
+    const hb_glyph_info_t *info = reference->info;
+    unsigned int i;
+    for (i = 0; i < count; i++)
+    {
+      if (contains && info[i].codepoint == dottedcircle_glyph)
+        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_LENGTH_MISMATCH;
+    return hb_buffer_diff_flags_t (result);
+  }
+
+  if (!count)
+    return hb_buffer_diff_flags_t (result);
+
+  const hb_glyph_info_t *buf_info = buffer->info;
+  const hb_glyph_info_t *ref_info = reference->info;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    if (buf_info->codepoint != ref_info->codepoint)
+      result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
+    if (buf_info->cluster != ref_info->cluster)
+      result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
+    if ((buf_info->mask & HB_GLYPH_FLAG_DEFINED) != (ref_info->mask & HB_GLYPH_FLAG_DEFINED))
+      result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
+    if (contains && ref_info->codepoint == dottedcircle_glyph)
+      result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
+    if (contains && ref_info->codepoint == 0)
+      result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
+    buf_info++;
+    ref_info++;
+  }
+
+  if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)
+  {
+    assert (buffer->have_positions);
+    const hb_glyph_position_t *buf_pos = buffer->pos;
+    const hb_glyph_position_t *ref_pos = reference->pos;
+    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)
+      {
+        result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
+        break;
+      }
+      buf_pos++;
+      ref_pos++;
+    }
+  }
+
+  return result;
+}
+
+
 /*
  * Debugging.
  */
@@ -1803,9 +1995,9 @@
     buffer->message_data = user_data;
     buffer->message_destroy = destroy;
   } else {
-    buffer->message_func = NULL;
-    buffer->message_data = NULL;
-    buffer->message_destroy = NULL;
+    buffer->message_func = nullptr;
+    buffer->message_data = nullptr;
+    buffer->message_destroy = nullptr;
   }
 }
 
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index bf289c1..a8a4b84 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -63,7 +63,7 @@
  */
 typedef struct hb_glyph_info_t {
   hb_codepoint_t codepoint;
-  hb_mask_t      mask;
+  hb_mask_t      mask; /* Holds hb_glyph_flags_t after hb_shape(), plus other things. */
   uint32_t       cluster;
 
   /*< private >*/
@@ -71,6 +71,19 @@
   hb_var_int_t   var2;
 } hb_glyph_info_t;
 
+typedef enum { /*< flags >*/
+  HB_GLYPH_FLAG_UNSAFE_TO_BREAK		= 0x00000001,
+
+  HB_GLYPH_FLAG_DEFINED			= 0x00000001 /* OR of all defined flags */
+} hb_glyph_flags_t;
+
+HB_EXTERN hb_glyph_flags_t
+hb_glyph_info_get_glyph_flags (const hb_glyph_info_t *info);
+
+#define hb_glyph_info_get_glyph_flags(info) \
+	((hb_glyph_flags_t) ((unsigned int) (info)->mask & HB_GLYPH_FLAG_DEFINED))
+
+
 /**
  * hb_glyph_position_t:
  * @x_advance: how much the line advances after drawing this glyph when setting
@@ -119,8 +132,8 @@
 #define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
 				       HB_SCRIPT_INVALID, \
 				       HB_LANGUAGE_INVALID, \
-				       NULL, \
-				       NULL}
+				       (void *) 0, \
+				       (void *) 0}
 
 HB_EXTERN hb_bool_t
 hb_segment_properties_equal (const hb_segment_properties_t *a,
@@ -163,6 +176,7 @@
 hb_buffer_get_user_data (hb_buffer_t        *buffer,
 			 hb_user_data_key_t *key);
 
+
 /**
  * hb_buffer_content_type_t:
  * @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
@@ -359,6 +373,11 @@
 			  unsigned int          item_offset,
 			  int                   item_length);
 
+HB_EXTERN void
+hb_buffer_append (hb_buffer_t *buffer,
+		  hb_buffer_t *source,
+		  unsigned int start,
+		  unsigned int end);
 
 HB_EXTERN hb_bool_t
 hb_buffer_set_length (hb_buffer_t  *buffer,
@@ -403,7 +422,8 @@
   HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS		= 0x00000001u,
   HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS		= 0x00000002u,
   HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES	= 0x00000004u,
-  HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS	= 0x00000008u
+  HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS	= 0x00000008u,
+  HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS		= 0x00000010u
 } hb_buffer_serialize_flags_t;
 
 /**
@@ -453,6 +473,45 @@
 
 
 /*
+ * Compare buffers
+ */
+
+typedef enum { /*< flags >*/
+  HB_BUFFER_DIFF_FLAG_EQUAL			= 0x0000,
+
+  /* Buffers with different content_type cannot be meaningfully compared
+   * in any further detail. */
+  HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH	= 0x0001,
+
+  /* For buffers with differing length, the per-glyph comparison is not
+   * attempted, though we do still scan reference for dottedcircle / .notdef
+   * glyphs. */
+  HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH		= 0x0002,
+
+  /* We want to know if dottedcircle / .notdef glyphs are present in the
+   * reference, as we may not care so much about other differences in this
+   * case. */
+  HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT		= 0x0004,
+  HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT	= 0x0008,
+
+  /* If the buffers have the same length, we compare them glyph-by-glyph
+   * and report which aspect(s) of the glyph info/position are different. */
+  HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH	= 0x0010,
+  HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH		= 0x0020,
+  HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH	= 0x0040,
+  HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH		= 0x0080
+
+} hb_buffer_diff_flags_t;
+
+/* Compare the contents of two buffers, report types of differences. */
+HB_EXTERN hb_buffer_diff_flags_t
+hb_buffer_diff (hb_buffer_t *buffer,
+		hb_buffer_t *reference,
+		hb_codepoint_t dottedcircle_glyph,
+		unsigned int position_fuzz);
+
+
+/*
  * Debugging.
  */
 
diff --git a/src/hb-cache-private.hh b/src/hb-cache-private.hh
deleted file mode 100644
index 24957e1..0000000
--- a/src/hb-cache-private.hh
+++ /dev/null
@@ -1,74 +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
- */
-
-#ifndef HB_CACHE_PRIVATE_HH
-#define HB_CACHE_PRIVATE_HH
-
-#include "hb-private.hh"
-
-
-/* Implements a lock-free cache for int->int functions. */
-
-template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
-struct hb_cache_t
-{
-  ASSERT_STATIC (key_bits >= cache_bits);
-  ASSERT_STATIC (key_bits + value_bits - cache_bits < 8 * sizeof (unsigned int));
-
-  inline void clear (void)
-  {
-    memset (values, 255, sizeof (values));
-  }
-
-  inline bool get (unsigned int key, unsigned int *value)
-  {
-    unsigned int k = key & ((1u<<cache_bits)-1);
-    unsigned int v = values[k];
-    if ((v >> value_bits) != (key >> cache_bits))
-      return false;
-    *value = v & ((1u<<value_bits)-1);
-    return true;
-  }
-
-  inline bool set (unsigned int key, unsigned int value)
-  {
-    if (unlikely ((key >> key_bits) || (value >> value_bits)))
-      return false; /* Overflows */
-    unsigned int k = key & ((1u<<cache_bits)-1);
-    unsigned int v = ((key>>cache_bits)<<value_bits) | value;
-    values[k] = v;
-    return true;
-  }
-
-  private:
-  unsigned int values[1u<<cache_bits];
-};
-
-typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
-typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
-
-
-#endif /* HB_CACHE_PRIVATE_HH */
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 64e77d4..cb1fb43 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -32,6 +32,9 @@
 #include "hb-object-private.hh"
 
 #include <locale.h>
+#ifdef HAVE_XLOCALE_H
+#include <xlocale.h>
+#endif
 
 
 /* hb_options_t */
@@ -82,7 +85,7 @@
   for (; i < 4; i++)
     tag[i] = ' ';
 
-  return HB_TAG_CHAR4 (tag);
+  return HB_TAG (tag[0], tag[1], tag[2], tag[3]);
 }
 
 /**
@@ -186,8 +189,10 @@
   const unsigned char *p1 = (const unsigned char *) v1;
   const unsigned char *p2 = (const unsigned char *) v2;
 
-  while (*p1 && *p1 == canon_map[*p2])
-    p1++, p2++;
+  while (*p1 && *p1 == canon_map[*p2]) {
+    p1++;
+    p2++;
+  }
 
   return *p1 == canon_map[*p2];
 }
@@ -219,9 +224,18 @@
   }
 
   inline hb_language_item_t & operator = (const char *s) {
-    lang = (hb_language_t) strdup (s);
-    for (unsigned char *p = (unsigned char *) lang; *p; p++)
-      *p = canon_map[*p];
+    /* If a custom allocated is used calling strdup() pairs
+    badly with a call to the custom free() in finish() below.
+    Therefore don't call strdup(), implement its behavior.
+    */
+    size_t len = strlen(s) + 1;
+    lang = (hb_language_t) malloc(len);
+    if (likely (lang))
+    {
+      memcpy((unsigned char *) lang, s, len);
+      for (unsigned char *p = (unsigned char *) lang; *p; p++)
+	*p = canon_map[*p];
+    }
 
     return *this;
   }
@@ -235,8 +249,8 @@
 static hb_language_item_t *langs;
 
 #ifdef HB_USE_ATEXIT
-static
-void free_langs (void)
+static void
+free_langs (void)
 {
   while (langs) {
     hb_language_item_t *next = langs->next;
@@ -260,9 +274,14 @@
   /* Not found; allocate one. */
   hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
   if (unlikely (!lang))
-    return NULL;
+    return nullptr;
   lang->next = first_lang;
   *lang = key;
+  if (unlikely (!lang->lang))
+  {
+    free (lang);
+    return nullptr;
+  }
 
   if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
     lang->finish ();
@@ -299,7 +318,7 @@
   if (!str || !len || !*str)
     return HB_LANGUAGE_INVALID;
 
-  hb_language_item_t *item = NULL;
+  hb_language_item_t *item = nullptr;
   if (len >= 0)
   {
     /* NUL-terminate it. */
@@ -330,7 +349,7 @@
 const char *
 hb_language_to_string (hb_language_t language)
 {
-  /* This is actually NULL-safe! */
+  /* This is actually nullptr-safe! */
   return language->s;
 }
 
@@ -350,7 +369,7 @@
 
   hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
   if (unlikely (language == HB_LANGUAGE_INVALID)) {
-    language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
+    language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
     (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
   }
 
@@ -543,9 +562,9 @@
 void *
 hb_user_data_array_t::get (hb_user_data_key_t *key)
 {
-  hb_user_data_item_t item = {NULL, NULL, NULL};
+  hb_user_data_item_t item = {nullptr, nullptr, nullptr};
 
-  return items.find (key, &item, lock) ? item.data : NULL;
+  return items.find (key, &item, lock) ? item.data : nullptr;
 }
 
 
@@ -655,6 +674,81 @@
 }
 
 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;
+
+  *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
+
+static HB_LOCALE_T C_locale;
+
+#ifdef HB_USE_ATEXIT
+static void
+free_C_locale (void)
+{
+  if (C_locale)
+    HB_FREE_LOCALE (C_locale);
+}
+#endif
+
+static HB_LOCALE_T
+get_C_locale (void)
+{
+retry:
+  HB_LOCALE_T C = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
+
+  if (unlikely (!C))
+  {
+    C = HB_CREATE_LOCALE ("C");
+
+    if (!hb_atomic_ptr_cmpexch (&C_locale, nullptr, C))
+    {
+      HB_FREE_LOCALE (C_locale);
+      goto retry;
+    }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_C_locale); /* First person registers atexit() callback. */
+#endif
+  }
+
+  return C;
+}
+#endif
+
+static bool
 parse_float (const char **pp, const char *end, float *pv)
 {
   char buf[32];
@@ -667,7 +761,11 @@
   float v;
 
   errno = 0;
-  v = strtof (p, &pend);
+#ifdef USE_XLOCALE
+  v = strtod_l (p, &pend, get_C_locale ());
+#else
+  v = strtod (p, &pend);
+#endif
   if (errno || p == pend)
     return false;
 
@@ -677,7 +775,7 @@
 }
 
 static bool
-parse_bool (const char **pp, const char *end, unsigned int *pv)
+parse_bool (const char **pp, const char *end, uint32_t *pv)
 {
   parse_space (pp, end);
 
@@ -686,9 +784,9 @@
     (*pp)++;
 
   /* CSS allows on/off as aliases 1/0. */
-  if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
+  if (*pp - p == 2 && 0 == strncmp (p, "on", 2))
     *pv = 1;
-  else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
+  else if (*pp - p == 3 && 0 == strncmp (p, "off", 3))
     *pv = 0;
   else
     return false;
@@ -776,7 +874,7 @@
 parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
 {
   bool had_equal = parse_char (pp, end, '=');
-  bool had_value = parse_uint (pp, end, &feature->value) ||
+  bool had_value = parse_uint32 (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.
diff --git a/src/hb-common.h b/src/hb-common.h
index 634cb96..26200ce 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -43,30 +43,16 @@
 # endif /* !__cplusplus */
 #endif
 
-#if !defined (HB_DONT_DEFINE_STDINT)
-
 #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>
-/* VS 2010 (_MSC_VER 1600) has stdint.h */
-#elif defined (_MSC_VER) && _MSC_VER < 1600
-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
 
-#endif
-
 HB_BEGIN_DECLS
 
 
@@ -148,7 +134,7 @@
 HB_EXTERN const char *
 hb_language_to_string (hb_language_t language);
 
-#define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
+#define HB_LANGUAGE_INVALID ((hb_language_t) 0)
 
 HB_EXTERN hb_language_t
 hb_language_get_default (void);
@@ -321,6 +307,14 @@
   /*9.0*/ HB_SCRIPT_TANGUT			= HB_TAG ('T','a','n','g'),
   /*9.0*/ HB_SCRIPT_NEWA			= HB_TAG ('N','e','w','a'),
 
+  /*
+   * Since 1.6.0
+   */
+  /*10.0*/HB_SCRIPT_MASARAM_GONDI		= HB_TAG ('G','o','n','m'),
+  /*10.0*/HB_SCRIPT_NUSHU			= HB_TAG ('N','s','h','u'),
+  /*10.0*/HB_SCRIPT_SOYOMBO			= HB_TAG ('S','o','y','o'),
+  /*10.0*/HB_SCRIPT_ZANABAZAR_SQUARE		= HB_TAG ('Z','a','n','b'),
+
   /* No script set. */
   HB_SCRIPT_INVALID				= HB_TAG_NONE,
 
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index e857dfa..4402017 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -27,15 +27,34 @@
  */
 
 #define HB_SHAPER coretext
+
+#include "hb-private.hh"
+#include "hb-debug.hh"
 #include "hb-shaper-impl-private.hh"
 
 #include "hb-coretext.h"
+#include <math.h>
 
+/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
+#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
 
-#ifndef HB_DEBUG_CORETEXT
-#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
-#endif
-
+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)
@@ -50,32 +69,29 @@
   CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
   CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
   if (unlikely (!cf_data))
-    return NULL;
+    return nullptr;
 
   const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
   const size_t length = CFDataGetLength (cf_data);
   if (!data || !length)
-    return NULL;
+    return nullptr;
 
   return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
 			 reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
 			 release_table_data);
 }
 
-hb_face_t *
-hb_coretext_face_create (CGFontRef cg_font)
+static void
+_hb_cg_font_release (void *data)
 {
-  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
+  CGFontRelease ((CGFontRef) data);
 }
 
 
-HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
-HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
-
-
-/*
- * shaper face data
- */
+HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face)
+HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(coretext, font,
+	fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) <= .5
+)
 
 static CTFontDescriptorRef
 get_last_resort_font_desc (void)
@@ -104,7 +120,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, NULL) == data);
+          hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
 
   hb_blob_destroy ((hb_blob_t *) info);
 }
@@ -112,8 +128,8 @@
 static CGFontRef
 create_cg_font (hb_face_t *face)
 {
-  CGFontRef cg_font = NULL;
-  if (face->destroy == (hb_destroy_func_t) CGFontRelease)
+  CGFontRef cg_font = nullptr;
+  if (face->destroy == _hb_cg_font_release)
   {
     cg_font = CGFontRetain ((CGFontRef) face->user_data);
   }
@@ -140,10 +156,36 @@
 static CTFontRef
 create_ct_font (CGFontRef cg_font, CGFloat font_size)
 {
-  CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
+  CTFontRef ct_font = nullptr;
+
+  /* CoreText does not enable trak table usage / tracking when creating a CTFont
+   * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
+   * to be through the CTFontCreateUIFontForLanguage call. */
+  CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
+  if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
+      CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
+  {
+    CTFontUIFontType font_type = kCTFontUIFontSystem;
+    if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
+      font_type = kCTFontUIFontEmphasizedSystem;
+
+    ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
+    CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
+    if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
+    {
+      CFRelease(ct_font);
+      ct_font = nullptr;
+    }
+    CFRelease (ct_result_name);
+  }
+  CFRelease (cg_postscript_name);
+
+  if (!ct_font)
+    ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
+
   if (unlikely (!ct_font)) {
     DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
-    return NULL;
+    return nullptr;
   }
 
   /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
@@ -153,7 +195,7 @@
    * reconfiguring the cascade list causes CoreText crashes. For details, see
    * crbug.com/549610 */
   // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
-  if (&CTGetCoreTextVersion != NULL && CTGetCoreTextVersion() < 0x00070000) {
+  if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
     CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
     bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
     CFRelease (fontName);
@@ -167,7 +209,7 @@
    * font fallback which we don't need anyway. */
   {
     CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
-    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, last_resort_font_desc);
+    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
     CFRelease (last_resort_font_desc);
     if (new_ct_font)
     {
@@ -202,51 +244,30 @@
   return ct_font;
 }
 
-struct hb_coretext_shaper_face_data_t {
-  CGFontRef cg_font;
-  CTFontRef ct_font;
-};
-
 hb_coretext_shaper_face_data_t *
 _hb_coretext_shaper_face_data_create (hb_face_t *face)
 {
-  hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
-  if (unlikely (!data))
-    return NULL;
+  CGFontRef cg_font = create_cg_font (face);
 
-  data->cg_font = create_cg_font (face);
-  if (unlikely (!data->cg_font))
+  if (unlikely (!cg_font))
   {
     DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
-    free (data);
-    return NULL;
+    return nullptr;
   }
 
-  /* We use 36pt size instead of UPEM, because CoreText implements the 'trak' table,
-   * which can make the font too tight at large sizes.  36pt should be a good semi-neutral
-   * size.
-   *
-   * Since we always create CTFont at a fixed size, our CTFont lives in face_data
-   * instead of font_data.  Which is good, because when people change scale on
-   * hb_font_t, we won't need to update our CTFont. */
-  data->ct_font = create_ct_font (data->cg_font, 36.);
-  if (unlikely (!data->ct_font))
-  {
-    DEBUG_MSG (CORETEXT, face, "CTFont creation failed.");
-    CFRelease (data->cg_font);
-    free (data);
-    return NULL;
-  }
-
-  return data;
+  return (hb_coretext_shaper_face_data_t *) cg_font;
 }
 
 void
 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
 {
-  CFRelease (data->ct_font);
-  CFRelease (data->cg_font);
-  free (data);
+  CFRelease ((CGFontRef) data);
+}
+
+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);
 }
 
 /*
@@ -255,29 +276,66 @@
 CGFontRef
 hb_coretext_face_get_cg_font (hb_face_t *face)
 {
-  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
-  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-  return face_data->cg_font;
+  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
+  return (CGFontRef) HB_SHAPER_DATA_GET (face);
 }
 
 
-/*
- * shaper font data
- */
-
-struct hb_coretext_shaper_font_data_t {};
-
 hb_coretext_shaper_font_data_t *
-_hb_coretext_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+_hb_coretext_shaper_font_data_create (hb_font_t *font)
 {
-  return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+  hb_face_t *face = font->face;
+  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
+  CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
+
+  CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size_from_ptem (font->ptem));
+
+  if (unlikely (!ct_font))
+  {
+    DEBUG_MSG (CORETEXT, font, "CGFont creation failed..");
+    return nullptr;
+  }
+
+  return (hb_coretext_shaper_font_data_t *) ct_font;
 }
 
 void
 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
 {
+  CFRelease ((CTFontRef) data);
 }
 
+/*
+ * Since: 1.7.2
+ */
+hb_font_t *
+hb_coretext_font_create (CTFontRef ct_font)
+{
+  CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, 0);
+  hb_face_t *face = hb_coretext_face_create (cg_font);
+  CFRelease (cg_font);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+
+  if (unlikely (hb_object_is_inert (font)))
+    return font;
+
+  hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font)));
+
+  /* Let there be dragons here... */
+  HB_SHAPER_DATA_GET (font) = (hb_coretext_shaper_font_data_t *) CFRetain (ct_font);
+
+  return font;
+}
+
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font)
+{
+  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
+  return (CTFontRef) HB_SHAPER_DATA_GET (font);
+}
+
+
 
 /*
  * shaper shape_plan data
@@ -300,15 +358,6 @@
 {
 }
 
-CTFontRef
-hb_coretext_font_get_ct_font (hb_font_t *font)
-{
-  hb_face_t *face = font->face;
-  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
-  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-  return face_data->ct_font;
-}
-
 
 /*
  * shaper
@@ -323,7 +372,9 @@
   feature_record_t rec;
   unsigned int order;
 
-  static int cmp (const active_feature_t *a, const active_feature_t *b) {
+  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 :
 	   a->order < b->order ? -1 : a->order > b->order ? 1 :
 	   a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
@@ -339,7 +390,9 @@
   bool start;
   active_feature_t feature;
 
-  static int cmp (const feature_event_t *a, const feature_event_t *b) {
+  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 :
 	   a->start < b->start ? -1 : a->start > b->start ? 1 :
 	   active_feature_t::cmp (&a->feature, &b->feature);
@@ -538,9 +591,10 @@
                     unsigned int        num_features)
 {
   hb_face_t *face = font->face;
-  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
+  CTFontRef ct_font = (CTFontRef) HB_SHAPER_DATA_GET (font);
 
-  CGFloat ct_font_size = CTFontGetSize (face_data->ct_font);
+  CGFloat ct_font_size = CTFontGetSize (ct_font);
   CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
   CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
 
@@ -641,22 +695,23 @@
 	  /* active_features.qsort (); */
 	  for (unsigned int j = 0; j < active_features.len; j++)
 	  {
-	    CFStringRef keys[2] = {
+	    CFStringRef keys[] = {
 	      kCTFontFeatureTypeIdentifierKey,
 	      kCTFontFeatureSelectorIdentifierKey
 	    };
-	    CFNumberRef values[2] = {
+	    CFNumberRef values[] = {
 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
 	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
 	    };
+	    static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), "");
 	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
 						       (const void **) keys,
 						       (const void **) values,
-						       2,
+						       ARRAY_LENGTH (keys),
 						       &kCFTypeDictionaryKeyCallBacks,
 						       &kCFTypeDictionaryValueCallBacks);
-	    CFRelease (values[0]);
-	    CFRelease (values[1]);
+	    for (unsigned int i = 0; i < ARRAY_LENGTH (values); i++)
+	      CFRelease (values[i]);
 
 	    CFArrayAppendValue (features_array, dict);
 	    CFRelease (dict);
@@ -674,12 +729,12 @@
 	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
 	  CFRelease (attributes);
 
-	  range->font = CTFontCreateCopyWithAttributes (face_data->ct_font, 0.0, NULL, font_desc);
+	  range->font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, font_desc);
 	  CFRelease (font_desc);
 	}
 	else
 	{
-	  range->font = NULL;
+	  range->font = nullptr;
 	}
 
 	range->index_first = last_index;
@@ -699,9 +754,6 @@
 	  active_features.remove (feature - active_features.array);
       }
     }
-
-    if (!range_records.len) /* No active feature found. */
-      goto fail_features;
   }
   else
   {
@@ -752,14 +804,14 @@
 
 #define FAIL(...) \
   HB_STMT_START { \
-    DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
+    DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
     ret = false; \
     goto fail; \
   } HB_STMT_END;
 
   bool ret = true;
-  CFStringRef string_ref = NULL;
-  CTLineRef line = NULL;
+  CFStringRef string_ref = nullptr;
+  CTLineRef line = nullptr;
 
   if (0)
   {
@@ -771,8 +823,8 @@
     assert (line);
     CFRelease (string_ref);
     CFRelease (line);
-    string_ref = NULL;
-    line = NULL;
+    string_ref = nullptr;
+    line = nullptr;
 
     /* Get previous start-of-scratch-area, that we use later for readjusting
      * our existing scratch arrays. */
@@ -793,7 +845,7 @@
     scratch_size -= old_scratch_used;
   }
   {
-    string_ref = CFStringCreateWithCharactersNoCopy (NULL,
+    string_ref = CFStringCreateWithCharactersNoCopy (nullptr,
 						     pchars, chars_len,
 						     kCFAllocatorNull);
     if (unlikely (!string_ref))
@@ -831,9 +883,9 @@
 	CFRelease (lang);
       }
       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
-				      kCTFontAttributeName, face_data->ct_font);
+				      kCTFontAttributeName, ct_font);
 
-      if (num_features)
+      if (num_features && range_records.len)
       {
 	unsigned int start = 0;
 	range_record_t *last_range = &range_records[0];
@@ -859,6 +911,30 @@
 	  CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
 					  kCTFontAttributeName, last_range->font);
       }
+      /* Enable/disable kern if requested.
+       *
+       * Note: once kern is disabled, reenabling it doesn't currently seem to work in CoreText.
+       */
+      if (num_features)
+      {
+	unsigned int zeroint = 0;
+	CFNumberRef zero = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &zeroint);
+	for (unsigned int i = 0; i < num_features; i++)
+	{
+	  const hb_feature_t &feature = features[i];
+	  if (feature.tag == HB_TAG('k','e','r','n') &&
+	      feature.start < chars_len && feature.start < feature.end)
+	  {
+	    CFRange feature_range = CFRangeMake (feature.start,
+	                                         MIN (feature.end, chars_len) - feature.start);
+	    if (feature.value)
+	      CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
+	    else
+	      CFAttributedStringSetAttribute (attr_string, feature_range, kCTKernAttributeName, zero);
+	  }
+	}
+	CFRelease (zero);
+      }
 
       int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
       CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
@@ -868,6 +944,7 @@
 						    1,
 						    &kCFTypeDictionaryKeyCallBacks,
 						    &kCFTypeDictionaryValueCallBacks);
+      CFRelease (level_number);
       if (unlikely (!options))
         FAIL ("CFDictionaryCreate failed");
 
@@ -885,7 +962,7 @@
 
     CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
     unsigned int num_runs = CFArrayGetCount (glyph_runs);
-    DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs);
+    DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
 
     buffer->len = 0;
     uint32_t status_and = ~0, status_or = 0;
@@ -911,7 +988,7 @@
       status_or  |= run_status;
       status_and &= run_status;
       DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
-      double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
+      double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
 	  run_advance = -run_advance;
       DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
@@ -924,7 +1001,7 @@
        */
       CFDictionaryRef attributes = CTRunGetAttributes (run);
       CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
-      if (!CFEqual (run_ct_font, face_data->ct_font))
+      if (!CFEqual (run_ct_font, ct_font))
       {
 	/* The run doesn't use our main font instance.  We have to figure out
 	 * whether font fallback happened, or this is just CoreText giving us
@@ -946,7 +1023,7 @@
 	 * However, even that wouldn't work if we were passed in the CGFont to
 	 * construct a hb_face to begin with.
 	 *
-	 * See: http://github.com/behdad/harfbuzz/pull/36
+	 * See: http://github.com/harfbuzz/harfbuzz/pull/36
 	 *
 	 * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
 	 */
@@ -962,13 +1039,13 @@
 	  CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
 	  if (run_cg_font)
 	  {
-	    matched = CFEqual (run_cg_font, face_data->cg_font);
+	    matched = CFEqual (run_cg_font, cg_font);
 	    CFRelease (run_cg_font);
 	  }
 	}
 	if (!matched)
 	{
-	  CFStringRef font_ps_name = CTFontCopyName (face_data->ct_font, kCTFontPostScriptNameKey);
+	  CFStringRef font_ps_name = CTFontCopyName (ct_font, kCTFontPostScriptNameKey);
 	  CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
 	  CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
 	  CFRelease (run_ps_name);
@@ -1037,7 +1114,7 @@
 
       /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
        * succeed, and so copying data to our own buffer will be rare.  Reports
-       * have it that this changed in OS X 10.10 Yosemite, and NULL is returned
+       * have it that this changed in OS X 10.10 Yosemite, and nullptr is returned
        * frequently.  At any rate, we can test that codepath by setting USE_PTR
        * to false. */
 
@@ -1053,13 +1130,13 @@
 
       { /* Setup glyphs */
         SCRATCH_SAVE();
-	const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
+	const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : nullptr;
 	if (!glyphs) {
 	  ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
 	  CTRunGetGlyphs (run, range_all, glyph_buf);
 	  glyphs = glyph_buf;
 	}
-	const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL;
+	const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : nullptr;
 	if (!string_indices) {
 	  ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
 	  CTRunGetStringIndices (run, range_all, index_buf);
@@ -1081,7 +1158,7 @@
 	 * 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();
-	const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
+	const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : nullptr;
 	if (!positions) {
 	  ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
 	  CTRunGetPositions (run, range_all, position_buf);
@@ -1157,6 +1234,9 @@
 	pos->x_advance = info->mask;
 	pos->x_offset = info->var1.i32;
 	pos->y_offset = info->var2.i32;
+
+	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+
 	info++, pos++;
       }
     else
@@ -1165,6 +1245,9 @@
 	pos->y_advance = info->mask;
 	pos->x_offset = info->var1.i32;
 	pos->y_offset = info->var2.i32;
+
+	info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+
 	info++, pos++;
       }
 
@@ -1202,6 +1285,8 @@
     }
   }
 
+  buffer->unsafe_to_break_all ();
+
 #undef FAIL
 
 fail:
@@ -1222,6 +1307,9 @@
  * AAT shaper
  */
 
+HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, face)
+HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font)
+
 /*
  * shaper face data
  */
@@ -1231,22 +1319,20 @@
 hb_coretext_aat_shaper_face_data_t *
 _hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
 {
-  hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
-  /* Umm, we just reference the table to check whether it exists.
-   * Maybe add better API for this? */
-  if (!hb_blob_get_length (mort_blob))
-  {
-    hb_blob_destroy (mort_blob);
-    mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
-    if (!hb_blob_get_length (mort_blob))
-    {
-      hb_blob_destroy (mort_blob);
-      return NULL;
-    }
-  }
-  hb_blob_destroy (mort_blob);
+  static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX};
 
-  return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+  for (unsigned int i = 0; i < ARRAY_LENGTH (tags); i++)
+  {
+    hb_blob_t *blob = face->reference_table (tags[i]);
+    if (hb_blob_get_length (blob))
+    {
+      hb_blob_destroy (blob);
+      return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
+    }
+    hb_blob_destroy (blob);
+  }
+
+  return nullptr;
 }
 
 void
@@ -1264,7 +1350,7 @@
 hb_coretext_aat_shaper_font_data_t *
 _hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
 {
-  return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+  return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
 }
 
 void
diff --git a/src/hb-coretext.h b/src/hb-coretext.h
index 82066e4..4b0a6f0 100644
--- a/src/hb-coretext.h
+++ b/src/hb-coretext.h
@@ -42,11 +42,15 @@
 
 #define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
 #define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
+#define HB_CORETEXT_TAG_KERX HB_TAG('k','e','r','x')
 
 
 HB_EXTERN hb_face_t *
 hb_coretext_face_create (CGFontRef cg_font);
 
+HB_EXTERN hb_font_t *
+hb_coretext_font_create (CTFontRef ct_font);
+
 
 HB_EXTERN CGFontRef
 hb_coretext_face_get_cg_font (hb_face_t *face);
diff --git a/src/hb-debug.hh b/src/hb-debug.hh
new file mode 100644
index 0000000..6c425f7
--- /dev/null
+++ b/src/hb-debug.hh
@@ -0,0 +1,431 @@
+/*
+ * 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_DEBUG_HH
+#define HB_DEBUG_HH
+
+#include "hb-private.hh"
+
+
+#ifndef HB_DEBUG
+#define HB_DEBUG 0
+#endif
+
+static inline bool
+_hb_debug (unsigned int level,
+	   unsigned int max_level)
+{
+  return level < max_level;
+}
+
+#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
+#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
+
+static inline void
+_hb_print_func (const char *func)
+{
+  if (func)
+  {
+    unsigned int func_len = strlen (func);
+    /* Skip "static" */
+    if (0 == strncmp (func, "static ", 7))
+      func += 7;
+    /* Skip "typename" */
+    if (0 == strncmp (func, "typename ", 9))
+      func += 9;
+    /* Skip return type */
+    const char *space = strchr (func, ' ');
+    if (space)
+      func = space + 1;
+    /* Skip parameter list */
+    const char *paren = strchr (func, '(');
+    if (paren)
+      func_len = paren - func;
+    fprintf (stderr, "%.*s", func_len, func);
+  }
+}
+
+template <int max_level> static inline void
+_hb_debug_msg_va (const char *what,
+		  const void *obj,
+		  const char *func,
+		  bool indented,
+		  unsigned int level,
+		  int level_dir,
+		  const char *message,
+		  va_list ap) HB_PRINTF_FUNC(7, 0);
+template <int max_level> static inline void
+_hb_debug_msg_va (const char *what,
+		  const void *obj,
+		  const char *func,
+		  bool indented,
+		  unsigned int level,
+		  int level_dir,
+		  const char *message,
+		  va_list ap)
+{
+  if (!_hb_debug (level, max_level))
+    return;
+
+  fprintf (stderr, "%-10s", what ? what : "");
+
+  if (obj)
+    fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj);
+  else
+    fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");
+
+  if (indented) {
+#define VBAR	"\342\224\202"	/* U+2502 BOX DRAWINGS LIGHT VERTICAL */
+#define VRBAR	"\342\224\234"	/* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+#define DLBAR	"\342\225\256"	/* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
+#define ULBAR	"\342\225\257"	/* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
+#define LBAR	"\342\225\264"	/* U+2574 BOX DRAWINGS LIGHT LEFT */
+    static const char bars[] =
+      VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+      VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+      VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+      VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+      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),
+	     level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
+  } else
+    fprintf (stderr, "   " VRBAR LBAR);
+
+  _hb_print_func (func);
+
+  if (message)
+  {
+    fprintf (stderr, ": ");
+    vfprintf (stderr, message, ap);
+  }
+
+  fprintf (stderr, "\n");
+}
+template <> inline void
+_hb_debug_msg_va<0> (const char *what HB_UNUSED,
+		     const void *obj HB_UNUSED,
+		     const char *func HB_UNUSED,
+		     bool indented HB_UNUSED,
+		     unsigned int level HB_UNUSED,
+		     int level_dir HB_UNUSED,
+		     const char *message HB_UNUSED,
+		     va_list ap HB_UNUSED) {}
+
+template <int max_level> static inline void
+_hb_debug_msg (const char *what,
+	       const void *obj,
+	       const char *func,
+	       bool indented,
+	       unsigned int level,
+	       int level_dir,
+	       const char *message,
+	       ...) HB_PRINTF_FUNC(7, 8);
+template <int max_level> static inline void
+_hb_debug_msg (const char *what,
+	       const void *obj,
+	       const char *func,
+	       bool indented,
+	       unsigned int level,
+	       int level_dir,
+	       const char *message,
+	       ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
+  va_end (ap);
+}
+template <> inline void
+_hb_debug_msg<0> (const char *what HB_UNUSED,
+		  const void *obj HB_UNUSED,
+		  const char *func HB_UNUSED,
+		  bool indented HB_UNUSED,
+		  unsigned int level HB_UNUSED,
+		  int level_dir HB_UNUSED,
+		  const char *message HB_UNUSED,
+		  ...) HB_PRINTF_FUNC(7, 8);
+template <> inline void
+_hb_debug_msg<0> (const char *what HB_UNUSED,
+		  const void *obj HB_UNUSED,
+		  const char *func HB_UNUSED,
+		  bool indented HB_UNUSED,
+		  unsigned int level HB_UNUSED,
+		  int level_dir HB_UNUSED,
+		  const char *message HB_UNUSED,
+		  ...) {}
+
+#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)	_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
+#define DEBUG_MSG(WHAT, OBJ, ...) 				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr,    false, 0, 0, __VA_ARGS__)
+#define DEBUG_MSG_FUNC(WHAT, OBJ, ...)				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
+
+
+/*
+ * Printer
+ */
+
+template <typename T>
+struct hb_printer_t {
+  const char *print (const T&) { return "something"; }
+};
+
+template <>
+struct hb_printer_t<bool> {
+  const char *print (bool v) { return v ? "true" : "false"; }
+};
+
+template <>
+struct hb_printer_t<hb_void_t> {
+  const char *print (hb_void_t) { return ""; }
+};
+
+
+/*
+ * Trace
+ */
+
+template <typename T>
+static inline void _hb_warn_no_return (bool returned)
+{
+  if (unlikely (!returned)) {
+    fprintf (stderr, "OUCH, returned with no call to return_trace().  This is a bug, please report.\n");
+  }
+}
+template <>
+/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
+{}
+
+template <int max_level, typename ret_t>
+struct hb_auto_trace_t
+{
+  explicit inline hb_auto_trace_t (unsigned int *plevel_,
+				   const char *what_,
+				   const void *obj_,
+				   const char *func,
+				   const char *message,
+				   ...) HB_PRINTF_FUNC(6, 7)
+				   : plevel (plevel_), what (what_), obj (obj_), returned (false)
+  {
+    if (plevel) ++*plevel;
+
+    va_list ap;
+    va_start (ap, message);
+    _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
+    va_end (ap);
+  }
+  inline ~hb_auto_trace_t (void)
+  {
+    _hb_warn_no_return<ret_t> (returned);
+    if (!returned) {
+      _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, " ");
+    }
+    if (plevel) --*plevel;
+  }
+
+  inline ret_t ret (ret_t v, unsigned int line = 0)
+  {
+    if (unlikely (returned)) {
+      fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
+      return v;
+    }
+
+    _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1,
+			      "return %s (line %d)",
+			      hb_printer_t<ret_t>().print (v), line);
+    if (plevel) --*plevel;
+    plevel = nullptr;
+    returned = true;
+    return v;
+  }
+
+  private:
+  unsigned int *plevel;
+  const char *what;
+  const void *obj;
+  bool returned;
+};
+template <typename ret_t> /* Make sure we don't use hb_auto_trace_t when not tracing. */
+struct hb_auto_trace_t<0, ret_t>
+{
+  explicit inline hb_auto_trace_t (unsigned int *plevel_,
+				   const char *what_,
+				   const void *obj_,
+				   const char *func,
+				   const char *message,
+				   ...) HB_PRINTF_FUNC(6, 7) {}
+
+  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
+};
+
+/* For disabled tracing; optimize out everything.
+ * https://github.com/harfbuzz/harfbuzz/pull/605 */
+template <typename ret_t>
+struct hb_no_trace_t {
+  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
+};
+
+#define return_trace(RET) return trace.ret (RET, __LINE__)
+
+
+/*
+ * Instances.
+ */
+
+#ifndef HB_DEBUG_ARABIC
+#define HB_DEBUG_ARABIC (HB_DEBUG+0)
+#endif
+
+#ifndef HB_DEBUG_BLOB
+#define HB_DEBUG_BLOB (HB_DEBUG+0)
+#endif
+
+#ifndef HB_DEBUG_CORETEXT
+#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
+#endif
+
+#ifndef HB_DEBUG_DIRECTWRITE
+#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
+#endif
+
+#ifndef HB_DEBUG_FT
+#define HB_DEBUG_FT (HB_DEBUG+0)
+#endif
+
+#ifndef HB_DEBUG_GET_COVERAGE
+#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
+#endif
+
+#ifndef HB_DEBUG_OBJECT
+#define HB_DEBUG_OBJECT (HB_DEBUG+0)
+#endif
+
+#ifndef HB_DEBUG_SHAPE_PLAN
+#define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
+#endif
+
+#ifndef HB_DEBUG_UNISCRIBE
+#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
+#endif
+
+/*
+ * With tracing.
+ */
+
+#ifndef HB_DEBUG_APPLY
+#define HB_DEBUG_APPLY (HB_DEBUG+0)
+#endif
+#if HB_DEBUG_APPLY
+#define TRACE_APPLY(this) \
+	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
+	 "idx %d gid %u lookup %d", \
+	 c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index)
+#else
+#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
+#if HB_DEBUG_SANITIZE
+#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
+
+#ifndef HB_DEBUG_SERIALIZE
+#define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
+#endif
+#if HB_DEBUG_SERIALIZE
+#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
+
+#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_WOULD_APPLY + \
+	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);
+#else
+#define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
+#endif
+
+
+#endif /* HB_DEBUG_HH */
diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h
index 0398dfa..eac7efb 100644
--- a/src/hb-deprecated.h
+++ b/src/hb-deprecated.h
@@ -34,6 +34,7 @@
 #include "hb-common.h"
 #include "hb-unicode.h"
 #include "hb-font.h"
+#include "hb-set.h"
 
 HB_BEGIN_DECLS
 
@@ -54,6 +55,9 @@
 			      hb_font_get_glyph_func_t func,
 			      void *user_data, hb_destroy_func_t destroy);
 
+HB_EXTERN void
+hb_set_invert (hb_set_t *set);
+
 #endif
 
 HB_END_DECLS
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index d63bc04..0674ef9 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -22,6 +22,8 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
+#include "hb-private.hh"
+#include "hb-debug.hh"
 #define HB_SHAPER directwrite
 #include "hb-shaper-impl-private.hh"
 
@@ -30,12 +32,8 @@
 #include "hb-directwrite.h"
 
 
-#ifndef HB_DEBUG_DIRECTWRITE
-#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
-#endif
-
-HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, face)
-HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, font)
+HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, face)
+HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, font)
 
 
 /*
@@ -140,7 +138,7 @@
   hb_directwrite_shaper_face_data_t *data =
     (hb_directwrite_shaper_face_data_t *) malloc (sizeof (hb_directwrite_shaper_face_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   // TODO: factory and fontFileLoader should be cached separately
   IDWriteFactory* dwriteFactory;
@@ -153,7 +151,7 @@
   HRESULT hr;
   hb_blob_t *blob = hb_face_reference_blob (face);
   IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
-    (uint8_t*) hb_blob_get_data (blob, NULL), hb_blob_get_length (blob));
+    (uint8_t*) hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob));
 
   IDWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
   dwriteFactory->RegisterFontFileLoader (fontFileLoader);
@@ -165,7 +163,7 @@
 
 #define FAIL(...) \
   HB_STMT_START { \
-    DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
+    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
     return false; \
   } HB_STMT_END;
 
@@ -233,12 +231,12 @@
 hb_directwrite_shaper_font_data_t *
 _hb_directwrite_shaper_font_data_create (hb_font_t *font)
 {
-  if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NULL;
+  if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return nullptr;
 
   hb_directwrite_shaper_font_data_t *data =
     (hb_directwrite_shaper_font_data_t *) malloc (sizeof (hb_directwrite_shaper_font_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   return data;
 }
@@ -313,7 +311,7 @@
     , mTextLength(textLength)
     , mLocaleName(localeName)
     , mReadingDirection(readingDirection)
-    , mCurrentRun(NULL) { };
+    , mCurrentRun(nullptr) { };
 
   ~TextAnalysis() {
     // delete runs, except mRunHead which is part of the TextAnalysis object
@@ -337,7 +335,7 @@
     mRunHead.mTextLength = mTextLength;
     mRunHead.mBidiLevel =
       (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
-    mRunHead.nextRun = NULL;
+    mRunHead.nextRun = nullptr;
     mCurrentRun = &mRunHead;
 
     // Call each of the analyzers in sequence, recording their results.
@@ -356,7 +354,7 @@
   {
     if (textPosition >= mTextLength) {
       // No text at this position, valid query though.
-      *textString = NULL;
+      *textString = nullptr;
       *textLength = 0;
     }
     else {
@@ -373,7 +371,7 @@
     if (textPosition == 0 || textPosition > mTextLength) {
       // Either there is no text before here (== 0), or this
       // is an invalid position. The query is considered valid thouh.
-      *textString = NULL;
+      *textString = nullptr;
       *textLength = 0;
     }
     else {
@@ -399,7 +397,7 @@
     OUT IDWriteNumberSubstitution** numberSubstitution)
   {
     // We do not support number substitution.
-    *numberSubstitution = NULL;
+    *numberSubstitution = nullptr;
     *textLength = mTextLength - textPosition;
 
     return S_OK;
@@ -617,14 +615,14 @@
   */
   uint32_t textLength = buffer->len;
 
-  TextAnalysis analysis(textString, textLength, NULL, readingDirection);
+  TextAnalysis analysis(textString, textLength, nullptr, readingDirection);
   TextAnalysis::Run *runHead;
   HRESULT hr;
   hr = analysis.GenerateResults(analyzer, &runHead);
 
 #define FAIL(...) \
   HB_STMT_START { \
-    DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
+    DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
     return false; \
   } HB_STMT_END;
 
@@ -639,7 +637,7 @@
   bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
   const wchar_t localeName[20] = {0};
-  if (buffer->props.language != NULL)
+  if (buffer->props.language != nullptr)
   {
     mbstowcs ((wchar_t*) localeName,
       hb_language_to_string (buffer->props.language), 20);
@@ -672,7 +670,7 @@
     malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
 
   hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
-    isRightToLeft, &runHead->mScript, localeName, NULL, &dwFeatures,
+    isRightToLeft, &runHead->mScript, localeName, nullptr, &dwFeatures,
     featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
     glyphProperties, &glyphCount);
 
@@ -880,6 +878,8 @@
     pos->x_offset =
       x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
     pos->y_offset = y_mult * info->var2.i32;
+
+    info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
   }
 
   if (isRightToLeft)
@@ -927,8 +927,7 @@
   hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
     features, num_features, width);
 
-  if (res)
-    buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
+  buffer->unsafe_to_break_all ();
 
   return res;
 }
diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh
new file mode 100644
index 0000000..e413847
--- /dev/null
+++ b/src/hb-dsalgs.hh
@@ -0,0 +1,161 @@
+/*
+ * 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-private.hh"
+
+
+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 = (min + 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 NULL;
+}
+
+
+
+/* From https://github.com/noporpoise/sort_r */
+
+/* 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, *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) {
+      for(; pl < pr; pl += w) {
+        if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
+          pr -= w; /* pivot now at pl */
+          break;
+        }
+      }
+      for(; pl < 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);
+}
+
+#endif /* HB_DSALGS_HH */
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 1ba9707..26fddbe 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -43,9 +43,9 @@
 
   true, /* immutable */
 
-  NULL, /* reference_table_func */
-  NULL, /* user_data */
-  NULL, /* destroy */
+  nullptr, /* reference_table_func */
+  nullptr, /* user_data */
+  nullptr, /* destroy */
 
   0,    /* index */
   1000, /* upem */
@@ -57,7 +57,7 @@
 #undef HB_SHAPER_IMPLEMENT
   },
 
-  NULL, /* shape_plans */
+  nullptr, /* shape_plans */
 };
 
 
@@ -109,7 +109,7 @@
 
   closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
   if (unlikely (!closure))
-    return NULL;
+    return nullptr;
 
   closure->blob = blob;
   closure->index = index;
@@ -118,8 +118,10 @@
 }
 
 static void
-_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
+_hb_face_for_data_closure_destroy (void *data)
 {
+  hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
+
   hb_blob_destroy (closure->blob);
   free (closure);
 }
@@ -169,9 +171,9 @@
 
   face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
 				    closure,
-				    (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
+				    _hb_face_for_data_closure_destroy);
 
-  hb_face_set_index (face, index);
+  face->index = index;
 
   return face;
 }
@@ -472,4 +474,33 @@
   hb_blob_destroy (maxp_blob);
 }
 
+/**
+ * hb_face_get_table_tags:
+ * @face: a face.
+ *
+ * Retrieves table tags for a face, if possible.
+ *
+ * Return value: total number of tables, or 0 if not possible to list.
+ *
+ * Since: 1.6.0
+ **/
+unsigned int
+hb_face_get_table_tags (hb_face_t    *face,
+			unsigned int  start_offset,
+			unsigned int *table_count, /* IN/OUT */
+			hb_tag_t     *table_tags /* OUT */)
+{
+  if (face->destroy != _hb_face_for_data_closure_destroy)
+  {
+    if (table_count)
+      *table_count = 0;
+    return 0;
+  }
 
+  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
+
+  const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
+  const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
+
+  return ot_face.get_table_tags (start_offset, table_count, table_tags);
+}
diff --git a/src/hb-face.h b/src/hb-face.h
index 91237b7..9842d52 100644
--- a/src/hb-face.h
+++ b/src/hb-face.h
@@ -111,6 +111,11 @@
 HB_EXTERN unsigned int
 hb_face_get_glyph_count (hb_face_t *face);
 
+HB_EXTERN unsigned int
+hb_face_get_table_tags (hb_face_t    *face,
+			unsigned int  start_offset,
+			unsigned int *table_count, /* IN/OUT */
+			hb_tag_t     *table_tags /* OUT */);
 
 HB_END_DECLS
 
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index ac6d4b0..3f09c3f 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -28,6 +28,10 @@
 #include "hb-shaper-impl-private.hh"
 
 
+HB_SHAPER_DATA_ENSURE_DEFINE(fallback, face)
+HB_SHAPER_DATA_ENSURE_DEFINE(fallback, font)
+
+
 /*
  * shaper face data
  */
@@ -125,7 +129,7 @@
       pos[i].y_advance = 0;
       continue;
     }
-    font->get_nominal_glyph (info[i].codepoint, &info[i].codepoint);
+    (void) font->get_nominal_glyph (info[i].codepoint, &info[i].codepoint);
     font->get_glyph_advance_for_direction (info[i].codepoint,
 					   direction,
 					   &pos[i].x_advance,
@@ -139,5 +143,7 @@
   if (HB_DIRECTION_IS_BACKWARD (direction))
     hb_buffer_reverse (buffer);
 
+  buffer->safe_to_break_all ();
+
   return true;
 }
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 53671d7..d2801fb 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -108,6 +108,8 @@
   unsigned int x_ppem;
   unsigned int y_ppem;
 
+  float ptem;
+
   /* Font variation coordinates. */
   unsigned int num_coords;
   int *coords;
diff --git a/src/hb-font.cc b/src/hb-font.cc
index ea45501..f3534b6 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -36,7 +36,7 @@
  */
 
 static hb_bool_t
-hb_font_get_font_h_extents_nil (hb_font_t *font,
+hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED,
 				void *font_data HB_UNUSED,
 				hb_font_extents_t *metrics,
 				void *user_data HB_UNUSED)
@@ -60,7 +60,7 @@
 }
 
 static hb_bool_t
-hb_font_get_font_v_extents_nil (hb_font_t *font,
+hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED,
 				void *font_data HB_UNUSED,
 				hb_font_extents_t *metrics,
 				void *user_data HB_UNUSED)
@@ -347,12 +347,12 @@
   true, /* immutable */
 
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   },
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   },
@@ -370,12 +370,12 @@
   true, /* immutable */
 
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   },
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   },
@@ -563,8 +563,8 @@
     ffuncs->destroy.name = destroy;                                      \
   } else {                                                               \
     ffuncs->get.f.name = hb_font_get_##name##_parent;                    \
-    ffuncs->user_data.name = NULL;                                       \
-    ffuncs->destroy.name = NULL;                                         \
+    ffuncs->user_data.name = nullptr;                                       \
+    ffuncs->destroy.name = nullptr;                                         \
   }                                                                      \
 }
 
@@ -1157,8 +1157,20 @@
   font->y_scale = parent->y_scale;
   font->x_ppem = parent->x_ppem;
   font->y_ppem = parent->y_ppem;
+  font->ptem = parent->ptem;
 
-  /* TODO: copy variation coordinates. */
+  font->num_coords = parent->num_coords;
+  if (!font->num_coords)
+    font->coords = nullptr;
+  else
+  {
+    unsigned int size = parent->num_coords * sizeof (parent->coords[0]);
+    font->coords = (int *) malloc (size);
+    if (unlikely (!font->coords))
+      font->num_coords = 0;
+    else
+      memcpy (font->coords, parent->coords, size);
+  }
 
   return font;
 }
@@ -1180,7 +1192,7 @@
 
     true, /* immutable */
 
-    NULL, /* parent */
+    nullptr, /* parent */
     const_cast<hb_face_t *> (&_hb_face_nil),
 
     1000, /* x_scale */
@@ -1188,13 +1200,14 @@
 
     0, /* x_ppem */
     0, /* y_ppem */
+    0, /* ptem */
 
     0, /* num_coords */
-    NULL, /* coords */
+    nullptr, /* coords */
 
     const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
-    NULL, /* user_data */
-    NULL, /* destroy */
+    nullptr, /* user_data */
+    nullptr, /* destroy */
 
     {
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
@@ -1372,6 +1385,32 @@
 }
 
 /**
+ * hb_font_set_face:
+ * @font: a font.
+ * @face: new face.
+ *
+ * Sets font-face of @font.
+ *
+ * Since: 1.4.3
+ **/
+void
+hb_font_set_face (hb_font_t *font,
+		  hb_face_t *face)
+{
+  if (font->immutable)
+    return;
+
+  if (unlikely (!face))
+    face = hb_face_get_empty ();
+
+  hb_face_t *old = font->face;
+
+  font->face = hb_face_reference (face);
+
+  hb_face_destroy (old);
+}
+
+/**
  * hb_font_get_face:
  * @font: a font.
  *
@@ -1536,6 +1575,40 @@
   if (y_ppem) *y_ppem = font->y_ppem;
 }
 
+/**
+ * hb_font_set_ptem:
+ * @font: a font.
+ * @ptem: 
+ *
+ * Sets "point size" of the font.
+ *
+ * Since: 1.6.0
+ **/
+void
+hb_font_set_ptem (hb_font_t *font, float ptem)
+{
+  if (font->immutable)
+    return;
+
+  font->ptem = ptem;
+}
+
+/**
+ * hb_font_get_ptem:
+ * @font: a font.
+ *
+ * Gets the "point size" of the font.  A value of 0 means unset.
+ *
+ * Return value: Point size.
+ *
+ * Since: 0.9.2
+ **/
+float
+hb_font_get_ptem (hb_font_t *font)
+{
+  return font->ptem;
+}
+
 /*
  * Variations
  */
@@ -1566,13 +1639,13 @@
 
   if (!variations_length)
   {
-    hb_font_set_var_coords_normalized (font, NULL, 0);
+    hb_font_set_var_coords_normalized (font, nullptr, 0);
     return;
   }
 
   unsigned int coords_length = hb_ot_var_get_axis_count (font->face);
 
-  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : NULL;
+  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
   if (unlikely (coords_length && !normalized))
     return;
 
@@ -1595,7 +1668,7 @@
   if (font->immutable)
     return;
 
-  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : NULL;
+  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
   if (unlikely (coords_length && !normalized))
     return;
 
@@ -1616,7 +1689,7 @@
   if (font->immutable)
     return;
 
-  int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : NULL;
+  int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
   if (unlikely (coords_length && !copy))
     return;
 
@@ -1627,7 +1700,7 @@
 }
 
 /**
- * hb_font_set_var_coords_normalized:
+ * hb_font_get_var_coords_normalized:
  *
  * Return value is valid as long as variation coordinates of the font
  * are not modified.
@@ -1676,7 +1749,7 @@
   trampoline_t *trampoline = (trampoline_t *) calloc (1, sizeof (trampoline_t));
 
   if (unlikely (!trampoline))
-    return NULL;
+    return nullptr;
 
   trampoline->closure.user_data = user_data;
   trampoline->closure.destroy = destroy;
diff --git a/src/hb-font.h b/src/hb-font.h
index e2e5979..540cdca 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -563,6 +563,10 @@
 HB_EXTERN hb_font_t *
 hb_font_get_parent (hb_font_t *font);
 
+HB_EXTERN void
+hb_font_set_face (hb_font_t *font,
+		  hb_face_t *face);
+
 HB_EXTERN hb_face_t *
 hb_font_get_face (hb_font_t *font);
 
@@ -603,6 +607,16 @@
 		  unsigned int *x_ppem,
 		  unsigned int *y_ppem);
 
+/*
+ * Point size per EM.  Used for optical-sizing in CoreText.
+ * A value of zero means "not set".
+ */
+HB_EXTERN void
+hb_font_set_ptem (hb_font_t *font, float ptem);
+
+HB_EXTERN float
+hb_font_get_ptem (hb_font_t *font);
+
 HB_EXTERN void
 hb_font_set_variations (hb_font_t *font,
 			const hb_variation_t *variations,
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 48d6a0e..4f33e11 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -28,24 +28,17 @@
  */
 
 #include "hb-private.hh"
+#include "hb-debug.hh"
 
 #include "hb-ft.h"
 
 #include "hb-font-private.hh"
 
-#include "hb-cache-private.hh" // Maybe use in the future?
-
 #include FT_ADVANCES_H
 #include FT_MULTIPLE_MASTERS_H
 #include FT_TRUETYPE_TABLES_H
 
 
-
-#ifndef HB_DEBUG_FT
-#define HB_DEBUG_FT (HB_DEBUG+0)
-#endif
-
-
 /* TODO:
  *
  * In general, this file does a fine job of what it's supposed to do.
@@ -83,7 +76,7 @@
   hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
 
   if (unlikely (!ft_font))
-    return NULL;
+    return nullptr;
 
   ft_font->ft_face = ft_face;
   ft_font->symbol = symbol;
@@ -95,14 +88,16 @@
 }
 
 static void
-_hb_ft_face_destroy (FT_Face ft_face)
+_hb_ft_face_destroy (void *data)
 {
-  FT_Done_Face (ft_face);
+  FT_Done_Face ((FT_Face) data);
 }
 
 static void
-_hb_ft_font_destroy (hb_ft_font_t *ft_font)
+_hb_ft_font_destroy (void *data)
 {
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
+
   if (ft_font->unref)
     _hb_ft_face_destroy (ft_font->ft_face);
 
@@ -124,7 +119,7 @@
   if (font->immutable)
     return;
 
-  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+  if (font->destroy != _hb_ft_font_destroy)
     return;
 
   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
@@ -144,7 +139,7 @@
 int
 hb_ft_font_get_load_flags (hb_font_t *font)
 {
-  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+  if (font->destroy != _hb_ft_font_destroy)
     return 0;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
@@ -155,8 +150,8 @@
 FT_Face
 hb_ft_font_get_face (hb_font_t *font)
 {
-  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
-    return NULL;
+  if (font->destroy != _hb_ft_font_destroy)
+    return nullptr;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 
@@ -422,7 +417,7 @@
   return true;
 }
 
-static hb_font_funcs_t *static_ft_funcs = NULL;
+static hb_font_funcs_t *static_ft_funcs = nullptr;
 
 #ifdef HB_USE_ATEXIT
 static
@@ -442,24 +437,24 @@
   {
     funcs = hb_font_funcs_create ();
 
-    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
-    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
-    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, NULL, NULL);
-    hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, NULL, NULL);
-    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
-    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
-    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
-    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
-    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
-    hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
-    hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
-    hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
-    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
+    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
+    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
+    hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
+    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
+    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);
+    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
+    //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);
+    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
 
     hb_font_funcs_make_immutable (funcs);
 
-    if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
+    if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) {
       hb_font_funcs_destroy (funcs);
       goto retry;
     }
@@ -474,7 +469,7 @@
   hb_font_set_funcs (font,
 		     funcs,
 		     _hb_ft_font_create (ft_face, symbol, unref),
-		     (hb_destroy_func_t) _hb_ft_font_destroy);
+		     _hb_ft_font_destroy);
 }
 
 
@@ -488,17 +483,17 @@
 
   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
 
-  error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
+  error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
   if (error)
-    return NULL;
+    return nullptr;
 
   buffer = (FT_Byte *) malloc (length);
-  if (buffer == NULL)
-    return NULL;
+  if (!buffer)
+    return nullptr;
 
   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
   if (error)
-    return NULL;
+    return nullptr;
 
   return hb_blob_create ((const char *) buffer, length,
 			 HB_MEMORY_MODE_WRITABLE,
@@ -521,7 +516,7 @@
 {
   hb_face_t *face;
 
-  if (ft_face->stream->read == NULL) {
+  if (!ft_face->stream->read) {
     hb_blob_t *blob;
 
     blob = hb_blob_create ((const char *) ft_face->stream->base,
@@ -553,7 +548,7 @@
 hb_ft_face_create_referenced (FT_Face ft_face)
 {
   FT_Reference_Face (ft_face);
-  return hb_ft_face_create (ft_face, (hb_destroy_func_t) _hb_ft_face_destroy);
+  return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
 }
 
 static void
@@ -579,7 +574,7 @@
     if (ft_face->generic.finalizer)
       ft_face->generic.finalizer (ft_face);
 
-    ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
+    ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
     ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
   }
 
@@ -608,6 +603,19 @@
   font = hb_font_create (face);
   hb_face_destroy (face);
   _hb_ft_font_set_funcs (font, ft_face, false);
+  hb_ft_font_changed (font);
+  return font;
+}
+
+void
+hb_ft_font_changed (hb_font_t *font)
+{
+  if (font->destroy != _hb_ft_font_destroy)
+    return;
+
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+  FT_Face ft_face = ft_font->ft_face;
+
   hb_font_set_scale (font,
 		     (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
 		     (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
@@ -618,7 +626,7 @@
 #endif
 
 #ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
-  FT_MM_Var *mm_var = NULL;
+  FT_MM_Var *mm_var = nullptr;
   if (!FT_Get_MM_Var (ft_face, &mm_var))
   {
     FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
@@ -632,14 +640,12 @@
 
 	hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
       }
-      free (coords);
-      free (ft_coords);
     }
+    free (coords);
+    free (ft_coords);
     free (mm_var);
   }
 #endif
-
-  return font;
 }
 
 /**
@@ -655,7 +661,7 @@
 hb_ft_font_create_referenced (FT_Face ft_face)
 {
   FT_Reference_Face (ft_face);
-  return hb_ft_font_create (ft_face, (hb_destroy_func_t) _hb_ft_face_destroy);
+  return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
 }
 
 
@@ -681,9 +687,9 @@
   {
     /* Not found; allocate one. */
     if (FT_Init_FreeType (&library))
-      return NULL;
+      return nullptr;
 
-    if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) {
+    if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
       FT_Done_FreeType (library);
       goto retry;
     }
@@ -711,7 +717,7 @@
   if (unlikely (!blob_length))
     DEBUG_MSG (FT, font, "Font face has empty blob");
 
-  FT_Face ft_face = NULL;
+  FT_Face ft_face = nullptr;
   FT_Error err = FT_New_Memory_Face (get_ft_library (),
 				     (const FT_Byte *) blob_data,
 				     blob_length,
@@ -738,9 +744,10 @@
   {
     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
 			  0, font->y_scale < 0 ? -1 : +1};
-    FT_Set_Transform (ft_face, &matrix, NULL);
+    FT_Set_Transform (ft_face, &matrix, nullptr);
   }
 
+#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
   unsigned int num_coords;
   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
   if (num_coords)
@@ -754,6 +761,7 @@
       free (ft_coords);
     }
   }
+#endif
 
   ft_face->generic.data = blob;
   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
diff --git a/src/hb-ft.h b/src/hb-ft.h
index dc8ef85..94013ee 100644
--- a/src/hb-ft.h
+++ b/src/hb-ft.h
@@ -116,7 +116,13 @@
 HB_EXTERN int
 hb_ft_font_get_load_flags (hb_font_t *font);
 
-/* Makes an hb_font_t use FreeType internally to implement font functions. */
+/* Call when size or variations settings on underlying FT_Face change. */
+HB_EXTERN void
+hb_ft_font_changed (hb_font_t *font);
+
+/* Makes an hb_font_t use FreeType internally to implement font functions.
+ * Note: this internally creates an FT_Face.  Use it when you create your
+ * hb_face_t using hb_face_create(). */
 HB_EXTERN void
 hb_ft_font_set_funcs (hb_font_t *font);
 
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 2b91b5b..50c30e9 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -364,25 +364,54 @@
   return utf8_decomposed_len;
 }
 
+static hb_unicode_funcs_t *static_glib_funcs = nullptr;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_glib_funcs (void)
+{
+  hb_unicode_funcs_destroy (static_glib_funcs);
+}
+#endif
+
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void)
 {
-  static const hb_unicode_funcs_t _hb_glib_unicode_funcs = {
-    HB_OBJECT_HEADER_STATIC,
+retry:
+  hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs);
 
-    NULL, /* parent */
-    true, /* immutable */
-    {
-#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_glib_unicode_##name,
+  if (unlikely (!funcs))
+  {
+    funcs = hb_unicode_funcs_create (nullptr);
+
+#define HB_UNICODE_FUNC_IMPLEMENT(name) \
+    hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr);
       HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
+
+    hb_unicode_funcs_make_immutable (funcs);
+
+    if (!hb_atomic_ptr_cmpexch (&static_glib_funcs, nullptr, funcs)) {
+      hb_unicode_funcs_destroy (funcs);
+      goto retry;
     }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_glib_funcs); /* First person registers atexit() callback. */
+#endif
   };
 
-  return const_cast<hb_unicode_funcs_t *> (&_hb_glib_unicode_funcs);
+  return hb_unicode_funcs_reference (funcs);
 }
 
 #if GLIB_CHECK_VERSION(2,31,10)
+
+static void
+_hb_g_bytes_unref (void *data)
+{
+  g_bytes_unref ((GBytes *) data);
+}
+
 /**
  * hb_glib_blob_create:
  *
@@ -397,6 +426,6 @@
 			 size,
 			 HB_MEMORY_MODE_READONLY,
 			 g_bytes_ref (gbytes),
-			 (hb_destroy_func_t) g_bytes_unref);
+			 _hb_g_bytes_unref);
 }
 #endif
diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc
index fef0024..a96c358 100644
--- a/src/hb-gobject-structs.cc
+++ b/src/hb-gobject-structs.cc
@@ -58,7 +58,7 @@
 	static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
 	{ \
 	  hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
-	  if (unlikely (!c)) return NULL; \
+	  if (unlikely (!c)) return nullptr; \
 	  *c = *l; \
 	  return c; \
 	} \
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index a2d90db..62aaae9 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -27,7 +27,6 @@
  */
 
 #define HB_SHAPER graphite2
-#define hb_graphite2_shaper_font_data_t gr_font
 #include "hb-shaper-impl-private.hh"
 
 #include "hb-graphite2.h"
@@ -35,8 +34,8 @@
 #include <graphite2/Segment.h>
 
 
-HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
-HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
+HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, face)
+HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, font)
 
 
 /*
@@ -60,7 +59,7 @@
   hb_graphite2_shaper_face_data_t *face_data = (hb_graphite2_shaper_face_data_t *) data;
   hb_graphite2_tablelist_t *tlist = face_data->tlist;
 
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
     if (p->tag == tag) {
@@ -75,7 +74,7 @@
     hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
     if (unlikely (!p)) {
       hb_blob_destroy (blob);
-      return NULL;
+      return nullptr;
     }
     p->blob = blob;
     p->tag = tag;
@@ -101,20 +100,20 @@
   if (!hb_blob_get_length (silf_blob))
   {
     hb_blob_destroy (silf_blob);
-    return NULL;
+    return nullptr;
   }
   hb_blob_destroy (silf_blob);
 
   hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   data->face = face;
   data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
 
   if (unlikely (!data->grface)) {
     free (data);
-    return NULL;
+    return nullptr;
   }
 
   return data;
@@ -144,7 +143,7 @@
 gr_face *
 hb_graphite2_face_get_gr_face (hb_face_t *face)
 {
-  if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL;
+  if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return nullptr;
   return HB_SHAPER_DATA_GET (face)->grface;
 }
 
@@ -153,26 +152,17 @@
  * shaper font data
  */
 
-static float hb_graphite2_get_advance (const void *hb_font, unsigned short gid)
-{
-  return ((hb_font_t *) hb_font)->get_glyph_h_advance (gid);
-}
+struct hb_graphite2_shaper_font_data_t {};
 
 hb_graphite2_shaper_font_data_t *
-_hb_graphite2_shaper_font_data_create (hb_font_t *font)
+_hb_graphite2_shaper_font_data_create (hb_font_t *font HB_UNUSED)
 {
-  if (unlikely (!hb_graphite2_shaper_face_data_ensure (font->face))) return NULL;
-
-  hb_face_t *face = font->face;
-  hb_graphite2_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-
-  return gr_make_font_with_advance_fn (font->x_scale, font, &hb_graphite2_get_advance, face_data->grface);
+  return (hb_graphite2_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
-_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data)
+_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data HB_UNUSED)
 {
-  gr_font_destroy (data);
 }
 
 /*
@@ -181,8 +171,7 @@
 gr_font *
 hb_graphite2_font_get_gr_font (hb_font_t *font)
 {
-  if (unlikely (!hb_graphite2_shaper_font_data_ensure (font))) return NULL;
-  return HB_SHAPER_DATA_GET (font);
+  return nullptr;
 }
 
 
@@ -230,10 +219,9 @@
 {
   hb_face_t *face = font->face;
   gr_face *grface = HB_SHAPER_DATA_GET (face)->grface;
-  gr_font *grfont = HB_SHAPER_DATA_GET (font);
 
   const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
-  const char *lang_end = lang ? strchr (lang, '-') : NULL;
+  const char *lang_end = lang ? strchr (lang, '-') : nullptr;
   int lang_len = lang_end ? lang_end - lang : -1;
   gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
 
@@ -244,7 +232,7 @@
       gr_fref_set_feature_value (fref, features[i].value, feats);
   }
 
-  gr_segment *seg = NULL;
+  gr_segment *seg = nullptr;
   const gr_slot *is;
   unsigned int ci = 0, ic = 0;
   float curradvx = 0., curradvy = 0.;
@@ -262,7 +250,7 @@
   hb_tag_t script_tag[2];
   hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
 
-  seg = gr_make_seg (grfont, grface,
+  seg = gr_make_seg (nullptr, grface,
 		     script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
 		     feats,
 		     gr_utf32, chars, buffer->len,
@@ -313,12 +301,14 @@
 
   hb_codepoint_t *pg = gids;
   clusters[0].cluster = buffer->info[0].cluster;
-  float curradv = HB_DIRECTION_IS_BACKWARD(buffer->props.direction) ? gr_slot_origin_X(gr_seg_first_slot(seg)) : 0.;
+  float 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;
   }
+  else
+    clusters[0].advance = 0;
   for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
   {
     unsigned int before = gr_slot_before (is);
@@ -342,13 +332,13 @@
       c->base_glyph = ic;
       c->num_glyphs = 0;
       if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+        c->advance = curradv - gr_slot_origin_X(is);
+      else
       {
-        ci++;
-        clusters[ci].advance = curradv - gr_slot_origin_X(is);
-      } else {
-        clusters[ci].advance = gr_slot_origin_X(is) - curradv;
-        ci++;
+        c->advance = 0;
+        clusters[ci].advance += gr_slot_origin_X(is) - curradv;
       }
+      ci++;
       curradv = gr_slot_origin_X(is);
     }
     clusters[ci].num_glyphs++;
@@ -357,8 +347,10 @@
 	clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
   }
 
-  if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
-    clusters[ci].advance = gr_seg_advance_X(seg) - curradv;
+  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+    clusters[ci].advance += curradv;
+  else
+    clusters[ci].advance += gr_seg_advance_X(seg) - curradv;
   ci++;
 
   for (unsigned int i = 0; i < ci; ++i)
@@ -368,53 +360,54 @@
       hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
       info->codepoint = gids[clusters[i].base_glyph + j];
       info->cluster = clusters[i].cluster;
+      info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
       info->var1.i32 = clusters[i].advance;     // all glyphs in the cluster get the same advance
     }
   }
   buffer->len = glyph_count;
 
-  float yscale = font->y_scale / font->x_scale;
+  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;
+  hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
   if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
   {
-    int currclus = -1;
-    const hb_glyph_info_t *info = buffer->info;
-    hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
     curradvx = 0;
     for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
     {
-      pPos->x_offset = gr_slot_origin_X (is) - curradvx;
+      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;
+        pPos->x_advance = info->var1.i32 * xscale;
         curradvx += pPos->x_advance;
         currclus = info->cluster;
       } else
         pPos->x_advance = 0.;
 
-      pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
+      pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
       curradvy += pPos->y_advance;
     }
   }
   else
   {
-    int currclus = -1;
-    const hb_glyph_info_t *info = buffer->info;
-    hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
-    curradvx = gr_seg_advance_X(seg);
+    curradvx = gr_seg_advance_X(seg) * xscale;
     for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
     {
       if (info->cluster != currclus)
       {
-        pPos->x_advance = info->var1.i32;
-        if (currclus != -1) curradvx -= info[-1].var1.i32;
+        pPos->x_advance = info->var1.i32 * xscale;
+        curradvx -= pPos->x_advance;
         currclus = info->cluster;
       } else
-      pPos->x_advance = 0.;
+        pPos->x_advance = 0.;
 
-      pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
+      pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
       curradvy -= pPos->y_advance;
-      pPos->x_offset = gr_slot_origin_X (is) - curradvx + pPos->x_advance;
+      pPos->x_offset = (gr_slot_origin_X (is) - info->var1.i32) * xscale - curradvx + pPos->x_advance;
       pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
     }
     hb_buffer_reverse_clusters (buffer);
@@ -423,5 +416,7 @@
   if (feats) gr_featureval_destroy (feats);
   gr_seg_destroy (seg);
 
+  buffer->unsafe_to_break_all ();
+
   return true;
 }
diff --git a/src/hb-graphite2.h b/src/hb-graphite2.h
index 122c3e4..82b1e64 100644
--- a/src/hb-graphite2.h
+++ b/src/hb-graphite2.h
@@ -39,9 +39,13 @@
 HB_EXTERN gr_face *
 hb_graphite2_face_get_gr_face (hb_face_t *face);
 
+#ifndef HB_DISABLE_DEPRECATED
+
 HB_EXTERN gr_font *
 hb_graphite2_font_get_gr_font (hb_font_t *font);
 
+#endif
+
 
 HB_END_DECLS
 
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index 0b25dc8..552eaec 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -332,40 +332,63 @@
   /* Normalise the codepoint using NFKD mode. */
   icu_err = U_ZERO_ERROR;
   len = unorm2_normalize (unorm2_getNFKDInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err);
-  if (icu_err)
+  if (U_FAILURE (icu_err))
     return 0;
 
   /* Convert the decomposed form from UTF-16 to UTF-32. */
   icu_err = U_ZERO_ERROR;
   u_strToUTF32 ((UChar32*) decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN, &utf32_len, normalized, len, &icu_err);
-  if (icu_err)
+  if (U_FAILURE (icu_err))
     return 0;
 
   return utf32_len;
 }
 
 
+static hb_unicode_funcs_t *static_icu_funcs = nullptr;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_icu_funcs (void)
+{
+  hb_unicode_funcs_destroy (static_icu_funcs);
+}
+#endif
+
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void)
 {
-  static const hb_unicode_funcs_t _hb_icu_unicode_funcs = {
-    HB_OBJECT_HEADER_STATIC,
+retry:
+  hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_icu_funcs);
 
-    NULL, /* parent */
-    true, /* immutable */
-    {
-#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name,
+  if (unlikely (!funcs))
+  {
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+    if (!hb_atomic_ptr_get (&normalizer)) {
+      UErrorCode icu_err = U_ZERO_ERROR;
+      /* We ignore failure in getNFCInstace(). */
+      (void) hb_atomic_ptr_cmpexch (&normalizer, nullptr, unorm2_getNFCInstance (&icu_err));
+    }
+#endif
+
+    funcs = hb_unicode_funcs_create (nullptr);
+
+#define HB_UNICODE_FUNC_IMPLEMENT(name) \
+    hb_unicode_funcs_set_##name##_func (funcs, hb_icu_unicode_##name, nullptr, nullptr);
       HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
+
+    hb_unicode_funcs_make_immutable (funcs);
+
+    if (!hb_atomic_ptr_cmpexch (&static_icu_funcs, nullptr, funcs)) {
+      hb_unicode_funcs_destroy (funcs);
+      goto retry;
     }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_icu_funcs); /* First person registers atexit() callback. */
+#endif
   };
 
-#if U_ICU_VERSION_MAJOR_NUM >= 49
-  if (!hb_atomic_ptr_get (&normalizer)) {
-    UErrorCode icu_err = U_ZERO_ERROR;
-    /* We ignore failure in getNFCInstace(). */
-    (void) hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err));
-  }
-#endif
-  return const_cast<hb_unicode_funcs_t *> (&_hb_icu_unicode_funcs);
+  return hb_unicode_funcs_reference (funcs);
 }
diff --git a/src/hb-mutex-private.hh b/src/hb-mutex-private.hh
index ed27035..49ed10e 100644
--- a/src/hb-mutex-private.hh
+++ b/src/hb-mutex-private.hh
@@ -68,7 +68,7 @@
 #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, NULL)
+#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)
diff --git a/src/hb-object-private.hh b/src/hb-object-private.hh
index 6b73ff9..baa1f8f 100644
--- a/src/hb-object-private.hh
+++ b/src/hb-object-private.hh
@@ -33,18 +33,12 @@
 #define HB_OBJECT_PRIVATE_HH
 
 #include "hb-private.hh"
+#include "hb-debug.hh"
 
 #include "hb-atomic-private.hh"
 #include "hb-mutex-private.hh"
 
 
-/* Debug */
-
-#ifndef HB_DEBUG_OBJECT
-#define HB_DEBUG_OBJECT (HB_DEBUG+0)
-#endif
-
-
 /* reference_count */
 
 #define HB_REFERENCE_COUNT_INERT_VALUE -1
@@ -193,7 +187,7 @@
 					     hb_user_data_key_t *key)
 {
   if (unlikely (!obj || hb_object_is_inert (obj)))
-    return NULL;
+    return nullptr;
   assert (hb_object_is_valid (obj));
   return obj->header.user_data.get (key);
 }
diff --git a/src/hb-open-file-private.hh b/src/hb-open-file-private.hh
index f208419..644e0b4 100644
--- a/src/hb-open-file-private.hh
+++ b/src/hb-open-file-private.hh
@@ -53,6 +53,9 @@
 
 typedef struct TableRecord
 {
+  int cmp (Tag t) const
+  { return t.cmp (tag); }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -61,9 +64,9 @@
 
   Tag		tag;		/* 4-byte identifier. */
   CheckSum	checkSum;	/* CheckSum for this table. */
-  ULONG		offset;		/* Offset from beginning of TrueType font
+  UINT32		offset;		/* Offset from beginning of TrueType font
 				 * file. */
-  ULONG		length;		/* Length of this table. */
+  UINT32		length;		/* Length of this table. */
   public:
   DEFINE_SIZE_STATIC (16);
 } OpenTypeTable;
@@ -73,27 +76,39 @@
   friend struct OpenTypeFontFile;
 
   inline unsigned int get_table_count (void) const
-  { return numTables; }
+  { return tables.len; }
   inline const TableRecord& get_table (unsigned int i) const
   {
-    if (unlikely (i >= numTables)) return Null(TableRecord);
     return tables[i];
   }
+  inline unsigned int get_table_tags (unsigned int start_offset,
+				      unsigned int *table_count, /* IN/OUT */
+				      hb_tag_t     *table_tags /* OUT */) const
+  {
+    if (table_count)
+    {
+      if (start_offset >= tables.len)
+        *table_count = 0;
+      else
+        *table_count = MIN<unsigned int> (*table_count, tables.len - start_offset);
+
+      const TableRecord *sub_tables = tables.array + start_offset;
+      unsigned int count = *table_count;
+      for (unsigned int i = 0; i < count; i++)
+	table_tags[i] = sub_tables[i].tag;
+    }
+    return tables.len;
+  }
   inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
   {
     Tag t;
     t.set (tag);
-    unsigned int count = numTables;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      if (t == tables[i].tag)
-      {
-        if (table_index) *table_index = i;
-        return true;
-      }
-    }
-    if (table_index) *table_index = Index::NOT_FOUND_INDEX;
-    return false;
+    /* Linear-search for small tables to work around fonts with unsorted
+     * table list. */
+    int i = tables.len < 64 ? tables.lsearch (t) : tables.bsearch (t);
+    if (table_index)
+      *table_index = i == -1 ? Index::NOT_FOUND_INDEX : (unsigned int) i;
+    return i != -1;
   }
   inline const TableRecord& get_table_by_tag (hb_tag_t tag) const
   {
@@ -106,16 +121,13 @@
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
+    return_trace (c->check_struct (this) && tables.sanitize (c));
   }
 
   protected:
   Tag		sfnt_version;	/* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
-  USHORT	numTables;	/* Number of tables. */
-  USHORT	searchRangeZ;	/* (Maximum power of 2 <= numTables) x 16 */
-  USHORT	entrySelectorZ;	/* Log2(maximum power of 2 <= numTables). */
-  USHORT	rangeShiftZ;	/* NumTables x 16-searchRange. */
-  TableRecord	tables[VAR];	/* TableRecord entries. numTables items */
+  BinSearchArrayOf<TableRecord>
+		tables;
   public:
   DEFINE_SIZE_ARRAY (12, tables);
 } OpenTypeFontFace;
@@ -142,7 +154,7 @@
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
   FixedVersion<>version;	/* Version of the TTC Header (1.0),
 				 * 0x00010000u */
-  ArrayOf<LOffsetTo<OffsetTable>, ULONG>
+  ArrayOf<LOffsetTo<OffsetTable>, UINT32>
 		table;		/* Array of offsets to the OffsetTable for each font
 				 * from the beginning of the file */
   public:
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index d90d68c..2f4e1b9 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -30,6 +30,7 @@
 #define HB_OPEN_TYPE_PRIVATE_HH
 
 #include "hb-private.hh"
+#include "hb-debug.hh"
 #include "hb-face-private.hh"
 
 
@@ -85,7 +86,7 @@
 #define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
   inline void _instance_assertion_on_line_##_line (void) const \
   { \
-    ASSERT_STATIC (_assertion); \
+    static_assert ((_assertion), ""); \
     ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
   }
 # define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
@@ -130,14 +131,16 @@
  */
 
 /* Global nul-content Null pool.  Enlarge as necessary. */
-/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
-static const void *_NullPool[(256+8) / sizeof (void *)];
+
+#define HB_NULL_POOL_SIZE 264
+static_assert (HB_NULL_POOL_SIZE % sizeof (void *) == 0, "Align HB_NULL_POOL_SIZE.");
+extern HB_INTERNAL const void * const _hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)];
 
 /* Generic nul-content Null objects. */
 template <typename Type>
 static inline const Type& Null (void) {
-  ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
-  return *CastP<Type> (_NullPool);
+  static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
+  return *CastP<Type> (_hb_NullPool);
 }
 
 /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
@@ -147,7 +150,7 @@
 /*static*/ inline const Type& Null<Type> (void) { \
   return *CastP<Type> (_Null##Type); \
 } /* The following line really exists such that we end in a place needing semicolon */ \
-ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
+static_assert (Type::min_size + 1 <= sizeof (_Null##Type), "Null pool too small.  Enlarge.")
 
 /* Accessor macro. */
 #define Null(Type) Null<Type>()
@@ -172,16 +175,6 @@
  * Sanitize
  */
 
-#ifndef HB_DEBUG_SANITIZE
-#define HB_DEBUG_SANITIZE (HB_DEBUG+0)
-#endif
-
-
-#define TRACE_SANITIZE(this) \
-	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
-	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "");
-
 /* This limits sanitizing time on really broken fonts. */
 #ifndef HB_SANITIZE_MAX_EDITS
 #define HB_SANITIZE_MAX_EDITS 32
@@ -192,9 +185,9 @@
 {
   inline hb_sanitize_context_t (void) :
 	debug_depth (0),
-	start (NULL), end (NULL),
+	start (nullptr), end (nullptr),
 	writable (false), edit_count (0),
-	blob (NULL) {}
+	blob (nullptr) {}
 
   inline const char *get_name (void) { return "SANITIZE"; }
   template <typename T, typename F>
@@ -214,7 +207,7 @@
 
   inline void start_processing (void)
   {
-    this->start = hb_blob_get_data (this->blob, NULL);
+    this->start = hb_blob_get_data (this->blob, nullptr);
     this->end = this->start + hb_blob_get_length (this->blob);
     assert (this->start <= this->end); /* Must not overflow. */
     this->edit_count = 0;
@@ -233,8 +226,8 @@
 		     this->start, this->end, this->edit_count);
 
     hb_blob_destroy (this->blob);
-    this->blob = NULL;
-    this->start = this->end = NULL;
+    this->blob = nullptr;
+    this->start = this->end = nullptr;
   }
 
   inline bool check_range (const void *base, unsigned int len) const
@@ -349,7 +342,7 @@
     } else {
       unsigned int edit_count = c->edit_count;
       if (edit_count && !c->writable) {
-        c->start = hb_blob_get_data_writable (blob, NULL);
+        c->start = hb_blob_get_data_writable (blob, nullptr);
 	c->end = c->start + hb_blob_get_length (blob);
 
 	if (c->start) {
@@ -374,7 +367,7 @@
 
   static const Type* lock_instance (hb_blob_t *blob) {
     hb_blob_make_immutable (blob);
-    const char *base = hb_blob_get_data (blob, NULL);
+    const char *base = hb_blob_get_data (blob, nullptr);
     return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
   }
 };
@@ -385,16 +378,6 @@
  * Serialize
  */
 
-#ifndef HB_DEBUG_SERIALIZE
-#define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
-#endif
-
-
-#define TRACE_SERIALIZE(this) \
-	hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
-	(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
-	 "");
-
 
 struct hb_serialize_context_t
 {
@@ -445,7 +428,7 @@
   {
     if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
       this->ran_out_of_room = true;
-      return NULL;
+      return nullptr;
     }
     memset (this->head, 0, size);
     char *ret = this->head;
@@ -471,7 +454,7 @@
   {
     unsigned int size = obj.get_size ();
     Type *ret = this->allocate_size<Type> (size);
-    if (unlikely (!ret)) return NULL;
+    if (unlikely (!ret)) return nullptr;
     memcpy (ret, obj, size);
     return ret;
   }
@@ -481,7 +464,7 @@
   {
     unsigned int size = obj.min_size;
     assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
-    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
     return reinterpret_cast<Type *> (&obj);
   }
 
@@ -490,7 +473,7 @@
   {
     unsigned int size = obj.get_size ();
     assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
-    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
     return reinterpret_cast<Type *> (&obj);
   }
 
@@ -632,10 +615,11 @@
   inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
   inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
   static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
-  inline int cmp (Type a) const
+  template <typename Type2>
+  inline int cmp (Type2 a) const
   {
     Type b = v;
-    if (sizeof (Type) < sizeof (int))
+    if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int))
       return (int) a - (int) b;
     else
       return a < b ? -1 : a == b ? 0 : +1;
@@ -651,23 +635,22 @@
   DEFINE_SIZE_STATIC (Size);
 };
 
-typedef	IntType<int8_t	, 1> CHAR;	/* 8-bit signed integer. */
-typedef	IntType<uint8_t	, 1> BYTE;	/* 8-bit unsigned integer. */
-typedef	IntType<int8_t	, 1> INT8;	/* 8-bit signed integer. */
-typedef IntType<uint16_t, 2> USHORT;	/* 16-bit unsigned integer. */
-typedef IntType<int16_t,  2> SHORT;	/* 16-bit signed integer. */
-typedef IntType<uint32_t, 4> ULONG;	/* 32-bit unsigned integer. */
-typedef IntType<int32_t,  4> LONG;	/* 32-bit signed integer. */
+typedef IntType<uint8_t,  1> UINT8;	/* 8-bit unsigned integer. */
+typedef IntType<int8_t,   1> INT8;	/* 8-bit signed integer. */
+typedef IntType<uint16_t, 2> UINT16;	/* 16-bit unsigned integer. */
+typedef IntType<int16_t,  2> INT16;	/* 16-bit signed integer. */
+typedef IntType<uint32_t, 4> UINT32;	/* 32-bit unsigned integer. */
+typedef IntType<int32_t,  4> INT32;	/* 32-bit signed integer. */
 typedef IntType<uint32_t, 3> UINT24;	/* 24-bit unsigned integer. */
 
-/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
-typedef SHORT FWORD;
+/* 16-bit signed integer (INT16) that describes a quantity in FUnits. */
+typedef INT16 FWORD;
 
-/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
-typedef USHORT UFWORD;
+/* 16-bit unsigned integer (UINT16) that describes a quantity in FUnits. */
+typedef UINT16 UFWORD;
 
 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
-struct F2DOT14 : SHORT
+struct F2DOT14 : INT16
 {
   //inline float to_float (void) const { return ???; }
   //inline void set_float (float f) { v.set (f * ???); }
@@ -676,7 +659,7 @@
 };
 
 /* 32-bit signed fixed-point number (16.16). */
-struct Fixed: LONG
+struct Fixed: INT32
 {
   //inline float to_float (void) const { return ???; }
   //inline void set_float (float f) { v.set (f * ???); }
@@ -694,15 +677,15 @@
     return_trace (likely (c->check_struct (this)));
   }
   protected:
-  LONG major;
-  ULONG minor;
+  INT32 major;
+  UINT32 minor;
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 /* Array of four uint8s (length = 32 bits) used to identify a script, language
  * system, feature, or baseline */
-struct Tag : ULONG
+struct Tag : UINT32
 {
   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
   inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
@@ -713,19 +696,16 @@
 DEFINE_NULL_DATA (Tag, "    ");
 
 /* Glyph index number, same as uint16 (length = 16 bits) */
-struct GlyphID : USHORT {
-  static inline int cmp (const GlyphID *a, const GlyphID *b) { return b->USHORT::cmp (*a); }
-  inline int cmp (hb_codepoint_t a) const { return (int) a - (int) *this; }
-};
+typedef UINT16 GlyphID;
 
 /* Script/language-system/feature index */
-struct Index : USHORT {
+struct Index : UINT16 {
   static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
 };
 DEFINE_NULL_DATA (Index, "\xff\xff");
 
 /* Offset, Null offset = 0 */
-template <typename Type=USHORT>
+template <typename Type>
 struct Offset : Type
 {
   inline bool is_null (void) const { return 0 == *this; }
@@ -733,15 +713,18 @@
   DEFINE_SIZE_STATIC (sizeof(Type));
 };
 
+typedef Offset<UINT16> Offset16;
+typedef Offset<UINT32> Offset32;
+
 
 /* CheckSum */
-struct CheckSum : ULONG
+struct CheckSum : UINT32
 {
   /* This is reference implementation from the spec. */
-  static inline uint32_t CalcTableChecksum (const ULONG *Table, uint32_t Length)
+  static inline uint32_t CalcTableChecksum (const UINT32 *Table, uint32_t Length)
   {
     uint32_t Sum = 0L;
-    const ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
+    const UINT32 *EndPtr = Table+((Length+3) & ~3) / UINT32::static_size;
 
     while (Table < EndPtr)
       Sum += *Table++;
@@ -750,7 +733,7 @@
 
   /* Note: data should be 4byte aligned and have 4byte padding at the end. */
   inline void set_for_data (const void *data, unsigned int length)
-  { set (CalcTableChecksum ((const ULONG *) data, length)); }
+  { set (CalcTableChecksum ((const UINT32 *) data, length)); }
 
   public:
   DEFINE_SIZE_STATIC (4);
@@ -761,7 +744,7 @@
  * Version Numbers
  */
 
-template <typename FixedType=USHORT>
+template <typename FixedType=UINT16>
 struct FixedVersion
 {
   inline uint32_t to_int (void) const { return (major << (sizeof(FixedType) * 8)) + minor; }
@@ -785,7 +768,7 @@
  * Use: (base+offset)
  */
 
-template <typename Type, typename OffsetType=USHORT>
+template <typename Type, typename OffsetType=UINT16>
 struct OffsetTo : Offset<OffsetType>
 {
   inline const Type& operator () (const void *base) const
@@ -830,7 +813,7 @@
   }
   DEFINE_SIZE_STATIC (sizeof(OffsetType));
 };
-template <typename Type> struct LOffsetTo : OffsetTo<Type, ULONG> {};
+template <typename Type> struct LOffsetTo : OffsetTo<Type, UINT32> {};
 template <typename Base, typename OffsetType, typename Type>
 static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
 template <typename Base, typename OffsetType, typename Type>
@@ -842,7 +825,7 @@
  */
 
 /* An array with a number of elements. */
-template <typename Type, typename LenType=USHORT>
+template <typename Type, typename LenType=UINT16>
 struct ArrayOf
 {
   const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
@@ -943,7 +926,7 @@
   inline bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && c->check_array (array, Type::static_size, len));
+    return_trace (len.sanitize (c) && c->check_array (array, Type::static_size, len));
   }
 
   public:
@@ -952,10 +935,10 @@
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
 };
-template <typename Type> struct LArrayOf : ArrayOf<Type, ULONG> {};
+template <typename Type> struct LArrayOf : ArrayOf<Type, UINT32> {};
 
 /* Array of Offset's */
-template <typename Type, typename OffsetType=USHORT>
+template <typename Type, typename OffsetType=UINT16>
 struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {};
 
 /* Array of offsets relative to the beginning of the array itself. */
@@ -983,7 +966,7 @@
 
 
 /* An array starting at second element. */
-template <typename Type, typename LenType=USHORT>
+template <typename Type, typename LenType=UINT16>
 struct HeadlessArrayOf
 {
   inline const Type& operator [] (unsigned int i) const
@@ -1009,12 +992,6 @@
     return_trace (true);
   }
 
-  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
-  {
-    return c->check_struct (this)
-	&& c->check_array (this, Type::static_size, len);
-  }
-
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1032,6 +1009,15 @@
     return_trace (true);
   }
 
+  private:
+  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (len.sanitize (c) &&
+		  (!len || c->check_array (array, Type::static_size, len - 1)));
+  }
+
+  public:
   LenType len;
   Type array[VAR];
   public:
@@ -1039,19 +1025,22 @@
 };
 
 
-/* An array with sorted elements.  Supports binary searching. */
-template <typename Type, typename LenType=USHORT>
+/*
+ * An array with sorted elements.  Supports binary searching.
+ */
+template <typename Type, typename LenType=UINT16>
 struct SortedArrayOf : ArrayOf<Type, LenType>
 {
   template <typename SearchType>
   inline int bsearch (const SearchType &x) const
   {
     /* Hand-coded bsearch here since this is in the hot inner loop. */
+    const Type *array = this->array;
     int min = 0, max = (int) this->len - 1;
     while (min <= max)
     {
       int mid = (min + max) / 2;
-      int c = this->array[mid].cmp (x);
+      int c = array[mid].cmp (x);
       if (c < 0)
         max = mid - 1;
       else if (c > 0)
@@ -1063,6 +1052,33 @@
   }
 };
 
+/*
+ * Binary-search arrays
+ */
+
+struct BinSearchHeader
+{
+  inline operator uint32_t (void) const { return len; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  UINT16	len;
+  UINT16	searchRangeZ;
+  UINT16	entrySelectorZ;
+  UINT16	rangeShiftZ;
+
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+template <typename Type>
+struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {};
+
 
 /* Lazy struct and blob loaders. */
 
@@ -1073,7 +1089,7 @@
   inline void init (hb_face_t *face_)
   {
     face = face_;
-    instance = NULL;
+    instance = nullptr;
   }
 
   inline void fini (void)
@@ -1096,7 +1112,7 @@
         p = const_cast<T *> (&OT::Null(T));
       else
 	p->init (face);
-      if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
+      if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p)))
       {
 	if (p != &OT::Null(T))
 	  p->fini ();
@@ -1123,8 +1139,8 @@
   inline void init (hb_face_t *face_)
   {
     face = face_;
-    instance = NULL;
-    blob = NULL;
+    instance = nullptr;
+    blob = nullptr;
   }
 
   inline void fini (void)
@@ -1140,7 +1156,7 @@
     {
       hb_blob_t *blob_ = OT::Sanitizer<T>::sanitize (face->reference_table (T::tableTag));
       p = const_cast<T *>(OT::Sanitizer<T>::lock_instance (blob_));
-      if (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p))
+      if (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p))
       {
 	hb_blob_destroy (blob_);
 	goto retry;
diff --git a/src/hb-ot-cbdt-table.hh b/src/hb-ot-cbdt-table.hh
index 0a7fbf5..415625e 100644
--- a/src/hb-ot-cbdt-table.hh
+++ b/src/hb-ot-cbdt-table.hh
@@ -47,20 +47,20 @@
     extents->height = -height;
   }
 
-  BYTE height;
-  BYTE width;
-  CHAR bearingX;
-  CHAR bearingY;
-  BYTE advance;
+  UINT8 height;
+  UINT8 width;
+  INT8 bearingX;
+  INT8 bearingY;
+  UINT8 advance;
 
   DEFINE_SIZE_STATIC(5);
 };
 
 struct BigGlyphMetrics : SmallGlyphMetrics
 {
-  CHAR vertBearingX;
-  CHAR vertBearingY;
-  BYTE vertAdvance;
+  INT8 vertBearingX;
+  INT8 vertBearingY;
+  UINT8 vertAdvance;
 
   DEFINE_SIZE_STATIC(8);
 };
@@ -73,18 +73,18 @@
     return_trace (c->check_struct (this));
   }
 
-  CHAR ascender;
-  CHAR decender;
-  BYTE widthMax;
-  CHAR caretSlopeNumerator;
-  CHAR caretSlopeDenominator;
-  CHAR caretOffset;
-  CHAR minOriginSB;
-  CHAR minAdvanceSB;
-  CHAR maxBeforeBL;
-  CHAR minAfterBL;
-  CHAR padding1;
-  CHAR padding2;
+  INT8 ascender;
+  INT8 decender;
+  UINT8 widthMax;
+  INT8 caretSlopeNumerator;
+  INT8 caretSlopeDenominator;
+  INT8 caretOffset;
+  INT8 minOriginSB;
+  INT8 minAdvanceSB;
+  INT8 maxBeforeBL;
+  INT8 minAfterBL;
+  INT8 padding1;
+  INT8 padding2;
 
   DEFINE_SIZE_STATIC(12);
 };
@@ -102,9 +102,9 @@
     return_trace (c->check_struct (this));
   }
 
-  USHORT indexFormat;
-  USHORT imageFormat;
-  ULONG imageDataOffset;
+  UINT16 indexFormat;
+  UINT16 imageFormat;
+  UINT32 imageDataOffset;
 
   DEFINE_SIZE_STATIC(8);
 };
@@ -137,8 +137,8 @@
   DEFINE_SIZE_ARRAY(8, offsetArrayZ);
 };
 
-struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<ULONG> {};
-struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<USHORT> {};
+struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<UINT32> {};
+struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<UINT16> {};
 
 struct IndexSubtable
 {
@@ -214,8 +214,8 @@
 						   offset, length, format);
   }
 
-  USHORT firstGlyphIndex;
-  USHORT lastGlyphIndex;
+  UINT16 firstGlyphIndex;
+  UINT16 lastGlyphIndex;
   LOffsetTo<IndexSubtable> offsetToSubtable;
 
   DEFINE_SIZE_STATIC(8);
@@ -245,7 +245,7 @@
         return &indexSubtablesZ[i];
       }
     }
-    return NULL;
+    return nullptr;
   }
 
   protected:
@@ -276,19 +276,19 @@
 
   protected:
   LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
-  ULONG indexTablesSize;
-  ULONG numberOfIndexSubtables;
-  ULONG colorRef;
+  UINT32 indexTablesSize;
+  UINT32 numberOfIndexSubtables;
+  UINT32 colorRef;
   SBitLineMetrics horizontal;
   SBitLineMetrics vertical;
-  USHORT startGlyphIndex;
-  USHORT endGlyphIndex;
-  BYTE ppemX;
-  BYTE ppemY;
-  BYTE bitDepth;
-  CHAR flags;
+  UINT16 startGlyphIndex;
+  UINT16 endGlyphIndex;
+  UINT8 ppemX;
+  UINT8 ppemY;
+  UINT8 bitDepth;
+  INT8 flags;
 
-public:
+  public:
   DEFINE_SIZE_STATIC(48);
 };
 
@@ -300,8 +300,8 @@
 struct GlyphBitmapDataFormat17
 {
   SmallGlyphMetrics glyphMetrics;
-  ULONG dataLen;
-  BYTE dataZ[VAR];
+  UINT32 dataLen;
+  UINT8 dataZ[VAR];
 
   DEFINE_SIZE_ARRAY(9, dataZ);
 };
@@ -315,6 +315,8 @@
 
 struct CBLC
 {
+  friend struct CBDT;
+
   static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -325,7 +327,7 @@
 		  sizeTables.sanitize (c, this));
   }
 
-  public:
+  protected:
   const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
 					 unsigned int *x_ppem, unsigned int *y_ppem) const
   {
@@ -344,7 +346,7 @@
       }
     }
 
-    return NULL;
+    return nullptr;
   }
 
   protected:
@@ -371,9 +373,94 @@
 		  likely (version.major == 2 || version.major == 3));
   }
 
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      upem = face->get_upem();
+
+      cblc_blob = Sanitizer<CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
+      cbdt_blob = Sanitizer<CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
+      cbdt_len = hb_blob_get_length (cbdt_blob);
+
+      if (hb_blob_get_length (cblc_blob) == 0) {
+	cblc = nullptr;
+	cbdt = nullptr;
+	return;  /* Not a bitmap font. */
+      }
+      cblc = Sanitizer<CBLC>::lock_instance (cblc_blob);
+      cbdt = Sanitizer<CBDT>::lock_instance (cbdt_blob);
+
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (this->cblc_blob);
+      hb_blob_destroy (this->cbdt_blob);
+    }
+
+    inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+    {
+      unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
+
+      if (!cblc)
+	return false;  // Not a color bitmap font.
+
+      const IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
+      if (!subtable_record || !x_ppem || !y_ppem)
+	return false;
+
+      if (subtable_record->get_extents (extents))
+	return true;
+
+      unsigned int image_offset = 0, image_length = 0, image_format = 0;
+      if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
+	return false;
+
+      {
+	if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+	  return false;
+
+	switch (image_format)
+	{
+	  case 17: {
+	    if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
+	      return false;
+
+	    const GlyphBitmapDataFormat17& glyphFormat17 =
+		StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+	    glyphFormat17.glyphMetrics.get_extents (extents);
+	  }
+	  break;
+	  default:
+	    // TODO: Support other image formats.
+	    return false;
+	}
+      }
+
+      /* Convert to the font units. */
+      extents->x_bearing *= upem / (float) x_ppem;
+      extents->y_bearing *= upem / (float) y_ppem;
+      extents->width *= upem / (float) x_ppem;
+      extents->height *= upem / (float) y_ppem;
+
+      return true;
+    }
+
+    private:
+    hb_blob_t *cblc_blob;
+    hb_blob_t *cbdt_blob;
+    const CBLC *cblc;
+    const CBDT *cbdt;
+
+    unsigned int cbdt_len;
+    unsigned int upem;
+  };
+
+
   protected:
   FixedVersion<>version;
-  BYTE dataZ[VAR];
+  UINT8 dataZ[VAR];
 
   public:
   DEFINE_SIZE_ARRAY(4, dataZ);
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 3a53a1c..883d7b3 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -58,10 +58,10 @@
   }
 
   protected:
-  USHORT	format;		/* Format number is set to 0. */
-  USHORT	lengthZ;	/* Byte length of this subtable. */
-  USHORT	languageZ;	/* Ignore. */
-  BYTE		glyphIdArray[256];/* An array that maps character
+  UINT16	format;		/* Format number is set to 0. */
+  UINT16	lengthZ;	/* Byte length of this subtable. */
+  UINT16	languageZ;	/* Ignore. */
+  UINT8		glyphIdArray[256];/* An array that maps character
 				 * code to glyph index values. */
   public:
   DEFINE_SIZE_STATIC (6 + 256);
@@ -88,8 +88,8 @@
 
       /* Custom two-array bsearch. */
       int min = 0, max = (int) thiz->segCount - 1;
-      const USHORT *startCount = thiz->startCount;
-      const USHORT *endCount = thiz->endCount;
+      const UINT16 *startCount = thiz->startCount;
+      const UINT16 *endCount = thiz->endCount;
       unsigned int i;
       while (min <= max)
       {
@@ -127,11 +127,11 @@
       return true;
     }
 
-    const USHORT *endCount;
-    const USHORT *startCount;
-    const USHORT *idDelta;
-    const USHORT *idRangeOffset;
-    const USHORT *glyphIdArray;
+    const UINT16 *endCount;
+    const UINT16 *startCount;
+    const UINT16 *idDelta;
+    const UINT16 *idRangeOffset;
+    const UINT16 *glyphIdArray;
     unsigned int segCount;
     unsigned int glyphIdArrayLength;
   };
@@ -165,24 +165,24 @@
   }
 
   protected:
-  USHORT	format;		/* Format number is set to 4. */
-  USHORT	length;		/* This is the length in bytes of the
+  UINT16	format;		/* Format number is set to 4. */
+  UINT16	length;		/* This is the length in bytes of the
 				 * subtable. */
-  USHORT	languageZ;	/* Ignore. */
-  USHORT	segCountX2;	/* 2 x segCount. */
-  USHORT	searchRangeZ;	/* 2 * (2**floor(log2(segCount))) */
-  USHORT	entrySelectorZ;	/* log2(searchRange/2) */
-  USHORT	rangeShiftZ;	/* 2 x segCount - searchRange */
+  UINT16	languageZ;	/* Ignore. */
+  UINT16	segCountX2;	/* 2 x segCount. */
+  UINT16	searchRangeZ;	/* 2 * (2**floor(log2(segCount))) */
+  UINT16	entrySelectorZ;	/* log2(searchRange/2) */
+  UINT16	rangeShiftZ;	/* 2 x segCount - searchRange */
 
-  USHORT	values[VAR];
+  UINT16	values[VAR];
 #if 0
-  USHORT	endCount[segCount];	/* End characterCode for each segment,
+  UINT16	endCount[segCount];	/* End characterCode for each segment,
 					 * last=0xFFFFu. */
-  USHORT	reservedPad;		/* Set to 0. */
-  USHORT	startCount[segCount];	/* Start character code for each segment. */
-  SHORT		idDelta[segCount];	/* Delta for all character codes in segment. */
-  USHORT	idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
-  USHORT	glyphIdArray[VAR];	/* Glyph index array (arbitrary length) */
+  UINT16	reservedPad;		/* Set to 0. */
+  UINT16	startCount[segCount];	/* Start character code for each segment. */
+  INT16		idDelta[segCount];	/* Delta for all character codes in segment. */
+  UINT16	idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
+  UINT16	glyphIdArray[VAR];	/* Glyph index array (arbitrary length) */
 #endif
 
   public:
@@ -208,9 +208,9 @@
   }
 
   private:
-  ULONG		startCharCode;	/* First character code in this group. */
-  ULONG		endCharCode;	/* Last character code in this group. */
-  ULONG		glyphID;	/* Glyph index; interpretation depends on
+  UINT32		startCharCode;	/* First character code in this group. */
+  UINT32		endCharCode;	/* Last character code in this group. */
+  UINT32		glyphID;	/* Glyph index; interpretation depends on
 				 * subtable format. */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -247,8 +247,8 @@
   DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
 };
 
-struct CmapSubtableFormat6  : CmapSubtableTrimmed<USHORT> {};
-struct CmapSubtableFormat10 : CmapSubtableTrimmed<ULONG > {};
+struct CmapSubtableFormat6  : CmapSubtableTrimmed<UINT16> {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<UINT32 > {};
 
 template <typename T>
 struct CmapSubtableLongSegmented
@@ -269,11 +269,11 @@
   }
 
   protected:
-  USHORT	format;		/* Subtable format; set to 12. */
-  USHORT	reservedZ;	/* Reserved; set to 0. */
-  ULONG		lengthZ;	/* Byte length of this subtable. */
-  ULONG		languageZ;	/* Ignore. */
-  SortedArrayOf<CmapSubtableLongGroup, ULONG>
+  UINT16	format;		/* Subtable format; set to 12. */
+  UINT16	reservedZ;	/* Reserved; set to 0. */
+  UINT32		lengthZ;	/* Byte length of this subtable. */
+  UINT32		languageZ;	/* Ignore. */
+  SortedArrayOf<CmapSubtableLongGroup, UINT32>
 		groups;		/* Groupings. */
   public:
   DEFINE_SIZE_ARRAY (16, groups);
@@ -316,13 +316,13 @@
   }
 
   UINT24	startUnicodeValue;	/* First value in this range. */
-  BYTE		additionalCount;	/* Number of additional values in this
+  UINT8		additionalCount;	/* Number of additional values in this
 					 * range. */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
-typedef SortedArrayOf<UnicodeValueRange, ULONG> DefaultUVS;
+typedef SortedArrayOf<UnicodeValueRange, UINT32> DefaultUVS;
 
 struct UVSMapping
 {
@@ -343,7 +343,7 @@
   DEFINE_SIZE_STATIC (5);
 };
 
-typedef SortedArrayOf<UVSMapping, ULONG> NonDefaultUVS;
+typedef SortedArrayOf<UVSMapping, UINT32> NonDefaultUVS;
 
 struct VariationSelectorRecord
 {
@@ -405,9 +405,9 @@
   }
 
   protected:
-  USHORT	format;		/* Format number is set to 14. */
-  ULONG		lengthZ;	/* Byte length of this subtable. */
-  SortedArrayOf<VariationSelectorRecord, ULONG>
+  UINT16	format;		/* Format number is set to 14. */
+  UINT32		lengthZ;	/* Byte length of this subtable. */
+  SortedArrayOf<VariationSelectorRecord, UINT32>
 		record;		/* Variation selector records; sorted
 				 * in increasing order of `varSelector'. */
   public:
@@ -451,7 +451,7 @@
 
   public:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   CmapSubtableFormat0	format0;
   CmapSubtableFormat4	format4;
   CmapSubtableFormat6	format6;
@@ -484,8 +484,8 @@
 		  subtable.sanitize (c, base));
   }
 
-  USHORT	platformID;	/* Platform ID. */
-  USHORT	encodingID;	/* Platform-specific encoding ID. */
+  UINT16	platformID;	/* Platform ID. */
+  UINT16	encodingID;	/* Platform-specific encoding ID. */
   LOffsetTo<CmapSubtable>
 		subtable;	/* Byte offset from beginning of table to the subtable for this encoding. */
   public:
@@ -496,6 +496,146 @@
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_cmap;
 
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  likely (version == 0) &&
+		  encodingRecord.sanitize (c, this));
+  }
+
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
+      const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
+      const OT::CmapSubtable *subtable = nullptr;
+      const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
+
+      bool symbol = false;
+      /* 32-bit subtables. */
+      if (!subtable) subtable = cmap->find_subtable (3, 10);
+      if (!subtable) subtable = cmap->find_subtable (0, 6);
+      if (!subtable) subtable = cmap->find_subtable (0, 4);
+      /* 16-bit subtables. */
+      if (!subtable) subtable = cmap->find_subtable (3, 1);
+      if (!subtable) subtable = cmap->find_subtable (0, 3);
+      if (!subtable) subtable = cmap->find_subtable (0, 2);
+      if (!subtable) subtable = cmap->find_subtable (0, 1);
+      if (!subtable) subtable = cmap->find_subtable (0, 0);
+      if (!subtable)
+      {
+	subtable = cmap->find_subtable (3, 0);
+	if (subtable) symbol = true;
+      }
+      /* Meh. */
+      if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
+
+      /* UVS subtable. */
+      if (!subtable_uvs)
+      {
+	const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
+	if (st && st->u.format == 14)
+	  subtable_uvs = &st->u.format14;
+      }
+      /* Meh. */
+      if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
+
+      this->uvs_table = subtable_uvs;
+
+      this->get_glyph_data = subtable;
+      if (unlikely (symbol))
+	this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
+      else
+	switch (subtable->u.format) {
+	/* Accelerate format 4 and format 12. */
+	default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;		break;
+	case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;	break;
+	case  4:
+	  {
+	    this->format4_accel.init (&subtable->u.format4);
+	    this->get_glyph_data = &this->format4_accel;
+	    this->get_glyph_func = this->format4_accel.get_glyph_func;
+	  }
+	  break;
+	}
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (this->blob);
+    }
+
+    inline bool get_nominal_glyph (hb_codepoint_t  unicode,
+				   hb_codepoint_t *glyph) const
+    {
+      return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
+    }
+
+    inline bool get_variation_glyph (hb_codepoint_t  unicode,
+				     hb_codepoint_t  variation_selector,
+				     hb_codepoint_t *glyph) const
+    {
+      switch (this->uvs_table->get_glyph_variant (unicode,
+						  variation_selector,
+						  glyph))
+      {
+	case OT::GLYPH_VARIANT_NOT_FOUND:		return false;
+	case OT::GLYPH_VARIANT_FOUND:		return true;
+	case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
+      }
+
+      return get_nominal_glyph (unicode, glyph);
+    }
+
+    protected:
+    typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
+					      hb_codepoint_t codepoint,
+					      hb_codepoint_t *glyph);
+
+    template <typename Type>
+    static inline 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 inline 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)))
+	return true;
+
+      if (codepoint <= 0x00FFu)
+      {
+	/* For symbol-encoded OpenType fonts, we duplicate the
+	 * U+F000..F0FF range at U+0000..U+00FF.  That's what
+	 * Windows seems to do, and that's hinted about at:
+	 * http://www.microsoft.com/typography/otspec/recom.htm
+	 * under "Non-Standard (Symbol) Fonts". */
+	return typed_obj->get_glyph (0xF000u + codepoint, glyph);
+      }
+
+      return false;
+    }
+
+    private:
+    hb_cmap_get_glyph_func_t get_glyph_func;
+    const void *get_glyph_data;
+    OT::CmapSubtableFormat4::accelerator_t format4_accel;
+
+    const OT::CmapSubtableFormat14 *uvs_table;
+    hb_blob_t *blob;
+  };
+
+  protected:
+
   inline const CmapSubtable *find_subtable (unsigned int platform_id,
 					    unsigned int encoding_id) const
   {
@@ -508,20 +648,13 @@
      * unsorted subtable list. */
     int result = encodingRecord./*bsearch*/lsearch (key);
     if (result == -1 || !encodingRecord[result].subtable)
-      return NULL;
+      return nullptr;
 
     return &(this+encodingRecord[result].subtable);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-		  likely (version == 0) &&
-		  encodingRecord.sanitize (c, this));
-  }
-
-  USHORT		version;	/* Table version number (0). */
+  protected:
+  UINT16		version;	/* Table version number (0). */
   SortedArrayOf<EncodingRecord>
 			encodingRecord;	/* Encoding tables. */
   public:
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 009db20..9864064 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -33,409 +33,20 @@
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-cbdt-table.hh"
 #include "hb-ot-glyf-table.hh"
-#include "hb-ot-head-table.hh"
-#include "hb-ot-hhea-table.hh"
 #include "hb-ot-hmtx-table.hh"
-#include "hb-ot-os2-table.hh"
-#include "hb-ot-var-hvar-table.hh"
-//#include "hb-ot-post-table.hh"
+#include "hb-ot-kern-table.hh"
+#include "hb-ot-post-table.hh"
 
 
-struct hb_ot_face_metrics_accelerator_t
-{
-  unsigned int num_metrics;
-  unsigned int num_advances;
-  unsigned int default_advance;
-  unsigned short ascender;
-  unsigned short descender;
-  unsigned short line_gap;
-  bool has_font_extents;
-
-  const OT::hmtxvmtx *table;
-  hb_blob_t *blob;
-
-  const OT::HVARVVAR *var;
-  hb_blob_t *var_blob;
-
-  inline void init (hb_face_t *face,
-		    hb_tag_t _hea_tag,
-		    hb_tag_t _mtx_tag,
-		    hb_tag_t _var_tag,
-		    hb_tag_t os2_tag,
-		    unsigned int default_advance = 0)
-  {
-    this->default_advance = default_advance ? default_advance : face->get_upem ();
-
-    bool got_font_extents = false;
-    if (os2_tag)
-    {
-      hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
-      const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
-#define USE_TYPO_METRICS (1u<<7)
-      if (0 != (os2->fsSelection & USE_TYPO_METRICS))
-      {
-	this->ascender = os2->sTypoAscender;
-	this->descender = os2->sTypoDescender;
-	this->line_gap = os2->sTypoLineGap;
-	got_font_extents = (this->ascender | this->descender) != 0;
-      }
-      hb_blob_destroy (os2_blob);
-    }
-
-    hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
-    const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
-    this->num_advances = _hea->numberOfLongMetrics;
-    if (!got_font_extents)
-    {
-      this->ascender = _hea->ascender;
-      this->descender = _hea->descender;
-      this->line_gap = _hea->lineGap;
-      got_font_extents = (this->ascender | this->descender) != 0;
-    }
-    hb_blob_destroy (_hea_blob);
-
-    this->has_font_extents = got_font_extents;
-
-    this->blob = OT::Sanitizer<OT::hmtxvmtx>::sanitize (face->reference_table (_mtx_tag));
-
-    /* Cap num_metrics() and num_advances() based on table length. */
-    unsigned int len = hb_blob_get_length (this->blob);
-    if (unlikely (this->num_advances * 4 > len))
-      this->num_advances = len / 4;
-    this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
-
-    /* We MUST set num_metrics to zero if num_advances is zero.
-     * Our get_advance() depends on that. */
-    if (unlikely (!this->num_advances))
-    {
-      this->num_metrics = this->num_advances = 0;
-      hb_blob_destroy (this->blob);
-      this->blob = hb_blob_get_empty ();
-    }
-    this->table = OT::Sanitizer<OT::hmtxvmtx>::lock_instance (this->blob);
-
-    this->var_blob = OT::Sanitizer<OT::HVARVVAR>::sanitize (face->reference_table (_var_tag));
-    this->var = OT::Sanitizer<OT::HVARVVAR>::lock_instance (this->var_blob);
-  }
-
-  inline void fini (void)
-  {
-    hb_blob_destroy (this->blob);
-    hb_blob_destroy (this->var_blob);
-  }
-
-  inline unsigned int get_advance (hb_codepoint_t  glyph,
-				   hb_font_t      *font) const
-  {
-    if (unlikely (glyph >= this->num_metrics))
-    {
-      /* If this->num_metrics is zero, it means we don't have the metrics table
-       * for this direction: return default advance.  Otherwise, it means that the
-       * glyph index is out of bound: return zero. */
-      if (this->num_metrics)
-	return 0;
-      else
-	return this->default_advance;
-    }
-
-    return this->table->longMetric[MIN (glyph, this->num_advances - 1)].advance
-	 + this->var->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
-  }
-};
-
-struct hb_ot_face_glyf_accelerator_t
-{
-  bool short_offset;
-  unsigned int num_glyphs;
-  const OT::loca *loca;
-  const OT::glyf *glyf;
-  hb_blob_t *loca_blob;
-  hb_blob_t *glyf_blob;
-  unsigned int glyf_len;
-
-  inline void init (hb_face_t *face)
-  {
-    hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head));
-    const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob);
-    if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0)
-    {
-      /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
-      hb_blob_destroy (head_blob);
-      return;
-    }
-    this->short_offset = 0 == head->indexToLocFormat;
-    hb_blob_destroy (head_blob);
-
-    this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
-    this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob);
-    this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
-    this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob);
-
-    this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1;
-    this->glyf_len = hb_blob_get_length (this->glyf_blob);
-  }
-
-  inline void fini (void)
-  {
-    hb_blob_destroy (this->loca_blob);
-    hb_blob_destroy (this->glyf_blob);
-  }
-
-  inline bool get_extents (hb_codepoint_t glyph,
-			   hb_glyph_extents_t *extents) const
-  {
-    if (unlikely (glyph >= this->num_glyphs))
-      return false;
-
-    unsigned int start_offset, end_offset;
-    if (this->short_offset)
-    {
-      start_offset = 2 * this->loca->u.shortsZ[glyph];
-      end_offset   = 2 * this->loca->u.shortsZ[glyph + 1];
-    }
-    else
-    {
-      start_offset = this->loca->u.longsZ[glyph];
-      end_offset   = this->loca->u.longsZ[glyph + 1];
-    }
-
-    if (start_offset > end_offset || end_offset > this->glyf_len)
-      return false;
-
-    if (end_offset - start_offset < OT::glyfGlyphHeader::static_size)
-      return true; /* Empty glyph; zero extents. */
-
-    const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, 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;
-  }
-};
-
-struct hb_ot_face_cbdt_accelerator_t
-{
-  hb_blob_t *cblc_blob;
-  hb_blob_t *cbdt_blob;
-  const OT::CBLC *cblc;
-  const OT::CBDT *cbdt;
-
-  unsigned int cbdt_len;
-  float upem;
-
-  inline void init (hb_face_t *face)
-  {
-    upem = face->get_upem();
-
-    cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
-    cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
-    cbdt_len = hb_blob_get_length (cbdt_blob);
-
-    if (hb_blob_get_length (cblc_blob) == 0) {
-      cblc = NULL;
-      cbdt = NULL;
-      return;  /* Not a bitmap font. */
-    }
-    cblc = OT::Sanitizer<OT::CBLC>::lock_instance (cblc_blob);
-    cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (cbdt_blob);
-
-  }
-
-  inline void fini (void)
-  {
-    hb_blob_destroy (this->cblc_blob);
-    hb_blob_destroy (this->cbdt_blob);
-  }
-
-  inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
-  {
-    unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
-
-    if (cblc == NULL)
-      return false;  // Not a color bitmap font.
-
-    const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
-    if (subtable_record == NULL)
-      return false;
-
-    if (subtable_record->get_extents (extents))
-      return true;
-
-    unsigned int image_offset = 0, image_length = 0, image_format = 0;
-    if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
-      return false;
-
-    {
-      /* TODO Move the following into CBDT struct when adding more formats. */
-
-      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
-	return false;
-
-      switch (image_format)
-      {
-	case 17: {
-	  if (unlikely (image_length < OT::GlyphBitmapDataFormat17::min_size))
-	    return false;
-
-	  const OT::GlyphBitmapDataFormat17& glyphFormat17 =
-	      OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, image_offset);
-	  glyphFormat17.glyphMetrics.get_extents (extents);
-	}
-	break;
-	default:
-	  // TODO: Support other image formats.
-	  return false;
-      }
-    }
-
-    /* Convert to the font units. */
-    extents->x_bearing *= upem / (float) x_ppem;
-    extents->y_bearing *= upem / (float) y_ppem;
-    extents->width *= upem / (float) x_ppem;
-    extents->height *= upem / (float) y_ppem;
-
-    return true;
-  }
-};
-
-typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
-					  hb_codepoint_t codepoint,
-					  hb_codepoint_t *glyph);
-
-template <typename Type>
-static inline 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 inline 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)))
-    return true;
-
-  if (codepoint <= 0x00FFu)
-  {
-    /* For symbol-encoded OpenType fonts, we duplicate the
-     * U+F000..F0FF range at U+0000..U+00FF.  That's what
-     * Windows seems to do, and that's hinted about at:
-     * http://www.microsoft.com/typography/otspec/recom.htm
-     * under "Non-Standard (Symbol) Fonts". */
-    return typed_obj->get_glyph (0xF000u + codepoint, glyph);
-  }
-
-  return false;
-}
-
-struct hb_ot_face_cmap_accelerator_t
-{
-  hb_cmap_get_glyph_func_t get_glyph_func;
-  const void *get_glyph_data;
-  OT::CmapSubtableFormat4::accelerator_t format4_accel;
-
-  const OT::CmapSubtableFormat14 *uvs_table;
-  hb_blob_t *blob;
-
-  inline void init (hb_face_t *face)
-  {
-    this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
-    const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
-    const OT::CmapSubtable *subtable = NULL;
-    const OT::CmapSubtableFormat14 *subtable_uvs = NULL;
-
-    bool symbol = false;
-    /* 32-bit subtables. */
-    if (!subtable) subtable = cmap->find_subtable (3, 10);
-    if (!subtable) subtable = cmap->find_subtable (0, 6);
-    if (!subtable) subtable = cmap->find_subtable (0, 4);
-    /* 16-bit subtables. */
-    if (!subtable) subtable = cmap->find_subtable (3, 1);
-    if (!subtable) subtable = cmap->find_subtable (0, 3);
-    if (!subtable) subtable = cmap->find_subtable (0, 2);
-    if (!subtable) subtable = cmap->find_subtable (0, 1);
-    if (!subtable) subtable = cmap->find_subtable (0, 0);
-    if (!subtable)
-    {
-      subtable = cmap->find_subtable (3, 0);
-      if (subtable) symbol = true;
-    }
-    /* Meh. */
-    if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
-
-    /* UVS subtable. */
-    if (!subtable_uvs)
-    {
-      const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
-      if (st && st->u.format == 14)
-        subtable_uvs = &st->u.format14;
-    }
-    /* Meh. */
-    if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
-
-    this->uvs_table = subtable_uvs;
-
-    this->get_glyph_data = subtable;
-    if (unlikely (symbol))
-      this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
-    else
-      switch (subtable->u.format) {
-      /* Accelerate format 4 and format 12. */
-      default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;		break;
-      case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;	break;
-      case  4:
-	{
-	  this->format4_accel.init (&subtable->u.format4);
-	  this->get_glyph_data = &this->format4_accel;
-	  this->get_glyph_func = this->format4_accel.get_glyph_func;
-	}
-	break;
-      }
-  }
-
-  inline void fini (void)
-  {
-    hb_blob_destroy (this->blob);
-  }
-
-  inline bool get_nominal_glyph (hb_codepoint_t  unicode,
-				 hb_codepoint_t *glyph) const
-  {
-    return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
-  }
-
-  inline bool get_variation_glyph (hb_codepoint_t  unicode,
-				   hb_codepoint_t  variation_selector,
-				   hb_codepoint_t *glyph) const
-  {
-    switch (this->uvs_table->get_glyph_variant (unicode,
-						variation_selector,
-						glyph))
-    {
-      case OT::GLYPH_VARIANT_NOT_FOUND:		return false;
-      case OT::GLYPH_VARIANT_FOUND:		return true;
-      case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
-    }
-
-    return get_nominal_glyph (unicode, glyph);
-  }
-};
-
 struct hb_ot_font_t
 {
-  hb_ot_face_cmap_accelerator_t cmap;
-  hb_ot_face_metrics_accelerator_t h_metrics;
-  hb_ot_face_metrics_accelerator_t v_metrics;
-  OT::hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
-  OT::hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
+  OT::cmap::accelerator_t cmap;
+  OT::hmtx::accelerator_t h_metrics;
+  OT::vmtx::accelerator_t v_metrics;
+  OT::hb_lazy_loader_t<OT::glyf::accelerator_t> glyf;
+  OT::hb_lazy_loader_t<OT::CBDT::accelerator_t> cbdt;
+  OT::hb_lazy_loader_t<OT::post::accelerator_t> post;
+  OT::hb_lazy_loader_t<OT::kern::accelerator_t> kern;
 };
 
 
@@ -445,26 +56,31 @@
   hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
 
   if (unlikely (!ot_font))
-    return NULL;
+    return nullptr;
 
   ot_font->cmap.init (face);
-  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_HVAR, HB_OT_TAG_os2);
-  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_OT_TAG_VVAR, HB_TAG_NONE,
-			   ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
+  ot_font->h_metrics.init (face);
+  ot_font->v_metrics.init (face, ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
   ot_font->glyf.init (face);
   ot_font->cbdt.init (face);
+  ot_font->post.init (face);
+  ot_font->kern.init (face);
 
   return ot_font;
 }
 
 static void
-_hb_ot_font_destroy (hb_ot_font_t *ot_font)
+_hb_ot_font_destroy (void *data)
 {
+  hb_ot_font_t *ot_font = (hb_ot_font_t *) data;
+
   ot_font->cmap.fini ();
   ot_font->h_metrics.fini ();
   ot_font->v_metrics.fini ();
   ot_font->glyf.fini ();
   ot_font->cbdt.fini ();
+  ot_font->post.fini ();
+  ot_font->kern.fini ();
 
   free (ot_font);
 }
@@ -514,6 +130,17 @@
   return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font));
 }
 
+static hb_position_t
+hb_ot_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_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return font->em_scale_x (ot_font->kern->get_h_kerning (left_glyph, right_glyph));
+}
+
 static hb_bool_t
 hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
 			 void *font_data,
@@ -534,6 +161,28 @@
 }
 
 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)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return ot_font->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)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return ot_font->post->get_glyph_from_name (name, len, glyph);
+}
+
+static hb_bool_t
 hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
 			  void *font_data,
 			  hb_font_extents_t *metrics,
@@ -561,7 +210,7 @@
   return ot_font->v_metrics.has_font_extents;
 }
 
-static hb_font_funcs_t *static_ot_funcs = NULL;
+static hb_font_funcs_t *static_ot_funcs = nullptr;
 
 #ifdef HB_USE_ATEXIT
 static
@@ -581,24 +230,24 @@
   {
     funcs = hb_font_funcs_create ();
 
-    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
-    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
-    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL);
-    hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL);
-    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
-    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
-    //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
-    //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
-    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
-    hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
-    //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
-    //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
-    //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
+    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
+    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
+    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
+    hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
+    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, nullptr, nullptr);
+    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, nullptr, nullptr);
+    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
+    //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
+    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, nullptr, nullptr);
+    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, 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);
+    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);
 
     hb_font_funcs_make_immutable (funcs);
 
-    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
+    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, nullptr, funcs)) {
       hb_font_funcs_destroy (funcs);
       goto retry;
     }
@@ -627,5 +276,5 @@
   hb_font_set_funcs (font,
 		     _hb_ot_get_font_funcs (),
 		     ot_font,
-		     (hb_destroy_func_t) _hb_ot_font_destroy);
+		     _hb_ot_font_destroy);
 }
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index dc7aa84..88d3850 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -28,6 +28,7 @@
 #define HB_OT_GLYF_TABLE_HH
 
 #include "hb-open-type-private.hh"
+#include "hb-ot-head-table.hh"
 
 
 namespace OT {
@@ -42,6 +43,8 @@
 
 struct loca
 {
+  friend struct glyf;
+
   static const hb_tag_t tableTag = HB_OT_TAG_loca;
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -50,12 +53,9 @@
     return_trace (true);
   }
 
-  public:
-  union {
-    USHORT	shortsZ[VAR];		/* Location offset divided by 2. */
-    ULONG	longsZ[VAR];		/* Location offset. */
-  } u;
-  DEFINE_SIZE_ARRAY (0, u.longsZ);
+  protected:
+  UINT8		dataX[VAR];		/* Location data. */
+  DEFINE_SIZE_ARRAY (0, dataX);
 };
 
 
@@ -78,26 +78,102 @@
     return_trace (true);
   }
 
-  public:
-  BYTE		dataX[VAR];		/* Glyphs data. */
+  struct GlyphHeader
+  {
+    INT16		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 accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      hb_blob_t *head_blob = Sanitizer<head>::sanitize (face->reference_table (HB_OT_TAG_head));
+      const head *head_table = Sanitizer<head>::lock_instance (head_blob);
+      if ((unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
+      {
+	/* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
+	hb_blob_destroy (head_blob);
+	return;
+      }
+      short_offset = 0 == head_table->indexToLocFormat;
+      hb_blob_destroy (head_blob);
+
+      loca_blob = Sanitizer<loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
+      loca_table = Sanitizer<loca>::lock_instance (loca_blob);
+      glyf_blob = Sanitizer<glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
+      glyf_table = Sanitizer<glyf>::lock_instance (glyf_blob);
+
+      num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1;
+      glyf_len = hb_blob_get_length (glyf_blob);
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (loca_blob);
+      hb_blob_destroy (glyf_blob);
+    }
+
+    inline bool get_extents (hb_codepoint_t glyph,
+			     hb_glyph_extents_t *extents) const
+    {
+      if (unlikely (glyph >= num_glyphs))
+	return false;
+
+      unsigned int start_offset, end_offset;
+      if (short_offset)
+      {
+        const UINT16 *offsets = (const UINT16 *) loca_table->dataX;
+	start_offset = 2 * offsets[glyph];
+	end_offset   = 2 * offsets[glyph + 1];
+      }
+      else
+      {
+        const UINT32 *offsets = (const UINT32 *) loca_table->dataX;
+	start_offset = offsets[glyph];
+	end_offset   = offsets[glyph + 1];
+      }
+
+      if (start_offset > end_offset || end_offset > glyf_len)
+	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;
+    }
+
+    private:
+    bool short_offset;
+    unsigned int num_glyphs;
+    const loca *loca_table;
+    const glyf *glyf_table;
+    hb_blob_t *loca_blob;
+    hb_blob_t *glyf_blob;
+    unsigned int glyf_len;
+  };
+
+  protected:
+  UINT8		dataX[VAR];		/* Glyphs data. */
 
   DEFINE_SIZE_ARRAY (0, dataX);
 };
 
-struct glyfGlyphHeader
-{
-  SHORT		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);
-};
-
 } /* namespace OT */
 
 
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index 9c3e51e..dd4349e 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -64,11 +64,11 @@
   FixedVersion<>version;		/* Version of the head table--currently
 					 * 0x00010000u for version 1.0. */
   FixedVersion<>fontRevision;		/* Set by font manufacturer. */
-  ULONG		checkSumAdjustment;	/* To compute: set it to 0, sum the
-					 * entire font as ULONG, then store
+  UINT32		checkSumAdjustment;	/* To compute: set it to 0, sum the
+					 * entire font as UINT32, then store
 					 * 0xB1B0AFBAu - sum. */
-  ULONG		magicNumber;		/* Set to 0x5F0F3CF5u. */
-  USHORT	flags;			/* Bit 0: Baseline for font at y=0;
+  UINT32		magicNumber;		/* Set to 0x5F0F3CF5u. */
+  UINT16	flags;			/* Bit 0: Baseline for font at y=0;
 					 * Bit 1: Left sidebearing point at x=0;
 					 * Bit 2: Instructions may depend on point size;
 					 * Bit 3: Force ppem to integer values for all
@@ -114,18 +114,18 @@
 					 * encoded in the cmap subtables represent proper
 					 * support for those code points.
 					 * Bit 15: Reserved, set to 0. */
-  USHORT	unitsPerEm;		/* Valid range is from 16 to 16384. This value
+  UINT16	unitsPerEm;		/* Valid range is from 16 to 16384. This value
 					 * should be a power of 2 for fonts that have
 					 * TrueType outlines. */
   LONGDATETIME	created;		/* Number of seconds since 12:00 midnight,
 					   January 1, 1904. 64-bit integer */
   LONGDATETIME	modified;		/* Number of seconds since 12:00 midnight,
 					   January 1, 1904. 64-bit integer */
-  SHORT		xMin;			/* For all glyph bounding boxes. */
-  SHORT		yMin;			/* For all glyph bounding boxes. */
-  SHORT		xMax;			/* For all glyph bounding boxes. */
-  SHORT		yMax;			/* For all glyph bounding boxes. */
-  USHORT	macStyle;		/* Bit 0: Bold (if set to 1);
+  INT16		xMin;			/* For all glyph bounding boxes. */
+  INT16		yMin;			/* For all glyph bounding boxes. */
+  INT16		xMax;			/* For all glyph bounding boxes. */
+  INT16		yMax;			/* For all glyph bounding boxes. */
+  UINT16	macStyle;		/* Bit 0: Bold (if set to 1);
 					 * Bit 1: Italic (if set to 1)
 					 * Bit 2: Underline (if set to 1)
 					 * Bit 3: Outline (if set to 1)
@@ -133,16 +133,16 @@
 					 * Bit 5: Condensed (if set to 1)
 					 * Bit 6: Extended (if set to 1)
 					 * Bits 7-15: Reserved (set to 0). */
-  USHORT	lowestRecPPEM;		/* Smallest readable size in pixels. */
-  SHORT		fontDirectionHint;	/* Deprecated (Set to 2).
+  UINT16	lowestRecPPEM;		/* Smallest readable size in pixels. */
+  INT16		fontDirectionHint;	/* Deprecated (Set to 2).
 					 * 0: Fully mixed directional glyphs;
 					 * 1: Only strongly left to right;
 					 * 2: Like 1 but also contains neutrals;
 					 * -1: Only strongly right to left;
 					 * -2: Like -1 but also contains neutrals. */
   public:
-  SHORT		indexToLocFormat;	/* 0 for short offsets, 1 for long. */
-  SHORT		glyphDataFormat;	/* 0 for current format. */
+  INT16		indexToLocFormat;	/* 0 for short offsets, 1 for long. */
+  INT16		glyphDataFormat;	/* 0 for current format. */
 
   DEFINE_SIZE_STATIC (54);
 };
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index c8e9536..dca0141 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -44,11 +44,6 @@
 
 struct _hea
 {
-  static const hb_tag_t tableTag = HB_TAG('_','h','e','a');
-
-  static const hb_tag_t hheaTag	= HB_OT_TAG_hhea;
-  static const hb_tag_t vheaTag	= HB_OT_TAG_vhea;
-
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -69,21 +64,21 @@
 					 * (xMax - xMin)) for horizontal. */
   FWORD		maxExtent;		/* horizontal: Max(lsb + (xMax - xMin)),
 					 * vertical: minLeadingBearing+(yMax-yMin). */
-  SHORT		caretSlopeRise;		/* Used to calculate the slope of the
+  INT16		caretSlopeRise;		/* Used to calculate the slope of the
 					 * cursor (rise/run); 1 for vertical caret,
 					 * 0 for horizontal.*/
-  SHORT		caretSlopeRun;		/* 0 for vertical caret, 1 for horizontal. */
-  SHORT		caretOffset;		/* The amount by which a slanted
+  INT16		caretSlopeRun;		/* 0 for vertical caret, 1 for horizontal. */
+  INT16		caretOffset;		/* The amount by which a slanted
 					 * highlight on a glyph needs
 					 * to be shifted to produce the
 					 * best appearance. Set to 0 for
 					 * non-slanted fonts. */
-  SHORT		reserved1;		/* Set to 0. */
-  SHORT		reserved2;		/* Set to 0. */
-  SHORT		reserved3;		/* Set to 0. */
-  SHORT		reserved4;		/* Set to 0. */
-  SHORT		metricDataFormat;	/* 0 for current format. */
-  USHORT	numberOfLongMetrics;	/* Number of LongMetric entries in metric
+  INT16		reserved1;		/* Set to 0. */
+  INT16		reserved2;		/* Set to 0. */
+  INT16		reserved3;		/* Set to 0. */
+  INT16		reserved4;		/* Set to 0. */
+  INT16		metricDataFormat;	/* 0 for current format. */
+  UINT16	numberOfLongMetrics;	/* Number of LongMetric entries in metric
 					 * table. */
   public:
   DEFINE_SIZE_STATIC (36);
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 30aa625..e710aee 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -28,6 +28,9 @@
 #define HB_OT_HMTX_TABLE_HH
 
 #include "hb-open-type-private.hh"
+#include "hb-ot-hhea-table.hh"
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-var-hvar-table.hh"
 
 
 namespace OT {
@@ -50,11 +53,9 @@
   DEFINE_SIZE_STATIC (4);
 };
 
+template <typename T>
 struct hmtxvmtx
 {
-  static const hb_tag_t hmtxTag	= HB_OT_TAG_hmtx;
-  static const hb_tag_t vmtxTag	= HB_OT_TAG_vmtx;
-
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -63,7 +64,107 @@
     return_trace (true);
   }
 
-  public:
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face,
+		      unsigned int default_advance_ = 0)
+    {
+      default_advance = default_advance_ ? default_advance_ : face->get_upem ();
+
+      bool got_font_extents = false;
+      if (T::os2Tag)
+      {
+	hb_blob_t *os2_blob = Sanitizer<os2>::sanitize (face->reference_table (T::os2Tag));
+	const os2 *os2_table = Sanitizer<os2>::lock_instance (os2_blob);
+#define USE_TYPO_METRICS (1u<<7)
+	if (0 != (os2_table->fsSelection & USE_TYPO_METRICS))
+	{
+	  ascender = os2_table->sTypoAscender;
+	  descender = os2_table->sTypoDescender;
+	  line_gap = os2_table->sTypoLineGap;
+	  got_font_extents = (ascender | descender) != 0;
+	}
+	hb_blob_destroy (os2_blob);
+      }
+
+      hb_blob_t *_hea_blob = Sanitizer<_hea>::sanitize (face->reference_table (T::headerTag));
+      const _hea *_hea_table = Sanitizer<_hea>::lock_instance (_hea_blob);
+      num_advances = _hea_table->numberOfLongMetrics;
+      if (!got_font_extents)
+      {
+	ascender = _hea_table->ascender;
+	descender = _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;
+
+      blob = Sanitizer<hmtxvmtx>::sanitize (face->reference_table (T::tableTag));
+
+      /* Cap num_metrics() and num_advances() based on table length. */
+      unsigned int len = hb_blob_get_length (blob);
+      if (unlikely (num_advances * 4 > len))
+	num_advances = len / 4;
+      num_metrics = num_advances + (len - 4 * num_advances) / 2;
+
+      /* We MUST set num_metrics to zero if num_advances is zero.
+       * Our get_advance() depends on that. */
+      if (unlikely (!num_advances))
+      {
+	num_metrics = num_advances = 0;
+	hb_blob_destroy (blob);
+	blob = hb_blob_get_empty ();
+      }
+      table = Sanitizer<hmtxvmtx>::lock_instance (blob);
+
+      var_blob = Sanitizer<HVARVVAR>::sanitize (face->reference_table (T::variationsTag));
+      var_table = Sanitizer<HVARVVAR>::lock_instance (var_blob);
+    }
+
+    inline void fini (void)
+    {
+      hb_blob_destroy (blob);
+      hb_blob_destroy (var_blob);
+    }
+
+    inline unsigned int get_advance (hb_codepoint_t  glyph,
+				     hb_font_t      *font) const
+    {
+      if (unlikely (glyph >= num_metrics))
+      {
+	/* If num_metrics is zero, it means we don't have the metrics table
+	 * for this direction: return default advance.  Otherwise, it means that the
+	 * glyph index is out of bound: return zero. */
+	if (num_metrics)
+	  return 0;
+	else
+	  return default_advance;
+      }
+
+      return table->longMetric[MIN (glyph, (uint32_t) num_advances - 1)].advance
+	   + var_table->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
+    }
+
+    public:
+    bool has_font_extents;
+    unsigned short ascender;
+    unsigned short descender;
+    unsigned short line_gap;
+
+    private:
+    unsigned int num_metrics;
+    unsigned int num_advances;
+    unsigned int default_advance;
+
+    const hmtxvmtx *table;
+    hb_blob_t *blob;
+    const HVARVVAR *var_table;
+    hb_blob_t *var_blob;
+  };
+
+  protected:
   LongMetric	longMetric[VAR];	/* Paired advance width and leading
 					 * bearing values for each glyph. The
 					 * value numOfHMetrics comes from
@@ -89,11 +190,17 @@
   DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX);
 };
 
-struct hmtx : hmtxvmtx {
+struct hmtx : hmtxvmtx<hmtx> {
   static const hb_tag_t tableTag	= HB_OT_TAG_hmtx;
+  static const hb_tag_t headerTag	= HB_OT_TAG_hhea;
+  static const hb_tag_t variationsTag	= HB_OT_TAG_HVAR;
+  static const hb_tag_t os2Tag		= HB_OT_TAG_os2;
 };
-struct vmtx : hmtxvmtx {
+struct vmtx : hmtxvmtx<vmtx> {
   static const hb_tag_t tableTag	= HB_OT_TAG_vmtx;
+  static const hb_tag_t headerTag	= HB_OT_TAG_vhea;
+  static const hb_tag_t variationsTag	= HB_OT_TAG_VVAR;
+  static const hb_tag_t os2Tag		= HB_TAG_NONE;
 };
 
 } /* namespace OT */
diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh
new file mode 100644
index 0000000..e07faca
--- /dev/null
+++ b/src/hb-ot-kern-table.hh
@@ -0,0 +1,394 @@
+/*
+ * 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_OT_KERN_TABLE_HH
+#define HB_OT_KERN_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+namespace OT {
+
+
+/*
+ * kern -- Kerning
+ */
+
+#define HB_OT_TAG_kern HB_TAG('k','e','r','n')
+
+struct hb_glyph_pair_t
+{
+  hb_codepoint_t left;
+  hb_codepoint_t right;
+};
+
+struct KernPair
+{
+  inline int get_kerning (void) const
+  { return value; }
+
+  inline int cmp (const hb_glyph_pair_t &o) const
+  {
+    int ret = left.cmp (o.left);
+    if (ret) return ret;
+    return right.cmp (o.right);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  GlyphID	left;
+  GlyphID	right;
+  FWORD		value;
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct KernSubTableFormat0
+{
+  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
+  {
+    hb_glyph_pair_t pair = {left, right};
+    int i = pairs.bsearch (pair);
+    if (i == -1)
+      return 0;
+    return pairs[i].get_kerning ();
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (pairs.sanitize (c));
+  }
+
+  protected:
+  BinSearchArrayOf<KernPair> pairs;	/* Array of kerning pairs. */
+  public:
+  DEFINE_SIZE_ARRAY (8, pairs);
+};
+
+struct KernClassTable
+{
+  inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (firstGlyph.sanitize (c) && classes.sanitize (c));
+  }
+
+  protected:
+  UINT16		firstGlyph;	/* First glyph in class range. */
+  ArrayOf<UINT16>	classes;	/* Glyph classes. */
+  public:
+  DEFINE_SIZE_ARRAY (4, classes);
+};
+
+struct KernSubTableFormat2
+{
+  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
+  {
+    unsigned int l = (this+leftClassTable).get_class (left);
+    unsigned int r = (this+leftClassTable).get_class (left);
+    unsigned int offset = l * rowWidth + r * sizeof (FWORD);
+    const FWORD *arr = &(this+array);
+    if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end))
+      return 0;
+    const FWORD *v = &StructAtOffset<FWORD> (arr, offset);
+    if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
+      return 0;
+    return *v;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (rowWidth.sanitize (c) &&
+		  leftClassTable.sanitize (c, this) &&
+		  rightClassTable.sanitize (c, this) &&
+		  array.sanitize (c, this));
+  }
+
+  protected:
+  UINT16	rowWidth;	/* The width, in bytes, of a row in the table. */
+  OffsetTo<KernClassTable>
+		leftClassTable;	/* Offset from beginning of this subtable to
+				 * left-hand class table. */
+  OffsetTo<KernClassTable>
+		rightClassTable;/* Offset from beginning of this subtable to
+				 * right-hand class table. */
+  OffsetTo<FWORD>
+		array;		/* Offset from beginning of this subtable to
+				 * the start of the kerning array. */
+  public:
+  DEFINE_SIZE_MIN (8);
+};
+
+struct KernSubTable
+{
+  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end, unsigned int format) const
+  {
+    switch (format) {
+    case 0: return u.format0.get_kerning (left, right);
+    case 2: return u.format2.get_kerning (left, right, end);
+    default:return 0;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int format) const
+  {
+    TRACE_SANITIZE (this);
+    switch (format) {
+    case 0: return_trace (u.format0.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  KernSubTableFormat0	format0;
+  KernSubTableFormat2	format2;
+  } u;
+  public:
+  DEFINE_SIZE_MIN (0);
+};
+
+
+template <typename T>
+struct KernSubTableWrapper
+{
+  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
+  inline const T* thiz (void) const { return static_cast<const T *> (this); }
+
+  inline bool is_horizontal (void) const
+  { return (thiz()->coverage & T::COVERAGE_CHECK_FLAGS) == T::COVERAGE_CHECK_HORIZONTAL; }
+
+  inline bool is_override (void) const
+  { return bool (thiz()->coverage & T::COVERAGE_OVERRIDE_FLAG); }
+
+  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
+  { return thiz()->subtable.get_kerning (left, right, end, thiz()->format); }
+
+  inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
+  { return is_horizontal () ? get_kerning (left, right, end) : 0; }
+
+  inline unsigned int get_size (void) const { return thiz()->length; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (thiz()) &&
+		  thiz()->length >= thiz()->min_size &&
+		  c->check_array (thiz(), 1, thiz()->length) &&
+		  thiz()->subtable.sanitize (c, thiz()->format));
+  }
+};
+
+template <typename T>
+struct KernTable
+{
+  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
+  inline const T* thiz (void) const { return static_cast<const T *> (this); }
+
+  inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
+  {
+    int v = 0;
+    const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data);
+    unsigned int count = thiz()->nTables;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (st->is_override ())
+        v = 0;
+      v += st->get_h_kerning (left, right, table_length + (const char *) this);
+      st = &StructAfter<typename T::SubTableWrapper> (*st);
+    }
+    return v;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (thiz()) ||
+		  thiz()->version != T::VERSION))
+      return_trace (false);
+
+    const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data);
+    unsigned int count = thiz()->nTables;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (unlikely (!st->sanitize (c)))
+	return_trace (false);
+      st = &StructAfter<typename T::SubTableWrapper> (*st);
+    }
+
+    return_trace (true);
+  }
+};
+
+struct KernOT : KernTable<KernOT>
+{
+  friend struct KernTable<KernOT>;
+
+  static const uint16_t VERSION = 0x0000u;
+
+  struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
+  {
+    friend struct KernSubTableWrapper<SubTableWrapper>;
+
+    enum coverage_flags_t {
+      COVERAGE_DIRECTION_FLAG	= 0x01u,
+      COVERAGE_MINIMUM_FLAG	= 0x02u,
+      COVERAGE_CROSSSTREAM_FLAG	= 0x04u,
+      COVERAGE_OVERRIDE_FLAG	= 0x08u,
+
+      COVERAGE_VARIATION_FLAG	= 0x00u, /* Not supported. */
+
+      COVERAGE_CHECK_FLAGS	= 0x07u,
+      COVERAGE_CHECK_HORIZONTAL	= 0x01u
+    };
+
+    protected:
+    UINT16	versionZ;	/* Unused. */
+    UINT16	length;		/* Length of the subtable (including this header). */
+    UINT8	format;		/* Subtable format. */
+    UINT8	coverage;	/* Coverage bits. */
+    KernSubTable subtable;	/* Subtable data. */
+    public:
+    DEFINE_SIZE_MIN (6);
+  };
+
+  protected:
+  UINT16	version;	/* Version--0x0000u */
+  UINT16	nTables;	/* Number of subtables in the kerning table. */
+  UINT8		data[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (4, data);
+};
+
+struct KernAAT : KernTable<KernAAT>
+{
+  friend struct KernTable<KernAAT>;
+
+  static const uint32_t VERSION = 0x00010000u;
+
+  struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
+  {
+    friend struct KernSubTableWrapper<SubTableWrapper>;
+
+    enum coverage_flags_t {
+      COVERAGE_DIRECTION_FLAG	= 0x80u,
+      COVERAGE_CROSSSTREAM_FLAG	= 0x40u,
+      COVERAGE_VARIATION_FLAG	= 0x20u,
+
+      COVERAGE_OVERRIDE_FLAG	= 0x00u, /* Not supported. */
+
+      COVERAGE_CHECK_FLAGS	= 0xE0u,
+      COVERAGE_CHECK_HORIZONTAL	= 0x00u
+    };
+
+    protected:
+    UINT32	length;		/* Length of the subtable (including this header). */
+    UINT8	coverage;	/* Coverage bits. */
+    UINT8	format;		/* Subtable format. */
+    UINT16	tupleIndex;	/* The tuple index (used for variations fonts).
+				 * This value specifies which tuple this subtable covers. */
+    KernSubTable subtable;	/* Subtable data. */
+    public:
+    DEFINE_SIZE_MIN (8);
+  };
+
+  protected:
+  UINT32		version;	/* Version--0x00010000u */
+  UINT32		nTables;	/* Number of subtables in the kerning table. */
+  UINT8		data[VAR];
+  public:
+  DEFINE_SIZE_ARRAY (8, data);
+};
+
+struct kern
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_kern;
+
+  inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
+  {
+    switch (u.major) {
+    case 0: return u.ot.get_h_kerning (left, right, table_length);
+    case 1: return u.aat.get_h_kerning (left, right, table_length);
+    default:return 0;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.major.sanitize (c)) return_trace (false);
+    switch (u.major) {
+    case 0: return_trace (u.ot.sanitize (c));
+    case 1: return_trace (u.aat.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      blob = Sanitizer<kern>::sanitize (face->reference_table (HB_OT_TAG_kern));
+      table = Sanitizer<kern>::lock_instance (blob);
+      table_length = hb_blob_get_length (blob);
+    }
+    inline void fini (void)
+    {
+      hb_blob_destroy (blob);
+    }
+
+    inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
+    { return table->get_h_kerning (left, right, table_length); }
+
+    private:
+    hb_blob_t *blob;
+    const kern *table;
+    unsigned int table_length;
+  };
+
+  protected:
+  union {
+  UINT16		major;
+  KernOT		ot;
+  KernAAT		aat;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, major);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_KERN_TABLE_HH */
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 180e5f0..5e699e1 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -29,6 +29,8 @@
 #ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH
 #define HB_OT_LAYOUT_COMMON_PRIVATE_HH
 
+#include "hb-private.hh"
+#include "hb-debug.hh"
 #include "hb-ot-layout-private.hh"
 #include "hb-open-type-private.hh"
 #include "hb-set-private.hh"
@@ -45,12 +47,6 @@
 namespace OT {
 
 
-#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);
-
-
 #define NOT_COVERED		((unsigned int) -1)
 
 
@@ -159,13 +155,13 @@
   }
 
   template <typename set_t>
-  inline void add_coverage (set_t *glyphs) const {
-    glyphs->add_range (start, end);
+  inline 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 */
-  USHORT	value;		/* Value */
+  UINT16	value;		/* Value */
   public:
   DEFINE_SIZE_STATIC (6);
 };
@@ -179,7 +175,7 @@
 				   unsigned int *_indexes /* OUT */) const
   {
     if (_count) {
-      const USHORT *arr = this->sub_array (start_offset, _count);
+      const UINT16 *arr = this->sub_array (start_offset, _count);
       unsigned int count = *_count;
       for (unsigned int i = 0; i < count; i++)
 	_indexes[i] = arr[i];
@@ -214,15 +210,15 @@
   }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<LangSys>::sanitize_closure_t * = NULL) const
+			const Record<LangSys>::sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && featureIndex.sanitize (c));
   }
 
-  Offset<>	lookupOrderZ;	/* = Null (reserved for an offset to a
+  Offset16	lookupOrderZ;	/* = Null (reserved for an offset to a
 				 * reordering table) */
-  USHORT	reqFeatureIndex;/* Index of a feature required for this
+  UINT16	reqFeatureIndex;/* Index of a feature required for this
 				 * language system--if no required features
 				 * = 0xFFFFu */
   IndexArray	featureIndex;	/* Array of indices into the FeatureList */
@@ -254,7 +250,7 @@
   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<Script>::sanitize_closure_t * = NULL) const
+			const Record<Script>::sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
     return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
@@ -347,12 +343,12 @@
       return_trace (true);
   }
 
-  USHORT	designSize;	/* Represents the design size in 720/inch
+  UINT16	designSize;	/* Represents the design size in 720/inch
 				 * units (decipoints).  The design size entry
 				 * must be non-zero.  When there is a design
 				 * size but no recommended size range, the
 				 * rest of the array will consist of zeros. */
-  USHORT	subfamilyID;	/* Has no independent meaning, but serves
+  UINT16	subfamilyID;	/* Has no independent meaning, but serves
 				 * as an identifier that associates fonts
 				 * in a subfamily. All fonts which share a
 				 * Preferred or Font Family name and which
@@ -362,7 +358,7 @@
 				 * same subfamily value. If this value is
 				 * zero, the remaining fields in the array
 				 * will be ignored. */
-  USHORT	subfamilyNameID;/* If the preceding value is non-zero, this
+  UINT16	subfamilyNameID;/* If the preceding value is non-zero, this
 				 * value must be set in the range 256 - 32767
 				 * (inclusive). It records the value of a
 				 * field in the name table, which must
@@ -376,10 +372,10 @@
 				 * subfamily in a menu.  Applications will
 				 * choose the appropriate version based on
 				 * their selection criteria. */
-  USHORT	rangeStart;	/* Large end of the recommended usage range
+  UINT16	rangeStart;	/* Large end of the recommended usage range
 				 * (inclusive), stored in 720/inch units
 				 * (decipoints). */
-  USHORT	rangeEnd;	/* Small end of the recommended usage range
+  UINT16	rangeEnd;	/* Small end of the recommended usage range
 				   (exclusive), stored in 720/inch units
 				 * (decipoints). */
   public:
@@ -397,12 +393,12 @@
     return_trace (c->check_struct (this));
   }
 
-  USHORT	version;	/* (set to 0): This corresponds to a “minor”
+  UINT16	version;	/* (set to 0): This corresponds to a “minor”
 				 * version number. Additional data may be
 				 * added to the end of this Feature Parameters
 				 * table in the future. */
 
-  USHORT	uiNameID;	/* The 'name' table name ID that specifies a
+  UINT16	uiNameID;	/* The 'name' table name ID that specifies a
 				 * string (or strings, for multiple languages)
 				 * for a user-interface label for this
 				 * feature.  The values of uiLabelNameId and
@@ -430,25 +426,25 @@
 		  characters.sanitize (c));
   }
 
-  USHORT	format;			/* Format number is set to 0. */
-  USHORT	featUILableNameID;	/* The ‘name’ table name ID that
+  UINT16	format;			/* Format number is set to 0. */
+  UINT16	featUILableNameID;	/* The ‘name’ table name ID that
 					 * specifies a string (or strings,
 					 * for multiple languages) for a
 					 * user-interface label for this
-					 * feature. (May be NULL.) */
-  USHORT	featUITooltipTextNameID;/* The ‘name’ table name ID that
+					 * feature. (May be nullptr.) */
+  UINT16	featUITooltipTextNameID;/* The ‘name’ table name ID that
 					 * specifies a string (or strings,
 					 * for multiple languages) that an
 					 * application can use for tooltip
 					 * text for this feature. (May be
-					 * NULL.) */
-  USHORT	sampleTextNameID;	/* The ‘name’ table name ID that
+					 * nullptr.) */
+  UINT16	sampleTextNameID;	/* The ‘name’ table name ID that
 					 * specifies sample text that
 					 * illustrates the effect of this
-					 * feature. (May be NULL.) */
-  USHORT	numNamedParameters;	/* Number of named parameters. (May
+					 * feature. (May be nullptr.) */
+  UINT16	numNamedParameters;	/* Number of named parameters. (May
 					 * be zero.) */
-  USHORT	firstParamUILabelNameID;/* The first ‘name’ table name ID
+  UINT16	firstParamUILabelNameID;/* The first ‘name’ table name ID
 					 * used to specify strings for
 					 * user-interface labels for the
 					 * feature parameters. (Must be zero
@@ -507,7 +503,7 @@
   { return this+featureParams; }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<Feature>::sanitize_closure_t *closure = NULL) const
+			const Record<Feature>::sanitize_closure_t *closure = nullptr) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
@@ -566,7 +562,7 @@
 typedef RecordListOf<Feature> FeatureList;
 
 
-struct LookupFlag : USHORT
+struct LookupFlag : UINT16
 {
   enum Flags {
     RightToLeft		= 0x0001u,
@@ -612,7 +608,7 @@
     unsigned int flag = lookupFlag;
     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
     {
-      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      const UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
       flag += (markFilteringSet << 16);
     }
     return flag;
@@ -644,7 +640,7 @@
     if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
       markFilteringSet.set (lookup_props >> 16);
     }
     return_trace (true);
@@ -657,18 +653,18 @@
     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      const UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
       if (!markFilteringSet.sanitize (c)) return_trace (false);
     }
     return_trace (true);
   }
 
   private:
-  USHORT	lookupType;		/* Different enumerations for GSUB and GPOS */
-  USHORT	lookupFlag;		/* Lookup qualifiers */
-  ArrayOf<Offset<> >
+  UINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
+  UINT16	lookupFlag;		/* Lookup qualifiers */
+  ArrayOf<Offset16>
 		subTable;		/* Array of SubTables */
-  USHORT	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
+  UINT16	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
 					 * structure. This field is only present if bit
 					 * UseMarkFilteringSet of lookup flags is set. */
   public:
@@ -690,7 +686,7 @@
   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     int i = glyphArray.bsearch (glyph_id);
-    ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
+    static_assert ((((unsigned int) -1) == NOT_COVERED), "");
     return i;
   }
 
@@ -719,10 +715,8 @@
   }
 
   template <typename set_t>
-  inline void add_coverage (set_t *glyphs) const {
-    unsigned int count = glyphArray.len;
-    for (unsigned int i = 0; i < count; i++)
-      glyphs->add (glyphArray[i]);
+  inline bool add_coverage (set_t *glyphs) const {
+    return glyphs->add_sorted_array (glyphArray.array, glyphArray.len);
   }
 
   public:
@@ -741,7 +735,7 @@
   private:
 
   protected:
-  USHORT	coverageFormat;	/* Format identifier--format = 1 */
+  UINT16	coverageFormat;	/* Format identifier--format = 1 */
   SortedArrayOf<GlyphID>
 		glyphArray;	/* Array of GlyphIDs--in numerical order */
   public:
@@ -821,10 +815,12 @@
   }
 
   template <typename set_t>
-  inline void add_coverage (set_t *glyphs) const {
+  inline bool add_coverage (set_t *glyphs) const {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
-      rangeRecord[i].add_coverage (glyphs);
+      if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
+        return false;
+    return true;
   }
 
   public:
@@ -864,7 +860,7 @@
   private:
 
   protected:
-  USHORT	coverageFormat;	/* Format identifier--format = 2 */
+  UINT16	coverageFormat;	/* Format identifier--format = 2 */
   SortedArrayOf<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID. rangeCount entries
@@ -931,17 +927,19 @@
     }
   }
 
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
   template <typename set_t>
-  inline void add_coverage (set_t *glyphs) const {
+  inline bool add_coverage (set_t *glyphs) const {
     switch (u.format) {
-    case 1: u.format1.add_coverage (glyphs); break;
-    case 2: u.format2.add_coverage (glyphs); break;
-    default:                                 break;
+    case 1: return u.format1.add_coverage (glyphs);
+    case 2: return u.format2.add_coverage (glyphs);
+    default:return false;
     }
   }
 
   struct Iter {
-    Iter (void) : format (0) {};
+    Iter (void) : format (0), u () {};
     inline void init (const Coverage &c_) {
       format = c_.u.format;
       switch (format) {
@@ -982,14 +980,14 @@
     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	format2;
     } u;
   };
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   CoverageFormat1	format1;
   CoverageFormat2	format2;
   } u;
@@ -1022,11 +1020,36 @@
   }
 
   template <typename set_t>
-  inline void add_class (set_t *glyphs, unsigned int klass) const {
+  inline bool add_coverage (set_t *glyphs) const {
+    unsigned int start = 0;
     unsigned int count = classValue.len;
     for (unsigned int i = 0; i < count; i++)
+    {
+      if (classValue[i])
+        continue;
+
+      if (start != i)
+	if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
+	  return false;
+
+      start = i + 1;
+    }
+    if (start != count)
+      if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
+	return false;
+
+    return true;
+  }
+
+  template <typename set_t>
+  inline bool add_class (set_t *glyphs, unsigned int klass) const {
+    unsigned int count = classValue.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
       if (classValue[i] == klass)
         glyphs->add (startGlyph + i);
+    }
+    return true;
   }
 
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
@@ -1051,9 +1074,9 @@
   }
 
   protected:
-  USHORT	classFormat;		/* Format identifier--format = 1 */
+  UINT16	classFormat;		/* Format identifier--format = 1 */
   GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
-  ArrayOf<USHORT>
+  ArrayOf<UINT16>
 		classValue;		/* Array of Class Values--one per GlyphID */
   public:
   DEFINE_SIZE_ARRAY (6, classValue);
@@ -1079,11 +1102,25 @@
   }
 
   template <typename set_t>
-  inline void add_class (set_t *glyphs, unsigned int klass) const {
+  inline bool add_coverage (set_t *glyphs) const {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
+      if (rangeRecord[i].value)
+	if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
+	  return false;
+    return true;
+  }
+
+  template <typename set_t>
+  inline bool add_class (set_t *glyphs, unsigned int klass) const {
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+    {
       if (rangeRecord[i].value == klass)
-        rangeRecord[i].add_coverage (glyphs);
+        if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
+	  return false;
+    }
+    return true;
   }
 
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
@@ -1111,7 +1148,7 @@
   }
 
   protected:
-  USHORT	classFormat;	/* Format identifier--format = 2 */
+  UINT16	classFormat;	/* Format identifier--format = 2 */
   SortedArrayOf<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID */
@@ -1141,11 +1178,25 @@
     }
   }
 
-  inline void add_class (hb_set_t *glyphs, unsigned int klass) const {
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename set_t>
+  inline bool add_coverage (set_t *glyphs) const {
     switch (u.format) {
-    case 1: u.format1.add_class (glyphs, klass); return;
-    case 2: u.format2.add_class (glyphs, klass); return;
-    default:return;
+    case 1: return u.format1.add_coverage (glyphs);
+    case 2: return u.format2.add_coverage (glyphs);
+    default:return false;
+    }
+  }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename set_t>
+  inline bool add_class (set_t *glyphs, unsigned int klass) const {
+    switch (u.format) {
+    case 1: return u.format1.add_class (glyphs, klass);
+    case 2: return u.format2.add_class (glyphs, klass);
+    default:return false;
     }
   }
 
@@ -1159,7 +1210,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   ClassDefFormat1	format1;
   ClassDefFormat2	format2;
   } u;
@@ -1244,8 +1295,8 @@
   }
 
   protected:
-  USHORT	axisCount;
-  USHORT	regionCount;
+  UINT16	axisCount;
+  UINT16	regionCount;
   VarRegionAxis	axesZ[VAR];
   public:
   DEFINE_SIZE_ARRAY (4, axesZ);
@@ -1269,13 +1320,13 @@
    unsigned int count = regionIndices.len;
    unsigned int scount = shortCount;
 
-   const BYTE *bytes = &StructAfter<BYTE> (regionIndices);
-   const BYTE *row = bytes + inner * (scount + count);
+   const UINT8 *bytes = &StructAfter<UINT8> (regionIndices);
+   const UINT8 *row = bytes + inner * (scount + count);
 
    float delta = 0.;
    unsigned int i = 0;
 
-   const SHORT *scursor = reinterpret_cast<const SHORT *> (row);
+   const INT16 *scursor = reinterpret_cast<const INT16 *> (row);
    for (; i < scount; i++)
    {
      float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
@@ -1297,15 +1348,15 @@
     return_trace (c->check_struct (this) &&
 		  regionIndices.sanitize(c) &&
 		  shortCount <= regionIndices.len &&
-		  c->check_array (&StructAfter<BYTE> (regionIndices),
+		  c->check_array (&StructAfter<UINT8> (regionIndices),
 				  get_row_size (), itemCount));
   }
 
   protected:
-  USHORT		itemCount;
-  USHORT		shortCount;
-  ArrayOf<USHORT>	regionIndices;
-  BYTE			bytesX[VAR];
+  UINT16		itemCount;
+  UINT16		shortCount;
+  ArrayOf<UINT16>	regionIndices;
+  UINT8			bytesX[VAR];
   public:
   DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
 };
@@ -1341,9 +1392,9 @@
   }
 
   protected:
-  USHORT				format;
+  UINT16				format;
   LOffsetTo<VarRegionList>		regions;
-  OffsetArrayOf<VarData, ULONG>		dataSets;
+  OffsetArrayOf<VarData, UINT32>		dataSets;
   public:
   DEFINE_SIZE_ARRAY (8, dataSets);
 };
@@ -1370,8 +1421,8 @@
   }
 
   protected:
-  USHORT	format;		/* Format identifier--format = 1 */
-  USHORT	axisIndex;
+  UINT16	format;		/* Format identifier--format = 1 */
+  UINT16	axisIndex;
   F2DOT14	filterRangeMinValue;
   F2DOT14	filterRangeMaxValue;
   public:
@@ -1400,7 +1451,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   ConditionFormat1	format1;
   } u;
   public:
@@ -1425,7 +1476,7 @@
   }
 
   protected:
-  OffsetArrayOf<Condition, ULONG> conditions;
+  OffsetArrayOf<Condition, UINT32> conditions;
   public:
   DEFINE_SIZE_ARRAY (2, conditions);
 };
@@ -1441,7 +1492,7 @@
   }
 
   protected:
-  USHORT		featureIndex;
+  UINT16		featureIndex;
   LOffsetTo<Feature>	feature;
   public:
   DEFINE_SIZE_STATIC (6);
@@ -1458,7 +1509,7 @@
       if (record.featureIndex == feature_index)
 	return &(this+record.feature);
     }
-    return NULL;
+    return nullptr;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -1561,8 +1612,8 @@
   inline unsigned int get_size (void) const
   {
     unsigned int f = deltaFormat;
-    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
-    return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
+    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * UINT16::static_size;
+    return UINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -1607,14 +1658,14 @@
   }
 
   protected:
-  USHORT	startSize;		/* Smallest size to correct--in ppem */
-  USHORT	endSize;		/* Largest size to correct--in ppem */
-  USHORT	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
+  UINT16	startSize;		/* Smallest size to correct--in ppem */
+  UINT16	endSize;		/* Largest size to correct--in ppem */
+  UINT16	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
 					 * 1	Signed 2-bit value, 8 values per uint16
 					 * 2	Signed 4-bit value, 4 values per uint16
 					 * 3	Signed 8-bit value, 2 values per uint16
 					 */
-  USHORT	deltaValue[VAR];	/* Array of compressed data */
+  UINT16	deltaValue[VAR];	/* Array of compressed data */
   public:
   DEFINE_SIZE_ARRAY (6, deltaValue);
 };
@@ -1645,9 +1696,9 @@
   }
 
   protected:
-  USHORT	outerIndex;
-  USHORT	innerIndex;
-  USHORT	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
+  UINT16	outerIndex;
+  UINT16	innerIndex;
+  UINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
   public:
   DEFINE_SIZE_STATIC (6);
 };
@@ -1655,10 +1706,10 @@
 struct DeviceHeader
 {
   protected:
-  USHORT		reserved1;
-  USHORT		reserved2;
+  UINT16		reserved1;
+  UINT16		reserved2;
   public:
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   public:
   DEFINE_SIZE_STATIC (6);
 };
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 552df0f..eed46dd 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -41,7 +41,7 @@
  * Attachment List Table
  */
 
-typedef ArrayOf<USHORT> AttachPoint;	/* Array of contour point indices--in
+typedef ArrayOf<UINT16> AttachPoint;	/* Array of contour point indices--in
 					 * increasing numerical order */
 
 struct AttachList
@@ -62,7 +62,7 @@
     const AttachPoint &points = this+attachPoint[index];
 
     if (point_count) {
-      const USHORT *array = points.sub_array (start_offset, point_count);
+      const UINT16 *array = points.sub_array (start_offset, point_count);
       unsigned int count = *point_count;
       for (unsigned int i = 0; i < count; i++)
 	point_array[i] = array[i];
@@ -109,8 +109,8 @@
   }
 
   protected:
-  USHORT	caretValueFormat;	/* Format identifier--format = 1 */
-  SHORT		coordinate;		/* X or Y value, in design units */
+  UINT16	caretValueFormat;	/* Format identifier--format = 1 */
+  INT16		coordinate;		/* X or Y value, in design units */
   public:
   DEFINE_SIZE_STATIC (4);
 };
@@ -136,8 +136,8 @@
   }
 
   protected:
-  USHORT	caretValueFormat;	/* Format identifier--format = 2 */
-  USHORT	caretValuePoint;	/* Contour point index on glyph */
+  UINT16	caretValueFormat;	/* Format identifier--format = 2 */
+  UINT16	caretValuePoint;	/* Contour point index on glyph */
   public:
   DEFINE_SIZE_STATIC (4);
 };
@@ -160,8 +160,8 @@
   }
 
   protected:
-  USHORT	caretValueFormat;	/* Format identifier--format = 3 */
-  SHORT		coordinate;		/* X or Y value, in design units */
+  UINT16	caretValueFormat;	/* Format identifier--format = 3 */
+  INT16		coordinate;		/* X or Y value, in design units */
   OffsetTo<Device>
 		deviceTable;		/* Offset to Device table for X or Y
 					 * value--from beginning of CaretValue
@@ -199,7 +199,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   CaretValueFormat1	format1;
   CaretValueFormat2	format2;
   CaretValueFormat3	format3;
@@ -294,7 +294,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   ArrayOf<LOffsetTo<Coverage> >
 		coverage;		/* Array of long offsets to mark set
 					 * coverage tables */
@@ -324,7 +324,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MarkGlyphSetsFormat1	format1;
   } u;
   public:
@@ -404,9 +404,9 @@
   {
     unsigned int klass = get_glyph_class (glyph);
 
-    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs);
-    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures);
-    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks);
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
 
     switch (klass) {
     default:			return 0;
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 952fd60..b344d79 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -51,11 +51,11 @@
 
 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
 
-typedef USHORT Value;
+typedef UINT16 Value;
 
 typedef Value ValueRecord[VAR];
 
-struct ValueFormat : USHORT
+struct ValueFormat : UINT16
 {
   enum Flags {
     xPlacement	= 0x0001u,	/* Includes horizontal adjustment for placement */
@@ -74,14 +74,14 @@
 
 /* All fields are options.  Only those available advance the value pointer. */
 #if 0
-  SHORT		xPlacement;		/* Horizontal adjustment for
+  INT16		xPlacement;		/* Horizontal adjustment for
 					 * placement--in design units */
-  SHORT		yPlacement;		/* Vertical adjustment for
+  INT16		yPlacement;		/* Vertical adjustment for
 					 * placement--in design units */
-  SHORT		xAdvance;		/* Horizontal adjustment for
+  INT16		xAdvance;		/* Horizontal adjustment for
 					 * advance--in design units (only used
 					 * for horizontal writing) */
-  SHORT		yAdvance;		/* Vertical adjustment for advance--in
+  INT16		yAdvance;		/* Vertical adjustment for advance--in
 					 * design units (only used for vertical
 					 * writing) */
   Offset	xPlaDevice;		/* Offset to Device table for
@@ -178,8 +178,8 @@
   static inline const OffsetTo<Device>& get_device (const Value* value)
   { return *CastP<OffsetTo<Device> > (value); }
 
-  static inline const SHORT& get_short (const Value* value)
-  { return *CastP<SHORT> (value); }
+  static inline const INT16& get_short (const Value* value)
+  { return *CastP<INT16> (value); }
 
   public:
 
@@ -247,9 +247,9 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
-  SHORT		xCoordinate;		/* Horizontal value--in design units */
-  SHORT		yCoordinate;		/* Vertical value--in design units */
+  UINT16	format;			/* Format identifier--format = 1 */
+  INT16		xCoordinate;		/* Horizontal value--in design units */
+  INT16		yCoordinate;		/* Vertical value--in design units */
   public:
   DEFINE_SIZE_STATIC (6);
 };
@@ -278,10 +278,10 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
-  SHORT		xCoordinate;		/* Horizontal value--in design units */
-  SHORT		yCoordinate;		/* Vertical value--in design units */
-  USHORT	anchorPoint;		/* Index to glyph contour point */
+  UINT16	format;			/* Format identifier--format = 2 */
+  INT16		xCoordinate;		/* Horizontal value--in design units */
+  INT16		yCoordinate;		/* Vertical value--in design units */
+  UINT16	anchorPoint;		/* Index to glyph contour point */
   public:
   DEFINE_SIZE_STATIC (8);
 };
@@ -308,9 +308,9 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 3 */
-  SHORT		xCoordinate;		/* Horizontal value--in design units */
-  SHORT		yCoordinate;		/* Vertical value--in design units */
+  UINT16	format;			/* Format identifier--format = 3 */
+  INT16		xCoordinate;		/* Horizontal value--in design units */
+  INT16		yCoordinate;		/* Vertical value--in design units */
   OffsetTo<Device>
 		xDeviceTable;		/* Offset to Device table for X
 					 * coordinate-- from beginning of
@@ -351,7 +351,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   AnchorFormat1		format1;
   AnchorFormat2		format2;
   AnchorFormat3		format3;
@@ -382,7 +382,7 @@
     return_trace (true);
   }
 
-  USHORT	rows;			/* Number of rows */
+  UINT16	rows;			/* Number of rows */
   protected:
   OffsetTo<Anchor>
 		matrixZ[VAR];		/* Matrix of offsets to Anchor tables--
@@ -403,7 +403,7 @@
   }
 
   protected:
-  USHORT	klass;			/* Class defined for this mark */
+  UINT16	klass;			/* Class defined for this mark */
   OffsetTo<Anchor>
 		markAnchor;		/* Offset to Anchor table--from
 					 * beginning of MarkArray table */
@@ -432,6 +432,7 @@
 
     hb_position_t mark_x, mark_y, base_x, base_y;
 
+    buffer->unsafe_to_break (glyph_pos, buffer->idx);
     mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
     glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
@@ -461,7 +462,7 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+coverage).add_coverage (c->input);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
@@ -491,7 +492,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
@@ -509,7 +510,7 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+coverage).add_coverage (c->input);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
@@ -543,13 +544,13 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
   ValueFormat	valueFormat;		/* Defines the types of data in the
 					 * ValueRecord */
-  USHORT	valueCount;		/* Number of ValueRecords */
+  UINT16	valueCount;		/* Number of ValueRecords */
   ValueRecord	values;			/* Array of ValueRecords--positioning
 					 * values applied to glyphs */
   public:
@@ -572,7 +573,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   SinglePosFormat1	format1;
   SinglePosFormat2	format2;
   } u;
@@ -603,15 +604,10 @@
     TRACE_COLLECT_GLYPHS (this);
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+    unsigned int record_size = UINT16::static_size * (1 + len1 + len2);
 
     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      c->input->add (record->secondGlyph);
-      record = &StructAtOffset<PairValueRecord> (record, record_size);
-    }
+    c->input->add_array (&record->secondGlyph, len, record_size);
   }
 
   inline bool apply (hb_apply_context_t *c,
@@ -622,7 +618,7 @@
     hb_buffer_t *buffer = c->buffer;
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+    unsigned int record_size = UINT16::static_size * (1 + len1 + len2);
 
     const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
     unsigned int count = len;
@@ -643,6 +639,7 @@
         min = mid + 1;
       else
       {
+        buffer->unsafe_to_break (buffer->idx, pos + 1);
 	valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
 	valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
 	if (len2)
@@ -666,7 +663,7 @@
   {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
-       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false);
+       && c->check_array (arrayZ, UINT16::static_size * closure->stride, len))) return_trace (false);
 
     unsigned int count = len;
     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
@@ -675,8 +672,8 @@
   }
 
   protected:
-  USHORT	len;			/* Number of PairValueRecords */
-  USHORT	arrayZ[VAR];		/* Array of PairValueRecords--ordered
+  UINT16	len;			/* Number of PairValueRecords */
+  UINT16	arrayZ[VAR];		/* Array of PairValueRecords--ordered
 					 * by GlyphID of the second glyph */
   public:
   DEFINE_SIZE_ARRAY (2, arrayZ);
@@ -687,7 +684,7 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+coverage).add_coverage (c->input);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     unsigned int count = pairSet.len;
     for (unsigned int i = 0; i < count; i++)
       (this+pairSet[i]).collect_glyphs (c, valueFormat);
@@ -731,7 +728,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
@@ -753,17 +750,8 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+coverage).add_coverage (c->input);
-
-    unsigned int count1 = class1Count;
-    const ClassDef &klass1 = this+classDef1;
-    for (unsigned int i = 0; i < count1; i++)
-      klass1.add_class (c->input, i);
-
-    unsigned int count2 = class2Count;
-    const ClassDef &klass2 = this+classDef2;
-    for (unsigned int i = 0; i < count2; i++)
-      klass2.add_class (c->input, i);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
+    if (unlikely (!(this+classDef2).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
@@ -790,6 +778,7 @@
     unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
 
+    buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
     valueFormat1.apply_value (c, this, v, buffer->cur_pos());
     valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
@@ -820,7 +809,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
@@ -838,9 +827,9 @@
 		classDef2;		/* Offset to ClassDef table--from
 					 * beginning of PairPos subtable--for
 					 * the second glyph of the pair */
-  USHORT	class1Count;		/* Number of classes in ClassDef1
+  UINT16	class1Count;		/* Number of classes in ClassDef1
 					 * table--includes Class0 */
-  USHORT	class2Count;		/* Number of classes in ClassDef2
+  UINT16	class2Count;		/* Number of classes in ClassDef2
 					 * table--includes Class0 */
   ValueRecord	values;			/* Matrix of value pairs:
 					 * class1-major, class2-minor,
@@ -865,7 +854,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   PairPosFormat1	format1;
   PairPosFormat2	format2;
   } u;
@@ -903,7 +892,7 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+coverage).add_coverage (c->input);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
@@ -929,6 +918,7 @@
     unsigned int i = buffer->idx;
     unsigned int j = skippy_iter.idx;
 
+    buffer->unsafe_to_break (i, j);
     hb_position_t entry_x, entry_y, exit_x, exit_y;
     (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
     (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
@@ -1018,7 +1008,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
@@ -1044,7 +1034,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   CursivePosFormat1	format1;
   } u;
 };
@@ -1060,8 +1050,8 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+markCoverage).add_coverage (c->input);
-    (this+baseCoverage).add_coverage (c->input);
+    if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
+    if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1083,7 +1073,9 @@
     do {
       if (!skippy_iter.prev ()) return_trace (false);
       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
-      if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
+      if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
+	  0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]))
+	break;
       skippy_iter.reject ();
     } while (1);
 
@@ -1107,14 +1099,14 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		markCoverage;		/* Offset to MarkCoverage table--from
 					 * beginning of MarkBasePos subtable */
   OffsetTo<Coverage>
 		baseCoverage;		/* Offset to BaseCoverage table--from
 					 * beginning of MarkBasePos subtable */
-  USHORT	classCount;		/* Number of classes defined for marks */
+  UINT16	classCount;		/* Number of classes defined for marks */
   OffsetTo<MarkArray>
 		markArray;		/* Offset to MarkArray table--from
 					 * beginning of MarkBasePos subtable */
@@ -1140,7 +1132,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MarkBasePosFormat1	format1;
   } u;
 };
@@ -1161,8 +1153,8 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+markCoverage).add_coverage (c->input);
-    (this+ligatureCoverage).add_coverage (c->input);
+    if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
+    if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1224,7 +1216,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		markCoverage;		/* Offset to Mark Coverage table--from
 					 * beginning of MarkLigPos subtable */
@@ -1232,7 +1224,7 @@
 		ligatureCoverage;	/* Offset to Ligature Coverage
 					 * table--from beginning of MarkLigPos
 					 * subtable */
-  USHORT	classCount;		/* Number of defined mark classes */
+  UINT16	classCount;		/* Number of defined mark classes */
   OffsetTo<MarkArray>
 		markArray;		/* Offset to MarkArray table--from
 					 * beginning of MarkLigPos subtable */
@@ -1258,7 +1250,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MarkLigPosFormat1	format1;
   } u;
 };
@@ -1274,8 +1266,8 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+mark1Coverage).add_coverage (c->input);
-    (this+mark2Coverage).add_coverage (c->input);
+    if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return;
+    if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return;
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1338,7 +1330,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		mark1Coverage;		/* Offset to Combining Mark1 Coverage
 					 * table--from beginning of MarkMarkPos
@@ -1347,7 +1339,7 @@
 		mark2Coverage;		/* Offset to Combining Mark2 Coverage
 					 * table--from beginning of MarkMarkPos
 					 * subtable */
-  USHORT	classCount;		/* Number of defined mark classes */
+  UINT16	classCount;		/* Number of defined mark classes */
   OffsetTo<MarkArray>
 		mark1Array;		/* Offset to Mark1Array table--from
 					 * beginning of MarkMarkPos subtable */
@@ -1373,7 +1365,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MarkMarkPosFormat1	format1;
   } u;
 };
@@ -1432,7 +1424,7 @@
 
   protected:
   union {
-  USHORT		sub_format;
+  UINT16		sub_format;
   SinglePos		single;
   PairPos		pair;
   CursivePos		cursive;
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 66fcb3f..0b09c4e 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -44,7 +44,7 @@
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       /* TODO Switch to range-based API to work around malicious fonts.
-       * https://github.com/behdad/harfbuzz/issues/363 */
+       * https://github.com/harfbuzz/harfbuzz/issues/363 */
       hb_codepoint_t glyph_id = iter.get_glyph ();
       if (c->glyphs->has (glyph_id))
 	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
@@ -54,13 +54,13 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       /* TODO Switch to range-based API to work around malicious fonts.
-       * https://github.com/behdad/harfbuzz/issues/363 */
+       * https://github.com/harfbuzz/harfbuzz/issues/363 */
       hb_codepoint_t glyph_id = iter.get_glyph ();
-      c->input->add (glyph_id);
       c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
     }
   }
@@ -110,11 +110,11 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
+  INT16		deltaGlyphID;		/* Add to original GlyphID to get
 					 * substitute GlyphID */
   public:
   DEFINE_SIZE_STATIC (6);
@@ -130,7 +130,7 @@
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       if (c->glyphs->has (iter.get_glyph ()))
 	c->glyphs->add (substitute[iter.get_coverage ()]);
     }
@@ -139,13 +139,13 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     Coverage::Iter iter;
     unsigned int count = substitute.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
-      c->input->add (iter.get_glyph ());
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       c->output->add (substitute[iter.get_coverage ()]);
     }
   }
@@ -195,7 +195,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
@@ -249,7 +249,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   SingleSubstFormat1	format1;
   SingleSubstFormat2	format2;
   } u;
@@ -269,9 +269,7 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    unsigned int count = substitute.len;
-    for (unsigned int i = 0; i < count; i++)
-      c->output->add (substitute[i]);
+    c->output->add_array (substitute.array, substitute.len);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -287,7 +285,7 @@
       return_trace (true);
     }
     /* Spec disallows this, but Uniscribe allows it.
-     * https://github.com/behdad/harfbuzz/issues/253 */
+     * https://github.com/harfbuzz/harfbuzz/issues/253 */
     else if (unlikely (count == 0))
     {
       c->buffer->delete_glyph ();
@@ -339,7 +337,7 @@
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        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);
     }
@@ -348,7 +346,7 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+coverage).add_coverage (c->input);
+    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);
@@ -400,7 +398,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
@@ -442,7 +440,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   MultipleSubstFormat1	format1;
   } u;
 };
@@ -461,7 +459,7 @@
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       if (c->glyphs->has (iter.get_glyph ())) {
 	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
 	unsigned int count = alt_set.len;
@@ -474,17 +472,15 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     Coverage::Iter iter;
     unsigned int count = alternateSet.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
-      c->input->add (iter.get_glyph ());
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
-      unsigned int count = alt_set.len;
-      for (unsigned int i = 0; i < count; i++)
-	c->output->add (alt_set[i]);
+      c->output->add_array (alt_set.array, alt_set.len);
     }
   }
 
@@ -552,7 +548,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
@@ -594,7 +590,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   AlternateSubstFormat1	format1;
   } u;
 };
@@ -615,9 +611,7 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    unsigned int count = component.len;
-    for (unsigned int i = 1; i < count; i++)
-      c->input->add (component[i]);
+    c->input->add_array (component.array, component.len ? component.len - 1 : 0);
     c->output->add (ligGlyph);
   }
 
@@ -658,7 +652,7 @@
     if (likely (!match_input (c, count,
 			      &component[1],
 			      match_glyph,
-			      NULL,
+			      nullptr,
 			      &match_length,
 			      match_positions,
 			      &is_mark_ligature,
@@ -792,7 +786,7 @@
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        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);
     }
@@ -801,13 +795,13 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     Coverage::Iter iter;
     unsigned int count = ligatureSet.len;
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
-      c->input->add (iter.get_glyph ());
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
     }
   }
@@ -868,7 +862,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
@@ -918,7 +912,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   LigatureSubstFormat1	format1;
   } u;
 };
@@ -961,7 +955,7 @@
     for (iter.init (this+coverage); iter.more (); iter.next ())
     {
       if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       if (c->glyphs->has (iter.get_glyph ()))
 	c->glyphs->add (substitute[iter.get_coverage ()]);
     }
@@ -970,25 +964,22 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
 
     unsigned int count;
 
-    (this+coverage).add_coverage (c->input);
-
     count = backtrack.len;
     for (unsigned int i = 0; i < count; i++)
-      (this+backtrack[i]).add_coverage (c->before);
+      if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return;
 
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     count = lookahead.len;
     for (unsigned int i = 0; i < count; i++)
-      (this+lookahead[i]).add_coverage (c->after);
+      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
 
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     count = substitute.len;
-    for (unsigned int i = 0; i < count; i++)
-      c->output->add (substitute[i]);
+    c->output->add_array (substitute.array, substitute.len);
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1014,14 +1005,17 @@
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
 
+  unsigned int start_index = 0, end_index = 0;
     if (match_backtrack (c,
-			 backtrack.len, (USHORT *) backtrack.array,
-			 match_coverage, this) &&
-        match_lookahead (c,
-			 lookahead.len, (USHORT *) lookahead.array,
+			 backtrack.len, (UINT16 *) backtrack.array,
 			 match_coverage, this,
-			 1))
+			 &start_index) &&
+        match_lookahead (c,
+			 lookahead.len, (UINT16 *) lookahead.array,
+			 match_coverage, this,
+			 1, &end_index))
     {
+      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
       c->replace_glyph_inplace (substitute[index]);
       /* Note: We DON'T decrease buffer->idx.  The main loop does it
        * for us.  This is useful for preventing surprises if someone
@@ -1045,7 +1039,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
@@ -1079,7 +1073,7 @@
 
   protected:
   union {
-  USHORT				format;		/* Format identifier */
+  UINT16				format;		/* Format identifier */
   ReverseChainSingleSubstFormat1	format1;
   } u;
 };
@@ -1125,7 +1119,7 @@
 
   protected:
   union {
-  USHORT			sub_format;
+  UINT16			sub_format;
   SingleSubst			single;
   MultipleSubst			multiple;
   AlternateSubst		alternate;
@@ -1277,9 +1271,11 @@
     if (unlikely (get_type () == SubstLookupSubTable::Extension))
     {
       /* The spec says all subtables of an Extension lookup should
-       * have the same type.  This is specially important if one has
-       * a reverse type! */
+       * have the same type, which shall not be the Extension type
+       * itself. This is specially important if one has a reverse type! */
       unsigned int type = get_subtable (0).u.extension.get_type ();
+      if (unlikely (type == SubstLookupSubTable::Extension))
+	return_trace (false);
       unsigned int count = get_subtable_count ();
       for (unsigned int i = 1; i < count; i++)
         if (get_subtable (i).u.extension.get_type () != type)
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index b7a0122..b08a591 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -29,6 +29,8 @@
 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
 
+#include "hb-private.hh"
+#include "hb-debug.hh"
 #include "hb-buffer-private.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-set-private.hh"
@@ -37,15 +39,6 @@
 namespace OT {
 
 
-#ifndef HB_DEBUG_CLOSURE
-#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
-#endif
-
-#define TRACE_CLOSURE(this) \
-	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
-	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "");
-
 struct hb_closure_context_t :
        hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
 {
@@ -77,7 +70,7 @@
 		        unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
 			  face (face_),
 			  glyphs (glyphs_),
-			  recurse_func (NULL),
+			  recurse_func (nullptr),
 			  nesting_level_left (nesting_level_left_),
 			  debug_depth (0) {}
 
@@ -85,16 +78,6 @@
 };
 
 
-
-#ifndef HB_DEBUG_WOULD_APPLY
-#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
-#endif
-
-#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);
-
 struct hb_would_apply_context_t :
        hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
 {
@@ -122,16 +105,6 @@
 };
 
 
-
-#ifndef HB_DEBUG_COLLECT_GLYPHS
-#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
-#endif
-
-#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, \
-	 "");
-
 struct hb_collect_glyphs_context_t :
        hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
 {
@@ -146,7 +119,7 @@
     if (unlikely (nesting_level_left == 0 || !recurse_func))
       return default_return_value ();
 
-    /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
+    /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
      * past the previous check.  For GSUB, we only want to collect the output
      * glyphs in the recursion.  If output is not requested, we can go home now.
      *
@@ -160,7 +133,7 @@
       return HB_VOID;
 
     /* Return if new lookup was recursed to before. */
-    if (recursed_lookups.has (lookup_index))
+    if (recursed_lookups->has (lookup_index))
       return HB_VOID;
 
     hb_set_t *old_before = before;
@@ -176,7 +149,7 @@
     input  = old_input;
     after  = old_after;
 
-    recursed_lookups.add (lookup_index);
+    recursed_lookups->add (lookup_index);
 
     return HB_VOID;
   }
@@ -187,31 +160,31 @@
   hb_set_t *after;
   hb_set_t *output;
   recurse_func_t recurse_func;
-  hb_set_t recursed_lookups;
+  hb_set_t *recursed_lookups;
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
   hb_collect_glyphs_context_t (hb_face_t *face_,
-			       hb_set_t  *glyphs_before, /* OUT. May be NULL */
-			       hb_set_t  *glyphs_input,  /* OUT. May be NULL */
-			       hb_set_t  *glyphs_after,  /* OUT. May be NULL */
-			       hb_set_t  *glyphs_output, /* OUT. May be NULL */
+			       hb_set_t  *glyphs_before, /* OUT. May be nullptr */
+			       hb_set_t  *glyphs_input,  /* OUT. May be nullptr */
+			       hb_set_t  *glyphs_after,  /* OUT. May be nullptr */
+			       hb_set_t  *glyphs_output, /* OUT. May be nullptr */
 			       unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
 			      face (face_),
 			      before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
 			      input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
 			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
 			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
-			      recurse_func (NULL),
-			      recursed_lookups (),
+			      recurse_func (nullptr),
+			      recursed_lookups (nullptr),
 			      nesting_level_left (nesting_level_left_),
 			      debug_depth (0)
   {
-    recursed_lookups.init ();
+    recursed_lookups = hb_set_create ();
   }
   ~hb_collect_glyphs_context_t (void)
   {
-    recursed_lookups.fini ();
+    hb_set_destroy (recursed_lookups);
   }
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
@@ -219,10 +192,6 @@
 
 
 
-#ifndef HB_DEBUG_GET_COVERAGE
-#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
-#endif
-
 /* XXX Can we remove this? */
 
 template <typename set_t>
@@ -249,17 +218,6 @@
 };
 
 
-
-#ifndef HB_DEBUG_APPLY
-#define HB_DEBUG_APPLY (HB_DEBUG+0)
-#endif
-
-#define TRACE_APPLY(this) \
-	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
-	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "idx %d gid %u lookup %d", \
-	 c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index);
-
 struct hb_apply_context_t :
        hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
 {
@@ -273,10 +231,10 @@
 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
 	     syllable arg1(0),
 #undef arg1
-	     match_func (NULL),
-	     match_data (NULL) {};
+	     match_func (nullptr),
+	     match_data (nullptr) {};
 
-    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
 
     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
     inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
@@ -294,7 +252,7 @@
     };
 
     inline may_match_t may_match (const hb_glyph_info_t &info,
-				  const USHORT          *glyph_data) const
+				  const UINT16          *glyph_data) const
     {
       if (!(info.mask & mask) ||
 	  (syllable && syllable != info.syllable ()))
@@ -319,7 +277,7 @@
       if (!c->check_glyph_property (&info, lookup_props))
 	return SKIP_YES;
 
-      if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_fvs (&info) &&
+      if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
 		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
 		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
 	return SKIP_MAYBE;
@@ -342,13 +300,13 @@
     inline void init (hb_apply_context_t *c_, bool context_match = false)
     {
       c = c_;
-      match_glyph_data = NULL,
-      matcher.set_match_func (NULL, NULL);
+      match_glyph_data = nullptr;
+      matcher.set_match_func (nullptr, nullptr);
       matcher.set_lookup_props (c->lookup_props);
       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
-      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+      matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
-      matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
+      matcher.set_ignore_zwj  (c->table_index == 1 || (context_match || c->auto_zwj));
       matcher.set_mask (context_match ? -1 : c->lookup_mask);
     }
     inline void set_lookup_props (unsigned int lookup_props)
@@ -357,7 +315,7 @@
     }
     inline void set_match_func (matcher_t::match_func_t match_func_,
 				const void *match_data_,
-				const USHORT glyph_data[])
+				const UINT16 glyph_data[])
     {
       matcher.set_match_func (match_func_, match_data_);
       match_glyph_data = glyph_data;
@@ -374,6 +332,13 @@
 
     inline void reject (void) { num_items++; match_glyph_data--; }
 
+    inline matcher_t::may_skip_t
+    may_skip (const hb_apply_context_t *c,
+	      const hb_glyph_info_t    &info) const
+    {
+      return matcher.may_skip (c, info);
+    }
+
     inline bool next (void)
     {
       assert (num_items > 0);
@@ -433,7 +398,7 @@
     protected:
     hb_apply_context_t *c;
     matcher_t matcher;
-    const USHORT *match_glyph_data;
+    const UINT16 *match_glyph_data;
 
     unsigned int num_items;
     unsigned int end;
@@ -448,7 +413,7 @@
   bool stop_sublookup_iteration (return_t r) const { return r; }
   return_t recurse (unsigned int lookup_index)
   {
-    if (unlikely (nesting_level_left == 0 || !recurse_func))
+    if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
       return default_return_value ();
 
     nesting_level_left--;
@@ -457,45 +422,50 @@
     return ret;
   }
 
-  unsigned int table_index; /* GSUB/GPOS */
+  skipping_iterator_t iter_input, iter_context;
+
   hb_font_t *font;
   hb_face_t *face;
   hb_buffer_t *buffer;
+  recurse_func_t recurse_func;
+  const GDEF &gdef;
+  const VariationStore &var_store;
+
   hb_direction_t direction;
   hb_mask_t lookup_mask;
-  bool auto_zwj;
-  recurse_func_t recurse_func;
-  unsigned int nesting_level_left;
-  unsigned int lookup_props;
-  const GDEF &gdef;
-  bool has_glyph_classes;
-  const VariationStore &var_store;
-  skipping_iterator_t iter_input, iter_context;
+  unsigned int table_index; /* GSUB/GPOS */
   unsigned int lookup_index;
+  unsigned int lookup_props;
+  unsigned int nesting_level_left;
   unsigned int debug_depth;
 
+  bool auto_zwnj;
+  bool auto_zwj;
+  bool has_glyph_classes;
+
 
   hb_apply_context_t (unsigned int table_index_,
 		      hb_font_t *font_,
 		      hb_buffer_t *buffer_) :
-			table_index (table_index_),
+			iter_input (), iter_context (),
 			font (font_), face (font->face), buffer (buffer_),
+			recurse_func (nullptr),
+			gdef (*hb_ot_layout_from_face (face)->gdef),
+			var_store (gdef.get_var_store ()),
 			direction (buffer_->props.direction),
 			lookup_mask (1),
-			auto_zwj (true),
-			recurse_func (NULL),
-			nesting_level_left (HB_MAX_NESTING_LEVEL),
-			lookup_props (0),
-			gdef (*hb_ot_layout_from_face (face)->gdef),
-			has_glyph_classes (gdef.has_glyph_classes ()),
-			var_store (gdef.get_var_store ()),
-			iter_input (),
-			iter_context (),
+			table_index (table_index_),
 			lookup_index ((unsigned int) -1),
-			debug_depth (0) {}
+			lookup_props (0),
+			nesting_level_left (HB_MAX_NESTING_LEVEL),
+			debug_depth (0),
+			auto_zwnj (true),
+			auto_zwj (true),
+			has_glyph_classes (gdef.has_glyph_classes ()) {}
 
   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
+  inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
   inline void set_lookup_props (unsigned int lookup_props_)
@@ -598,9 +568,9 @@
 
 
 
-typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
-typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
-typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+typedef bool (*intersects_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
+typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
 
 struct ContextClosureFuncs
 {
@@ -616,16 +586,16 @@
 };
 
 
-static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
 }
-static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline bool intersects_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.intersects_class (glyphs, value);
 }
-static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline bool intersects_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).intersects (glyphs);
@@ -633,7 +603,7 @@
 
 static inline bool intersects_array (hb_closure_context_t *c,
 				     unsigned int count,
-				     const USHORT values[],
+				     const UINT16 values[],
 				     intersects_func_t intersects_func,
 				     const void *intersects_data)
 {
@@ -644,16 +614,16 @@
 }
 
 
-static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+static inline void collect_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
 {
   glyphs->add (value);
 }
-static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline void collect_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   class_def.add_class (glyphs, value);
 }
-static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+static inline void collect_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   (data+coverage).add_coverage (glyphs);
@@ -661,7 +631,7 @@
 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
 				  hb_set_t *glyphs,
 				  unsigned int count,
-				  const USHORT values[],
+				  const UINT16 values[],
 				  collect_glyphs_func_t collect_func,
 				  const void *collect_data)
 {
@@ -670,16 +640,16 @@
 }
 
 
-static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
+static inline bool match_glyph (hb_codepoint_t glyph_id, const UINT16 &value, const void *data HB_UNUSED)
 {
   return glyph_id == value;
 }
-static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+static inline bool match_class (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.get_class (glyph_id) == value;
 }
-static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+static inline bool match_coverage (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
@@ -687,7 +657,7 @@
 
 static inline bool would_match_input (hb_would_apply_context_t *c,
 				      unsigned int count, /* Including the first glyph (not matched) */
-				      const USHORT input[], /* Array of input values--start with second glyph */
+				      const UINT16 input[], /* Array of input values--start with second glyph */
 				      match_func_t match_func,
 				      const void *match_data)
 {
@@ -702,15 +672,15 @@
 }
 static inline bool match_input (hb_apply_context_t *c,
 				unsigned int count, /* Including the first glyph (not matched) */
-				const USHORT input[], /* Array of input values--start with second glyph */
+				const UINT16 input[], /* Array of input values--start with second glyph */
 				match_func_t match_func,
 				const void *match_data,
 				unsigned int *end_offset,
 				unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
-				bool *p_is_mark_ligature = NULL,
-				unsigned int *p_total_component_count = NULL)
+				bool *p_is_mark_ligature = nullptr,
+				unsigned int *p_total_component_count = nullptr)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
 
@@ -731,11 +701,17 @@
    * - Ligatures cannot be formed across glyphs attached to different components
    *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
    *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
-   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
-   *   There is an exception to this: If a ligature tries ligating with marks that
-   *   belong to it itself, go ahead, assuming that the font designer knows what
-   *   they are doing (otherwise it can break Indic stuff when a matra wants to
-   *   ligate with a conjunct...)
+   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
+   *   There are a couple of exceptions to this:
+   *
+   *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
+   *     assuming that the font designer knows what they are doing (otherwise it can
+   *     break Indic stuff when a matra wants to ligate with a conjunct,
+   *
+   *   o If two marks want to ligate and they belong to different components of the
+   *     same ligature glyph, and said ligature glyph is to be ignored according to
+   *     mark-filtering rules, then allow.
+   *     https://github.com/harfbuzz/harfbuzz/issues/545
    */
 
   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
@@ -746,6 +722,12 @@
   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
 
+  enum {
+    LIGBASE_NOT_CHECKED,
+    LIGBASE_MAY_NOT_SKIP,
+    LIGBASE_MAY_SKIP
+  } ligbase = LIGBASE_NOT_CHECKED;
+
   match_positions[0] = buffer->idx;
   for (unsigned int i = 1; i < count; i++)
   {
@@ -756,13 +738,43 @@
     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
 
-    if (first_lig_id && first_lig_comp) {
+    if (first_lig_id && first_lig_comp)
+    {
       /* If first component was attached to a previous ligature component,
        * all subsequent components should be attached to the same ligature
-       * component, otherwise we shouldn't ligate them. */
+       * component, otherwise we shouldn't ligate them... */
       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
-	return_trace (false);
-    } else {
+      {
+        /* ...unless, we are attached to a base ligature and that base
+	 * ligature is ignorable. */
+        if (ligbase == LIGBASE_NOT_CHECKED)
+	{
+	  bool found = false;
+	  const hb_glyph_info_t *out = buffer->out_info;
+	  unsigned int j = buffer->out_len;
+	  while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
+	  {
+	    if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
+	    {
+	      j--;
+	      found = true;
+	      break;
+	    }
+	    j--;
+	  }
+
+	  if (found && skippy_iter.may_skip (c, out[j]) == hb_apply_context_t::matcher_t::SKIP_YES)
+	    ligbase = LIGBASE_MAY_SKIP;
+	  else
+	    ligbase = LIGBASE_MAY_NOT_SKIP;
+	}
+
+        if (ligbase == LIGBASE_MAY_NOT_SKIP)
+	  return_trace (false);
+      }
+    }
+    else
+    {
       /* If first component was NOT attached to a previous ligature component,
        * all subsequent components should also NOT be attached to any ligature
        * component, unless they are attached to the first component itself! */
@@ -792,7 +804,7 @@
 				 bool is_mark_ligature,
 				 unsigned int total_component_count)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_buffer_t *buffer = c->buffer;
 
@@ -884,11 +896,12 @@
 
 static inline bool match_backtrack (hb_apply_context_t *c,
 				    unsigned int count,
-				    const USHORT backtrack[],
+				    const UINT16 backtrack[],
 				    match_func_t match_func,
-				    const void *match_data)
+				    const void *match_data,
+				    unsigned int *match_start)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   skippy_iter.reset (c->buffer->backtrack_len (), count);
@@ -898,17 +911,20 @@
     if (!skippy_iter.prev ())
       return_trace (false);
 
+  *match_start = skippy_iter.idx;
+
   return_trace (true);
 }
 
 static inline bool match_lookahead (hb_apply_context_t *c,
 				    unsigned int count,
-				    const USHORT lookahead[],
+				    const UINT16 lookahead[],
 				    match_func_t match_func,
 				    const void *match_data,
-				    unsigned int offset)
+				    unsigned int offset,
+				    unsigned int *end_index)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   skippy_iter.reset (c->buffer->idx + offset - 1, count);
@@ -918,6 +934,8 @@
     if (!skippy_iter.next ())
       return_trace (false);
 
+  *end_index = skippy_iter.idx + 1;
+
   return_trace (true);
 }
 
@@ -931,9 +949,9 @@
     return_trace (c->check_struct (this));
   }
 
-  USHORT	sequenceIndex;		/* Index into current glyph
+  UINT16	sequenceIndex;		/* Index into current glyph
 					 * sequence--first glyph = 0 */
-  USHORT	lookupListIndex;	/* Lookup to apply to that
+  UINT16	lookupListIndex;	/* Lookup to apply to that
 					 * position--zero--based */
   public:
   DEFINE_SIZE_STATIC (4);
@@ -956,10 +974,10 @@
 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
 				 unsigned int match_length)
 {
-  TRACE_APPLY (NULL);
+  TRACE_APPLY (nullptr);
 
   hb_buffer_t *buffer = c->buffer;
-  unsigned int end;
+  int end;
 
   /* All positions are distance from beginning of *output* buffer.
    * Adjust. */
@@ -984,7 +1002,11 @@
     if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
       continue;
 
-    buffer->move_to (match_positions[idx]);
+    if (unlikely (!buffer->move_to (match_positions[idx])))
+      break;
+
+    if (unlikely (buffer->max_ops <= 0))
+      break;
 
     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
     if (!c->recurse (lookupRecord[i].lookupListIndex))
@@ -996,10 +1018,32 @@
     if (!delta)
         continue;
 
-    /* Recursed lookup changed buffer len.  Adjust. */
+    /* Recursed lookup changed buffer len.  Adjust.
+     *
+     * TODO:
+     *
+     * Right now, if buffer length increased by n, we assume n new glyphs
+     * were added right after the current position, and if buffer length
+     * was decreased by n, we assume n match positions after the current
+     * one where removed.  The former (buffer length increased) case is
+     * fine, but the decrease case can be improved in at least two ways,
+     * both of which are significant:
+     *
+     *   - If recursed-to lookup is MultipleSubst and buffer length
+     *     decreased, then it's current match position that was deleted,
+     *     NOT the one after it.
+     *
+     *   - If buffer length was decreased by n, it does not necessarily
+     *     mean that n match positions where removed, as there might
+     *     have been marks and default-ignorables in the sequence.  We
+     *     should instead drop match positions between current-position
+     *     and current-position + n instead.
+     *
+     * It should be possible to construct tests for both of these cases.
+     */
 
-    end = int (end) + delta;
-    if (end <= match_positions[idx])
+    end += delta;
+    if (end <= int (match_positions[idx]))
     {
       /* End might end up being smaller than match_positions[idx] if the recursed
        * lookup ended up removing many items, more than we have had matched.
@@ -1068,7 +1112,7 @@
 
 static inline void context_closure_lookup (hb_closure_context_t *c,
 					   unsigned int inputCount, /* Including the first glyph (not matched) */
-					   const USHORT input[], /* Array of input values--start with second glyph */
+					   const UINT16 input[], /* Array of input values--start with second glyph */
 					   unsigned int lookupCount,
 					   const LookupRecord lookupRecord[],
 					   ContextClosureLookupContext &lookup_context)
@@ -1082,7 +1126,7 @@
 
 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 						  unsigned int inputCount, /* Including the first glyph (not matched) */
-						  const USHORT input[], /* Array of input values--start with second glyph */
+						  const UINT16 input[], /* Array of input values--start with second glyph */
 						  unsigned int lookupCount,
 						  const LookupRecord lookupRecord[],
 						  ContextCollectGlyphsLookupContext &lookup_context)
@@ -1096,7 +1140,7 @@
 
 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
-					       const USHORT input[], /* Array of input values--start with second glyph */
+					       const UINT16 input[], /* Array of input values--start with second glyph */
 					       unsigned int lookupCount HB_UNUSED,
 					       const LookupRecord lookupRecord[] HB_UNUSED,
 					       ContextApplyLookupContext &lookup_context)
@@ -1107,7 +1151,7 @@
 }
 static inline bool context_apply_lookup (hb_apply_context_t *c,
 					 unsigned int inputCount, /* Including the first glyph (not matched) */
-					 const USHORT input[], /* Array of input values--start with second glyph */
+					 const UINT16 input[], /* Array of input values--start with second glyph */
 					 unsigned int lookupCount,
 					 const LookupRecord lookupRecord[],
 					 ContextApplyLookupContext &lookup_context)
@@ -1118,10 +1162,11 @@
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data,
 		      &match_length, match_positions)
-      && apply_lookup (c,
+      && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
+	  apply_lookup (c,
 		       inputCount, match_positions,
 		       lookupCount, lookupRecord,
-		       match_length);
+		       match_length));
 }
 
 struct Rule
@@ -1164,19 +1209,19 @@
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return inputCount.sanitize (c)
-	&& lookupCount.sanitize (c)
-	&& c->check_range (inputZ,
-			   inputZ[0].static_size * inputCount
-			   + lookupRecordX[0].static_size * lookupCount);
+    return_trace (inputCount.sanitize (c) &&
+		  lookupCount.sanitize (c) &&
+		  c->check_range (inputZ,
+				  inputZ[0].static_size * inputCount +
+				  lookupRecordX[0].static_size * lookupCount));
   }
 
   protected:
-  USHORT	inputCount;		/* Total number of glyphs in input
+  UINT16	inputCount;		/* Total number of glyphs in input
 					 * glyph sequence--includes the first
 					 * glyph */
-  USHORT	lookupCount;		/* Number of LookupRecords */
-  USHORT	inputZ[VAR];		/* Array of match inputs--start with
+  UINT16	lookupCount;		/* Number of LookupRecords */
+  UINT16	inputZ[VAR];		/* Array of match inputs--start with
 					 * second glyph */
   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
 					 * design order */
@@ -1251,7 +1296,7 @@
 
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph},
-      NULL
+      nullptr
     };
 
     unsigned int count = ruleSet.len;
@@ -1269,7 +1314,7 @@
 
     struct ContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
-      NULL
+      nullptr
     };
 
     unsigned int count = ruleSet.len;
@@ -1284,7 +1329,7 @@
     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ContextApplyLookupContext lookup_context = {
       {match_glyph},
-      NULL
+      nullptr
     };
     return_trace (rule_set.would_apply (c, lookup_context));
   }
@@ -1304,7 +1349,7 @@
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
       {match_glyph},
-      NULL
+      nullptr
     };
     return_trace (rule_set.apply (c, lookup_context));
   }
@@ -1316,7 +1361,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
@@ -1409,7 +1454,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
@@ -1438,7 +1483,7 @@
       this
     };
     context_closure_lookup (c,
-			    glyphCount, (const USHORT *) (coverageZ + 1),
+			    glyphCount, (const UINT16 *) (coverageZ + 1),
 			    lookupCount, lookupRecord,
 			    lookup_context);
   }
@@ -1455,7 +1500,7 @@
     };
 
     context_collect_glyphs_lookup (c,
-				   glyphCount, (const USHORT *) (coverageZ + 1),
+				   glyphCount, (const UINT16 *) (coverageZ + 1),
 				   lookupCount, lookupRecord,
 				   lookup_context);
   }
@@ -1469,7 +1514,7 @@
       {match_coverage},
       this
     };
-    return_trace (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_would_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1488,7 +1533,7 @@
       {match_coverage},
       this
     };
-    return_trace (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
@@ -1505,10 +1550,10 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 3 */
-  USHORT	glyphCount;		/* Number of glyphs in the input glyph
+  UINT16	format;			/* Format identifier--format = 3 */
+  UINT16	glyphCount;		/* Number of glyphs in the input glyph
 					 * sequence */
-  USHORT	lookupCount;		/* Number of LookupRecords */
+  UINT16	lookupCount;		/* Number of LookupRecords */
   OffsetTo<Coverage>
 		coverageZ[VAR];		/* Array of offsets to Coverage
 					 * table in glyph sequence order */
@@ -1535,7 +1580,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   ContextFormat1	format1;
   ContextFormat2	format2;
   ContextFormat3	format3;
@@ -1565,11 +1610,11 @@
 
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 						 unsigned int backtrackCount,
-						 const USHORT backtrack[],
+						 const UINT16 backtrack[],
 						 unsigned int inputCount, /* Including the first glyph (not matched) */
-						 const USHORT input[], /* Array of input values--start with second glyph */
+						 const UINT16 input[], /* Array of input values--start with second glyph */
 						 unsigned int lookaheadCount,
-						 const USHORT lookahead[],
+						 const UINT16 lookahead[],
 						 unsigned int lookupCount,
 						 const LookupRecord lookupRecord[],
 						 ChainContextClosureLookupContext &lookup_context)
@@ -1589,11 +1634,11 @@
 
 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 						        unsigned int backtrackCount,
-						        const USHORT backtrack[],
+						        const UINT16 backtrack[],
 						        unsigned int inputCount, /* Including the first glyph (not matched) */
-						        const USHORT input[], /* Array of input values--start with second glyph */
+						        const UINT16 input[], /* Array of input values--start with second glyph */
 						        unsigned int lookaheadCount,
-						        const USHORT lookahead[],
+						        const UINT16 lookahead[],
 						        unsigned int lookupCount,
 						        const LookupRecord lookupRecord[],
 						        ChainContextCollectGlyphsLookupContext &lookup_context)
@@ -1613,11 +1658,11 @@
 
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
 						     unsigned int backtrackCount,
-						     const USHORT backtrack[] HB_UNUSED,
+						     const UINT16 backtrack[] HB_UNUSED,
 						     unsigned int inputCount, /* Including the first glyph (not matched) */
-						     const USHORT input[], /* Array of input values--start with second glyph */
+						     const UINT16 input[], /* Array of input values--start with second glyph */
 						     unsigned int lookaheadCount,
-						     const USHORT lookahead[] HB_UNUSED,
+						     const UINT16 lookahead[] HB_UNUSED,
 						     unsigned int lookupCount HB_UNUSED,
 						     const LookupRecord lookupRecord[] HB_UNUSED,
 						     ChainContextApplyLookupContext &lookup_context)
@@ -1630,16 +1675,16 @@
 
 static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
 					       unsigned int backtrackCount,
-					       const USHORT backtrack[],
+					       const UINT16 backtrack[],
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
-					       const USHORT input[], /* Array of input values--start with second glyph */
+					       const UINT16 input[], /* Array of input values--start with second glyph */
 					       unsigned int lookaheadCount,
-					       const USHORT lookahead[],
+					       const UINT16 lookahead[],
 					       unsigned int lookupCount,
 					       const LookupRecord lookupRecord[],
 					       ChainContextApplyLookupContext &lookup_context)
 {
-  unsigned int match_length = 0;
+  unsigned int start_index = 0, match_length = 0, end_index = 0;
   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
@@ -1647,15 +1692,17 @@
 		      &match_length, match_positions)
       && match_backtrack (c,
 			  backtrackCount, backtrack,
-			  lookup_context.funcs.match, lookup_context.match_data[0])
+			  lookup_context.funcs.match, lookup_context.match_data[0],
+			  &start_index)
       && match_lookahead (c,
 			  lookaheadCount, lookahead,
 			  lookup_context.funcs.match, lookup_context.match_data[2],
-			  match_length)
-      && apply_lookup (c,
+			  match_length, &end_index)
+      && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
+          apply_lookup (c,
 		       inputCount, match_positions,
 		       lookupCount, lookupRecord,
-		       match_length);
+		       match_length));
 }
 
 struct ChainRule
@@ -1663,8 +1710,8 @@
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_closure_lookup (c,
 				  backtrack.len, backtrack.array,
@@ -1677,8 +1724,8 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_collect_glyphs_lookup (c,
 					 backtrack.len, backtrack.array,
@@ -1691,8 +1738,8 @@
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_WOULD_APPLY (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (chain_context_would_apply_lookup (c,
 						    backtrack.len, backtrack.array,
@@ -1704,8 +1751,8 @@
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (chain_context_apply_lookup (c,
 					      backtrack.len, backtrack.array,
@@ -1718,23 +1765,23 @@
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return_trace (false);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
     if (!input.sanitize (c)) return_trace (false);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
     if (!lookahead.sanitize (c)) return_trace (false);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
   protected:
-  ArrayOf<USHORT>
+  ArrayOf<UINT16>
 		backtrack;		/* Array of backtracking values
 					 * (to be matched before the input
 					 * sequence) */
-  HeadlessArrayOf<USHORT>
+  HeadlessArrayOf<UINT16>
 		inputX;			/* Array of input values (start with
 					 * second glyph) */
-  ArrayOf<USHORT>
+  ArrayOf<UINT16>
 		lookaheadX;		/* Array of lookahead values's (to be
 					 * matched after the input sequence) */
   ArrayOf<LookupRecord>
@@ -1807,7 +1854,7 @@
 
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
 
     unsigned int count = ruleSet.len;
@@ -1825,7 +1872,7 @@
 
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
 
     unsigned int count = ruleSet.len;
@@ -1840,7 +1887,7 @@
     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ChainContextApplyLookupContext lookup_context = {
       {match_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
     return_trace (rule_set.would_apply (c, lookup_context));
   }
@@ -1859,7 +1906,7 @@
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
       {match_glyph},
-      {NULL, NULL, NULL}
+      {nullptr, nullptr, nullptr}
     };
     return_trace (rule_set.apply (c, lookup_context));
   }
@@ -1871,7 +1918,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 1 */
+  UINT16	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
@@ -1986,7 +2033,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 2 */
+  UINT16	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
@@ -2026,9 +2073,9 @@
       {this, this, this}
     };
     chain_context_closure_lookup (c,
-				  backtrack.len, (const USHORT *) backtrack.array,
-				  input.len, (const USHORT *) input.array + 1,
-				  lookahead.len, (const USHORT *) lookahead.array,
+				  backtrack.len, (const UINT16 *) backtrack.array,
+				  input.len, (const UINT16 *) input.array + 1,
+				  lookahead.len, (const UINT16 *) lookahead.array,
 				  lookup.len, lookup.array,
 				  lookup_context);
   }
@@ -2047,9 +2094,9 @@
       {this, this, this}
     };
     chain_context_collect_glyphs_lookup (c,
-					 backtrack.len, (const USHORT *) backtrack.array,
-					 input.len, (const USHORT *) input.array + 1,
-					 lookahead.len, (const USHORT *) lookahead.array,
+					 backtrack.len, (const UINT16 *) backtrack.array,
+					 input.len, (const UINT16 *) input.array + 1,
+					 lookahead.len, (const UINT16 *) lookahead.array,
 					 lookup.len, lookup.array,
 					 lookup_context);
   }
@@ -2066,9 +2113,9 @@
       {this, this, this}
     };
     return_trace (chain_context_would_apply_lookup (c,
-						    backtrack.len, (const USHORT *) backtrack.array,
-						    input.len, (const USHORT *) input.array + 1,
-						    lookahead.len, (const USHORT *) lookahead.array,
+						    backtrack.len, (const UINT16 *) backtrack.array,
+						    input.len, (const UINT16 *) input.array + 1,
+						    lookahead.len, (const UINT16 *) lookahead.array,
 						    lookup.len, lookup.array, lookup_context));
   }
 
@@ -2093,9 +2140,9 @@
       {this, this, this}
     };
     return_trace (chain_context_apply_lookup (c,
-					      backtrack.len, (const USHORT *) backtrack.array,
-					      input.len, (const USHORT *) input.array + 1,
-					      lookahead.len, (const USHORT *) lookahead.array,
+					      backtrack.len, (const UINT16 *) backtrack.array,
+					      input.len, (const UINT16 *) input.array + 1,
+					      lookahead.len, (const UINT16 *) lookahead.array,
 					      lookup.len, lookup.array, lookup_context));
   }
 
@@ -2113,7 +2160,7 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier--format = 3 */
+  UINT16	format;			/* Format identifier--format = 3 */
   OffsetArrayOf<Coverage>
 		backtrack;		/* Array of coverage tables
 					 * in backtracking sequence, in  glyph
@@ -2150,7 +2197,7 @@
 
   protected:
   union {
-  USHORT		format;	/* Format identifier */
+  UINT16		format;	/* Format identifier */
   ChainContextFormat1	format1;
   ChainContextFormat2	format2;
   ChainContextFormat3	format3;
@@ -2187,11 +2234,11 @@
   }
 
   protected:
-  USHORT	format;			/* Format identifier. Set to 1. */
-  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
+  UINT16	format;			/* Format identifier. Set to 1. */
+  UINT16	extensionLookupType;	/* Lookup type of subtable referenced
 					 * by ExtensionOffset (i.e. the
 					 * extension subtable). */
-  ULONG		extensionOffset;	/* Offset to the extension subtable,
+  UINT32		extensionOffset;	/* Offset to the extension subtable,
 					 * of lookup type subtable. */
   public:
   DEFINE_SIZE_STATIC (8);
@@ -2229,7 +2276,7 @@
 
   protected:
   union {
-  USHORT		format;		/* Format identifier */
+  UINT16		format;		/* Format identifier */
   ExtensionFormat1<T>	format1;
   } u;
 };
@@ -2241,9 +2288,6 @@
 
 struct GSUBGPOS
 {
-  static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
-  static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
-
   inline unsigned int get_script_count (void) const
   { return (this+scriptList).len; }
   inline const Tag& get_script_tag (unsigned int i) const
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
index c306849..adbaad6 100644
--- a/src/hb-ot-layout-jstf-table.hh
+++ b/src/hb-ot-layout-jstf-table.hh
@@ -124,7 +124,7 @@
 struct JstfLangSys : OffsetListOf<JstfPriority>
 {
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<JstfLangSys>::sanitize_closure_t * = NULL) const
+			const Record<JstfLangSys>::sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
     return_trace (OffsetListOf<JstfPriority>::sanitize (c));
@@ -165,7 +165,7 @@
   inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<JstfScript>::sanitize_closure_t * = NULL) const
+			const Record<JstfScript>::sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
     return_trace (extenderGlyphs.sanitize (c, this) &&
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index 8c348be..0f0926f 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -33,7 +33,7 @@
 
 #include "hb-font-private.hh"
 #include "hb-buffer-private.hh"
-#include "hb-set-private.hh"
+#include "hb-set-digest-private.hh"
 #include "hb-open-type-private.hh"
 
 
@@ -197,8 +197,7 @@
 #define syllable()		var1.u8[3] /* GSUB/GPOS shaping boundaries */
 
 
-/* loop over syllables */
-
+/* Loop over syllables. Based on foreach_cluster(). */
 #define foreach_syllable(buffer, start, end) \
   for (unsigned int \
        _count = buffer->len, \
@@ -227,7 +226,9 @@
  * - General_Category: 5 bits.
  * - A bit each for:
  *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
- *   * Whether it's one of the three Mongolian Free Variation Selectors.
+ *   * Whether it's one of the three Mongolian Free Variation Selectors,
+ *     CGJ, or other characters that are hidden but should not be ignored
+ *     like most other Default_Ignorable()s do during matching.
  *   * One free bit right now.
  *
  * The high-byte has different meanings, switched by the Gen-Cat:
@@ -240,7 +241,8 @@
 enum hb_unicode_props_flags_t {
   UPROPS_MASK_GEN_CAT	= 0x001Fu,
   UPROPS_MASK_IGNORABLE	= 0x0020u,
-  UPROPS_MASK_FVS	= 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3 */
+  UPROPS_MASK_HIDDEN	= 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3,
+                                    * or TAG characters */
 
   /* If GEN_CAT=FORMAT, top byte masks: */
   UPROPS_MASK_Cf_ZWJ	= 0x0100u,
@@ -264,16 +266,21 @@
       buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
       props |=  UPROPS_MASK_IGNORABLE;
       if (u == 0x200Cu) props |= UPROPS_MASK_Cf_ZWNJ;
-      if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
+      else if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
       /* Mongolian Free Variation Selectors need to be remembered
        * because although we need to hide them like default-ignorables,
        * they need to non-ignorable during shaping.  This is similar to
        * what we do for joiners in Indic-like shapers, but since the
        * FVSes are GC=Mn, we have use a separate bit to remember them.
        * Fixes:
-       * https://github.com/behdad/harfbuzz/issues/234
-       */
-      if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_FVS;
+       * https://github.com/harfbuzz/harfbuzz/issues/234 */
+      else if (unlikely (hb_in_range (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;
+      /* COMBINING GRAPHEME JOINER should not be skipped; at least some times.
+       * https://github.com/harfbuzz/harfbuzz/issues/554 */
+      else if (unlikely (u == 0x034Fu)) props |= UPROPS_MASK_HIDDEN;
     }
     else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
     {
@@ -298,7 +305,7 @@
       /* Recategorize emoji skin-tone modifiers as Unicode mark, so they
        * behave correctly in non-native directionality.  They originally
        * are MODIFIER_SYMBOL.  Fixes:
-       * https://github.com/behdad/harfbuzz/issues/169
+       * https://github.com/harfbuzz/harfbuzz/issues/169
        */
       if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
       {
@@ -343,6 +350,8 @@
   return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
 }
 
+#define info_cc(info) (_hb_glyph_info_get_modified_combining_class (&(info)))
+
 static inline bool
 _hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
 {
@@ -373,9 +382,9 @@
 	 !_hb_glyph_info_ligated (info);
 }
 static inline hb_bool_t
-_hb_glyph_info_is_default_ignorable_and_not_fvs (const hb_glyph_info_t *info)
+_hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
 {
-  return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_FVS))
+  return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN))
 	  == UPROPS_MASK_IGNORABLE) &&
 	 !_hb_glyph_info_ligated (info);
 }
@@ -623,5 +632,4 @@
 #undef lig_props
 #undef glyph_props
 
-
 #endif /* HB_OT_LAYOUT_PRIVATE_HH */
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index d7ededd..8845889 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -35,18 +35,20 @@
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
 #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-ot-name-table.hh" // Just so we compile it; unused otherwise.
 
 #include "hb-ot-map-private.hh"
 
 
-HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
+const void * const OT::_hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)] = {};
+
 
 hb_ot_layout_t *
 _hb_ot_layout_create (hb_face_t *face)
 {
   hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
   if (unlikely (!layout))
-    return NULL;
+    return nullptr;
 
   layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
   layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
@@ -103,14 +105,28 @@
       || (928 == gdef_len && 59332 == gpos_len && 23298 == gsub_len)
       /* sha1sum:6d400781948517c3c0441ba42acb309584b73033  tahomabd.ttf from Windows 8.1 */
       || (940 == gdef_len && 60732 == gpos_len && 23310 == gsub_len)
+      /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
+      || (964 == gdef_len && 60072 == gpos_len && 23836 == gsub_len)
+      /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
+      || (976 == gdef_len && 61456 == gpos_len && 23832 == gsub_len)
       /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846  tahoma.ttf from Windows 10 */
       || (994 == gdef_len && 60336 == gpos_len && 24474 == gsub_len)
       /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343  tahomabd.ttf from Windows 10 */
       || (1006 == gdef_len && 61740 == gpos_len && 24470 == gsub_len)
+      /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
+      || (1006 == gdef_len && 61346 == gpos_len && 24576 == gsub_len)
+      /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
+      || (1018 == gdef_len && 62828 == gpos_len && 24572 == gsub_len)
+      /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5  tahoma.ttf from Windows 10 AU */
+      || (1006 == gdef_len && 61352 == gpos_len && 24576 == gsub_len)
+      /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2  tahomabd.ttf from Windows 10 AU */
+      || (1018 == gdef_len && 62834 == gpos_len && 24572 == gsub_len)
       /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7  Tahoma.ttf from Mac OS X 10.9 */
       || (832 == gdef_len && 47162 == gpos_len && 7324 == gsub_len)
       /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba  Tahoma Bold.ttf from Mac OS X 10.9 */
       || (844 == gdef_len && 45474 == gpos_len && 7302 == gsub_len)
+      /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc  himalaya.ttf from Windows 7 */
+      || (180 == gdef_len && 7254 == gpos_len && 13054 == gsub_len)
       /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0  himalaya.ttf from Windows 8 */
       || (192 == gdef_len && 7254 == gpos_len && 12638 == gsub_len)
       /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427  himalaya.ttf from Windows 8.1 */
@@ -121,6 +137,14 @@
       /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f  cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
       /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b  cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
       || (188 == gdef_len && 3426 == gpos_len && 264 == gsub_len)
+      /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */
+      || (1058 == gdef_len && 11818 == gpos_len && 47032 == gsub_len)
+      /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/
+      || (1046 == gdef_len && 12600 == gpos_len && 47030 == gsub_len)
+      /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */
+      || (1058 == gdef_len && 16770 == gpos_len && 71796 == gsub_len)
+      /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */
+      || (1046 == gdef_len && 17862 == gpos_len && 71790 == gsub_len)
       /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
       || (1046 == gdef_len && 17112 == gpos_len && 71788 == gsub_len)
       /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
@@ -129,6 +153,9 @@
       || (1330 == gdef_len && 57938 == gpos_len && 109904 == gsub_len)
       /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
       || (1330 == gdef_len && 58972 == gpos_len && 109904 == gsub_len)
+      /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85  Padauk.ttf
+       *  "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
+      || (1004 == gdef_len && 14836 == gpos_len && 59092 == gsub_len)
     )
     {
       /* Many versions of Tahoma have bad GDEF tables that incorrectly classify some spacing marks
@@ -153,7 +180,7 @@
 		(layout->gpos_lookup_count && !layout->gpos_accels)))
   {
     _hb_ot_layout_destroy (layout);
-    return NULL;
+    return nullptr;
   }
 
   for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
@@ -256,7 +283,7 @@
 				  hb_codepoint_t  glyph,
 				  unsigned int    start_offset,
 				  unsigned int   *caret_count /* IN/OUT */,
-				  int            *caret_array /* OUT */)
+				  hb_position_t  *caret_array /* OUT */)
 {
   return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
 }
@@ -298,7 +325,7 @@
 				hb_tag_t      script_tag,
 				unsigned int *script_index)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   if (g.find_script_index (script_tag, script_index))
@@ -329,7 +356,7 @@
 				  unsigned int   *script_index,
 				  hb_tag_t       *chosen_script)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   while (*script_tags)
@@ -388,7 +415,7 @@
 				 hb_tag_t      feature_tag,
 				 unsigned int *feature_index)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   unsigned int num_features = g.get_feature_count ();
@@ -425,7 +452,7 @@
 				   hb_tag_t      language_tag,
 				   unsigned int *language_index)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX), "");
   const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
 
   if (s.find_lang_sys_index (language_tag, language_index))
@@ -451,7 +478,7 @@
 						     script_index,
 						     language_index,
 						     feature_index,
-						     NULL);
+						     nullptr);
 }
 
 /**
@@ -504,7 +531,7 @@
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
-  ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
+  static_assert ((sizeof (unsigned int) == sizeof (hb_tag_t)), "");
   unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
 
   if (feature_tags) {
@@ -525,7 +552,7 @@
 				    hb_tag_t      feature_tag,
 				    unsigned int *feature_index)
 {
-  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+  static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
@@ -574,6 +601,7 @@
 hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
 				     hb_tag_t      table_tag)
 {
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return 0;
   switch (table_tag)
   {
     case HB_OT_TAG_GSUB:
@@ -629,7 +657,7 @@
 						    script_index,
 						    language_index,
 						    &required_feature_index,
-						    NULL))
+						    nullptr))
       _hb_ot_layout_collect_lookups_lookups (face,
 					     table_tag,
 					     required_feature_index,
@@ -698,7 +726,7 @@
     unsigned int count = hb_ot_layout_script_get_language_tags (face,
 								table_tag,
 								script_index,
-								0, NULL, NULL);
+								0, nullptr, nullptr);
     for (unsigned int language_index = 0; language_index < count; language_index++)
       _hb_ot_layout_collect_lookups_features (face,
 					      table_tag,
@@ -745,7 +773,7 @@
     /* All scripts */
     unsigned int count = hb_ot_layout_table_get_script_tags (face,
 							     table_tag,
-							     0, NULL, NULL);
+							     0, nullptr, nullptr);
     for (unsigned int script_index = 0; script_index < count; script_index++)
       _hb_ot_layout_collect_lookups_languages (face,
 					       table_tag,
@@ -782,10 +810,10 @@
 hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
 				    hb_tag_t      table_tag,
 				    unsigned int  lookup_index,
-				    hb_set_t     *glyphs_before, /* OUT. May be NULL */
-				    hb_set_t     *glyphs_input,  /* OUT. May be NULL */
-				    hb_set_t     *glyphs_after,  /* OUT. May be NULL */
-				    hb_set_t     *glyphs_output  /* OUT. May be NULL */)
+				    hb_set_t     *glyphs_before, /* OUT. May be nullptr */
+				    hb_set_t     *glyphs_input,  /* OUT. May be nullptr */
+				    hb_set_t     *glyphs_after,  /* OUT. May be nullptr */
+				    hb_set_t     *glyphs_output  /* OUT. May be nullptr */)
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
 
@@ -836,7 +864,7 @@
 						  unsigned int *lookup_count /* IN/OUT */,
 						  unsigned int *lookup_indexes /* OUT */)
 {
-  ASSERT_STATIC (OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
+  static_assert ((OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   const OT::Feature &f = g.get_feature_variation (feature_index, variations_index);
@@ -944,11 +972,11 @@
  **/
 hb_bool_t
 hb_ot_layout_get_size_params (hb_face_t    *face,
-			      unsigned int *design_size,       /* OUT.  May be NULL */
-			      unsigned int *subfamily_id,      /* OUT.  May be NULL */
-			      unsigned int *subfamily_name_id, /* OUT.  May be NULL */
-			      unsigned int *range_start,       /* OUT.  May be NULL */
-			      unsigned int *range_end          /* OUT.  May be NULL */)
+			      unsigned int *design_size,       /* OUT.  May be nullptr */
+			      unsigned int *subfamily_id,      /* OUT.  May be nullptr */
+			      unsigned int *subfamily_name_id, /* OUT.  May be nullptr */
+			      unsigned int *range_start,       /* OUT.  May be nullptr */
+			      unsigned int *range_end          /* OUT.  May be nullptr */)
 {
   const OT::GPOS &gpos = _get_gpos (face);
   const hb_tag_t tag = HB_TAG ('s','i','z','e');
@@ -1196,6 +1224,7 @@
       c.set_lookup_index (lookup_index);
       c.set_lookup_mask (lookups[table_index][i].mask);
       c.set_auto_zwj (lookups[table_index][i].auto_zwj);
+      c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
       apply_string<Proxy> (&c,
 			   proxy.table.get_lookup (lookup_index),
 			   proxy.accels[lookup_index]);
diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 0395c9c..97b92cc 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -50,19 +50,25 @@
     hb_mask_t mask;
     hb_mask_t _1_mask; /* mask for value=1, for quick access */
     unsigned int needs_fallback : 1;
+    unsigned int auto_zwnj : 1;
     unsigned int auto_zwj : 1;
 
-    static int cmp (const feature_map_t *a, const feature_map_t *b)
-    { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
+    inline int cmp (const hb_tag_t *tag_) const
+    { return *tag_ < tag ? -1 : *tag_ > tag ? 1 : 0; }
   };
 
   struct lookup_map_t {
     unsigned short index;
+    unsigned short auto_zwnj : 1;
     unsigned short auto_zwj : 1;
     hb_mask_t mask;
 
-    static int cmp (const lookup_map_t *a, const lookup_map_t *b)
-    { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
+    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;
+      return a->index < b->index ? -1 : a->index > b->index ? 1 : 0;
+    }
   };
 
   typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
@@ -77,7 +83,7 @@
 
   inline hb_mask_t get_global_mask (void) const { return global_mask; }
 
-  inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = NULL) const {
+  inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = nullptr) const {
     const feature_map_t *map = features.bsearch (&feature_tag);
     if (shift) *shift = map ? map->shift : 0;
     return map ? map->mask : 0;
@@ -106,14 +112,14 @@
   inline void get_stage_lookups (unsigned int table_index, unsigned int stage,
 				 const struct lookup_map_t **plookups, unsigned int *lookup_count) const {
     if (unlikely (stage == (unsigned int) -1)) {
-      *plookups = NULL;
+      *plookups = nullptr;
       *lookup_count = 0;
       return;
     }
     assert (stage <= stages[table_index].len);
     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;
-    *plookups = &lookups[table_index][start];
+    *plookups = end == start ? nullptr : &lookups[table_index][start];
     *lookup_count = end - start;
   }
 
@@ -150,8 +156,9 @@
   F_NONE		= 0x0000u,
   F_GLOBAL		= 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
   F_HAS_FALLBACK	= 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
-  F_MANUAL_ZWJ		= 0x0004u, /* Don't skip over ZWJ when matching. */
-  F_GLOBAL_SEARCH	= 0x0008u  /* If feature not found in LangSys, look for it in global feature list and pick one. */
+  F_MANUAL_ZWNJ		= 0x0004u, /* Don't skip over ZWNJ when matching **context**. */
+  F_MANUAL_ZWJ		= 0x0008u, /* Don't skip over ZWJ when matching **input**. */
+  F_GLOBAL_SEARCH	= 0x0010u  /* If feature not found in LangSys, look for it in global feature list and pick one. */
 };
 HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
 /* Macro version for where const is desired. */
@@ -196,7 +203,8 @@
 				unsigned int  feature_index,
 				unsigned int  variations_index,
 				hb_mask_t     mask,
-				bool          auto_zwj);
+				bool          auto_zwnj = true,
+				bool          auto_zwj = true);
 
   struct feature_info_t {
     hb_tag_t tag;
@@ -206,9 +214,13 @@
     unsigned int default_value; /* for non-global features, what should the unset glyphs take */
     unsigned int stage[2]; /* GSUB/GPOS */
 
-    static int cmp (const feature_info_t *a, const feature_info_t *b)
-    { return (a->tag != b->tag) ?  (a->tag < b->tag ? -1 : 1) :
-	     (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); }
+    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;
+      return (a->tag != b->tag) ?  (a->tag < b->tag ? -1 : 1) :
+	     (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
+    }
   };
 
   struct stage_info_t {
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index 9b331d5..ea9bde9 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -85,6 +85,7 @@
 				  unsigned int  feature_index,
 				  unsigned int  variations_index,
 				  hb_mask_t     mask,
+				  bool          auto_zwnj,
 				  bool          auto_zwj)
 {
   unsigned int lookup_indices[32];
@@ -112,6 +113,7 @@
         return;
       lookup->mask = mask;
       lookup->index = lookup_indices[i];
+      lookup->auto_zwnj = auto_zwnj;
       lookup->auto_zwj = auto_zwj;
     }
 
@@ -136,7 +138,11 @@
 			      const int    *coords,
 			      unsigned int  num_coords)
 {
-  m.global_mask = 1;
+  static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
+  unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
+  unsigned int global_bit_shift = _hb_popcount32 (HB_GLYPH_FLAG_DEFINED);
+
+  m.global_mask = global_bit_mask;
 
   unsigned int required_feature_index[2];
   hb_tag_t required_feature_tag[2];
@@ -188,7 +194,8 @@
 
 
   /* Allocate bits now */
-  unsigned int next_bit = 1;
+  unsigned int next_bit = global_bit_shift + 1;
+
   for (unsigned int i = 0; i < feature_infos.len; i++)
   {
     const feature_info_t *info = &feature_infos[i];
@@ -243,11 +250,12 @@
     map->index[1] = feature_index[1];
     map->stage[0] = info->stage[0];
     map->stage[1] = info->stage[1];
+    map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
     map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
     if ((info->flags & F_GLOBAL) && info->max_value == 1) {
       /* Uses the global bit */
-      map->shift = 0;
-      map->mask = 1;
+      map->shift = global_bit_shift;
+      map->mask = global_bit_mask;
     } else {
       map->shift = next_bit;
       map->mask = (1u << (next_bit + bits_needed)) - (1u << next_bit);
@@ -261,8 +269,8 @@
   feature_infos.shrink (0); /* Done with these */
 
 
-  add_gsub_pause (NULL);
-  add_gpos_pause (NULL);
+  add_gsub_pause (nullptr);
+  add_gpos_pause (nullptr);
 
   for (unsigned int table_index = 0; table_index < 2; table_index++)
   {
@@ -284,8 +292,7 @@
 	add_lookups (m, face, table_index,
 		     required_feature_index[table_index],
 		     variations_index,
-		     1 /* mask */,
-		     true /* auto_zwj */);
+		     global_bit_mask);
 
       for (unsigned i = 0; i < m.features.len; i++)
         if (m.features[i].stage[table_index] == stage)
@@ -293,6 +300,7 @@
 		       m.features[i].index[table_index],
 		       variations_index,
 		       m.features[i].mask,
+		       m.features[i].auto_zwnj,
 		       m.features[i].auto_zwj);
 
       /* Sort lookups and merge duplicates */
@@ -307,6 +315,7 @@
 	  else
 	  {
 	    m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
+	    m.lookups[table_index][j].auto_zwnj &= m.lookups[table_index][i].auto_zwnj;
 	    m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
 	  }
 	m.lookups[table_index].shrink (j + 1);
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index 191d79e..7dc3283 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -48,9 +48,9 @@
   }
 
   protected:
-  SHORT			value;		/* The X or Y value in design units */
+  INT16			value;		/* The X or Y value in design units */
   OffsetTo<Device>	deviceTable;	/* Offset to the device table - from the
-					 * beginning of parent table. May be NULL.
+					 * beginning of parent table. May be nullptr.
 					 * Suggested format for device table is 1. */
 
   public:
@@ -154,10 +154,10 @@
   }
 
   protected:
-  SHORT percentScaleDown[2];
-  USHORT minHeight[2];
+  INT16 percentScaleDown[2];
+  UINT16 minHeight[2];
   MathValueRecord mathValueRecords[51];
-  SHORT radicalDegreeBottomRaisePercent;
+  INT16 radicalDegreeBottomRaisePercent;
 
   public:
   DEFINE_SIZE_STATIC (214);
@@ -279,7 +279,7 @@
   }
 
   protected:
-  USHORT	  heightCount;
+  UINT16	  heightCount;
   MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
 					  * which the kern value changes.
 					  * Sorted by the height value in
@@ -319,7 +319,7 @@
 
   protected:
   /* Offset to MathKern table for each corner -
-   * from the beginning of MathKernInfo table. May be NULL. */
+   * from the beginning of MathKernInfo table. May be nullptr. */
   OffsetTo<MathKern> mathKern[4];
 
   public:
@@ -402,7 +402,7 @@
    * from the beginning of MathGlyphInfo table. When the left or right glyph of
    * a box is an extended shape variant, the (ink) box (and not the default
    * position defined by values in MathConstants table) should be used for
-   * vertical positioning purposes. May be NULL.. */
+   * vertical positioning purposes. May be nullptr.. */
   OffsetTo<Coverage> extendedShapeCoverage;
 
    /* Offset to MathKernInfo table -
@@ -425,7 +425,7 @@
 
   protected:
   GlyphID variantGlyph;       /* Glyph ID for the variant. */
-  USHORT  advanceMeasurement; /* Advance width/height, in design units, of the
+  UINT16  advanceMeasurement; /* Advance width/height, in design units, of the
 			       * variant, in the direction of requested
 			       * glyph extension. */
 
@@ -433,7 +433,7 @@
   DEFINE_SIZE_STATIC (4);
 };
 
-struct PartFlags : USHORT
+struct PartFlags : UINT16
 {
   enum Flags {
     Extender	= 0x0001u, /* If set, the part can be skipped or repeated. */
@@ -463,8 +463,8 @@
     out.end_connector_length	= font->em_scale (endConnectorLength, scale);
     out.full_advance		= font->em_scale (fullAdvance, scale);
 
-    ASSERT_STATIC ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
-		   (unsigned int) PartFlags::Extender);
+    static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
+		   (unsigned int) PartFlags::Extender, "");
 
     out.flags = (hb_ot_math_glyph_part_flags_t)
 		(unsigned int)
@@ -473,15 +473,15 @@
 
   protected:
   GlyphID   glyph;		  /* Glyph ID for the part. */
-  USHORT    startConnectorLength; /* Advance width/ height of the straight bar
+  UINT16    startConnectorLength; /* Advance width/ height of the straight bar
 				   * connector material, in design units, is at
 				   * the beginning of the glyph, in the
 				   * direction of the extension. */
-  USHORT    endConnectorLength;   /* Advance width/ height of the straight bar
+  UINT16    endConnectorLength;   /* Advance width/ height of the straight bar
 				   * connector material, in design units, is at
 				   * the end of the glyph, in the direction of
 				   * the extension. */
-  USHORT    fullAdvance;	  /* Full advance width/height for this part,
+  UINT16    fullAdvance;	  /* Full advance width/height for this part,
 				   * in the direction of the extension.
 				   * In design units. */
   PartFlags partFlags;		  /* Part qualifiers. */
@@ -571,7 +571,7 @@
 
   protected:
   /* Offset to MathGlyphAssembly table for this shape - from the beginning of
-     MathGlyphConstruction table. May be NULL. */
+     MathGlyphConstruction table. May be nullptr. */
   OffsetTo<MathGlyphAssembly>	  glyphAssembly;
 
   /* MathGlyphVariantRecords for alternative variants of the glyphs. */
@@ -651,7 +651,7 @@
   }
 
   protected:
-  USHORT	     minConnectorOverlap; /* Minimum overlap of connecting
+  UINT16	     minConnectorOverlap; /* Minimum overlap of connecting
 					   * glyphs during glyph construction,
 					   * in design units. */
   OffsetTo<Coverage> vertGlyphCoverage;   /* Offset to Coverage table -
@@ -660,10 +660,10 @@
   OffsetTo<Coverage> horizGlyphCoverage;  /* Offset to Coverage table -
 					   * from the beginning of MathVariants
 					   * table. */
-  USHORT	     vertGlyphCount;      /* Number of glyphs for which
+  UINT16	     vertGlyphCount;      /* Number of glyphs for which
 					   * information is provided for
 					   * vertically growing variants. */
-  USHORT	     horizGlyphCount;     /* Number of glyphs for which
+  UINT16	     horizGlyphCount;     /* Number of glyphs for which
 					   * information is provided for
 					   * horizontally growing variants. */
 
diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc
index 2d7e679..f82a073 100644
--- a/src/hb-ot-math.cc
+++ b/src/hb-ot-math.cc
@@ -26,10 +26,9 @@
 
 #include "hb-open-type-private.hh"
 
+#include "hb-ot-layout-private.hh"
 #include "hb-ot-math-table.hh"
 
-HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
-
 static inline const OT::MATH&
 _get_math (hb_face_t *face)
 {
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 943e390..f6d283e 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -60,7 +60,7 @@
   protected:
   FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000u or 0x00010000u. */
-  USHORT	numGlyphs;		/* The number of glyphs in the font. */
+  UINT16	numGlyphs;		/* The number of glyphs in the font. */
   public:
   DEFINE_SIZE_STATIC (6);
 };
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 870f123..4c5b3c0 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -42,8 +42,10 @@
 
 struct NameRecord
 {
-  static int cmp (const NameRecord *a, const NameRecord *b)
+  static int cmp (const void *pa, const void *pb)
   {
+    const NameRecord *a = (const NameRecord *) pa;
+    const NameRecord *b = (const NameRecord *) pb;
     int ret;
     ret = b->platformID.cmp (a->platformID);
     if (ret) return ret;
@@ -63,12 +65,12 @@
     return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
   }
 
-  USHORT	platformID;	/* Platform ID. */
-  USHORT	encodingID;	/* Platform-specific encoding ID. */
-  USHORT	languageID;	/* Language ID. */
-  USHORT	nameID;		/* Name ID. */
-  USHORT	length;		/* String length (in bytes). */
-  USHORT	offset;		/* String offset from start of storage area (in bytes). */
+  UINT16	platformID;	/* Platform ID. */
+  UINT16	encodingID;	/* Platform-specific encoding ID. */
+  UINT16	languageID;	/* Language ID. */
+  UINT16	nameID;		/* Name ID. */
+  UINT16	length;		/* String length (in bytes). */
+  UINT16	offset;		/* String offset from start of storage area (in bytes). */
   public:
   DEFINE_SIZE_STATIC (12);
 };
@@ -89,7 +91,7 @@
     key.encodingID.set (encoding_id);
     key.languageID.set (language_id);
     key.nameID.set (name_id);
-    NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), (hb_compare_func_t) NameRecord::cmp);
+    NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), NameRecord::cmp);
 
     if (!match)
       return 0;
@@ -121,9 +123,9 @@
   }
 
   /* We only implement format 0 for now. */
-  USHORT	format;			/* Format selector (=0/1). */
-  USHORT	count;			/* Number of name records. */
-  Offset<>	stringOffset;		/* Offset to start of string storage (from start of table). */
+  UINT16	format;			/* Format selector (=0/1). */
+  UINT16	count;			/* Number of name records. */
+  Offset16	stringOffset;		/* Offset to start of string storage (from start of table). */
   NameRecord	nameRecord[VAR];	/* The name records where count is the number of records. */
   public:
   DEFINE_SIZE_ARRAY (6, nameRecord);
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index 4709cd6..aa78f1e 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -50,50 +50,50 @@
   }
 
   public:
-  USHORT	version;
+  UINT16	version;
 
   /* Version 0 */
-  SHORT		xAvgCharWidth;
-  USHORT	usWeightClass;
-  USHORT	usWidthClass;
-  USHORT	fsType;
-  SHORT		ySubscriptXSize;
-  SHORT		ySubscriptYSize;
-  SHORT		ySubscriptXOffset;
-  SHORT		ySubscriptYOffset;
-  SHORT		ySuperscriptXSize;
-  SHORT		ySuperscriptYSize;
-  SHORT		ySuperscriptXOffset;
-  SHORT		ySuperscriptYOffset;
-  SHORT		yStrikeoutSize;
-  SHORT		yStrikeoutPosition;
-  SHORT		sFamilyClass;
-  BYTE		panose[10];
-  ULONG		ulUnicodeRange[4];
+  INT16		xAvgCharWidth;
+  UINT16	usWeightClass;
+  UINT16	usWidthClass;
+  UINT16	fsType;
+  INT16		ySubscriptXSize;
+  INT16		ySubscriptYSize;
+  INT16		ySubscriptXOffset;
+  INT16		ySubscriptYOffset;
+  INT16		ySuperscriptXSize;
+  INT16		ySuperscriptYSize;
+  INT16		ySuperscriptXOffset;
+  INT16		ySuperscriptYOffset;
+  INT16		yStrikeoutSize;
+  INT16		yStrikeoutPosition;
+  INT16		sFamilyClass;
+  UINT8		panose[10];
+  UINT32		ulUnicodeRange[4];
   Tag		achVendID;
-  USHORT	fsSelection;
-  USHORT	usFirstCharIndex;
-  USHORT	usLastCharIndex;
-  SHORT		sTypoAscender;
-  SHORT		sTypoDescender;
-  SHORT		sTypoLineGap;
-  USHORT	usWinAscent;
-  USHORT	usWinDescent;
+  UINT16	fsSelection;
+  UINT16	usFirstCharIndex;
+  UINT16	usLastCharIndex;
+  INT16		sTypoAscender;
+  INT16		sTypoDescender;
+  INT16		sTypoLineGap;
+  UINT16	usWinAscent;
+  UINT16	usWinDescent;
 
   /* Version 1 */
-  //ULONG ulCodePageRange1;
-  //ULONG ulCodePageRange2;
+  //UINT32 ulCodePageRange1;
+  //UINT32 ulCodePageRange2;
 
   /* Version 2 */
-  //SHORT sxHeight;
-  //SHORT sCapHeight;
-  //USHORT  usDefaultChar;
-  //USHORT  usBreakChar;
-  //USHORT  usMaxContext;
+  //INT16 sxHeight;
+  //INT16 sCapHeight;
+  //UINT16  usDefaultChar;
+  //UINT16  usBreakChar;
+  //UINT16  usMaxContext;
 
   /* Version 5 */
-  //USHORT  usLowerOpticalPointSize;
-  //USHORT  usUpperOpticalPointSize;
+  //UINT16  usLowerOpticalPointSize;
+  //UINT16  usUpperOpticalPointSize;
 
   public:
   DEFINE_SIZE_STATIC (78);
diff --git a/src/hb-ot-post-macroman.hh b/src/hb-ot-post-macroman.hh
new file mode 100644
index 0000000..dbbb97e
--- /dev/null
+++ b/src/hb-ot-post-macroman.hh
@@ -0,0 +1,294 @@
+/*
+ * 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_OT_POST_MACROMAN_HH
+#if 0 /* Make checks happy. */
+#define HB_OT_POST_MACROMAN_HH
+#include "hb-private.hh"
+#endif
+
+
+_S(".notdef")
+_S(".null")
+_S("nonmarkingreturn")
+_S("space")
+_S("exclam")
+_S("quotedbl")
+_S("numbersign")
+_S("dollar")
+_S("percent")
+_S("ampersand")
+_S("quotesingle")
+_S("parenleft")
+_S("parenright")
+_S("asterisk")
+_S("plus")
+_S("comma")
+_S("hyphen")
+_S("period")
+_S("slash")
+_S("zero")
+_S("one")
+_S("two")
+_S("three")
+_S("four")
+_S("five")
+_S("six")
+_S("seven")
+_S("eight")
+_S("nine")
+_S("colon")
+_S("semicolon")
+_S("less")
+_S("equal")
+_S("greater")
+_S("question")
+_S("at")
+_S("A")
+_S("B")
+_S("C")
+_S("D")
+_S("E")
+_S("F")
+_S("G")
+_S("H")
+_S("I")
+_S("J")
+_S("K")
+_S("L")
+_S("M")
+_S("N")
+_S("O")
+_S("P")
+_S("Q")
+_S("R")
+_S("S")
+_S("T")
+_S("U")
+_S("V")
+_S("W")
+_S("X")
+_S("Y")
+_S("Z")
+_S("bracketleft")
+_S("backslash")
+_S("bracketright")
+_S("asciicircum")
+_S("underscore")
+_S("grave")
+_S("a")
+_S("b")
+_S("c")
+_S("d")
+_S("e")
+_S("f")
+_S("g")
+_S("h")
+_S("i")
+_S("j")
+_S("k")
+_S("l")
+_S("m")
+_S("n")
+_S("o")
+_S("p")
+_S("q")
+_S("r")
+_S("s")
+_S("t")
+_S("u")
+_S("v")
+_S("w")
+_S("x")
+_S("y")
+_S("z")
+_S("braceleft")
+_S("bar")
+_S("braceright")
+_S("asciitilde")
+_S("Adieresis")
+_S("Aring")
+_S("Ccedilla")
+_S("Eacute")
+_S("Ntilde")
+_S("Odieresis")
+_S("Udieresis")
+_S("aacute")
+_S("agrave")
+_S("acircumflex")
+_S("adieresis")
+_S("atilde")
+_S("aring")
+_S("ccedilla")
+_S("eacute")
+_S("egrave")
+_S("ecircumflex")
+_S("edieresis")
+_S("iacute")
+_S("igrave")
+_S("icircumflex")
+_S("idieresis")
+_S("ntilde")
+_S("oacute")
+_S("ograve")
+_S("ocircumflex")
+_S("odieresis")
+_S("otilde")
+_S("uacute")
+_S("ugrave")
+_S("ucircumflex")
+_S("udieresis")
+_S("dagger")
+_S("degree")
+_S("cent")
+_S("sterling")
+_S("section")
+_S("bullet")
+_S("paragraph")
+_S("germandbls")
+_S("registered")
+_S("copyright")
+_S("trademark")
+_S("acute")
+_S("dieresis")
+_S("notequal")
+_S("AE")
+_S("Oslash")
+_S("infinity")
+_S("plusminus")
+_S("lessequal")
+_S("greaterequal")
+_S("yen")
+_S("mu")
+_S("partialdiff")
+_S("summation")
+_S("product")
+_S("pi")
+_S("integral")
+_S("ordfeminine")
+_S("ordmasculine")
+_S("Omega")
+_S("ae")
+_S("oslash")
+_S("questiondown")
+_S("exclamdown")
+_S("logicalnot")
+_S("radical")
+_S("florin")
+_S("approxequal")
+_S("Delta")
+_S("guillemotleft")
+_S("guillemotright")
+_S("ellipsis")
+_S("nonbreakingspace")
+_S("Agrave")
+_S("Atilde")
+_S("Otilde")
+_S("OE")
+_S("oe")
+_S("endash")
+_S("emdash")
+_S("quotedblleft")
+_S("quotedblright")
+_S("quoteleft")
+_S("quoteright")
+_S("divide")
+_S("lozenge")
+_S("ydieresis")
+_S("Ydieresis")
+_S("fraction")
+_S("currency")
+_S("guilsinglleft")
+_S("guilsinglright")
+_S("fi")
+_S("fl")
+_S("daggerdbl")
+_S("periodcentered")
+_S("quotesinglbase")
+_S("quotedblbase")
+_S("perthousand")
+_S("Acircumflex")
+_S("Ecircumflex")
+_S("Aacute")
+_S("Edieresis")
+_S("Egrave")
+_S("Iacute")
+_S("Icircumflex")
+_S("Idieresis")
+_S("Igrave")
+_S("Oacute")
+_S("Ocircumflex")
+_S("apple")
+_S("Ograve")
+_S("Uacute")
+_S("Ucircumflex")
+_S("Ugrave")
+_S("dotlessi")
+_S("circumflex")
+_S("tilde")
+_S("macron")
+_S("breve")
+_S("dotaccent")
+_S("ring")
+_S("cedilla")
+_S("hungarumlaut")
+_S("ogonek")
+_S("caron")
+_S("Lslash")
+_S("lslash")
+_S("Scaron")
+_S("scaron")
+_S("Zcaron")
+_S("zcaron")
+_S("brokenbar")
+_S("Eth")
+_S("eth")
+_S("Yacute")
+_S("yacute")
+_S("Thorn")
+_S("thorn")
+_S("minus")
+_S("multiply")
+_S("onesuperior")
+_S("twosuperior")
+_S("threesuperior")
+_S("onehalf")
+_S("onequarter")
+_S("threequarters")
+_S("franc")
+_S("Gbreve")
+_S("gbreve")
+_S("Idotaccent")
+_S("Scedilla")
+_S("scedilla")
+_S("Cacute")
+_S("cacute")
+_S("Ccaron")
+_S("ccaron")
+_S("dcroat")
+
+
+#endif /* HB_OT_POST_MACROMAN_HH */
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index 82ab388..7f1c2c4 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -28,7 +28,15 @@
 #define HB_OT_POST_TABLE_HH
 
 #include "hb-open-type-private.hh"
+#include "hb-dsalgs.hh"
 
+#define HB_STRING_ARRAY_NAME format1_names
+#define HB_STRING_ARRAY_LIST "hb-ot-post-macroman.hh"
+#include "hb-string-array.hh"
+#undef HB_STRING_ARRAY_LIST
+#undef HB_STRING_ARRAY_NAME
+
+#define NUM_FORMAT1_NAMES 258
 
 namespace OT {
 
@@ -45,16 +53,13 @@
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (numberOfGlyphs.sanitize (c) &&
-		  c->check_array (glyphNameIndex, sizeof (USHORT), numberOfGlyphs));
+    return_trace (glyphNameIndex.sanitize (c));
   }
 
-  USHORT	numberOfGlyphs;		/* Number of glyphs (this should be the
-					 * same as numGlyphs in 'maxp' table). */
-  USHORT	glyphNameIndex[VAR];	/* This is not an offset, but is the
+  ArrayOf<UINT16>glyphNameIndex;	/* This is not an offset, but is the
 					 * ordinal number of the glyph in 'post'
 					 * string tables. */
-  BYTE		namesX[VAR];		/* Glyph names with length bytes [variable]
+  UINT8		namesX[VAR];		/* Glyph names with length bytes [variable]
 					 * (a Pascal string). */
 
   DEFINE_SIZE_ARRAY2 (2, glyphNameIndex, namesX);
@@ -71,12 +76,170 @@
       return_trace (false);
     if (version.to_int () == 0x00020000)
     {
-      const postV2Tail &v2 = StructAfter<postV2Tail>(*this);
+      const postV2Tail &v2 = StructAfter<postV2Tail> (*this);
       return_trace (v2.sanitize (c));
     }
     return_trace (true);
   }
 
+  struct accelerator_t
+  {
+    inline void init (hb_face_t *face)
+    {
+      blob = Sanitizer<post>::sanitize (face->reference_table (HB_OT_TAG_post));
+      const post *table = Sanitizer<post>::lock_instance (blob);
+      unsigned int table_length = hb_blob_get_length (blob);
+
+      version = table->version.to_int ();
+      index_to_offset.init ();
+      if (version != 0x00020000)
+        return;
+
+      const postV2Tail &v2 = StructAfter<postV2Tail> (*table);
+
+      glyphNameIndex = &v2.glyphNameIndex;
+      pool = &StructAfter<uint8_t> (v2.glyphNameIndex);
+
+      const uint8_t *end = (uint8_t *) table + table_length;
+      for (const uint8_t *data = pool; data < end && data + *data <= end; data += 1 + *data)
+      {
+	uint32_t *offset = index_to_offset.push ();
+	if (unlikely (!offset))
+	  break;
+	*offset = data - pool;
+      }
+    }
+    inline void fini (void)
+    {
+      index_to_offset.finish ();
+      free (gids_sorted_by_name);
+    }
+
+    inline bool get_glyph_name (hb_codepoint_t glyph,
+				char *buf, unsigned int buf_len) const
+    {
+      hb_string_t s = find_glyph_name (glyph);
+      if (!s.len)
+        return false;
+      if (!buf_len)
+	return true;
+      if (buf_len <= s.len) /* What to do with truncation? Returning false for now. */
+        return false;
+      strncpy (buf, s.bytes, s.len);
+      buf[s.len] = '\0';
+      return true;
+    }
+
+    inline bool get_glyph_from_name (const char *name, int len,
+				     hb_codepoint_t *glyph) const
+    {
+      unsigned int count = get_glyph_count ();
+      if (unlikely (!count))
+        return false;
+
+      if (len < 0)
+	len = strlen (name);
+
+      if (unlikely (!len))
+	return false;
+
+    retry:
+      uint16_t *gids = (uint16_t *) hb_atomic_ptr_get (&gids_sorted_by_name);
+
+      if (unlikely (!gids))
+      {
+	gids = (uint16_t *) malloc (count * sizeof (gids[0]));
+	if (unlikely (!gids))
+	  return false; /* Anything better?! */
+
+	for (unsigned int i = 0; i < count; i++)
+	  gids[i] = i;
+	hb_sort_r (gids, count, sizeof (gids[0]), cmp_gids, (void *) this);
+
+	if (!hb_atomic_ptr_cmpexch (&gids_sorted_by_name, nullptr, gids)) {
+	  free (gids);
+	  goto retry;
+	}
+      }
+
+      hb_string_t st (name, len);
+      const uint16_t *gid = (const uint16_t *) hb_bsearch_r (&st, gids, count, sizeof (gids[0]), cmp_key, (void *) this);
+      if (gid)
+      {
+	*glyph = *gid;
+	return true;
+      }
+
+      return false;
+    }
+
+    protected:
+
+    inline unsigned int get_glyph_count (void) const
+    {
+      if (version == 0x00010000)
+        return NUM_FORMAT1_NAMES;
+
+      if (version == 0x00020000)
+        return glyphNameIndex->len;
+
+      return 0;
+    }
+
+    static inline int cmp_gids (const void *pa, const void *pb, void *arg)
+    {
+      const accelerator_t *thiz = (const accelerator_t *) arg;
+      uint16_t a = * (const uint16_t *) pa;
+      uint16_t b = * (const uint16_t *) pb;
+      return thiz->find_glyph_name (b).cmp (thiz->find_glyph_name (a));
+    }
+
+    static inline int cmp_key (const void *pk, const void *po, void *arg)
+    {
+      const accelerator_t *thiz = (const accelerator_t *) arg;
+      const hb_string_t *key = (const hb_string_t *) pk;
+      uint16_t o = * (const uint16_t *) po;
+      return thiz->find_glyph_name (o).cmp (*key);
+    }
+
+    inline hb_string_t find_glyph_name (hb_codepoint_t glyph) const
+    {
+      if (version == 0x00010000)
+      {
+	if (glyph >= NUM_FORMAT1_NAMES)
+	  return hb_string_t ();
+
+	return format1_names (glyph);
+      }
+
+      if (version != 0x00020000 || glyph >= glyphNameIndex->len)
+	return hb_string_t ();
+
+      unsigned int index = glyphNameIndex->array[glyph];
+      if (index < NUM_FORMAT1_NAMES)
+	return format1_names (index);
+      index -= NUM_FORMAT1_NAMES;
+
+      if (index >= index_to_offset.len)
+	return hb_string_t ();
+      unsigned int offset = index_to_offset.array[index];
+
+      const uint8_t *data = pool + offset;
+      unsigned int name_length = *data;
+      data++;
+
+      return hb_string_t ((const char *) data, name_length);
+    }
+
+    private:
+    hb_blob_t *blob;
+    uint32_t version;
+    const ArrayOf<UINT16> *glyphNameIndex;
+    hb_prealloced_array_t<uint32_t, 1> index_to_offset;
+    const uint8_t *pool;
+    mutable uint16_t *gids_sorted_by_name;
+  };
+
   public:
   FixedVersion<>version;		/* 0x00010000 for version 1.0
 					 * 0x00020000 for version 2.0
@@ -98,16 +261,16 @@
 					 * from the value of this field. */
   FWORD		underlineThickness;	/* Suggested values for the underline
 					   thickness. */
-  ULONG		isFixedPitch;		/* Set to 0 if the font is proportionally
+  UINT32		isFixedPitch;		/* Set to 0 if the font is proportionally
 					 * spaced, non-zero if the font is not
 					 * proportionally spaced (i.e. monospaced). */
-  ULONG		minMemType42;		/* Minimum memory usage when an OpenType font
+  UINT32		minMemType42;		/* Minimum memory usage when an OpenType font
 					 * is downloaded. */
-  ULONG		maxMemType42;		/* Maximum memory usage when an OpenType font
+  UINT32		maxMemType42;		/* Maximum memory usage when an OpenType font
 					 * is downloaded. */
-  ULONG		minMemType1;		/* Minimum memory usage when an OpenType font
+  UINT32		minMemType1;		/* Minimum memory usage when an OpenType font
 					 * is downloaded as a Type 1 font. */
-  ULONG		maxMemType1;		/* Maximum memory usage when an OpenType font
+  UINT32		maxMemType1;		/* Maximum memory usage when an OpenType font
 					 * is downloaded as a Type 1 font. */
 /*postV2Tail	v2[VAR];*/
   DEFINE_SIZE_STATIC (32);
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index d97d285..d98cde1 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -73,11 +73,11 @@
   }
 
   if (!num_glyphs)
-    return NULL;
+    return nullptr;
 
   /* 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, OT::GlyphID::cmp, &substitutes[0]);
+  hb_stable_sort (&glyphs[0], num_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &substitutes[0]);
 
   OT::Supplier<OT::GlyphID> glyphs_supplier      (glyphs, num_glyphs);
   OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
@@ -94,7 +94,7 @@
   c.end_serialize ();
   /* TODO sanitize the results? */
 
-  return ret ? c.copy<OT::SubstLookup> () : NULL;
+  return ret ? c.copy<OT::SubstLookup> () : nullptr;
 }
 
 static OT::SubstLookup *
@@ -126,7 +126,7 @@
     first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
     num_first_glyphs++;
   }
-  hb_stable_sort (&first_glyphs[0], num_first_glyphs, OT::GlyphID::cmp, &first_glyphs_indirection[0]);
+  hb_stable_sort (&first_glyphs[0], num_first_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::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++)
@@ -153,7 +153,7 @@
   }
 
   if (!num_ligatures)
-    return NULL;
+    return nullptr;
 
   OT::Supplier<OT::GlyphID>   first_glyphs_supplier                      (first_glyphs, num_first_glyphs);
   OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier    (ligature_per_first_glyph_count_list, num_first_glyphs);
@@ -177,7 +177,7 @@
   c.end_serialize ();
   /* TODO sanitize the results? */
 
-  return ret ? c.copy<OT::SubstLookup> () : NULL;
+  return ret ? c.copy<OT::SubstLookup> () : nullptr;
 }
 
 static OT::SubstLookup *
@@ -237,8 +237,8 @@
     return false;
 
   const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
-  ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
-		 <= ARABIC_FALLBACK_MAX_LOOKUPS);
+  static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
+		 <= ARABIC_FALLBACK_MAX_LOOKUPS, "");
   /* TODO sanitize the table? */
 
   unsigned j = 0;
@@ -271,7 +271,7 @@
 				   const hb_ot_shape_plan_t *plan,
 				   hb_font_t *font)
 {
-  ASSERT_STATIC (ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS);
+  static_assert ((ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), "");
   unsigned int j = 0;
   for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
   {
diff --git a/src/hb-ot-shape-complex-arabic-table.hh b/src/hb-ot-shape-complex-arabic-table.hh
index 736c7f7..cd6e405 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-9.0.0.txt
- * # Date: 2016-02-24, 22:25:00 GMT [RP]
- * # Blocks-9.0.0.txt
- * # Date: 2016-02-05, 23:48:00 GMT [KW]
+ * # ArabicShaping-10.0.0.txt
+ * # Date: 2017-02-16, 00:00:00 GMT [RP, KW]
+ * # Blocks-10.0.0.txt
+ * # Date: 2017-04-12, 17:30:00 GMT [KW]
  * UnicodeData.txt does not have a header.
  */
 
@@ -72,7 +72,10 @@
   /* Mandaic */
 
   /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,U,U,U,X,X,X,X,X,X,X,
-  /* 0860 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+  /* Syriac Supplement */
+
+  /* 0860 */ D,U,D,D,D,D,U,R,D,R,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
   /* 0880 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
 
   /* Arabic Extended-A */
@@ -130,7 +133,7 @@
   /* 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,
 
-}; /* Table items: 1214; occupancy: 54% */
+}; /* Table items: 1214; occupancy: 55% */
 
 
 static unsigned int
@@ -139,28 +142,28 @@
   switch (u >> 12)
   {
     case 0x0u:
-      if (hb_in_range (u, 0x0600u, 0x08E2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x0600u, 0x08E2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
       break;
 
     case 0x1u:
-      if (hb_in_range (u, 0x1806u, 0x18AAu)) return joining_table[u - 0x1806u + joining_offset_0x1806u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1806u, 0x18AAu)) return joining_table[u - 0x1806u + joining_offset_0x1806u];
       break;
 
     case 0x2u:
-      if (hb_in_range (u, 0x200Cu, 0x2069u)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
+      if (hb_in_range<hb_codepoint_t> (u, 0x200Cu, 0x2069u)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
       break;
 
     case 0xAu:
-      if (hb_in_range (u, 0xA840u, 0xA873u)) return joining_table[u - 0xA840u + joining_offset_0xa840u];
+      if (hb_in_range<hb_codepoint_t> (u, 0xA840u, 0xA873u)) return joining_table[u - 0xA840u + joining_offset_0xa840u];
       break;
 
     case 0x10u:
-      if (hb_in_range (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
-      if (hb_in_range (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
       break;
 
     case 0x1Eu:
-      if (hb_in_range (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
       break;
 
     default:
diff --git a/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shape-complex-arabic-win1256.hh
index e70c48f..54c6cdc 100644
--- a/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -43,16 +43,16 @@
 #define OT_TABLE_END			}
 #define OT_LABEL_START(Name)		unsigned char Name[
 #define OT_LABEL_END			];
-#define OT_BYTE(u8)			+1/*byte*/
-#define OT_USHORT(u16)			+2/*bytes*/
+#define OT_UINT8(u8)			+1/*byte*/
+#define OT_UINT16(u16)			+2/*bytes*/
 #else
 #undef  OT_MEASURE
 #define OT_TABLE_START			TABLE_NAME = {
 #define OT_TABLE_END			};
 #define OT_LABEL_START(Name)		{
 #define OT_LABEL_END			},
-#define OT_BYTE(u8)			(u8),
-#define OT_USHORT(u16)			(unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
+#define OT_UINT8(u8)			(u8),
+#define OT_UINT16(u16)			(unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
 #define OT_COUNT(Name, ItemSize)	((unsigned int) sizeof(((struct TABLE_NAME*)0)->Name) \
 					 / (unsigned int)(ItemSize) \
 					 /* OT_ASSERT it's divisible (and positive). */)
@@ -80,24 +80,24 @@
  */
 
 #define OT_TAG(a,b,c,d) \
-	OT_BYTE(a) OT_BYTE(b) OT_BYTE(c) OT_BYTE(d)
+	OT_UINT8(a) OT_UINT8(b) OT_UINT8(c) OT_UINT8(d)
 
 #define OT_OFFSET(From, To) /* Offset from From to To in bytes */ \
-	OT_USHORT(OT_DISTANCE(From, To))
+	OT_UINT16(OT_DISTANCE(From, To))
 
 #define OT_GLYPHID /* GlyphID */ \
-	OT_USHORT
+	OT_UINT16
 
 #define OT_UARRAY(Name, Items) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(OT_COUNT(Name##Data, 2)) \
+	OT_UINT16(OT_COUNT(Name##Data, 2)) \
 	OT_LABEL(Name##Data) \
 	Items \
 	OT_LABEL_END
 
 #define OT_UHEADLESSARRAY(Name, Items) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(OT_COUNT(Name##Data, 2) + 1) \
+	OT_UINT16(OT_COUNT(Name##Data, 2) + 1) \
 	OT_LABEL(Name##Data) \
 	Items \
 	OT_LABEL_END
@@ -111,19 +111,19 @@
 
 #define OT_LOOKUP(Name, LookupType, LookupFlag, SubLookupOffsets) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(LookupType) \
-	OT_USHORT(LookupFlag) \
+	OT_UINT16(LookupType) \
+	OT_UINT16(LookupFlag) \
 	OT_LABEL_END \
 	OT_UARRAY(Name##SubLookupOffsetsArray, OT_LIST(SubLookupOffsets))
 
 #define OT_SUBLOOKUP(Name, SubFormat, Items) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(SubFormat) \
+	OT_UINT16(SubFormat) \
 	Items
 
 #define OT_COVERAGE1(Name, Items) \
 	OT_LABEL_START(Name) \
-	OT_USHORT(1) \
+	OT_UINT16(1) \
 	OT_LABEL_END \
 	OT_UARRAY(Name##Glyphs, OT_LIST(Items))
 
@@ -174,7 +174,7 @@
 /* Table manifest. */
 #define MANIFEST(Items) \
 	OT_LABEL_START(manifest) \
-	OT_USHORT(OT_COUNT(manifestData, 6)) \
+	OT_UINT16(OT_COUNT(manifestData, 6)) \
 	OT_LABEL(manifestData) \
 	Items \
 	OT_LABEL_END
@@ -304,8 +304,8 @@
 #undef OT_TABLE_END
 #undef OT_LABEL_START
 #undef OT_LABEL_END
-#undef OT_BYTE
-#undef OT_USHORT
+#undef OT_UINT8
+#undef OT_UINT16
 #undef OT_DISTANCE
 #undef OT_COUNT
 
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 56ec5cd..eb9d36f 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -24,24 +24,21 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb-private.hh"
+#include "hb-debug.hh"
 #include "hb-ot-shape-complex-arabic-private.hh"
 #include "hb-ot-shape-private.hh"
 
 
-#ifndef HB_DEBUG_ARABIC
-#define HB_DEBUG_ARABIC (HB_DEBUG+0)
-#endif
-
-
 /* buffer var allocations */
 #define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
 
 #define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
 
 /* See:
- * https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
+ * https://github.com/harfbuzz/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
 #define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
-	(FLAG_SAFE (gen_cat) & \
+	(FLAG_UNSAFE (gen_cat) & \
 	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
 	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
@@ -90,7 +87,7 @@
   if (likely (j_type != JOINING_TYPE_X))
     return j_type;
 
-  return (FLAG_SAFE(gen_cat) &
+  return (FLAG_UNSAFE(gen_cat) &
 	  (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
 	   FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
 	   FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
@@ -199,6 +196,9 @@
    * work.  However, testing shows that rlig and calt are applied
    * together for Mongolian in Uniscribe.  As such, we only add a
    * pause for Arabic, not other scripts.
+   *
+   * A pause after calt is required to make KFGQPC Uthmanic Script HAFS
+   * work correctly.  See https://github.com/harfbuzz/harfbuzz/issues/505
    */
 
   map->add_gsub_pause (nuke_joiners);
@@ -209,20 +209,23 @@
   map->add_global_bool_feature (HB_TAG('c','c','m','p'));
   map->add_global_bool_feature (HB_TAG('l','o','c','l'));
 
-  map->add_gsub_pause (NULL);
+  map->add_gsub_pause (nullptr);
 
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
   {
     bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
     map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
-    map->add_gsub_pause (NULL);
+    map->add_gsub_pause (nullptr);
   }
 
   map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
   if (plan->props.script == HB_SCRIPT_ARABIC)
     map->add_gsub_pause (arabic_fallback_shape);
 
+  /* No pause after rclt.  See 98460779bae19e4d64d29461ff154b3527bf8420. */
+  map->add_global_bool_feature (HB_TAG('r','c','l','t'));
   map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+  map->add_gsub_pause (nullptr);
 
   /* The spec includes 'cswh'.  Earlier versions of Windows
    * used to enable this by default, but testing suggests
@@ -232,7 +235,6 @@
    * Note that IranNastaliq uses this feature extensively
    * to fixup broken glyph sequences.  Oh well...
    * Test case: U+0643,U+0640,U+0631. */
-  //map->add_gsub_pause (NULL);
   //map->add_global_bool_feature (HB_TAG('c','s','w','h'));
   map->add_global_bool_feature (HB_TAG('m','s','e','t'));
 }
@@ -260,7 +262,7 @@
 {
   arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
   if (unlikely (!arabic_plan))
-    return NULL;
+    return nullptr;
 
   arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
   arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
@@ -316,7 +318,10 @@
     const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
 
     if (entry->prev_action != NONE && prev != (unsigned int) -1)
+    {
       info[prev].arabic_shaping_action() = entry->prev_action;
+      buffer->unsafe_to_break (prev, i + 1);
+    }
 
     info[i].arabic_shaping_action() = entry->curr_action;
 
@@ -345,7 +350,7 @@
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
-    if (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du)))
+    if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x180Bu, 0x180Du)))
       info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
 }
 
@@ -404,7 +409,7 @@
   {
     /* This sucks.  We need a font to build the fallback plan... */
     fallback_plan = arabic_fallback_plan_create (plan, font);
-    if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) {
+    if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, nullptr, fallback_plan))) {
       arabic_fallback_plan_destroy (fallback_plan);
       goto retry;
     }
@@ -524,11 +529,11 @@
       }
       i++; // Don't touch i again.
 
-      DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)",
+      DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%d,%d,%d)",
 		 step == MEASURE ? "measuring" : "cutting", context, start, end);
-      DEBUG_MSG (ARABIC, NULL, "rest of word:    count=%d width %d", start - context, w_total);
-      DEBUG_MSG (ARABIC, NULL, "fixed tiles:     count=%d width=%d", n_fixed, w_fixed);
-      DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
+      DEBUG_MSG (ARABIC, nullptr, "rest of word:    count=%d width %d", start - context, w_total);
+      DEBUG_MSG (ARABIC, nullptr, "fixed tiles:     count=%d width=%d", n_fixed, w_fixed);
+      DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
 
       /* Number of additional times to repeat each repeating tile. */
       int n_copies = 0;
@@ -540,7 +545,7 @@
       /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */
       hb_position_t extra_repeat_overlap = 0;
       hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
-      if (shortfall > 0)
+      if (shortfall > 0 && n_repeating > 0)
       {
         ++n_copies;
         hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
@@ -551,10 +556,11 @@
       if (step == MEASURE)
       {
 	extra_glyphs_needed += n_copies * n_repeating;
-	DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
+	DEBUG_MSG (ARABIC, nullptr, "will add extra %d copies of repeating tiles", n_copies);
       }
       else
       {
+	buffer->unsafe_to_break (context, end);
 	hb_position_t x_offset = 0;
 	for (unsigned int k = end; k > start; k--)
 	{
@@ -564,7 +570,7 @@
 	  if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
 	    repeat += n_copies;
 
-	  DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
+	  DEBUG_MSG (ARABIC, nullptr, "appending %d copies of glyph %d; j=%d",
 		     repeat, info[k - 1].codepoint, j);
 	  for (unsigned int n = 0; n < repeat; n++)
 	  {
@@ -605,20 +611,94 @@
   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
 
+/* http://www.unicode.org/reports/tr53/tr53-1.pdf */
+
+static hb_codepoint_t
+modifier_combining_marks[] =
+{
+  0x0654u, /* ARABIC HAMZA ABOVE */
+  0x0655u, /* ARABIC HAMZA BELOW */
+  0x0658u, /* ARABIC MARK NOON GHUNNA */
+  0x06DCu, /* ARABIC SMALL HIGH SEEN */
+  0x06E3u, /* ARABIC SMALL LOW SEEN */
+  0x06E7u, /* ARABIC SMALL HIGH YEH */
+  0x06E8u, /* ARABIC SMALL HIGH NOON */
+  0x08F3u, /* ARABIC SMALL HIGH WAW */
+};
+
+static inline bool
+info_is_mcm (const hb_glyph_info_t &info)
+{
+  hb_codepoint_t u = info.codepoint;
+  for (unsigned int i = 0; i < ARRAY_LENGTH (modifier_combining_marks); i++)
+    if (u == modifier_combining_marks[i])
+      return true;
+  return false;
+}
+
+static void
+reorder_marks_arabic (const hb_ot_shape_plan_t *plan,
+		      hb_buffer_t              *buffer,
+		      unsigned int              start,
+		      unsigned int              end)
+{
+  hb_glyph_info_t *info = buffer->info;
+
+  unsigned int i = start;
+  for (unsigned int cc = 220; cc <= 230; cc += 10)
+  {
+    DEBUG_MSG (ARABIC, buffer, "Looking for %d's starting at %d\n", cc, i);
+    while (i < end && info_cc(info[i]) < cc)
+      i++;
+    DEBUG_MSG (ARABIC, buffer, "Looking for %d's stopped at %d\n", cc, i);
+
+    if (i == end)
+      break;
+
+    if (info_cc(info[i]) > cc)
+      continue;
+
+    /* Technically we should also check "info_cc(info[j]) == cc"
+     * in the following loop.  But not doing it is safe; we might
+     * end up moving all the 220 MCMs and 230 MCMs together in one
+     * move and be done. */
+    unsigned int j = i;
+    while (j < end && info_is_mcm (info[j]))
+      j++;
+    DEBUG_MSG (ARABIC, buffer, "Found %d's from %d to %d\n", cc, i, j);
+
+    if (i == j)
+      continue;
+
+    /* Shift it! */
+    DEBUG_MSG (ARABIC, buffer, "Shifting %d's: %d %d\n", cc, i, j);
+    hb_glyph_info_t temp[HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS];
+    assert (j - i <= ARRAY_LENGTH (temp));
+    buffer->merge_clusters (start, j);
+    memmove (temp, &info[i], (j - i) * sizeof (hb_glyph_info_t));
+    memmove (&info[start + j - i], &info[start], (i - start) * sizeof (hb_glyph_info_t));
+    memmove (&info[start], temp, (j - i) * sizeof (hb_glyph_info_t));
+
+    start += j - i;
+
+    i = j;
+  }
+}
+
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
 {
-  "arabic",
   collect_features_arabic,
-  NULL, /* override_features */
+  nullptr, /* override_features */
   data_create_arabic,
   data_destroy_arabic,
-  NULL, /* preprocess_text */
+  nullptr, /* preprocess_text */
   postprocess_glyphs_arabic,
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
+  nullptr, /* decompose */
+  nullptr, /* compose */
   setup_masks_arabic,
-  NULL, /* disable_otl */
+  nullptr, /* disable_otl */
+  reorder_marks_arabic,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
diff --git a/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shape-complex-default.cc
index 42830ab..68a62a1 100644
--- a/src/hb-ot-shape-complex-default.cc
+++ b/src/hb-ot-shape-complex-default.cc
@@ -29,18 +29,18 @@
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
 {
-  "default",
-  NULL, /* collect_features */
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
-  NULL, /* setup_masks */
-  NULL, /* disable_otl */
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
index af50565..7508c22 100644
--- a/src/hb-ot-shape-complex-hangul.cc
+++ b/src/hb-ot-shape-complex-hangul.cc
@@ -80,7 +80,7 @@
 {
   hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
   if (unlikely (!hangul_plan))
-    return NULL;
+    return nullptr;
 
   for (unsigned int i = 0; i < HANGUL_FEATURE_COUNT; i++)
     hangul_plan->mask_array[i] = plan->map.get_1_mask (hangul_features[i]);
@@ -105,16 +105,16 @@
 #define NCount (VCount * TCount)
 #define SCount (LCount * NCount)
 
-#define isCombiningL(u) (hb_in_range ((u), LBase, LBase+LCount-1))
-#define isCombiningV(u) (hb_in_range ((u), VBase, VBase+VCount-1))
-#define isCombiningT(u) (hb_in_range ((u), TBase+1, TBase+TCount-1))
-#define isCombinedS(u) (hb_in_range ((u), SBase, SBase+SCount-1))
+#define isCombiningL(u) (hb_in_range<hb_codepoint_t> ((u), LBase, LBase+LCount-1))
+#define isCombiningV(u) (hb_in_range<hb_codepoint_t> ((u), VBase, VBase+VCount-1))
+#define isCombiningT(u) (hb_in_range<hb_codepoint_t> ((u), TBase+1, TBase+TCount-1))
+#define isCombinedS(u) (hb_in_range<hb_codepoint_t> ((u), SBase, SBase+SCount-1))
 
-#define isL(u) (hb_in_ranges ((u), 0x1100u, 0x115Fu, 0xA960u, 0xA97Cu))
-#define isV(u) (hb_in_ranges ((u), 0x1160u, 0x11A7u, 0xD7B0u, 0xD7C6u))
-#define isT(u) (hb_in_ranges ((u), 0x11A8u, 0x11FFu, 0xD7CBu, 0xD7FBu))
+#define isL(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1100u, 0x115Fu, 0xA960u, 0xA97Cu))
+#define isV(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1160u, 0x11A7u, 0xD7B0u, 0xD7C6u))
+#define isT(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x11A8u, 0x11FFu, 0xD7CBu, 0xD7FBu))
 
-#define isHangulTone(u) (hb_in_range ((u), 0x302Eu, 0x302Fu))
+#define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302Eu, 0x302Fu))
 
 /* buffer var allocations */
 #define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
@@ -202,6 +202,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->next_glyph ();
 	if (!is_zero_width_char (font, u))
 	{
@@ -258,6 +259,7 @@
 	  else
 	    t = 0; /* The next character was not a trailing jamo. */
 	}
+	buffer->unsafe_to_break (buffer->idx, buffer->idx + (t ? 3 : 2));
 
 	/* We've got a syllable <L,V,T?>; see if it can potentially be composed. */
 	if (isCombiningL (l) && isCombiningV (v) && (t == 0 || isCombiningT (t)))
@@ -322,6 +324,8 @@
 	  end = start + 1;
 	  continue;
 	}
+	else
+	  buffer->unsafe_to_break (buffer->idx, buffer->idx + 2); /* Mark unsafe between LV and T. */
       }
 
       /* Otherwise, decompose if font doesn't support <LV> or <LVT>,
@@ -368,6 +372,8 @@
 	    buffer->merge_out_clusters (start, end);
 	  continue;
 	}
+	else if ((!tindex && buffer->idx + 1 < count && isT (buffer->cur(+1).codepoint)))
+	  buffer->unsafe_to_break (buffer->idx, buffer->idx + 2); /* Mark unsafe between LV and T. */
       }
 
       if (has_glyph)
@@ -408,18 +414,18 @@
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
 {
-  "hangul",
   collect_features_hangul,
   override_features_hangul,
   data_create_hangul,
   data_destroy_hangul,
   preprocess_text_hangul,
-  NULL, /* postprocess_glyphs */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
-  NULL, /* decompose */
-  NULL, /* compose */
+  nullptr, /* decompose */
+  nullptr, /* compose */
   setup_masks_hangul,
-  NULL, /* disable_otl */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
diff --git a/src/hb-ot-shape-complex-hebrew.cc b/src/hb-ot-shape-complex-hebrew.cc
index 96f2494..34cf28b 100644
--- a/src/hb-ot-shape-complex-hebrew.cc
+++ b/src/hb-ot-shape-complex-hebrew.cc
@@ -161,7 +161,7 @@
    * script.  This matches Uniscribe better, and makes fonts like
    * Arial that have GSUB/GPOS/GDEF but no data for Hebrew work.
    * See:
-   * https://github.com/behdad/harfbuzz/issues/347#issuecomment-267838368
+   * https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368
    */
   return plan->map.chosen_script[1] != HB_TAG ('h','e','b','r');
 }
@@ -169,18 +169,18 @@
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
 {
-  "hebrew",
-  NULL, /* collect_features */
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
+  nullptr, /* decompose */
   compose_hebrew,
-  NULL, /* setup_masks */
+  nullptr, /* setup_masks */
   disable_otl_hebrew,
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl
index 86a7ceb..58d35c0 100644
--- a/src/hb-ot-shape-complex-indic-machine.rl
+++ b/src/hb-ot-shape-complex-indic-machine.rl
@@ -57,6 +57,7 @@
 Ra    = 16;
 CM    = 17;
 Symbol= 18;
+CS    = 19;
 
 c = (C | Ra);			# is_consonant
 n = ((ZWNJ?.RS)? (N.N?)?);	# is_consonant_modifier
@@ -76,9 +77,9 @@
 halant_or_matra_group = (final_halant_group | (h.ZWJ)? matra_group{0,4}) (Coeng (cn|V))?;
 
 
-consonant_syllable =	Repha? (cn.halant_group){0,4} cn medial_group halant_or_matra_group syllable_tail;
+consonant_syllable =	(Repha|CS)? (cn.halant_group){0,4} cn medial_group halant_or_matra_group syllable_tail;
 vowel_syllable =	reph? V.n? (ZWJ | (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail);
-standalone_cluster =	(Repha? PLACEHOLDER | reph? DOTTEDCIRCLE).n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
+standalone_cluster =	((Repha|CS)? PLACEHOLDER | reph? DOTTEDCIRCLE).n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
 symbol_cluster = 	symbol syllable_tail;
 broken_cluster =	reph? n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
 other =			any;
diff --git a/src/hb-ot-shape-complex-indic-private.hh b/src/hb-ot-shape-complex-indic-private.hh
index bb975e3..a1e0d52 100644
--- a/src/hb-ot-shape-complex-indic-private.hh
+++ b/src/hb-ot-shape-complex-indic-private.hh
@@ -60,7 +60,8 @@
   OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
   OT_Ra = 16,
   OT_CM = 17,  /* Consonant-Medial. */
-  OT_Symbol = 18 /* Avagraha, etc that take marks (SM,A,VD). */
+  OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
+  OT_CS = 19
 };
 
 #define MEDIAL_FLAGS (FLAG (OT_CM))
@@ -70,7 +71,7 @@
  * 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_Ra) | MEDIAL_FLAGS | 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))
 #define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
 
@@ -121,8 +122,8 @@
   INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED		= OT_X, /* Don't care. */
   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED		= OT_CM,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA	= OT_N,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER	= OT_C,
-  INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK		= OT_SM,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER	= OT_CS,
+  INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK		= OT_SM, /* https://github.com/harfbuzz/harfbuzz/issues/552 */
   INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER		= OT_Coeng,
   INDIC_SYLLABIC_CATEGORY_JOINER			= OT_ZWJ,
   INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER		= OT_X,
@@ -132,7 +133,7 @@
   INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER			= OT_PLACEHOLDER, /* Don't care. */
   INDIC_SYLLABIC_CATEGORY_PURE_KILLER			= OT_M, /* Is like a vowel matra. */
   INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER		= OT_RS,
-  INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER		= OT_M, /* Misc Khmer signs. */
+  INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER		= OT_SM,
   INDIC_SYLLABIC_CATEGORY_TONE_LETTER			= OT_X,
   INDIC_SYLLABIC_CATEGORY_TONE_MARK			= OT_N,
   INDIC_SYLLABIC_CATEGORY_VIRAMA			= OT_H,
diff --git a/src/hb-ot-shape-complex-indic-table.cc b/src/hb-ot-shape-complex-indic-table.cc
index 80a6b25..bfd1c6d 100644
--- a/src/hb-ot-shape-complex-indic-table.cc
+++ b/src/hb-ot-shape-complex-indic-table.cc
@@ -6,61 +6,62 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-9.0.0.txt
- * # Date: 2016-05-21, 02:46:00 GMT [RP]
- * # IndicPositionalCategory-9.0.0.txt
- * # Date: 2016-02-25, 00:48:00 GMT [RP]
- * # Blocks-9.0.0.txt
- * # Date: 2016-02-05, 23:48:00 GMT [KW]
+ * # IndicSyllabicCategory-10.0.0.txt
+ * # Date: 2017-05-31, 01:07:00 GMT [KW, RP]
+ * # IndicPositionalCategory-10.0.0.txt
+ * # Date: 2017-05-31, 01:07:00 GMT [RP]
+ * # Blocks-10.0.0.txt
+ * # Date: 2017-04-12, 17:30:00 GMT [KW]
  */
 
 #include "hb-ot-shape-complex-indic-private.hh"
 
 
 #define ISC_A	INDIC_SYLLABIC_CATEGORY_AVAGRAHA		/*  15 chars; Avagraha */
-#define ISC_Bi	INDIC_SYLLABIC_CATEGORY_BINDU			/*  67 chars; Bindu */
+#define ISC_Bi	INDIC_SYLLABIC_CATEGORY_BINDU			/*  80 chars; Bindu */
 #define ISC_BJN	INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER	/*  20 chars; Brahmi_Joining_Number */
-#define ISC_Ca	INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK	/*  53 chars; Cantillation_Mark */
-#define ISC_C	INDIC_SYLLABIC_CATEGORY_CONSONANT		/* 1907 chars; Consonant */
+#define ISC_Ca	INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK	/*  57 chars; Cantillation_Mark */
+#define ISC_C	INDIC_SYLLABIC_CATEGORY_CONSONANT		/* 2024 chars; Consonant */
 #define ISC_CD	INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD		/*  10 chars; Consonant_Dead */
-#define ISC_CF	INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL		/*  62 chars; Consonant_Final */
+#define ISC_CF	INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL		/*  68 chars; Consonant_Final */
 #define ISC_CHL	INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER	/*   5 chars; Consonant_Head_Letter */
 #define ISC_CK	INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER	/*   2 chars; Consonant_Killer */
-#define ISC_CM	INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL	/*  22 chars; Consonant_Medial */
-#define ISC_CP	INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER	/*  16 chars; Consonant_Placeholder */
-#define ISC_CPR	INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA	/*   1 chars; Consonant_Preceding_Repha */
-#define ISC_CPrf	INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED	/*   2 chars; Consonant_Prefixed */
-#define ISC_CS	INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED	/*  90 chars; Consonant_Subjoined */
-#define ISC_CSR	INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA	/*   4 chars; Consonant_Succeeding_Repha */
+#define ISC_CM	INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL	/*  27 chars; Consonant_Medial */
+#define ISC_CP	INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER	/*  18 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	/*   5 chars; Consonant_Succeeding_Repha */
 #define ISC_CWS	INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER	/*   4 chars; Consonant_With_Stacker */
-#define ISC_GM	INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK		/*   2 chars; Gemination_Mark */
-#define ISC_IS	INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER	/*   7 chars; Invisible_Stacker */
+#define ISC_GM	INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK		/*   3 chars; Gemination_Mark */
+#define ISC_IS	INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER	/*  10 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			/*  24 chars; Nukta */
-#define ISC_Nd	INDIC_SYLLABIC_CATEGORY_NUMBER			/* 459 chars; Number */
+#define ISC_N	INDIC_SYLLABIC_CATEGORY_NUKTA			/*  28 chars; Nukta */
+#define ISC_Nd	INDIC_SYLLABIC_CATEGORY_NUMBER			/* 469 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		/*  16 chars; Pure_Killer */
+#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	/*  22 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			/*  24 chars; Virama */
-#define ISC_Vs	INDIC_SYLLABIC_CATEGORY_VISARGA			/*  31 chars; Visarga */
+#define ISC_Vs	INDIC_SYLLABIC_CATEGORY_VISARGA			/*  34 chars; Visarga */
 #define ISC_Vo	INDIC_SYLLABIC_CATEGORY_VOWEL			/*  30 chars; Vowel */
-#define ISC_M	INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT		/* 602 chars; Vowel_Dependent */
-#define ISC_VI	INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT	/* 431 chars; Vowel_Independent */
+#define ISC_M	INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT		/* 633 chars; Vowel_Dependent */
+#define ISC_VI	INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT	/* 443 chars; Vowel_Independent */
 
-#define IMC_B	INDIC_MATRA_CATEGORY_BOTTOM			/* 300 chars; Bottom */
+#define IMC_B	INDIC_MATRA_CATEGORY_BOTTOM			/* 330 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			/*  57 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			/* 258 chars; Right */
-#define IMC_T	INDIC_MATRA_CATEGORY_TOP			/* 342 chars; Top */
+#define IMC_R	INDIC_MATRA_CATEGORY_RIGHT			/* 262 chars; Right */
+#define IMC_T	INDIC_MATRA_CATEGORY_TOP			/* 380 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 */
@@ -133,7 +134,7 @@
   /* 09E0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 09E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 09F0 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 09F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 09F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Bi,x),  _(x,x),  _(x,x),  _(x,x),
 
   /* Gurmukhi */
 
@@ -171,7 +172,7 @@
   /* 0AE0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 0AF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0AF8 */  _(x,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0AF8 */  _(x,x),  _(C,x), _(Ca,T), _(Ca,T), _(Ca,T),  _(N,T),  _(N,T),  _(N,T),
 
   /* Oriya */
 
@@ -251,14 +252,14 @@
 
   /* Malayalam */
 
-  /* 0D00 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0D00 */ _(Bi,T), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
   /* 0D10 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0D18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0D20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0D28 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0D30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0D38 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(A,x),  _(M,R),  _(M,R),
+  /* 0D38 */  _(C,x),  _(C,x),  _(C,x), _(PK,T), _(PK,T),  _(A,x),  _(M,R),  _(M,R),
   /* 0D40 */  _(M,R),  _(M,R),  _(M,R),  _(M,B),  _(M,B),  _(x,x),  _(M,L),  _(M,L),
   /* 0D48 */  _(M,L),  _(x,x), _(M,LR), _(M,LR), _(M,LR),  _(V,T),_(CPR,x),  _(x,x),
   /* 0D50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CD,x), _(CD,x), _(CD,x),  _(M,R),
@@ -341,7 +342,7 @@
   /* 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),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CF0 */  _(x,x),  _(x,x), _(Vs,x), _(Vs,x), _(Ca,T),  _(x,x),  _(x,x), _(Ca,R),
   /* 1CF8 */ _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
 #define indic_offset_0x2008u 1656
@@ -368,7 +369,7 @@
 
   /* A8E0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
   /* A8E8 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
-  /* A8F0 */ _(Ca,T), _(Ca,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* A8F0 */ _(Ca,T), _(Ca,T), _(Bi,x), _(Bi,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
 #define indic_offset_0xa9e0u 1720
 
@@ -390,7 +391,7 @@
   /* AA70 */  _(x,x),  _(C,x),  _(C,x),  _(C,x), _(CP,x), _(CP,x), _(CP,x),  _(x,x),
   /* AA78 */  _(x,x),  _(x,x),  _(C,x), _(TM,R), _(TM,T), _(TM,R),  _(C,x),  _(C,x),
 
-}; /* Table items: 1784; occupancy: 69% */
+}; /* Table items: 1784; occupancy: 70% */
 
 INDIC_TABLE_ELEMENT_TYPE
 hb_indic_get_categories (hb_codepoint_t u)
@@ -398,28 +399,28 @@
   switch (u >> 12)
   {
     case 0x0u:
-      if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
-      if (hb_in_range (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
-      if (hb_in_range (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
       if (unlikely (u == 0x00A0u)) return _(CP,x);
       break;
 
     case 0x1u:
-      if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
-      if (hb_in_range (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
-      if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
       break;
 
     case 0x2u:
-      if (hb_in_range (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
-      if (hb_in_range (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
       if (unlikely (u == 0x25CCu)) return _(CP,x);
       break;
 
     case 0xAu:
-      if (hb_in_range (u, 0xA8E0u, 0xA8F7u)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
-      if (hb_in_range (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
-      if (hb_in_range (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
+      if (hb_in_range<hb_codepoint_t> (u, 0xA8E0u, 0xA8F7u)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
       break;
 
     default:
@@ -467,6 +468,7 @@
 #undef ISC_VI
 
 #undef IMC_B
+#undef IMC_BL
 #undef IMC_BR
 #undef IMC_L
 #undef IMC_LR
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index b48fb56..97d6d38 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -142,7 +142,7 @@
 {
   /* If it ligated, all bets are off. */
   if (_hb_glyph_info_ligated (&info)) return false;
-  return !!(FLAG_SAFE (info.indic_category()) & flags);
+  return !!(FLAG_UNSAFE (info.indic_category()) & flags);
 }
 
 static inline bool
@@ -177,15 +177,15 @@
    */
 
   /* The following act more like the Bindus. */
-  if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
+  if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0953u, 0x0954u)))
     cat = OT_SM;
   /* The following act like consonants. */
-  else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
+  else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0x0A72u, 0x0A73u,
 				      0x1CF5u, 0x1CF6u)))
     cat = OT_C;
   /* TODO: The following should only be allowed after a Visarga.
    * For now, just treat them like regular tone marks. */
-  else if (unlikely (hb_in_range (u, 0x1CE2u, 0x1CE8u)))
+  else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1CE2u, 0x1CE8u)))
     cat = OT_A;
   /* TODO: The following should only be allowed after some of
    * the nasalization marks, maybe only for U+1CE9..U+1CF1.
@@ -193,15 +193,39 @@
   else if (unlikely (u == 0x1CEDu))
     cat = OT_A;
   /* The following take marks in standalone clusters, similar to Avagraha. */
-  else if (unlikely (hb_in_ranges (u, 0xA8F2u, 0xA8F7u,
+  else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0xA8F2u, 0xA8F7u,
 				      0x1CE9u, 0x1CECu,
 				      0x1CEEu, 0x1CF1u)))
   {
     cat = OT_Symbol;
-    ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
+    static_assert (((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol), "");
   }
+  else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CDu, 0x17D1u) ||
+		     u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
+  {
+    /* These can occur mid-syllable (eg. before matras), even though Unicode marks them as Syllable_Modifier.
+     * https://github.com/roozbehp/unicode-data/issues/5 */
+    cat = OT_M;
+    pos = POS_ABOVE_C;
+  }
+  else if (unlikely (u == 0x0A51u))
+  {
+    /* https://github.com/harfbuzz/harfbuzz/issues/524 */
+    cat = OT_M;
+    pos = POS_BELOW_C;
+  }
+
+  /* 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 == 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 == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */
   else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
-  else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
+  else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u)))
 				    cat = OT_PLACEHOLDER;
   else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
 
@@ -210,7 +234,7 @@
    * Re-assign position.
    */
 
-  if ((FLAG_SAFE (cat) & CONSONANT_FLAGS))
+  if ((FLAG_UNSAFE (cat) & CONSONANT_FLAGS))
   {
     pos = POS_BASE_C;
     if (is_ra (u))
@@ -220,7 +244,7 @@
   {
     pos = matra_position (u, pos);
   }
-  else if ((FLAG_SAFE (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
+  else if ((FLAG_UNSAFE (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
   {
     pos = POS_SMVD;
   }
@@ -411,12 +435,12 @@
   unsigned int i = 0;
   map->add_gsub_pause (initial_reordering);
   for (; i < INDIC_BASIC_FEATURES; i++) {
-    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
-    map->add_gsub_pause (NULL);
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
+    map->add_gsub_pause (nullptr);
   }
   map->add_gsub_pause (final_reordering);
   for (; i < INDIC_NUM_FEATURES; i++) {
-    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
   }
 
   map->add_global_bool_feature (HB_TAG('c','a','l','t'));
@@ -485,7 +509,7 @@
 
       /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
        * during shape planning...  Instead, overwrite it here.  It's safe.  Don't worry! */
-      (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph;
+      virama_glyph = glyph;
     }
 
     *pglyph = glyph;
@@ -495,7 +519,7 @@
   const indic_config_t *config;
 
   bool is_old_spec;
-  hb_codepoint_t virama_glyph;
+  mutable hb_codepoint_t virama_glyph;
 
   would_substitute_feature_t rphf;
   would_substitute_feature_t pref;
@@ -510,7 +534,7 @@
 {
   indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
   if (unlikely (!indic_plan))
-    return NULL;
+    return nullptr;
 
   indic_plan->config = &indic_configs[0];
   for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++)
@@ -615,6 +639,8 @@
 		 hb_buffer_t *buffer)
 {
   find_syllables (buffer);
+  foreach_syllable (buffer, start, end)
+    buffer->unsafe_to_break (start, end);
 }
 
 static int
@@ -666,6 +692,21 @@
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   hb_glyph_info_t *info = buffer->info;
 
+  /* https://github.com/harfbuzz/harfbuzz/issues/435#issuecomment-335560167
+   * // For compatibility with legacy usage in Kannada,
+   * // Ra+h+ZWJ must behave like Ra+ZWJ+h...
+   */
+  if (buffer->props.script == HB_SCRIPT_KANNADA &&
+      start + 3 <= end &&
+      is_one_of (info[start  ], FLAG (OT_Ra)) &&
+      is_one_of (info[start+1], FLAG (OT_H)) &&
+      is_one_of (info[start+2], FLAG (OT_ZWJ)))
+  {
+    buffer->merge_clusters (start+1, start+3);
+    hb_glyph_info_t tmp = info[start+1];
+    info[start+1] = info[start+2];
+    info[start+2] = tmp;
+  }
 
   /* 1. Find base consonant:
    *
@@ -673,7 +714,7 @@
    * following algorithm: starting from the end of the syllable, move backwards
    * until a consonant is found that does not have a below-base or post-base
    * form (post-base forms have to follow below-base forms), or that is not a
-   * pre-base reordering Ra, or arrive at the first consonant. The consonant
+   * pre-base-reordering Ra, or arrive at the first consonant. The consonant
    * stopped at will be the base.
    *
    *   o If the syllable starts with Ra + Halant (in a script that has Reph)
@@ -744,11 +785,11 @@
 	    if (info[i].indic_position() == POS_BELOW_C)
 	      seen_below = true;
 
-	    /* -> or that is not a pre-base reordering Ra,
+	    /* -> or that is not a pre-base-reordering Ra,
 	     *
 	     * IMPLEMENTATION NOTES:
 	     *
-	     * Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped
+	     * Our pre-base-reordering Ra's are marked POS_POST_C, so will be skipped
 	     * by the logic above already.
 	     */
 
@@ -831,8 +872,8 @@
 
   /* 2. Decompose and reorder Matras:
    *
-   * Each matra and any syllable modifier sign in the cluster are moved to the
-   * appropriate position relative to the consonant(s) in the cluster. The
+   * Each matra and any syllable modifier sign in the syllable are moved to the
+   * appropriate position relative to the consonant(s) in the syllable. The
    * shaping engine decomposes two- or three-part matras into their constituent
    * parts before any repositioning. Matra characters are classified by which
    * consonant in a conjunct they have affinity for and are reordered to the
@@ -928,7 +969,7 @@
     indic_position_t last_pos = POS_START;
     for (unsigned int i = start; i < end; i++)
     {
-      if ((FLAG_SAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
+      if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
       {
 	info[i].indic_position() = last_pos;
 	if (unlikely (info[i].indic_category() == OT_H &&
@@ -1083,7 +1124,7 @@
   unsigned int pref_len = 2;
   if (indic_plan->mask_array[PREF] && base + pref_len < end)
   {
-    /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
+    /* 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++)
@@ -1258,7 +1299,7 @@
 
 
   /* This function relies heavily on halant glyphs.  Lots of ligation
-   * and possibly multiplication substitutions happened prior to this
+   * and possibly multiple substitutions happened prior to this
    * phase, and that might have messed up our properties.  Recover
    * from a particular case of that where we're fairly sure that a
    * class of OT_H is desired but has been lost. */
@@ -1282,7 +1323,7 @@
    * After the localized forms and basic shaping forms GSUB features have been
    * applied (see below), the shaping engine performs some final glyph
    * reordering before applying all the remaining font features to the entire
-   * cluster.
+   * syllable.
    */
 
   bool try_pref = !!indic_plan->mask_array[PREF];
@@ -1477,7 +1518,7 @@
 
     /*       3. If reph should be repositioned after the main consonant: find the
      *          first consonant not ligated with main, or find the first
-     *          consonant that is not a potential pre-base reordering Ra.
+     *          consonant that is not a potential pre-base-reordering Ra.
      */
     if (reph_pos == REPH_POS_AFTER_MAIN)
     {
@@ -1497,8 +1538,8 @@
     if (reph_pos == REPH_POS_AFTER_SUB)
     {
       new_reph_pos = base;
-      while (new_reph_pos < end &&
-	     !( FLAG_SAFE (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
+      while (new_reph_pos + 1 < end &&
+	     !( 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;
@@ -1566,13 +1607,13 @@
   }
 
 
-  /*   o Reorder pre-base reordering consonants:
+  /*   o Reorder pre-base-reordering consonants:
    *
-   *     If a pre-base reordering consonant is found, reorder it according to
+   *     If a pre-base-reordering consonant is found, reorder it according to
    *     the following rules:
    */
 
-  if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
+  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)
@@ -1646,11 +1687,15 @@
 
 
   /* Apply 'init' to the Left Matra if it's a word start. */
-  if (info[start].indic_position () == POS_PRE_M &&
-      (!start ||
-       !(FLAG_SAFE (_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];
+  if (info[start].indic_position () == POS_PRE_M)
+  {
+    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];
+    else
+      buffer->unsafe_to_break (start - 1, start + 1);
+  }
 
 
   /*
@@ -1665,8 +1710,8 @@
         break;
 
       default:
-	/* Uniscribe merges the entire cluster... Except for Tamil & Sinhala.
-	 * This means, half forms are submerged into the main consonants cluster.
+	/* Uniscribe merges the entire syllable into a single cluster... Except for Tamil & Sinhala.
+	 * This means, half forms are submerged into the main consonant's cluster.
 	 * This is unnecessary, and makes cursor positioning harder, but that's what
 	 * Uniscribe does. */
 	buffer->merge_clusters (start, end);
@@ -1738,7 +1783,7 @@
 #endif
   }
 
-  if ((ab == 0x0DDAu || hb_in_range (ab, 0x0DDCu, 0x0DDEu)))
+  if ((ab == 0x0DDAu || hb_in_range<hb_codepoint_t> (ab, 0x0DDCu, 0x0DDEu)))
   {
     /*
      * Sinhala split matras...  Let the fun begin.
@@ -1803,18 +1848,18 @@
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
 {
-  "indic",
   collect_features_indic,
   override_features_indic,
   data_create_indic,
   data_destroy_indic,
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_indic,
   compose_indic,
   setup_masks_indic,
-  NULL, /* disable_otl */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl
index 9649a91..45733ac 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.rl
+++ b/src/hb-ot-shape-complex-myanmar-machine.rl
@@ -41,7 +41,7 @@
 A    = 10;
 As   = 18;
 C    = 1;
-D    = 19;
+D    = 32;
 D0   = 20;
 DB   = 3;
 GB   = 11;
@@ -62,6 +62,7 @@
 ZWNJ = 5;
 Ra   = 16;
 P    = 31;
+CS   = 19;
 
 j = ZWJ|ZWNJ;			# Joiners
 k = (Ra As H);			# Kinzi
@@ -76,7 +77,7 @@
 complex_syllable_tail = As* medial_group main_vowel_group post_vowel_group* pwo_tone_group* V* j?;
 syllable_tail = (H | complex_syllable_tail);
 
-consonant_syllable =	k? (c|IV|D|GB).VS? (H (c|IV).VS?)* syllable_tail;
+consonant_syllable =	(k|CS)? (c|IV|D|GB).VS? (H (c|IV).VS?)* syllable_tail;
 punctuation_cluster = 	P V;
 broken_cluster =	k? VS? syllable_tail;
 other =			any;
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index bb68622..5ea1dbf 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -103,7 +103,7 @@
   for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
   {
     map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
-    map->add_gsub_pause (NULL);
+    map->add_gsub_pause (nullptr);
   }
   map->add_gsub_pause (final_reordering);
   for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
@@ -130,8 +130,7 @@
 /* Note: This enum is duplicated in the -machine.rl source file.
  * Not sure how to avoid duplication. */
 enum myanmar_category_t {
-  OT_As  = 18, /* Asat */
-  OT_D   = 19, /* Digits except zero */
+  OT_As  = 18,  /* Asat */
   OT_D0  = 20, /* Digit zero */
   OT_DB  = OT_N, /* Dot below */
   OT_GB  = OT_PLACEHOLDER,
@@ -145,7 +144,8 @@
   OT_VPre = 28,
   OT_VPst = 29,
   OT_VS   = 30, /* Variation selectors */
-  OT_P    = 31  /* Punctuation */
+  OT_P    = 31, /* Punctuation */
+  OT_D    = 32, /* Digits except zero */
 };
 
 
@@ -154,7 +154,7 @@
 {
   /* If it ligated, all bets are off. */
   if (_hb_glyph_info_ligated (&info)) return false;
-  return !!(FLAG_SAFE (info.myanmar_category()) & flags);
+  return !!(FLAG_UNSAFE (info.myanmar_category()) & flags);
 }
 
 static inline bool
@@ -175,7 +175,7 @@
   /* Myanmar
    * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze
    */
-  if (unlikely (hb_in_range (u, 0xFE00u, 0xFE0Fu)))
+  if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)))
     cat = (indic_category_t) OT_VS;
 
   switch (u)
@@ -297,6 +297,8 @@
 		 hb_buffer_t *buffer)
 {
   find_syllables (buffer);
+  foreach_syllable (buffer, start, end)
+    buffer->unsafe_to_break (start, end);
 }
 
 static int
@@ -510,36 +512,36 @@
  * generic shaper, except that it zeros mark advances GDEF_LATE. */
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
 {
-  "default",
-  NULL, /* collect_features */
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
-  NULL, /* setup_masks */
-  NULL, /* disable_otl */
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
 {
-  "myanmar",
   collect_features_myanmar,
   override_features_myanmar,
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
-  NULL, /* decompose */
-  NULL, /* compose */
+  nullptr, /* decompose */
+  nullptr, /* compose */
   setup_masks_myanmar,
-  NULL, /* disable_otl */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
index 39572df..fb2f611 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex-private.hh
@@ -39,6 +39,8 @@
 #define complex_var_u8_1()	var2.u8[3]
 
 
+#define HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS 32
+
 enum hb_ot_shape_zero_width_marks_type_t {
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
@@ -63,12 +65,10 @@
 
 struct hb_ot_complex_shaper_t
 {
-  char name[8];
-
   /* collect_features()
    * Called during shape_plan().
    * Shapers should use plan->map to add their features and callbacks.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*collect_features) (hb_ot_shape_planner_t *plan);
 
@@ -76,7 +76,7 @@
    * Called during shape_plan().
    * Shapers should use plan->map to override features and add callbacks after
    * common features are added.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*override_features) (hb_ot_shape_planner_t *plan);
 
@@ -84,15 +84,15 @@
   /* data_create()
    * Called at the end of shape_plan().
    * Whatever shapers return will be accessible through plan->data later.
-   * If NULL is returned, means a plan failure.
+   * If nullptr is returned, means a plan failure.
    */
   void *(*data_create) (const hb_ot_shape_plan_t *plan);
 
   /* data_destroy()
    * Called when the shape_plan is being destroyed.
    * plan->data is passed here for destruction.
-   * If NULL is returned, means a plan failure.
-   * May be NULL.
+   * If nullptr is returned, means a plan failure.
+   * May be nullptr.
    */
   void (*data_destroy) (void *data);
 
@@ -100,7 +100,7 @@
   /* preprocess_text()
    * Called during shape().
    * Shapers can use to modify text before shaping starts.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*preprocess_text) (const hb_ot_shape_plan_t *plan,
 			   hb_buffer_t              *buffer,
@@ -109,7 +109,7 @@
   /* postprocess_glyphs()
    * Called during shape().
    * Shapers can use to modify glyphs after shaping ends.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan,
 			      hb_buffer_t              *buffer,
@@ -120,7 +120,7 @@
 
   /* decompose()
    * Called during shape()'s normalization.
-   * May be NULL.
+   * May be nullptr.
    */
   bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
 		     hb_codepoint_t  ab,
@@ -129,7 +129,7 @@
 
   /* compose()
    * Called during shape()'s normalization.
-   * May be NULL.
+   * May be nullptr.
    */
   bool (*compose) (const hb_ot_shape_normalize_context_t *c,
 		   hb_codepoint_t  a,
@@ -140,7 +140,7 @@
    * Called during shape().
    * Shapers should use map to get feature masks and set on buffer.
    * Shapers may NOT modify characters.
-   * May be NULL.
+   * May be nullptr.
    */
   void (*setup_masks) (const hb_ot_shape_plan_t *plan,
 		       hb_buffer_t              *buffer,
@@ -150,10 +150,20 @@
    * Called during shape().
    * If set and returns true, GDEF/GSUB/GPOS of the font are ignored
    * and fallback operations used.
-   * May be NULL.
+   * May be nullptr.
    */
   bool (*disable_otl) (const hb_ot_shape_plan_t *plan);
 
+  /* reorder_marks()
+   * Called during shape().
+   * Shapers can use to modify ordering of combining marks.
+   * May be nullptr.
+   */
+  void (*reorder_marks) (const hb_ot_shape_plan_t *plan,
+			 hb_buffer_t              *buffer,
+			 unsigned int              start,
+			 unsigned int              end);
+
   hb_ot_shape_zero_width_marks_type_t zero_width_marks;
 
   bool fallback_position;
@@ -191,6 +201,9 @@
     case HB_SCRIPT_MANICHAEAN:
     case HB_SCRIPT_PSALTER_PAHLAVI:
 
+    /* Unicode-9.0 additions */
+    case HB_SCRIPT_ADLAM:
+
       /* For Arabic script, use the Arabic shaper even if no OT script tag was found.
        * This is because we do fallback shaping for Arabic script (and not others).
        * But note that Arabic shaping is applicable only to horizontal layout; for
@@ -250,10 +263,12 @@
     case HB_SCRIPT_SINHALA:
 
       /* If the designer designed the font for the 'DFLT' script,
-       * use the default shaper.  Otherwise, use the specific shaper.
+       * (or we ended up arbitrarily pick 'latn'), use the default shaper.
+       * Otherwise, use the specific shaper.
        * Note that for some simple scripts, there may not be *any*
        * GSUB/GPOS needed, so there may be no scripts found! */
-      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
+	  planner->map.chosen_script[0] == HB_TAG ('l','a','t','n'))
 	return &_hb_ot_complex_shaper_default;
       else
 	return &_hb_ot_complex_shaper_indic;
@@ -269,7 +284,7 @@
 					      planner->map.script_index[0],
 					      planner->map.language_index[0],
 					      HB_TAG ('p','r','e','f'),
-					      NULL))
+					      nullptr))
 	return &_hb_ot_complex_shaper_indic;
       else
 	return &_hb_ot_complex_shaper_default;
@@ -359,11 +374,18 @@
     case HB_SCRIPT_MARCHEN:
     case HB_SCRIPT_NEWA:
 
+    /* Unicode-10.0 additions */
+    case HB_SCRIPT_MASARAM_GONDI:
+    case HB_SCRIPT_SOYOMBO:
+    case HB_SCRIPT_ZANABAZAR_SQUARE:
+
       /* If the designer designed the font for the 'DFLT' script,
-       * use the default shaper.  Otherwise, use the specific shaper.
+       * (or we ended up arbitrarily pick 'latn'), use the default shaper.
+       * Otherwise, use the specific shaper.
        * Note that for some simple scripts, there may not be *any*
        * GSUB/GPOS needed, so there may be no scripts found! */
-      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
+	  planner->map.chosen_script[0] == HB_TAG ('l','a','t','n'))
 	return &_hb_ot_complex_shaper_default;
       else
 	return &_hb_ot_complex_shaper_use;
diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc
index e6f80f5..6ba925c 100644
--- a/src/hb-ot-shape-complex-thai.cc
+++ b/src/hb-ot-shape-complex-thai.cc
@@ -52,7 +52,7 @@
     return RC;
   if (u == 0x0E0Eu || u == 0x0E0Fu)
     return DC;
-  if (hb_in_range (u, 0x0E01u, 0x0E2Eu))
+  if (hb_in_range<hb_codepoint_t> (u, 0x0E01u, 0x0E2Eu))
     return NC;
   return NOT_CONSONANT;
 }
@@ -70,12 +70,12 @@
 static thai_mark_type_t
 get_mark_type (hb_codepoint_t u)
 {
-  if (u == 0x0E31u || hb_in_range (u, 0x0E34u, 0x0E37u) ||
-      u == 0x0E47u || hb_in_range (u, 0x0E4Du, 0x0E4Eu))
+  if (u == 0x0E31u || hb_in_range<hb_codepoint_t> (u, 0x0E34u, 0x0E37u) ||
+      u == 0x0E47u || hb_in_range<hb_codepoint_t> (u, 0x0E4Du, 0x0E4Eu))
     return AV;
-  if (hb_in_range (u, 0x0E38u, 0x0E3Au))
+  if (hb_in_range<hb_codepoint_t> (u, 0x0E38u, 0x0E3Au))
     return BV;
-  if (hb_in_range (u, 0x0E48u, 0x0E4Cu))
+  if (hb_in_range<hb_codepoint_t> (u, 0x0E48u, 0x0E4Cu))
     return T;
   return NOT_MARK;
 }
@@ -97,7 +97,7 @@
     hb_codepoint_t u;
     hb_codepoint_t win_pua;
     hb_codepoint_t mac_pua;
-  } const *pua_mappings = NULL;
+  } const *pua_mappings = nullptr;
   static const thai_pua_mapping_t SD_mappings[] = {
     {0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
     {0x0E49u, 0xF70Bu, 0xF88Eu}, /* MAI THO */
@@ -244,6 +244,7 @@
     /* At least one of the above/below actions is NOP. */
     thai_action_t action = above_edge.action != NOP ? above_edge.action : below_edge.action;
 
+    buffer->unsafe_to_break (base, i);
     if (action == RD)
       info[base].codepoint = thai_pua_shape (info[base].codepoint, action, font);
     else
@@ -310,7 +311,7 @@
 #define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u)
 #define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du)
 #define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
-#define IS_TONE_MARK(x) (hb_in_ranges ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
+#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
 
   buffer->clear_output ();
   unsigned int count = buffer->len;
@@ -365,18 +366,18 @@
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
 {
-  "thai",
-  NULL, /* collect_features */
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
   preprocess_text_thai,
-  NULL, /* postprocess_glyphs */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
-  NULL, /* setup_masks */
-  NULL, /* disable_otl */
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   false,/* fallback_position */
 };
diff --git a/src/hb-ot-shape-complex-tibetan.cc b/src/hb-ot-shape-complex-tibetan.cc
index aadf59f..eaac0bf 100644
--- a/src/hb-ot-shape-complex-tibetan.cc
+++ b/src/hb-ot-shape-complex-tibetan.cc
@@ -46,18 +46,18 @@
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
 {
-  "default",
   collect_features_tibetan,
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
-  NULL, /* decompose */
-  NULL, /* compose */
-  NULL, /* setup_masks */
-  NULL, /* disable_otl */
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
diff --git a/src/hb-ot-shape-complex-use-machine.rl b/src/hb-ot-shape-complex-use-machine.rl
index f6b814b..86cd8b2 100644
--- a/src/hb-ot-shape-complex-use-machine.rl
+++ b/src/hb-ot-shape-complex-use-machine.rl
@@ -86,21 +86,23 @@
 VMPre	= 23; # VOWEL_MOD_PRE
 SMAbv	= 41; # SYM_MOD_ABOVE
 SMBlw	= 42; # SYM_MOD_BELOW
+CS	= 43; # CONS_WITH_STACKER
 
 
 consonant_modifiers = CMAbv* CMBlw* ((H B | SUB) VS? CMAbv? CMBlw*)*;
-medial_consonants = MPre? MAbv? MBlw? MPst?;
+# Override: Allow two MBlw. https://github.com/harfbuzz/harfbuzz/issues/376
+medial_consonants = MPre? MAbv? MBlw?.MBlw? MPst?;
 dependent_vowels = VPre* VAbv* VBlw* VPst*;
 vowel_modifiers = VMPre* VMAbv* VMBlw* VMPst*;
 final_consonants = FAbv* FBlw* FPst* FM?;
 
 virama_terminated_cluster =
-	R? (B | GB) VS?
+	(R|CS)? (B | GB) VS?
 	consonant_modifiers
 	H
 ;
 standard_cluster =
-	R? (B | GB) VS?
+	(R|CS)? (B | GB) VS?
 	consonant_modifiers
 	medial_consonants
 	dependent_vowels
diff --git a/src/hb-ot-shape-complex-use-private.hh b/src/hb-ot-shape-complex-use-private.hh
index ae428cb..3e763ae 100644
--- a/src/hb-ot-shape-complex-use-private.hh
+++ b/src/hb-ot-shape-complex-use-private.hh
@@ -87,7 +87,8 @@
   USE_VMPst	= 39,	/* VOWEL_MOD_POST */
   USE_VMPre	= 23,	/* VOWEL_MOD_PRE */
   USE_SMAbv	= 41,	/* SYM_MOD_ABOVE */
-  USE_SMBlw	= 42	/* SYM_MOD_BELOW */
+  USE_SMBlw	= 42,	/* SYM_MOD_BELOW */
+  USE_CS	= 43	/* CONS_WITH_STACKER */
 };
 
 HB_INTERNAL USE_TABLE_ELEMENT_TYPE
diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc
index 38c46d0..fd6978f 100644
--- a/src/hb-ot-shape-complex-use-table.cc
+++ b/src/hb-ot-shape-complex-use-table.cc
@@ -6,12 +6,12 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-9.0.0.txt
- * # Date: 2016-05-21, 02:46:00 GMT [RP]
- * # IndicPositionalCategory-9.0.0.txt
- * # Date: 2016-02-25, 00:48:00 GMT [RP]
- * # Blocks-9.0.0.txt
- * # Date: 2016-02-05, 23:48:00 GMT [KW]
+ * # IndicSyllabicCategory-10.0.0.txt
+ * # Date: 2017-05-31, 01:07:00 GMT [KW, RP]
+ * # IndicPositionalCategory-10.0.0.txt
+ * # Date: 2017-05-31, 01:07:00 GMT [RP]
+ * # Blocks-10.0.0.txt
+ * # Date: 2017-04-12, 17:30:00 GMT [KW]
  * UnicodeData.txt does not have a header.
  */
 
@@ -19,6 +19,7 @@
 
 #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 */
@@ -97,7 +98,7 @@
   /* 09C0 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VPre,  VPre,     O,     O,  VPre,  VPre,     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,     O,     O,     O,     O,
+  /* 09F0 */     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     O,     O,     O,
 
   /* Gurmukhi */
 
@@ -119,7 +120,7 @@
   /* 0AC0 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,     O,  VAbv,  VAbv,  VAbv,     O,  VPst,  VPst,     H,     O,     O,
   /* 0AD0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 0AE0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0AF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     O,     O,     O,     O,     O,     O,
+  /* 0AF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     B, VMAbv, VMAbv, VMAbv, CMAbv, CMAbv, CMAbv,
 
   /* Oriya */
 
@@ -163,14 +164,14 @@
   /* 0CC0 */  VAbv,  VPst,  VPst,  VPst,  VPst,     O,  VAbv,  VAbv,  VAbv,     O,  VAbv,  VAbv,  VAbv,     H,     O,     O,
   /* 0CD0 */     O,     O,     O,     O,     O,  VPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     B,     O,
   /* 0CE0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0CF0 */     O,     R,     R,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 0CF0 */     O,    CS,    CS,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Malayalam */
 
-  /* 0D00 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
   /* 0D10 */     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 0D20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0D30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,  VPst,  VPst,
+  /* 0D30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,     B,  VPst,  VPst,
   /* 0D40 */  VPst,  VPst,  VPst,  VBlw,  VBlw,     O,  VPre,  VPre,  VPre,     O,  VPre,  VPre,  VPre,     H,     R,     O,
   /* 0D50 */     O,     O,     O,     O,   IND,   IND,   IND,  VPst,     O,     O,     O,     O,     O,     O,     O,     B,
   /* 0D60 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
@@ -274,9 +275,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,  FPst,  FAbv,  FAbv,  FAbv,  FBlw,  FBlw,  FBlw,  FBlw,     O,
+  /* 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,  VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,    FM,    FM,    FM,     O,     O,    FM,
+  /* 1A70 */  VPre,  VPre,  VPre,  VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,  VAbv,    FM,    FM,     O,     O,  FBlw,
   /* 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,
 
@@ -323,7 +324,7 @@
 
   /* 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,     O,     O,     O, VMAbv, VMAbv,     O,     O,     O,     O,     O,     O,
+  /* 1CF0 */     O,     O, VMPst, VMPst, VMAbv,     O,     O, VMPst, VMAbv, VMAbv,     O,     O,     O,     O,     O,     O,
 
 #define use_offset_0x1df8u 2552
 
@@ -347,7 +348,14 @@
   /* 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,
 
-#define use_offset_0xa800u 2616
+#define use_offset_0x20f0u 2616
+
+
+  /* Combining Diacritical Marks for Symbols */
+
+  /* 20F0 */ VMAbv,     O,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0xa800u 2624
 
 
   /* Syloti Nagri */
@@ -369,14 +377,14 @@
   /* A880 */ VMPst, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A890 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A8A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A8B0 */     B,     B,     B,     B,  FPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,
+  /* A8B0 */     B,     B,     B,     B,  MPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,  VPst,
   /* A8C0 */  VPst,  VPst,  VPst,  VPst,     H, VMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* A8D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
   /* Devanagari Extended */
 
   /* A8E0 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,
-  /* A8F0 */ VMAbv, VMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A8F0 */ VMAbv, VMAbv,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Kayah Li */
 
@@ -397,7 +405,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,  MPst,
+  /* A9B0 */     B,     B,     B, CMAbv,  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VPre,  VAbv,   SUB,  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,
 
@@ -410,7 +418,7 @@
 
   /* AA00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* AA10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* AA20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VAbv,  VPre,
+  /* AA20 */     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VAbv,  VPre,
   /* AA30 */  VPre,  VAbv,  VBlw,  MPst,  MPre,  MBlw,  MBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* AA40 */     B,     B,     B,  FAbv,     B,     B,     B,     B,     B,     B,     B,     B,  FAbv,  FPst,     O,     O,
   /* AA50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
@@ -434,7 +442,7 @@
   /* AAE0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPre,  VBlw,  VAbv,  VPre,  VPst,
   /* AAF0 */     O,     O,     O,     O,     O, VMPst,     H,     O,
 
-#define use_offset_0xabc0u 3376
+#define use_offset_0xabc0u 3384
 
 
   /* Meetei Mayek */
@@ -444,14 +452,14 @@
   /* ABE0 */     B,     B,     B,  VPst,  VPst,  VAbv,  VPst,  VPst,  VBlw,  VPst,  VPst,     O, VMPst,  VBlw,     O,     O,
   /* ABF0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
-#define use_offset_0xfe00u 3440
+#define use_offset_0xfe00u 3448
 
 
   /* Variation Selectors */
 
   /* FE00 */    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,
 
-#define use_offset_0x10a00u 3456
+#define use_offset_0x10a00u 3464
 
 
   /* Kharoshthi */
@@ -462,12 +470,12 @@
   /* 10A30 */     B,     B,     B,     B,     O,     O,     O,     O, CMAbv, CMBlw, CMBlw,     O,     O,     O,     O,     H,
   /* 10A40 */     B,     B,     B,     B,     B,     B,     B,     B,
 
-#define use_offset_0x11000u 3528
+#define use_offset_0x11000u 3536
 
 
   /* Brahmi */
 
-  /* 11000 */ VMPst, VMAbv, VMPst,     R,     R,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11000 */ VMPst, VMAbv, VMPst,    CS,    CS,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11010 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11020 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11030 */     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,
@@ -483,7 +491,7 @@
   /* 110A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 110B0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VAbv,  VAbv,  VPst,  VPst,     H, CMBlw,     O,     O,     O,     O,     O,
 
-#define use_offset_0x11100u 3720
+#define use_offset_0x11100u 3728
 
 
   /* Chakma */
@@ -521,7 +529,7 @@
   /* 11220 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPst,  VPst,  VBlw,
   /* 11230 */  VAbv,  VAbv,  VAbv,  VAbv, VMAbv,     H, CMAbv, CMAbv,     O,     O,     O,     O,     O,     O, VMAbv,     O,
 
-#define use_offset_0x11280u 4040
+#define use_offset_0x11280u 4048
 
 
   /* Multani */
@@ -545,11 +553,11 @@
   /* 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,     O, CMBlw,     B,  VPst,  VPst,
   /* 11340 */  VAbv,  VPst,  VPst,  VPst,  VPst,     O,     O,  VPre,  VPre,     O,     O,  VPre,  VPre,     H,     O,     O,
-  /* 11350 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11350 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     B,     B,
   /* 11360 */     B,     B,  VPst,  VPst,     O,     O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     O,     O,     O,
   /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,     O,     O,     O,
 
-#define use_offset_0x11400u 4288
+#define use_offset_0x11400u 4296
 
 
   /* Newa */
@@ -572,7 +580,7 @@
   /* 114C0 */ VMAbv, VMPst,     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 4512
+#define use_offset_0x11580u 4520
 
 
   /* Siddham */
@@ -615,7 +623,26 @@
   /* 11720 */  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VAbv,  VBlw,  VAbv,  VAbv,  VAbv,     O,     O,     O,     O,
   /* 11730 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
 
-#define use_offset_0x11c00u 4960
+#define use_offset_0x11a00u 4968
+
+
+  /* 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,
+  /* 11A40 */     O,     O,     O,     O,     O,    GB,     O,     H,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Soyombo */
+
+  /* 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,
+  /* 11A90 */  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw, VMAbv, VMPst, CMAbv,     H,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0x11c00u 5128
 
 
   /* Bhaiksuki */
@@ -636,7 +663,19 @@
   /* 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,
 
-}; /* Table items: 5144; occupancy: 72% */
+#define use_offset_0x11d00u 5312
+
+
+  /* Masaram Gondi */
+
+  /* 11D00 */     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,
+  /* 11D10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11D20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11D30 */     B,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,     O,     O,     O,  VAbv,     O,  VAbv,  VAbv,     O,  VAbv,
+  /* 11D40 */ VMAbv, VMAbv, CMBlw,  VAbv,  VBlw,     H,     R,  MBlw,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11D50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+}; /* Table items: 5408; occupancy: 73% */
 
 USE_TABLE_ELEMENT_TYPE
 hb_use_get_categories (hb_codepoint_t u)
@@ -644,47 +683,50 @@
   switch (u >> 12)
   {
     case 0x0u:
-      if (hb_in_range (u, 0x0028u, 0x003Fu)) return use_table[u - 0x0028u + use_offset_0x0028u];
-      if (hb_in_range (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u];
-      if (hb_in_range (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return use_table[u - 0x0028u + use_offset_0x0028u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u];
       if (unlikely (u == 0x034Fu)) return CGJ;
       break;
 
     case 0x1u:
-      if (hb_in_range (u, 0x1000u, 0x109Fu)) return use_table[u - 0x1000u + use_offset_0x1000u];
-      if (hb_in_range (u, 0x1700u, 0x17EFu)) return use_table[u - 0x1700u + use_offset_0x1700u];
-      if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return use_table[u - 0x1900u + use_offset_0x1900u];
-      if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
-      if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
-      if (hb_in_range (u, 0x1DF8u, 0x1DFFu)) return use_table[u - 0x1DF8u + use_offset_0x1df8u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return use_table[u - 0x1000u + use_offset_0x1000u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1700u, 0x17EFu)) return use_table[u - 0x1700u + use_offset_0x1700u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1900u, 0x1A9Fu)) return use_table[u - 0x1900u + use_offset_0x1900u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1DF8u, 0x1DFFu)) return use_table[u - 0x1DF8u + use_offset_0x1df8u];
       break;
 
     case 0x2u:
-      if (hb_in_range (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u];
-      if (hb_in_range (u, 0x2060u, 0x2087u)) return use_table[u - 0x2060u + use_offset_0x2060u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x2060u, 0x2087u)) return use_table[u - 0x2060u + use_offset_0x2060u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x20F0u, 0x20F7u)) return use_table[u - 0x20F0u + use_offset_0x20f0u];
       if (unlikely (u == 0x25CCu)) return GB;
       break;
 
     case 0xAu:
-      if (hb_in_range (u, 0xA800u, 0xAAF7u)) return use_table[u - 0xA800u + use_offset_0xa800u];
-      if (hb_in_range (u, 0xABC0u, 0xABFFu)) return use_table[u - 0xABC0u + use_offset_0xabc0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0xA800u, 0xAAF7u)) return use_table[u - 0xA800u + use_offset_0xa800u];
+      if (hb_in_range<hb_codepoint_t> (u, 0xABC0u, 0xABFFu)) return use_table[u - 0xABC0u + use_offset_0xabc0u];
       break;
 
     case 0xFu:
-      if (hb_in_range (u, 0xFE00u, 0xFE0Fu)) return use_table[u - 0xFE00u + use_offset_0xfe00u];
+      if (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)) return use_table[u - 0xFE00u + use_offset_0xfe00u];
       break;
 
     case 0x10u:
-      if (hb_in_range (u, 0x10A00u, 0x10A47u)) return use_table[u - 0x10A00u + use_offset_0x10a00u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x10A00u, 0x10A47u)) return use_table[u - 0x10A00u + use_offset_0x10a00u];
       break;
 
     case 0x11u:
-      if (hb_in_range (u, 0x11000u, 0x110BFu)) return use_table[u - 0x11000u + use_offset_0x11000u];
-      if (hb_in_range (u, 0x11100u, 0x1123Fu)) return use_table[u - 0x11100u + use_offset_0x11100u];
-      if (hb_in_range (u, 0x11280u, 0x11377u)) return use_table[u - 0x11280u + use_offset_0x11280u];
-      if (hb_in_range (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u];
-      if (hb_in_range (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u];
-      if (hb_in_range (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x11000u, 0x110BFu)) return use_table[u - 0x11000u + use_offset_0x11000u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x11100u, 0x1123Fu)) return use_table[u - 0x11100u + use_offset_0x11100u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x11280u, 0x11377u)) return use_table[u - 0x11280u + use_offset_0x11280u];
+      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, 0x11A00u, 0x11A9Fu)) return use_table[u - 0x11A00u + use_offset_0x11a00u];
+      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, 0x11D5Fu)) return use_table[u - 0x11D00u + use_offset_0x11d00u];
       if (unlikely (u == 0x1107Fu)) return HN;
       break;
 
@@ -696,6 +738,7 @@
 
 #undef B
 #undef CGJ
+#undef CS
 #undef FM
 #undef GB
 #undef H
diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc
index af68706..62acd69 100644
--- a/src/hb-ot-shape-complex-use.cc
+++ b/src/hb-ot-shape-complex-use.cc
@@ -144,7 +144,7 @@
   /* "Topographical features" */
   for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++)
     map->add_feature (arabic_features[i], 1, F_NONE);
-  map->add_gsub_pause (NULL);
+  map->add_gsub_pause (nullptr);
 
   /* "Standard typographic presentation" and "Positional feature application" */
   for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
@@ -199,7 +199,7 @@
 {
   use_shape_plan_t *use_plan = (use_shape_plan_t *) calloc (1, sizeof (use_shape_plan_t));
   if (unlikely (!use_plan))
-    return NULL;
+    return nullptr;
 
   use_plan->rphf_mask = plan->map.get_1_mask (HB_TAG('r','p','h','f'));
 
@@ -209,7 +209,7 @@
     if (unlikely (!use_plan->arabic_plan))
     {
       free (use_plan);
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -292,7 +292,7 @@
   if (use_plan->arabic_plan)
     return;
 
-  ASSERT_STATIC (INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4);
+  static_assert ((INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4), "");
   hb_mask_t masks[4], all_masks = 0;
   for (unsigned int i = 0; i < 4; i++)
   {
@@ -354,6 +354,8 @@
 		 hb_buffer_t *buffer)
 {
   find_syllables (buffer);
+  foreach_syllable (buffer, start, end)
+    buffer->unsafe_to_break (start, end);
   setup_rphf_mask (plan, buffer);
   setup_topographical_masks (plan, buffer);
 }
@@ -422,7 +424,7 @@
 {
   syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   /* Only a few syllable types need reordering. */
-  if (unlikely (!(FLAG_SAFE (syllable_type) &
+  if (unlikely (!(FLAG_UNSAFE (syllable_type) &
 		  (FLAG (virama_terminated_cluster) |
 		   FLAG (standard_cluster) |
 		   FLAG (broken_cluster) |
@@ -593,18 +595,18 @@
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
 {
-  "use",
   collect_features_use,
-  NULL, /* override_features */
+  nullptr, /* override_features */
   data_create_use,
   data_destroy_use,
-  NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_use,
   compose_use,
   setup_masks_use,
-  NULL, /* disable_otl */
+  nullptr, /* disable_otl */
+  nullptr, /* reorder_marks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index ea8312b..458c8ea 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -210,7 +210,7 @@
   pos.x_offset = pos.y_offset = 0;
 
 
-  /* We dont position LEFT and RIGHT marks. */
+  /* We don't position LEFT and RIGHT marks. */
 
   /* X positioning */
   switch (combining_class)
@@ -218,10 +218,10 @@
     case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
       if (buffer->props.direction == HB_DIRECTION_LTR) {
-	pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
+	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
         break;
       } else if (buffer->props.direction == HB_DIRECTION_RTL) {
-	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
+	pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
         break;
       }
       HB_FALLTHROUGH;
@@ -307,6 +307,9 @@
 		      unsigned int end)
 {
   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
+
+  buffer->unsafe_to_break (base, end);
+
   hb_glyph_extents_t base_extents;
   if (!font->get_glyph_extents (buffer->info[base].codepoint,
 				&base_extents))
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 107617e..fd9e7c2 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -91,7 +91,7 @@
 static inline void
 set_glyph (hb_glyph_info_t &info, hb_font_t *font)
 {
-  font->get_nominal_glyph (info.codepoint, &info.glyph_index());
+  (void) font->get_nominal_glyph (info.codepoint, &info.glyph_index());
 }
 
 static inline void
@@ -345,14 +345,18 @@
       if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
         break;
 
-    /* We are going to do a O(n^2).  Only do this if the sequence is short. */
-    if (end - i > 10) {
+    /* We are going to do a O(n^2).  Only do this if the sequence is short,
+     * but not too short ;). */
+    if (end - i < 2 || end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) {
       i = end;
       continue;
     }
 
     buffer->sort (i, end, compare_combining_class);
 
+    if (plan->shaper->reorder_marks)
+      plan->shaper->reorder_marks (plan, buffer, i, end);
+
     i = end;
   }
 
@@ -369,46 +373,58 @@
   buffer->clear_output ();
   count = buffer->len;
   unsigned int starter = 0;
+  bool combine = true;
   buffer->next_glyph ();
   while (buffer->idx < count && !buffer->in_error)
   {
     hb_codepoint_t composed, glyph;
-    if (/* We don't try to compose a non-mark character with it's preceding starter.
+    if (combine &&
+	/* We don't try to compose a non-mark character with it's preceding starter.
 	 * This is both an optimization to avoid trying to compose every two neighboring
 	 * glyphs in most scripts AND a desired feature for Hangul.  Apparently Hangul
 	 * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
-	HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())) &&
-	/* If there's anything between the starter and this char, they should have CCC
-	 * smaller than this character's. */
-	(starter == buffer->out_len - 1 ||
-	 _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) &&
-	/* And compose. */
-	c.compose (&c,
-		   buffer->out_info[starter].codepoint,
-		   buffer->cur().codepoint,
-		   &composed) &&
-	/* And the font has glyph for the composite. */
-	font->get_nominal_glyph (composed, &glyph))
+	HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())))
     {
-      /* Composes. */
-      buffer->next_glyph (); /* Copy to out-buffer. */
-      if (unlikely (buffer->in_error))
-        return;
-      buffer->merge_out_clusters (starter, buffer->out_len);
-      buffer->out_len--; /* Remove the second composable. */
-      /* Modify starter and carry on. */
-      buffer->out_info[starter].codepoint = composed;
-      buffer->out_info[starter].glyph_index() = glyph;
-      _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
+      if (/* If there's anything between the starter and this char, they should have CCC
+	   * smaller than this character's. */
+	  (starter == buffer->out_len - 1 ||
+	   info_cc (buffer->prev()) < info_cc (buffer->cur())) &&
+	  /* And compose. */
+	  c.compose (&c,
+		     buffer->out_info[starter].codepoint,
+		     buffer->cur().codepoint,
+		     &composed) &&
+	  /* And the font has glyph for the composite. */
+	  font->get_nominal_glyph (composed, &glyph))
+      {
+	/* Composes. */
+	buffer->next_glyph (); /* Copy to out-buffer. */
+	if (unlikely (buffer->in_error))
+	  return;
+	buffer->merge_out_clusters (starter, buffer->out_len);
+	buffer->out_len--; /* Remove the second composable. */
+	/* Modify starter and carry on. */
+	buffer->out_info[starter].codepoint = composed;
+	buffer->out_info[starter].glyph_index() = glyph;
+	_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
 
-      continue;
+	continue;
+      }
+      else if (/* We sometimes custom-tailor the sorted order of marks. In that case, stop
+		* trying to combine as soon as combining-class drops. */
+	       starter < buffer->out_len - 1 &&
+	       info_cc (buffer->prev()) > info_cc (buffer->cur()))
+        combine = false;
     }
 
     /* Blocked, or doesn't compose. */
     buffer->next_glyph ();
 
-    if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0)
+    if (info_cc (buffer->prev()) == 0)
+    {
       starter = buffer->out_len - 1;
+      combine = true;
+    }
   }
   buffer->swap_buffers ();
 
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index 594e54c..fe5d2b7 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -73,7 +73,7 @@
   hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
 			 face (master_plan->face_unsafe),
 			 props (master_plan->props),
-			 shaper (NULL),
+			 shaper (nullptr),
 			 map (face, &props) {}
   ~hb_ot_shape_planner_t (void) { map.finish (); }
 
@@ -99,7 +99,9 @@
   }
 
   private:
-  NO_COPY (hb_ot_shape_planner_t);
+  /* No copy. */
+  hb_ot_shape_planner_t (const hb_ot_shape_planner_t &);
+  hb_ot_shape_planner_t &operator = (const hb_ot_shape_planner_t &);
 };
 
 
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 6b38739..2f28b56 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -70,7 +70,7 @@
   hb_ot_map_builder_t *map = &planner->map;
 
   map->add_global_bool_feature (HB_TAG('r','v','r','n'));
-  map->add_gsub_pause (NULL);
+  map->add_gsub_pause (nullptr);
 
   switch (props->direction) {
     case HB_DIRECTION_LTR:
@@ -108,7 +108,7 @@
     /* We really want to find a 'vert' feature if there's any in the font, no
      * matter which script/langsys it is listed (or not) under.
      * See various bugs referenced from:
-     * https://github.com/behdad/harfbuzz/issues/63 */
+     * https://github.com/harfbuzz/harfbuzz/issues/63 */
     map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
   }
 
@@ -128,6 +128,8 @@
  * shaper face data
  */
 
+HB_SHAPER_DATA_ENSURE_DEFINE(ot, face)
+
 hb_ot_shaper_face_data_t *
 _hb_ot_shaper_face_data_create (hb_face_t *face)
 {
@@ -145,6 +147,8 @@
  * shaper font data
  */
 
+HB_SHAPER_DATA_ENSURE_DEFINE(ot, font)
+
 struct hb_ot_shaper_font_data_t {};
 
 hb_ot_shaper_font_data_t *
@@ -172,7 +176,7 @@
 {
   hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
   if (unlikely (!plan))
-    return NULL;
+    return nullptr;
 
   hb_ot_shape_planner_t planner (shape_plan);
 
@@ -186,7 +190,7 @@
   if (plan->shaper->data_create) {
     plan->data = plan->shaper->data_create (plan);
     if (unlikely (!plan->data))
-      return NULL;
+      return nullptr;
   }
 
   return plan;
@@ -271,8 +275,7 @@
 static void
 hb_form_clusters (hb_buffer_t *buffer)
 {
-  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
-      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
     return;
 
   /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
@@ -284,11 +287,17 @@
     if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
 		!_hb_glyph_info_is_joiner (&info[i])))
     {
-      buffer->merge_clusters (base, i);
+      if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+	buffer->merge_clusters (base, i);
+      else
+	buffer->unsafe_to_break (base, i);
       base = i;
     }
   }
-  buffer->merge_clusters (base, count);
+  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+    buffer->merge_clusters (base, count);
+  else
+    buffer->unsafe_to_break (base, count);
 }
 
 static void
@@ -374,7 +383,6 @@
     post_mask = c->plan->numr_mask | c->plan->frac_mask;
   }
 
-  /* TODO look in pre/post context text also. */
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
@@ -391,6 +399,8 @@
 	     HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
         end++;
 
+      buffer->unsafe_to_break (start, end);
+
       for (unsigned int j = start; j < i; j++)
         info[j].mask |= pre_mask;
       info[i].mask |= c->plan->frac_mask;
@@ -506,9 +516,10 @@
 	  /* Merge cluster backward. */
 	  if (cluster < info[j - 1].cluster)
 	  {
+	    unsigned int mask = info[i].mask;
 	    unsigned int old_cluster = info[j - 1].cluster;
 	    for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
-	      info[k - 1].cluster = cluster;
+	      buffer->set_cluster (info[k - 1], cluster, mask);
 	  }
 	  continue;
 	}
@@ -574,8 +585,6 @@
 {
   hb_buffer_t *buffer = c->buffer;
 
-  hb_ot_shape_initialize_masks (c);
-
   hb_ot_mirror_chars (c);
 
   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
@@ -684,9 +693,9 @@
 static inline void
 hb_ot_position_complex (hb_ot_shape_context_t *c)
 {
-  hb_ot_layout_position_start (c->font, c->buffer);
-
   unsigned int count = c->buffer->len;
+  hb_glyph_info_t *info = c->buffer->info;
+  hb_glyph_position_t *pos = c->buffer->pos;
 
   /* If the font has no GPOS, AND, no fallback positioning will
    * happen, AND, direction is forward, then when zeroing mark
@@ -701,6 +710,17 @@
 				     !c->plan->shaper->fallback_position &&
 				     HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
 
+  /* We change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
+
+  /* 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++)
+      c->font->add_glyph_h_origin (info[i].codepoint,
+				   &pos[i].x_offset,
+				   &pos[i].y_offset);
+
+  hb_ot_layout_position_start (c->font, c->buffer);
+
   switch (c->plan->shaper->zero_width_marks)
   {
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
@@ -714,30 +734,8 @@
   }
 
   if (likely (!c->fallback_positioning))
-  {
-    hb_glyph_info_t *info = c->buffer->info;
-    hb_glyph_position_t *pos = c->buffer->pos;
-
-    /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
-
-    /* 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++)
-	c->font->add_glyph_h_origin (info[i].codepoint,
-				     &pos[i].x_offset,
-				     &pos[i].y_offset);
-
     c->plan->position (c->font, c->buffer);
 
-    /* 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++)
-	c->font->subtract_glyph_h_origin (info[i].codepoint,
-					  &pos[i].x_offset,
-					  &pos[i].y_offset);
-
-  }
-
   switch (c->plan->shaper->zero_width_marks)
   {
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
@@ -754,6 +752,13 @@
   hb_ot_layout_position_finish_advances (c->font, c->buffer);
   hb_ot_zero_width_default_ignorables (c);
   hb_ot_layout_position_finish_offsets (c->font, c->buffer);
+
+  /* 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++)
+      c->font->subtract_glyph_h_origin (info[i].codepoint,
+					&pos[i].x_offset,
+					&pos[i].y_offset);
 }
 
 static inline void
@@ -779,6 +784,31 @@
   _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
 }
 
+static inline void
+hb_propagate_flags (hb_buffer_t *buffer)
+{
+  /* Propagate cluster-level glyph flags to be the same on all cluster glyphs.
+   * Simplifies using them. */
+
+  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK))
+    return;
+
+  hb_glyph_info_t *info = buffer->info;
+
+  foreach_cluster (buffer, start, end)
+  {
+    unsigned int mask = 0;
+    for (unsigned int i = start; i < end; i++)
+      if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
+      {
+	 mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
+	 break;
+      }
+    if (mask)
+      for (unsigned int i = start; i < end; i++)
+	info[i].mask |= mask;
+  }
+}
 
 /* Pull it all together! */
 
@@ -787,11 +817,16 @@
 {
   c->buffer->deallocate_var_all ();
   c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
-  if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
+  if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
   {
-    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
+    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
 			      (unsigned) HB_BUFFER_MAX_LEN_MIN);
   }
+  if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
+  {
+    c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
+			      (unsigned) HB_BUFFER_MAX_OPS_MIN);
+  }
 
   bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan);
   //c->fallback_substitute     = disable_otl || !hb_ot_layout_has_substitution (c->face);
@@ -805,8 +840,10 @@
 
   c->buffer->clear_output ();
 
+  hb_ot_shape_initialize_masks (c);
   hb_set_unicode_props (c->buffer);
   hb_insert_dotted_circle (c->buffer, c->font);
+
   hb_form_clusters (c->buffer);
 
   hb_ensure_native_direction (c->buffer);
@@ -822,11 +859,14 @@
   if (c->plan->shaper->postprocess_glyphs)
     c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
 
+  hb_propagate_flags (c->buffer);
+
   _hb_buffer_deallocate_unicode_vars (c->buffer);
 
   c->buffer->props.direction = c->target_direction;
 
   c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+  c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
   c->buffer->deallocate_var_all ();
 }
 
@@ -894,7 +934,7 @@
 {
   hb_ot_shape_plan_t plan;
 
-  const char *shapers[] = {"ot", NULL};
+  const char *shapers[] = {"ot", nullptr};
   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
 							     features, num_features, shapers);
 
@@ -905,18 +945,19 @@
   for (unsigned int i = 0; i < count; i++)
     add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
 
-  hb_set_t lookups;
-  lookups.init ();
-  hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
+  hb_set_t *lookups = hb_set_create ();
+  hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, lookups);
 
   /* And find transitive closure. */
-  hb_set_t copy;
-  copy.init ();
+  hb_set_t *copy = hb_set_create ();
   do {
-    copy.set (glyphs);
-    for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
+    copy->set (glyphs);
+    for (hb_codepoint_t lookup_index = -1; hb_set_next (lookups, &lookup_index);)
       hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
-  } while (!copy.is_equal (glyphs));
+  } while (!copy->is_equal (glyphs));
+  hb_set_destroy (copy);
+
+  hb_set_destroy (lookups);
 
   hb_shape_plan_destroy (shape_plan);
 }
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index 9b0db50..1338c31 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -270,28 +270,36 @@
   {"cak",	HB_TAG('C','A','K',' ')},	/* Kaqchikel */
   {"cbk",	HB_TAG('C','B','K',' ')},	/* Chavacano */
   {"cbl",	HB_TAG('Q','I','N',' ')},	/* Bualkhaw Chin */
+  {"cco",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"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')},	/* Chinantec */
   {"chk",	HB_TAG('C','H','K','0')},	/* Chuukese */
   {"cho",	HB_TAG('C','H','O',' ')},	/* Choctaw */
   {"chp",	HB_TAG('C','H','P',' ')},	/* Chipewyan */
+  {"chq",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"chr",	HB_TAG('C','H','R',' ')},	/* Cherokee */
   {"chy",	HB_TAG('C','H','Y',' ')},	/* Cheyenne */
+  {"chz",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"cja",	HB_TAG('C','J','A',' ')},	/* Western Cham */
   {"cjm",	HB_TAG('C','J','M',' ')},	/* Eastern Cham */
   {"cka",	HB_TAG('Q','I','N',' ')},	/* Khumi Awa Chin */
   {"ckb",	HB_TAG('K','U','R',' ')},	/* Central Kurdish (Sorani) */
   {"ckt",	HB_TAG('C','H','K',' ')},	/* Chukchi */
   {"cld",	HB_TAG('S','Y','R',' ')},	/* Chaldean Neo-Aramaic */
+  {"cle",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"cmr",	HB_TAG('Q','I','N',' ')},	/* Mro-Khimi Chin */
   {"cnb",	HB_TAG('Q','I','N',' ')},	/* Chinbon Chin */
   {"cnh",	HB_TAG('Q','I','N',' ')},	/* Hakha Chin */
   {"cnk",	HB_TAG('Q','I','N',' ')},	/* Khumi Chin */
+  {"cnl",	HB_TAG('C','C','H','N')},	/* Chinantec */
+  {"cnt",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"cnw",	HB_TAG('Q','I','N',' ')},	/* Ngawn Chin */
   {"cop",	HB_TAG('C','O','P',' ')},	/* Coptic */
+  {"cpa",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"cpp",	HB_TAG('C','P','P',' ')},	/* Creoles */
   {"cr",	HB_TAG('C','R','E',' ')},	/* Cree */
   {"cre",	HB_TAG('Y','C','R',' ')},	/* Y-Cree */
@@ -302,15 +310,21 @@
   {"crm",	HB_TAG('M','C','R',' ')},	/* Moose Cree */
   {"crx",	HB_TAG('C','R','R',' ')},	/* Carrier */
   {"cs",	HB_TAG('C','S','Y',' ')},	/* Czech */
+  {"csa",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"csb",	HB_TAG('C','S','B',' ')},	/* Kashubian */
   {"csh",	HB_TAG('Q','I','N',' ')},	/* Asho Chin */
+  {"cso",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"csy",	HB_TAG('Q','I','N',' ')},	/* Siyin Chin */
   {"ctd",	HB_TAG('Q','I','N',' ')},	/* Tedim Chin */
+  {"cte",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"ctg",	HB_TAG('C','T','G',' ')},	/* Chittagonian */
+  {"ctl",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"cts",	HB_TAG('B','I','K',' ')},	/* Northern Catanduanes Bikol */
   {"cu",	HB_TAG('C','S','L',' ')},	/* Church Slavic */
+  {"cuc",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"cuk",	HB_TAG('C','U','K',' ')},	/* San Blas Kuna */
   {"cv",	HB_TAG('C','H','U',' ')},	/* Chuvash */
+  {"cvn",	HB_TAG('C','C','H','N')},	/* Chinantec */
   {"cwd",	HB_TAG('D','C','R',' ')},	/* Woods Cree */
   {"cy",	HB_TAG('W','E','L',' ')},	/* Welsh */
   {"czt",	HB_TAG('Q','I','N',' ')},	/* Zotung Chin */
@@ -380,7 +394,6 @@
   {"gkp",	HB_TAG('G','K','P',' ')},	/* Kpelle (Guinea) */
   {"gl",	HB_TAG('G','A','L',' ')},	/* Galician */
   {"gld",	HB_TAG('N','A','N',' ')},	/* Nanai */
-  {"gle",	HB_TAG('I','R','T',' ')},	/* Irish Traditional */
   {"glk",	HB_TAG('G','L','K',' ')},	/* Gilaki */
   {"gn",	HB_TAG('G','U','A',' ')},	/* Guarani [macrolanguage] */
   {"gnn",	HB_TAG('G','N','N',' ')},	/* Gumatj */
@@ -538,7 +551,6 @@
   {"mag",	HB_TAG('M','A','G',' ')},	/* Magahi */
   {"mai",	HB_TAG('M','T','H',' ')},	/* Maithili */
   {"mak",	HB_TAG('M','K','R',' ')},	/* Makasar */
-  {"mal",	HB_TAG('M','A','L',' ')},	/* Malayalam */
   {"mam",	HB_TAG('M','A','M',' ')},	/* Mam */
   {"man",	HB_TAG('M','N','K',' ')},	/* Manding/Mandingo [macrolanguage] */
   {"mdc",	HB_TAG('M','L','E',' ')},	/* Male (Papua New Guinea) */
@@ -867,9 +879,11 @@
 };
 
 static int
-lang_compare_first_component (const char *a,
-			      const char *b)
+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;
 
@@ -906,12 +920,12 @@
     char tag[4];
     int i;
     s += 6;
-    for (i = 0; i < 4 && ISALPHA (s[i]); i++)
+    for (i = 0; i < 4 && ISALNUM (s[i]); i++)
       tag[i] = TOUPPER (s[i]);
     if (i) {
       for (; i < 4; i++)
 	tag[i] = ' ';
-      return HB_TAG_CHAR4 (tag);
+      return HB_TAG (tag[0], tag[1], tag[2], tag[3]);
     }
   }
 
@@ -960,7 +974,7 @@
     const LangTag *lang_tag;
     lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
 				    ARRAY_LENGTH (ot_languages), sizeof (LangTag),
-				    (hb_compare_func_t) lang_compare_first_component);
+				    lang_compare_first_component);
     if (lang_tag)
       return lang_tag->tag;
   }
@@ -1008,7 +1022,7 @@
   unsigned int i;
 
   if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
-    return NULL;
+    return nullptr;
 
   /* struct LangTag has only room for 3-letter language tags. */
   switch (tag) {
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
index ace0f5f..4b88a40 100644
--- a/src/hb-ot-var-avar-table.hh
+++ b/src/hb-ot-var-avar-table.hh
@@ -57,8 +57,13 @@
      * that at least -1, 0, and +1 must be mapped. But we include these as
      * part of a better error recovery scheme. */
 
-    if (!len)
-      return value;
+    if (len < 2)
+    {
+      if (!len)
+	return value;
+      else /* len == 1*/
+	return value - array[0].fromCoord + array[0].toCoord;
+    }
 
     if (value <= array[0].fromCoord)
       return value - array[0].fromCoord + array[0].toCoord;
@@ -76,8 +81,8 @@
 
     int denom = array[i].fromCoord - array[i-1].fromCoord;
     return array[i-1].toCoord +
-	   (array[i].toCoord - array[i-1].toCoord) *
-	   (value - array[i-1].fromCoord + denom/2) / denom;
+	   ((array[i].toCoord - array[i-1].toCoord) *
+	    (value - array[i-1].fromCoord) + denom/2) / denom;
   }
 
   DEFINE_SIZE_ARRAY (2, array);
@@ -128,8 +133,8 @@
   protected:
   FixedVersion<>version;	/* Version of the avar table
 				 * initially set to 0x00010000u */
-  USHORT	reserved;	/* This field is permanently reserved. Set to 0. */
-  USHORT	axisCount;	/* The number of variation axes in the font. This
+  UINT16	reserved;	/* This field is permanently reserved. Set to 0. */
+  UINT16	axisCount;	/* The number of variation axes in the font. This
 				 * must be the same number as axisCount in the
 				 * 'fvar' table. */
   SegmentMaps	axisSegmentMapsZ;
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 9f6fb32..2a9357a 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -42,11 +42,11 @@
   }
 
   protected:
-  USHORT	subfamilyNameID;/* The name ID for entries in the 'name' table
+  UINT16	subfamilyNameID;/* The name ID for entries in the 'name' table
 				 * that provide subfamily names for this instance. */
-  USHORT	reserved;	/* Reserved for future use — set to 0. */
+  UINT16	reserved;	/* Reserved for future use — set to 0. */
   Fixed		coordinates[VAR];/* The coordinates array for this instance. */
-  //USHORT	postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
+  //UINT16	postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
   //				  * table that provide PostScript names for this
   //				  * instance. */
 
@@ -67,8 +67,8 @@
   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. */
-  USHORT	reserved;	/* Reserved for future use — set to 0. */
-  USHORT	axisNameID;	/* The name ID for entries in the 'name' table that
+  UINT16	reserved;	/* Reserved for future use — set to 0. */
+  UINT16	axisNameID;	/* The name ID for entries in the 'name' table that
 				 * provide a display name for this axis. */
 
   public:
@@ -186,16 +186,16 @@
   protected:
   FixedVersion<>version;	/* Version of the fvar table
 				 * initially set to 0x00010000u */
-  Offset<>	things;		/* Offset in bytes from the beginning of the table
+  Offset16	things;		/* Offset in bytes from the beginning of the table
 				 * to the start of the AxisRecord array. */
-  USHORT	reserved;	/* This field is permanently reserved. Set to 2. */
-  USHORT	axisCount;	/* The number of variation axes in the font (the
+  UINT16	reserved;	/* This field is permanently reserved. Set to 2. */
+  UINT16	axisCount;	/* The number of variation axes in the font (the
 				 * number of records in the axes array). */
-  USHORT	axisSize;	/* The size in bytes of each VariationAxisRecord —
+  UINT16	axisSize;	/* The size in bytes of each VariationAxisRecord —
 				 * set to 20 (0x0014) for this version. */
-  USHORT	instanceCount;	/* The number of named instances defined in the font
+  UINT16	instanceCount;	/* The number of named instances defined in the font
 				 * (the number of records in the instances array). */
-  USHORT	instanceSize;	/* The size in bytes of each InstanceRecord — set
+  UINT16	instanceSize;	/* The size in bytes of each InstanceRecord — set
 				 * to either axisCount * sizeof(Fixed) + 4, or to
 				 * axisCount * sizeof(Fixed) + 6. */
 
diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh
index 3a2a820..fac843a 100644
--- a/src/hb-ot-var-hvar-table.hh
+++ b/src/hb-ot-var-hvar-table.hh
@@ -55,7 +55,7 @@
     unsigned int u = 0;
     { /* Fetch it. */
       unsigned int w = get_width ();
-      const BYTE *p = mapData + w * v;
+      const UINT8 *p = mapData + w * v;
       for (; w; w--)
 	u = (u << 8) + *p++;
     }
@@ -78,10 +78,10 @@
   { return (format & 0xF) + 1; }
 
   protected:
-  USHORT format;		/* A packed field that describes the compressed
+  UINT16	format;		/* A packed field that describes the compressed
 				 * representation of delta-set indices. */
-  USHORT mapCount;		/* The number of mapping entries. */
-  BYTE mapData[VAR];		/* The delta-set index mapping data. */
+  UINT16	mapCount;	/* The number of mapping entries. */
+  UINT8		mapData[VAR];	/* The delta-set index mapping data. */
 
   public:
   DEFINE_SIZE_ARRAY (4, mapData);
diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh
new file mode 100644
index 0000000..e17ff51
--- /dev/null
+++ b/src/hb-ot-var-mvar-table.hh
@@ -0,0 +1,114 @@
+/*
+ * 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_OT_VAR_MVAR_TABLE_HH
+#define HB_OT_VAR_MVAR_TABLE_HH
+
+#include "hb-ot-layout-common-private.hh"
+
+
+namespace OT {
+
+
+struct VariationValueRecord
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  public:
+  Tag		valueTag;	/* Four-byte tag identifying a font-wide measure. */
+  UINT32		varIdx;		/* Outer/inner index into VariationStore item. */
+
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+
+/*
+ * MVAR -- Metrics Variations Table
+ */
+
+#define HB_OT_TAG_MVAR HB_TAG('M','V','A','R')
+
+struct MVAR
+{
+  static const hb_tag_t tableTag	= HB_OT_TAG_MVAR;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  likely (version.major == 1) &&
+		  c->check_struct (this) &&
+		  valueRecordSize >= VariationValueRecord::static_size &&
+		  varStore.sanitize (c, this) &&
+		  c->check_array (values, valueRecordSize, valueRecordCount));
+  }
+
+  inline float get_var (hb_tag_t tag,
+			int *coords, unsigned int coord_count) const
+  {
+    const VariationValueRecord *record;
+    record = (VariationValueRecord *) bsearch (&tag, values,
+					       valueRecordCount, valueRecordSize,
+					       tag_compare);
+    if (!record)
+      return 0.;
+
+    return (this+varStore).get_delta (record->varIdx, coords, coord_count);
+  }
+
+protected:
+  static inline int tag_compare (const void *pa, const void *pb)
+  {
+    const hb_tag_t *a = (const hb_tag_t *) pa;
+    const Tag *b = (const Tag *) pb;
+    return b->cmp (*a);
+  }
+
+  protected:
+  FixedVersion<>version;	/* Version of the metrics variation table
+				 * initially set to 0x00010000u */
+  UINT16	reserved;	/* Not used; set to 0. */
+  UINT16	valueRecordSize;/* The size in bytes of each value record —
+				 * must be greater than zero. */
+  UINT16	valueRecordCount;/* The number of value records — may be zero. */
+  OffsetTo<VariationStore>
+		varStore;	/* Offset to item variation store table. */
+  UINT8		values[VAR];	/* Array of value records. The records must be
+				 * in binary order of their valueTag field. */
+
+  public:
+  DEFINE_SIZE_ARRAY (12, values);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_VAR_MVAR_TABLE_HH */
diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc
index d4d16df..90ba0bd 100644
--- a/src/hb-ot-var.cc
+++ b/src/hb-ot-var.cc
@@ -29,10 +29,9 @@
 #include "hb-ot-layout-private.hh"
 #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"
 
-HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
-
 /*
  * fvar/avar
  */
@@ -131,7 +130,7 @@
   for (unsigned int i = 0; i < variations_length; i++)
   {
     unsigned int axis_index;
-    if (hb_ot_var_find_axis (face, variations[i].tag, &axis_index, NULL) &&
+    if (hb_ot_var_find_axis (face, variations[i].tag, &axis_index, nullptr) &&
 	axis_index < coords_length)
       coords[axis_index] = fvar.normalize_axis_value (axis_index, variations[i].value);
   }
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 666af62..acddd89 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -44,16 +44,14 @@
 #include <stddef.h>
 #include <string.h>
 #include <assert.h>
-
-/* We only use these two for debug output.  However, the debug code is
- * always seen by the compiler (and optimized out in non-debug builds.
- * If including these becomes a problem, we can start thinking about
- * someway around that. */
-#include <stdio.h>
 #include <errno.h>
+#include <stdio.h>
 #include <stdarg.h>
 
 
+#define HB_PASTE1(a,b) a##b
+#define HB_PASTE(a,b) HB_PASTE1(a,b)
+
 /* Compile-time custom allocator support. */
 
 #if defined(hb_malloc_impl) \
@@ -74,10 +72,25 @@
 /* Compiler attributes */
 
 
-#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
-#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
-#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
-#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
+#if __cplusplus < 201103L
+
+#ifndef nullptr
+#define nullptr NULL
+#endif
+
+// Static assertions
+#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
+
+#endif // __cplusplus < 201103L
+
+#define _GNU_SOURCE 1
+
+#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
+#define likely(expr) (__builtin_expect (!!(expr), 1))
+#define unlikely(expr) (__builtin_expect (!!(expr), 0))
 #else
 #define likely(expr) (expr)
 #define unlikely(expr) (expr)
@@ -99,6 +112,8 @@
 #endif
 #if __GNUC__ >= 4
 #define HB_UNUSED	__attribute__((unused))
+#elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */
+#define HB_UNUSED __pragma(warning(suppress: 4100 4101))
 #else
 #define HB_UNUSED
 #endif
@@ -168,21 +183,17 @@
 
 #  if defined(_WIN32_WCE)
      /* Some things not defined on Windows CE. */
-#    define strdup _strdup
 #    define vsnprintf _vsnprintf
-#    define getenv(Name) NULL
+#    define getenv(Name) nullptr
 #    if _WIN32_WCE < 0x800
 #      define setlocale(Category, Locale) "C"
 static int errno = 0; /* Use something better? */
 #    endif
 #  elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
-#    define getenv(Name) NULL
+#    define getenv(Name) nullptr
 #  endif
 #  if defined(_MSC_VER) && _MSC_VER < 1900
 #    define snprintf _snprintf
-#  elif defined(_MSC_VER) && _MSC_VER >= 1900
-#    /* Covers VC++ Error for strdup being a deprecated POSIX name and to instead use _strdup instead */
-#    define strdup _strdup
 #  endif
 #endif
 
@@ -214,11 +225,6 @@
 
 /* Basics */
 
-
-#ifndef NULL
-# define NULL ((void *) 0)
-#endif
-
 #undef MIN
 template <typename Type>
 static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
@@ -240,32 +246,26 @@
 #define HB_STMT_START do
 #define HB_STMT_END   while (0)
 
-#define _ASSERT_STATIC1(_line, _cond)	HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
-#define _ASSERT_STATIC0(_line, _cond)	_ASSERT_STATIC1 (_line, (_cond))
-#define ASSERT_STATIC(_cond)		_ASSERT_STATIC0 (__LINE__, (_cond))
-
-template <unsigned int cond> class hb_assert_constant_t {};
+template <unsigned int cond> class hb_assert_constant_t;
+template <> class hb_assert_constant_t<1> {};
 
 #define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
 
-#define _PASTE1(a,b) a##b
-#define PASTE(a,b) _PASTE1(a,b)
-
 /* Lets assert int types.  Saves trouble down the road. */
 
-ASSERT_STATIC (sizeof (int8_t) == 1);
-ASSERT_STATIC (sizeof (uint8_t) == 1);
-ASSERT_STATIC (sizeof (int16_t) == 2);
-ASSERT_STATIC (sizeof (uint16_t) == 2);
-ASSERT_STATIC (sizeof (int32_t) == 4);
-ASSERT_STATIC (sizeof (uint32_t) == 4);
-ASSERT_STATIC (sizeof (int64_t) == 8);
-ASSERT_STATIC (sizeof (uint64_t) == 8);
+static_assert ((sizeof (int8_t) == 1), "");
+static_assert ((sizeof (uint8_t) == 1), "");
+static_assert ((sizeof (int16_t) == 2), "");
+static_assert ((sizeof (uint16_t) == 2), "");
+static_assert ((sizeof (int32_t) == 4), "");
+static_assert ((sizeof (uint32_t) == 4), "");
+static_assert ((sizeof (int64_t) == 8), "");
+static_assert ((sizeof (uint64_t) == 8), "");
 
-ASSERT_STATIC (sizeof (hb_codepoint_t) == 4);
-ASSERT_STATIC (sizeof (hb_position_t) == 4);
-ASSERT_STATIC (sizeof (hb_mask_t) == 4);
-ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
+static_assert ((sizeof (hb_codepoint_t) == 4), "");
+static_assert ((sizeof (hb_position_t) == 4), "");
+static_assert ((sizeof (hb_mask_t) == 4), "");
+static_assert ((sizeof (hb_var_int_t) == 4), "");
 
 
 /* We like our types POD */
@@ -300,7 +300,7 @@
 /* Void! */
 struct _hb_void_t {};
 typedef const _hb_void_t *hb_void_t;
-#define HB_VOID ((const _hb_void_t *) NULL)
+#define HB_VOID ((const _hb_void_t *) nullptr)
 
 /* Return the number of 1 bits in mask. */
 static inline HB_CONST_FUNC unsigned int
@@ -316,6 +316,18 @@
   return (((y + (y >> 3)) & 030707070707) % 077);
 #endif
 }
+static inline HB_CONST_FUNC unsigned int
+_hb_popcount64 (uint64_t mask)
+{
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+  if (sizeof (long) >= sizeof (mask))
+    return __builtin_popcountl (mask);
+#endif
+  return _hb_popcount32 (mask & 0xFFFFFFFF) + _hb_popcount32 (mask >> 32);
+}
+template <typename T> static inline unsigned int _hb_popcount (T mask);
+template <> inline unsigned int _hb_popcount<uint32_t> (uint32_t mask) { return _hb_popcount32 (mask); }
+template <> inline unsigned int _hb_popcount<uint64_t> (uint64_t mask) { return _hb_popcount64 (mask); }
 
 /* Returns the number of bits needed to store number */
 static inline HB_CONST_FUNC unsigned int
@@ -357,16 +369,11 @@
 }
 
 
-/* Type of bsearch() / qsort() compare function */
-typedef int (*hb_compare_func_t) (const void *, const void *);
-
-
-
 
 /* arrays and maps */
 
 
-#define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
+#define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr}
 template <typename Type, unsigned int StaticSize=16>
 struct hb_prealloced_array_t
 {
@@ -375,41 +382,56 @@
   Type *array;
   Type static_array[StaticSize];
 
-  void init (void) { memset (this, 0, sizeof (*this)); }
+  void init (void)
+  {
+    len = 0;
+    allocated = ARRAY_LENGTH (static_array);
+    array = static_array;
+  }
 
   inline Type& operator [] (unsigned int i) { return array[i]; }
   inline const Type& operator [] (unsigned int i) const { return array[i]; }
 
   inline Type *push (void)
   {
-    if (!array) {
-      array = static_array;
-      allocated = ARRAY_LENGTH (static_array);
-    }
-    if (likely (len < allocated))
-      return &array[len++];
+    if (unlikely (!resize (len + 1)))
+      return nullptr;
 
-    /* Need to reallocate */
-    unsigned int new_allocated = allocated + (allocated >> 1) + 8;
-    Type *new_array = NULL;
+    return &array[len - 1];
+  }
 
-    if (array == static_array) {
-      new_array = (Type *) calloc (new_allocated, sizeof (Type));
-      if (new_array)
-        memcpy (new_array, array, len * sizeof (Type));
-    } else {
-      bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
-      if (likely (!overflows)) {
-	new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
+  inline bool resize (unsigned int size)
+  {
+    if (unlikely (size > allocated))
+    {
+      /* Need to reallocate */
+
+      unsigned int new_allocated = allocated;
+      while (size >= new_allocated)
+        new_allocated += (new_allocated >> 1) + 8;
+
+      Type *new_array = nullptr;
+
+      if (array == static_array) {
+	new_array = (Type *) calloc (new_allocated, sizeof (Type));
+	if (new_array)
+	  memcpy (new_array, array, len * sizeof (Type));
+      } else {
+	bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
+	if (likely (!overflows)) {
+	  new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
+	}
       }
+
+      if (unlikely (!new_array))
+	return false;
+
+      array = new_array;
+      allocated = new_allocated;
     }
 
-    if (unlikely (!new_array))
-      return NULL;
-
-    array = new_array;
-    allocated = new_allocated;
-    return &array[len++];
+    len = size;
+    return true;
   }
 
   inline void pop (void)
@@ -438,42 +460,67 @@
     for (unsigned int i = 0; i < len; i++)
       if (array[i] == v)
 	return &array[i];
-    return NULL;
+    return nullptr;
   }
   template <typename T>
   inline const Type *find (T v) const {
     for (unsigned int i = 0; i < len; i++)
       if (array[i] == v)
 	return &array[i];
-    return NULL;
+    return nullptr;
   }
 
   inline void qsort (void)
   {
-    ::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+    ::qsort (array, len, sizeof (Type), Type::cmp);
   }
 
   inline void qsort (unsigned int start, unsigned int end)
   {
-    ::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
+    ::qsort (array + start, end - start, sizeof (Type), Type::cmp);
   }
 
   template <typename T>
-  inline Type *bsearch (T *key)
+  inline Type *bsearch (T *x)
   {
-    return (Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+    unsigned int i;
+    return bfind (x, &i) ? &array[i] : nullptr;
   }
   template <typename T>
-  inline const Type *bsearch (T *key) const
+  inline const Type *bsearch (T *x) const
   {
-    return (const Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+    unsigned int i;
+    return bfind (x, &i) ? &array[i] : nullptr;
+  }
+  template <typename T>
+  inline bool bfind (T *x, unsigned int *i) const
+  {
+    int min = 0, max = (int) this->len - 1;
+    while (min <= max)
+    {
+      int mid = (min + max) / 2;
+      int c = this->array[mid].cmp (x);
+      if (c < 0)
+        max = mid - 1;
+      else if (c > 0)
+        min = mid + 1;
+      else
+      {
+        *i = mid;
+	return true;
+      }
+    }
+    if (max < 0 || (max < (int) this->len && this->array[max].cmp (x) > 0))
+      max++;
+    *i = max;
+    return false;
   }
 
   inline void finish (void)
   {
     if (array != static_array)
       free (array);
-    array = NULL;
+    array = nullptr;
     allocated = len = 0;
   }
 };
@@ -490,7 +537,7 @@
 template <typename item_t, typename lock_t>
 struct hb_lockable_set_t
 {
-  hb_prealloced_array_t <item_t, 2> items;
+  hb_prealloced_array_t <item_t, 1> items;
 
   inline void init (void) { items.init (); }
 
@@ -507,7 +554,7 @@
 	old.finish ();
       }
       else {
-        item = NULL;
+        item = nullptr;
 	l.unlock ();
       }
     } else {
@@ -595,22 +642,6 @@
 static inline unsigned char TOLOWER (unsigned char c)
 { return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
 
-#define HB_TAG_CHAR4(s)   (HB_TAG(((const char *) s)[0], \
-				  ((const char *) s)[1], \
-				  ((const char *) s)[2], \
-				  ((const char *) s)[3]))
-
-
-/* C++ helpers */
-
-/* Makes class uncopyable.  Use in private: section. */
-#define NO_COPY(T) \
-  T (const T &o); \
-  T &operator = (const T &o)
-
-
-/* Debug */
-
 
 /* HB_NDEBUG disables some sanity checks that are very safe to disable and
  * should be disabled in production systems.  If NDEBUG is defined, enable
@@ -621,255 +652,6 @@
 #define HB_NDEBUG
 #endif
 
-#ifndef HB_DEBUG
-#define HB_DEBUG 0
-#endif
-
-static inline bool
-_hb_debug (unsigned int level,
-	   unsigned int max_level)
-{
-  return level < max_level;
-}
-
-#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
-#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
-
-static inline void
-_hb_print_func (const char *func)
-{
-  if (func)
-  {
-    unsigned int func_len = strlen (func);
-    /* Skip "static" */
-    if (0 == strncmp (func, "static ", 7))
-      func += 7;
-    /* Skip "typename" */
-    if (0 == strncmp (func, "typename ", 9))
-      func += 9;
-    /* Skip return type */
-    const char *space = strchr (func, ' ');
-    if (space)
-      func = space + 1;
-    /* Skip parameter list */
-    const char *paren = strchr (func, '(');
-    if (paren)
-      func_len = paren - func;
-    fprintf (stderr, "%.*s", func_len, func);
-  }
-}
-
-template <int max_level> static inline void
-_hb_debug_msg_va (const char *what,
-		  const void *obj,
-		  const char *func,
-		  bool indented,
-		  unsigned int level,
-		  int level_dir,
-		  const char *message,
-		  va_list ap) HB_PRINTF_FUNC(7, 0);
-template <int max_level> static inline void
-_hb_debug_msg_va (const char *what,
-		  const void *obj,
-		  const char *func,
-		  bool indented,
-		  unsigned int level,
-		  int level_dir,
-		  const char *message,
-		  va_list ap)
-{
-  if (!_hb_debug (level, max_level))
-    return;
-
-  fprintf (stderr, "%-10s", what ? what : "");
-
-  if (obj)
-    fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj);
-  else
-    fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");
-
-  if (indented) {
-#define VBAR	"\342\224\202"	/* U+2502 BOX DRAWINGS LIGHT VERTICAL */
-#define VRBAR	"\342\224\234"	/* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
-#define DLBAR	"\342\225\256"	/* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
-#define ULBAR	"\342\225\257"	/* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
-#define LBAR	"\342\225\264"	/* U+2574 BOX DRAWINGS LIGHT LEFT */
-    static const char bars[] =
-      VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
-      VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
-      VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
-      VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
-      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),
-	     level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
-  } else
-    fprintf (stderr, "   " VRBAR LBAR);
-
-  _hb_print_func (func);
-
-  if (message)
-  {
-    fprintf (stderr, ": ");
-    vfprintf (stderr, message, ap);
-  }
-
-  fprintf (stderr, "\n");
-}
-template <> inline void
-_hb_debug_msg_va<0> (const char *what HB_UNUSED,
-		     const void *obj HB_UNUSED,
-		     const char *func HB_UNUSED,
-		     bool indented HB_UNUSED,
-		     unsigned int level HB_UNUSED,
-		     int level_dir HB_UNUSED,
-		     const char *message HB_UNUSED,
-		     va_list ap HB_UNUSED) {}
-
-template <int max_level> static inline void
-_hb_debug_msg (const char *what,
-	       const void *obj,
-	       const char *func,
-	       bool indented,
-	       unsigned int level,
-	       int level_dir,
-	       const char *message,
-	       ...) HB_PRINTF_FUNC(7, 8);
-template <int max_level> static inline void
-_hb_debug_msg (const char *what,
-	       const void *obj,
-	       const char *func,
-	       bool indented,
-	       unsigned int level,
-	       int level_dir,
-	       const char *message,
-	       ...)
-{
-  va_list ap;
-  va_start (ap, message);
-  _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
-  va_end (ap);
-}
-template <> inline void
-_hb_debug_msg<0> (const char *what HB_UNUSED,
-		  const void *obj HB_UNUSED,
-		  const char *func HB_UNUSED,
-		  bool indented HB_UNUSED,
-		  unsigned int level HB_UNUSED,
-		  int level_dir HB_UNUSED,
-		  const char *message HB_UNUSED,
-		  ...) HB_PRINTF_FUNC(7, 8);
-template <> inline void
-_hb_debug_msg<0> (const char *what HB_UNUSED,
-		  const void *obj HB_UNUSED,
-		  const char *func HB_UNUSED,
-		  bool indented HB_UNUSED,
-		  unsigned int level HB_UNUSED,
-		  int level_dir HB_UNUSED,
-		  const char *message HB_UNUSED,
-		  ...) {}
-
-#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)	_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
-#define DEBUG_MSG(WHAT, OBJ, ...) 				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    false, 0, 0, __VA_ARGS__)
-#define DEBUG_MSG_FUNC(WHAT, OBJ, ...)				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
-
-
-/*
- * Printer
- */
-
-template <typename T>
-struct hb_printer_t {
-  const char *print (const T&) { return "something"; }
-};
-
-template <>
-struct hb_printer_t<bool> {
-  const char *print (bool v) { return v ? "true" : "false"; }
-};
-
-template <>
-struct hb_printer_t<hb_void_t> {
-  const char *print (hb_void_t) { return ""; }
-};
-
-
-/*
- * Trace
- */
-
-template <typename T>
-static inline void _hb_warn_no_return (bool returned)
-{
-  if (unlikely (!returned)) {
-    fprintf (stderr, "OUCH, returned with no call to return_trace().  This is a bug, please report.\n");
-  }
-}
-template <>
-/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
-{}
-
-template <int max_level, typename ret_t>
-struct hb_auto_trace_t {
-  explicit inline hb_auto_trace_t (unsigned int *plevel_,
-				   const char *what_,
-				   const void *obj_,
-				   const char *func,
-				   const char *message,
-				   ...) : plevel (plevel_), what (what_), obj (obj_), returned (false)
-  {
-    if (plevel) ++*plevel;
-
-    va_list ap;
-    va_start (ap, message);
-    _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
-    va_end (ap);
-  }
-  inline ~hb_auto_trace_t (void)
-  {
-    _hb_warn_no_return<ret_t> (returned);
-    if (!returned) {
-      _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
-    }
-    if (plevel) --*plevel;
-  }
-
-  inline ret_t ret (ret_t v, unsigned int line = 0)
-  {
-    if (unlikely (returned)) {
-      fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
-      return v;
-    }
-
-    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1,
-			      "return %s (line %d)",
-			      hb_printer_t<ret_t>().print (v), line);
-    if (plevel) --*plevel;
-    plevel = NULL;
-    returned = true;
-    return v;
-  }
-
-  private:
-  unsigned int *plevel;
-  const char *what;
-  const void *obj;
-  bool returned;
-};
-template <typename ret_t> /* Optimize when tracing is disabled */
-struct hb_auto_trace_t<0, ret_t> {
-  explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED,
-				   const char *what HB_UNUSED,
-				   const void *obj HB_UNUSED,
-				   const char *func HB_UNUSED,
-				   const char *message HB_UNUSED,
-				   ...) {}
-
-  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
-};
-
-#define return_trace(RET) return trace.ret (RET, __LINE__)
 
 /* Misc */
 
@@ -887,7 +669,7 @@
    * 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. */
-  ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
+  static_assert ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
 
   /* The casts below are important as if T is smaller than int,
    * the subtract results will become a signed int! */
@@ -912,7 +694,7 @@
  * one enum to another...  So this doesn't provide the type-checking that I
  * originally had in mind... :(.
  *
- * For MSVC warnings, see: https://github.com/behdad/harfbuzz/pull/163
+ * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
  */
 #ifdef _MSC_VER
 # pragma warning(disable:4200)
@@ -932,11 +714,10 @@
 
 /* Useful for set-operations on small enums.
  * For example, for testing "x ∈ {x1, x2, x3}" use:
- * (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
  */
-#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((x) < 32) + (1U << (x)))
-#define FLAG_SAFE(x) (1U << (x))
-#define FLAG_UNSAFE(x) ((x) < 32 ? FLAG_SAFE(x) : 0)
+#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned int)(x) < 32) + (1U << (unsigned int)(x)))
+#define FLAG_UNSAFE(x) ((unsigned int)(x) < 32 ? (1U << (unsigned int)(x)) : 0)
 #define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
 
 
@@ -968,7 +749,7 @@
 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 *) NULL);
+  hb_stable_sort (array, len, compar, (int *) nullptr);
 }
 
 static inline hb_bool_t
@@ -990,6 +771,73 @@
 }
 
 
+/* Vectorization */
+
+struct HbOpOr
+{
+  static const bool passthru_left = true;
+  static const bool passthru_right = true;
+  template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
+};
+struct HbOpAnd
+{
+  static const bool passthru_left = false;
+  static const bool passthru_right = false;
+  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
+};
+struct HbOpMinus
+{
+  static const bool passthru_left = true;
+  static const bool passthru_right = false;
+  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
+};
+struct HbOpXor
+{
+  static const bool passthru_left = true;
+  static const bool passthru_right = true;
+  template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
+};
+
+/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))). */
+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]; }
+
+  template <class Op>
+  inline hb_vector_size_t process (const hb_vector_size_t &o) const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      Op::process (r.v[i], v[i], o.v[i]);
+    return r;
+  }
+  inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
+  { return process<HbOpOr> (o); }
+  inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
+  { return process<HbOpAnd> (o); }
+  inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
+  { return process<HbOpXor> (o); }
+  inline hb_vector_size_t operator ~ () const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      r.v[i] = ~v[i];
+    return r;
+  }
+
+  private:
+  static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
+  elt_t v[byte_size / sizeof (elt_t)];
+};
+
+/* The `vector_size' attribute was introduced in gcc 3.1. */
+#if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
+#define HAVE_VECTOR_SIZE 1
+#endif
+
+
 /* Global runtime options. */
 
 struct hb_options_t
@@ -1002,7 +850,7 @@
   unsigned int i;
   hb_options_t opts;
 };
-ASSERT_STATIC (sizeof (int) == sizeof (hb_options_union_t));
+static_assert ((sizeof (int) == sizeof (hb_options_union_t)), "");
 
 HB_INTERNAL void
 _hb_options_init (void);
@@ -1021,4 +869,31 @@
 /* Size signifying variable-sized array */
 #define VAR 1
 
+
+/* String type. */
+
+struct hb_string_t
+{
+  inline hb_string_t (void) : bytes (nullptr), len (0) {}
+  inline hb_string_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
+
+  inline int cmp (const hb_string_t &a) const
+  {
+    if (len != a.len)
+      return (int) a.len - (int) len;
+
+    return memcmp (a.bytes, bytes, len);
+  }
+  static inline int cmp (const void *pa, const void *pb)
+  {
+    hb_string_t *a = (hb_string_t *) pa;
+    hb_string_t *b = (hb_string_t *) pb;
+    return b->cmp (*a);
+  }
+
+  const char *bytes;
+  unsigned int len;
+};
+
+
 #endif /* HB_PRIVATE_HH */
diff --git a/src/hb-set-digest-private.hh b/src/hb-set-digest-private.hh
new file mode 100644
index 0000000..e099a82
--- /dev/null
+++ b/src/hb-set-digest-private.hh
@@ -0,0 +1,179 @@
+/*
+ * 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
+ */
+
+#ifndef HB_SET_DIGEST_PRIVATE_HH
+#define HB_SET_DIGEST_PRIVATE_HH
+
+#include "hb-private.hh"
+
+/*
+ * The set digests here implement various "filters" that support
+ * "approximate member query".  Conceptually these are like Bloom
+ * Filter and Quotient Filter, however, much smaller, faster, and
+ * designed to fit the requirements of our uses for glyph coverage
+ * queries.
+ *
+ * Our filters are highly accurate if the lookup covers fairly local
+ * set of glyphs, but fully flooded and ineffective if coverage is
+ * all over the place.
+ *
+ * The frozen-set can be used instead of a digest, to trade more
+ * memory for 100% accuracy, but in practice, that doesn't look like
+ * an attractive trade-off.
+ */
+
+template <typename mask_t, unsigned int shift>
+struct hb_set_digest_lowest_bits_t
+{
+  ASSERT_POD ();
+
+  static const unsigned int mask_bytes = sizeof (mask_t);
+  static const unsigned int mask_bits = sizeof (mask_t) * 8;
+  static const unsigned int 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), "");
+
+  inline void init (void) {
+    mask = 0;
+  }
+
+  inline void add (hb_codepoint_t g) {
+    mask |= mask_for (g);
+  }
+
+  inline bool add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
+      mask = (mask_t) -1;
+    else {
+      mask_t ma = mask_for (a);
+      mask_t mb = mask_for (b);
+      mask |= mb + (mb - ma) - (mb < ma);
+    }
+    return true;
+  }
+
+  template <typename T>
+  inline void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    for (unsigned int i = 0; i < count; i++)
+    {
+      add (*array);
+      array = (const T *) (stride + (const char *) array);
+    }
+  }
+  template <typename T>
+  inline bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    for (unsigned int i = 0; i < count; i++)
+    {
+      add (*array);
+      array = (const T *) (stride + (const char *) array);
+    }
+    return true;
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return !!(mask & mask_for (g));
+  }
+
+  private:
+
+  static inline mask_t mask_for (hb_codepoint_t g) {
+    return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1));
+  }
+  mask_t mask;
+};
+
+template <typename head_t, typename tail_t>
+struct hb_set_digest_combiner_t
+{
+  ASSERT_POD ();
+
+  inline void init (void) {
+    head.init ();
+    tail.init ();
+  }
+
+  inline void add (hb_codepoint_t g) {
+    head.add (g);
+    tail.add (g);
+  }
+
+  inline bool add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    head.add_range (a, b);
+    tail.add_range (a, b);
+    return true;
+  }
+  template <typename T>
+  inline void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    head.add_array (array, count, stride);
+    tail.add_array (array, count, stride);
+  }
+  template <typename T>
+  inline bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    head.add_sorted_array (array, count, stride);
+    tail.add_sorted_array (array, count, stride);
+    return true;
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return head.may_have (g) && tail.may_have (g);
+  }
+
+  private:
+  head_t head;
+  tail_t tail;
+};
+
+
+/*
+ * hb_set_digest_t
+ *
+ * This is a combination of digests that performs "best".
+ * There is not much science to this: it's a result of intuition
+ * and testing.
+ */
+typedef hb_set_digest_combiner_t
+<
+  hb_set_digest_lowest_bits_t<unsigned long, 4>,
+  hb_set_digest_combiner_t
+  <
+    hb_set_digest_lowest_bits_t<unsigned long, 0>,
+    hb_set_digest_lowest_bits_t<unsigned long, 9>
+  >
+> hb_set_digest_t;
+
+
+#endif /* HB_SET_DIGEST_PRIVATE_HH */
diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh
index e2010d7..9c6f3ee 100644
--- a/src/hb-set-private.hh
+++ b/src/hb-set-private.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2012  Google, Inc.
+ * Copyright © 2012,2017  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -32,254 +32,462 @@
 
 
 /*
- * The set digests here implement various "filters" that support
- * "approximate member query".  Conceptually these are like Bloom
- * Filter and Quotient Filter, however, much smaller, faster, and
- * designed to fit the requirements of our uses for glyph coverage
- * queries.
- *
- * Our filters are highly accurate if the lookup covers fairly local
- * set of glyphs, but fully flooded and ineffective if coverage is
- * all over the place.
- *
- * The frozen-set can be used instead of a digest, to trade more
- * memory for 100% accuracy, but in practice, that doesn't look like
- * an attractive trade-off.
- */
-
-template <typename mask_t, unsigned int shift>
-struct hb_set_digest_lowest_bits_t
-{
-  ASSERT_POD ();
-
-  static const unsigned int mask_bytes = sizeof (mask_t);
-  static const unsigned int mask_bits = sizeof (mask_t) * 8;
-  static const unsigned int 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;
-
-  ASSERT_STATIC (shift < sizeof (hb_codepoint_t) * 8);
-  ASSERT_STATIC (shift + num_bits <= sizeof (hb_codepoint_t) * 8);
-
-  inline void init (void) {
-    mask = 0;
-  }
-
-  inline void add (hb_codepoint_t g) {
-    mask |= mask_for (g);
-  }
-
-  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
-    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
-      mask = (mask_t) -1;
-    else {
-      mask_t ma = mask_for (a);
-      mask_t mb = mask_for (b);
-      mask |= mb + (mb - ma) - (mb < ma);
-    }
-  }
-
-  inline bool may_have (hb_codepoint_t g) const {
-    return !!(mask & mask_for (g));
-  }
-
-  private:
-
-  static inline mask_t mask_for (hb_codepoint_t g) {
-    return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1));
-  }
-  mask_t mask;
-};
-
-template <typename head_t, typename tail_t>
-struct hb_set_digest_combiner_t
-{
-  ASSERT_POD ();
-
-  inline void init (void) {
-    head.init ();
-    tail.init ();
-  }
-
-  inline void add (hb_codepoint_t g) {
-    head.add (g);
-    tail.add (g);
-  }
-
-  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
-    head.add_range (a, b);
-    tail.add_range (a, b);
-  }
-
-  inline bool may_have (hb_codepoint_t g) const {
-    return head.may_have (g) && tail.may_have (g);
-  }
-
-  private:
-  head_t head;
-  tail_t tail;
-};
-
-
-/*
- * hb_set_digest_t
- *
- * This is a combination of digests that performs "best".
- * There is not much science to this: it's a result of intuition
- * and testing.
- */
-typedef hb_set_digest_combiner_t
-<
-  hb_set_digest_lowest_bits_t<unsigned long, 4>,
-  hb_set_digest_combiner_t
-  <
-    hb_set_digest_lowest_bits_t<unsigned long, 0>,
-    hb_set_digest_lowest_bits_t<unsigned long, 9>
-  >
-> hb_set_digest_t;
-
-
-
-/*
  * hb_set_t
  */
 
-
-/* TODO Make this faster and memmory efficient. */
+/* TODO Keep a free-list so we can free pages that are completely zeroed.  At that
+ * point maybe also use a sentinel value for "all-1" pages? */
 
 struct hb_set_t
 {
-  friend struct hb_frozen_set_t;
+  struct page_map_t
+  {
+    inline int cmp (const page_map_t *o) const { return (int) o->major - (int) major; }
+
+    uint32_t major;
+    uint32_t index;
+  };
+
+  struct page_t
+  {
+    inline void init0 (void) { memset (&v, 0, sizeof (v)); }
+    inline void init1 (void) { memset (&v, 0xff, sizeof (v)); }
+
+    inline unsigned int len (void) const
+    { return ARRAY_LENGTH_CONST (v); }
+
+    inline bool is_empty (void) const
+    {
+      for (unsigned int i = 0; i < len (); i++)
+        if (v[i])
+	  return false;
+      return true;
+    }
+
+    inline void add (hb_codepoint_t g) { elt (g) |= mask (g); }
+    inline void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
+    inline bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); }
+
+    inline 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);
+      else
+      {
+	*la |= ~(mask (a) - 1);
+	la++;
+
+	memset (la, 0xff, (char *) lb - (char *) la);
+
+	*lb |= ((mask (b) << 1) - 1);
+      }
+    }
+
+    inline bool is_equal (const page_t *other) const
+    {
+      return 0 == memcmp (&v, &other->v, sizeof (v));
+    }
+
+    inline unsigned int get_population (void) const
+    {
+      unsigned int pop = 0;
+      for (unsigned int i = 0; i < len (); i++)
+        pop += _hb_popcount (v[i]);
+      return pop;
+    }
+
+    inline bool next (hb_codepoint_t *codepoint) const
+    {
+      unsigned int m = (*codepoint + 1) & MASK;
+      if (!m)
+      {
+	*codepoint = INVALID;
+	return false;
+      }
+      unsigned int i = m / ELT_BITS;
+      unsigned int j = m & ELT_MASK;
+
+      for (; j < ELT_BITS; j++)
+        if (v[i] & (elt_t (1) << j))
+	  goto found;
+      for (i++; i < len (); i++)
+        if (v[i])
+	  for (j = 0; j < ELT_BITS; j++)
+	    if (v[i] & (elt_t (1) << j))
+	      goto found;
+
+      *codepoint = INVALID;
+      return false;
+
+    found:
+      *codepoint = i * ELT_BITS + j;
+      return true;
+    }
+    inline hb_codepoint_t get_min (void) const
+    {
+      for (unsigned int i = 0; i < len (); i++)
+        if (v[i])
+	{
+	  elt_t e = v[i];
+	  for (unsigned int j = 0; j < ELT_BITS; j++)
+	    if (e & (elt_t (1) << j))
+	      return i * ELT_BITS + j;
+	}
+      return INVALID;
+    }
+    inline hb_codepoint_t get_max (void) const
+    {
+      for (int i = len () - 1; i >= 0; i--)
+        if (v[i])
+	{
+	  elt_t e = v[i];
+	  for (int j = ELT_BITS - 1; j >= 0; j--)
+	    if (e & (elt_t (1) << j))
+	      return i * ELT_BITS + j;
+	}
+      return 0;
+    }
+
+    static const unsigned int PAGE_BITS = 8192; /* Use to tune. */
+    static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
+
+    typedef uint64_t elt_t;
+
+#if 0 && HAVE_VECTOR_SIZE
+    /* The vectorized version does not work with clang as non-const
+     * elt() errs "non-const reference cannot bind to vector element". */
+    typedef elt_t vector_t __attribute__((vector_size (PAGE_BITS / 8)));
+#else
+    typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
+#endif
+
+    vector_t v;
+
+    static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
+    static const unsigned int ELT_MASK = ELT_BITS - 1;
+    static const unsigned int BITS = sizeof (vector_t) * 8;
+    static const unsigned int MASK = BITS - 1;
+    static_assert (PAGE_BITS == BITS, "");
+
+    elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
+    elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
+    elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & ELT_MASK); }
+  };
+  static_assert (page_t::PAGE_BITS == sizeof (page_t) * 8, "");
 
   hb_object_header_t header;
   ASSERT_POD ();
   bool in_error;
+  hb_prealloced_array_t<page_map_t, 8> page_map;
+  hb_prealloced_array_t<page_t, 1> pages;
 
-  inline void init (void) {
-    hb_object_init (this);
-    clear ();
+  inline void init (void)
+  {
+    page_map.init ();
+    pages.init ();
   }
-  inline void fini (void) {
+  inline void finish (void)
+  {
+    page_map.finish ();
+    pages.finish ();
   }
+
+  inline bool resize (unsigned int count)
+  {
+    if (unlikely (in_error)) return false;
+    if (!pages.resize (count) || !page_map.resize (count))
+    {
+      pages.resize (page_map.len);
+      in_error = true;
+      return false;
+    }
+    return true;
+  }
+
   inline void clear (void) {
     if (unlikely (hb_object_is_inert (this)))
       return;
     in_error = false;
-    memset (elts, 0, sizeof elts);
+    page_map.resize (0);
+    pages.resize (0);
   }
   inline bool is_empty (void) const {
-    for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
-      if (elts[i])
+    unsigned int count = pages.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!pages[i].is_empty ())
         return false;
     return true;
   }
+
   inline void add (hb_codepoint_t g)
   {
     if (unlikely (in_error)) return;
     if (unlikely (g == INVALID)) return;
-    if (unlikely (g > MAX_G)) return;
-    elt (g) |= mask (g);
+    page_t *page = page_for_insert (g); if (unlikely (!page)) return;
+    page->add (g);
   }
-  inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
+  inline bool add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (in_error)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
+    if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
+    unsigned int ma = get_major (a);
+    unsigned int mb = get_major (b);
+    if (ma == mb)
+    {
+      page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
+      page->add_range (a, b);
+    }
+    else
+    {
+      page_t *page = page_for_insert (a); if (unlikely (!page)) return false;
+      page->add_range (a, major_start (ma + 1) - 1);
+
+      for (unsigned int m = ma + 1; m < mb; m++)
+      {
+	page = page_for_insert (major_start (m)); if (unlikely (!page)) return false;
+	page->init1 ();
+      }
+
+      page = page_for_insert (b); if (unlikely (!page)) return false;
+      page->add_range (major_start (mb), b);
+    }
+    return true;
+  }
+
+  template <typename T>
+  inline void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
   {
     if (unlikely (in_error)) return;
-    /* TODO Speedup */
-    for (unsigned int i = a; i < b + 1; i++)
-      add (i);
+    if (!count) return;
+    hb_codepoint_t g = *array;
+    while (count)
+    {
+      unsigned int m = get_major (g);
+      page_t *page = page_for_insert (g); if (unlikely (!page)) return;
+      unsigned int start = major_start (m);
+      unsigned int end = major_start (m + 1);
+      do
+      {
+	page->add (g);
+
+	array++;
+	count--;
+      }
+      while (count && (g = *array, start <= g && g < end));
+    }
   }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename T>
+  inline bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    if (unlikely (in_error)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
+    if (!count) return true;
+    hb_codepoint_t g = *array;
+    hb_codepoint_t last_g = g;
+    while (count)
+    {
+      unsigned int m = get_major (g);
+      page_t *page = page_for_insert (g); if (unlikely (!page)) return false;
+      unsigned int end = major_start (m + 1);
+      do
+      {
+        /* If we try harder we can change the following comparison to <=;
+	 * Not sure if it's worth it. */
+        if (g < last_g) return false;
+	last_g = g;
+	page->add (g);
+
+	array++;
+	count--;
+      }
+      while (count && (g = *array, g < end));
+    }
+    return true;
+  }
+
   inline void del (hb_codepoint_t g)
   {
     if (unlikely (in_error)) return;
-    if (unlikely (g > MAX_G)) return;
-    elt (g) &= ~mask (g);
+    page_t *p = page_for (g);
+    if (!p)
+      return;
+    p->del (g);
   }
   inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
   {
+    /* TODO Optimize, like add_range(). */
     if (unlikely (in_error)) return;
-    /* TODO Speedup */
     for (unsigned int i = a; i < b + 1; i++)
       del (i);
   }
   inline bool has (hb_codepoint_t g) const
   {
-    if (unlikely (g > MAX_G)) return false;
-    return !!(elt (g) & mask (g));
+    const page_t *p = page_for (g);
+    if (!p)
+      return false;
+    return p->has (g);
   }
   inline bool intersects (hb_codepoint_t first,
 			  hb_codepoint_t last) const
   {
-    if (unlikely (first > MAX_G)) return false;
-    if (unlikely (last  > MAX_G)) last = MAX_G;
-    unsigned int end = last + 1;
-    for (hb_codepoint_t i = first; i < end; i++)
-      if (has (i))
-        return true;
-    return false;
-  }
-  inline bool is_equal (const hb_set_t *other) const
-  {
-    for (unsigned int i = 0; i < ELTS; i++)
-      if (elts[i] != other->elts[i])
-        return false;
-    return true;
+    hb_codepoint_t c = first - 1;
+    return next (&c) && c <= last;
   }
   inline void set (const hb_set_t *other)
   {
     if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] = other->elts[i];
+    unsigned int count = other->pages.len;
+    if (!resize (count))
+      return;
+
+    memcpy (pages.array, other->pages.array, count * sizeof (pages.array[0]));
+    memcpy (page_map.array, other->page_map.array, count * sizeof (page_map.array[0]));
   }
-  inline void union_ (const hb_set_t *other)
+
+  inline bool is_equal (const hb_set_t *other) const
+  {
+    unsigned int na = pages.len;
+    unsigned int nb = other->pages.len;
+
+    unsigned int a = 0, b = 0;
+    for (; a < na && b < nb; )
+    {
+      if (page_at (a).is_empty ()) { a++; continue; }
+      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;
+      a++;
+      b++;
+    }
+    for (; a < na; a++)
+      if (!page_at (a).is_empty ()) { return false; }
+    for (; b < nb; b++)
+      if (!other->page_at (b).is_empty ()) { return false; }
+
+    return true;
+  }
+
+  template <class Op>
+  inline void process (const hb_set_t *other)
   {
     if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] |= other->elts[i];
+
+    unsigned int na = pages.len;
+    unsigned int nb = other->pages.len;
+
+    unsigned int count = 0;
+    unsigned int a = 0, b = 0;
+    for (; a < na && b < nb; )
+    {
+      if (page_map[a].major == other->page_map[b].major)
+      {
+        count++;
+	a++;
+	b++;
+      }
+      else if (page_map[a].major < other->page_map[b].major)
+      {
+        if (Op::passthru_left)
+	  count++;
+        a++;
+      }
+      else
+      {
+        if (Op::passthru_right)
+	  count++;
+        b++;
+      }
+    }
+    if (Op::passthru_left)
+      count += na - a;
+    if (Op::passthru_right)
+      count += nb - b;
+
+    if (!resize (count))
+      return;
+
+    /* Process in-place backward. */
+    a = na;
+    b = nb;
+    for (; a && b; )
+    {
+      if (page_map[a - 1].major == other->page_map[b - 1].major)
+      {
+	a--;
+	b--;
+        Op::process (page_at (--count).v, page_at (a).v, other->page_at (b).v);
+      }
+      else if (page_map[a - 1].major > other->page_map[b - 1].major)
+      {
+        a--;
+        if (Op::passthru_left)
+	  page_at (--count).v = page_at (a).v;
+      }
+      else
+      {
+        b--;
+        if (Op::passthru_right)
+	  page_at (--count).v = other->page_at (b).v;
+      }
+    }
+    if (Op::passthru_left)
+      while (a)
+	page_at (--count).v = page_at (--a).v;
+    if (Op::passthru_right)
+      while (b)
+	page_at (--count).v = other->page_at (--b).v;
+    assert (!count);
+  }
+
+  inline void union_ (const hb_set_t *other)
+  {
+    process<HbOpOr> (other);
   }
   inline void intersect (const hb_set_t *other)
   {
-    if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] &= other->elts[i];
+    process<HbOpAnd> (other);
   }
   inline void subtract (const hb_set_t *other)
   {
-    if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] &= ~other->elts[i];
+    process<HbOpMinus> (other);
   }
   inline void symmetric_difference (const hb_set_t *other)
   {
-    if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] ^= other->elts[i];
-  }
-  inline void invert (void)
-  {
-    if (unlikely (in_error)) return;
-    for (unsigned int i = 0; i < ELTS; i++)
-      elts[i] = ~elts[i];
+    process<HbOpXor> (other);
   }
   inline bool next (hb_codepoint_t *codepoint) const
   {
     if (unlikely (*codepoint == INVALID)) {
-      hb_codepoint_t i = get_min ();
-      if (i != INVALID) {
-        *codepoint = i;
+      *codepoint = get_min ();
+      return *codepoint != INVALID;
+    }
+
+    page_map_t map = {get_major (*codepoint), 0};
+    unsigned int i;
+    page_map.bfind (&map, &i);
+    if (i < page_map.len)
+    {
+      if (pages[page_map[i].index].next (codepoint))
+      {
+	*codepoint += page_map[i].major * page_t::PAGE_BITS;
+        return true;
+      }
+      i++;
+    }
+    for (; i < page_map.len; i++)
+    {
+      hb_codepoint_t m = pages[page_map[i].index].get_min ();
+      if (m != INVALID)
+      {
+	*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
 	return true;
-      } else {
-	*codepoint = INVALID;
-        return false;
       }
     }
-    for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++)
-      if (has (i)) {
-        *codepoint = i;
-	return true;
-      }
     *codepoint = INVALID;
     return false;
   }
@@ -303,99 +511,66 @@
 
   inline unsigned int get_population (void) const
   {
-    unsigned int count = 0;
-    for (unsigned int i = 0; i < ELTS; i++)
-      count += _hb_popcount32 (elts[i]);
-    return count;
+    unsigned int pop = 0;
+    unsigned int count = pages.len;
+    for (unsigned int i = 0; i < count; i++)
+      pop += pages[i].get_population ();
+    return pop;
   }
   inline hb_codepoint_t get_min (void) const
   {
-    for (unsigned int i = 0; i < ELTS; i++)
-      if (elts[i])
-	for (unsigned int j = 0; j < BITS; j++)
-	  if (elts[i] & (1u << j))
-	    return i * BITS + j;
+    unsigned int count = pages.len;
+    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 INVALID;
   }
   inline hb_codepoint_t get_max (void) const
   {
-    for (unsigned int i = ELTS; i; i--)
-      if (elts[i - 1])
-	for (unsigned int j = BITS; j; j--)
-	  if (elts[i - 1] & (1u << (j - 1)))
-	    return (i - 1) * BITS + (j - 1);
+    unsigned int count = pages.len;
+    for (int i = count - 1; i >= 0; i++)
+      if (!page_at (i).is_empty ())
+        return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_max ();
     return INVALID;
   }
 
-  typedef uint32_t elt_t;
-  static const unsigned int MAX_G = 65536 - 1; /* XXX Fix this... */
-  static const unsigned int SHIFT = 5;
-  static const unsigned int BITS = (1 << SHIFT);
-  static const unsigned int MASK = BITS - 1;
-  static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS;
   static  const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
 
-  elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
-  elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
-  elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
-
-  elt_t elts[ELTS]; /* XXX 8kb */
-
-  ASSERT_STATIC (sizeof (elt_t) * 8 == BITS);
-  ASSERT_STATIC (sizeof (elt_t) * 8 * ELTS > MAX_G);
-};
-
-struct hb_frozen_set_t
-{
-  static const unsigned int SHIFT = hb_set_t::SHIFT;
-  static const unsigned int BITS = hb_set_t::BITS;
-  static const unsigned int MASK = hb_set_t::MASK;
-  typedef hb_set_t::elt_t elt_t;
-
-  inline void init (const hb_set_t &set)
+  inline page_t *page_for_insert (hb_codepoint_t g)
   {
-    start = count = 0;
-    elts = NULL;
-
-    unsigned int max = set.get_max ();
-    if (max == set.INVALID)
-      return;
-    unsigned int min = set.get_min ();
-    const elt_t &min_elt = set.elt (min);
-
-    start = min & ~MASK;
-    count = max - start + 1;
-    unsigned int num_elts = (count + BITS - 1) / BITS;
-    unsigned int elts_size = num_elts * sizeof (elt_t);
-    elts = (elt_t *) malloc (elts_size);
-    if (unlikely (!elts))
+    page_map_t map = {get_major (g), pages.len};
+    unsigned int i;
+    if (!page_map.bfind (&map, &i))
     {
-      start = count = 0;
-      return;
+      if (!resize (pages.len + 1))
+	return nullptr;
+
+      pages[map.index].init0 ();
+      memmove (&page_map[i + 1], &page_map[i], (page_map.len - 1 - i) * sizeof (page_map[0]));
+      page_map[i] = map;
     }
-    memcpy (elts, &min_elt, elts_size);
+    return &pages[page_map[i].index];
   }
-
-  inline void fini (void)
+  inline page_t *page_for (hb_codepoint_t g)
   {
-    if (elts)
-      free (elts);
+    page_map_t key = {get_major (g)};
+    const page_map_t *found = page_map.bsearch (&key);
+    if (found)
+      return &pages[found->index];
+    return nullptr;
   }
-
-  inline bool has (hb_codepoint_t g) const
+  inline const page_t *page_for (hb_codepoint_t g) const
   {
-    /* hb_codepoint_t is unsigned. */
-    g -= start;
-    if (unlikely (g > count)) return false;
-    return !!(elt (g) & mask (g));
+    page_map_t key = {get_major (g)};
+    const page_map_t *found = page_map.bsearch (&key);
+    if (found)
+      return &pages[found->index];
+    return nullptr;
   }
-
-  elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
-  elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
-
-  private:
-  hb_codepoint_t start, count;
-  elt_t *elts;
+  inline page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
+  inline const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
+  inline unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
+  inline hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
 };
 
 
diff --git a/src/hb-set.cc b/src/hb-set.cc
index f3fe1ba..0b4f871 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -45,7 +45,7 @@
   if (!(set = hb_object_create<hb_set_t> ()))
     return hb_set_get_empty ();
 
-  set->clear ();
+  set->init ();
 
   return set;
 }
@@ -95,7 +95,7 @@
 {
   if (!hb_object_destroy (set)) return;
 
-  set->fini ();
+  set->finish ();
 
   free (set);
 }
@@ -376,11 +376,12 @@
  * 
  *
  * Since: 0.9.10
+ *
+ * Deprecated: 1.6.1
  **/
 void
 hb_set_invert (hb_set_t *set)
 {
-  set->invert ();
 }
 
 /**
diff --git a/src/hb-set.h b/src/hb-set.h
index 2164c1a..2ce4060 100644
--- a/src/hb-set.h
+++ b/src/hb-set.h
@@ -126,9 +126,6 @@
 hb_set_symmetric_difference (hb_set_t       *set,
 			     const hb_set_t *other);
 
-HB_EXTERN void
-hb_set_invert (hb_set_t *set);
-
 HB_EXTERN unsigned int
 hb_set_get_population (const hb_set_t *set);
 
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 600faae..6eeba2b 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -24,24 +24,14 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb-private.hh"
+#include "hb-debug.hh"
 #include "hb-shape-plan-private.hh"
 #include "hb-shaper-private.hh"
 #include "hb-font-private.hh"
 #include "hb-buffer-private.hh"
 
 
-#ifndef HB_DEBUG_SHAPE_PLAN
-#define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
-#endif
-
-
-#define HB_SHAPER_IMPLEMENT(shaper) \
-	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
-	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
-#include "hb-shaper-list.hh"
-#undef HB_SHAPER_IMPLEMENT
-
-
 static void
 hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
 		    const hb_feature_t *user_features,
@@ -122,7 +112,7 @@
 {
   return hb_shape_plan_create2 (face, props,
 				user_features, num_user_features,
-				NULL, 0,
+				nullptr, 0,
 				shaper_list);
 }
 
@@ -135,7 +125,7 @@
 		       unsigned int                   num_coords,
 		       const char * const            *shaper_list)
 {
-  DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+  DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
 		  "face=%p num_features=%d num_coords=%d shaper_list=%p",
 		  face,
 		  num_user_features,
@@ -143,8 +133,8 @@
 		  shaper_list);
 
   hb_shape_plan_t *shape_plan;
-  hb_feature_t *features = NULL;
-  int *coords = NULL;
+  hb_feature_t *features = nullptr;
+  int *coords = nullptr;
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
@@ -167,7 +157,7 @@
   assert (props->direction != HB_DIRECTION_INVALID);
 
   hb_face_make_immutable (face);
-  shape_plan->default_shaper_list = shaper_list == NULL;
+  shape_plan->default_shaper_list = !shaper_list;
   shape_plan->face_unsafe = face;
   shape_plan->props = *props;
   shape_plan->num_user_features = num_user_features;
@@ -203,16 +193,16 @@
     HB_OBJECT_HEADER_STATIC,
 
     true, /* default_shaper_list */
-    NULL, /* face */
+    nullptr, /* face */
     HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
 
-    NULL, /* shaper_func */
-    NULL, /* shaper_name */
+    nullptr, /* shaper_func */
+    nullptr, /* shaper_name */
 
-    NULL, /* user_features */
+    nullptr, /* user_features */
     0,    /* num_user_featurs */
 
-    NULL, /* coords */
+    nullptr, /* coords */
     0,    /* num_coords */
 
     {
@@ -430,7 +420,7 @@
   return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
 	 hb_shape_plan_user_features_match (shape_plan, proposal) &&
 	 hb_shape_plan_coords_match (shape_plan, proposal) &&
-	 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
+	 ((shape_plan->default_shaper_list && !proposal->shaper_list) ||
 	  (shape_plan->shaper_func == proposal->shaper_func));
 }
 
@@ -438,11 +428,12 @@
 hb_non_global_user_features_present (const hb_feature_t *user_features,
 				     unsigned int        num_user_features)
 {
-  while (num_user_features)
+  while (num_user_features) {
     if (user_features->start != 0 || user_features->end != (unsigned int) -1)
       return true;
-    else
-      num_user_features--, user_features++;
+    num_user_features--;
+    user_features++;
+  }
   return false;
 }
 
@@ -476,7 +467,7 @@
 {
   return hb_shape_plan_create_cached2 (face, props,
 				       user_features, num_user_features,
-				       NULL, 0,
+				       nullptr, 0,
 				       shaper_list);
 }
 
@@ -489,7 +480,7 @@
 			      unsigned int                   num_coords,
 			      const char * const            *shaper_list)
 {
-  DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+  DEBUG_MSG_FUNC (SHAPE_PLAN, nullptr,
 		  "face=%p num_features=%d shaper_list=%p",
 		  face,
 		  num_user_features,
@@ -500,7 +491,7 @@
     shaper_list,
     user_features,
     num_user_features,
-    NULL
+    nullptr
   };
 
   if (shaper_list) {
@@ -526,15 +517,17 @@
 
 retry:
   hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
-  for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
-    if (hb_shape_plan_matches (node->shape_plan, &proposal))
-    {
-      DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
-      return hb_shape_plan_reference (node->shape_plan);
-    }
+
+  /* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */
+  if (!hb_coords_present (coords, num_coords))
+    for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
+      if (hb_shape_plan_matches (node->shape_plan, &proposal))
+      {
+        DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
+        return hb_shape_plan_reference (node->shape_plan);
+      }
 
   /* Not found. */
-
   hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
 						       user_features, num_user_features,
 						       coords, num_coords,
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index f080a15..39355b3 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -76,7 +76,7 @@
     /* Not found; allocate one. */
     shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
     if (unlikely (!shaper_list)) {
-      static const char *nil_shaper_list[] = {NULL};
+      static const char *nil_shaper_list[] = {nullptr};
       return nil_shaper_list;
     }
 
@@ -84,9 +84,9 @@
     unsigned int i;
     for (i = 0; i < HB_SHAPERS_COUNT; i++)
       shaper_list[i] = shapers[i].name;
-    shaper_list[i] = NULL;
+    shaper_list[i] = nullptr;
 
-    if (!hb_atomic_ptr_cmpexch (&static_shaper_list, NULL, shaper_list)) {
+    if (!hb_atomic_ptr_cmpexch (&static_shaper_list, nullptr, shaper_list)) {
       free (shaper_list);
       goto retry;
     }
@@ -157,5 +157,5 @@
 	  const hb_feature_t  *features,
 	  unsigned int         num_features)
 {
-  hb_shape_full (font, buffer, features, num_features, NULL);
+  hb_shape_full (font, buffer, features, num_features, nullptr);
 }
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
index d1d1146..ce2d9f2 100644
--- a/src/hb-shaper-private.hh
+++ b/src/hb-shaper-private.hh
@@ -65,35 +65,51 @@
 #define HB_SHAPER_DATA_INVALID ((void *) -1)
 #define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID)
 
-#define HB_SHAPER_DATA_TYPE(shaper, object)		struct hb_##shaper##_shaper_##object##_data_t
+#define HB_SHAPER_DATA_TYPE_NAME(shaper, object)	hb_##shaper##_shaper_##object##_data_t
+#define HB_SHAPER_DATA_TYPE(shaper, object)		struct HB_SHAPER_DATA_TYPE_NAME(shaper, object)
 #define HB_SHAPER_DATA_INSTANCE(shaper, object, instance)	(* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper)
-#define HB_SHAPER_DATA(shaper, object)			HB_SHAPER_DATA_INSTANCE (shaper, object, object)
+#define HB_SHAPER_DATA(shaper, object)			HB_SHAPER_DATA_INSTANCE(shaper, object, object)
 #define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_create
 #define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_destroy
+#define HB_SHAPER_DATA_ENSURE_FUNC(shaper, object)	hb_##shaper##_shaper_##object##_data_ensure
 
 #define HB_SHAPER_DATA_PROTOTYPE(shaper, object) \
 	HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \
 	extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
 	HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS); \
 	extern "C" HB_INTERNAL void \
-	HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data)
+	HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data); \
+	extern "C" HB_INTERNAL bool \
+	HB_SHAPER_DATA_ENSURE_FUNC (shaper, object) (hb_##object##_t *object)
 
 #define HB_SHAPER_DATA_DESTROY(shaper, object) \
     if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object)) \
       if (data != HB_SHAPER_DATA_INVALID && data != HB_SHAPER_DATA_SUCCEEDED) \
         HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data);
 
-#define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
-static inline bool \
-hb_##shaper##_shaper_##object##_data_ensure (hb_##object##_t *object) \
+#define HB_SHAPER_DATA_ENSURE_DEFINE(shaper, object) \
+	HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(shaper, object, true)
+
+#define HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(shaper, object, condition) \
+bool \
+HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \
 {\
   retry: \
   HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
+  if (likely (data) && !(condition)) { \
+    /* Drop and recreate. */ \
+    /* If someone dropped it in the mean time, throw it away and don't touch it. \
+     * Otherwise, destruct it. */ \
+    if (hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), data, nullptr)) { \
+      HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
+    } \
+    goto retry; \
+  } \
   if (unlikely (!data)) { \
     data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
     if (unlikely (!data)) \
       data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
-    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), NULL, data)) { \
+    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), nullptr, data)) { \
       if (data && \
 	  data != HB_SHAPER_DATA_INVALID && \
 	  data != HB_SHAPER_DATA_SUCCEEDED) \
@@ -101,7 +117,7 @@
       goto retry; \
     } \
   } \
-  return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
+  return data != nullptr && !HB_SHAPER_DATA_IS_INVALID (data); \
 }
 
 
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
index b25566d..2c44cf2 100644
--- a/src/hb-shaper.cc
+++ b/src/hb-shaper.cc
@@ -59,14 +59,14 @@
   {
     char *env = getenv ("HB_SHAPER_LIST");
     if (!env || !*env) {
-      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]);
       return (const hb_shaper_pair_t *) all_shapers;
     }
 
     /* Not found; allocate one. */
     shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
     if (unlikely (!shapers)) {
-      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]);
       return (const hb_shaper_pair_t *) all_shapers;
     }
 
@@ -97,7 +97,7 @@
 	p = end + 1;
     }
 
-    if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
+    if (!hb_atomic_ptr_cmpexch (&static_shapers, nullptr, shapers)) {
       free (shapers);
       goto retry;
     }
diff --git a/src/hb-string-array.hh b/src/hb-string-array.hh
new file mode 100644
index 0000000..ba829b0
--- /dev/null
+++ b/src/hb-string-array.hh
@@ -0,0 +1,81 @@
+/*
+ * 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_STRING_ARRAY_HH
+#if 0 /* Make checks happy. */
+#define HB_STRING_ARRAY_HH
+#endif
+
+#include "hb-private.hh"
+
+/* Based on Bruno Haible's code in Appendix B of Ulrich Drepper's dsohowto.pdf:
+ * https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf */
+
+#define HB_STRING_ARRAY_TYPE_NAME	HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr_t)
+#define HB_STRING_ARRAY_POOL_NAME	HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr)
+#define HB_STRING_ARRAY_OFFS_NAME	HB_PASTE(HB_STRING_ARRAY_NAME, _msgidx)
+
+static const union HB_STRING_ARRAY_TYPE_NAME {
+  struct {
+/* I like to avoid storing the nul-termination byte since we don't need it,
+ * but C++ does not allow that.
+ * https://stackoverflow.com/questions/28433862/why-initializer-string-for-array-of-chars-is-too-long-compiles-fine-in-c-not
+ */
+#define _S(s) char HB_PASTE (str, __LINE__)[sizeof (s)];
+#include HB_STRING_ARRAY_LIST
+#undef _S
+  } st;
+  char str[VAR];
+}
+HB_STRING_ARRAY_POOL_NAME =
+{
+  {
+#define _S(s) s,
+#include HB_STRING_ARRAY_LIST
+#undef _S
+  }
+};
+static const unsigned int HB_STRING_ARRAY_OFFS_NAME[] =
+{
+#define _S(s) offsetof (union HB_STRING_ARRAY_TYPE_NAME, st.HB_PASTE(str, __LINE__)),
+#include HB_STRING_ARRAY_LIST
+#undef _S
+  sizeof (HB_STRING_ARRAY_TYPE_NAME)
+};
+
+static inline hb_string_t
+HB_STRING_ARRAY_NAME (unsigned int i)
+{
+  assert (i < ARRAY_LENGTH (HB_STRING_ARRAY_OFFS_NAME) - 1);
+  return hb_string_t (HB_STRING_ARRAY_POOL_NAME.str + HB_STRING_ARRAY_OFFS_NAME[i],
+		      HB_STRING_ARRAY_OFFS_NAME[i + 1] - HB_STRING_ARRAY_OFFS_NAME[i] - 1);
+}
+
+#undef HB_STRING_ARRAY_TYPE_NAME
+#undef HB_STRING_ARRAY_POOL_NAME
+#undef HB_STRING_ARRAY_OFFS_NAME
+
+#endif /* HB_STRING_ARRAY_HH */
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
index a884e3f..9515bda 100644
--- a/src/hb-ucdn.cc
+++ b/src/hb-ucdn.cc
@@ -160,17 +160,23 @@
     HB_SCRIPT_NEWA,
     HB_SCRIPT_OSAGE,
     HB_SCRIPT_TANGUT,
+    HB_SCRIPT_MASARAM_GONDI,
+    HB_SCRIPT_NUSHU,
+    HB_SCRIPT_SOYOMBO,
+    HB_SCRIPT_ZANABAZAR_SQUARE,
 };
 
 static hb_unicode_combining_class_t
-hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+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 unsigned int
-hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			hb_codepoint_t unicode,
 			void *user_data HB_UNUSED)
 {
     int w = ucdn_get_east_asian_width(unicode);
@@ -178,28 +184,31 @@
 }
 
 static hb_unicode_general_category_t
-hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+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_codepoint_t unicode,
+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_codepoint_t unicode,
+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_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)
 {
@@ -207,7 +216,7 @@
 }
 
 static hb_bool_t
-hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs,
+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)
 {
@@ -215,29 +224,50 @@
 }
 
 static unsigned int
-hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs,
+hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 				hb_codepoint_t u, hb_codepoint_t *decomposed,
 				void *user_data HB_UNUSED)
 {
     return ucdn_compat_decompose(u, decomposed);
 }
 
+static hb_unicode_funcs_t *static_ucdn_funcs = nullptr;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_ucdn_funcs (void)
+{
+  hb_unicode_funcs_destroy (static_ucdn_funcs);
+}
+#endif
+
 extern "C" HB_INTERNAL
 hb_unicode_funcs_t *
 hb_ucdn_get_unicode_funcs (void)
 {
-  static const hb_unicode_funcs_t _hb_ucdn_unicode_funcs = {
-    HB_OBJECT_HEADER_STATIC,
+retry:
+  hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_ucdn_funcs);
 
-    NULL, /* parent */
-    true, /* immutable */
-    {
-#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_ucdn_##name,
+  if (unlikely (!funcs))
+  {
+    funcs = hb_unicode_funcs_create (nullptr);
+
+#define HB_UNICODE_FUNC_IMPLEMENT(name) \
+    hb_unicode_funcs_set_##name##_func (funcs, hb_ucdn_##name, nullptr, nullptr);
       HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
+
+    hb_unicode_funcs_make_immutable (funcs);
+
+    if (!hb_atomic_ptr_cmpexch (&static_ucdn_funcs, nullptr, funcs)) {
+      hb_unicode_funcs_destroy (funcs);
+      goto retry;
     }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_ucdn_funcs); /* First person registers atexit() callback. */
+#endif
   };
 
-  return const_cast<hb_unicode_funcs_t *> (&_hb_ucdn_unicode_funcs);
+  return hb_unicode_funcs_reference (funcs);
 }
-
diff --git a/src/hb-ucdn/Makefile.sources b/src/hb-ucdn/Makefile.sources
index d5f87b2..cb823b6 100644
--- a/src/hb-ucdn/Makefile.sources
+++ b/src/hb-ucdn/Makefile.sources
@@ -1,4 +1,7 @@
+NULL =
+
 LIBHB_UCDN_sources = \
 	ucdn.h \
 	ucdn.c \
-	unicodedata_db.h
+	ucdn_db.h \
+	$(NULL)
diff --git a/src/hb-ucdn/README b/src/hb-ucdn/README
index fcb97b9..2203ae6 100644
--- a/src/hb-ucdn/README
+++ b/src/hb-ucdn/README
@@ -31,10 +31,10 @@
 
 How to Use
 
-Include ucdn.c, ucdn.h and unicodedata_db.h in your project. Now,
-just use the functions as documented in ucdn.h.
+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
-unicodedata_db.h.
+ucdn_db.h.
diff --git a/src/hb-ucdn/ucdn.c b/src/hb-ucdn/ucdn.c
index f4e9be1..30747fe 100644
--- a/src/hb-ucdn/ucdn.c
+++ b/src/hb-ucdn/ucdn.c
@@ -23,7 +23,6 @@
     unsigned char category;
     unsigned char combining;
     unsigned char bidi_class;
-    unsigned char mirrored;
     unsigned char east_asian_width;
     unsigned char script;
     unsigned char linebreak_class;
@@ -43,7 +42,7 @@
     short count, index;
 } Reindex;
 
-#include "unicodedata_db.h"
+#include "ucdn_db.h"
 
 /* constants required for Hangul (de)composition */
 #define SBASE 0xAC00
@@ -91,20 +90,30 @@
     return &decomp_data[index];
 }
 
-static int get_comp_index(uint32_t code, const Reindex *idx)
+static int compare_reindex(const void *a, const void *b)
 {
-    int i;
+    Reindex *ra = (Reindex *)a;
+    Reindex *rb = (Reindex *)b;
 
-    for (i = 0; idx[i].start; i++) {
-        const Reindex *cur = &idx[i];
-        if (code < cur->start)
-            return -1;
-        if (code <= cur->start + cur->count) {
-            return cur->index + (code - cur->start);
-        }
-    }
+    if (ra->start < rb->start)
+        return -1;
+    else if (ra->start > (rb->start + rb->count))
+        return 1;
+    else
+        return 0;
+}
 
-    return -1;
+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)
@@ -127,8 +136,8 @@
     BracketPair *res;
 
     bp.from = code;
-    res = bsearch(&bp, bracket_pairs, BIDI_BRACKET_LEN, sizeof(BracketPair),
-            compare_bp);
+    res = (BracketPair *) bsearch(&bp, bracket_pairs, BIDI_BRACKET_LEN,
+                                 sizeof(BracketPair), compare_bp);
     return res;
 }
 
@@ -154,23 +163,18 @@
 
 static int hangul_pair_compose(uint32_t *code, uint32_t a, uint32_t b)
 {
-    if (b < VBASE || b >= (TBASE + TCOUNT))
-        return 0;
-
-    if ((a < LBASE || a >= (LBASE + LCOUNT))
-            && (a < SBASE || a >= (SBASE + SCOUNT)))
-        return 0;
-
-    if (a >= SBASE) {
+    if (a >= SBASE && a < (SBASE + SCOUNT) && b >= TBASE && b < (TBASE + TCOUNT)) {
         /* LV,T */
         *code = a + (b - TBASE);
         return 3;
-    } else {
+    } 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;
     }
 }
 
@@ -178,7 +182,7 @@
 {
     const unsigned short *code = *code_ptr;
 
-    if ((code[0] & 0xd800) != 0xd800) {
+    if (code[0] < 0xd800 || code[0] > 0xdc00) {
         *code_ptr += 1;
         return (uint32_t)code[0];
     } else {
@@ -215,7 +219,7 @@
 
 int ucdn_get_mirrored(uint32_t code)
 {
-    return get_ucd_record(code)->mirrored;
+    return ucdn_mirror(code) != code;
 }
 
 int ucdn_get_script(uint32_t code)
@@ -264,12 +268,9 @@
     MirrorPair mp = {0};
     MirrorPair *res;
 
-    if (get_ucd_record(code)->mirrored == 0)
-        return code;
-
     mp.from = code;
-    res = bsearch(&mp, mirror_pairs, BIDI_MIRROR_LEN, sizeof(MirrorPair),
-            compare_mp);
+    res = (MirrorPair *) bsearch(&mp, mirror_pairs, BIDI_MIRROR_LEN,
+                                sizeof(MirrorPair), compare_mp);
 
     if (res == NULL)
         return code;
@@ -326,8 +327,8 @@
     if (hangul_pair_compose(code, a, b))
         return 1;
 
-    l = get_comp_index(a, nfc_first);
-    r = get_comp_index(b, nfc_last);
+    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;
diff --git a/src/hb-ucdn/ucdn.h b/src/hb-ucdn/ucdn.h
index f694dc5..2d5fc35 100644
--- a/src/hb-ucdn/ucdn.h
+++ b/src/hb-ucdn/ucdn.h
@@ -36,30 +36,16 @@
 
 HB_BEGIN_HEADER
 
-#if !defined (HB_DONT_DEFINE_STDINT)
-
 #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>
-/* VS 2010 (_MSC_VER 1600) has stdint.h */
-#elif defined (_MSC_VER) && _MSC_VER < 1600
-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
 
-#endif
-
 
 #define UCDN_EAST_ASIAN_F 0
 #define UCDN_EAST_ASIAN_H 1
@@ -206,6 +192,10 @@
 #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
@@ -247,6 +237,9 @@
 #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
diff --git a/src/hb-ucdn/unicodedata_db.h b/src/hb-ucdn/ucdn_db.h
similarity index 64%
rename from src/hb-ucdn/unicodedata_db.h
rename to src/hb-ucdn/ucdn_db.h
index c9cd59b..8d2d8de 100644
--- a/src/hb-ucdn/unicodedata_db.h
+++ b/src/hb-ucdn/ucdn_db.h
@@ -1,999 +1,1012 @@
 /* this file was generated by makeunicodedata.py 3.2 */
 
-#define UNIDATA_VERSION "9.0.0"
+#define UNIDATA_VERSION "10.0.0"
 /* a list of unique database records */
 static const UCDRecord ucd_records[] = {
-    {2, 0, 18, 0, 5, 102, 41},
-    {0, 0, 14, 0, 5, 0, 21},
-    {0, 0, 16, 0, 5, 0, 17},
-    {0, 0, 15, 0, 5, 0, 35},
-    {0, 0, 16, 0, 5, 0, 30},
-    {0, 0, 17, 0, 5, 0, 30},
-    {0, 0, 15, 0, 5, 0, 33},
-    {0, 0, 15, 0, 5, 0, 21},
-    {0, 0, 16, 0, 5, 0, 21},
-    {29, 0, 17, 0, 3, 0, 40},
-    {21, 0, 18, 0, 3, 0, 6},
-    {21, 0, 18, 0, 3, 0, 3},
-    {21, 0, 10, 0, 3, 0, 12},
-    {23, 0, 10, 0, 3, 0, 9},
-    {21, 0, 10, 0, 3, 0, 10},
-    {21, 0, 18, 0, 3, 0, 12},
-    {22, 0, 18, 1, 3, 0, 0},
-    {18, 0, 18, 1, 3, 0, 2},
-    {25, 0, 9, 0, 3, 0, 9},
-    {21, 0, 12, 0, 3, 0, 8},
-    {17, 0, 9, 0, 3, 0, 16},
-    {21, 0, 12, 0, 3, 0, 7},
-    {13, 0, 8, 0, 3, 0, 11},
-    {21, 0, 18, 0, 3, 0, 8},
-    {25, 0, 18, 1, 3, 0, 12},
-    {25, 0, 18, 0, 3, 0, 12},
-    {9, 0, 0, 0, 3, 1, 12},
-    {21, 0, 18, 0, 3, 0, 9},
-    {24, 0, 18, 0, 3, 0, 12},
-    {16, 0, 18, 0, 3, 0, 12},
-    {5, 0, 0, 0, 3, 1, 12},
-    {25, 0, 18, 0, 3, 0, 17},
-    {18, 0, 18, 1, 3, 0, 1},
-    {0, 0, 15, 0, 5, 0, 36},
-    {29, 0, 12, 0, 5, 0, 4},
-    {21, 0, 18, 0, 4, 0, 0},
-    {23, 0, 10, 0, 3, 0, 10},
-    {23, 0, 10, 0, 4, 0, 9},
-    {26, 0, 18, 0, 3, 0, 12},
-    {21, 0, 18, 0, 4, 0, 29},
-    {24, 0, 18, 0, 4, 0, 29},
-    {26, 0, 18, 0, 5, 0, 12},
-    {7, 0, 0, 0, 4, 1, 29},
-    {20, 0, 18, 1, 5, 0, 3},
-    {1, 0, 14, 0, 4, 0, 17},
-    {26, 0, 18, 0, 4, 0, 12},
-    {26, 0, 10, 0, 4, 0, 10},
-    {25, 0, 10, 0, 4, 0, 9},
-    {15, 0, 8, 0, 4, 0, 29},
-    {24, 0, 18, 0, 4, 0, 18},
-    {5, 0, 0, 0, 5, 0, 12},
-    {19, 0, 18, 1, 5, 0, 3},
-    {15, 0, 18, 0, 4, 0, 29},
-    {9, 0, 0, 0, 5, 1, 12},
-    {9, 0, 0, 0, 4, 1, 12},
-    {25, 0, 18, 0, 4, 0, 29},
-    {5, 0, 0, 0, 4, 1, 12},
-    {5, 0, 0, 0, 5, 1, 12},
-    {7, 0, 0, 0, 5, 1, 12},
-    {8, 0, 0, 0, 5, 1, 12},
-    {6, 0, 0, 0, 5, 1, 12},
-    {6, 0, 18, 0, 5, 0, 12},
-    {6, 0, 0, 0, 5, 0, 12},
-    {24, 0, 18, 0, 5, 0, 12},
-    {24, 0, 18, 0, 4, 0, 12},
-    {6, 0, 18, 0, 4, 0, 29},
-    {6, 0, 18, 0, 5, 0, 18},
-    {6, 0, 0, 0, 4, 0, 29},
-    {24, 0, 18, 0, 5, 34, 12},
-    {12, 230, 13, 0, 4, 40, 21},
-    {12, 232, 13, 0, 4, 40, 21},
-    {12, 220, 13, 0, 4, 40, 21},
-    {12, 216, 13, 0, 4, 40, 21},
-    {12, 202, 13, 0, 4, 40, 21},
-    {12, 1, 13, 0, 4, 40, 21},
-    {12, 240, 13, 0, 4, 40, 21},
-    {12, 0, 13, 0, 4, 40, 4},
-    {12, 233, 13, 0, 4, 40, 4},
-    {12, 234, 13, 0, 4, 40, 4},
-    {9, 0, 0, 0, 5, 2, 12},
-    {5, 0, 0, 0, 5, 2, 12},
-    {24, 0, 18, 0, 5, 2, 12},
-    {2, 0, 18, 0, 5, 102, 41},
-    {6, 0, 0, 0, 5, 2, 12},
-    {21, 0, 18, 0, 5, 0, 8},
-    {21, 0, 18, 0, 5, 0, 12},
-    {9, 0, 0, 0, 4, 2, 12},
-    {5, 0, 0, 0, 4, 2, 12},
-    {9, 0, 0, 0, 5, 54, 12},
-    {5, 0, 0, 0, 5, 54, 12},
-    {25, 0, 18, 0, 5, 2, 12},
-    {9, 0, 0, 0, 5, 3, 12},
-    {9, 0, 0, 0, 4, 3, 12},
-    {5, 0, 0, 0, 4, 3, 12},
-    {5, 0, 0, 0, 5, 3, 12},
-    {26, 0, 0, 0, 5, 3, 12},
-    {12, 230, 13, 0, 5, 3, 21},
-    {12, 230, 13, 0, 5, 40, 21},
-    {11, 0, 13, 0, 5, 3, 21},
-    {9, 0, 0, 0, 5, 4, 12},
-    {6, 0, 0, 0, 5, 4, 12},
-    {21, 0, 0, 0, 5, 4, 12},
-    {5, 0, 0, 0, 5, 4, 12},
-    {21, 0, 0, 0, 5, 0, 8},
-    {17, 0, 18, 0, 5, 4, 17},
-    {26, 0, 18, 0, 5, 4, 12},
-    {23, 0, 10, 0, 5, 4, 9},
-    {12, 220, 13, 0, 5, 5, 21},
-    {12, 230, 13, 0, 5, 5, 21},
-    {12, 222, 13, 0, 5, 5, 21},
-    {12, 228, 13, 0, 5, 5, 21},
-    {12, 10, 13, 0, 5, 5, 21},
-    {12, 11, 13, 0, 5, 5, 21},
-    {12, 12, 13, 0, 5, 5, 21},
-    {12, 13, 13, 0, 5, 5, 21},
-    {12, 14, 13, 0, 5, 5, 21},
-    {12, 15, 13, 0, 5, 5, 21},
-    {12, 16, 13, 0, 5, 5, 21},
-    {12, 17, 13, 0, 5, 5, 21},
-    {12, 18, 13, 0, 5, 5, 21},
-    {12, 19, 13, 0, 5, 5, 21},
-    {12, 20, 13, 0, 5, 5, 21},
-    {12, 21, 13, 0, 5, 5, 21},
-    {12, 22, 13, 0, 5, 5, 21},
-    {17, 0, 3, 0, 5, 5, 17},
-    {12, 23, 13, 0, 5, 5, 21},
-    {21, 0, 3, 0, 5, 5, 12},
-    {12, 24, 13, 0, 5, 5, 21},
-    {12, 25, 13, 0, 5, 5, 21},
-    {21, 0, 3, 0, 5, 5, 6},
-    {7, 0, 3, 0, 5, 5, 13},
-    {1, 0, 11, 0, 5, 6, 12},
-    {1, 0, 11, 0, 5, 0, 12},
-    {25, 0, 18, 0, 5, 6, 12},
-    {25, 0, 4, 0, 5, 6, 12},
-    {21, 0, 10, 0, 5, 6, 10},
-    {23, 0, 4, 0, 5, 6, 10},
-    {21, 0, 12, 0, 5, 0, 8},
-    {21, 0, 4, 0, 5, 6, 8},
-    {26, 0, 18, 0, 5, 6, 12},
-    {12, 230, 13, 0, 5, 6, 21},
-    {12, 30, 13, 0, 5, 6, 21},
-    {12, 31, 13, 0, 5, 6, 21},
-    {12, 32, 13, 0, 5, 6, 21},
-    {21, 0, 4, 0, 5, 0, 6},
-    {1, 0, 4, 0, 5, 0, 21},
-    {21, 0, 4, 0, 5, 6, 6},
-    {7, 0, 4, 0, 5, 6, 12},
-    {6, 0, 4, 0, 5, 0, 12},
-    {12, 27, 13, 0, 5, 40, 21},
-    {12, 28, 13, 0, 5, 40, 21},
-    {12, 29, 13, 0, 5, 40, 21},
-    {12, 30, 13, 0, 5, 40, 21},
-    {12, 31, 13, 0, 5, 40, 21},
-    {12, 32, 13, 0, 5, 40, 21},
-    {12, 33, 13, 0, 5, 40, 21},
-    {12, 34, 13, 0, 5, 40, 21},
-    {12, 220, 13, 0, 5, 40, 21},
-    {12, 220, 13, 0, 5, 6, 21},
-    {13, 0, 11, 0, 5, 6, 11},
-    {21, 0, 11, 0, 5, 6, 11},
-    {21, 0, 4, 0, 5, 6, 12},
-    {12, 35, 13, 0, 5, 40, 21},
-    {6, 0, 4, 0, 5, 6, 12},
-    {13, 0, 8, 0, 5, 6, 11},
-    {26, 0, 4, 0, 5, 6, 12},
-    {21, 0, 4, 0, 5, 7, 12},
-    {1, 0, 4, 0, 5, 7, 12},
-    {7, 0, 4, 0, 5, 7, 12},
-    {12, 36, 13, 0, 5, 7, 21},
-    {12, 230, 13, 0, 5, 7, 21},
-    {12, 220, 13, 0, 5, 7, 21},
-    {7, 0, 4, 0, 5, 8, 12},
-    {12, 0, 13, 0, 5, 8, 21},
-    {13, 0, 3, 0, 5, 65, 11},
-    {7, 0, 3, 0, 5, 65, 12},
-    {12, 230, 13, 0, 5, 65, 21},
-    {12, 220, 13, 0, 5, 65, 21},
-    {6, 0, 3, 0, 5, 65, 12},
-    {26, 0, 18, 0, 5, 65, 12},
-    {21, 0, 18, 0, 5, 65, 12},
-    {21, 0, 18, 0, 5, 65, 8},
-    {21, 0, 18, 0, 5, 65, 6},
-    {7, 0, 3, 0, 5, 81, 12},
-    {12, 230, 13, 0, 5, 81, 21},
-    {6, 0, 3, 0, 5, 81, 12},
-    {21, 0, 3, 0, 5, 81, 12},
-    {7, 0, 3, 0, 5, 94, 12},
-    {12, 220, 13, 0, 5, 94, 21},
-    {21, 0, 3, 0, 5, 94, 12},
-    {12, 27, 13, 0, 5, 6, 21},
-    {12, 28, 13, 0, 5, 6, 21},
-    {12, 29, 13, 0, 5, 6, 21},
-    {12, 0, 13, 0, 5, 9, 21},
-    {10, 0, 0, 0, 5, 9, 21},
-    {7, 0, 0, 0, 5, 9, 12},
-    {12, 7, 13, 0, 5, 9, 21},
-    {12, 9, 13, 0, 5, 9, 21},
-    {12, 230, 13, 0, 5, 9, 21},
-    {21, 0, 0, 0, 5, 0, 17},
-    {13, 0, 0, 0, 5, 9, 11},
-    {21, 0, 0, 0, 5, 9, 12},
-    {6, 0, 0, 0, 5, 9, 12},
-    {7, 0, 0, 0, 5, 10, 12},
-    {12, 0, 13, 0, 5, 10, 21},
-    {10, 0, 0, 0, 5, 10, 21},
-    {12, 7, 13, 0, 5, 10, 21},
-    {12, 9, 13, 0, 5, 10, 21},
-    {13, 0, 0, 0, 5, 10, 11},
-    {23, 0, 10, 0, 5, 10, 10},
-    {15, 0, 0, 0, 5, 10, 12},
-    {15, 0, 0, 0, 5, 10, 10},
-    {26, 0, 0, 0, 5, 10, 12},
-    {23, 0, 10, 0, 5, 10, 9},
-    {12, 0, 13, 0, 5, 11, 21},
-    {10, 0, 0, 0, 5, 11, 21},
-    {7, 0, 0, 0, 5, 11, 12},
-    {12, 7, 13, 0, 5, 11, 21},
-    {12, 9, 13, 0, 5, 11, 21},
-    {13, 0, 0, 0, 5, 11, 11},
-    {12, 0, 13, 0, 5, 12, 21},
-    {10, 0, 0, 0, 5, 12, 21},
-    {7, 0, 0, 0, 5, 12, 12},
-    {12, 7, 13, 0, 5, 12, 21},
-    {12, 9, 13, 0, 5, 12, 21},
-    {13, 0, 0, 0, 5, 12, 11},
-    {21, 0, 0, 0, 5, 12, 12},
-    {23, 0, 10, 0, 5, 12, 9},
-    {12, 0, 13, 0, 5, 13, 21},
-    {10, 0, 0, 0, 5, 13, 21},
-    {7, 0, 0, 0, 5, 13, 12},
-    {12, 7, 13, 0, 5, 13, 21},
-    {12, 9, 13, 0, 5, 13, 21},
-    {13, 0, 0, 0, 5, 13, 11},
-    {26, 0, 0, 0, 5, 13, 12},
-    {15, 0, 0, 0, 5, 13, 12},
-    {12, 0, 13, 0, 5, 14, 21},
-    {7, 0, 0, 0, 5, 14, 12},
-    {10, 0, 0, 0, 5, 14, 21},
-    {12, 9, 13, 0, 5, 14, 21},
-    {13, 0, 0, 0, 5, 14, 11},
-    {15, 0, 0, 0, 5, 14, 12},
-    {26, 0, 18, 0, 5, 14, 12},
-    {23, 0, 10, 0, 5, 14, 9},
-    {12, 0, 13, 0, 5, 15, 21},
-    {10, 0, 0, 0, 5, 15, 21},
-    {7, 0, 0, 0, 5, 15, 12},
-    {12, 9, 13, 0, 5, 15, 21},
-    {12, 84, 13, 0, 5, 15, 21},
-    {12, 91, 13, 0, 5, 15, 21},
-    {13, 0, 0, 0, 5, 15, 11},
-    {15, 0, 18, 0, 5, 15, 12},
-    {26, 0, 0, 0, 5, 15, 12},
-    {7, 0, 0, 0, 5, 16, 12},
-    {12, 0, 13, 0, 5, 16, 21},
-    {10, 0, 0, 0, 5, 16, 21},
-    {12, 7, 13, 0, 5, 16, 21},
-    {12, 0, 0, 0, 5, 16, 21},
-    {12, 9, 13, 0, 5, 16, 21},
-    {13, 0, 0, 0, 5, 16, 11},
-    {12, 0, 13, 0, 5, 17, 21},
-    {10, 0, 0, 0, 5, 17, 21},
-    {7, 0, 0, 0, 5, 17, 12},
-    {12, 9, 13, 0, 5, 17, 21},
-    {26, 0, 0, 0, 5, 17, 12},
-    {15, 0, 0, 0, 5, 17, 12},
-    {13, 0, 0, 0, 5, 17, 11},
-    {26, 0, 0, 0, 5, 17, 10},
-    {10, 0, 0, 0, 5, 18, 21},
-    {7, 0, 0, 0, 5, 18, 12},
-    {12, 9, 13, 0, 5, 18, 21},
-    {12, 0, 13, 0, 5, 18, 21},
-    {13, 0, 0, 0, 5, 18, 11},
-    {21, 0, 0, 0, 5, 18, 12},
-    {7, 0, 0, 0, 5, 19, 38},
-    {12, 0, 13, 0, 5, 19, 38},
-    {12, 103, 13, 0, 5, 19, 38},
-    {12, 9, 13, 0, 5, 19, 38},
-    {23, 0, 10, 0, 5, 0, 9},
-    {6, 0, 0, 0, 5, 19, 38},
-    {12, 107, 13, 0, 5, 19, 38},
-    {21, 0, 0, 0, 5, 19, 12},
-    {13, 0, 0, 0, 5, 19, 11},
-    {21, 0, 0, 0, 5, 19, 17},
-    {7, 0, 0, 0, 5, 20, 38},
-    {12, 0, 13, 0, 5, 20, 38},
-    {12, 118, 13, 0, 5, 20, 38},
-    {6, 0, 0, 0, 5, 20, 38},
-    {12, 122, 13, 0, 5, 20, 38},
-    {13, 0, 0, 0, 5, 20, 11},
-    {7, 0, 0, 0, 5, 21, 12},
-    {26, 0, 0, 0, 5, 21, 18},
-    {21, 0, 0, 0, 5, 21, 18},
-    {21, 0, 0, 0, 5, 21, 12},
-    {21, 0, 0, 0, 5, 21, 4},
-    {21, 0, 0, 0, 5, 21, 17},
-    {21, 0, 0, 0, 5, 21, 6},
-    {26, 0, 0, 0, 5, 21, 12},
-    {12, 220, 13, 0, 5, 21, 21},
-    {13, 0, 0, 0, 5, 21, 11},
-    {15, 0, 0, 0, 5, 21, 12},
-    {26, 0, 0, 0, 5, 21, 17},
-    {12, 216, 13, 0, 5, 21, 21},
-    {22, 0, 18, 1, 5, 21, 0},
-    {18, 0, 18, 1, 5, 21, 1},
-    {10, 0, 0, 0, 5, 21, 21},
-    {12, 129, 13, 0, 5, 21, 21},
-    {12, 130, 13, 0, 5, 21, 21},
-    {12, 0, 13, 0, 5, 21, 21},
-    {12, 132, 13, 0, 5, 21, 21},
-    {10, 0, 0, 0, 5, 21, 17},
-    {12, 230, 13, 0, 5, 21, 21},
-    {12, 9, 13, 0, 5, 21, 21},
-    {26, 0, 0, 0, 5, 0, 12},
-    {7, 0, 0, 0, 5, 22, 38},
-    {10, 0, 0, 0, 5, 22, 38},
-    {12, 0, 13, 0, 5, 22, 38},
-    {12, 7, 13, 0, 5, 22, 38},
-    {12, 9, 13, 0, 5, 22, 38},
-    {13, 0, 0, 0, 5, 22, 11},
-    {21, 0, 0, 0, 5, 22, 17},
-    {21, 0, 0, 0, 5, 22, 12},
-    {12, 220, 13, 0, 5, 22, 38},
-    {26, 0, 0, 0, 5, 22, 38},
-    {9, 0, 0, 0, 5, 23, 12},
-    {7, 0, 0, 0, 5, 23, 12},
-    {21, 0, 0, 0, 5, 0, 12},
-    {6, 0, 0, 0, 5, 23, 12},
-    {7, 0, 0, 0, 2, 24, 25},
-    {7, 0, 0, 0, 5, 24, 26},
-    {7, 0, 0, 0, 5, 24, 27},
-    {7, 0, 0, 0, 5, 25, 12},
-    {12, 230, 13, 0, 5, 25, 21},
-    {21, 0, 0, 0, 5, 25, 12},
-    {21, 0, 0, 0, 5, 25, 17},
-    {15, 0, 0, 0, 5, 25, 12},
-    {26, 0, 18, 0, 5, 25, 12},
-    {9, 0, 0, 0, 5, 26, 12},
-    {5, 0, 0, 0, 5, 26, 12},
-    {17, 0, 18, 0, 5, 27, 17},
-    {7, 0, 0, 0, 5, 27, 12},
-    {21, 0, 0, 0, 5, 27, 12},
-    {29, 0, 17, 0, 5, 28, 17},
-    {7, 0, 0, 0, 5, 28, 12},
-    {22, 0, 18, 1, 5, 28, 0},
-    {18, 0, 18, 1, 5, 28, 1},
-    {7, 0, 0, 0, 5, 29, 12},
-    {14, 0, 0, 0, 5, 29, 12},
-    {7, 0, 0, 0, 5, 41, 12},
-    {12, 0, 13, 0, 5, 41, 21},
-    {12, 9, 13, 0, 5, 41, 21},
-    {7, 0, 0, 0, 5, 42, 12},
-    {12, 0, 13, 0, 5, 42, 21},
-    {12, 9, 13, 0, 5, 42, 21},
-    {7, 0, 0, 0, 5, 43, 12},
-    {12, 0, 13, 0, 5, 43, 21},
-    {7, 0, 0, 0, 5, 44, 12},
-    {12, 0, 13, 0, 5, 44, 21},
-    {7, 0, 0, 0, 5, 30, 38},
-    {12, 0, 13, 0, 5, 30, 38},
-    {10, 0, 0, 0, 5, 30, 38},
-    {12, 9, 13, 0, 5, 30, 38},
-    {21, 0, 0, 0, 5, 30, 17},
-    {21, 0, 0, 0, 5, 30, 5},
-    {6, 0, 0, 0, 5, 30, 38},
-    {21, 0, 0, 0, 5, 30, 12},
-    {23, 0, 10, 0, 5, 30, 9},
-    {12, 230, 13, 0, 5, 30, 38},
-    {13, 0, 0, 0, 5, 30, 11},
-    {15, 0, 18, 0, 5, 30, 12},
-    {21, 0, 18, 0, 5, 31, 12},
-    {21, 0, 18, 0, 5, 0, 6},
-    {21, 0, 18, 0, 5, 31, 17},
-    {21, 0, 18, 0, 5, 0, 17},
-    {17, 0, 18, 0, 5, 31, 18},
-    {21, 0, 18, 0, 5, 31, 6},
-    {12, 0, 13, 0, 5, 31, 21},
-    {1, 0, 14, 0, 5, 31, 4},
-    {13, 0, 0, 0, 5, 31, 11},
-    {7, 0, 0, 0, 5, 31, 12},
-    {6, 0, 0, 0, 5, 31, 12},
-    {12, 228, 13, 0, 5, 31, 21},
-    {7, 0, 0, 0, 5, 45, 12},
-    {12, 0, 13, 0, 5, 45, 21},
-    {10, 0, 0, 0, 5, 45, 21},
-    {12, 222, 13, 0, 5, 45, 21},
-    {12, 230, 13, 0, 5, 45, 21},
-    {12, 220, 13, 0, 5, 45, 21},
-    {26, 0, 18, 0, 5, 45, 12},
-    {21, 0, 18, 0, 5, 45, 6},
-    {13, 0, 0, 0, 5, 45, 11},
-    {7, 0, 0, 0, 5, 46, 38},
-    {7, 0, 0, 0, 5, 55, 38},
-    {13, 0, 0, 0, 5, 55, 11},
-    {15, 0, 0, 0, 5, 55, 38},
-    {26, 0, 18, 0, 5, 55, 38},
-    {26, 0, 18, 0, 5, 30, 12},
-    {7, 0, 0, 0, 5, 53, 12},
-    {12, 230, 13, 0, 5, 53, 21},
-    {12, 220, 13, 0, 5, 53, 21},
-    {10, 0, 0, 0, 5, 53, 21},
-    {12, 0, 13, 0, 5, 53, 21},
-    {21, 0, 0, 0, 5, 53, 12},
-    {7, 0, 0, 0, 5, 77, 38},
-    {10, 0, 0, 0, 5, 77, 38},
-    {12, 0, 13, 0, 5, 77, 38},
-    {12, 9, 13, 0, 5, 77, 38},
-    {12, 230, 13, 0, 5, 77, 38},
-    {12, 220, 13, 0, 5, 77, 21},
-    {13, 0, 0, 0, 5, 77, 11},
-    {21, 0, 0, 0, 5, 77, 38},
-    {6, 0, 0, 0, 5, 77, 38},
-    {11, 0, 13, 0, 5, 40, 21},
-    {12, 0, 13, 0, 5, 61, 21},
-    {10, 0, 0, 0, 5, 61, 21},
-    {7, 0, 0, 0, 5, 61, 12},
-    {12, 7, 13, 0, 5, 61, 21},
-    {10, 9, 0, 0, 5, 61, 21},
-    {13, 0, 0, 0, 5, 61, 11},
-    {21, 0, 0, 0, 5, 61, 17},
-    {21, 0, 0, 0, 5, 61, 12},
-    {26, 0, 0, 0, 5, 61, 12},
-    {12, 230, 13, 0, 5, 61, 21},
-    {12, 220, 13, 0, 5, 61, 21},
-    {12, 0, 13, 0, 5, 66, 21},
-    {10, 0, 0, 0, 5, 66, 21},
-    {7, 0, 0, 0, 5, 66, 12},
-    {10, 9, 0, 0, 5, 66, 21},
-    {12, 9, 13, 0, 5, 66, 21},
-    {13, 0, 0, 0, 5, 66, 11},
-    {7, 0, 0, 0, 5, 92, 12},
-    {12, 7, 13, 0, 5, 92, 21},
-    {10, 0, 0, 0, 5, 92, 21},
-    {12, 0, 13, 0, 5, 92, 21},
-    {10, 9, 0, 0, 5, 92, 21},
-    {21, 0, 0, 0, 5, 92, 12},
-    {7, 0, 0, 0, 5, 67, 12},
-    {10, 0, 0, 0, 5, 67, 21},
-    {12, 0, 13, 0, 5, 67, 21},
-    {12, 7, 13, 0, 5, 67, 21},
-    {21, 0, 0, 0, 5, 67, 17},
-    {13, 0, 0, 0, 5, 67, 11},
-    {13, 0, 0, 0, 5, 68, 11},
-    {7, 0, 0, 0, 5, 68, 12},
-    {6, 0, 0, 0, 5, 68, 12},
-    {21, 0, 0, 0, 5, 68, 17},
-    {21, 0, 0, 0, 5, 66, 12},
-    {12, 1, 13, 0, 5, 40, 21},
-    {10, 0, 0, 0, 5, 0, 21},
-    {7, 0, 0, 0, 5, 0, 12},
-    {6, 0, 0, 0, 5, 3, 12},
-    {12, 234, 13, 0, 5, 40, 21},
-    {12, 214, 13, 0, 5, 40, 21},
-    {12, 202, 13, 0, 5, 40, 21},
-    {12, 233, 13, 0, 5, 40, 21},
-    {8, 0, 0, 0, 5, 2, 12},
-    {24, 0, 18, 0, 5, 2, 18},
-    {29, 0, 17, 0, 5, 0, 17},
-    {29, 0, 17, 0, 5, 0, 4},
-    {1, 0, 14, 0, 5, 0, 20},
-    {1, 0, 14, 0, 5, 40, 21},
-    {1, 0, 14, 0, 5, 40, 41},
-    {1, 0, 0, 0, 5, 0, 21},
-    {1, 0, 3, 0, 5, 0, 21},
-    {17, 0, 18, 0, 4, 0, 17},
-    {17, 0, 18, 0, 5, 0, 4},
-    {17, 0, 18, 0, 5, 0, 17},
-    {17, 0, 18, 0, 4, 0, 19},
-    {17, 0, 18, 0, 4, 0, 29},
-    {20, 0, 18, 0, 4, 0, 3},
-    {19, 0, 18, 0, 4, 0, 3},
-    {22, 0, 18, 0, 5, 0, 0},
-    {20, 0, 18, 0, 5, 0, 3},
-    {21, 0, 18, 0, 4, 0, 12},
-    {21, 0, 18, 0, 4, 0, 15},
-    {21, 0, 18, 0, 4, 0, 17},
-    {27, 0, 17, 0, 5, 0, 30},
-    {28, 0, 15, 0, 5, 0, 30},
-    {1, 0, 1, 0, 5, 0, 21},
-    {1, 0, 5, 0, 5, 0, 21},
-    {1, 0, 7, 0, 5, 0, 21},
-    {1, 0, 2, 0, 5, 0, 21},
-    {1, 0, 6, 0, 5, 0, 21},
-    {21, 0, 10, 0, 4, 0, 10},
-    {21, 0, 10, 0, 5, 0, 10},
-    {21, 0, 18, 0, 4, 0, 10},
-    {21, 0, 18, 0, 5, 0, 10},
-    {21, 0, 18, 0, 5, 0, 5},
-    {16, 0, 18, 0, 5, 0, 12},
-    {25, 0, 12, 0, 5, 0, 8},
-    {22, 0, 18, 1, 5, 0, 0},
-    {18, 0, 18, 1, 5, 0, 1},
-    {25, 0, 18, 0, 5, 0, 12},
-    {1, 0, 14, 0, 5, 0, 22},
-    {1, 0, 14, 0, 5, 0, 12},
-    {1, 0, 19, 0, 5, 0, 21},
-    {1, 0, 20, 0, 5, 0, 21},
-    {1, 0, 21, 0, 5, 0, 21},
-    {1, 0, 22, 0, 5, 0, 21},
-    {1, 0, 14, 0, 5, 0, 21},
-    {15, 0, 8, 0, 5, 0, 12},
-    {25, 0, 9, 0, 5, 0, 12},
-    {6, 0, 0, 0, 4, 1, 29},
-    {23, 0, 10, 0, 5, 0, 10},
-    {23, 0, 10, 0, 1, 0, 9},
-    {2, 0, 18, 0, 5, 102, 9},
-    {9, 0, 0, 0, 5, 0, 12},
-    {26, 0, 18, 0, 4, 0, 10},
-    {26, 0, 18, 0, 4, 0, 29},
-    {5, 0, 0, 0, 4, 0, 29},
-    {26, 0, 18, 0, 4, 0, 9},
-    {9, 0, 0, 0, 4, 1, 29},
-    {26, 0, 10, 0, 5, 0, 12},
-    {25, 0, 18, 1, 5, 0, 12},
-    {15, 0, 18, 0, 5, 0, 12},
-    {15, 0, 18, 0, 4, 0, 12},
-    {15, 0, 18, 0, 5, 0, 29},
-    {14, 0, 0, 0, 4, 1, 29},
-    {14, 0, 0, 0, 5, 1, 12},
-    {25, 0, 18, 1, 4, 0, 29},
-    {25, 0, 9, 0, 5, 0, 9},
-    {25, 0, 10, 0, 5, 0, 9},
-    {25, 0, 18, 0, 5, 0, 15},
-    {26, 0, 18, 0, 2, 0, 14},
-    {22, 0, 18, 1, 2, 0, 0},
-    {18, 0, 18, 1, 2, 0, 1},
-    {26, 0, 18, 0, 2, 0, 12},
-    {26, 0, 18, 0, 5, 0, 14},
-    {26, 0, 0, 0, 4, 0, 29},
-    {26, 0, 18, 0, 5, 0, 29},
-    {25, 0, 18, 0, 2, 0, 12},
-    {26, 0, 18, 0, 4, 0, 14},
-    {26, 0, 18, 0, 5, 0, 41},
-    {26, 0, 18, 0, 4, 0, 41},
-    {26, 0, 18, 0, 2, 0, 41},
-    {26, 0, 18, 0, 2, 0, 29},
-    {26, 0, 18, 0, 5, 0, 3},
-    {26, 0, 18, 0, 5, 0, 6},
-    {26, 0, 0, 0, 5, 52, 12},
-    {9, 0, 0, 0, 5, 56, 12},
-    {5, 0, 0, 0, 5, 56, 12},
-    {26, 0, 18, 0, 5, 54, 12},
-    {12, 230, 13, 0, 5, 54, 21},
-    {21, 0, 18, 0, 5, 54, 6},
-    {21, 0, 18, 0, 5, 54, 17},
-    {15, 0, 18, 0, 5, 54, 12},
-    {5, 0, 0, 0, 5, 23, 12},
-    {7, 0, 0, 0, 5, 57, 12},
-    {6, 0, 0, 0, 5, 57, 12},
-    {21, 0, 0, 0, 5, 57, 17},
-    {12, 9, 13, 0, 5, 57, 21},
-    {21, 0, 18, 0, 5, 0, 3},
-    {21, 0, 18, 0, 5, 0, 0},
-    {17, 0, 18, 0, 5, 0, 12},
-    {17, 0, 18, 0, 5, 0, 19},
-    {26, 0, 18, 0, 2, 35, 14},
-    {29, 0, 17, 0, 0, 0, 17},
-    {21, 0, 18, 0, 2, 0, 1},
-    {21, 0, 18, 0, 2, 0, 14},
-    {6, 0, 0, 0, 2, 35, 5},
-    {7, 0, 0, 0, 2, 0, 14},
-    {14, 0, 0, 0, 2, 35, 14},
-    {17, 0, 18, 0, 2, 0, 5},
-    {22, 0, 18, 0, 2, 0, 0},
-    {18, 0, 18, 0, 2, 0, 1},
-    {12, 218, 13, 0, 2, 40, 21},
-    {12, 228, 13, 0, 2, 40, 21},
-    {12, 232, 13, 0, 2, 40, 21},
-    {12, 222, 13, 0, 2, 40, 21},
-    {10, 224, 0, 0, 2, 24, 21},
-    {17, 0, 18, 0, 2, 0, 14},
-    {6, 0, 0, 0, 2, 0, 14},
-    {6, 0, 0, 0, 2, 0, 21},
-    {7, 0, 0, 0, 2, 0, 5},
-    {7, 0, 0, 0, 2, 32, 32},
-    {7, 0, 0, 0, 2, 32, 14},
-    {12, 8, 13, 0, 2, 40, 21},
-    {24, 0, 18, 0, 2, 0, 5},
-    {6, 0, 0, 0, 2, 32, 5},
-    {7, 0, 0, 0, 2, 33, 32},
-    {7, 0, 0, 0, 2, 33, 14},
-    {21, 0, 18, 0, 2, 0, 5},
-    {6, 0, 0, 0, 2, 0, 32},
-    {6, 0, 0, 0, 2, 33, 5},
-    {7, 0, 0, 0, 2, 34, 14},
-    {7, 0, 0, 0, 2, 24, 14},
-    {26, 0, 0, 0, 2, 0, 14},
-    {15, 0, 0, 0, 2, 0, 14},
-    {26, 0, 0, 0, 2, 24, 14},
-    {26, 0, 18, 0, 2, 24, 14},
-    {15, 0, 0, 0, 4, 0, 29},
-    {15, 0, 18, 0, 2, 0, 14},
-    {26, 0, 0, 0, 2, 33, 14},
-    {7, 0, 0, 0, 2, 35, 14},
-    {2, 0, 18, 0, 2, 102, 14},
-    {7, 0, 0, 0, 2, 36, 14},
-    {6, 0, 0, 0, 2, 36, 5},
-    {26, 0, 18, 0, 2, 36, 14},
-    {7, 0, 0, 0, 5, 82, 12},
-    {6, 0, 0, 0, 5, 82, 12},
-    {21, 0, 0, 0, 5, 82, 17},
-    {7, 0, 0, 0, 5, 69, 12},
-    {6, 0, 0, 0, 5, 69, 12},
-    {21, 0, 18, 0, 5, 69, 17},
-    {21, 0, 18, 0, 5, 69, 6},
-    {13, 0, 0, 0, 5, 69, 11},
-    {7, 0, 0, 0, 5, 3, 12},
-    {21, 0, 18, 0, 5, 3, 12},
-    {6, 0, 18, 0, 5, 3, 12},
-    {7, 0, 0, 0, 5, 83, 12},
-    {14, 0, 0, 0, 5, 83, 12},
-    {12, 230, 13, 0, 5, 83, 21},
-    {21, 0, 0, 0, 5, 83, 12},
-    {21, 0, 0, 0, 5, 83, 17},
-    {24, 0, 0, 0, 5, 0, 12},
-    {7, 0, 0, 0, 5, 58, 12},
-    {12, 0, 13, 0, 5, 58, 21},
-    {12, 9, 13, 0, 5, 58, 21},
-    {10, 0, 0, 0, 5, 58, 21},
-    {26, 0, 18, 0, 5, 58, 12},
-    {15, 0, 0, 0, 5, 0, 12},
-    {7, 0, 0, 0, 5, 64, 12},
-    {21, 0, 18, 0, 5, 64, 18},
-    {21, 0, 18, 0, 5, 64, 6},
-    {10, 0, 0, 0, 5, 70, 21},
-    {7, 0, 0, 0, 5, 70, 12},
-    {12, 9, 13, 0, 5, 70, 21},
-    {12, 0, 13, 0, 5, 70, 21},
-    {21, 0, 0, 0, 5, 70, 17},
-    {13, 0, 0, 0, 5, 70, 11},
-    {21, 0, 0, 0, 5, 9, 18},
-    {13, 0, 0, 0, 5, 71, 11},
-    {7, 0, 0, 0, 5, 71, 12},
-    {12, 0, 13, 0, 5, 71, 21},
-    {12, 220, 13, 0, 5, 71, 21},
-    {21, 0, 0, 0, 5, 71, 17},
-    {7, 0, 0, 0, 5, 72, 12},
-    {12, 0, 13, 0, 5, 72, 21},
-    {10, 0, 0, 0, 5, 72, 21},
-    {10, 9, 0, 0, 5, 72, 21},
-    {21, 0, 0, 0, 5, 72, 12},
-    {12, 0, 13, 0, 5, 84, 21},
-    {10, 0, 0, 0, 5, 84, 21},
-    {7, 0, 0, 0, 5, 84, 12},
-    {12, 7, 13, 0, 5, 84, 21},
-    {10, 9, 0, 0, 5, 84, 21},
-    {21, 0, 0, 0, 5, 84, 12},
-    {21, 0, 0, 0, 5, 84, 17},
-    {13, 0, 0, 0, 5, 84, 11},
-    {6, 0, 0, 0, 5, 22, 38},
-    {7, 0, 0, 0, 5, 76, 12},
-    {12, 0, 13, 0, 5, 76, 21},
-    {10, 0, 0, 0, 5, 76, 21},
-    {13, 0, 0, 0, 5, 76, 11},
-    {21, 0, 0, 0, 5, 76, 12},
-    {21, 0, 0, 0, 5, 76, 17},
-    {7, 0, 0, 0, 5, 78, 38},
-    {12, 230, 13, 0, 5, 78, 38},
-    {12, 220, 13, 0, 5, 78, 38},
-    {6, 0, 0, 0, 5, 78, 38},
-    {21, 0, 0, 0, 5, 78, 38},
-    {7, 0, 0, 0, 5, 85, 12},
-    {10, 0, 0, 0, 5, 85, 21},
-    {12, 0, 13, 0, 5, 85, 21},
-    {21, 0, 0, 0, 5, 85, 17},
-    {6, 0, 0, 0, 5, 85, 12},
-    {12, 9, 13, 0, 5, 85, 21},
-    {13, 0, 0, 0, 5, 85, 11},
-    {7, 0, 0, 0, 2, 24, 23},
-    {7, 0, 0, 0, 2, 24, 24},
-    {4, 0, 0, 0, 5, 102, 39},
-    {3, 0, 0, 0, 4, 102, 41},
-    {12, 26, 13, 0, 5, 5, 21},
-    {25, 0, 9, 0, 5, 5, 12},
-    {24, 0, 4, 0, 5, 6, 12},
-    {18, 0, 18, 0, 5, 0, 1},
-    {12, 0, 13, 0, 4, 40, 21},
-    {21, 0, 18, 0, 2, 0, 8},
-    {21, 0, 18, 0, 2, 0, 6},
-    {21, 0, 18, 0, 2, 0, 15},
-    {16, 0, 18, 0, 2, 0, 14},
-    {21, 0, 12, 0, 2, 0, 1},
-    {21, 0, 12, 0, 2, 0, 5},
-    {21, 0, 10, 0, 2, 0, 14},
-    {25, 0, 9, 0, 2, 0, 14},
-    {17, 0, 9, 0, 2, 0, 14},
-    {25, 0, 18, 1, 2, 0, 14},
-    {25, 0, 18, 0, 2, 0, 14},
-    {23, 0, 10, 0, 2, 0, 9},
-    {21, 0, 10, 0, 2, 0, 10},
-    {21, 0, 18, 0, 0, 0, 6},
-    {21, 0, 18, 0, 0, 0, 14},
-    {21, 0, 10, 0, 0, 0, 14},
-    {23, 0, 10, 0, 0, 0, 9},
-    {21, 0, 10, 0, 0, 0, 10},
-    {22, 0, 18, 1, 0, 0, 0},
-    {18, 0, 18, 1, 0, 0, 1},
-    {25, 0, 9, 0, 0, 0, 14},
-    {21, 0, 12, 0, 0, 0, 1},
-    {17, 0, 9, 0, 0, 0, 14},
-    {21, 0, 12, 0, 0, 0, 14},
-    {13, 0, 8, 0, 0, 0, 14},
-    {21, 0, 12, 0, 0, 0, 5},
-    {21, 0, 18, 0, 0, 0, 5},
-    {25, 0, 18, 1, 0, 0, 14},
-    {25, 0, 18, 0, 0, 0, 14},
-    {9, 0, 0, 0, 0, 1, 14},
-    {24, 0, 18, 0, 0, 0, 14},
-    {16, 0, 18, 0, 0, 0, 14},
-    {5, 0, 0, 0, 0, 1, 14},
-    {21, 0, 18, 0, 1, 0, 1},
-    {22, 0, 18, 1, 1, 0, 0},
-    {18, 0, 18, 1, 1, 0, 1},
-    {21, 0, 18, 0, 1, 0, 5},
-    {7, 0, 0, 0, 1, 33, 14},
-    {7, 0, 0, 0, 1, 33, 32},
-    {6, 0, 0, 0, 1, 0, 32},
-    {6, 0, 0, 0, 1, 0, 5},
-    {7, 0, 0, 0, 1, 24, 14},
-    {23, 0, 10, 0, 0, 0, 10},
-    {26, 0, 18, 0, 0, 0, 14},
-    {26, 0, 18, 0, 1, 0, 12},
-    {25, 0, 18, 0, 1, 0, 12},
-    {1, 0, 18, 0, 5, 0, 21},
-    {26, 0, 18, 0, 5, 0, 31},
-    {7, 0, 0, 0, 5, 47, 12},
-    {14, 0, 18, 0, 5, 2, 12},
-    {15, 0, 18, 0, 5, 2, 12},
-    {26, 0, 18, 0, 5, 2, 12},
-    {26, 0, 0, 0, 5, 2, 12},
-    {7, 0, 0, 0, 5, 73, 12},
-    {7, 0, 0, 0, 5, 74, 12},
-    {7, 0, 0, 0, 5, 37, 12},
-    {15, 0, 0, 0, 5, 37, 12},
-    {7, 0, 0, 0, 5, 38, 12},
-    {14, 0, 0, 0, 5, 38, 12},
-    {7, 0, 0, 0, 5, 118, 12},
-    {12, 230, 13, 0, 5, 118, 21},
-    {7, 0, 0, 0, 5, 48, 12},
-    {21, 0, 0, 0, 5, 48, 17},
-    {7, 0, 0, 0, 5, 59, 12},
-    {21, 0, 0, 0, 5, 59, 17},
-    {14, 0, 0, 0, 5, 59, 12},
-    {9, 0, 0, 0, 5, 39, 12},
-    {5, 0, 0, 0, 5, 39, 12},
-    {7, 0, 0, 0, 5, 49, 12},
-    {7, 0, 0, 0, 5, 50, 12},
-    {13, 0, 0, 0, 5, 50, 11},
-    {9, 0, 0, 0, 5, 136, 12},
-    {5, 0, 0, 0, 5, 136, 12},
-    {7, 0, 0, 0, 5, 106, 12},
-    {7, 0, 0, 0, 5, 104, 12},
-    {21, 0, 0, 0, 5, 104, 12},
-    {7, 0, 0, 0, 5, 110, 12},
-    {7, 0, 3, 0, 5, 51, 12},
-    {7, 0, 3, 0, 5, 86, 12},
-    {21, 0, 3, 0, 5, 86, 17},
-    {15, 0, 3, 0, 5, 86, 12},
-    {7, 0, 3, 0, 5, 120, 12},
-    {26, 0, 3, 0, 5, 120, 12},
-    {15, 0, 3, 0, 5, 120, 12},
-    {7, 0, 3, 0, 5, 116, 12},
-    {15, 0, 3, 0, 5, 116, 12},
-    {7, 0, 3, 0, 5, 128, 12},
-    {15, 0, 3, 0, 5, 128, 12},
-    {7, 0, 3, 0, 5, 63, 12},
-    {15, 0, 3, 0, 5, 63, 12},
-    {21, 0, 18, 0, 5, 63, 17},
-    {7, 0, 3, 0, 5, 75, 12},
-    {21, 0, 3, 0, 5, 75, 12},
-    {7, 0, 3, 0, 5, 97, 12},
-    {7, 0, 3, 0, 5, 96, 12},
-    {15, 0, 3, 0, 5, 96, 12},
-    {7, 0, 3, 0, 5, 60, 12},
-    {12, 0, 13, 0, 5, 60, 21},
-    {12, 220, 13, 0, 5, 60, 21},
-    {12, 230, 13, 0, 5, 60, 21},
-    {12, 1, 13, 0, 5, 60, 21},
-    {12, 9, 13, 0, 5, 60, 21},
-    {15, 0, 3, 0, 5, 60, 12},
-    {21, 0, 3, 0, 5, 60, 17},
-    {21, 0, 3, 0, 5, 60, 12},
-    {7, 0, 3, 0, 5, 87, 12},
-    {15, 0, 3, 0, 5, 87, 12},
-    {21, 0, 3, 0, 5, 87, 12},
-    {7, 0, 3, 0, 5, 117, 12},
-    {15, 0, 3, 0, 5, 117, 12},
-    {7, 0, 3, 0, 5, 112, 12},
-    {26, 0, 3, 0, 5, 112, 12},
-    {12, 230, 13, 0, 5, 112, 21},
-    {12, 220, 13, 0, 5, 112, 21},
-    {15, 0, 3, 0, 5, 112, 12},
-    {21, 0, 3, 0, 5, 112, 17},
-    {21, 0, 3, 0, 5, 112, 15},
-    {7, 0, 3, 0, 5, 79, 12},
-    {21, 0, 18, 0, 5, 79, 17},
-    {7, 0, 3, 0, 5, 88, 12},
-    {15, 0, 3, 0, 5, 88, 12},
-    {7, 0, 3, 0, 5, 89, 12},
-    {15, 0, 3, 0, 5, 89, 12},
-    {7, 0, 3, 0, 5, 122, 12},
-    {21, 0, 3, 0, 5, 122, 12},
-    {15, 0, 3, 0, 5, 122, 12},
-    {7, 0, 3, 0, 5, 90, 12},
-    {9, 0, 3, 0, 5, 130, 12},
-    {5, 0, 3, 0, 5, 130, 12},
-    {15, 0, 3, 0, 5, 130, 12},
-    {15, 0, 11, 0, 5, 6, 12},
-    {10, 0, 0, 0, 5, 93, 21},
-    {12, 0, 13, 0, 5, 93, 21},
-    {7, 0, 0, 0, 5, 93, 12},
-    {12, 9, 13, 0, 5, 93, 21},
-    {21, 0, 0, 0, 5, 93, 17},
-    {21, 0, 0, 0, 5, 93, 12},
-    {15, 0, 18, 0, 5, 93, 12},
-    {13, 0, 0, 0, 5, 93, 11},
-    {12, 0, 13, 0, 5, 91, 21},
-    {10, 0, 0, 0, 5, 91, 21},
-    {7, 0, 0, 0, 5, 91, 12},
-    {12, 9, 13, 0, 5, 91, 21},
-    {12, 7, 13, 0, 5, 91, 21},
-    {21, 0, 0, 0, 5, 91, 12},
-    {1, 0, 0, 0, 5, 91, 12},
-    {21, 0, 0, 0, 5, 91, 17},
-    {7, 0, 0, 0, 5, 100, 12},
-    {13, 0, 0, 0, 5, 100, 11},
-    {12, 230, 13, 0, 5, 95, 21},
-    {7, 0, 0, 0, 5, 95, 12},
-    {12, 0, 13, 0, 5, 95, 21},
-    {10, 0, 0, 0, 5, 95, 21},
-    {12, 9, 13, 0, 5, 95, 21},
-    {13, 0, 0, 0, 5, 95, 11},
-    {21, 0, 0, 0, 5, 95, 17},
-    {7, 0, 0, 0, 5, 111, 12},
-    {12, 7, 13, 0, 5, 111, 21},
-    {21, 0, 0, 0, 5, 111, 12},
-    {21, 0, 0, 0, 5, 111, 18},
-    {12, 0, 13, 0, 5, 99, 21},
-    {10, 0, 0, 0, 5, 99, 21},
-    {7, 0, 0, 0, 5, 99, 12},
-    {10, 9, 0, 0, 5, 99, 21},
-    {21, 0, 0, 0, 5, 99, 17},
-    {21, 0, 0, 0, 5, 99, 12},
-    {12, 7, 13, 0, 5, 99, 21},
-    {13, 0, 0, 0, 5, 99, 11},
-    {21, 0, 0, 0, 5, 99, 18},
-    {15, 0, 0, 0, 5, 18, 12},
-    {7, 0, 0, 0, 5, 108, 12},
-    {10, 0, 0, 0, 5, 108, 21},
-    {12, 0, 13, 0, 5, 108, 21},
-    {10, 9, 0, 0, 5, 108, 21},
-    {12, 7, 13, 0, 5, 108, 21},
-    {21, 0, 0, 0, 5, 108, 17},
-    {21, 0, 0, 0, 5, 108, 12},
-    {7, 0, 0, 0, 5, 129, 12},
-    {21, 0, 0, 0, 5, 129, 17},
-    {7, 0, 0, 0, 5, 109, 12},
-    {12, 0, 13, 0, 5, 109, 21},
-    {10, 0, 0, 0, 5, 109, 21},
-    {12, 7, 13, 0, 5, 109, 21},
-    {12, 9, 13, 0, 5, 109, 21},
-    {13, 0, 0, 0, 5, 109, 11},
-    {12, 0, 13, 0, 5, 107, 21},
-    {10, 0, 0, 0, 5, 107, 21},
-    {7, 0, 0, 0, 5, 107, 12},
-    {12, 7, 13, 0, 5, 107, 21},
-    {10, 9, 0, 0, 5, 107, 21},
-    {12, 230, 13, 0, 5, 107, 21},
-    {7, 0, 0, 0, 5, 135, 12},
-    {10, 0, 0, 0, 5, 135, 21},
-    {12, 0, 13, 0, 5, 135, 21},
-    {12, 9, 13, 0, 5, 135, 21},
-    {12, 7, 13, 0, 5, 135, 21},
-    {21, 0, 0, 0, 5, 135, 17},
-    {21, 0, 0, 0, 5, 135, 12},
-    {13, 0, 0, 0, 5, 135, 11},
-    {7, 0, 0, 0, 5, 124, 12},
-    {10, 0, 0, 0, 5, 124, 21},
-    {12, 0, 13, 0, 5, 124, 21},
-    {12, 9, 13, 0, 5, 124, 21},
-    {12, 7, 13, 0, 5, 124, 21},
-    {21, 0, 0, 0, 5, 124, 12},
-    {13, 0, 0, 0, 5, 124, 11},
-    {7, 0, 0, 0, 5, 123, 12},
-    {10, 0, 0, 0, 5, 123, 21},
-    {12, 0, 13, 0, 5, 123, 21},
-    {12, 9, 13, 0, 5, 123, 21},
-    {12, 7, 13, 0, 5, 123, 21},
-    {21, 0, 0, 0, 5, 123, 18},
-    {21, 0, 0, 0, 5, 123, 17},
-    {21, 0, 0, 0, 5, 123, 6},
-    {21, 0, 0, 0, 5, 123, 12},
-    {7, 0, 0, 0, 5, 114, 12},
-    {10, 0, 0, 0, 5, 114, 21},
-    {12, 0, 13, 0, 5, 114, 21},
-    {12, 9, 13, 0, 5, 114, 21},
-    {21, 0, 0, 0, 5, 114, 17},
-    {21, 0, 0, 0, 5, 114, 12},
-    {13, 0, 0, 0, 5, 114, 11},
-    {21, 0, 18, 0, 5, 31, 18},
-    {7, 0, 0, 0, 5, 101, 12},
-    {12, 0, 13, 0, 5, 101, 21},
-    {10, 0, 0, 0, 5, 101, 21},
-    {10, 9, 0, 0, 5, 101, 21},
-    {12, 7, 13, 0, 5, 101, 21},
-    {13, 0, 0, 0, 5, 101, 11},
-    {7, 0, 0, 0, 5, 126, 38},
-    {12, 0, 13, 0, 5, 126, 38},
-    {10, 0, 0, 0, 5, 126, 38},
-    {12, 9, 13, 0, 5, 126, 38},
-    {13, 0, 0, 0, 5, 126, 11},
-    {15, 0, 0, 0, 5, 126, 38},
-    {21, 0, 0, 0, 5, 126, 17},
-    {26, 0, 0, 0, 5, 126, 38},
-    {9, 0, 0, 0, 5, 125, 12},
-    {5, 0, 0, 0, 5, 125, 12},
-    {13, 0, 0, 0, 5, 125, 11},
-    {15, 0, 0, 0, 5, 125, 12},
-    {7, 0, 0, 0, 5, 125, 12},
-    {7, 0, 0, 0, 5, 121, 12},
-    {7, 0, 0, 0, 5, 133, 12},
-    {10, 0, 0, 0, 5, 133, 21},
-    {12, 0, 13, 0, 5, 133, 21},
-    {12, 9, 0, 0, 5, 133, 21},
-    {21, 0, 0, 0, 5, 133, 17},
-    {13, 0, 0, 0, 5, 133, 11},
-    {15, 0, 0, 0, 5, 133, 12},
-    {21, 0, 0, 0, 5, 134, 18},
-    {21, 0, 0, 0, 5, 134, 6},
-    {7, 0, 0, 0, 5, 134, 12},
-    {12, 0, 13, 0, 5, 134, 21},
-    {10, 0, 0, 0, 5, 134, 21},
-    {7, 0, 0, 0, 5, 62, 12},
-    {14, 0, 0, 0, 5, 62, 12},
-    {21, 0, 0, 0, 5, 62, 17},
-    {7, 0, 0, 0, 5, 80, 12},
-    {7, 0, 0, 0, 5, 80, 0},
-    {7, 0, 0, 0, 5, 80, 1},
-    {7, 0, 0, 0, 5, 127, 12},
-    {7, 0, 0, 0, 5, 127, 0},
-    {7, 0, 0, 0, 5, 127, 1},
-    {7, 0, 0, 0, 5, 115, 12},
-    {13, 0, 0, 0, 5, 115, 11},
-    {21, 0, 0, 0, 5, 115, 17},
-    {7, 0, 0, 0, 5, 103, 12},
-    {12, 1, 13, 0, 5, 103, 21},
-    {21, 0, 0, 0, 5, 103, 17},
-    {7, 0, 0, 0, 5, 119, 12},
-    {12, 230, 13, 0, 5, 119, 21},
-    {21, 0, 0, 0, 5, 119, 17},
-    {21, 0, 0, 0, 5, 119, 12},
-    {26, 0, 0, 0, 5, 119, 12},
-    {6, 0, 0, 0, 5, 119, 12},
-    {13, 0, 0, 0, 5, 119, 11},
-    {15, 0, 0, 0, 5, 119, 12},
-    {7, 0, 0, 0, 5, 98, 12},
-    {10, 0, 0, 0, 5, 98, 21},
-    {12, 0, 13, 0, 5, 98, 21},
-    {6, 0, 0, 0, 5, 98, 12},
-    {6, 0, 0, 0, 2, 137, 5},
-    {7, 0, 0, 0, 2, 137, 14},
-    {7, 0, 0, 0, 5, 105, 12},
-    {26, 0, 0, 0, 5, 105, 12},
-    {12, 0, 13, 0, 5, 105, 21},
-    {12, 1, 13, 0, 5, 105, 21},
-    {21, 0, 0, 0, 5, 105, 17},
-    {10, 216, 0, 0, 5, 0, 21},
-    {10, 226, 0, 0, 5, 0, 21},
-    {12, 230, 13, 0, 5, 2, 21},
-    {25, 0, 0, 0, 5, 0, 12},
-    {13, 0, 8, 0, 5, 0, 11},
-    {26, 0, 0, 0, 5, 131, 12},
-    {12, 0, 13, 0, 5, 131, 21},
-    {21, 0, 0, 0, 5, 131, 17},
-    {21, 0, 0, 0, 5, 131, 12},
-    {12, 230, 13, 0, 5, 56, 21},
-    {7, 0, 3, 0, 5, 113, 12},
-    {15, 0, 3, 0, 5, 113, 12},
-    {12, 220, 13, 0, 5, 113, 21},
-    {9, 0, 3, 0, 5, 132, 12},
-    {5, 0, 3, 0, 5, 132, 12},
-    {12, 230, 13, 0, 5, 132, 21},
-    {12, 7, 13, 0, 5, 132, 21},
-    {13, 0, 3, 0, 5, 132, 11},
-    {21, 0, 3, 0, 5, 132, 0},
-    {2, 0, 18, 0, 5, 102, 14},
-    {26, 0, 0, 0, 2, 0, 29},
-    {26, 0, 0, 0, 5, 0, 28},
-    {26, 0, 0, 0, 2, 32, 14},
-    {24, 0, 18, 0, 2, 0, 41},
-    {26, 0, 18, 0, 5, 0, 5},
+    {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},
+    {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, 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},
+    {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},
+    {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},
+    {7, 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},
+    {5, 0, 0, 5, 23, 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},
+    {15, 0, 11, 5, 6, 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, 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},
+    {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},
+    {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},
+    {10, 0, 0, 5, 141, 21},
+    {12, 9, 13, 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, 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},
+    {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},
+    {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 364
@@ -1893,6 +1906,10 @@
 #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_GENERAL_CATEGORY_CC 0
 #define UCDN_GENERAL_CATEGORY_CF 1
@@ -1968,21 +1985,21 @@
     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, 94, 96, 
-    97, 98, 99, 100, 101, 102, 103, 104, 94, 105, 94, 106, 94, 94, 94, 107, 
-    107, 107, 108, 109, 110, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 111, 
-    111, 112, 113, 114, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 
-    94, 94, 115, 116, 117, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 
+    97, 98, 99, 100, 101, 102, 103, 104, 94, 105, 94, 106, 107, 94, 94, 108, 
+    108, 108, 109, 110, 111, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 112, 
+    112, 113, 114, 115, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 
+    94, 94, 116, 117, 118, 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, 
-    94, 94, 94, 118, 118, 119, 120, 94, 94, 94, 121, 122, 122, 122, 122, 122, 
-    122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 
-    122, 122, 122, 122, 123, 122, 122, 124, 94, 94, 94, 94, 94, 94, 94, 94, 
+    94, 94, 94, 119, 119, 120, 121, 94, 94, 94, 122, 123, 123, 123, 123, 123, 
+    123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 
+    123, 123, 123, 123, 124, 123, 123, 125, 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, 94, 94, 94, 94, 94, 94, 94, 125, 94, 94, 94, 94, 94, 94, 
-    94, 94, 94, 94, 94, 126, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 
-    94, 94, 94, 94, 94, 94, 94, 127, 128, 129, 130, 131, 132, 133, 134, 135, 
-    135, 136, 94, 94, 94, 94, 94, 137, 94, 94, 94, 94, 94, 94, 94, 138, 139, 
-    94, 94, 94, 94, 140, 94, 141, 142, 143, 144, 145, 146, 147, 148, 149, 
-    150, 151, 151, 151, 151, 151, 152, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 126, 127, 128, 94, 94, 94, 
+    94, 94, 94, 94, 94, 94, 129, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 
+    94, 94, 94, 94, 94, 94, 94, 94, 130, 131, 132, 133, 134, 135, 136, 137, 
+    138, 138, 139, 94, 94, 94, 94, 94, 140, 94, 94, 94, 94, 94, 94, 94, 141, 
+    142, 94, 94, 94, 94, 143, 94, 144, 145, 146, 147, 148, 149, 150, 151, 
+    152, 153, 154, 154, 154, 154, 154, 155, 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, 
@@ -1991,32 +2008,31 @@
     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, 153, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 154, 155, 52, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 156, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 52, 52, 
-    158, 157, 157, 157, 157, 159, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 
-    157, 157, 157, 157, 157, 157, 157, 157, 157, 159, 94, 94, 94, 94, 94, 94, 
-    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 156, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 157, 158, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    159, 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, 160, 161, 161, 161, 161, 161, 
+    161, 161, 161, 161, 161, 161, 161, 52, 52, 162, 161, 161, 161, 161, 163, 
+    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, 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, 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, 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, 161, 161, 161, 161, 161, 161, 161, 161, 
+    161, 161, 161, 163, 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, 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, 94, 94, 94, 94, 94, 94, 94, 
@@ -2157,8 +2173,8 @@
     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, 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, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 160, 161, 
     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, 164, 165, 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, 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, 94, 
@@ -2172,7 +2188,7 @@
     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, 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, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 74, 74, 74, 74, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
@@ -2186,7 +2202,7 @@
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 162, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 166, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
@@ -2200,7 +2216,8 @@
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
     74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 162, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 166, 
 };
 
 static const unsigned short index1[] = {
@@ -2220,1136 +2237,1145 @@
     128, 128, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 145, 145, 
     146, 147, 148, 149, 128, 128, 128, 128, 128, 128, 150, 150, 150, 150, 
     151, 152, 153, 120, 154, 155, 156, 156, 156, 157, 158, 159, 160, 160, 
-    161, 162, 163, 164, 165, 166, 167, 167, 167, 168, 120, 120, 120, 120, 
-    120, 120, 120, 120, 128, 128, 169, 170, 120, 120, 171, 126, 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, 120, 214, 215, 216, 217, 217, 218, 
-    219, 220, 221, 222, 223, 120, 224, 225, 226, 227, 228, 229, 230, 231, 
-    231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 120, 242, 243, 
-    244, 245, 246, 243, 247, 248, 249, 250, 251, 120, 252, 253, 254, 255, 
-    256, 257, 258, 259, 259, 258, 259, 260, 261, 262, 263, 264, 265, 266, 
-    120, 267, 268, 269, 270, 271, 271, 270, 272, 273, 274, 275, 276, 277, 
-    278, 279, 280, 120, 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, 120, 306, 307, 307, 307, 307, 307, 
-    308, 309, 310, 311, 312, 313, 120, 120, 120, 120, 314, 315, 316, 317, 
-    318, 319, 320, 321, 322, 323, 324, 325, 120, 120, 120, 120, 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, 120, 120, 
-    120, 120, 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, 120, 396, 396, 397, 120, 398, 398, 399, 120, 
-    400, 401, 402, 120, 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, 120, 420, 418, 418, 418, 418, 421, 
-    384, 384, 384, 384, 384, 384, 384, 384, 422, 120, 423, 423, 423, 424, 
-    425, 426, 427, 428, 429, 430, 431, 431, 431, 432, 433, 120, 434, 434, 
-    434, 434, 434, 435, 434, 434, 434, 436, 437, 438, 439, 439, 439, 439, 
-    440, 440, 441, 442, 443, 443, 443, 443, 443, 443, 444, 445, 446, 447, 
-    448, 449, 450, 451, 450, 451, 452, 453, 454, 455, 120, 120, 120, 120, 
-    120, 120, 120, 120, 456, 457, 457, 457, 457, 457, 458, 459, 460, 461, 
-    462, 463, 464, 465, 466, 467, 468, 469, 469, 469, 470, 471, 472, 473, 
-    474, 474, 474, 474, 475, 476, 477, 478, 479, 479, 479, 479, 480, 481, 
-    482, 483, 484, 485, 486, 487, 488, 488, 488, 489, 100, 490, 120, 120, 
-    120, 120, 120, 120, 491, 120, 492, 493, 494, 495, 496, 497, 54, 54, 54, 
-    54, 498, 499, 56, 56, 56, 56, 56, 500, 501, 502, 54, 503, 54, 54, 54, 
-    504, 56, 56, 56, 505, 506, 507, 508, 509, 509, 509, 510, 511, 27, 27, 27, 
-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 512, 513, 27, 
-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 514, 515, 516, 517, 514, 515, 
-    514, 515, 516, 517, 514, 518, 514, 515, 514, 516, 514, 519, 514, 519, 
-    514, 519, 520, 521, 522, 523, 524, 525, 514, 526, 527, 528, 529, 530, 
-    531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 
-    545, 546, 56, 547, 548, 549, 550, 551, 552, 552, 553, 554, 555, 556, 557, 
-    120, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 
-    571, 570, 572, 573, 574, 575, 576, 577, 578, 579, 580, 579, 581, 582, 
-    579, 583, 579, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 
-    595, 596, 597, 598, 599, 594, 594, 600, 601, 602, 603, 604, 594, 594, 
-    605, 585, 606, 607, 594, 594, 608, 594, 594, 579, 609, 610, 611, 612, 
-    613, 614, 615, 615, 615, 615, 615, 615, 615, 615, 616, 579, 579, 617, 
-    618, 585, 585, 619, 579, 579, 579, 579, 584, 620, 621, 622, 623, 579, 
-    579, 579, 579, 623, 120, 120, 120, 579, 624, 120, 120, 625, 625, 625, 
-    625, 625, 626, 626, 627, 628, 628, 628, 628, 628, 628, 628, 628, 628, 
-    629, 625, 630, 631, 631, 631, 631, 631, 631, 631, 631, 631, 632, 631, 
-    631, 631, 631, 633, 579, 631, 631, 634, 579, 635, 636, 637, 638, 639, 
-    640, 636, 579, 634, 641, 579, 642, 643, 644, 645, 646, 579, 579, 579, 
-    647, 648, 649, 650, 579, 651, 652, 579, 653, 579, 579, 654, 655, 656, 
-    657, 579, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 579, 
-    579, 579, 669, 579, 670, 579, 671, 672, 673, 674, 675, 676, 625, 677, 
-    677, 678, 579, 579, 579, 669, 679, 680, 681, 682, 683, 684, 685, 585, 
-    585, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 
-    686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 
-    686, 686, 686, 686, 686, 585, 585, 585, 585, 585, 585, 585, 585, 585, 
-    585, 585, 585, 585, 585, 585, 585, 687, 688, 688, 689, 594, 594, 585, 
-    690, 691, 692, 693, 694, 695, 696, 697, 698, 585, 699, 594, 700, 701, 
-    702, 703, 683, 585, 585, 597, 690, 703, 704, 705, 706, 594, 594, 594, 
-    594, 707, 708, 594, 594, 594, 594, 709, 710, 711, 683, 712, 713, 579, 
-    579, 579, 714, 579, 579, 585, 585, 715, 716, 717, 636, 579, 579, 718, 
-    579, 579, 579, 719, 579, 579, 579, 579, 720, 579, 721, 722, 120, 120, 
-    723, 120, 120, 724, 724, 724, 724, 724, 725, 726, 726, 726, 726, 726, 
-    727, 728, 729, 730, 731, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 
-    732, 733, 734, 735, 736, 736, 736, 736, 737, 738, 739, 739, 739, 739, 
-    739, 739, 739, 740, 741, 742, 370, 370, 372, 120, 372, 372, 372, 372, 
-    372, 372, 372, 372, 743, 743, 743, 743, 744, 745, 746, 747, 748, 749, 
-    750, 751, 752, 120, 120, 120, 120, 120, 120, 120, 753, 753, 753, 754, 
-    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 755, 120, 753, 753, 
-    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 
-    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 756, 120, 120, 120, 
-    757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 769, 
-    770, 769, 769, 769, 771, 772, 773, 774, 775, 776, 777, 777, 778, 777, 
-    777, 777, 779, 780, 781, 782, 783, 784, 784, 784, 784, 785, 786, 787, 
-    787, 787, 787, 787, 787, 787, 787, 787, 787, 788, 789, 790, 784, 784, 
-    784, 791, 757, 757, 757, 757, 758, 120, 792, 792, 793, 793, 793, 794, 
-    795, 796, 790, 790, 790, 797, 798, 799, 793, 793, 793, 800, 795, 796, 
-    790, 790, 790, 790, 801, 799, 790, 802, 803, 803, 803, 803, 803, 804, 
-    803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 790, 790, 790, 
-    805, 806, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 807, 
-    790, 790, 790, 805, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 809, 810, 579, 579, 579, 579, 579, 579, 579, 579, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 809, 810, 810, 810, 
-    810, 810, 811, 811, 812, 811, 811, 811, 811, 811, 811, 811, 811, 811, 
-    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 
-    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 
-    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 
-    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 
-    811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 813, 
-    814, 814, 814, 814, 814, 814, 815, 120, 816, 816, 816, 816, 816, 817, 
-    818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 
-    818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 
-    818, 818, 818, 818, 818, 819, 818, 818, 820, 821, 120, 120, 101, 101, 
-    101, 101, 101, 822, 823, 824, 101, 101, 101, 825, 826, 826, 826, 826, 
-    826, 826, 826, 826, 827, 828, 829, 120, 64, 64, 830, 831, 832, 27, 833, 
-    27, 27, 27, 27, 27, 27, 27, 834, 835, 27, 836, 837, 27, 27, 838, 839, 
-    120, 120, 120, 120, 120, 120, 120, 840, 841, 842, 843, 844, 844, 845, 
-    846, 847, 848, 849, 849, 849, 849, 849, 849, 850, 120, 851, 852, 852, 
-    852, 852, 852, 853, 854, 855, 856, 857, 858, 859, 859, 860, 861, 862, 
-    863, 864, 864, 865, 866, 867, 867, 868, 869, 870, 871, 367, 367, 367, 
-    872, 873, 874, 874, 874, 874, 874, 875, 876, 877, 878, 879, 880, 881, 
-    348, 352, 882, 883, 883, 883, 883, 883, 884, 885, 120, 886, 887, 888, 
-    889, 348, 348, 890, 891, 892, 892, 892, 892, 892, 892, 893, 894, 895, 
-    120, 120, 896, 897, 898, 899, 120, 900, 900, 900, 120, 372, 372, 54, 54, 
-    54, 54, 54, 901, 902, 120, 903, 903, 903, 903, 903, 903, 903, 903, 903, 
-    903, 897, 897, 897, 897, 904, 905, 906, 907, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 
-    909, 909, 908, 909, 909, 910, 909, 909, 909, 909, 909, 909, 908, 909, 
-    909, 910, 909, 909, 909, 908, 909, 909, 910, 909, 909, 909, 908, 909, 
-    909, 911, 120, 368, 368, 912, 913, 369, 369, 369, 369, 369, 914, 915, 
-    915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 
-    915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 
-    915, 915, 915, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 
-    916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 
-    916, 916, 916, 916, 916, 916, 916, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 809, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 917, 810, 810, 810, 810, 918, 120, 919, 
-    920, 121, 921, 922, 923, 924, 121, 128, 128, 128, 128, 128, 128, 128, 
-    128, 128, 128, 128, 128, 925, 926, 927, 120, 928, 128, 128, 128, 128, 
+    161, 162, 163, 164, 165, 166, 167, 167, 167, 168, 145, 169, 120, 120, 
+    120, 120, 120, 120, 128, 128, 170, 171, 120, 120, 172, 126, 173, 174, 
+    175, 176, 177, 178, 178, 178, 178, 178, 178, 179, 180, 181, 182, 178, 
+    183, 184, 185, 178, 186, 187, 188, 189, 189, 190, 191, 192, 193, 194, 
+    195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 204, 205, 206, 207, 
+    208, 209, 210, 211, 212, 213, 214, 120, 215, 216, 217, 218, 218, 219, 
+    220, 221, 222, 223, 224, 120, 225, 226, 227, 228, 229, 230, 231, 232, 
+    232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 120, 243, 244, 
+    245, 246, 247, 244, 248, 249, 250, 251, 252, 120, 253, 254, 255, 256, 
+    257, 258, 259, 260, 260, 259, 260, 261, 262, 263, 264, 265, 266, 267, 
+    120, 268, 269, 270, 271, 272, 272, 271, 273, 274, 275, 276, 277, 278, 
+    279, 280, 281, 120, 282, 283, 284, 285, 285, 285, 285, 286, 287, 288, 
+    289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 296, 296, 299, 300, 
+    297, 301, 302, 303, 304, 305, 306, 120, 307, 308, 308, 308, 308, 308, 
+    309, 310, 311, 312, 313, 314, 120, 120, 120, 120, 315, 316, 317, 318, 
+    319, 320, 321, 322, 323, 324, 325, 326, 120, 120, 120, 120, 327, 328, 
+    329, 330, 331, 332, 333, 334, 335, 336, 335, 335, 335, 337, 338, 339, 
+    340, 341, 342, 343, 342, 342, 342, 344, 345, 346, 347, 348, 120, 120, 
+    120, 120, 349, 349, 349, 349, 349, 350, 351, 352, 353, 354, 355, 356, 
+    357, 358, 359, 349, 360, 361, 353, 362, 363, 363, 363, 363, 364, 365, 
+    366, 366, 366, 366, 366, 367, 368, 368, 368, 368, 368, 368, 368, 368, 
+    368, 368, 368, 368, 369, 369, 369, 369, 369, 369, 369, 369, 369, 370, 
+    370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 371, 371, 371, 371, 
+    371, 371, 371, 371, 371, 372, 373, 372, 371, 371, 371, 371, 371, 372, 
+    371, 371, 371, 371, 372, 373, 372, 371, 373, 371, 371, 371, 371, 371, 
+    371, 371, 372, 371, 371, 371, 371, 371, 371, 371, 371, 374, 375, 376, 
+    377, 378, 371, 371, 379, 380, 381, 381, 381, 381, 381, 381, 381, 381, 
+    381, 381, 382, 383, 384, 385, 385, 385, 385, 385, 385, 385, 385, 385, 
+    385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 
+    385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 
+    385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 
+    385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 
+    385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 386, 385, 385, 
+    387, 388, 388, 389, 390, 390, 390, 390, 390, 390, 390, 390, 390, 391, 
+    392, 393, 394, 395, 396, 120, 397, 397, 398, 120, 399, 399, 400, 120, 
+    401, 402, 403, 120, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408, 
+    409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 419, 419, 419, 
+    420, 419, 419, 419, 419, 419, 419, 120, 421, 419, 419, 419, 419, 422, 
+    385, 385, 385, 385, 385, 385, 385, 385, 423, 120, 424, 424, 424, 425, 
+    426, 427, 428, 429, 430, 431, 432, 432, 432, 433, 434, 120, 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, 120, 120, 120, 120, 
+    120, 120, 120, 120, 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, 120, 120, 
+    120, 120, 120, 120, 492, 120, 493, 494, 495, 496, 497, 498, 54, 54, 54, 
+    54, 499, 500, 56, 56, 56, 56, 56, 501, 502, 503, 54, 504, 54, 54, 54, 
+    505, 56, 56, 56, 506, 507, 508, 509, 510, 510, 510, 511, 512, 27, 27, 27, 
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 513, 514, 27, 
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 515, 516, 517, 518, 515, 516, 
+    515, 516, 517, 518, 515, 519, 515, 516, 515, 517, 515, 520, 515, 520, 
+    515, 520, 521, 522, 523, 524, 525, 526, 515, 527, 528, 529, 530, 531, 
+    532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 
+    546, 547, 56, 548, 549, 550, 551, 552, 553, 553, 554, 555, 556, 557, 558, 
+    120, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 
+    572, 571, 573, 574, 575, 576, 577, 578, 579, 580, 581, 580, 582, 583, 
+    580, 584, 580, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 586, 
+    595, 596, 586, 597, 598, 586, 586, 598, 586, 599, 600, 599, 586, 586, 
+    601, 586, 586, 586, 586, 586, 602, 586, 586, 580, 603, 604, 605, 606, 
+    607, 608, 609, 609, 609, 609, 609, 609, 609, 609, 610, 580, 580, 611, 
+    612, 586, 586, 613, 580, 580, 580, 580, 585, 606, 614, 615, 580, 580, 
+    580, 580, 580, 616, 120, 120, 120, 580, 617, 120, 120, 618, 618, 618, 
+    618, 618, 619, 619, 620, 621, 621, 621, 621, 621, 621, 621, 621, 621, 
+    622, 618, 623, 624, 624, 624, 624, 624, 624, 624, 624, 624, 625, 624, 
+    624, 624, 624, 626, 580, 624, 624, 627, 580, 628, 629, 630, 631, 632, 
+    633, 629, 580, 627, 634, 580, 635, 636, 637, 638, 639, 580, 580, 580, 
+    640, 641, 642, 643, 580, 644, 645, 580, 646, 580, 580, 647, 648, 649, 
+    650, 580, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 580, 
+    580, 580, 662, 580, 663, 580, 664, 665, 666, 667, 668, 669, 618, 670, 
+    670, 671, 580, 580, 580, 662, 672, 673, 586, 586, 586, 674, 675, 586, 
+    586, 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, 
+    676, 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, 
+    676, 676, 676, 676, 676, 586, 586, 586, 586, 586, 586, 586, 586, 586, 
+    586, 586, 586, 586, 586, 586, 586, 677, 678, 678, 679, 586, 586, 586, 
+    586, 586, 586, 586, 680, 586, 586, 586, 681, 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, 580, 
+    580, 580, 682, 580, 580, 586, 586, 683, 684, 685, 629, 580, 580, 686, 
+    580, 580, 580, 687, 580, 580, 580, 580, 688, 580, 689, 617, 120, 120, 
+    690, 120, 120, 691, 691, 691, 691, 691, 692, 693, 693, 693, 693, 693, 
+    694, 695, 696, 697, 698, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 
+    699, 700, 701, 702, 703, 703, 703, 703, 704, 705, 706, 706, 706, 706, 
+    706, 706, 706, 707, 708, 709, 371, 371, 373, 120, 373, 373, 373, 373, 
+    373, 373, 373, 373, 710, 710, 710, 710, 711, 712, 713, 714, 715, 716, 
+    717, 718, 719, 720, 120, 120, 120, 120, 120, 120, 721, 721, 721, 722, 
+    721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 723, 120, 721, 721, 
+    721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 
+    721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 724, 120, 120, 120, 
+    725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 737, 
+    738, 737, 737, 737, 739, 740, 741, 742, 743, 744, 745, 745, 746, 745, 
+    745, 745, 747, 748, 749, 750, 751, 752, 752, 752, 752, 753, 754, 755, 
+    755, 755, 755, 755, 755, 755, 755, 755, 755, 756, 757, 758, 752, 752, 
+    752, 759, 725, 725, 725, 725, 726, 120, 760, 760, 761, 761, 761, 762, 
+    763, 764, 758, 758, 758, 765, 766, 767, 761, 761, 761, 768, 763, 764, 
+    758, 758, 758, 758, 769, 767, 758, 770, 771, 771, 771, 771, 771, 772, 
+    771, 771, 771, 771, 771, 771, 771, 771, 771, 771, 771, 758, 758, 758, 
+    773, 774, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 775, 
+    758, 758, 758, 773, 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, 777, 778, 580, 580, 580, 580, 580, 580, 580, 580, 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, 779, 
+    778, 778, 780, 780, 781, 780, 780, 780, 780, 780, 780, 780, 780, 780, 
+    780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 
+    780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 
+    780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 
+    780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 
+    780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 782, 
+    783, 783, 783, 783, 783, 783, 784, 120, 785, 785, 785, 785, 785, 786, 
+    787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 
+    787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 
+    787, 787, 787, 787, 787, 788, 787, 787, 789, 790, 120, 120, 101, 101, 
+    101, 101, 101, 791, 792, 793, 101, 101, 101, 794, 795, 795, 795, 795, 
+    795, 795, 795, 795, 796, 797, 798, 120, 64, 64, 799, 800, 801, 27, 802, 
+    27, 27, 27, 27, 27, 27, 27, 803, 804, 27, 805, 806, 27, 27, 807, 808, 
+    120, 120, 120, 120, 120, 120, 120, 809, 810, 811, 812, 813, 813, 814, 
+    815, 816, 817, 818, 818, 818, 818, 818, 818, 819, 120, 820, 821, 821, 
+    821, 821, 821, 822, 823, 824, 825, 826, 827, 828, 828, 829, 830, 831, 
+    832, 833, 833, 834, 835, 836, 836, 837, 838, 839, 840, 368, 368, 368, 
+    841, 842, 843, 843, 843, 843, 843, 844, 845, 846, 847, 848, 849, 850, 
+    349, 353, 851, 852, 852, 852, 852, 852, 853, 854, 120, 855, 856, 857, 
+    858, 349, 349, 859, 860, 861, 861, 861, 861, 861, 861, 862, 863, 864, 
+    120, 120, 865, 866, 867, 868, 120, 869, 869, 869, 120, 373, 373, 54, 54, 
+    54, 54, 54, 870, 871, 120, 872, 872, 872, 872, 872, 872, 872, 872, 872, 
+    872, 866, 866, 866, 866, 873, 874, 875, 876, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 
+    878, 878, 877, 878, 878, 879, 878, 878, 878, 878, 878, 878, 877, 878, 
+    878, 879, 878, 878, 878, 877, 878, 878, 879, 878, 878, 878, 877, 878, 
+    878, 880, 120, 369, 369, 881, 882, 370, 370, 370, 370, 370, 883, 884, 
+    884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 
+    884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 884, 
+    884, 884, 884, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 
+    885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 
+    885, 885, 885, 885, 885, 885, 885, 776, 776, 776, 776, 776, 776, 776, 
+    776, 776, 776, 776, 776, 776, 777, 776, 776, 776, 776, 776, 776, 776, 
+    776, 776, 776, 776, 776, 776, 886, 778, 778, 778, 778, 887, 120, 888, 
+    889, 121, 890, 891, 892, 893, 121, 128, 128, 128, 128, 128, 128, 128, 
+    128, 128, 128, 128, 128, 894, 895, 896, 120, 897, 128, 128, 128, 128, 
     128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
     128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
-    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 929, 120, 
-    120, 128, 128, 128, 128, 128, 128, 128, 128, 930, 128, 128, 128, 128, 
-    128, 128, 120, 120, 120, 120, 120, 128, 931, 932, 932, 933, 934, 935, 
-    936, 937, 938, 939, 940, 941, 942, 943, 944, 169, 128, 128, 128, 128, 
-    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 945, 946, 
-    947, 948, 949, 950, 951, 951, 952, 953, 954, 954, 955, 956, 957, 958, 
-    959, 959, 959, 959, 960, 961, 961, 961, 962, 963, 963, 963, 964, 965, 
-    966, 120, 967, 968, 969, 968, 968, 970, 968, 968, 971, 968, 972, 968, 
-    972, 120, 120, 120, 120, 968, 968, 968, 968, 968, 968, 968, 968, 968, 
-    968, 968, 968, 968, 968, 968, 973, 974, 975, 975, 975, 975, 975, 976, 
-    615, 977, 977, 977, 977, 977, 977, 978, 979, 980, 981, 579, 982, 983, 
-    120, 120, 120, 120, 120, 615, 615, 615, 615, 615, 984, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 985, 
-    985, 985, 986, 987, 987, 987, 987, 987, 987, 988, 120, 989, 990, 990, 
-    991, 992, 992, 992, 992, 993, 120, 994, 994, 995, 996, 997, 997, 997, 
-    997, 998, 999, 1000, 1000, 1000, 1001, 1002, 1002, 1002, 1002, 1003, 
-    1002, 1004, 120, 120, 120, 120, 120, 1005, 1005, 1005, 1005, 1005, 1006, 
-    1006, 1006, 1006, 1006, 1007, 1007, 1007, 1007, 1007, 1007, 1008, 1008, 
-    1008, 1009, 1010, 1011, 1012, 1012, 1012, 1012, 1013, 1014, 1014, 1014, 
-    1014, 1015, 1016, 1016, 1016, 1016, 1016, 120, 1017, 1017, 1017, 1017, 
-    1017, 1017, 1018, 1019, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 1020, 1020, 1020, 1020, 1020, 
-    1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 
-    1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 
-    1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1021, 120, 1020, 
-    1020, 1022, 120, 1020, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 1023, 1024, 1025, 1025, 
-    1025, 1025, 1026, 1027, 1028, 1028, 1029, 1030, 1031, 1031, 1032, 1033, 
-    1034, 1034, 1034, 1035, 1036, 1037, 120, 120, 120, 120, 120, 120, 1038, 
-    1038, 1039, 1040, 1041, 1041, 1042, 1043, 1044, 1044, 1044, 1045, 120, 
-    120, 120, 120, 120, 120, 120, 120, 1046, 1046, 1046, 1046, 1047, 1047, 
-    1047, 1048, 1049, 1049, 1050, 1049, 1049, 1049, 1049, 1049, 1051, 1052, 
-    1053, 1054, 1055, 1055, 1056, 1057, 1058, 120, 1059, 1060, 1061, 1061, 
-    1061, 1062, 1063, 1063, 1063, 1064, 120, 120, 120, 120, 1065, 1066, 1065, 
-    1065, 1067, 1068, 1069, 120, 1070, 1070, 1070, 1070, 1070, 1070, 1071, 
-    1072, 1073, 1073, 1074, 1075, 1076, 1076, 1077, 1078, 1079, 1079, 1080, 
-    1081, 120, 1082, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1083, 
-    1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1084, 120, 120, 120, 120, 
-    120, 120, 1085, 1085, 1085, 1085, 1085, 1085, 1086, 120, 1087, 1087, 
-    1087, 1087, 1087, 1087, 1088, 1089, 120, 120, 120, 120, 120, 120, 120, 
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 898, 120, 
+    120, 128, 128, 128, 128, 128, 128, 128, 128, 899, 128, 128, 128, 128, 
+    128, 128, 120, 120, 120, 120, 120, 128, 900, 901, 901, 902, 903, 904, 
+    905, 906, 907, 908, 909, 910, 911, 912, 913, 170, 128, 128, 128, 128, 
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 914, 915, 
+    916, 917, 918, 919, 920, 920, 921, 922, 923, 923, 924, 925, 926, 927, 
+    928, 928, 928, 928, 929, 930, 930, 930, 931, 932, 932, 932, 933, 934, 
+    935, 120, 936, 937, 938, 937, 937, 939, 937, 937, 940, 937, 941, 937, 
+    941, 120, 120, 120, 120, 937, 937, 937, 937, 937, 937, 937, 937, 937, 
+    937, 937, 937, 937, 937, 937, 942, 943, 944, 944, 944, 944, 944, 945, 
+    609, 946, 946, 946, 946, 946, 946, 947, 948, 949, 950, 580, 951, 952, 
+    120, 120, 120, 120, 120, 609, 609, 609, 609, 609, 953, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 954, 
+    954, 954, 955, 956, 956, 956, 956, 956, 956, 957, 120, 958, 959, 959, 
+    960, 961, 961, 961, 961, 962, 963, 964, 964, 965, 966, 967, 967, 967, 
+    967, 968, 969, 970, 970, 970, 971, 972, 972, 972, 972, 973, 972, 974, 
+    120, 120, 120, 120, 120, 975, 975, 975, 975, 975, 976, 976, 976, 976, 
+    976, 977, 977, 977, 977, 977, 977, 978, 978, 978, 979, 980, 981, 982, 
+    982, 982, 982, 983, 984, 984, 984, 984, 985, 986, 986, 986, 986, 986, 
+    120, 987, 987, 987, 987, 987, 987, 988, 989, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 990, 
+    990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 
+    990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 
+    990, 990, 990, 990, 990, 990, 990, 990, 990, 991, 120, 990, 990, 992, 
+    120, 990, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 993, 994, 995, 995, 995, 995, 996, 
+    997, 998, 998, 999, 1000, 1001, 1001, 1002, 1003, 1004, 1004, 1004, 1005, 
+    1006, 1007, 120, 120, 120, 120, 120, 120, 1008, 1008, 1009, 1010, 1011, 
+    1011, 1012, 1013, 1014, 1014, 1014, 1015, 120, 120, 120, 120, 120, 120, 
+    120, 120, 1016, 1016, 1016, 1016, 1017, 1017, 1017, 1018, 1019, 1019, 
+    1020, 1019, 1019, 1019, 1019, 1019, 1021, 1022, 1023, 1024, 1025, 1025, 
+    1026, 1027, 1028, 120, 1029, 1030, 1031, 1031, 1031, 1032, 1033, 1033, 
+    1033, 1034, 120, 120, 120, 120, 1035, 1036, 1035, 1035, 1037, 1038, 1039, 
+    120, 1040, 1040, 1040, 1040, 1040, 1040, 1041, 1042, 1043, 1043, 1044, 
+    1045, 1046, 1046, 1047, 1048, 1049, 1049, 1050, 1051, 120, 1052, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 1053, 1053, 1053, 1053, 
+    1053, 1053, 1053, 1053, 1053, 1054, 120, 120, 120, 120, 120, 120, 1055, 
+    1055, 1055, 1055, 1055, 1055, 1056, 120, 1057, 1057, 1057, 1057, 1057, 
+    1057, 1058, 1059, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 1090, 1090, 1090, 1091, 120, 
+    120, 120, 120, 120, 120, 1060, 1060, 1060, 1061, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1062, 1063, 1063, 
+    1063, 1063, 1063, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 120, 
+    1071, 1072, 1073, 1073, 1073, 1073, 1073, 1074, 1075, 1076, 120, 1077, 
+    1077, 1077, 1078, 1079, 1080, 1081, 1082, 1082, 1082, 1083, 1084, 1085, 
+    1086, 1087, 120, 1088, 1088, 1088, 1088, 1089, 120, 1090, 1091, 1091, 
+    1091, 1091, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 
+    120, 1101, 1101, 1102, 1101, 1101, 1103, 1104, 1105, 120, 120, 120, 120, 
+    120, 120, 120, 120, 1106, 1107, 1108, 1109, 1108, 1110, 1111, 1111, 1111, 
+    1111, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1120, 
+    1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1129, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 1092, 1093, 1093, 1093, 1093, 1093, 1093, 1094, 1095, 1096, 1097, 
-    1098, 1099, 1100, 120, 1101, 1102, 1103, 1103, 1103, 1103, 1103, 1104, 
-    1105, 1106, 120, 1107, 1107, 1107, 1108, 1109, 1110, 1111, 1112, 1112, 
-    1112, 1113, 1114, 1115, 1116, 1117, 120, 1118, 1118, 1118, 1118, 1119, 
-    120, 1120, 1121, 1121, 1121, 1121, 1121, 1122, 1123, 1124, 1125, 1126, 
-    1127, 1128, 1129, 1130, 120, 1131, 1131, 1132, 1131, 1131, 1133, 1134, 
-    1135, 120, 120, 120, 120, 120, 120, 120, 120, 1136, 1137, 1138, 1139, 
-    1138, 1140, 1141, 1141, 1141, 1141, 1141, 1142, 1143, 1144, 1145, 1146, 
-    1147, 1148, 1149, 1150, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 
-    1158, 1159, 1159, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 1160, 1160, 1160, 1160, 1160, 1160, 1161, 
-    1162, 1163, 1164, 1165, 1166, 120, 120, 120, 120, 1167, 1167, 1167, 1167, 
-    1167, 1167, 1168, 1169, 1170, 120, 1171, 1172, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 1173, 1173, 1173, 1173, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 
-    1180, 120, 120, 120, 120, 1181, 1181, 1181, 1181, 1181, 1181, 1182, 1183, 
-    1184, 120, 1185, 1186, 1187, 1188, 120, 120, 1189, 1189, 1189, 1189, 
-    1189, 1190, 1191, 120, 1192, 1193, 120, 120, 120, 120, 120, 120, 1194, 
-    1194, 1194, 1195, 1196, 1197, 1198, 1199, 120, 120, 120, 120, 120, 120, 
+    120, 1130, 1130, 1130, 1130, 1130, 1130, 1131, 1132, 1133, 1134, 1135, 
+    1136, 120, 120, 120, 120, 1137, 1137, 1137, 1137, 1137, 1137, 1138, 1139, 
+    1140, 120, 1141, 1142, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1143, 1143, 1143, 1143, 
+    1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 120, 120, 120, 120, 1151, 
+    1151, 1151, 1151, 1151, 1151, 1152, 1153, 1154, 120, 1155, 1156, 1157, 
+    1158, 120, 120, 1159, 1159, 1159, 1159, 1159, 1160, 1161, 120, 1162, 
+    1163, 120, 120, 120, 120, 120, 120, 1164, 1164, 1164, 1165, 1166, 1167, 
+    1168, 1169, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1200, 1200, 1200, 1200, 
-    1201, 1201, 1201, 1201, 1202, 1203, 1204, 1205, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 1170, 1170, 1170, 1170, 1171, 1171, 1171, 1171, 1172, 
+    1173, 1174, 1175, 1176, 1177, 1178, 1178, 1178, 1178, 1179, 1180, 1181, 
+    120, 1182, 1183, 1184, 1184, 1184, 1184, 1185, 1186, 1187, 1188, 1189, 
+    120, 120, 120, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1191, 1192, 
+    1193, 1192, 1192, 1192, 1194, 1195, 1196, 1197, 120, 1198, 1199, 1200, 
+    1201, 1202, 1203, 1203, 1203, 1204, 1205, 1205, 1206, 1207, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 1208, 1209, 1210, 1210, 1210, 1210, 
+    1211, 1212, 1213, 120, 1214, 1215, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1216, 
+    1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 
+    1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 
+    1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 
+    1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 
+    1216, 1216, 1217, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 
+    1218, 1218, 1219, 1220, 120, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 
+    1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 
+    1216, 1216, 1216, 1216, 1216, 1221, 120, 120, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1207, 
-    1208, 1209, 1208, 1208, 1208, 1210, 1211, 1212, 1213, 120, 1214, 1215, 
-    1216, 1217, 1218, 1219, 1219, 1219, 1220, 1221, 1221, 1222, 1223, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 1224, 1224, 1224, 1224, 1224, 
-    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 
-    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 
-    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 
-    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1225, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1226, 1226, 1226, 
-    1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1227, 1228, 
-    120, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 
-    1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 
-    1224, 1229, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1230, 1230, 1230, 
-    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 
-    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 
-    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 
-    1230, 1230, 1230, 1230, 1231, 1230, 1230, 1230, 1230, 1232, 1233, 1230, 
-    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 
-    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 
-    1230, 1230, 1230, 1230, 1234, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 
-    1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 
-    1230, 1230, 1235, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 
+    1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 
+    1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 
+    1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1223, 1222, 1222, 
+    1222, 1222, 1224, 1225, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 
+    1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 
+    1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1226, 1222, 1222, 
+    1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 
+    1222, 1222, 1222, 1222, 1222, 1222, 1222, 1227, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 
-    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 
-    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 
-    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 
-    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1237, 1236, 
-    1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 
-    1236, 1238, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 826, 826, 826, 
-    826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 
-    826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 826, 
-    826, 826, 826, 826, 826, 826, 826, 826, 1239, 1240, 1240, 1240, 1241, 
-    1242, 1243, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    1244, 1244, 1244, 1245, 1246, 120, 1247, 1247, 1247, 1247, 1247, 1247, 
-    1248, 1249, 1250, 120, 1251, 1252, 1253, 1247, 1247, 1254, 1247, 1247, 
+    120, 120, 120, 120, 120, 120, 120, 1228, 1228, 1228, 1228, 1228, 1228, 
+    1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 
+    1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 
+    1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 
+    1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 
+    1228, 1228, 1228, 1229, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 
+    1228, 1228, 1228, 1228, 1228, 1228, 1230, 120, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1256, 120, 1257, 1258, 
-    1258, 1258, 1258, 1259, 120, 1260, 1261, 1262, 120, 120, 120, 120, 120, 
-    120, 120, 120, 1263, 120, 120, 120, 1264, 1264, 1264, 1264, 1264, 1264, 
-    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 
-    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 
-    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 
-    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 
-    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1265, 120, 120, 1264, 1264, 
-    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 
-    1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 
-    1264, 1264, 1264, 1264, 1266, 120, 1267, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 
+    795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 
+    795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 
+    1231, 1232, 1232, 1232, 1233, 1234, 1235, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 1236, 1236, 1236, 1237, 1238, 120, 1239, 
+    1239, 1239, 1239, 1239, 1239, 1240, 1241, 1242, 120, 1243, 1244, 1245, 
+    1239, 1239, 1246, 1239, 1239, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 
+    1247, 1248, 120, 1249, 1250, 1250, 1250, 1250, 1251, 120, 1252, 1253, 
+    1254, 120, 120, 120, 120, 120, 120, 120, 120, 1255, 120, 120, 120, 1256, 
+    1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 
+    1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 
+    1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 
+    1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 
+    1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 
+    1257, 120, 120, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 
+    1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 
+    1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1258, 120, 1259, 
+    737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 
+    737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 737, 
+    737, 737, 737, 737, 737, 737, 1260, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 
+    1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 
+    1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 
+    1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 
+    1261, 1261, 1261, 1261, 1262, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 
+    1263, 1263, 1263, 1263, 1263, 1263, 1264, 1263, 1265, 1263, 1266, 1263, 
+    1267, 1268, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 609, 
+    609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 
+    609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 
+    609, 1269, 120, 609, 609, 609, 609, 1270, 1271, 609, 609, 609, 609, 609, 
+    609, 1272, 1273, 1274, 1275, 1276, 1277, 609, 609, 609, 1278, 609, 609, 
+    609, 609, 609, 609, 609, 1279, 120, 120, 949, 949, 949, 949, 949, 949, 
+    949, 949, 1280, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 580, 580, 
+    580, 580, 580, 580, 580, 580, 580, 580, 616, 120, 944, 944, 1281, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1268, 1268, 1268, 
-    1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1269, 1268, 
-    1270, 1268, 1271, 1268, 1272, 1273, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 
-    615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 
-    615, 615, 615, 615, 615, 615, 1274, 120, 615, 615, 615, 615, 1275, 1276, 
-    615, 615, 615, 615, 615, 615, 1277, 1278, 1279, 1280, 1281, 1282, 615, 
-    615, 615, 1283, 615, 615, 615, 615, 615, 615, 615, 1284, 120, 120, 980, 
-    980, 980, 980, 980, 980, 980, 980, 1285, 120, 120, 120, 120, 120, 120, 
+    120, 120, 1282, 1282, 1282, 1283, 1284, 1284, 1285, 1282, 1282, 1286, 
+    1287, 1284, 1284, 1282, 1282, 1282, 1283, 1284, 1284, 1288, 1289, 1290, 
+    1286, 1291, 1292, 1284, 1282, 1282, 1282, 1283, 1284, 1284, 1293, 1294, 
+    1295, 1296, 1284, 1284, 1284, 1297, 1298, 1299, 1300, 1284, 1284, 1285, 
+    1282, 1282, 1286, 1284, 1284, 1284, 1282, 1282, 1282, 1283, 1284, 1284, 
+    1285, 1282, 1282, 1286, 1284, 1284, 1284, 1282, 1282, 1282, 1283, 1284, 
+    1284, 1285, 1282, 1282, 1286, 1284, 1284, 1284, 1282, 1282, 1282, 1283, 
+    1284, 1284, 1301, 1282, 1282, 1282, 1302, 1284, 1284, 1303, 1304, 1282, 
+    1282, 1305, 1284, 1284, 1306, 1285, 1282, 1282, 1307, 1284, 1284, 1308, 
+    1309, 1282, 1282, 1310, 1284, 1284, 1284, 1311, 1282, 1282, 1282, 1302, 
+    1284, 1284, 1303, 1312, 1313, 1313, 1313, 1313, 1313, 1313, 1314, 1314, 
+    1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 
+    1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 
+    1314, 1314, 1314, 1314, 1314, 1314, 1315, 1315, 1315, 1315, 1315, 1315, 
+    1316, 1317, 1315, 1315, 1315, 1315, 1315, 1318, 1319, 1314, 1320, 1321, 
+    120, 1322, 1323, 1315, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    1324, 1325, 1325, 1326, 1327, 1328, 120, 120, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 623, 
-    120, 975, 975, 1286, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 1287, 1287, 1287, 1288, 1289, 1289, 
-    1290, 1287, 1287, 1291, 1292, 1289, 1289, 1287, 1287, 1287, 1288, 1289, 
-    1289, 1293, 1294, 1295, 1291, 1296, 1297, 1289, 1287, 1287, 1287, 1288, 
-    1289, 1289, 1298, 1299, 1300, 1301, 1289, 1289, 1289, 1302, 1303, 1304, 
-    1305, 1289, 1289, 1290, 1287, 1287, 1291, 1289, 1289, 1289, 1287, 1287, 
-    1287, 1288, 1289, 1289, 1290, 1287, 1287, 1291, 1289, 1289, 1289, 1287, 
-    1287, 1287, 1288, 1289, 1289, 1290, 1287, 1287, 1291, 1289, 1289, 1289, 
-    1287, 1287, 1287, 1288, 1289, 1289, 1306, 1287, 1287, 1287, 1307, 1289, 
-    1289, 1308, 1309, 1287, 1287, 1310, 1289, 1289, 1311, 1290, 1287, 1287, 
-    1312, 1289, 1289, 1313, 1314, 1287, 1287, 1315, 1289, 1289, 1289, 1316, 
-    1287, 1287, 1287, 1307, 1289, 1289, 1308, 1317, 1318, 1318, 1318, 1318, 
-    1318, 1318, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 
-    1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 
-    1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1320, 1320, 
-    1320, 1320, 1320, 1320, 1321, 1322, 1320, 1320, 1320, 1320, 1320, 1323, 
-    1324, 1319, 1325, 1326, 120, 1327, 1328, 1320, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 1329, 1330, 1330, 1331, 1332, 1333, 120, 120, 
+    120, 120, 120, 120, 120, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 
+    1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 
+    1329, 1329, 1329, 1329, 1330, 1331, 1332, 120, 120, 120, 120, 120, 1333, 
+    1333, 1333, 1333, 1334, 1335, 1335, 1335, 1336, 1337, 1338, 1339, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1334, 1334, 1334, 1334, 
-    1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 
-    1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1335, 1336, 1337, 120, 
-    120, 120, 120, 120, 1338, 1338, 1338, 1338, 1339, 1340, 1340, 1340, 1341, 
-    1342, 1343, 1344, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 1345, 128, 128, 128, 1346, 
-    1347, 1348, 1349, 1350, 1351, 1346, 1352, 1346, 1348, 1348, 1353, 128, 
-    1354, 128, 1355, 1356, 1354, 128, 1355, 120, 120, 120, 120, 120, 120, 
-    1357, 120, 1358, 1359, 1359, 1359, 1359, 1360, 1359, 1359, 1359, 1359, 
-    1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1360, 1361, 1359, 1362, 
-    1363, 1359, 1363, 1364, 1363, 1359, 1359, 1359, 1365, 1361, 626, 1366, 
-    628, 628, 628, 1367, 628, 628, 628, 628, 628, 628, 628, 1368, 628, 628, 
-    628, 1369, 1370, 1371, 628, 1372, 1361, 1361, 1361, 1361, 1361, 1361, 
-    1373, 1374, 1374, 1374, 1375, 1361, 790, 790, 790, 790, 790, 1376, 790, 
-    1377, 1378, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 757, 
-    757, 757, 757, 1379, 1380, 1381, 757, 757, 757, 757, 757, 757, 757, 757, 
-    1382, 1383, 757, 1384, 1385, 757, 757, 1386, 1387, 1388, 1389, 1384, 
-    1359, 757, 757, 1390, 1391, 757, 757, 757, 757, 757, 757, 757, 1392, 
-    1393, 1394, 1395, 757, 1396, 1397, 1394, 1398, 1399, 757, 757, 757, 1400, 
-    1401, 1402, 757, 757, 757, 757, 757, 757, 757, 757, 1403, 1404, 757, 
-    1405, 649, 1406, 757, 1407, 1408, 579, 1409, 757, 757, 757, 1359, 1410, 
-    1411, 1359, 1359, 1412, 1359, 1358, 1359, 1359, 1359, 1359, 1359, 1413, 
-    1414, 1359, 1359, 1413, 1415, 757, 757, 757, 757, 757, 757, 757, 757, 
-    1416, 1417, 579, 579, 579, 579, 1418, 1419, 757, 757, 757, 757, 1420, 
-    757, 1421, 757, 1422, 1358, 1423, 1361, 1359, 1424, 1425, 1361, 579, 579, 
-    579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 1426, 1361, 
-    579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 1427, 1361, 1361, 1361, 
-    1361, 1361, 579, 1426, 579, 579, 579, 579, 579, 579, 579, 1361, 579, 
-    1428, 579, 579, 579, 579, 579, 1361, 579, 579, 579, 1429, 1361, 1361, 
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 757, 1430, 
-    1431, 1361, 1432, 1433, 757, 1434, 757, 1435, 1361, 1361, 1361, 1361, 
-    757, 757, 1436, 1361, 1361, 1361, 1361, 1361, 1437, 1361, 1361, 1361, 
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1438, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 1439, 810, 810, 810, 810, 810, 808, 
-    808, 808, 808, 808, 808, 1440, 810, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 809, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 
-    808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, 917, 
-    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 
-    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 
-    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 
-    810, 808, 808, 808, 809, 810, 810, 810, 810, 810, 810, 810, 810, 810, 
-    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 
-    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 
-    810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 810, 
-    810, 810, 810, 810, 810, 810, 810, 810, 1441, 1442, 120, 120, 120, 1443, 
-    1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 
-    932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 
-    932, 932, 932, 120, 120, 916, 916, 916, 916, 916, 916, 916, 916, 916, 
-    916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 
-    916, 916, 916, 916, 916, 916, 916, 916, 1444, 
+    120, 120, 120, 120, 120, 1340, 128, 128, 128, 1341, 1342, 1343, 1344, 
+    1345, 1346, 1341, 1347, 1341, 1343, 1343, 1348, 128, 1349, 128, 1350, 
+    1351, 1349, 128, 1350, 120, 120, 120, 120, 120, 120, 1352, 120, 1353, 
+    1354, 1354, 1354, 1354, 1355, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 
+    1354, 1354, 1354, 1354, 1354, 1355, 1356, 1354, 1357, 1358, 1354, 1358, 
+    1359, 1358, 1354, 1354, 1354, 1360, 1356, 619, 1361, 621, 621, 621, 1362, 
+    621, 621, 621, 621, 621, 621, 621, 1363, 621, 621, 621, 1364, 1365, 1366, 
+    621, 1367, 1356, 1356, 1356, 1356, 1356, 1356, 1368, 1369, 1369, 1369, 
+    1370, 1356, 758, 758, 758, 758, 758, 1371, 758, 1372, 1373, 1356, 1374, 
+    1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 
+    1356, 1356, 1356, 1356, 1356, 1356, 1356, 725, 725, 725, 725, 1375, 1376, 
+    1377, 725, 725, 725, 725, 725, 725, 725, 725, 1378, 1379, 725, 1380, 
+    1381, 725, 725, 1382, 1383, 1384, 1385, 1380, 1354, 725, 725, 1386, 1387, 
+    725, 725, 725, 725, 725, 725, 725, 1388, 1389, 1390, 1391, 725, 1392, 
+    1393, 1390, 1394, 1395, 725, 725, 725, 1396, 1397, 1398, 725, 725, 725, 
+    725, 725, 725, 725, 725, 1399, 1400, 725, 1401, 642, 1402, 725, 1403, 
+    1404, 580, 1405, 725, 725, 725, 1354, 1406, 1407, 1354, 1354, 1408, 1354, 
+    1353, 1354, 1354, 1354, 1354, 1354, 1409, 1410, 1354, 1354, 1409, 1411, 
+    725, 725, 725, 725, 725, 725, 725, 725, 1412, 1413, 580, 580, 580, 580, 
+    1414, 1415, 725, 725, 725, 725, 1416, 725, 1417, 725, 1418, 1419, 1420, 
+    1356, 1354, 1421, 1422, 1423, 580, 580, 580, 580, 580, 580, 580, 580, 
+    580, 580, 580, 580, 580, 580, 1424, 1356, 580, 580, 580, 580, 580, 580, 
+    580, 580, 580, 580, 1425, 1356, 1356, 1356, 1356, 1356, 580, 1424, 580, 
+    580, 580, 580, 580, 580, 580, 1356, 580, 1426, 580, 580, 580, 580, 580, 
+    1356, 580, 580, 580, 1427, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 
+    1356, 1356, 1356, 580, 1424, 725, 1428, 1429, 725, 1390, 1430, 725, 1431, 
+    725, 725, 725, 1432, 1356, 1356, 725, 725, 725, 1356, 1356, 1356, 1356, 
+    1356, 1423, 1356, 1433, 1434, 1435, 1356, 1356, 1356, 1356, 1356, 1356, 
+    1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 
+    1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 
+    1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 
+    1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 
+    1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 
+    1436, 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, 1437, 
+    778, 778, 778, 778, 778, 776, 776, 776, 776, 776, 776, 1438, 778, 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, 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, 886, 778, 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, 1439, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 
+    778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 
+    778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 776, 776, 776, 
+    777, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 
+    778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 
+    778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 
+    778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 
+    778, 778, 778, 778, 1440, 1441, 120, 120, 120, 1442, 1442, 1442, 1442, 
+    1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 901, 901, 901, 
+    901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 
+    901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 120, 
+    120, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 
+    885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 
+    885, 885, 885, 885, 1443, 
 };
 
 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, 25, 24, 10, 15, 26, 26, 26, 
-    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 16, 27, 17, 
-    28, 29, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 
-    30, 30, 30, 16, 31, 32, 25, 1, 1, 1, 1, 1, 1, 33, 1, 1, 34, 35, 36, 13, 
-    37, 13, 38, 39, 40, 41, 42, 43, 25, 44, 45, 28, 46, 47, 48, 48, 49, 50, 
-    39, 39, 40, 48, 42, 51, 52, 52, 52, 35, 53, 53, 53, 53, 53, 53, 54, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 54, 53, 53, 53, 53, 53, 53, 55, 54, 53, 
-    53, 53, 53, 53, 54, 56, 56, 56, 57, 57, 57, 57, 56, 57, 56, 56, 56, 57, 
-    56, 56, 57, 57, 56, 57, 56, 56, 57, 57, 57, 55, 56, 56, 56, 57, 56, 57, 
-    56, 57, 53, 56, 53, 57, 53, 57, 53, 57, 53, 57, 53, 57, 53, 57, 53, 57, 
-    53, 56, 53, 56, 53, 57, 53, 57, 53, 57, 53, 56, 53, 57, 53, 57, 53, 57, 
-    53, 57, 53, 57, 54, 56, 53, 56, 54, 56, 53, 57, 53, 57, 56, 53, 57, 53, 
-    57, 53, 57, 54, 56, 54, 56, 53, 56, 53, 57, 53, 56, 56, 54, 56, 53, 56, 
-    53, 57, 53, 57, 54, 56, 53, 57, 53, 57, 53, 53, 57, 53, 57, 53, 57, 57, 
-    57, 53, 53, 57, 53, 57, 53, 53, 57, 53, 53, 53, 57, 57, 53, 53, 53, 53, 
-    57, 53, 53, 57, 53, 53, 53, 57, 57, 57, 53, 53, 57, 53, 53, 57, 53, 57, 
-    53, 57, 53, 53, 57, 53, 57, 57, 53, 57, 53, 53, 57, 53, 53, 53, 57, 53, 
-    57, 53, 53, 57, 57, 58, 53, 57, 57, 57, 58, 58, 58, 58, 53, 59, 57, 53, 
-    59, 57, 53, 59, 57, 53, 56, 53, 56, 53, 56, 53, 56, 53, 56, 53, 56, 53, 
-    56, 53, 56, 57, 53, 57, 57, 53, 59, 57, 53, 57, 53, 53, 53, 57, 53, 57, 
-    57, 57, 57, 57, 57, 57, 53, 53, 57, 53, 53, 57, 57, 53, 57, 53, 53, 53, 
-    53, 57, 57, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 
-    57, 57, 57, 57, 58, 57, 57, 57, 60, 60, 60, 60, 60, 60, 60, 60, 60, 61, 
-    61, 62, 62, 62, 62, 62, 62, 62, 63, 63, 64, 63, 61, 65, 66, 65, 65, 65, 
-    66, 65, 61, 61, 67, 62, 63, 63, 63, 63, 63, 63, 40, 40, 40, 40, 63, 40, 
-    63, 49, 60, 60, 60, 60, 60, 63, 63, 63, 63, 63, 68, 68, 61, 63, 62, 63, 
-    63, 63, 63, 63, 63, 63, 63, 63, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 
-    69, 69, 69, 70, 71, 71, 71, 71, 70, 72, 71, 71, 71, 71, 71, 73, 73, 71, 
-    71, 71, 71, 73, 73, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 74, 74, 
-    74, 74, 74, 71, 71, 71, 71, 69, 69, 69, 69, 69, 69, 69, 69, 75, 69, 71, 
-    71, 71, 69, 69, 69, 71, 71, 76, 69, 69, 69, 71, 71, 71, 71, 69, 70, 71, 
-    71, 69, 77, 78, 78, 77, 78, 78, 77, 69, 69, 69, 69, 69, 79, 80, 79, 80, 
-    61, 81, 79, 80, 82, 82, 83, 80, 80, 80, 84, 79, 82, 82, 82, 82, 81, 63, 
-    79, 85, 79, 79, 79, 82, 79, 82, 79, 79, 80, 86, 86, 86, 86, 86, 86, 86, 
-    86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 82, 86, 86, 86, 86, 86, 86, 86, 
-    79, 79, 80, 80, 80, 80, 80, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 
-    87, 87, 87, 87, 87, 87, 80, 87, 87, 87, 87, 87, 87, 87, 80, 80, 80, 80, 
-    80, 79, 80, 80, 79, 79, 79, 80, 80, 80, 79, 80, 79, 80, 79, 80, 79, 80, 
-    79, 80, 88, 89, 88, 89, 88, 89, 88, 89, 88, 89, 88, 89, 88, 89, 80, 80, 
-    80, 80, 79, 80, 90, 79, 80, 79, 79, 80, 80, 79, 79, 79, 91, 92, 91, 91, 
-    91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 
-    92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 94, 93, 94, 94, 94, 94, 94, 94, 
-    94, 94, 94, 94, 94, 94, 94, 94, 91, 94, 91, 94, 91, 94, 91, 94, 91, 94, 
-    95, 96, 96, 97, 97, 96, 98, 98, 91, 94, 91, 94, 91, 94, 91, 91, 94, 91, 
-    94, 91, 94, 91, 94, 91, 94, 91, 94, 91, 94, 94, 82, 99, 99, 99, 99, 99, 
-    99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 82, 
-    82, 100, 101, 101, 101, 101, 101, 101, 82, 102, 102, 102, 102, 102, 102, 
-    102, 102, 102, 102, 102, 102, 102, 102, 102, 82, 103, 104, 82, 82, 105, 
-    105, 106, 82, 107, 108, 108, 108, 108, 107, 108, 108, 108, 109, 107, 108, 
-    108, 108, 108, 108, 108, 107, 107, 107, 107, 107, 107, 108, 108, 107, 
-    108, 108, 109, 110, 108, 111, 112, 113, 114, 115, 116, 117, 118, 119, 
-    120, 120, 121, 122, 123, 124, 125, 126, 127, 128, 126, 108, 107, 129, 
-    119, 82, 82, 82, 82, 82, 82, 82, 82, 130, 130, 130, 130, 130, 130, 130, 
-    130, 130, 130, 130, 82, 82, 82, 82, 82, 130, 130, 130, 126, 126, 82, 82, 
-    82, 131, 131, 131, 131, 131, 132, 133, 133, 134, 135, 135, 136, 137, 138, 
-    139, 139, 140, 140, 140, 140, 140, 140, 140, 140, 141, 142, 143, 144, 
-    145, 82, 146, 144, 147, 147, 147, 147, 147, 147, 147, 147, 148, 147, 147, 
-    147, 147, 147, 147, 147, 147, 147, 147, 149, 150, 151, 152, 153, 154, 
-    155, 156, 97, 97, 157, 158, 140, 140, 140, 140, 140, 158, 140, 140, 158, 
-    159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 135, 160, 160, 161, 
-    147, 147, 162, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 
-    146, 147, 140, 140, 140, 140, 140, 140, 140, 132, 139, 140, 140, 140, 
-    140, 158, 140, 163, 163, 140, 140, 139, 158, 140, 140, 158, 147, 147, 
-    164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 147, 147, 147, 165, 
-    165, 147, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 
-    166, 166, 82, 167, 168, 169, 168, 168, 168, 168, 168, 168, 168, 168, 168, 
-    168, 168, 168, 168, 168, 170, 171, 170, 170, 171, 170, 170, 171, 171, 
-    171, 170, 171, 171, 170, 171, 170, 170, 170, 171, 170, 171, 170, 171, 
-    170, 171, 170, 170, 82, 82, 168, 168, 168, 172, 172, 172, 172, 172, 172, 
-    172, 172, 172, 172, 172, 172, 172, 172, 173, 173, 173, 173, 173, 173, 
-    173, 173, 173, 173, 173, 172, 82, 82, 82, 82, 82, 82, 174, 174, 174, 174, 
-    174, 174, 174, 174, 174, 174, 175, 175, 175, 175, 175, 175, 175, 175, 
-    175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176, 176, 176, 176, 
-    176, 176, 177, 176, 178, 178, 179, 180, 181, 182, 178, 82, 82, 82, 82, 
-    82, 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, 82, 82, 186, 186, 186, 
-    186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 82, 187, 187, 
-    187, 187, 187, 187, 187, 187, 187, 188, 188, 188, 82, 82, 189, 82, 147, 
-    147, 147, 147, 147, 82, 147, 147, 147, 147, 147, 147, 147, 147, 82, 82, 
-    82, 82, 82, 82, 140, 140, 140, 140, 140, 140, 132, 158, 140, 140, 158, 
-    140, 140, 158, 140, 140, 140, 158, 158, 158, 190, 191, 192, 140, 140, 
-    140, 158, 140, 140, 158, 158, 140, 140, 140, 140, 140, 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, 97, 157, 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, 82, 203, 203, 203, 203, 203, 203, 203, 203, 82, 82, 203, 203, 
-    82, 82, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 
-    203, 82, 203, 203, 203, 203, 203, 203, 203, 82, 203, 82, 82, 82, 203, 
-    203, 203, 203, 82, 82, 206, 203, 205, 205, 205, 204, 204, 204, 204, 82, 
-    82, 205, 205, 82, 82, 205, 205, 207, 203, 82, 82, 82, 82, 82, 82, 82, 82, 
-    205, 82, 82, 82, 82, 203, 203, 82, 203, 203, 203, 204, 204, 82, 82, 208, 
-    208, 208, 208, 208, 208, 208, 208, 208, 208, 203, 203, 209, 209, 210, 
-    210, 210, 210, 210, 211, 212, 213, 82, 82, 82, 82, 82, 214, 214, 215, 82, 
-    216, 216, 216, 216, 216, 216, 82, 82, 82, 82, 216, 216, 82, 82, 216, 216, 
-    216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 82, 216, 216, 
-    216, 216, 216, 216, 216, 82, 216, 216, 82, 216, 216, 82, 216, 216, 82, 
-    82, 217, 82, 215, 215, 215, 214, 214, 82, 82, 82, 82, 214, 214, 82, 82, 
-    214, 214, 218, 82, 82, 82, 214, 82, 82, 82, 82, 82, 82, 82, 216, 216, 
-    216, 216, 82, 216, 82, 82, 82, 82, 82, 82, 82, 219, 219, 219, 219, 219, 
-    219, 219, 219, 219, 219, 214, 214, 216, 216, 216, 214, 82, 82, 82, 220, 
-    220, 221, 82, 222, 222, 222, 222, 222, 222, 222, 222, 222, 82, 222, 222, 
-    222, 82, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 
-    222, 82, 222, 222, 222, 222, 222, 222, 222, 82, 222, 222, 82, 222, 222, 
-    222, 222, 222, 82, 82, 223, 222, 221, 221, 221, 220, 220, 220, 220, 220, 
-    82, 220, 220, 221, 82, 221, 221, 224, 82, 82, 222, 82, 82, 82, 82, 82, 
-    82, 82, 222, 222, 220, 220, 82, 82, 225, 225, 225, 225, 225, 225, 225, 
-    225, 225, 225, 226, 227, 82, 82, 82, 82, 82, 82, 82, 222, 82, 82, 82, 82, 
-    82, 82, 82, 228, 229, 229, 82, 230, 230, 230, 230, 230, 230, 230, 230, 
-    82, 82, 230, 230, 82, 82, 230, 230, 230, 230, 230, 230, 230, 230, 230, 
-    230, 230, 230, 230, 230, 82, 230, 230, 230, 230, 230, 230, 230, 82, 230, 
-    230, 82, 230, 230, 230, 230, 230, 82, 82, 231, 230, 229, 228, 229, 228, 
-    228, 228, 228, 82, 82, 229, 229, 82, 82, 229, 229, 232, 82, 82, 82, 82, 
-    82, 82, 82, 82, 228, 229, 82, 82, 82, 82, 230, 230, 82, 230, 230, 230, 
-    228, 228, 82, 82, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 234, 
-    230, 235, 235, 235, 235, 235, 235, 82, 82, 236, 237, 82, 237, 237, 237, 
-    237, 237, 237, 82, 82, 82, 237, 237, 237, 82, 237, 237, 237, 237, 82, 82, 
-    82, 237, 237, 82, 237, 82, 237, 237, 82, 82, 82, 237, 237, 82, 82, 82, 
-    237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 82, 82, 82, 82, 238, 
-    238, 236, 238, 238, 82, 82, 82, 238, 238, 238, 82, 238, 238, 238, 239, 
-    82, 82, 237, 82, 82, 82, 82, 82, 82, 238, 82, 82, 82, 82, 82, 82, 240, 
-    240, 240, 240, 240, 240, 240, 240, 240, 240, 241, 241, 241, 242, 242, 
-    242, 242, 242, 242, 243, 242, 82, 82, 82, 82, 82, 244, 245, 245, 245, 82, 
-    246, 246, 246, 246, 246, 246, 246, 246, 82, 246, 246, 246, 82, 246, 246, 
-    246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 82, 
-    82, 82, 246, 244, 244, 244, 245, 245, 245, 245, 82, 244, 244, 244, 82, 
-    244, 244, 244, 247, 82, 82, 82, 82, 82, 82, 82, 248, 249, 82, 246, 246, 
-    246, 82, 82, 82, 82, 82, 246, 246, 244, 244, 82, 82, 250, 250, 250, 250, 
-    250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251, 252, 
-    253, 254, 255, 255, 82, 253, 253, 253, 253, 253, 253, 253, 253, 82, 253, 
-    253, 253, 82, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
-    253, 253, 253, 253, 253, 253, 82, 253, 253, 253, 253, 253, 82, 82, 256, 
-    253, 255, 257, 255, 255, 255, 255, 255, 82, 257, 255, 255, 82, 255, 255, 
-    254, 258, 82, 82, 82, 82, 82, 82, 82, 255, 255, 82, 82, 82, 82, 82, 82, 
-    82, 253, 82, 253, 253, 254, 254, 82, 82, 259, 259, 259, 259, 259, 259, 
-    259, 259, 259, 259, 82, 253, 253, 82, 82, 82, 82, 82, 82, 260, 261, 261, 
-    82, 262, 262, 262, 262, 262, 262, 262, 262, 82, 262, 262, 262, 82, 262, 
-    262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 
-    262, 262, 82, 82, 262, 261, 261, 261, 260, 260, 260, 260, 82, 261, 261, 
-    261, 82, 261, 261, 261, 263, 262, 264, 82, 82, 82, 82, 262, 262, 262, 
-    261, 265, 265, 265, 265, 265, 265, 265, 262, 262, 262, 260, 260, 82, 82, 
-    266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 265, 265, 265, 265, 
-    265, 265, 265, 265, 265, 267, 262, 262, 262, 262, 262, 262, 82, 82, 268, 
-    268, 82, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 
-    269, 269, 269, 269, 269, 82, 82, 82, 269, 269, 269, 269, 269, 269, 269, 
-    269, 82, 269, 269, 269, 269, 269, 269, 269, 269, 269, 82, 269, 82, 82, 
-    82, 82, 270, 82, 82, 82, 82, 268, 268, 268, 271, 271, 271, 82, 271, 82, 
-    268, 268, 268, 268, 268, 268, 268, 268, 82, 82, 82, 82, 82, 82, 272, 272, 
-    272, 272, 272, 272, 272, 272, 272, 272, 82, 82, 268, 268, 273, 82, 82, 
-    82, 82, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 
-    274, 274, 274, 275, 274, 274, 275, 275, 275, 275, 276, 276, 277, 82, 82, 
-    82, 82, 278, 274, 274, 274, 274, 274, 274, 279, 275, 280, 280, 280, 280, 
-    275, 275, 275, 281, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 
-    283, 283, 82, 82, 82, 82, 82, 284, 284, 82, 284, 82, 82, 284, 284, 82, 
-    284, 82, 82, 284, 82, 82, 82, 82, 82, 82, 284, 284, 284, 284, 82, 284, 
-    284, 284, 284, 284, 284, 284, 82, 284, 284, 284, 82, 284, 82, 284, 82, 
-    82, 284, 284, 82, 284, 284, 284, 284, 285, 284, 284, 285, 285, 285, 285, 
-    286, 286, 82, 285, 285, 284, 82, 82, 284, 284, 284, 284, 284, 82, 287, 
-    82, 288, 288, 288, 288, 285, 285, 82, 82, 289, 289, 289, 289, 289, 289, 
-    289, 289, 289, 289, 82, 82, 284, 284, 284, 284, 290, 291, 291, 291, 292, 
-    293, 292, 292, 294, 292, 292, 295, 294, 296, 296, 296, 296, 296, 294, 
-    297, 296, 297, 297, 297, 298, 298, 297, 297, 297, 297, 297, 297, 299, 
-    299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 300, 300, 300, 300, 
-    300, 300, 300, 300, 300, 301, 298, 297, 298, 297, 302, 303, 304, 303, 
-    304, 305, 305, 290, 290, 290, 290, 290, 290, 290, 290, 82, 290, 290, 290, 
-    290, 290, 290, 290, 290, 290, 290, 290, 290, 82, 82, 82, 82, 306, 307, 
-    308, 309, 308, 308, 308, 308, 308, 307, 307, 307, 307, 308, 310, 307, 
-    308, 311, 311, 312, 295, 311, 311, 290, 290, 290, 290, 290, 308, 308, 
-    308, 308, 308, 308, 308, 308, 308, 308, 308, 82, 308, 308, 308, 308, 308, 
-    308, 308, 308, 308, 308, 308, 308, 82, 301, 301, 297, 297, 297, 297, 297, 
-    297, 298, 297, 297, 297, 297, 297, 297, 82, 297, 297, 292, 292, 295, 292, 
-    293, 313, 313, 313, 313, 294, 294, 82, 82, 82, 82, 82, 314, 314, 314, 
-    314, 314, 314, 314, 314, 314, 314, 314, 315, 315, 316, 316, 316, 316, 
-    315, 316, 316, 316, 316, 316, 317, 315, 318, 318, 315, 315, 316, 316, 
-    314, 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, 320, 320, 321, 
-    321, 321, 321, 314, 314, 314, 314, 314, 314, 315, 315, 316, 316, 314, 
-    314, 314, 314, 316, 316, 316, 314, 315, 315, 315, 314, 314, 315, 315, 
-    315, 315, 315, 315, 315, 314, 314, 314, 316, 316, 316, 316, 314, 314, 
-    314, 314, 314, 316, 315, 315, 316, 316, 315, 315, 315, 315, 315, 315, 
-    322, 314, 315, 319, 319, 315, 315, 315, 316, 323, 323, 324, 324, 324, 
-    324, 324, 324, 324, 324, 324, 324, 324, 324, 324, 324, 82, 324, 82, 82, 
-    82, 82, 82, 324, 82, 82, 325, 325, 325, 325, 325, 325, 325, 325, 325, 
-    325, 325, 326, 327, 325, 325, 325, 328, 328, 328, 328, 328, 328, 328, 
-    328, 329, 329, 329, 329, 329, 329, 329, 329, 330, 330, 330, 330, 330, 
-    330, 330, 330, 331, 331, 331, 331, 331, 331, 331, 331, 331, 82, 331, 331, 
-    331, 331, 82, 82, 331, 331, 331, 331, 331, 331, 331, 82, 331, 331, 331, 
-    82, 82, 332, 332, 332, 333, 334, 333, 333, 333, 333, 333, 333, 333, 335, 
-    335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 
-    335, 335, 335, 335, 335, 82, 82, 82, 336, 336, 336, 336, 336, 336, 336, 
-    336, 336, 336, 82, 82, 82, 82, 82, 82, 337, 337, 337, 337, 337, 337, 337, 
-    337, 337, 337, 337, 337, 337, 337, 82, 82, 338, 338, 338, 338, 338, 338, 
-    82, 82, 339, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 
-    340, 340, 340, 340, 340, 340, 340, 340, 341, 341, 340, 342, 343, 343, 
-    343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 
-    343, 343, 344, 345, 82, 82, 82, 346, 346, 346, 346, 346, 346, 346, 346, 
-    346, 346, 346, 199, 199, 199, 347, 347, 347, 346, 346, 346, 346, 346, 
-    346, 346, 346, 82, 82, 82, 82, 82, 82, 82, 348, 348, 348, 348, 348, 348, 
-    348, 348, 348, 348, 348, 348, 348, 82, 348, 348, 348, 348, 349, 349, 350, 
-    82, 82, 82, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 352, 352, 
-    353, 199, 199, 82, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 355, 
-    355, 82, 82, 82, 82, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 
-    356, 356, 356, 82, 356, 356, 356, 82, 357, 357, 82, 82, 82, 82, 358, 358, 
-    358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 359, 359, 360, 359, 
-    359, 359, 359, 359, 359, 359, 360, 360, 360, 360, 360, 360, 360, 360, 
-    359, 360, 360, 359, 359, 359, 359, 359, 359, 359, 359, 359, 361, 359, 
-    362, 362, 363, 364, 362, 365, 362, 366, 358, 367, 82, 82, 368, 368, 368, 
-    368, 368, 368, 368, 368, 368, 368, 82, 82, 82, 82, 82, 82, 369, 369, 369, 
-    369, 369, 369, 369, 369, 369, 369, 82, 82, 82, 82, 82, 82, 370, 370, 371, 
-    371, 372, 373, 374, 370, 375, 375, 370, 376, 376, 376, 377, 82, 378, 378, 
-    378, 378, 378, 378, 378, 378, 378, 378, 82, 82, 82, 82, 82, 82, 379, 379, 
-    379, 379, 379, 379, 379, 379, 379, 379, 379, 380, 379, 379, 379, 379, 
-    379, 379, 379, 379, 379, 376, 376, 379, 379, 381, 379, 82, 82, 82, 82, 
-    82, 340, 340, 340, 340, 340, 340, 82, 82, 382, 382, 382, 382, 382, 382, 
-    382, 382, 382, 382, 382, 382, 382, 382, 382, 82, 383, 383, 383, 384, 384, 
-    384, 384, 383, 383, 384, 384, 384, 82, 82, 82, 82, 384, 384, 383, 384, 
-    384, 384, 384, 384, 384, 385, 386, 387, 82, 82, 82, 82, 388, 82, 82, 82, 
-    389, 389, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 391, 391, 
-    391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 82, 82, 391, 
-    391, 391, 391, 391, 82, 82, 82, 392, 392, 392, 392, 392, 392, 392, 392, 
-    392, 392, 392, 392, 82, 82, 82, 82, 392, 392, 82, 82, 82, 82, 82, 82, 
-    393, 393, 393, 393, 393, 393, 393, 393, 393, 393, 394, 82, 82, 82, 395, 
-    395, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 
-    397, 397, 397, 397, 397, 397, 397, 397, 397, 397, 398, 399, 400, 400, 
-    401, 82, 82, 402, 402, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 
-    403, 403, 403, 404, 405, 404, 405, 405, 405, 405, 405, 405, 405, 82, 406, 
-    404, 405, 404, 404, 405, 405, 405, 405, 405, 405, 405, 405, 404, 404, 
-    404, 404, 404, 404, 405, 405, 407, 407, 407, 407, 407, 407, 407, 407, 82, 
-    82, 408, 409, 409, 409, 409, 409, 409, 409, 409, 409, 409, 82, 82, 82, 
-    82, 82, 82, 410, 410, 410, 410, 410, 410, 410, 411, 410, 410, 410, 410, 
-    410, 410, 82, 82, 97, 97, 97, 97, 97, 157, 157, 157, 157, 157, 157, 97, 
-    97, 157, 412, 82, 413, 413, 413, 413, 414, 415, 415, 415, 415, 415, 415, 
-    415, 415, 415, 415, 415, 415, 415, 415, 415, 416, 414, 413, 413, 413, 
-    413, 413, 414, 413, 414, 414, 414, 414, 414, 413, 414, 417, 415, 415, 
-    415, 415, 415, 415, 415, 82, 82, 82, 82, 418, 418, 418, 418, 418, 418, 
-    418, 418, 418, 418, 419, 419, 420, 419, 419, 419, 419, 421, 421, 421, 
-    421, 421, 421, 421, 421, 421, 421, 422, 423, 422, 422, 422, 422, 422, 
-    422, 422, 421, 421, 421, 421, 421, 421, 421, 421, 421, 82, 82, 82, 424, 
-    424, 425, 426, 426, 426, 426, 426, 426, 426, 426, 426, 426, 426, 426, 
-    426, 426, 425, 424, 424, 424, 424, 425, 425, 424, 424, 427, 428, 424, 
-    424, 426, 426, 429, 429, 429, 429, 429, 429, 429, 429, 429, 429, 426, 
-    426, 426, 426, 426, 426, 430, 430, 430, 430, 430, 430, 430, 430, 430, 
-    430, 430, 430, 430, 430, 431, 432, 433, 433, 432, 432, 432, 433, 432, 
-    433, 433, 433, 434, 434, 82, 82, 82, 82, 82, 82, 82, 82, 435, 435, 435, 
-    435, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 437, 
-    437, 437, 437, 437, 437, 437, 437, 438, 438, 438, 438, 438, 438, 438, 
-    438, 437, 437, 438, 439, 82, 82, 82, 440, 440, 440, 440, 440, 441, 441, 
-    441, 441, 441, 441, 441, 441, 441, 441, 82, 82, 82, 436, 436, 436, 442, 
-    442, 442, 442, 442, 442, 442, 442, 442, 442, 443, 443, 443, 443, 443, 
-    443, 443, 443, 443, 443, 443, 443, 443, 443, 444, 444, 444, 444, 444, 
-    444, 445, 445, 94, 82, 82, 82, 82, 82, 82, 82, 446, 446, 446, 446, 446, 
-    446, 446, 446, 97, 97, 97, 326, 447, 157, 157, 157, 157, 157, 97, 97, 
-    157, 157, 157, 157, 97, 448, 447, 447, 447, 447, 447, 447, 447, 449, 449, 
-    449, 449, 157, 449, 449, 449, 449, 448, 448, 97, 449, 449, 82, 97, 97, 
-    82, 82, 82, 82, 82, 82, 57, 57, 57, 57, 57, 57, 80, 80, 80, 80, 80, 94, 
-    60, 60, 60, 60, 60, 60, 60, 60, 60, 83, 83, 83, 83, 83, 60, 60, 60, 60, 
-    83, 83, 83, 83, 83, 57, 57, 57, 57, 57, 450, 57, 57, 57, 57, 57, 57, 57, 
-    57, 57, 57, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 83, 97, 97, 
-    157, 97, 97, 97, 97, 97, 97, 97, 157, 97, 97, 451, 452, 157, 453, 97, 97, 
-    97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 
-    97, 82, 82, 82, 82, 82, 97, 454, 157, 97, 157, 53, 57, 53, 57, 53, 57, 
-    57, 57, 57, 57, 57, 57, 57, 57, 53, 57, 80, 80, 80, 80, 80, 80, 80, 80, 
-    79, 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 82, 82, 79, 79, 
-    79, 79, 79, 79, 82, 82, 82, 79, 82, 79, 82, 79, 82, 79, 455, 455, 455, 
-    455, 455, 455, 455, 455, 80, 80, 80, 80, 80, 82, 80, 80, 79, 79, 79, 79, 
-    455, 81, 80, 81, 81, 81, 80, 80, 80, 82, 80, 80, 79, 79, 79, 79, 455, 81, 
-    81, 81, 80, 80, 80, 80, 82, 82, 80, 80, 79, 79, 79, 79, 82, 81, 81, 81, 
-    79, 79, 79, 79, 79, 81, 81, 81, 82, 82, 80, 80, 80, 82, 80, 80, 79, 79, 
-    79, 79, 455, 456, 81, 82, 457, 457, 457, 457, 457, 457, 457, 458, 457, 
-    457, 457, 459, 460, 461, 462, 463, 464, 465, 466, 464, 467, 468, 39, 85, 
-    469, 470, 471, 472, 469, 470, 471, 472, 39, 39, 473, 85, 474, 474, 474, 
-    475, 476, 477, 478, 479, 480, 481, 482, 34, 483, 484, 483, 483, 484, 485, 
-    486, 486, 85, 43, 51, 39, 487, 487, 473, 488, 488, 85, 85, 85, 489, 490, 
-    491, 487, 487, 487, 85, 85, 85, 85, 85, 85, 85, 85, 492, 85, 488, 85, 
-    373, 85, 373, 373, 373, 373, 85, 373, 373, 457, 493, 494, 494, 494, 494, 
-    82, 495, 496, 497, 498, 499, 499, 499, 499, 499, 499, 500, 60, 82, 82, 
-    48, 500, 500, 500, 500, 500, 501, 501, 492, 490, 491, 502, 500, 48, 48, 
-    48, 48, 500, 500, 500, 500, 500, 501, 501, 492, 490, 491, 82, 60, 60, 60, 
-    60, 60, 82, 82, 82, 278, 278, 278, 278, 278, 278, 278, 503, 278, 504, 
-    278, 278, 37, 278, 278, 278, 278, 278, 278, 278, 278, 278, 503, 278, 278, 
-    278, 278, 503, 278, 278, 503, 505, 505, 505, 505, 505, 505, 505, 505, 
-    505, 97, 97, 447, 447, 97, 97, 97, 97, 447, 447, 447, 97, 97, 412, 412, 
-    412, 412, 97, 412, 412, 412, 447, 447, 97, 157, 97, 447, 447, 157, 157, 
-    157, 157, 97, 82, 82, 82, 82, 82, 82, 82, 41, 41, 506, 507, 41, 508, 41, 
-    506, 41, 507, 50, 506, 506, 506, 50, 50, 506, 506, 506, 509, 41, 506, 
-    510, 41, 492, 506, 506, 506, 506, 506, 41, 41, 41, 508, 508, 41, 506, 41, 
-    86, 41, 506, 41, 53, 511, 506, 506, 512, 50, 506, 506, 53, 506, 50, 449, 
-    449, 449, 449, 50, 41, 41, 50, 50, 506, 506, 513, 492, 492, 492, 492, 
-    506, 50, 50, 50, 50, 41, 492, 41, 41, 57, 313, 514, 514, 514, 515, 52, 
-    516, 514, 514, 514, 514, 514, 52, 515, 515, 52, 514, 517, 517, 517, 517, 
-    517, 517, 517, 517, 517, 517, 517, 517, 518, 518, 518, 518, 517, 517, 
-    518, 518, 518, 518, 518, 518, 518, 518, 518, 53, 57, 518, 518, 518, 518, 
-    52, 41, 41, 82, 82, 82, 82, 55, 55, 55, 55, 55, 508, 508, 508, 508, 508, 
-    492, 492, 41, 41, 41, 41, 492, 41, 41, 492, 41, 41, 492, 41, 41, 41, 41, 
-    41, 41, 41, 492, 41, 41, 41, 41, 41, 41, 41, 41, 41, 45, 45, 41, 41, 41, 
-    41, 41, 41, 41, 41, 41, 41, 41, 41, 492, 492, 41, 41, 55, 41, 55, 41, 41, 
-    41, 41, 41, 41, 41, 41, 41, 41, 45, 41, 41, 41, 41, 492, 492, 492, 492, 
-    492, 492, 492, 492, 492, 492, 492, 492, 55, 513, 519, 519, 513, 492, 492, 
-    55, 519, 513, 513, 519, 513, 513, 492, 55, 492, 519, 520, 521, 492, 519, 
-    513, 492, 492, 492, 519, 513, 513, 519, 55, 519, 519, 513, 513, 55, 513, 
-    55, 513, 55, 55, 55, 55, 519, 519, 513, 519, 513, 513, 513, 513, 513, 55, 
-    55, 55, 55, 492, 513, 492, 513, 519, 519, 513, 513, 513, 513, 513, 513, 
-    513, 513, 513, 513, 519, 513, 513, 513, 519, 492, 492, 492, 492, 492, 
-    519, 513, 513, 513, 492, 492, 492, 492, 492, 492, 492, 492, 492, 513, 
-    519, 55, 513, 492, 519, 519, 519, 519, 513, 513, 519, 519, 492, 492, 519, 
-    519, 513, 513, 519, 519, 513, 513, 519, 519, 513, 513, 513, 513, 513, 
-    492, 492, 513, 513, 513, 513, 492, 492, 55, 492, 492, 513, 55, 492, 492, 
-    492, 492, 492, 492, 492, 492, 513, 513, 492, 55, 513, 513, 513, 492, 492, 
-    492, 492, 492, 513, 519, 492, 513, 513, 513, 513, 513, 492, 492, 513, 
-    513, 492, 492, 492, 492, 513, 513, 513, 513, 513, 513, 513, 513, 492, 
-    522, 490, 491, 490, 491, 41, 41, 41, 41, 41, 41, 508, 41, 41, 41, 41, 41, 
-    41, 41, 523, 523, 41, 41, 41, 41, 513, 513, 41, 41, 41, 41, 41, 41, 41, 
-    524, 525, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 313, 313, 313, 313, 
-    313, 313, 313, 313, 313, 313, 313, 313, 313, 41, 492, 41, 41, 41, 41, 41, 
-    41, 41, 41, 313, 41, 41, 41, 41, 41, 492, 492, 492, 492, 492, 492, 492, 
-    492, 492, 41, 41, 41, 41, 492, 492, 41, 41, 41, 41, 41, 41, 41, 526, 526, 
-    526, 526, 41, 41, 41, 523, 527, 527, 523, 41, 41, 41, 41, 41, 41, 41, 41, 
-    41, 41, 41, 82, 41, 41, 41, 82, 82, 82, 82, 82, 52, 52, 52, 52, 52, 52, 
-    52, 52, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 528, 528, 528, 
-    528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 516, 52, 52, 52, 
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 515, 508, 508, 508, 508, 508, 508, 
-    508, 508, 508, 508, 508, 508, 41, 41, 41, 41, 508, 508, 508, 508, 529, 
-    41, 41, 41, 41, 41, 508, 508, 508, 508, 41, 41, 508, 508, 41, 508, 508, 
-    508, 508, 508, 508, 508, 41, 41, 41, 41, 41, 41, 41, 41, 508, 508, 41, 
-    41, 508, 55, 41, 41, 41, 41, 508, 508, 41, 41, 508, 55, 41, 41, 41, 41, 
-    508, 508, 508, 41, 41, 508, 41, 41, 508, 508, 41, 41, 41, 41, 41, 41, 41, 
-    508, 492, 492, 492, 492, 492, 530, 530, 492, 527, 527, 527, 527, 41, 508, 
-    508, 41, 41, 508, 41, 41, 41, 41, 508, 508, 41, 41, 41, 41, 523, 523, 
-    529, 529, 527, 41, 527, 527, 531, 532, 531, 527, 41, 527, 527, 527, 41, 
-    41, 41, 41, 508, 41, 508, 41, 41, 41, 41, 41, 526, 526, 526, 526, 526, 
-    526, 526, 526, 526, 526, 526, 526, 41, 41, 41, 41, 508, 508, 41, 508, 
-    508, 508, 41, 508, 531, 508, 508, 41, 508, 508, 41, 55, 41, 41, 41, 41, 
-    41, 41, 41, 523, 41, 41, 41, 526, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 
-    508, 508, 41, 526, 41, 41, 41, 41, 41, 41, 41, 41, 526, 526, 313, 41, 41, 
-    41, 41, 41, 41, 41, 41, 523, 523, 531, 527, 527, 527, 527, 523, 523, 531, 
-    531, 531, 508, 508, 508, 508, 531, 526, 531, 531, 531, 508, 531, 523, 
-    508, 508, 508, 531, 531, 508, 508, 531, 508, 508, 531, 531, 531, 41, 508, 
-    41, 41, 41, 41, 508, 508, 523, 508, 508, 508, 508, 508, 508, 531, 523, 
-    523, 531, 523, 508, 531, 531, 533, 523, 508, 508, 523, 531, 531, 527, 
-    527, 527, 527, 527, 526, 41, 41, 527, 527, 534, 534, 532, 532, 41, 41, 
-    526, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 45, 41, 41, 41, 41, 
-    41, 41, 526, 41, 526, 41, 41, 41, 41, 526, 526, 526, 41, 535, 41, 41, 41, 
-    536, 536, 536, 536, 536, 536, 41, 537, 537, 527, 41, 41, 41, 490, 491, 
-    490, 491, 490, 491, 490, 491, 490, 491, 490, 491, 490, 491, 52, 52, 516, 
-    516, 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, 41, 526, 526, 526, 
-    41, 41, 41, 41, 41, 41, 41, 526, 513, 492, 492, 513, 513, 490, 491, 492, 
-    513, 513, 492, 513, 513, 513, 492, 492, 492, 492, 492, 513, 513, 513, 
-    513, 492, 492, 492, 492, 492, 513, 513, 513, 492, 492, 492, 513, 513, 
-    513, 513, 16, 32, 16, 32, 16, 32, 16, 32, 490, 491, 538, 538, 538, 538, 
-    538, 538, 538, 538, 492, 492, 492, 490, 491, 16, 32, 490, 491, 490, 491, 
-    490, 491, 490, 491, 490, 491, 492, 492, 513, 513, 513, 513, 513, 513, 
-    492, 492, 492, 492, 492, 492, 492, 513, 513, 513, 513, 513, 513, 492, 
-    492, 492, 513, 492, 492, 492, 492, 513, 513, 513, 513, 513, 492, 513, 
-    513, 492, 492, 490, 491, 490, 491, 513, 492, 492, 492, 492, 513, 492, 
-    513, 513, 513, 492, 492, 513, 513, 492, 492, 492, 492, 492, 492, 492, 
-    492, 492, 492, 513, 513, 513, 513, 513, 513, 492, 492, 490, 491, 492, 
-    492, 492, 492, 513, 513, 513, 513, 513, 513, 513, 513, 513, 513, 513, 
-    492, 513, 513, 513, 513, 492, 492, 513, 492, 513, 492, 492, 513, 492, 
-    513, 513, 513, 513, 492, 492, 492, 492, 492, 513, 513, 492, 492, 492, 
-    492, 513, 513, 513, 513, 492, 513, 513, 492, 492, 513, 513, 492, 492, 
-    492, 492, 513, 513, 513, 513, 513, 513, 513, 513, 513, 513, 513, 492, 
-    492, 513, 513, 513, 513, 513, 513, 513, 513, 492, 513, 513, 513, 513, 
-    513, 513, 513, 513, 492, 492, 492, 492, 492, 513, 492, 513, 492, 492, 
-    492, 513, 513, 513, 513, 513, 492, 492, 492, 492, 513, 492, 492, 492, 
-    513, 513, 513, 513, 513, 492, 513, 492, 492, 41, 41, 41, 526, 526, 41, 
-    41, 41, 492, 492, 492, 492, 492, 41, 41, 492, 492, 492, 492, 492, 492, 
-    41, 41, 41, 526, 41, 41, 41, 41, 535, 508, 508, 41, 41, 41, 41, 82, 82, 
-    41, 41, 41, 41, 41, 41, 41, 41, 82, 82, 41, 41, 82, 82, 82, 41, 41, 41, 
-    41, 82, 41, 41, 41, 41, 41, 41, 41, 41, 82, 82, 82, 82, 82, 82, 82, 82, 
-    82, 82, 41, 41, 41, 41, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 
-    539, 539, 539, 539, 539, 82, 540, 540, 540, 540, 540, 540, 540, 540, 540, 
-    540, 540, 540, 540, 540, 540, 82, 53, 57, 53, 53, 53, 57, 57, 53, 57, 53, 
-    57, 53, 57, 53, 53, 53, 53, 57, 53, 57, 57, 53, 57, 57, 57, 57, 57, 57, 
-    60, 60, 53, 53, 88, 89, 88, 89, 89, 541, 541, 541, 541, 541, 541, 88, 89, 
-    88, 89, 542, 542, 542, 88, 89, 82, 82, 82, 82, 82, 543, 544, 544, 544, 
-    545, 543, 544, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 
-    546, 546, 546, 82, 546, 82, 82, 82, 82, 82, 546, 82, 82, 547, 547, 547, 
-    547, 547, 547, 547, 547, 82, 82, 82, 82, 82, 82, 82, 548, 549, 82, 82, 
-    82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 550, 96, 96, 96, 96, 96, 
-    96, 96, 96, 551, 551, 43, 51, 43, 51, 551, 551, 551, 43, 51, 551, 43, 51, 
-    373, 373, 373, 373, 373, 373, 373, 373, 85, 466, 552, 373, 553, 85, 43, 
-    51, 85, 85, 43, 51, 490, 491, 490, 491, 490, 491, 490, 491, 373, 373, 
-    373, 373, 371, 61, 373, 373, 85, 373, 373, 85, 85, 85, 85, 85, 554, 554, 
-    373, 373, 373, 85, 466, 373, 471, 373, 373, 82, 82, 82, 555, 555, 555, 
-    555, 555, 555, 555, 555, 555, 555, 82, 555, 555, 555, 555, 555, 555, 555, 
-    555, 555, 82, 82, 82, 82, 555, 555, 555, 555, 555, 555, 82, 82, 523, 523, 
-    523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 82, 82, 82, 82, 556, 
-    557, 557, 558, 523, 559, 560, 561, 524, 525, 524, 525, 524, 525, 524, 
-    525, 524, 525, 523, 523, 524, 525, 524, 525, 524, 525, 524, 525, 562, 
-    563, 564, 564, 523, 561, 561, 561, 561, 561, 561, 561, 561, 561, 565, 
-    566, 567, 568, 569, 569, 570, 571, 571, 571, 571, 572, 523, 523, 561, 
-    561, 561, 559, 573, 558, 523, 527, 82, 574, 575, 574, 575, 574, 575, 574, 
-    575, 574, 575, 575, 575, 575, 575, 575, 575, 575, 575, 575, 575, 575, 
-    575, 575, 575, 575, 575, 574, 575, 575, 575, 575, 575, 575, 575, 574, 
-    575, 574, 575, 574, 575, 575, 575, 575, 575, 575, 574, 575, 575, 575, 
-    575, 575, 575, 574, 574, 82, 82, 576, 576, 577, 577, 578, 578, 575, 562, 
-    579, 580, 579, 580, 579, 580, 579, 580, 579, 580, 580, 580, 580, 580, 
-    580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 579, 580, 
-    580, 580, 580, 580, 580, 580, 579, 580, 579, 580, 579, 580, 580, 580, 
-    580, 580, 580, 579, 580, 580, 580, 580, 580, 580, 579, 579, 580, 580, 
-    580, 580, 581, 582, 583, 583, 580, 82, 82, 82, 82, 82, 584, 584, 584, 
-    584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 82, 
-    82, 82, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 
-    585, 585, 585, 585, 585, 585, 585, 585, 585, 82, 586, 586, 587, 587, 587, 
-    587, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 584, 584, 584, 82, 
-    82, 82, 82, 82, 579, 579, 579, 579, 579, 579, 579, 579, 588, 588, 588, 
-    588, 588, 588, 588, 588, 588, 588, 588, 588, 588, 589, 589, 82, 587, 587, 
-    587, 587, 587, 587, 587, 587, 587, 587, 586, 586, 586, 586, 586, 586, 
-    590, 590, 590, 590, 590, 590, 590, 590, 523, 591, 591, 591, 591, 591, 
-    591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 588, 588, 588, 588, 
-    589, 589, 589, 586, 586, 591, 591, 591, 591, 591, 591, 591, 586, 586, 
-    586, 586, 523, 523, 523, 523, 592, 592, 592, 592, 592, 592, 592, 592, 
-    592, 592, 592, 592, 592, 592, 592, 82, 586, 586, 586, 586, 586, 586, 586, 
-    523, 523, 523, 523, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 
-    586, 523, 523, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 
-    593, 593, 593, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 595, 
-    595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 596, 595, 
-    595, 595, 595, 595, 595, 595, 82, 82, 82, 597, 597, 597, 597, 597, 597, 
-    597, 597, 597, 597, 597, 597, 597, 597, 597, 82, 598, 598, 598, 598, 598, 
-    598, 598, 598, 599, 599, 599, 599, 599, 599, 600, 600, 601, 601, 601, 
-    601, 601, 601, 601, 601, 601, 601, 601, 601, 602, 603, 604, 603, 605, 
-    605, 605, 605, 605, 605, 605, 605, 605, 605, 601, 601, 82, 82, 82, 82, 
-    91, 94, 91, 94, 91, 94, 606, 96, 98, 98, 98, 607, 96, 96, 96, 96, 96, 96, 
-    96, 96, 96, 96, 607, 608, 91, 94, 91, 94, 450, 450, 96, 96, 609, 609, 
-    609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 610, 610, 
-    610, 610, 610, 610, 610, 610, 610, 610, 611, 611, 612, 613, 613, 613, 
-    613, 613, 63, 63, 63, 63, 63, 63, 63, 61, 61, 61, 61, 61, 61, 61, 61, 61, 
-    63, 63, 53, 57, 53, 57, 53, 57, 57, 57, 53, 57, 53, 57, 53, 57, 60, 57, 
-    57, 57, 57, 57, 57, 57, 57, 53, 57, 53, 57, 53, 53, 57, 61, 614, 614, 53, 
-    57, 53, 57, 58, 53, 57, 53, 57, 57, 57, 53, 57, 53, 57, 53, 53, 53, 53, 
-    53, 82, 53, 53, 53, 53, 53, 57, 53, 57, 82, 82, 82, 82, 82, 82, 82, 58, 
-    60, 60, 57, 58, 58, 58, 58, 58, 615, 615, 616, 615, 615, 615, 617, 615, 
-    615, 615, 615, 616, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 
-    615, 615, 615, 615, 615, 618, 618, 616, 616, 618, 619, 619, 619, 619, 82, 
-    82, 82, 82, 620, 620, 620, 620, 620, 620, 313, 313, 503, 512, 82, 82, 82, 
-    82, 82, 82, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 
-    622, 622, 623, 623, 624, 624, 625, 625, 625, 625, 625, 625, 625, 625, 
-    625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 624, 624, 624, 624, 
-    624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 626, 627, 82, 
-    82, 82, 82, 82, 82, 82, 82, 628, 628, 629, 629, 629, 629, 629, 629, 629, 
-    629, 629, 629, 82, 82, 82, 82, 82, 82, 198, 198, 198, 198, 198, 198, 198, 
-    198, 198, 198, 195, 195, 195, 195, 195, 195, 201, 201, 201, 195, 630, 
-    195, 82, 82, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 632, 632, 
-    632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 
-    632, 632, 632, 632, 633, 633, 633, 633, 633, 634, 634, 634, 199, 635, 
-    636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 
-    636, 637, 637, 637, 637, 637, 637, 637, 637, 637, 637, 637, 638, 639, 82, 
-    82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 640, 328, 328, 328, 328, 328, 82, 
-    82, 82, 641, 641, 641, 642, 643, 643, 643, 643, 643, 643, 643, 643, 643, 
-    643, 643, 643, 643, 643, 643, 644, 642, 642, 641, 641, 641, 641, 642, 
-    642, 641, 642, 642, 642, 645, 646, 646, 646, 646, 646, 646, 647, 647, 
-    647, 646, 646, 646, 646, 82, 62, 648, 648, 648, 648, 648, 648, 648, 648, 
-    648, 648, 82, 82, 82, 82, 646, 646, 314, 314, 314, 314, 314, 316, 649, 
-    314, 319, 319, 314, 314, 314, 314, 314, 82, 650, 650, 650, 650, 650, 650, 
-    650, 650, 650, 651, 651, 651, 651, 651, 651, 652, 652, 651, 651, 652, 
-    652, 651, 651, 82, 650, 650, 650, 651, 650, 650, 650, 650, 650, 650, 650, 
-    650, 651, 652, 82, 82, 653, 653, 653, 653, 653, 653, 653, 653, 653, 653, 
-    82, 82, 654, 655, 655, 655, 649, 314, 314, 314, 314, 314, 314, 323, 323, 
-    323, 314, 315, 316, 315, 314, 314, 656, 656, 656, 656, 656, 656, 656, 
-    656, 657, 656, 657, 657, 658, 656, 656, 657, 657, 656, 656, 656, 656, 
-    656, 657, 657, 656, 657, 656, 82, 82, 82, 82, 82, 82, 82, 82, 656, 656, 
-    659, 660, 660, 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, 
-    662, 663, 663, 662, 662, 664, 664, 661, 665, 665, 662, 666, 82, 82, 331, 
-    331, 331, 331, 331, 331, 82, 57, 57, 57, 614, 60, 60, 60, 60, 57, 57, 57, 
-    57, 57, 80, 82, 82, 338, 338, 338, 338, 338, 338, 338, 338, 661, 661, 
-    661, 662, 662, 663, 662, 662, 663, 662, 662, 664, 662, 666, 82, 82, 667, 
-    667, 667, 667, 667, 667, 667, 667, 667, 667, 82, 82, 82, 82, 82, 82, 668, 
-    669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 
-    669, 669, 669, 669, 669, 668, 669, 669, 669, 669, 669, 669, 669, 82, 82, 
-    82, 82, 329, 329, 329, 329, 329, 329, 329, 82, 82, 82, 82, 330, 330, 330, 
-    330, 330, 330, 330, 330, 330, 82, 82, 82, 82, 670, 670, 670, 670, 670, 
-    670, 670, 670, 671, 671, 671, 671, 671, 671, 671, 671, 593, 593, 594, 
-    594, 594, 594, 594, 594, 57, 57, 57, 57, 57, 57, 57, 82, 82, 82, 82, 102, 
-    102, 102, 102, 102, 82, 82, 82, 82, 82, 130, 672, 130, 130, 673, 130, 
-    130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 82, 130, 130, 
-    130, 130, 130, 82, 130, 82, 130, 130, 82, 130, 130, 82, 130, 130, 147, 
-    147, 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, 
-    674, 674, 674, 82, 82, 82, 82, 82, 82, 82, 82, 82, 147, 147, 147, 147, 
-    147, 147, 147, 147, 147, 147, 147, 675, 471, 82, 82, 147, 147, 147, 147, 
-    147, 147, 147, 147, 147, 147, 136, 139, 82, 82, 676, 676, 676, 676, 676, 
-    676, 676, 676, 677, 557, 557, 677, 677, 678, 678, 563, 564, 679, 82, 82, 
-    82, 82, 82, 82, 97, 97, 97, 97, 97, 97, 97, 157, 157, 157, 157, 157, 157, 
-    157, 96, 96, 558, 570, 570, 680, 680, 563, 564, 563, 564, 563, 564, 563, 
-    564, 563, 564, 563, 564, 563, 564, 563, 564, 558, 558, 563, 564, 558, 
-    558, 558, 558, 680, 680, 680, 681, 558, 681, 82, 581, 682, 678, 678, 570, 
-    524, 525, 524, 525, 524, 525, 683, 558, 558, 684, 685, 686, 686, 687, 82, 
-    558, 688, 689, 558, 82, 82, 82, 82, 147, 147, 147, 147, 147, 82, 82, 493, 
-    82, 690, 691, 692, 693, 694, 691, 691, 695, 696, 691, 697, 698, 699, 698, 
-    700, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 702, 703, 704, 
-    705, 704, 690, 691, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 
-    706, 706, 706, 706, 706, 706, 706, 706, 695, 691, 696, 707, 708, 707, 
-    709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 
-    709, 709, 709, 709, 695, 705, 696, 705, 695, 696, 710, 711, 712, 710, 
-    713, 714, 715, 715, 715, 715, 715, 715, 715, 715, 715, 716, 714, 714, 
-    714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 
-    714, 714, 714, 714, 714, 717, 717, 718, 718, 718, 718, 718, 718, 718, 
-    718, 718, 718, 718, 718, 718, 718, 718, 82, 82, 82, 718, 718, 718, 718, 
-    718, 718, 82, 82, 718, 718, 718, 82, 82, 82, 719, 693, 705, 707, 720, 
-    693, 693, 82, 721, 722, 722, 722, 722, 721, 721, 82, 82, 723, 723, 723, 
-    724, 508, 82, 82, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 
-    725, 82, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 82, 725, 725, 
-    725, 82, 725, 725, 82, 725, 725, 725, 725, 725, 725, 725, 82, 82, 725, 
-    725, 725, 82, 82, 82, 82, 82, 199, 373, 199, 82, 82, 82, 82, 620, 620, 
-    620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 82, 82, 82, 313, 
-    726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 727, 
-    727, 727, 727, 728, 728, 728, 728, 728, 728, 728, 728, 728, 728, 728, 
-    728, 728, 728, 728, 728, 728, 727, 727, 728, 729, 729, 82, 41, 41, 41, 
-    41, 82, 82, 82, 82, 728, 82, 82, 82, 82, 82, 82, 82, 313, 313, 313, 313, 
-    313, 157, 82, 82, 730, 730, 730, 730, 730, 730, 730, 730, 730, 730, 730, 
-    730, 730, 82, 82, 82, 731, 731, 731, 731, 731, 731, 731, 731, 731, 82, 
-    82, 82, 82, 82, 82, 82, 157, 500, 500, 500, 500, 500, 500, 500, 500, 500, 
-    500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 82, 82, 82, 82, 732, 
-    732, 732, 732, 732, 732, 732, 732, 733, 733, 733, 733, 82, 82, 82, 82, 
-    734, 734, 734, 734, 734, 734, 734, 734, 734, 735, 734, 734, 734, 734, 
-    734, 734, 734, 734, 735, 82, 82, 82, 82, 82, 736, 736, 736, 736, 736, 
-    736, 736, 736, 736, 736, 736, 736, 736, 736, 737, 737, 737, 737, 737, 82, 
-    82, 82, 82, 82, 738, 738, 738, 738, 738, 738, 738, 738, 738, 738, 738, 
-    738, 738, 738, 82, 739, 740, 740, 740, 740, 740, 740, 740, 740, 740, 740, 
-    740, 740, 82, 82, 82, 82, 741, 742, 742, 742, 742, 742, 82, 82, 743, 743, 
-    743, 743, 743, 743, 743, 743, 744, 744, 744, 744, 744, 744, 744, 744, 
-    745, 745, 745, 745, 745, 745, 745, 745, 746, 746, 746, 746, 746, 746, 
-    746, 746, 746, 746, 746, 746, 746, 746, 82, 82, 747, 747, 747, 747, 747, 
-    747, 747, 747, 747, 747, 82, 82, 82, 82, 82, 82, 748, 748, 748, 748, 748, 
-    748, 748, 748, 748, 748, 748, 748, 82, 82, 82, 82, 749, 749, 749, 749, 
-    749, 749, 749, 749, 749, 749, 749, 749, 82, 82, 82, 82, 750, 750, 750, 
-    750, 750, 750, 750, 750, 751, 751, 751, 751, 751, 751, 751, 751, 751, 
-    751, 751, 751, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 752, 753, 753, 
-    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 82, 753, 
-    753, 753, 753, 753, 753, 82, 82, 754, 754, 754, 754, 754, 754, 82, 82, 
-    754, 82, 754, 754, 754, 754, 754, 754, 754, 754, 754, 754, 754, 754, 754, 
-    754, 754, 754, 754, 754, 754, 754, 82, 754, 754, 82, 82, 82, 754, 82, 82, 
-    754, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 
-    755, 82, 756, 757, 757, 757, 757, 757, 757, 757, 757, 758, 758, 758, 758, 
-    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 759, 759, 760, 
-    760, 760, 760, 760, 760, 760, 761, 761, 761, 761, 761, 761, 761, 761, 
-    761, 761, 761, 761, 761, 761, 761, 82, 82, 82, 82, 82, 82, 82, 82, 762, 
-    762, 762, 762, 762, 762, 762, 762, 762, 763, 763, 763, 763, 763, 763, 
-    763, 763, 763, 763, 763, 82, 763, 763, 82, 82, 82, 82, 82, 764, 764, 764, 
-    764, 764, 765, 765, 765, 765, 765, 765, 765, 765, 765, 765, 765, 765, 
-    765, 765, 766, 766, 766, 766, 766, 766, 82, 82, 82, 767, 768, 768, 768, 
-    768, 768, 768, 768, 768, 768, 768, 82, 82, 82, 82, 82, 769, 770, 770, 
-    770, 770, 770, 770, 770, 770, 771, 771, 771, 771, 771, 771, 771, 771, 82, 
-    82, 82, 82, 772, 772, 771, 771, 772, 772, 772, 772, 772, 772, 772, 772, 
-    82, 82, 772, 772, 772, 772, 772, 772, 773, 774, 774, 774, 82, 774, 774, 
-    82, 82, 82, 82, 82, 774, 775, 774, 776, 773, 773, 773, 773, 82, 773, 773, 
-    773, 82, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
-    773, 773, 773, 773, 773, 773, 82, 82, 82, 82, 776, 777, 775, 82, 82, 82, 
-    82, 778, 779, 779, 779, 779, 779, 779, 779, 779, 780, 780, 780, 780, 780, 
-    780, 780, 780, 781, 82, 82, 82, 82, 82, 82, 82, 782, 782, 782, 782, 782, 
-    782, 782, 782, 782, 782, 782, 782, 782, 783, 783, 784, 785, 785, 785, 
-    785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 786, 786, 786, 787, 
-    787, 787, 787, 787, 787, 787, 787, 788, 787, 787, 787, 787, 787, 787, 
-    787, 787, 787, 787, 787, 787, 789, 790, 82, 82, 82, 82, 791, 791, 791, 
-    791, 791, 792, 792, 792, 792, 792, 792, 793, 82, 794, 794, 794, 794, 794, 
-    794, 794, 794, 794, 794, 794, 794, 794, 794, 82, 82, 82, 795, 795, 795, 
-    795, 795, 795, 795, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 
-    796, 796, 796, 796, 82, 82, 797, 797, 797, 797, 797, 797, 797, 797, 798, 
-    798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 82, 82, 82, 82, 82, 
-    799, 799, 799, 799, 799, 799, 799, 799, 800, 800, 800, 800, 800, 800, 
-    800, 800, 800, 800, 82, 82, 82, 82, 82, 82, 82, 801, 801, 801, 801, 82, 
-    82, 82, 82, 802, 802, 802, 802, 802, 802, 802, 803, 803, 803, 803, 803, 
-    803, 803, 803, 803, 82, 82, 82, 82, 82, 82, 82, 804, 804, 804, 804, 804, 
-    804, 804, 804, 804, 804, 804, 82, 82, 82, 82, 82, 805, 805, 805, 805, 
-    805, 805, 805, 805, 805, 805, 805, 82, 82, 82, 82, 82, 82, 82, 806, 806, 
-    806, 806, 806, 806, 807, 807, 807, 807, 807, 807, 807, 807, 807, 807, 
-    807, 807, 807, 807, 807, 82, 808, 809, 808, 810, 810, 810, 810, 810, 810, 
-    810, 810, 810, 810, 810, 810, 810, 809, 809, 809, 809, 809, 809, 809, 
-    809, 809, 809, 809, 809, 809, 809, 811, 812, 812, 813, 813, 813, 813, 
-    813, 82, 82, 82, 82, 814, 814, 814, 814, 814, 814, 814, 814, 814, 814, 
-    814, 814, 814, 814, 814, 814, 814, 814, 814, 814, 815, 815, 815, 815, 
-    815, 815, 815, 815, 815, 815, 82, 82, 82, 82, 82, 82, 82, 811, 816, 816, 
-    817, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 818, 
-    817, 817, 817, 816, 816, 816, 816, 817, 817, 819, 820, 821, 821, 822, 
-    823, 823, 823, 823, 82, 82, 82, 82, 82, 82, 824, 824, 824, 824, 824, 824, 
-    824, 824, 824, 82, 82, 82, 82, 82, 82, 82, 825, 825, 825, 825, 825, 825, 
-    825, 825, 825, 825, 82, 82, 82, 82, 82, 82, 826, 826, 826, 827, 827, 827, 
-    827, 827, 827, 827, 827, 827, 827, 827, 827, 827, 827, 827, 827, 827, 
-    827, 827, 827, 828, 828, 828, 828, 828, 829, 828, 828, 828, 828, 828, 
-    828, 830, 830, 82, 831, 831, 831, 831, 831, 831, 831, 831, 831, 831, 832, 
-    832, 832, 832, 82, 82, 82, 82, 833, 833, 833, 833, 833, 833, 833, 833, 
-    833, 833, 833, 834, 835, 836, 833, 82, 837, 837, 838, 839, 839, 839, 839, 
-    839, 839, 839, 839, 839, 839, 839, 839, 839, 839, 839, 839, 838, 838, 
-    838, 837, 837, 837, 837, 837, 837, 837, 837, 837, 838, 840, 839, 839, 
-    839, 839, 841, 841, 842, 841, 842, 843, 837, 837, 842, 82, 82, 844, 844, 
-    844, 844, 844, 844, 844, 844, 844, 844, 839, 845, 839, 841, 841, 841, 82, 
-    846, 846, 846, 846, 846, 846, 846, 846, 846, 846, 846, 846, 846, 846, 
-    846, 846, 846, 846, 846, 846, 82, 82, 82, 847, 847, 847, 847, 847, 847, 
-    847, 847, 847, 847, 82, 847, 847, 847, 847, 847, 847, 847, 847, 847, 848, 
-    848, 848, 849, 849, 849, 848, 848, 849, 850, 851, 849, 852, 852, 853, 
-    852, 852, 853, 849, 82, 854, 854, 854, 854, 854, 854, 854, 82, 854, 82, 
-    854, 854, 854, 854, 82, 854, 854, 854, 854, 854, 854, 854, 854, 854, 854, 
-    854, 854, 854, 854, 854, 82, 854, 854, 855, 82, 82, 82, 82, 82, 82, 856, 
-    856, 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, 
-    857, 858, 858, 858, 857, 857, 857, 857, 857, 857, 859, 860, 82, 82, 82, 
-    82, 82, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 82, 82, 82, 82, 
-    82, 82, 862, 862, 863, 863, 82, 864, 864, 864, 864, 864, 864, 864, 864, 
-    82, 82, 864, 864, 82, 82, 864, 864, 864, 864, 864, 864, 864, 864, 864, 
-    864, 864, 864, 864, 864, 82, 864, 864, 864, 864, 864, 864, 864, 82, 864, 
-    864, 82, 864, 864, 864, 864, 864, 82, 82, 865, 864, 863, 863, 862, 863, 
-    863, 863, 863, 82, 82, 863, 863, 82, 82, 863, 863, 866, 82, 82, 864, 82, 
-    82, 82, 82, 82, 82, 863, 82, 82, 82, 82, 82, 864, 864, 864, 864, 864, 
-    863, 863, 82, 82, 867, 867, 867, 867, 867, 867, 867, 82, 82, 82, 868, 
-    868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 869, 869, 
-    869, 870, 870, 870, 870, 870, 870, 870, 870, 869, 869, 871, 870, 870, 
-    869, 872, 868, 868, 868, 868, 873, 873, 873, 873, 874, 875, 875, 875, 
-    875, 875, 875, 875, 875, 875, 875, 82, 873, 82, 874, 82, 82, 876, 876, 
-    876, 876, 876, 876, 876, 876, 877, 877, 877, 878, 878, 878, 878, 878, 
-    878, 877, 878, 877, 877, 877, 877, 878, 878, 877, 879, 880, 876, 876, 
-    881, 876, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 82, 82, 82, 
-    82, 82, 82, 883, 883, 883, 883, 883, 883, 883, 883, 883, 883, 883, 883, 
-    883, 883, 883, 884, 884, 884, 885, 885, 885, 885, 82, 82, 884, 884, 884, 
-    884, 885, 885, 884, 886, 887, 888, 889, 889, 890, 890, 891, 891, 891, 
-    889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 
-    889, 883, 883, 883, 883, 885, 885, 82, 82, 892, 892, 892, 892, 892, 892, 
-    892, 892, 893, 893, 893, 894, 894, 894, 894, 894, 894, 894, 894, 893, 
-    893, 894, 893, 895, 894, 896, 896, 897, 892, 82, 82, 82, 898, 898, 898, 
-    898, 898, 898, 898, 898, 898, 898, 82, 82, 82, 82, 82, 82, 899, 899, 899, 
-    899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 82, 82, 82, 900, 900, 
-    900, 900, 900, 900, 900, 900, 900, 900, 900, 901, 902, 901, 902, 902, 
-    901, 901, 901, 901, 901, 901, 903, 904, 905, 905, 905, 905, 905, 905, 
-    905, 905, 905, 905, 82, 82, 82, 82, 82, 82, 906, 906, 906, 906, 906, 906, 
-    906, 906, 906, 906, 82, 82, 82, 907, 907, 907, 908, 908, 907, 907, 907, 
-    907, 908, 907, 907, 907, 907, 909, 82, 82, 82, 82, 910, 910, 910, 910, 
-    910, 910, 910, 910, 910, 910, 911, 911, 912, 912, 912, 913, 914, 914, 
-    914, 914, 914, 914, 914, 914, 915, 915, 915, 915, 915, 915, 915, 915, 
-    916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 917, 917, 917, 917, 
-    917, 917, 917, 917, 917, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 
-    918, 919, 919, 919, 919, 919, 919, 919, 919, 919, 82, 82, 82, 82, 82, 82, 
-    82, 920, 920, 920, 920, 920, 920, 920, 920, 920, 82, 920, 920, 920, 920, 
-    920, 920, 920, 920, 920, 920, 920, 920, 920, 921, 922, 922, 922, 922, 
-    922, 922, 922, 82, 922, 922, 922, 922, 922, 922, 921, 923, 920, 924, 924, 
-    924, 924, 924, 82, 82, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 
-    926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 
-    926, 926, 926, 926, 926, 82, 82, 82, 927, 928, 929, 929, 929, 929, 929, 
-    929, 929, 929, 929, 929, 929, 929, 929, 929, 82, 82, 930, 930, 930, 930, 
-    930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 82, 931, 930, 930, 930, 
-    930, 930, 930, 930, 931, 930, 930, 931, 930, 930, 82, 932, 932, 932, 932, 
-    932, 932, 932, 932, 932, 932, 82, 82, 82, 82, 82, 82, 933, 933, 933, 933, 
-    933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 82, 934, 934, 934, 
-    934, 934, 82, 82, 82, 932, 932, 932, 932, 82, 82, 82, 82, 935, 935, 935, 
-    935, 935, 935, 935, 935, 936, 936, 936, 937, 937, 937, 935, 935, 935, 
-    935, 937, 935, 935, 935, 936, 937, 936, 937, 935, 935, 935, 935, 935, 
-    935, 935, 936, 937, 937, 935, 935, 935, 935, 935, 935, 935, 935, 935, 
-    935, 935, 82, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 
-    938, 938, 939, 940, 938, 938, 938, 938, 938, 938, 938, 82, 609, 82, 82, 
-    82, 82, 82, 82, 82, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 
-    941, 941, 941, 941, 941, 82, 942, 942, 942, 942, 942, 942, 942, 942, 942, 
-    942, 82, 82, 82, 82, 943, 943, 944, 944, 944, 944, 944, 944, 944, 944, 
-    944, 944, 944, 944, 944, 944, 82, 82, 945, 945, 945, 945, 945, 946, 82, 
-    82, 947, 947, 947, 947, 947, 947, 947, 947, 948, 948, 948, 948, 948, 948, 
-    948, 949, 949, 949, 950, 950, 951, 951, 951, 951, 952, 952, 952, 952, 
-    949, 951, 82, 82, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 82, 
-    954, 954, 954, 954, 954, 954, 954, 82, 947, 947, 947, 947, 947, 82, 82, 
-    82, 82, 82, 947, 947, 947, 955, 955, 955, 955, 955, 955, 955, 955, 955, 
-    955, 955, 955, 955, 82, 82, 82, 955, 956, 956, 956, 956, 956, 956, 956, 
-    956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 
-    956, 82, 82, 82, 82, 82, 82, 82, 82, 957, 957, 957, 957, 958, 958, 958, 
-    958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 959, 82, 82, 82, 82, 
-    82, 82, 82, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 
-    960, 82, 82, 82, 960, 960, 960, 82, 82, 82, 82, 82, 580, 575, 82, 82, 82, 
-    82, 82, 82, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 82, 
-    82, 82, 82, 82, 961, 961, 961, 961, 961, 82, 82, 82, 961, 82, 82, 82, 82, 
-    82, 82, 82, 961, 961, 82, 82, 962, 963, 964, 965, 499, 499, 499, 499, 82, 
-    82, 82, 82, 313, 313, 313, 313, 313, 313, 82, 82, 313, 313, 313, 313, 
-    313, 313, 313, 82, 82, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 
-    313, 313, 966, 966, 447, 447, 447, 313, 313, 313, 967, 966, 966, 966, 
-    966, 966, 499, 499, 499, 499, 499, 499, 499, 499, 157, 157, 157, 157, 
-    157, 157, 157, 157, 313, 313, 97, 97, 97, 97, 97, 157, 157, 313, 313, 
-    313, 313, 313, 313, 97, 97, 97, 97, 313, 313, 313, 82, 82, 82, 82, 82, 
-    82, 82, 728, 728, 968, 968, 968, 728, 82, 82, 620, 620, 82, 82, 82, 82, 
-    82, 82, 506, 506, 506, 506, 506, 506, 506, 506, 506, 506, 50, 50, 50, 50, 
-    50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 506, 506, 506, 
-    506, 506, 506, 506, 506, 506, 506, 50, 50, 50, 50, 50, 50, 50, 82, 50, 
-    50, 50, 50, 50, 50, 506, 82, 506, 506, 82, 82, 506, 82, 82, 506, 506, 82, 
-    82, 506, 506, 506, 506, 82, 506, 506, 50, 50, 82, 50, 82, 50, 50, 50, 50, 
-    50, 50, 50, 82, 50, 50, 50, 50, 50, 50, 50, 506, 506, 82, 506, 506, 506, 
-    506, 82, 82, 506, 506, 506, 506, 506, 506, 506, 506, 82, 506, 506, 506, 
-    506, 506, 506, 506, 82, 50, 50, 506, 506, 82, 506, 506, 506, 506, 82, 
-    506, 506, 506, 506, 506, 82, 506, 82, 82, 82, 506, 506, 506, 506, 506, 
-    506, 506, 82, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 82, 82, 
-    506, 969, 50, 50, 50, 50, 50, 50, 50, 50, 50, 513, 50, 50, 50, 50, 50, 
-    50, 506, 506, 506, 506, 506, 506, 506, 506, 506, 969, 50, 50, 50, 50, 50, 
-    50, 50, 50, 50, 513, 50, 50, 506, 506, 506, 506, 506, 969, 50, 50, 50, 
-    50, 50, 50, 50, 50, 50, 513, 50, 50, 50, 50, 50, 50, 506, 506, 506, 506, 
-    506, 506, 506, 506, 506, 969, 50, 513, 50, 50, 50, 50, 50, 50, 50, 50, 
-    506, 50, 82, 82, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 971, 
-    971, 971, 971, 971, 971, 971, 971, 972, 972, 972, 972, 972, 972, 972, 
-    972, 972, 972, 972, 972, 972, 972, 972, 971, 971, 971, 971, 972, 972, 
-    972, 972, 972, 972, 972, 972, 972, 972, 971, 971, 971, 971, 971, 971, 
-    971, 971, 972, 971, 971, 971, 971, 971, 971, 972, 971, 971, 973, 973, 
-    973, 973, 974, 82, 82, 82, 82, 82, 82, 82, 972, 972, 972, 972, 972, 82, 
-    972, 972, 972, 972, 972, 972, 972, 975, 975, 975, 975, 975, 975, 975, 82, 
-    975, 975, 975, 975, 975, 975, 975, 975, 975, 82, 82, 975, 975, 975, 975, 
-    975, 975, 975, 82, 975, 975, 82, 975, 975, 975, 975, 975, 82, 82, 82, 82, 
-    82, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 82, 
-    82, 977, 977, 977, 977, 977, 977, 977, 977, 977, 978, 978, 978, 978, 978, 
-    978, 978, 82, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 980, 980, 
-    980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 
-    980, 980, 981, 981, 981, 981, 981, 981, 982, 82, 82, 82, 82, 82, 983, 
-    983, 983, 983, 983, 983, 983, 983, 983, 983, 82, 82, 82, 82, 984, 984, 
-    147, 147, 147, 147, 82, 147, 147, 147, 82, 147, 147, 82, 147, 82, 82, 
-    147, 82, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 82, 147, 147, 
-    147, 147, 82, 147, 82, 147, 82, 82, 82, 82, 82, 82, 147, 82, 82, 82, 82, 
-    147, 82, 147, 82, 147, 82, 147, 147, 147, 82, 147, 82, 147, 82, 147, 82, 
-    147, 82, 147, 147, 147, 147, 82, 147, 82, 147, 147, 82, 147, 147, 147, 
-    147, 147, 147, 147, 147, 147, 82, 82, 82, 82, 82, 147, 147, 147, 82, 147, 
-    147, 147, 133, 133, 82, 82, 82, 82, 82, 82, 527, 527, 527, 527, 523, 527, 
-    527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 
-    985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 527, 527, 
-    527, 527, 527, 527, 527, 985, 985, 527, 527, 527, 527, 527, 527, 527, 
-    527, 527, 527, 527, 527, 527, 527, 523, 527, 527, 527, 527, 527, 527, 
-    985, 985, 48, 48, 48, 516, 516, 985, 985, 985, 528, 528, 528, 528, 528, 
-    528, 313, 985, 528, 528, 41, 41, 985, 985, 985, 985, 528, 528, 528, 528, 
-    528, 528, 986, 528, 528, 986, 986, 986, 986, 986, 986, 986, 986, 986, 
-    986, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 985, 985, 985, 
-    985, 985, 985, 985, 985, 985, 987, 987, 987, 987, 987, 987, 987, 987, 
-    987, 987, 988, 586, 586, 985, 985, 985, 985, 985, 586, 586, 586, 586, 
-    985, 985, 985, 985, 586, 985, 985, 985, 985, 985, 985, 985, 586, 586, 
-    985, 985, 985, 985, 985, 985, 523, 527, 527, 527, 527, 527, 527, 527, 
-    527, 527, 527, 527, 527, 523, 523, 523, 523, 523, 523, 523, 523, 523, 
-    527, 523, 523, 523, 523, 523, 523, 527, 523, 523, 523, 523, 523, 523, 
-    523, 534, 523, 523, 523, 523, 523, 523, 527, 527, 527, 527, 527, 527, 
-    527, 527, 41, 41, 527, 527, 523, 523, 523, 523, 523, 526, 526, 523, 523, 
-    523, 523, 523, 526, 523, 523, 523, 523, 523, 523, 534, 534, 523, 523, 
-    523, 523, 523, 534, 532, 527, 527, 527, 523, 523, 527, 527, 527, 523, 
-    527, 527, 527, 523, 523, 523, 989, 989, 989, 989, 989, 523, 523, 523, 
-    523, 523, 523, 523, 527, 523, 527, 534, 534, 523, 523, 534, 534, 534, 
-    534, 534, 534, 534, 534, 534, 534, 534, 523, 523, 523, 523, 523, 523, 
-    523, 523, 523, 523, 523, 523, 523, 534, 534, 534, 534, 523, 523, 523, 
-    523, 534, 523, 534, 523, 523, 523, 534, 523, 523, 523, 523, 534, 534, 
-    534, 523, 534, 534, 534, 526, 523, 526, 523, 526, 523, 523, 523, 523, 
-    523, 534, 523, 523, 523, 523, 526, 523, 526, 526, 523, 523, 523, 523, 
-    523, 523, 523, 523, 523, 523, 527, 527, 523, 526, 526, 526, 526, 526, 
-    526, 526, 523, 523, 523, 523, 523, 523, 523, 523, 526, 526, 526, 526, 
-    526, 526, 523, 523, 523, 523, 523, 526, 526, 526, 526, 526, 526, 526, 
-    526, 526, 526, 526, 526, 41, 41, 41, 41, 527, 523, 523, 523, 523, 527, 
-    527, 527, 527, 527, 527, 532, 527, 527, 527, 527, 534, 527, 527, 527, 
-    527, 527, 532, 527, 527, 527, 527, 534, 534, 527, 527, 527, 527, 527, 41, 
-    41, 41, 41, 41, 41, 41, 41, 527, 527, 527, 527, 41, 41, 527, 523, 523, 
-    523, 523, 523, 523, 523, 523, 523, 523, 534, 534, 534, 523, 523, 523, 
-    534, 534, 534, 534, 534, 41, 41, 41, 41, 41, 41, 536, 536, 536, 990, 990, 
-    990, 41, 41, 41, 41, 523, 523, 523, 534, 523, 523, 523, 523, 523, 523, 
-    523, 523, 534, 534, 534, 523, 534, 523, 523, 523, 523, 523, 527, 527, 
-    523, 523, 523, 985, 985, 985, 985, 985, 527, 527, 527, 523, 523, 985, 
-    985, 985, 527, 527, 527, 527, 523, 523, 523, 985, 41, 41, 41, 41, 985, 
-    985, 985, 985, 41, 41, 41, 41, 41, 985, 985, 985, 41, 41, 985, 985, 985, 
-    985, 985, 985, 41, 41, 41, 41, 41, 41, 985, 985, 534, 534, 534, 534, 534, 
-    534, 534, 985, 523, 523, 523, 523, 523, 523, 534, 523, 534, 985, 985, 
-    534, 534, 534, 534, 534, 534, 534, 523, 523, 534, 534, 534, 985, 523, 
-    523, 523, 523, 985, 985, 985, 985, 523, 523, 523, 523, 523, 523, 523, 
-    985, 523, 523, 985, 985, 985, 985, 985, 985, 523, 985, 985, 985, 985, 
-    985, 985, 985, 985, 985, 985, 985, 985, 985, 82, 82, 593, 593, 593, 593, 
-    593, 593, 593, 594, 593, 593, 593, 593, 593, 594, 594, 594, 594, 594, 
-    594, 594, 594, 594, 82, 82, 82, 499, 82, 82, 82, 82, 82, 82, 499, 499, 
-    499, 499, 499, 499, 499, 499, 671, 671, 671, 671, 671, 671, 82, 82, 
+    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, 81, 101, 101, 101, 101, 101, 101, 
+    101, 101, 101, 101, 101, 101, 101, 101, 101, 81, 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, 81, 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, 81, 81, 
+    81, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 
+    183, 183, 183, 183, 184, 183, 183, 183, 183, 183, 183, 183, 183, 183, 
+    184, 183, 183, 183, 184, 183, 183, 183, 183, 183, 81, 81, 185, 185, 185, 
+    185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 81, 186, 186, 
+    186, 186, 186, 186, 186, 186, 186, 187, 187, 187, 81, 81, 188, 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, 81, 139, 139, 139, 139, 139, 
+    139, 131, 157, 139, 139, 157, 139, 139, 157, 139, 139, 139, 157, 157, 
+    157, 189, 190, 191, 139, 139, 139, 157, 139, 139, 157, 157, 139, 139, 
+    139, 139, 139, 192, 192, 192, 193, 194, 194, 194, 194, 194, 194, 194, 
+    194, 194, 194, 194, 194, 194, 194, 192, 193, 195, 194, 193, 193, 193, 
+    192, 192, 192, 192, 192, 192, 192, 192, 193, 193, 193, 193, 196, 193, 
+    193, 194, 96, 156, 197, 197, 192, 192, 192, 194, 194, 192, 192, 198, 198, 
+    199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 200, 201, 194, 194, 
+    194, 194, 194, 194, 202, 203, 204, 204, 81, 202, 202, 202, 202, 202, 202, 
+    202, 202, 81, 81, 202, 202, 81, 81, 202, 202, 202, 202, 202, 202, 202, 
+    202, 202, 202, 202, 202, 202, 202, 81, 202, 202, 202, 202, 202, 202, 202, 
+    81, 202, 81, 81, 81, 202, 202, 202, 202, 81, 81, 205, 202, 204, 204, 204, 
+    203, 203, 203, 203, 81, 81, 204, 204, 81, 81, 204, 204, 206, 202, 81, 81, 
+    81, 81, 81, 81, 81, 81, 204, 81, 81, 81, 81, 202, 202, 81, 202, 202, 202, 
+    203, 203, 81, 81, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 202, 
+    202, 208, 208, 209, 209, 209, 209, 209, 210, 211, 212, 202, 213, 81, 81, 
+    81, 214, 214, 215, 81, 216, 216, 216, 216, 216, 216, 81, 81, 81, 81, 216, 
+    216, 81, 81, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 
+    216, 216, 81, 216, 216, 216, 216, 216, 216, 216, 81, 216, 216, 81, 216, 
+    216, 81, 216, 216, 81, 81, 217, 81, 215, 215, 215, 214, 214, 81, 81, 81, 
+    81, 214, 214, 81, 81, 214, 214, 218, 81, 81, 81, 214, 81, 81, 81, 81, 81, 
+    81, 81, 216, 216, 216, 216, 81, 216, 81, 81, 81, 81, 81, 81, 81, 219, 
+    219, 219, 219, 219, 219, 219, 219, 219, 219, 214, 214, 216, 216, 216, 
+    214, 81, 81, 81, 220, 220, 221, 81, 222, 222, 222, 222, 222, 222, 222, 
+    222, 222, 81, 222, 222, 222, 81, 222, 222, 222, 222, 222, 222, 222, 222, 
+    222, 222, 222, 222, 222, 222, 81, 222, 222, 222, 222, 222, 222, 222, 81, 
+    222, 222, 81, 222, 222, 222, 222, 222, 81, 81, 223, 222, 221, 221, 221, 
+    220, 220, 220, 220, 220, 81, 220, 220, 221, 81, 221, 221, 224, 81, 81, 
+    222, 81, 81, 81, 81, 81, 81, 81, 222, 222, 220, 220, 81, 81, 225, 225, 
+    225, 225, 225, 225, 225, 225, 225, 225, 226, 227, 81, 81, 81, 81, 81, 81, 
+    81, 222, 220, 220, 220, 220, 220, 220, 81, 228, 229, 229, 81, 230, 230, 
+    230, 230, 230, 230, 230, 230, 81, 81, 230, 230, 81, 81, 230, 230, 230, 
+    230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 81, 230, 230, 230, 
+    230, 230, 230, 230, 81, 230, 230, 81, 230, 230, 230, 230, 230, 81, 81, 
+    231, 230, 229, 228, 229, 228, 228, 228, 228, 81, 81, 229, 229, 81, 81, 
+    229, 229, 232, 81, 81, 81, 81, 81, 81, 81, 81, 228, 229, 81, 81, 81, 81, 
+    230, 230, 81, 230, 230, 230, 228, 228, 81, 81, 233, 233, 233, 233, 233, 
+    233, 233, 233, 233, 233, 234, 230, 235, 235, 235, 235, 235, 235, 81, 81, 
+    236, 237, 81, 237, 237, 237, 237, 237, 237, 81, 81, 81, 237, 237, 237, 
+    81, 237, 237, 237, 237, 81, 81, 81, 237, 237, 81, 237, 81, 237, 237, 81, 
+    81, 81, 237, 237, 81, 81, 81, 237, 237, 237, 237, 237, 237, 237, 237, 
+    237, 237, 81, 81, 81, 81, 238, 238, 236, 238, 238, 81, 81, 81, 238, 238, 
+    238, 81, 238, 238, 238, 239, 81, 81, 237, 81, 81, 81, 81, 81, 81, 238, 
+    81, 81, 81, 81, 81, 81, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 
+    241, 241, 241, 242, 242, 242, 242, 242, 242, 243, 242, 81, 81, 81, 81, 
+    81, 244, 245, 245, 245, 81, 246, 246, 246, 246, 246, 246, 246, 246, 81, 
+    246, 246, 246, 81, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 
+    246, 246, 246, 246, 246, 81, 81, 81, 246, 244, 244, 244, 245, 245, 245, 
+    245, 81, 244, 244, 244, 81, 244, 244, 244, 247, 81, 81, 81, 81, 81, 81, 
+    81, 248, 249, 81, 246, 246, 246, 81, 81, 81, 81, 81, 246, 246, 244, 244, 
+    81, 81, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 
+    251, 251, 251, 251, 252, 253, 254, 255, 255, 81, 253, 253, 253, 253, 253, 
+    253, 253, 253, 81, 253, 253, 253, 81, 253, 253, 253, 253, 253, 253, 253, 
+    253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 81, 253, 253, 253, 
+    253, 253, 81, 81, 256, 253, 255, 257, 255, 255, 255, 255, 255, 81, 257, 
+    255, 255, 81, 255, 255, 254, 258, 81, 81, 81, 81, 81, 81, 81, 255, 255, 
+    81, 81, 81, 81, 81, 81, 81, 253, 81, 253, 253, 254, 254, 81, 81, 259, 
+    259, 259, 259, 259, 259, 259, 259, 259, 259, 81, 253, 253, 81, 81, 81, 
+    81, 81, 260, 260, 261, 261, 81, 262, 262, 262, 262, 262, 262, 262, 262, 
+    81, 262, 262, 262, 81, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 
+    262, 262, 262, 262, 262, 262, 262, 263, 263, 262, 261, 261, 261, 260, 
+    260, 260, 260, 81, 261, 261, 261, 81, 261, 261, 261, 263, 262, 264, 81, 
+    81, 81, 81, 262, 262, 262, 261, 265, 265, 265, 265, 265, 265, 265, 262, 
+    262, 262, 260, 260, 81, 81, 266, 266, 266, 266, 266, 266, 266, 266, 266, 
+    266, 265, 265, 265, 265, 265, 265, 265, 265, 265, 267, 262, 262, 262, 
+    262, 262, 262, 81, 81, 268, 268, 81, 269, 269, 269, 269, 269, 269, 269, 
+    269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 81, 81, 81, 269, 
+    269, 269, 269, 269, 269, 269, 269, 81, 269, 269, 269, 269, 269, 269, 269, 
+    269, 269, 81, 269, 81, 81, 81, 81, 270, 81, 81, 81, 81, 268, 268, 268, 
+    271, 271, 271, 81, 271, 81, 268, 268, 268, 268, 268, 268, 268, 268, 81, 
+    81, 81, 81, 81, 81, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 81, 
+    81, 268, 268, 273, 81, 81, 81, 81, 274, 274, 274, 274, 274, 274, 274, 
+    274, 274, 274, 274, 274, 274, 274, 274, 274, 275, 274, 274, 275, 275, 
+    275, 275, 276, 276, 277, 81, 81, 81, 81, 278, 274, 274, 274, 274, 274, 
+    274, 279, 275, 280, 280, 280, 280, 275, 275, 275, 281, 282, 282, 282, 
+    282, 282, 282, 282, 282, 282, 282, 283, 283, 81, 81, 81, 81, 81, 284, 
+    284, 81, 284, 81, 81, 284, 284, 81, 284, 81, 81, 284, 81, 81, 81, 81, 81, 
+    81, 284, 284, 284, 284, 81, 284, 284, 284, 284, 284, 284, 284, 81, 284, 
+    284, 284, 81, 284, 81, 284, 81, 81, 284, 284, 81, 284, 284, 284, 284, 
+    285, 284, 284, 285, 285, 285, 285, 286, 286, 81, 285, 285, 284, 81, 81, 
+    284, 284, 284, 284, 284, 81, 287, 81, 288, 288, 288, 288, 285, 285, 81, 
+    81, 289, 289, 289, 289, 289, 289, 289, 289, 289, 289, 81, 81, 284, 284, 
+    284, 284, 290, 291, 291, 291, 292, 293, 292, 292, 294, 292, 292, 295, 
+    294, 296, 296, 296, 296, 296, 294, 297, 296, 297, 297, 297, 298, 298, 
+    297, 297, 297, 297, 297, 297, 299, 299, 299, 299, 299, 299, 299, 299, 
+    299, 299, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 301, 298, 
+    297, 298, 297, 302, 303, 304, 303, 304, 305, 305, 290, 290, 290, 290, 
+    290, 290, 290, 290, 81, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 
+    290, 290, 81, 81, 81, 81, 306, 307, 308, 309, 308, 308, 308, 308, 308, 
+    307, 307, 307, 307, 308, 310, 307, 308, 311, 311, 312, 295, 311, 311, 
+    290, 290, 290, 290, 290, 308, 308, 308, 308, 308, 308, 308, 308, 308, 
+    308, 308, 81, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 
+    81, 301, 301, 297, 297, 297, 297, 297, 297, 298, 297, 297, 297, 297, 297, 
+    297, 81, 297, 297, 292, 292, 295, 292, 293, 313, 313, 313, 313, 294, 294, 
+    81, 81, 81, 81, 81, 314, 314, 314, 314, 314, 314, 314, 314, 314, 314, 
+    314, 315, 315, 316, 316, 316, 316, 315, 316, 316, 316, 316, 316, 317, 
+    315, 318, 318, 315, 315, 316, 316, 314, 319, 319, 319, 319, 319, 319, 
+    319, 319, 319, 319, 320, 320, 321, 321, 321, 321, 314, 314, 314, 314, 
+    314, 314, 315, 315, 316, 316, 314, 314, 314, 314, 316, 316, 316, 314, 
+    315, 315, 315, 314, 314, 315, 315, 315, 315, 315, 315, 315, 314, 314, 
+    314, 316, 316, 316, 316, 314, 314, 314, 314, 314, 316, 315, 315, 316, 
+    316, 315, 315, 315, 315, 315, 315, 322, 314, 315, 319, 319, 315, 315, 
+    315, 316, 323, 323, 324, 324, 324, 324, 324, 324, 324, 324, 324, 324, 
+    324, 324, 324, 324, 81, 324, 81, 81, 81, 81, 81, 324, 81, 81, 325, 325, 
+    325, 325, 325, 325, 325, 325, 325, 325, 325, 326, 327, 325, 325, 325, 
+    328, 328, 328, 328, 328, 328, 328, 328, 329, 329, 329, 329, 329, 329, 
+    329, 329, 330, 330, 330, 330, 330, 330, 330, 330, 331, 331, 331, 331, 
+    331, 331, 331, 331, 331, 81, 331, 331, 331, 331, 81, 81, 331, 331, 331, 
+    331, 331, 331, 331, 81, 331, 331, 331, 81, 81, 332, 332, 332, 333, 334, 
+    333, 333, 333, 333, 333, 333, 333, 335, 335, 335, 335, 335, 335, 335, 
+    335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 81, 81, 
+    81, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 81, 81, 81, 81, 81, 
+    81, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 
+    81, 81, 338, 338, 338, 338, 338, 338, 81, 81, 339, 340, 340, 340, 340, 
+    340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 
+    340, 340, 341, 341, 340, 342, 343, 343, 343, 343, 343, 343, 343, 343, 
+    343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 344, 345, 81, 81, 81, 
+    346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 198, 198, 198, 
+    347, 347, 347, 346, 346, 346, 346, 346, 346, 346, 346, 81, 81, 81, 81, 
+    81, 81, 81, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 
+    348, 81, 348, 348, 348, 348, 349, 349, 350, 81, 81, 81, 351, 351, 351, 
+    351, 351, 351, 351, 351, 351, 351, 352, 352, 353, 198, 198, 81, 354, 354, 
+    354, 354, 354, 354, 354, 354, 354, 354, 355, 355, 81, 81, 81, 81, 356, 
+    356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 81, 356, 356, 
+    356, 81, 357, 357, 81, 81, 81, 81, 358, 358, 358, 358, 358, 358, 358, 
+    358, 358, 358, 358, 358, 359, 359, 360, 359, 359, 359, 359, 359, 359, 
+    359, 360, 360, 360, 360, 360, 360, 360, 360, 359, 360, 360, 359, 359, 
+    359, 359, 359, 359, 359, 359, 359, 361, 359, 362, 362, 363, 364, 362, 
+    365, 362, 366, 358, 367, 81, 81, 368, 368, 368, 368, 368, 368, 368, 368, 
+    368, 368, 81, 81, 81, 81, 81, 81, 369, 369, 369, 369, 369, 369, 369, 369, 
+    369, 369, 81, 81, 81, 81, 81, 81, 370, 370, 371, 371, 372, 373, 374, 370, 
+    375, 375, 370, 376, 376, 376, 377, 81, 378, 378, 378, 378, 378, 378, 378, 
+    378, 378, 378, 81, 81, 81, 81, 81, 81, 379, 379, 379, 379, 379, 379, 379, 
+    379, 379, 379, 379, 380, 379, 379, 379, 379, 379, 379, 379, 379, 379, 
+    376, 376, 379, 379, 381, 379, 81, 81, 81, 81, 81, 340, 340, 340, 340, 
+    340, 340, 81, 81, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 
+    382, 382, 382, 382, 81, 383, 383, 383, 384, 384, 384, 384, 383, 383, 384, 
+    384, 384, 81, 81, 81, 81, 384, 384, 383, 384, 384, 384, 384, 384, 384, 
+    385, 386, 387, 81, 81, 81, 81, 388, 81, 81, 81, 389, 389, 390, 390, 390, 
+    390, 390, 390, 390, 390, 390, 390, 391, 391, 391, 391, 391, 391, 391, 
+    391, 391, 391, 391, 391, 391, 391, 81, 81, 391, 391, 391, 391, 391, 81, 
+    81, 81, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 392, 81, 
+    81, 81, 81, 392, 392, 81, 81, 81, 81, 81, 81, 393, 393, 393, 393, 393, 
+    393, 393, 393, 393, 393, 394, 81, 81, 81, 395, 395, 396, 396, 396, 396, 
+    396, 396, 396, 396, 397, 397, 397, 397, 397, 397, 397, 397, 397, 397, 
+    397, 397, 397, 397, 397, 398, 399, 400, 400, 401, 81, 81, 402, 402, 403, 
+    403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 404, 405, 
+    404, 405, 405, 405, 405, 405, 405, 405, 81, 406, 404, 405, 404, 404, 405, 
+    405, 405, 405, 405, 405, 405, 405, 404, 404, 404, 404, 404, 404, 405, 
+    405, 407, 407, 407, 407, 407, 407, 407, 407, 81, 81, 408, 409, 409, 409, 
+    409, 409, 409, 409, 409, 409, 409, 81, 81, 81, 81, 81, 81, 410, 410, 410, 
+    410, 410, 410, 410, 411, 410, 410, 410, 410, 410, 410, 81, 81, 96, 96, 
+    96, 96, 96, 156, 156, 156, 156, 156, 156, 96, 96, 156, 412, 81, 413, 413, 
+    413, 413, 414, 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, 415, 
+    415, 415, 415, 415, 416, 414, 413, 413, 413, 413, 413, 414, 413, 414, 
+    414, 414, 414, 414, 413, 414, 417, 415, 415, 415, 415, 415, 415, 415, 81, 
+    81, 81, 81, 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, 419, 419, 
+    420, 419, 419, 419, 419, 421, 421, 421, 421, 421, 421, 421, 421, 421, 
+    421, 422, 423, 422, 422, 422, 422, 422, 422, 422, 421, 421, 421, 421, 
+    421, 421, 421, 421, 421, 81, 81, 81, 424, 424, 425, 426, 426, 426, 426, 
+    426, 426, 426, 426, 426, 426, 426, 426, 426, 426, 425, 424, 424, 424, 
+    424, 425, 425, 424, 424, 427, 428, 424, 424, 426, 426, 429, 429, 429, 
+    429, 429, 429, 429, 429, 429, 429, 426, 426, 426, 426, 426, 426, 430, 
+    430, 430, 430, 430, 430, 430, 430, 430, 430, 430, 430, 430, 430, 431, 
+    432, 433, 433, 432, 432, 432, 433, 432, 433, 433, 433, 434, 434, 81, 81, 
+    81, 81, 81, 81, 81, 81, 435, 435, 435, 435, 436, 436, 436, 436, 436, 436, 
+    436, 436, 436, 436, 436, 436, 437, 437, 437, 437, 437, 437, 437, 437, 
+    438, 438, 438, 438, 438, 438, 438, 438, 437, 437, 438, 439, 81, 81, 81, 
+    440, 440, 440, 440, 440, 441, 441, 441, 441, 441, 441, 441, 441, 441, 
+    441, 81, 81, 81, 436, 436, 436, 442, 442, 442, 442, 442, 442, 442, 442, 
+    442, 442, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 
+    443, 443, 444, 444, 444, 444, 444, 444, 445, 445, 93, 81, 81, 81, 81, 81, 
+    81, 81, 446, 446, 446, 446, 446, 446, 446, 446, 96, 96, 96, 326, 447, 
+    156, 156, 156, 156, 156, 96, 96, 156, 156, 156, 156, 96, 448, 447, 447, 
+    447, 447, 447, 447, 447, 449, 449, 449, 449, 156, 449, 449, 449, 449, 
+    448, 448, 96, 449, 449, 448, 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, 450, 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, 451, 452, 156, 453, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 
+    96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 454, 455, 455, 156, 81, 96, 456, 
+    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, 457, 457, 457, 457, 457, 457, 457, 457, 79, 79, 79, 
+    79, 79, 81, 79, 79, 78, 78, 78, 78, 457, 80, 79, 80, 80, 80, 79, 79, 79, 
+    81, 79, 79, 78, 78, 78, 78, 457, 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, 457, 458, 80, 81, 459, 459, 
+    459, 459, 459, 459, 459, 460, 459, 459, 459, 461, 462, 463, 464, 465, 
+    466, 467, 468, 466, 469, 470, 38, 84, 471, 472, 473, 42, 471, 472, 473, 
+    42, 38, 38, 474, 84, 475, 475, 475, 476, 477, 478, 479, 480, 481, 482, 
+    483, 33, 484, 485, 484, 484, 485, 486, 487, 487, 84, 42, 50, 38, 488, 
+    488, 474, 489, 489, 84, 84, 84, 490, 473, 491, 488, 488, 488, 84, 84, 84, 
+    84, 84, 84, 84, 84, 492, 84, 489, 84, 373, 84, 373, 373, 373, 373, 84, 
+    373, 373, 459, 493, 494, 494, 494, 494, 81, 495, 496, 497, 498, 499, 499, 
+    499, 499, 499, 499, 500, 59, 81, 81, 47, 500, 500, 500, 500, 500, 501, 
+    501, 492, 473, 491, 502, 500, 47, 47, 47, 47, 500, 500, 500, 500, 500, 
+    501, 501, 492, 473, 491, 81, 59, 59, 59, 59, 59, 81, 81, 81, 278, 278, 
+    278, 278, 278, 278, 278, 503, 278, 504, 278, 278, 36, 278, 278, 278, 278, 
+    278, 278, 278, 278, 278, 503, 278, 278, 278, 278, 503, 278, 278, 503, 
+    278, 505, 505, 505, 505, 505, 505, 505, 505, 96, 96, 447, 447, 96, 96, 
+    96, 96, 447, 447, 447, 96, 96, 412, 412, 412, 412, 96, 412, 412, 412, 
+    447, 447, 96, 156, 96, 447, 447, 156, 156, 156, 156, 96, 81, 81, 81, 81, 
+    81, 81, 81, 40, 40, 506, 507, 40, 508, 40, 506, 40, 507, 49, 506, 506, 
+    506, 49, 49, 506, 506, 506, 509, 40, 506, 510, 40, 492, 506, 506, 506, 
+    506, 506, 40, 40, 40, 508, 508, 40, 506, 40, 85, 40, 506, 40, 52, 511, 
+    506, 506, 512, 49, 506, 506, 52, 506, 49, 449, 449, 449, 449, 49, 40, 40, 
+    49, 49, 506, 506, 492, 492, 492, 492, 492, 506, 49, 49, 49, 49, 40, 492, 
+    40, 40, 56, 313, 513, 513, 513, 514, 51, 515, 513, 513, 513, 513, 513, 
+    51, 514, 514, 51, 513, 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, 
+    516, 516, 517, 517, 517, 517, 516, 516, 517, 517, 517, 517, 517, 517, 
+    517, 517, 517, 52, 56, 517, 517, 517, 517, 51, 40, 40, 81, 81, 81, 81, 
+    54, 54, 54, 54, 54, 508, 508, 508, 508, 508, 492, 492, 40, 40, 40, 40, 
+    492, 40, 40, 492, 40, 40, 492, 40, 40, 40, 40, 40, 40, 40, 492, 40, 40, 
+    40, 40, 40, 40, 40, 40, 40, 44, 44, 40, 40, 40, 40, 40, 40, 40, 40, 40, 
+    40, 40, 40, 492, 492, 40, 40, 54, 40, 54, 40, 40, 40, 40, 40, 40, 40, 40, 
+    40, 40, 44, 40, 40, 40, 40, 492, 492, 492, 492, 492, 492, 492, 492, 492, 
+    492, 492, 492, 54, 492, 54, 54, 492, 492, 492, 54, 54, 492, 492, 54, 492, 
+    492, 492, 54, 492, 54, 518, 519, 492, 54, 492, 492, 492, 492, 54, 492, 
+    492, 54, 54, 54, 54, 492, 492, 54, 492, 54, 492, 54, 54, 54, 54, 54, 54, 
+    492, 54, 492, 492, 492, 492, 492, 54, 54, 54, 54, 492, 492, 492, 492, 54, 
+    54, 492, 492, 54, 492, 492, 492, 54, 492, 492, 492, 492, 492, 54, 492, 
+    492, 492, 492, 492, 54, 54, 492, 492, 54, 54, 54, 54, 492, 492, 54, 54, 
+    492, 492, 54, 54, 492, 492, 492, 492, 492, 54, 492, 492, 492, 54, 492, 
+    492, 492, 492, 492, 492, 492, 492, 492, 492, 492, 492, 492, 54, 492, 492, 
+    492, 492, 492, 492, 492, 520, 473, 491, 473, 491, 40, 40, 40, 40, 40, 40, 
+    508, 40, 40, 40, 40, 40, 40, 40, 521, 521, 40, 40, 40, 40, 492, 492, 40, 
+    40, 40, 40, 40, 40, 40, 522, 523, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 
+    40, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 40, 
+    492, 40, 40, 40, 40, 40, 40, 40, 40, 313, 40, 40, 40, 40, 40, 492, 492, 
+    492, 492, 492, 492, 492, 492, 492, 40, 40, 40, 40, 40, 524, 524, 524, 
+    524, 40, 40, 40, 521, 525, 525, 521, 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, 526, 526, 526, 526, 
+    526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 515, 51, 51, 51, 51, 
+    51, 51, 51, 51, 51, 51, 51, 51, 514, 508, 508, 508, 508, 508, 508, 508, 
+    508, 508, 508, 508, 508, 40, 40, 40, 40, 508, 508, 508, 508, 527, 40, 40, 
+    40, 40, 40, 508, 508, 508, 508, 40, 40, 508, 508, 40, 508, 508, 508, 508, 
+    508, 508, 508, 40, 40, 40, 40, 40, 40, 40, 40, 508, 508, 40, 40, 508, 54, 
+    40, 40, 40, 40, 508, 508, 40, 40, 508, 54, 40, 40, 40, 40, 508, 508, 508, 
+    40, 40, 508, 40, 40, 508, 508, 40, 40, 40, 40, 40, 40, 40, 508, 492, 492, 
+    492, 492, 492, 528, 528, 492, 525, 525, 525, 525, 40, 508, 508, 40, 40, 
+    508, 40, 40, 40, 40, 508, 508, 40, 40, 40, 40, 521, 521, 527, 527, 525, 
+    40, 525, 525, 529, 530, 529, 525, 40, 525, 525, 525, 40, 40, 40, 40, 508, 
+    40, 508, 40, 40, 40, 40, 40, 524, 524, 524, 524, 524, 524, 524, 524, 524, 
+    524, 524, 524, 40, 40, 40, 40, 508, 508, 40, 508, 508, 508, 40, 508, 529, 
+    508, 508, 40, 508, 508, 40, 54, 40, 40, 40, 40, 40, 40, 40, 521, 40, 40, 
+    40, 524, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 508, 508, 40, 524, 40, 
+    40, 40, 40, 40, 40, 40, 40, 524, 524, 313, 40, 40, 40, 40, 40, 40, 40, 
+    40, 521, 521, 529, 525, 525, 525, 525, 521, 521, 529, 529, 529, 508, 508, 
+    508, 508, 529, 524, 529, 529, 529, 508, 529, 521, 508, 508, 508, 529, 
+    529, 508, 508, 529, 508, 508, 529, 529, 529, 40, 508, 40, 40, 40, 40, 
+    508, 508, 521, 508, 508, 508, 508, 508, 508, 529, 521, 521, 529, 521, 
+    508, 529, 529, 531, 521, 508, 508, 521, 529, 529, 525, 525, 525, 525, 
+    525, 524, 40, 40, 525, 525, 532, 532, 530, 530, 40, 40, 524, 40, 40, 40, 
+    40, 40, 40, 40, 40, 40, 40, 40, 40, 44, 40, 40, 40, 40, 40, 40, 524, 40, 
+    524, 40, 40, 40, 40, 524, 524, 524, 40, 533, 40, 40, 40, 534, 534, 534, 
+    534, 534, 534, 40, 535, 535, 525, 40, 40, 40, 473, 491, 473, 491, 473, 
+    491, 473, 491, 473, 491, 473, 491, 473, 491, 51, 51, 515, 515, 515, 515, 
+    515, 515, 515, 515, 515, 515, 515, 515, 40, 524, 524, 524, 40, 40, 40, 
+    40, 40, 40, 40, 524, 492, 492, 492, 492, 492, 473, 491, 492, 492, 492, 
+    492, 492, 492, 492, 16, 31, 16, 31, 16, 31, 16, 31, 473, 491, 536, 536, 
+    536, 536, 536, 536, 536, 536, 492, 492, 492, 473, 491, 16, 31, 473, 491, 
+    473, 491, 473, 491, 473, 491, 473, 491, 492, 492, 492, 492, 492, 492, 
+    492, 473, 491, 473, 491, 492, 492, 492, 492, 492, 492, 492, 492, 473, 
+    491, 492, 492, 40, 40, 40, 524, 524, 40, 40, 40, 492, 492, 492, 492, 492, 
+    40, 40, 492, 492, 492, 492, 492, 492, 40, 40, 40, 524, 40, 40, 40, 40, 
+    533, 508, 508, 40, 40, 40, 40, 81, 81, 40, 40, 40, 40, 40, 40, 40, 40, 
+    81, 81, 40, 40, 81, 81, 81, 40, 40, 40, 40, 81, 40, 40, 40, 40, 40, 40, 
+    81, 81, 81, 81, 40, 40, 40, 40, 537, 537, 537, 537, 537, 537, 537, 537, 
+    537, 537, 537, 537, 537, 537, 537, 81, 538, 538, 538, 538, 538, 538, 538, 
+    538, 538, 538, 538, 538, 538, 538, 538, 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, 539, 539, 539, 539, 539, 
+    539, 87, 88, 87, 88, 540, 540, 540, 87, 88, 81, 81, 81, 81, 81, 541, 542, 
+    542, 542, 543, 541, 542, 544, 544, 544, 544, 544, 544, 544, 544, 544, 
+    544, 544, 544, 544, 544, 81, 544, 81, 81, 81, 81, 81, 544, 81, 81, 545, 
+    545, 545, 545, 545, 545, 545, 545, 81, 81, 81, 81, 81, 81, 81, 546, 547, 
+    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 548, 95, 95, 95, 
+    95, 95, 95, 95, 95, 549, 549, 42, 50, 42, 50, 549, 549, 549, 42, 50, 549, 
+    42, 50, 373, 373, 373, 373, 373, 373, 373, 373, 84, 468, 550, 373, 551, 
+    84, 42, 50, 84, 84, 42, 50, 473, 491, 473, 491, 473, 491, 473, 491, 373, 
+    373, 373, 373, 371, 60, 373, 373, 84, 373, 373, 84, 84, 84, 84, 84, 552, 
+    552, 373, 373, 373, 84, 468, 373, 473, 373, 373, 373, 373, 373, 373, 373, 
+    81, 81, 81, 81, 81, 81, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 
+    81, 553, 553, 553, 553, 553, 553, 553, 553, 553, 81, 81, 81, 81, 553, 
+    553, 553, 553, 553, 553, 81, 81, 521, 521, 521, 521, 521, 521, 521, 521, 
+    521, 521, 521, 521, 81, 81, 81, 81, 554, 555, 555, 556, 521, 557, 558, 
+    559, 522, 523, 522, 523, 522, 523, 522, 523, 522, 523, 521, 521, 522, 
+    523, 522, 523, 522, 523, 522, 523, 560, 522, 523, 523, 521, 559, 559, 
+    559, 559, 559, 559, 559, 559, 559, 561, 562, 563, 564, 565, 565, 566, 
+    567, 567, 567, 567, 568, 521, 521, 559, 559, 559, 557, 569, 556, 521, 
+    525, 81, 570, 571, 570, 571, 570, 571, 570, 571, 570, 571, 571, 571, 571, 
+    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 570, 
+    571, 571, 571, 571, 571, 571, 571, 570, 571, 570, 571, 570, 571, 571, 
+    571, 571, 571, 571, 570, 571, 571, 571, 571, 571, 571, 570, 570, 81, 81, 
+    572, 572, 573, 573, 574, 574, 571, 560, 575, 576, 575, 576, 575, 576, 
+    575, 576, 575, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 
+    576, 576, 576, 576, 576, 576, 575, 576, 576, 576, 576, 576, 576, 576, 
+    575, 576, 575, 576, 575, 576, 576, 576, 576, 576, 576, 575, 576, 576, 
+    576, 576, 576, 576, 575, 575, 576, 576, 576, 576, 577, 578, 579, 579, 
+    576, 81, 81, 81, 81, 81, 580, 580, 580, 580, 580, 580, 580, 580, 580, 
+    580, 580, 580, 580, 580, 580, 580, 580, 580, 81, 81, 581, 581, 581, 581, 
+    581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 
+    581, 581, 581, 581, 81, 582, 582, 583, 583, 583, 583, 582, 582, 582, 582, 
+    582, 582, 582, 582, 582, 582, 580, 580, 580, 81, 81, 81, 81, 81, 575, 
+    575, 575, 575, 575, 575, 575, 575, 584, 584, 584, 584, 584, 584, 584, 
+    584, 584, 584, 584, 584, 584, 585, 585, 81, 583, 583, 583, 583, 583, 583, 
+    583, 583, 583, 583, 582, 582, 582, 582, 582, 582, 586, 586, 586, 586, 
+    586, 586, 586, 586, 521, 587, 587, 587, 587, 587, 587, 587, 587, 587, 
+    587, 587, 587, 587, 587, 587, 584, 584, 584, 584, 585, 585, 585, 582, 
+    582, 587, 587, 587, 587, 587, 587, 587, 582, 582, 582, 582, 521, 521, 
+    521, 521, 588, 588, 588, 588, 588, 588, 588, 588, 588, 588, 588, 588, 
+    588, 588, 588, 81, 582, 582, 582, 582, 582, 582, 582, 521, 521, 521, 521, 
+    582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 521, 521, 589, 
+    589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 590, 
+    590, 590, 590, 590, 590, 590, 590, 590, 590, 589, 589, 589, 590, 590, 
+    590, 590, 590, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 
+    591, 591, 592, 591, 591, 591, 591, 591, 591, 591, 81, 81, 81, 593, 593, 
+    593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 81, 594, 
+    594, 594, 594, 594, 594, 594, 594, 595, 595, 595, 595, 595, 595, 596, 
+    596, 597, 597, 597, 597, 597, 597, 597, 597, 597, 597, 597, 597, 598, 
+    599, 600, 599, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 597, 
+    597, 81, 81, 81, 81, 90, 93, 90, 93, 90, 93, 602, 95, 97, 97, 97, 603, 
+    95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 603, 604, 90, 93, 90, 93, 450, 
+    450, 95, 95, 605, 605, 605, 605, 605, 605, 605, 605, 605, 605, 605, 605, 
+    605, 605, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 607, 607, 
+    608, 609, 609, 609, 609, 609, 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, 610, 610, 52, 56, 52, 56, 57, 52, 56, 52, 56, 56, 56, 52, 56, 52, 
+    56, 52, 52, 52, 52, 52, 81, 52, 52, 52, 52, 52, 56, 52, 56, 81, 81, 81, 
+    81, 81, 81, 81, 57, 59, 59, 56, 57, 57, 57, 57, 57, 611, 611, 612, 611, 
+    611, 611, 613, 611, 611, 611, 611, 612, 611, 611, 611, 611, 611, 611, 
+    611, 611, 611, 611, 611, 611, 611, 611, 611, 614, 614, 612, 612, 614, 
+    615, 615, 615, 615, 81, 81, 81, 81, 616, 616, 616, 616, 616, 616, 313, 
+    313, 503, 512, 81, 81, 81, 81, 81, 81, 617, 617, 617, 617, 617, 617, 617, 
+    617, 617, 617, 617, 617, 618, 618, 619, 619, 620, 620, 621, 621, 621, 
+    621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 
+    621, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 
+    620, 620, 620, 622, 623, 81, 81, 81, 81, 81, 81, 81, 81, 624, 624, 625, 
+    625, 625, 625, 625, 625, 625, 625, 625, 625, 81, 81, 81, 81, 81, 81, 197, 
+    197, 197, 197, 197, 197, 197, 197, 197, 197, 194, 194, 194, 194, 194, 
+    194, 200, 200, 200, 194, 626, 194, 81, 81, 627, 627, 627, 627, 627, 627, 
+    627, 627, 627, 627, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 
+    628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 629, 629, 629, 629, 
+    629, 630, 630, 630, 198, 631, 632, 632, 632, 632, 632, 632, 632, 632, 
+    632, 632, 632, 632, 632, 632, 632, 633, 633, 633, 633, 633, 633, 633, 
+    633, 633, 633, 633, 634, 635, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 
+    636, 328, 328, 328, 328, 328, 81, 81, 81, 637, 637, 637, 638, 639, 639, 
+    639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 640, 
+    638, 638, 637, 637, 637, 637, 638, 638, 637, 638, 638, 638, 641, 642, 
+    642, 642, 642, 642, 642, 643, 643, 643, 642, 642, 642, 642, 81, 61, 644, 
+    644, 644, 644, 644, 644, 644, 644, 644, 644, 81, 81, 81, 81, 642, 642, 
+    314, 314, 314, 314, 314, 316, 645, 314, 319, 319, 314, 314, 314, 314, 
+    314, 81, 646, 646, 646, 646, 646, 646, 646, 646, 646, 647, 647, 647, 647, 
+    647, 647, 648, 648, 647, 647, 648, 648, 647, 647, 81, 646, 646, 646, 647, 
+    646, 646, 646, 646, 646, 646, 646, 646, 647, 648, 81, 81, 649, 649, 649, 
+    649, 649, 649, 649, 649, 649, 649, 81, 81, 650, 651, 651, 651, 645, 314, 
+    314, 314, 314, 314, 314, 323, 323, 323, 314, 315, 316, 315, 314, 314, 
+    652, 652, 652, 652, 652, 652, 652, 652, 653, 652, 653, 653, 654, 652, 
+    652, 653, 653, 652, 652, 652, 652, 652, 653, 653, 652, 653, 652, 81, 81, 
+    81, 81, 81, 81, 81, 81, 652, 652, 655, 656, 656, 657, 657, 657, 657, 657, 
+    657, 657, 657, 657, 657, 657, 658, 659, 659, 658, 658, 660, 660, 657, 
+    661, 661, 658, 662, 81, 81, 331, 331, 331, 331, 331, 331, 81, 56, 56, 56, 
+    610, 59, 59, 59, 59, 56, 56, 56, 56, 56, 79, 81, 81, 338, 338, 338, 338, 
+    338, 338, 338, 338, 657, 657, 657, 658, 658, 659, 658, 658, 659, 658, 
+    658, 660, 658, 662, 81, 81, 663, 663, 663, 663, 663, 663, 663, 663, 663, 
+    663, 81, 81, 81, 81, 81, 81, 664, 665, 665, 665, 665, 665, 665, 665, 665, 
+    665, 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, 664, 665, 665, 
+    665, 665, 665, 665, 665, 81, 81, 81, 81, 329, 329, 329, 329, 329, 329, 
+    329, 81, 81, 81, 81, 330, 330, 330, 330, 330, 330, 330, 330, 330, 81, 81, 
+    81, 81, 666, 666, 666, 666, 666, 666, 666, 666, 667, 667, 667, 667, 667, 
+    667, 667, 667, 589, 589, 590, 590, 590, 590, 590, 590, 56, 56, 56, 56, 
+    56, 56, 56, 81, 81, 81, 81, 101, 101, 101, 101, 101, 81, 81, 81, 81, 81, 
+    129, 668, 129, 129, 669, 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, 670, 670, 670, 670, 670, 670, 670, 
+    670, 670, 670, 670, 670, 670, 670, 670, 670, 81, 81, 81, 81, 81, 81, 81, 
+    81, 81, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 491, 473, 
+    81, 81, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 135, 138, 81, 
+    81, 671, 671, 671, 671, 671, 671, 671, 671, 672, 555, 555, 672, 672, 673, 
+    673, 522, 523, 674, 81, 81, 81, 81, 81, 81, 96, 96, 96, 96, 96, 96, 96, 
+    156, 156, 156, 156, 156, 156, 156, 95, 95, 556, 566, 566, 675, 675, 522, 
+    523, 522, 523, 522, 523, 522, 523, 522, 523, 522, 523, 522, 523, 522, 
+    523, 556, 556, 522, 523, 556, 556, 556, 556, 675, 675, 675, 676, 556, 
+    676, 81, 577, 677, 673, 673, 566, 522, 523, 522, 523, 522, 523, 678, 556, 
+    556, 679, 680, 681, 681, 681, 81, 556, 682, 683, 556, 81, 81, 81, 81, 
+    146, 146, 146, 146, 146, 81, 81, 493, 81, 684, 685, 686, 687, 688, 685, 
+    685, 689, 690, 685, 691, 692, 693, 692, 694, 695, 695, 695, 695, 695, 
+    695, 695, 695, 695, 695, 696, 697, 698, 698, 698, 684, 685, 699, 699, 
+    699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 
+    699, 699, 689, 685, 690, 700, 701, 700, 702, 702, 702, 702, 702, 702, 
+    702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 689, 698, 
+    690, 698, 689, 690, 703, 704, 705, 703, 706, 707, 708, 708, 708, 708, 
+    708, 708, 708, 708, 708, 709, 707, 707, 707, 707, 707, 707, 707, 707, 
+    707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 710, 
+    710, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 
+    711, 711, 81, 81, 81, 711, 711, 711, 711, 711, 711, 81, 81, 711, 711, 
+    711, 81, 81, 81, 712, 687, 698, 700, 713, 687, 687, 81, 714, 715, 715, 
+    715, 715, 714, 714, 81, 81, 716, 716, 716, 717, 508, 81, 81, 718, 718, 
+    718, 718, 718, 718, 718, 718, 718, 718, 718, 718, 81, 718, 718, 718, 718, 
+    718, 718, 718, 718, 718, 718, 81, 718, 718, 718, 81, 718, 718, 81, 718, 
+    718, 718, 718, 718, 718, 718, 81, 81, 718, 718, 718, 81, 81, 81, 81, 81, 
+    198, 373, 198, 81, 81, 81, 81, 616, 616, 616, 616, 616, 616, 616, 616, 
+    616, 616, 616, 616, 616, 81, 81, 81, 313, 719, 719, 719, 719, 719, 719, 
+    719, 719, 719, 719, 719, 719, 719, 720, 720, 720, 720, 721, 721, 721, 
+    721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 
+    720, 720, 721, 722, 722, 81, 40, 40, 40, 40, 81, 81, 81, 81, 721, 81, 81, 
+    81, 81, 81, 81, 81, 313, 313, 313, 313, 313, 156, 81, 81, 723, 723, 723, 
+    723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 81, 81, 81, 724, 724, 
+    724, 724, 724, 724, 724, 724, 724, 81, 81, 81, 81, 81, 81, 81, 156, 500, 
+    500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 
+    500, 500, 500, 500, 81, 81, 81, 81, 725, 725, 725, 725, 725, 725, 725, 
+    725, 726, 726, 726, 726, 81, 81, 81, 81, 81, 81, 81, 81, 81, 725, 725, 
+    725, 727, 727, 727, 727, 727, 727, 727, 727, 727, 728, 727, 727, 727, 
+    727, 727, 727, 727, 727, 728, 81, 81, 81, 81, 81, 729, 729, 729, 729, 
+    729, 729, 729, 729, 729, 729, 729, 729, 729, 729, 730, 730, 730, 730, 
+    730, 81, 81, 81, 81, 81, 731, 731, 731, 731, 731, 731, 731, 731, 731, 
+    731, 731, 731, 731, 731, 81, 732, 733, 733, 733, 733, 733, 733, 733, 733, 
+    733, 733, 733, 733, 81, 81, 81, 81, 734, 735, 735, 735, 735, 735, 81, 81, 
+    736, 736, 736, 736, 736, 736, 736, 736, 737, 737, 737, 737, 737, 737, 
+    737, 737, 738, 738, 738, 738, 738, 738, 738, 738, 739, 739, 739, 739, 
+    739, 739, 739, 739, 739, 739, 739, 739, 739, 739, 81, 81, 740, 740, 740, 
+    740, 740, 740, 740, 740, 740, 740, 81, 81, 81, 81, 81, 81, 741, 741, 741, 
+    741, 741, 741, 741, 741, 741, 741, 741, 741, 81, 81, 81, 81, 742, 742, 
+    742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 81, 81, 81, 81, 743, 
+    743, 743, 743, 743, 743, 743, 743, 744, 744, 744, 744, 744, 744, 744, 
+    744, 744, 744, 744, 744, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 745, 
+    746, 746, 746, 746, 746, 746, 746, 746, 746, 746, 746, 746, 746, 746, 
+    746, 81, 746, 746, 746, 746, 746, 746, 81, 81, 747, 747, 747, 747, 747, 
+    747, 81, 81, 747, 81, 747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 
+    747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 81, 747, 747, 81, 81, 
+    81, 747, 81, 81, 747, 748, 748, 748, 748, 748, 748, 748, 748, 748, 748, 
+    748, 748, 748, 748, 81, 749, 750, 750, 750, 750, 750, 750, 750, 750, 751, 
+    751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 
+    752, 752, 753, 753, 753, 753, 753, 753, 753, 754, 754, 754, 754, 754, 
+    754, 754, 754, 754, 754, 754, 754, 754, 754, 754, 81, 81, 81, 81, 81, 81, 
+    81, 81, 755, 755, 755, 755, 755, 755, 755, 755, 755, 756, 756, 756, 756, 
+    756, 756, 756, 756, 756, 756, 756, 81, 756, 756, 81, 81, 81, 81, 81, 757, 
+    757, 757, 757, 757, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 759, 759, 759, 759, 759, 759, 81, 81, 81, 760, 761, 
+    761, 761, 761, 761, 761, 761, 761, 761, 761, 81, 81, 81, 81, 81, 762, 
+    763, 763, 763, 763, 763, 763, 763, 763, 764, 764, 764, 764, 764, 764, 
+    764, 764, 81, 81, 81, 81, 765, 765, 764, 764, 765, 765, 765, 765, 765, 
+    765, 765, 765, 81, 81, 765, 765, 765, 765, 765, 765, 766, 767, 767, 767, 
+    81, 767, 767, 81, 81, 81, 81, 81, 767, 768, 767, 769, 766, 766, 766, 766, 
+    81, 766, 766, 766, 81, 766, 766, 766, 766, 766, 766, 766, 766, 766, 766, 
+    766, 766, 766, 766, 766, 766, 766, 766, 766, 81, 81, 81, 81, 769, 770, 
+    768, 81, 81, 81, 81, 771, 772, 772, 772, 772, 772, 772, 772, 772, 773, 
+    773, 773, 773, 773, 773, 773, 773, 774, 81, 81, 81, 81, 81, 81, 81, 775, 
+    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 776, 776, 
+    777, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 
+    779, 779, 779, 780, 780, 780, 780, 780, 780, 780, 780, 781, 780, 780, 
+    780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 782, 783, 81, 81, 81, 
+    81, 784, 784, 784, 784, 784, 785, 785, 785, 785, 785, 785, 786, 81, 787, 
+    787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 81, 81, 
+    81, 788, 788, 788, 788, 788, 788, 788, 789, 789, 789, 789, 789, 789, 789, 
+    789, 789, 789, 789, 789, 789, 789, 81, 81, 790, 790, 790, 790, 790, 790, 
+    790, 790, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 81, 81, 
+    81, 81, 81, 792, 792, 792, 792, 792, 792, 792, 792, 793, 793, 793, 793, 
+    793, 793, 793, 793, 793, 793, 81, 81, 81, 81, 81, 81, 81, 794, 794, 794, 
+    794, 81, 81, 81, 81, 795, 795, 795, 795, 795, 795, 795, 796, 796, 796, 
+    796, 796, 796, 796, 796, 796, 81, 81, 81, 81, 81, 81, 81, 797, 797, 797, 
+    797, 797, 797, 797, 797, 797, 797, 797, 81, 81, 81, 81, 81, 798, 798, 
+    798, 798, 798, 798, 798, 798, 798, 798, 798, 81, 81, 81, 81, 81, 81, 81, 
+    799, 799, 799, 799, 799, 799, 800, 800, 800, 800, 800, 800, 800, 800, 
+    800, 800, 800, 800, 800, 800, 800, 81, 801, 802, 801, 803, 803, 803, 803, 
+    803, 803, 803, 803, 803, 803, 803, 803, 803, 802, 802, 802, 802, 802, 
+    802, 802, 802, 802, 802, 802, 802, 802, 802, 804, 805, 805, 806, 806, 
+    806, 806, 806, 81, 81, 81, 81, 807, 807, 807, 807, 807, 807, 807, 807, 
+    807, 807, 807, 807, 807, 807, 807, 807, 807, 807, 807, 807, 808, 808, 
+    808, 808, 808, 808, 808, 808, 808, 808, 81, 81, 81, 81, 81, 81, 81, 804, 
+    809, 809, 810, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, 
+    811, 811, 810, 810, 810, 809, 809, 809, 809, 810, 810, 812, 813, 814, 
+    814, 815, 816, 816, 816, 816, 81, 81, 81, 81, 81, 81, 817, 817, 817, 817, 
+    817, 817, 817, 817, 817, 81, 81, 81, 81, 81, 81, 81, 818, 818, 818, 818, 
+    818, 818, 818, 818, 818, 818, 81, 81, 81, 81, 81, 81, 819, 819, 819, 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, 822, 821, 821, 821, 
+    821, 821, 821, 823, 823, 81, 824, 824, 824, 824, 824, 824, 824, 824, 824, 
+    824, 825, 825, 825, 825, 81, 81, 81, 81, 826, 826, 826, 826, 826, 826, 
+    826, 826, 826, 826, 826, 827, 828, 829, 826, 81, 830, 830, 831, 832, 832, 
+    832, 832, 832, 832, 832, 832, 832, 832, 832, 832, 832, 832, 832, 832, 
+    831, 831, 831, 830, 830, 830, 830, 830, 830, 830, 830, 830, 831, 833, 
+    832, 832, 832, 832, 834, 834, 835, 834, 835, 836, 830, 830, 835, 81, 81, 
+    837, 837, 837, 837, 837, 837, 837, 837, 837, 837, 832, 838, 832, 834, 
+    834, 834, 81, 839, 839, 839, 839, 839, 839, 839, 839, 839, 839, 839, 839, 
+    839, 839, 839, 839, 839, 839, 839, 839, 81, 81, 81, 840, 840, 840, 840, 
+    840, 840, 840, 840, 840, 840, 81, 840, 840, 840, 840, 840, 840, 840, 840, 
+    840, 841, 841, 841, 842, 842, 842, 841, 841, 842, 843, 844, 842, 845, 
+    845, 846, 845, 845, 846, 842, 81, 847, 847, 847, 847, 847, 847, 847, 81, 
+    847, 81, 847, 847, 847, 847, 81, 847, 847, 847, 847, 847, 847, 847, 847, 
+    847, 847, 847, 847, 847, 847, 847, 81, 847, 847, 848, 81, 81, 81, 81, 81, 
+    81, 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, 849, 
+    849, 850, 851, 851, 851, 850, 850, 850, 850, 850, 850, 852, 853, 81, 81, 
+    81, 81, 81, 854, 854, 854, 854, 854, 854, 854, 854, 854, 854, 81, 81, 81, 
+    81, 81, 81, 855, 855, 856, 856, 81, 857, 857, 857, 857, 857, 857, 857, 
+    857, 81, 81, 857, 857, 81, 81, 857, 857, 857, 857, 857, 857, 857, 857, 
+    857, 857, 857, 857, 857, 857, 81, 857, 857, 857, 857, 857, 857, 857, 81, 
+    857, 857, 81, 857, 857, 857, 857, 857, 81, 81, 858, 857, 856, 856, 855, 
+    856, 856, 856, 856, 81, 81, 856, 856, 81, 81, 856, 856, 859, 81, 81, 857, 
+    81, 81, 81, 81, 81, 81, 856, 81, 81, 81, 81, 81, 857, 857, 857, 857, 857, 
+    856, 856, 81, 81, 860, 860, 860, 860, 860, 860, 860, 81, 81, 81, 861, 
+    861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 862, 862, 
+    862, 863, 863, 863, 863, 863, 863, 863, 863, 862, 862, 864, 863, 863, 
+    862, 865, 861, 861, 861, 861, 866, 866, 866, 866, 867, 868, 868, 868, 
+    868, 868, 868, 868, 868, 868, 868, 81, 866, 81, 867, 81, 81, 869, 869, 
+    869, 869, 869, 869, 869, 869, 870, 870, 870, 871, 871, 871, 871, 871, 
+    871, 870, 871, 870, 870, 870, 870, 871, 871, 870, 872, 873, 869, 869, 
+    874, 869, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 81, 81, 81, 
+    81, 81, 81, 876, 876, 876, 876, 876, 876, 876, 876, 876, 876, 876, 876, 
+    876, 876, 876, 877, 877, 877, 878, 878, 878, 878, 81, 81, 877, 877, 877, 
+    877, 878, 878, 877, 879, 880, 881, 882, 882, 883, 883, 884, 884, 884, 
+    882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 
+    882, 876, 876, 876, 876, 878, 878, 81, 81, 885, 885, 885, 885, 885, 885, 
+    885, 885, 886, 886, 886, 887, 887, 887, 887, 887, 887, 887, 887, 886, 
+    886, 887, 886, 888, 887, 889, 889, 890, 885, 81, 81, 81, 891, 891, 891, 
+    891, 891, 891, 891, 891, 891, 891, 81, 81, 81, 81, 81, 81, 892, 892, 892, 
+    892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 81, 81, 81, 893, 893, 
+    893, 893, 893, 893, 893, 893, 893, 893, 893, 894, 895, 894, 895, 895, 
+    894, 894, 894, 894, 894, 894, 896, 897, 898, 898, 898, 898, 898, 898, 
+    898, 898, 898, 898, 81, 81, 81, 81, 81, 81, 899, 899, 899, 899, 899, 899, 
+    899, 899, 899, 899, 81, 81, 81, 900, 900, 900, 901, 901, 900, 900, 900, 
+    900, 901, 900, 900, 900, 900, 902, 81, 81, 81, 81, 903, 903, 903, 903, 
+    903, 903, 903, 903, 903, 903, 904, 904, 905, 905, 905, 906, 907, 907, 
+    907, 907, 907, 907, 907, 907, 908, 908, 908, 908, 908, 908, 908, 908, 
+    909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 910, 910, 910, 910, 
+    910, 910, 910, 910, 910, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 
+    911, 912, 913, 913, 913, 913, 913, 913, 914, 914, 913, 913, 912, 912, 
+    912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 
+    913, 915, 913, 913, 913, 913, 914, 912, 913, 913, 913, 913, 916, 917, 
+    918, 918, 918, 918, 916, 917, 915, 919, 920, 920, 920, 920, 920, 920, 
+    921, 921, 920, 920, 920, 919, 919, 919, 919, 919, 919, 919, 919, 919, 
+    919, 919, 919, 919, 919, 919, 919, 81, 81, 919, 919, 919, 919, 920, 920, 
+    920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 921, 920, 922, 
+    923, 923, 923, 81, 924, 924, 924, 923, 923, 81, 81, 81, 81, 81, 925, 925, 
+    925, 925, 925, 925, 925, 925, 925, 81, 81, 81, 81, 81, 81, 81, 926, 926, 
+    926, 926, 926, 926, 926, 926, 926, 81, 926, 926, 926, 926, 926, 926, 926, 
+    926, 926, 926, 926, 926, 926, 927, 928, 928, 928, 928, 928, 928, 928, 81, 
+    928, 928, 928, 928, 928, 928, 927, 929, 926, 930, 930, 930, 930, 930, 81, 
+    81, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 932, 932, 932, 932, 
+    932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 
+    932, 81, 81, 81, 933, 934, 935, 935, 935, 935, 935, 935, 935, 935, 935, 
+    935, 935, 935, 935, 935, 81, 81, 936, 936, 936, 936, 936, 936, 936, 936, 
+    936, 936, 936, 936, 936, 936, 81, 937, 936, 936, 936, 936, 936, 936, 936, 
+    937, 936, 936, 937, 936, 936, 81, 938, 938, 938, 938, 938, 938, 938, 81, 
+    938, 938, 81, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 
+    938, 938, 939, 939, 939, 939, 939, 939, 81, 81, 81, 939, 81, 939, 939, 
+    81, 939, 939, 939, 940, 939, 941, 941, 938, 939, 942, 942, 942, 942, 942, 
+    942, 942, 942, 942, 942, 81, 81, 81, 81, 81, 81, 943, 943, 943, 943, 943, 
+    943, 943, 943, 943, 943, 81, 81, 81, 81, 81, 81, 944, 944, 944, 944, 944, 
+    944, 944, 944, 944, 944, 944, 944, 944, 944, 944, 81, 945, 945, 945, 945, 
+    945, 81, 81, 81, 943, 943, 943, 943, 81, 81, 81, 81, 946, 946, 946, 946, 
+    946, 946, 946, 946, 947, 947, 947, 948, 948, 948, 946, 946, 946, 946, 
+    948, 946, 946, 946, 947, 948, 947, 948, 946, 946, 946, 946, 946, 946, 
+    946, 947, 948, 948, 946, 946, 946, 946, 946, 946, 946, 946, 946, 946, 
+    946, 81, 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, 
+    949, 950, 951, 949, 949, 949, 949, 949, 949, 949, 81, 605, 81, 81, 81, 
+    81, 81, 81, 81, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 
+    952, 952, 952, 952, 81, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 
+    81, 81, 81, 81, 954, 954, 955, 955, 955, 955, 955, 955, 955, 955, 955, 
+    955, 955, 955, 955, 955, 81, 81, 956, 956, 956, 956, 956, 957, 81, 81, 
+    958, 958, 958, 958, 958, 958, 958, 958, 959, 959, 959, 959, 959, 959, 
+    959, 960, 960, 960, 961, 961, 962, 962, 962, 962, 963, 963, 963, 963, 
+    960, 962, 81, 81, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 81, 
+    965, 965, 965, 965, 965, 965, 965, 81, 958, 958, 958, 958, 958, 81, 81, 
+    81, 81, 81, 958, 958, 958, 966, 966, 966, 966, 966, 966, 966, 966, 966, 
+    966, 966, 966, 966, 81, 81, 81, 966, 967, 967, 967, 967, 967, 967, 967, 
+    967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 
+    967, 81, 81, 81, 81, 81, 81, 81, 81, 968, 968, 968, 968, 969, 969, 969, 
+    969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 970, 971, 81, 81, 81, 
+    81, 81, 81, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 
+    972, 81, 81, 81, 972, 972, 972, 81, 81, 81, 81, 81, 576, 571, 571, 571, 
+    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 81, 973, 973, 973, 
+    973, 973, 973, 973, 973, 973, 973, 973, 973, 81, 81, 81, 81, 974, 974, 
+    974, 974, 974, 974, 974, 974, 974, 974, 974, 81, 81, 81, 81, 81, 974, 
+    974, 974, 974, 974, 81, 81, 81, 974, 81, 81, 81, 81, 81, 81, 81, 974, 
+    974, 81, 81, 975, 976, 977, 978, 499, 499, 499, 499, 81, 81, 81, 81, 313, 
+    313, 313, 313, 313, 313, 81, 81, 313, 313, 313, 313, 313, 313, 313, 81, 
+    81, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 979, 979, 
+    447, 447, 447, 313, 313, 313, 980, 979, 979, 979, 979, 979, 499, 499, 
+    499, 499, 499, 499, 499, 499, 156, 156, 156, 156, 156, 156, 156, 156, 
+    313, 313, 96, 96, 96, 96, 96, 156, 156, 313, 313, 313, 313, 313, 313, 96, 
+    96, 96, 96, 313, 313, 313, 81, 81, 81, 81, 81, 81, 81, 721, 721, 981, 
+    981, 981, 721, 81, 81, 616, 616, 81, 81, 81, 81, 81, 81, 506, 506, 506, 
+    506, 506, 506, 506, 506, 506, 506, 49, 49, 49, 49, 49, 49, 49, 49, 49, 
+    49, 49, 49, 49, 49, 49, 49, 49, 49, 506, 506, 506, 506, 506, 506, 506, 
+    506, 506, 506, 49, 49, 49, 49, 49, 49, 49, 81, 49, 49, 49, 49, 49, 49, 
+    506, 81, 506, 506, 81, 81, 506, 81, 81, 506, 506, 81, 81, 506, 506, 506, 
+    506, 81, 506, 506, 49, 49, 81, 49, 81, 49, 49, 49, 49, 49, 49, 49, 81, 
+    49, 49, 49, 49, 49, 49, 49, 506, 506, 81, 506, 506, 506, 506, 81, 81, 
+    506, 506, 506, 506, 506, 506, 506, 506, 81, 506, 506, 506, 506, 506, 506, 
+    506, 81, 49, 49, 506, 506, 81, 506, 506, 506, 506, 81, 506, 506, 506, 
+    506, 506, 81, 506, 81, 81, 81, 506, 506, 506, 506, 506, 506, 506, 81, 49, 
+    49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 81, 81, 506, 982, 49, 49, 49, 
+    49, 49, 49, 49, 49, 49, 492, 49, 49, 49, 49, 49, 49, 506, 506, 506, 506, 
+    506, 506, 506, 506, 506, 982, 49, 49, 49, 49, 49, 49, 49, 49, 49, 492, 
+    49, 49, 506, 506, 506, 506, 506, 982, 49, 49, 49, 49, 49, 49, 49, 49, 49, 
+    492, 49, 49, 49, 49, 49, 49, 506, 506, 506, 506, 506, 506, 506, 506, 506, 
+    982, 49, 492, 49, 49, 49, 49, 49, 49, 49, 49, 506, 49, 81, 81, 983, 983, 
+    983, 983, 983, 983, 983, 983, 983, 983, 984, 984, 984, 984, 984, 984, 
+    984, 984, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 
+    985, 985, 985, 984, 984, 984, 984, 985, 985, 985, 985, 985, 985, 985, 
+    985, 985, 985, 984, 984, 984, 984, 984, 984, 984, 984, 985, 984, 984, 
+    984, 984, 984, 984, 985, 984, 984, 986, 986, 986, 986, 987, 81, 81, 81, 
+    81, 81, 81, 81, 985, 985, 985, 985, 985, 81, 985, 985, 985, 985, 985, 
+    985, 985, 988, 988, 988, 988, 988, 988, 988, 81, 988, 988, 988, 988, 988, 
+    988, 988, 988, 988, 81, 81, 988, 988, 988, 988, 988, 988, 988, 81, 988, 
+    988, 81, 988, 988, 988, 988, 988, 81, 81, 81, 81, 81, 989, 989, 989, 989, 
+    989, 989, 989, 989, 989, 989, 989, 989, 989, 81, 81, 990, 990, 990, 990, 
+    990, 990, 990, 990, 990, 991, 991, 991, 991, 991, 991, 991, 81, 992, 992, 
+    992, 992, 992, 992, 992, 992, 992, 992, 993, 993, 993, 993, 993, 993, 
+    993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 994, 994, 
+    994, 994, 994, 994, 995, 81, 81, 81, 81, 81, 996, 996, 996, 996, 996, 
+    996, 996, 996, 996, 996, 81, 81, 81, 81, 997, 997, 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, 525, 525, 525, 525, 521, 525, 525, 525, 525, 525, 
+    525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 998, 998, 998, 998, 
+    998, 998, 998, 998, 998, 998, 998, 998, 525, 525, 525, 525, 525, 525, 
+    525, 998, 998, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 
+    525, 525, 525, 521, 525, 525, 525, 525, 525, 525, 998, 998, 47, 47, 47, 
+    515, 515, 998, 998, 998, 526, 526, 526, 526, 526, 526, 313, 998, 526, 
+    526, 40, 40, 998, 998, 998, 998, 526, 526, 526, 526, 526, 526, 999, 526, 
+    526, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 526, 526, 526, 
+    526, 526, 526, 526, 526, 526, 526, 998, 998, 998, 998, 998, 998, 998, 
+    998, 998, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 
+    1001, 582, 582, 998, 998, 998, 998, 998, 582, 582, 582, 582, 998, 998, 
+    998, 998, 582, 998, 998, 998, 998, 998, 998, 998, 582, 582, 998, 998, 
+    998, 998, 998, 998, 521, 521, 521, 521, 521, 521, 998, 998, 521, 525, 
+    525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 521, 521, 521, 
+    521, 521, 521, 521, 521, 521, 525, 521, 521, 521, 521, 521, 521, 525, 
+    521, 521, 521, 521, 521, 521, 521, 532, 521, 521, 521, 521, 521, 521, 
+    525, 525, 525, 525, 525, 525, 525, 525, 40, 40, 525, 525, 521, 521, 521, 
+    521, 521, 524, 524, 521, 521, 521, 521, 521, 524, 521, 521, 521, 521, 
+    521, 532, 532, 532, 521, 521, 532, 521, 521, 532, 530, 530, 525, 525, 
+    521, 521, 525, 525, 525, 521, 525, 525, 525, 521, 521, 521, 1002, 1002, 
+    1002, 1002, 1002, 521, 521, 521, 521, 521, 521, 521, 525, 521, 525, 532, 
+    532, 521, 521, 532, 532, 532, 532, 532, 532, 532, 532, 532, 532, 532, 
+    521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 532, 
+    532, 532, 532, 521, 521, 521, 521, 532, 521, 532, 521, 521, 521, 532, 
+    521, 521, 521, 521, 532, 532, 532, 521, 532, 532, 532, 524, 521, 524, 
+    521, 524, 521, 521, 521, 521, 521, 532, 521, 521, 521, 521, 524, 521, 
+    524, 524, 521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 525, 525, 
+    521, 524, 524, 524, 524, 524, 524, 524, 521, 521, 521, 521, 521, 521, 
+    521, 521, 524, 524, 524, 524, 524, 524, 521, 521, 521, 521, 521, 524, 
+    524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 40, 40, 40, 40, 
+    525, 521, 521, 521, 521, 525, 525, 525, 525, 525, 530, 530, 525, 525, 
+    525, 525, 532, 525, 525, 525, 525, 525, 530, 525, 525, 525, 525, 532, 
+    532, 525, 525, 525, 525, 525, 40, 40, 40, 40, 40, 40, 40, 40, 525, 525, 
+    525, 525, 40, 40, 525, 521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 
+    532, 532, 532, 521, 521, 521, 532, 532, 532, 532, 532, 40, 40, 40, 40, 
+    40, 40, 534, 534, 534, 1003, 1003, 1003, 40, 40, 40, 40, 521, 521, 521, 
+    532, 521, 521, 521, 521, 521, 521, 521, 521, 532, 532, 532, 521, 532, 
+    521, 521, 521, 521, 521, 525, 525, 525, 525, 525, 525, 532, 525, 525, 
+    525, 521, 521, 521, 525, 525, 998, 998, 998, 525, 525, 525, 521, 521, 
+    998, 998, 998, 525, 525, 525, 525, 521, 521, 521, 521, 521, 998, 998, 
+    998, 998, 998, 998, 998, 40, 40, 40, 40, 998, 998, 998, 998, 40, 40, 40, 
+    40, 40, 998, 998, 998, 40, 40, 998, 998, 998, 998, 998, 998, 40, 40, 40, 
+    40, 40, 40, 998, 998, 532, 532, 532, 532, 532, 521, 532, 532, 521, 521, 
+    521, 521, 521, 521, 532, 521, 532, 532, 521, 521, 521, 532, 532, 998, 
+    521, 521, 521, 521, 521, 998, 998, 998, 521, 521, 521, 521, 998, 998, 
+    998, 998, 521, 532, 532, 532, 532, 532, 532, 532, 532, 532, 532, 532, 
+    532, 532, 521, 521, 521, 521, 521, 521, 521, 521, 521, 998, 998, 998, 
+    998, 998, 998, 998, 81, 81, 589, 589, 589, 589, 589, 589, 589, 590, 589, 
+    589, 589, 589, 589, 590, 590, 590, 589, 590, 590, 590, 590, 590, 590, 
+    590, 590, 590, 590, 590, 590, 590, 81, 81, 81, 499, 81, 81, 81, 81, 81, 
+    81, 499, 499, 499, 499, 499, 499, 499, 499, 667, 667, 667, 667, 667, 667, 
+    81, 81, 
 };
 
 /* decomposition data */
diff --git a/src/hb-unicode-private.hh b/src/hb-unicode-private.hh
index a4d118b..82bb9a4 100644
--- a/src/hb-unicode-private.hh
+++ b/src/hb-unicode-private.hh
@@ -108,7 +108,7 @@
     /* XXX This hack belongs to the Myanmar shaper. */
     if (unlikely (unicode == 0x1037u)) unicode = 0x103Au;
 
-    /* XXX This hack belongs to the SEA shaper (for Tai Tham):
+    /* XXX This hack belongs to the USE shaper (for Tai Tham):
      * Reorder SAKOT to ensure it comes after any tone marks. */
     if (unlikely (unicode == 0x1A60u)) return 254;
 
@@ -126,7 +126,7 @@
   {
     /* U+180B..180D MONGOLIAN FREE VARIATION SELECTORs are handled in the
      * Arabic shaper.  No need to match them here. */
-    return unlikely (hb_in_ranges (unicode,
+    return unlikely (hb_in_ranges<hb_codepoint_t> (unicode,
 				   0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */
 				   0xE0100u, 0xE01EFu));  /* VARIATION SELECTOR-17..256 */
   }
@@ -137,6 +137,7 @@
    * we do NOT want to hide them, as the way Uniscribe has implemented them
    * is with regular spacing glyphs, and that's the way fonts are made to work.
    * As such, we make exceptions for those four.
+   * Also ignoring U+1BCA0..1BCA3. https://github.com/harfbuzz/harfbuzz/issues/503
    *
    * Unicode 7.0:
    * $ grep '; Default_Ignorable_Code_Point ' DerivedCoreProperties.txt | sed 's/;.*#/#/'
@@ -179,13 +180,13 @@
 	case 0x00: return unlikely (ch == 0x00ADu);
 	case 0x03: return unlikely (ch == 0x034Fu);
 	case 0x06: return unlikely (ch == 0x061Cu);
-	case 0x17: return hb_in_range (ch, 0x17B4u, 0x17B5u);
-	case 0x18: return hb_in_range (ch, 0x180Bu, 0x180Eu);
-	case 0x20: return hb_in_ranges (ch, 0x200Bu, 0x200Fu,
+	case 0x17: return hb_in_range<hb_codepoint_t> (ch, 0x17B4u, 0x17B5u);
+	case 0x18: return hb_in_range<hb_codepoint_t> (ch, 0x180Bu, 0x180Eu);
+	case 0x20: return hb_in_ranges<hb_codepoint_t> (ch, 0x200Bu, 0x200Fu,
 					    0x202Au, 0x202Eu,
 					    0x2060u, 0x206Fu);
-	case 0xFE: return hb_in_range (ch, 0xFE00u, 0xFE0Fu) || ch == 0xFEFFu;
-	case 0xFF: return hb_in_range (ch, 0xFFF0u, 0xFFF8u);
+	case 0xFE: return hb_in_range<hb_codepoint_t> (ch, 0xFE00u, 0xFE0Fu) || ch == 0xFEFFu;
+	case 0xFF: return hb_in_range<hb_codepoint_t> (ch, 0xFFF0u, 0xFFF8u);
 	default: return false;
       }
     }
@@ -193,9 +194,8 @@
     {
       /* Other planes */
       switch (plane) {
-	case 0x01: return hb_in_ranges (ch, 0x1BCA0u, 0x1BCA3u,
-					    0x1D173u, 0x1D17Au);
-	case 0x0E: return hb_in_range (ch, 0xE0000u, 0xE0FFFu);
+	case 0x01: return hb_in_range<hb_codepoint_t> (ch, 0x1D173u, 0x1D17Au);
+	case 0x0E: return hb_in_range<hb_codepoint_t> (ch, 0xE0000u, 0xE0FFFu);
 	default: return false;
       }
     }
@@ -346,23 +346,24 @@
 #define HB_MODIFIED_COMBINING_CLASS_CCC122 122 /* mai * */
 
 /* Tibetan
- * Modify U+0F74 (ccc=132) to reorder before ccc=130 marks.
+ * 
+ * In case of multiple vowel-signs, use u first (but after achung) 
+ * this allows Dzongkha multi-vowel shortcuts to render correctly 
  */
 #define HB_MODIFIED_COMBINING_CLASS_CCC129 129 /* sign aa */
-#define HB_MODIFIED_COMBINING_CLASS_CCC130 130 /* sign i */
-#define HB_MODIFIED_COMBINING_CLASS_CCC132 128 /* sign u */
-
+#define HB_MODIFIED_COMBINING_CLASS_CCC130 132 /* sign i */
+#define HB_MODIFIED_COMBINING_CLASS_CCC132 131 /* sign u */
 
 /* Misc */
 
 #define HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat) \
-	(FLAG_SAFE (gen_cat) & \
+	(FLAG_UNSAFE (gen_cat) & \
 	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
 
 #define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL(gen_cat) \
-	(FLAG_SAFE (gen_cat) & \
+	(FLAG_UNSAFE (gen_cat) & \
 	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL)))
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index d553a71..726baeb 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -188,7 +188,7 @@
 const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
   HB_OBJECT_HEADER_STATIC,
 
-  NULL, /* parent */
+  nullptr, /* parent */
   true, /* immutable */
   {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_nil,
@@ -365,7 +365,7 @@
   } else {									\
     ufuncs->func.name = ufuncs->parent->func.name;				\
     ufuncs->user_data.name = ufuncs->parent->user_data.name;			\
-    ufuncs->destroy.name = NULL;						\
+    ufuncs->destroy.name = nullptr;						\
   }										\
 }
 
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 6e4db01..0b0bad5 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -24,6 +24,8 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb-private.hh"
+#include "hb-debug.hh"
 #define HB_SHAPER uniscribe
 #include "hb-shaper-impl-private.hh"
 
@@ -38,11 +40,6 @@
 #include "hb-ot-tag.h"
 
 
-#ifndef HB_DEBUG_UNISCRIBE
-#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
-#endif
-
-
 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)
@@ -202,9 +199,9 @@
   inline void init (void)
   {
     HMODULE hinstLib;
-    this->ScriptItemizeOpenType = NULL;
-    this->ScriptShapeOpenType   = NULL;
-    this->ScriptPlaceOpenType   = NULL;
+    this->ScriptItemizeOpenType = nullptr;
+    this->ScriptShapeOpenType   = nullptr;
+    this->ScriptPlaceOpenType   = nullptr;
 
     hinstLib = GetModuleHandle (TEXT ("usp10.dll"));
     if (hinstLib)
@@ -217,7 +214,7 @@
 	!this->ScriptShapeOpenType   ||
 	!this->ScriptPlaceOpenType)
     {
-      DEBUG_MSG (UNISCRIBE, NULL, "OpenType versions of functions not found; falling back.");
+      DEBUG_MSG (UNISCRIBE, nullptr, "OpenType versions of functions not found; falling back.");
       this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType;
       this->ScriptShapeOpenType   = hb_ScriptShapeOpenType;
       this->ScriptPlaceOpenType   = hb_ScriptPlaceOpenType;
@@ -242,11 +239,11 @@
   {
     funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
     if (unlikely (!funcs))
-      return NULL;
+      return nullptr;
 
     funcs->init ();
 
-    if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) {
+    if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, nullptr, funcs)) {
       free (funcs);
       goto retry;
     }
@@ -264,7 +261,9 @@
   OPENTYPE_FEATURE_RECORD rec;
   unsigned int order;
 
-  static int cmp (const active_feature_t *a, const active_feature_t *b) {
+  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 :
 	   a->order < b->order ? -1 : a->order > b->order ? 1 :
 	   a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 :
@@ -280,7 +279,9 @@
   bool start;
   active_feature_t feature;
 
-  static int cmp (const feature_event_t *a, const feature_event_t *b) {
+  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 :
 	   a->start < b->start ? -1 : a->start > b->start ? 1 :
 	   active_feature_t::cmp (&a->feature, &b->feature);
@@ -293,8 +294,8 @@
   unsigned int index_last;  /* == end - 1 */
 };
 
-HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face)
-HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font)
+HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, face)
+HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, font)
 
 
 /*
@@ -316,7 +317,7 @@
   const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
   UUID id;
   UuidCreate ((UUID*) &id);
-  ASSERT_STATIC (2 + 3 * (16/2) < LF_FACESIZE);
+  static_assert ((2 + 3 * (16/2) < LF_FACESIZE), "");
   unsigned int name_str_len = 0;
   face_name[name_str_len++] = 'F';
   face_name[name_str_len++] = '_';
@@ -369,7 +370,7 @@
   if (!new_sfnt_data)
   {
     hb_blob_destroy (blob);
-    return NULL;
+    return nullptr;
   }
 
   memcpy(new_sfnt_data, orig_sfnt_data, length);
@@ -417,7 +418,7 @@
     {
       free (new_sfnt_data);
       hb_blob_destroy (blob);
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -427,7 +428,7 @@
 
   hb_blob_destroy (blob);
   return hb_blob_create ((const char *) new_sfnt_data, new_length,
-			 HB_MEMORY_MODE_WRITABLE, NULL, free);
+			 HB_MEMORY_MODE_WRITABLE, nullptr, free);
 }
 
 hb_uniscribe_shaper_face_data_t *
@@ -435,13 +436,13 @@
 {
   hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   data->funcs = hb_uniscribe_shaper_get_funcs ();
   if (unlikely (!data->funcs))
   {
     free (data);
-    return NULL;
+    return nullptr;
   }
 
   hb_blob_t *blob = hb_face_reference_blob (face);
@@ -452,18 +453,18 @@
   if (unlikely (!blob))
   {
     free (data);
-    return NULL;
+    return nullptr;
   }
 
   DWORD num_fonts_installed;
-  data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL),
+  data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, nullptr),
 				   hb_blob_get_length (blob),
 				   0, &num_fonts_installed);
   if (unlikely (!data->fh))
   {
     DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
     free (data);
-    return NULL;
+    return nullptr;
   }
 
   return data;
@@ -495,7 +496,7 @@
 		   unsigned int font_size)
 {
   memset (lf, 0, sizeof (*lf));
-  lf->lfHeight = -font_size;
+  lf->lfHeight = - (int) font_size;
   lf->lfCharSet = DEFAULT_CHARSET;
 
   hb_face_t *face = font->face;
@@ -509,11 +510,11 @@
 hb_uniscribe_shaper_font_data_t *
 _hb_uniscribe_shaper_font_data_create (hb_font_t *font)
 {
-  if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL;
+  if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return nullptr;
 
   hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
   if (unlikely (!data))
-    return NULL;
+    return nullptr;
 
   int font_size = font->face->get_upem (); /* Default... */
   /* No idea if the following is even a good idea. */
@@ -525,25 +526,25 @@
   data->x_mult = (double) font->x_scale / font_size;
   data->y_mult = (double) font->y_scale / font_size;
 
-  data->hdc = GetDC (NULL);
+  data->hdc = GetDC (nullptr);
 
   if (unlikely (!populate_log_font (&data->log_font, font, font_size))) {
     DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
     _hb_uniscribe_shaper_font_data_destroy (data);
-    return NULL;
+    return nullptr;
   }
 
   data->hfont = CreateFontIndirectW (&data->log_font);
   if (unlikely (!data->hfont)) {
     DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
     _hb_uniscribe_shaper_font_data_destroy (data);
-     return NULL;
+     return nullptr;
   }
 
   if (!SelectObject (data->hdc, data->hfont)) {
     DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
     _hb_uniscribe_shaper_font_data_destroy (data);
-     return NULL;
+     return nullptr;
   }
 
   return data;
@@ -553,7 +554,7 @@
 _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
 {
   if (data->hdc)
-    ReleaseDC (NULL, data->hdc);
+    ReleaseDC (nullptr, data->hdc);
   if (data->hfont)
     DeleteObject (data->hfont);
   if (data->script_cache)
@@ -564,7 +565,7 @@
 LOGFONTW *
 hb_uniscribe_font_get_logfontw (hb_font_t *font)
 {
-  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
+  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr;
   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   return &font_data->log_font;
 }
@@ -572,7 +573,7 @@
 HFONT
 hb_uniscribe_font_get_hfont (hb_font_t *font)
 {
-  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
+  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr;
   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   return font_data->hfont;
 }
@@ -738,7 +739,7 @@
 
 #define FAIL(...) \
   HB_STMT_START { \
-    DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
+    DEBUG_MSG (UNISCRIBE, nullptr, __VA_ARGS__); \
     return false; \
   } HB_STMT_END;
 
@@ -854,7 +855,7 @@
   unsigned int glyphs_offset = 0;
   unsigned int glyphs_len;
   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
-  for (unsigned int i = 0; i < item_count; i++)
+  for (int i = 0; i < item_count; i++)
   {
     unsigned int chars_offset = items[i].iCharPos;
     unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
@@ -960,7 +961,7 @@
 				     /* out */
 				     advances + glyphs_offset,
 				     offsets + glyphs_offset,
-				     NULL);
+				     nullptr);
     if (unlikely (FAILED (hr)))
       FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
 
@@ -1024,11 +1025,15 @@
     pos->x_advance = x_mult * (int32_t) info->mask;
     pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32);
     pos->y_offset = y_mult * info->var2.i32;
+
+    info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
   }
 
   if (backward)
     hb_buffer_reverse (buffer);
 
+  buffer->unsafe_to_break_all ();
+
   /* Wow, done! */
   return true;
 }
diff --git a/src/hb-utf-private.hh b/src/hb-utf-private.hh
index 74cf5d6..211eb4d 100644
--- a/src/hb-utf-private.hh
+++ b/src/hb-utf-private.hh
@@ -48,7 +48,7 @@
 
     if (c > 0x7Fu)
     {
-      if (hb_in_range (c, 0xC2u, 0xDFu)) /* Two-byte */
+      if (hb_in_range<hb_codepoint_t> (c, 0xC2u, 0xDFu)) /* Two-byte */
       {
 	unsigned int t1;
 	if (likely (text < end &&
@@ -60,7 +60,7 @@
 	else
 	  goto error;
       }
-      else if (hb_in_range (c, 0xE0u, 0xEFu)) /* Three-byte */
+      else if (hb_in_range<hb_codepoint_t> (c, 0xE0u, 0xEFu)) /* Three-byte */
       {
 	unsigned int t1, t2;
 	if (likely (1 < end - text &&
@@ -68,14 +68,14 @@
 		    (t2 = text[1] - 0x80u) <= 0x3Fu))
 	{
 	  c = ((c&0xFu)<<12) | (t1<<6) | t2;
-	  if (unlikely (c < 0x0800u || hb_in_range (c, 0xD800u, 0xDFFFu)))
+	  if (unlikely (c < 0x0800u || hb_in_range<hb_codepoint_t> (c, 0xD800u, 0xDFFFu)))
 	    goto error;
 	  text += 2;
 	}
 	else
 	  goto error;
       }
-      else if (hb_in_range (c, 0xF0u, 0xF4u)) /* Four-byte */
+      else if (hb_in_range<hb_codepoint_t> (c, 0xF0u, 0xF4u)) /* Four-byte */
       {
 	unsigned int t1, t2, t3;
 	if (likely (2 < end - text &&
@@ -84,7 +84,7 @@
 		    (t3 = text[2] - 0x80u) <= 0x3Fu))
 	{
 	  c = ((c&0x7u)<<18) | (t1<<12) | (t2<<6) | t3;
-	  if (unlikely (!hb_in_range (c, 0x10000u, 0x10FFFFu)))
+	  if (unlikely (!hb_in_range<hb_codepoint_t> (c, 0x10000u, 0x10FFFFu)))
 	    goto error;
 	  text += 3;
 	}
@@ -140,7 +140,7 @@
   {
     hb_codepoint_t c = *text++;
 
-    if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
+    if (likely (!hb_in_range<hb_codepoint_t> (c, 0xD800u, 0xDFFFu)))
     {
       *unicode = c;
       return text;
@@ -150,7 +150,7 @@
     {
       /* High-surrogate in c */
       hb_codepoint_t l = *text;
-      if (likely (hb_in_range (l, 0xDC00u, 0xDFFFu)))
+      if (likely (hb_in_range<hb_codepoint_t> (l, 0xDC00u, 0xDFFFu)))
       {
 	/* Low-surrogate in l */
 	*unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
@@ -172,7 +172,7 @@
   {
     hb_codepoint_t c = *--text;
 
-    if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
+    if (likely (!hb_in_range<hb_codepoint_t> (c, 0xD800u, 0xDFFFu)))
     {
       *unicode = c;
       return text;
@@ -182,7 +182,7 @@
     {
       /* Low-surrogate in c */
       hb_codepoint_t h = text[-1];
-      if (likely (hb_in_range (h, 0xD800u, 0xDBFFu)))
+      if (likely (hb_in_range<hb_codepoint_t> (h, 0xD800u, 0xDBFFu)))
       {
         /* High-surrogate in h */
         *unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);
diff --git a/src/main.cc b/src/main.cc
index f9708cc..819100e 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -38,6 +38,7 @@
 
 using namespace OT;
 
+const void * const OT::_hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)] = {};
 
 int
 main (int argc, char **argv)
@@ -47,11 +48,11 @@
     exit (1);
   }
 
-  const char *font_data = NULL;
+  const char *font_data = nullptr;
   int len = 0;
 
 #ifdef HAVE_GLIB
-  GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+  GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
   font_data = g_mapped_file_get_contents (mf);
   len = g_mapped_file_get_length (mf);
 #else
@@ -105,8 +106,8 @@
 
       switch (table.tag) {
 
-      case GSUBGPOS::GSUBTag:
-      case GSUBGPOS::GPOSTag:
+      case HB_OT_TAG_GSUB:
+      case HB_OT_TAG_GPOS:
 	{
 
 	const GSUBGPOS &g = *CastP<GSUBGPOS> (font_data + table.offset);
diff --git a/src/sample.py b/src/sample.py
index c2cb94d..844fa4c 100755
--- a/src/sample.py
+++ b/src/sample.py
@@ -45,7 +45,7 @@
 ## Add text to buffer
 ##
 #
-# See https://github.com/behdad/harfbuzz/pull/271
+# See https://github.com/harfbuzz/harfbuzz/pull/271
 #
 if False:
 	# If you do not care about cluster values reflecting Python
diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc
index 18c46e9..4b429ea 100644
--- a/src/test-buffer-serialize.cc
+++ b/src/test-buffer-serialize.cc
@@ -24,11 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "hb-private.hh"
 
 #include "hb.h"
+#include "hb-ot.h"
 #ifdef HAVE_FREETYPE
 #include "hb-ft.h"
 #endif
@@ -45,7 +44,7 @@
 int
 main (int argc, char **argv)
 {
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   if (argc != 2) {
     fprintf (stderr, "usage: %s font-file\n", argv[0]);
@@ -61,7 +60,7 @@
     hb_memory_mode_t mm;
 
 #ifdef HAVE_GLIB
-    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
     font_data = g_mapped_file_get_contents (mf);
     len = g_mapped_file_get_length (mf);
     destroy = (hb_destroy_func_t) g_mapped_file_unref;
@@ -86,14 +85,15 @@
 
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
-  blob = NULL;
+  blob = nullptr;
 
   unsigned int upem = hb_face_get_upem (face);
   hb_font_t *font = hb_font_create (face);
   hb_face_destroy (face);
   hb_font_set_scale (font, upem, upem);
+  hb_ot_font_set_funcs (font);
 #ifdef HAVE_FREETYPE
-  hb_ft_font_set_funcs (font);
+  //hb_ft_font_set_funcs (font);
 #endif
 
   hb_buffer_t *buf;
@@ -115,7 +115,7 @@
       ret = false;
 
     hb_buffer_serialize_glyphs (buf, 0, hb_buffer_get_length (buf),
-				out, sizeof (out), NULL,
+				out, sizeof (out), nullptr,
 				font, HB_BUFFER_SERIALIZE_FORMAT_JSON,
 				HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
     puts (out);
diff --git a/src/test-size-params.cc b/src/test-size-params.cc
index 35d9e3c..9741b87 100644
--- a/src/test-size-params.cc
+++ b/src/test-size-params.cc
@@ -24,9 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "hb-private.hh"
 
 #include "hb.h"
 #include "hb-ot.h"
@@ -43,7 +41,7 @@
 int
 main (int argc, char **argv)
 {
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   if (argc != 2) {
     fprintf (stderr, "usage: %s font-file\n", argv[0]);
@@ -59,7 +57,7 @@
     hb_memory_mode_t mm;
 
 #ifdef HAVE_GLIB
-    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
     font_data = g_mapped_file_get_contents (mf);
     len = g_mapped_file_get_length (mf);
     destroy = (hb_destroy_func_t) g_mapped_file_unref;
@@ -85,7 +83,7 @@
   /* Create the face */
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
-  blob = NULL;
+  blob = nullptr;
 
   unsigned int p[5];
   bool ret = hb_ot_layout_get_size_params (face, p, p+1, p+2, p+3, p+4);
diff --git a/src/test-would-substitute.cc b/src/test-would-substitute.cc
index 8ea87cd..efebf2d 100644
--- a/src/test-would-substitute.cc
+++ b/src/test-would-substitute.cc
@@ -24,9 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "hb-private.hh"
 
 #include "hb.h"
 #include "hb-ot.h"
@@ -47,7 +45,7 @@
 int
 main (int argc, char **argv)
 {
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   if (argc != 4 && argc != 5) {
     fprintf (stderr, "usage: %s font-file lookup-index first-glyph [second-glyph]\n", argv[0]);
@@ -63,7 +61,7 @@
     hb_memory_mode_t mm;
 
 #ifdef HAVE_GLIB
-    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
     font_data = g_mapped_file_get_contents (mf);
     len = g_mapped_file_get_length (mf);
     destroy = (hb_destroy_func_t) g_mapped_file_unref;
@@ -89,7 +87,7 @@
   /* Create the face */
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
-  blob = NULL;
+  blob = nullptr;
 
   hb_font_t *font = hb_font_create (face);
 #ifdef HAVE_FREETYPE
@@ -102,5 +100,5 @@
       (argc > 4 &&
        !hb_font_glyph_from_string (font, argv[4], -1, &glyphs[1])))
     return 2;
-  return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], NULL, 0), glyphs, len, false);
+  return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], nullptr, 0), glyphs, len, false);
 }
diff --git a/src/test.cc b/src/test.cc
index 0c90f8f..9592b37 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -24,9 +24,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "hb-private.hh"
 
 #include "hb.h"
 
@@ -46,7 +44,7 @@
 int
 main (int argc, char **argv)
 {
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   if (argc != 2) {
     fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
@@ -62,7 +60,7 @@
     hb_memory_mode_t mm;
 
 #ifdef HAVE_GLIB
-    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, nullptr);
     font_data = g_mapped_file_get_contents (mf);
     len = g_mapped_file_get_length (mf);
     destroy = (hb_destroy_func_t) g_mapped_file_unref;
@@ -90,7 +88,7 @@
   /* Create the face */
   hb_face_t *face = hb_face_create (blob, 0 /* first face */);
   hb_blob_destroy (blob);
-  blob = NULL;
+  blob = nullptr;
   unsigned int upem = hb_face_get_upem (face);
 
   hb_font_t *font = hb_font_create (face);
@@ -105,11 +103,11 @@
   hb_buffer_add_utf8 (buffer, "\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb0\xe0\xa5\x8d\xe0\xa4\x95", -1, 0, -1);
   hb_buffer_guess_segment_properties (buffer);
 
-  hb_shape (font, buffer, NULL, 0);
+  hb_shape (font, buffer, nullptr, 0);
 
   unsigned int count = hb_buffer_get_length (buffer);
-  hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, NULL);
-  hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, NULL);
+  hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, nullptr);
+  hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, nullptr);
 
   for (unsigned int i = 0; i < count; i++)
   {
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..53d257b
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(api)
diff --git a/test/api/CMakeLists.txt b/test/api/CMakeLists.txt
new file mode 100644
index 0000000..4e786ba
--- /dev/null
+++ b/test/api/CMakeLists.txt
@@ -0,0 +1,39 @@
+macro (_add_tests)
+  foreach(test_name ${ARGV})
+    if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.c)
+      add_executable (${test_name} ${test_name}.c)
+    elseif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.cc)
+      add_executable (${test_name} ${test_name}.cc)
+    else ()
+      message(FATAL_ERROR "No source file found for test ${test_name}")
+    endif ()
+    target_link_libraries (${test_name} harfbuzz)
+    add_test (${test_name} ${test_name})
+  endforeach ()
+  set_tests_properties (${ARGV} PROPERTIES ENVIRONMENT
+    "G_TEST_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};G_TEST_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}"
+    )
+endmacro ()
+
+if (HB_HAVE_GLIB)
+  _add_tests (
+    test-blob
+    test-buffer
+    test-common
+    test-font
+    test-object
+    test-set
+    test-shape
+    test-unicode
+    test-version
+    test-ot-tag
+    test-c
+    test-cplusplus
+    )
+
+  if (HB_HAVE_FREETYPE)
+    _add_tests (
+      test-ot-math
+      )
+  endif (HB_HAVE_FREETYPE)
+endif (HB_HAVE_GLIB)
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index 530bf3e..231ec22 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -31,11 +31,11 @@
 	test-version \
 	$(NULL)
 
-test_unicode_CPPFLAGS = $(AM_CPPFLAGS)
+test_unicode_CPPFLAGS = \
+	$(AM_CPPFLAGS) \
+	$(GLIB_CFLAGS) \
+	$(NULL)
 test_unicode_LDADD = $(LDADD)
-if HAVE_GLIB
-test_unicode_CPPFLAGS += $(GLIB_CFLAGS)
-endif
 if HAVE_ICU
 test_unicode_CPPFLAGS += $(ICU_CFLAGS)
 test_unicode_LDADD += $(top_builddir)/src/libharfbuzz-icu.la $(ICU_LIBS)
@@ -149,12 +149,12 @@
 
 
 
-else
+else # !HAVE_GLIB
 check-am: err-glib
 err-glib:
 	@echo "You need to have glib support enabled to run the tests"
 	@exit 77
-endif
+endif # HAVE_GLIB
 
 .PHONY: check-symbols check-tool check-valgrind
 
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
index 4d41218..040f0c2 100644
--- a/test/api/hb-test.h
+++ b/test/api/hb-test.h
@@ -27,7 +27,9 @@
 #ifndef HB_TEST_H
 #define HB_TEST_H
 
+#ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif
 
 #include <hb-glib.h>
 
diff --git a/test/api/test-buffer.c b/test/api/test-buffer.c
index 17607f1..51322a4 100644
--- a/test/api/test-buffer.c
+++ b/test/api/test-buffer.c
@@ -196,7 +196,7 @@
   g_assert_cmpint (len, ==, 5);
 
   for (i = 0; i < len; i++) {
-    g_assert_cmphex (glyphs[i].mask,      ==, 1);
+    g_assert_cmphex (glyphs[i].mask,      ==, 0);
     g_assert_cmphex (glyphs[i].var1.u32,  ==, 0);
     g_assert_cmphex (glyphs[i].var2.u32,  ==, 0);
   }
diff --git a/test/api/test-c.c b/test/api/test-c.c
index 6e8602f..4b43b83 100644
--- a/test/api/test-c.c
+++ b/test/api/test-c.c
@@ -27,7 +27,9 @@
 /* This file tests that all headers can be included from .c files */
 
 
+#ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif
 
 #include <hb.h>
 
diff --git a/test/api/test-font.c b/test/api/test-font.c
index 34f6c74..527dfcd 100644
--- a/test/api/test-font.c
+++ b/test/api/test-font.c
@@ -35,13 +35,23 @@
 static void
 test_face_empty (void)
 {
+  hb_face_t *created_from_empty;
+  hb_face_t *created_from_null;
+
   g_assert (hb_face_get_empty ());
-  g_assert (hb_face_get_empty () != hb_face_create (hb_blob_get_empty (), 0));
-  g_assert (hb_face_get_empty () != hb_face_create (NULL, 0));
+
+  created_from_empty = hb_face_create (hb_blob_get_empty (), 0);
+  g_assert (hb_face_get_empty () != created_from_empty);
+
+  created_from_null = hb_face_create (NULL, 0);
+  g_assert (hb_face_get_empty () != created_from_null);
 
   g_assert (hb_face_reference_table (hb_face_get_empty (), HB_TAG ('h','e','a','d')) == hb_blob_get_empty ());
 
   g_assert_cmpint (hb_face_get_upem (hb_face_get_empty ()), ==, 1000);
+
+  hb_face_destroy (created_from_null);
+  hb_face_destroy (created_from_empty);
 }
 
 static void
@@ -357,14 +367,29 @@
 static void
 test_font_empty (void)
 {
+  hb_font_t *created_from_empty;
+  hb_font_t *created_from_null;
+  hb_font_t *created_sub_from_null;
+
   g_assert (hb_font_get_empty ());
-  g_assert (hb_font_get_empty () != hb_font_create (hb_face_get_empty ()));
-  g_assert (hb_font_get_empty () != hb_font_create (NULL));
-  g_assert (hb_font_get_empty () != hb_font_create_sub_font (NULL));
+
+  created_from_empty = hb_font_create (hb_face_get_empty ());
+  g_assert (hb_font_get_empty () != created_from_empty);
+
+  created_from_null = hb_font_create (NULL);
+  g_assert (hb_font_get_empty () != created_from_null);
+
+  created_sub_from_null = hb_font_create_sub_font (NULL);
+  g_assert (hb_font_get_empty () != created_sub_from_null);
+
   g_assert (hb_font_is_immutable (hb_font_get_empty ()));
 
   g_assert (hb_font_get_face (hb_font_get_empty ()) == hb_face_get_empty ());
   g_assert (hb_font_get_parent (hb_font_get_empty ()) == NULL);
+
+  hb_font_destroy (created_sub_from_null);
+  hb_font_destroy (created_from_null);
+  hb_font_destroy (created_from_empty);
 }
 
 static void
diff --git a/test/api/test-set.c b/test/api/test-set.c
index 9634951..bbea2cf 100644
--- a/test/api/test-set.c
+++ b/test/api/test-set.c
@@ -76,12 +76,6 @@
   g_assert_cmpint (hb_set_get_min (s), ==, 10);
   g_assert_cmpint (hb_set_get_max (s), ==, 29);
 
-  hb_set_invert (s);
-  test_not_empty (s);
-  g_assert (!hb_set_has (s, 13));
-  g_assert_cmpint (hb_set_get_min (s), ==, 0);
-
-  hb_set_invert (s);
   test_not_empty (s);
   g_assert (hb_set_has (s, 13));
   g_assert_cmpint (hb_set_get_population (s), ==, 20);
@@ -92,9 +86,43 @@
   test_not_empty (s);
   g_assert (!hb_set_has (s, 13));
 
+  hb_set_add_range (s, 200, 800);
+  test_not_empty (s);
+  g_assert (!hb_set_has (s, 100));
+  g_assert (!hb_set_has (s, 199));
+  g_assert (hb_set_has (s, 200));
+  g_assert (hb_set_has (s, 201));
+  g_assert (hb_set_has (s, 243));
+  g_assert (hb_set_has (s, 254));
+  g_assert (hb_set_has (s, 255));
+  g_assert (hb_set_has (s, 256));
+  g_assert (hb_set_has (s, 257));
+  g_assert (hb_set_has (s, 511));
+  g_assert (hb_set_has (s, 512));
+  g_assert (hb_set_has (s, 600));
+  g_assert (hb_set_has (s, 767));
+  g_assert (hb_set_has (s, 768));
+  g_assert (hb_set_has (s, 769));
+  g_assert (hb_set_has (s, 782));
+  g_assert (hb_set_has (s, 798));
+  g_assert (hb_set_has (s, 799));
+  g_assert (hb_set_has (s, 800));
+  g_assert (!hb_set_has (s, 801));
+  g_assert (!hb_set_has (s, 802));
+
   hb_set_destroy (s);
 }
 
+static inline void
+print_set (hb_set_t *s)
+{
+  hb_codepoint_t next;
+  printf ("{");
+  for (next = HB_SET_VALUE_INVALID; hb_set_next (s, &next); )
+    printf ("%d, ", next);
+  printf ("}\n");
+}
+
 static void
 test_set_algebra (void)
 {
@@ -155,7 +183,56 @@
   g_assert (!hb_set_has (s, 13));
   g_assert (hb_set_has (s, 19));
 
+  /* https://github.com/harfbuzz/harfbuzz/issues/579 */
+  hb_set_clear (s);
+  test_empty (s);
+  hb_set_add_range (s, 886, 895);
+  hb_set_add (s, 1024);
+  hb_set_add (s, 1152);
+  hb_set_clear (o);
+  test_empty (o);
+  hb_set_add (o, 889);
+  hb_set_add (o, 1024);
+  g_assert (!hb_set_is_equal (s, o));
+  hb_set_intersect (o, s);
+  test_not_empty (o);
+  g_assert (!hb_set_is_equal (s, o));
+  g_assert_cmpint (hb_set_get_population (o), ==, 2);
+  g_assert (hb_set_has (o, 889));
+  g_assert (hb_set_has (o, 1024));
+  hb_set_clear (o);
+  test_empty (o);
+  hb_set_add_range (o, 887, 889);
+  hb_set_add (o, 1121);
+  g_assert (!hb_set_is_equal (s, o));
+  hb_set_intersect (o, s);
+  test_not_empty (o);
+  g_assert (!hb_set_is_equal (s, o));
+  g_assert_cmpint (hb_set_get_population (o), ==, 3);
+  g_assert (hb_set_has (o, 887));
+  g_assert (hb_set_has (o, 888));
+  g_assert (hb_set_has (o, 889));
+
+  hb_set_clear (s);
+  test_empty (s);
+  hb_set_add_range (s, 886, 895);
+  hb_set_add (s, 1014);
+  hb_set_add (s, 1017);
+  hb_set_add (s, 1024);
+  hb_set_add (s, 1113);
+  hb_set_add (s, 1121);
+  g_assert_cmpint (hb_set_get_population (s), ==, 15);
+
+  hb_set_clear (o);
+  test_empty (o);
+  hb_set_add (o, 889);
+  g_assert_cmpint (hb_set_get_population (o), ==, 1);
+  hb_set_intersect (o, s);
+  g_assert_cmpint (hb_set_get_population (o), ==, 1);
+  g_assert (hb_set_has (o, 889));
+
   hb_set_destroy (s);
+  hb_set_destroy (o);
 }
 
 static void
@@ -167,6 +244,8 @@
   hb_set_add (s, 13);
   hb_set_add_range (s, 6, 6);
   hb_set_add_range (s, 10, 15);
+  hb_set_add (s, 1100);
+  hb_set_add (s, 1200);
   hb_set_add (s, 20005);
 
   test_not_empty (s);
@@ -184,6 +263,10 @@
   g_assert (hb_set_next (s, &next));
   g_assert_cmpint (next, ==, 15);
   g_assert (hb_set_next (s, &next));
+  g_assert_cmpint (next, ==, 1100);
+  g_assert (hb_set_next (s, &next));
+  g_assert_cmpint (next, ==, 1200);
+  g_assert (hb_set_next (s, &next));
   g_assert_cmpint (next, ==, 20005);
   g_assert (!hb_set_next (s, &next));
   g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID);
@@ -196,6 +279,12 @@
   g_assert_cmpint (first, ==, 10);
   g_assert_cmpint (last,  ==, 15);
   g_assert (hb_set_next_range (s, &first, &last));
+  g_assert_cmpint (first, ==, 1100);
+  g_assert_cmpint (last,  ==, 1100);
+  g_assert (hb_set_next_range (s, &first, &last));
+  g_assert_cmpint (first, ==, 1200);
+  g_assert_cmpint (last,  ==, 1200);
+  g_assert (hb_set_next_range (s, &first, &last));
   g_assert_cmpint (first, ==, 20005);
   g_assert_cmpint (last,  ==, 20005);
   g_assert (!hb_set_next_range (s, &first, &last));
diff --git a/test/fuzzing/README b/test/fuzzing/README
index c858f5d..af99cf9 100644
--- a/test/fuzzing/README
+++ b/test/fuzzing/README
@@ -18,4 +18,4 @@
 For more details consult the following locations:
   - http://llvm.org/docs/LibFuzzer.html or
   - https://github.com/google/libfuzzer-bot/tree/master/harfbuzz
-  - https://github.com/behdad/harfbuzz/issues/139
+  - https://github.com/harfbuzz/harfbuzz/issues/139
diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am
index ea0b28a..4cf5574 100644
--- a/test/shaping/Makefile.am
+++ b/test/shaping/Makefile.am
@@ -26,7 +26,7 @@
 	hb-unicode-encode \
 	hb-unicode-prettyname \
 	record-test.sh \
-	run-tests.sh \
+	run-tests.py \
 	texts/in-tree \
 	fonts/sha1sum \
 	$(TESTS) \
@@ -43,27 +43,43 @@
 TESTS = \
 	tests/arabic-fallback-shaping.tests \
 	tests/arabic-feature-order.tests \
+	tests/arabic-like-joining.tests \
+	tests/arabic-mark-order.tests \
+	tests/arabic-stch.tests \
 	tests/automatic-fractions.tests \
 	tests/cluster.tests \
 	tests/color-fonts.tests \
 	tests/context-matching.tests \
 	tests/cursive-positioning.tests \
 	tests/default-ignorables.tests \
+	tests/emoji-flag-tags.tests \
 	tests/fallback-positioning.tests \
 	tests/fuzzed.tests \
 	tests/hangul-jamo.tests \
 	tests/hyphens.tests \
+	tests/indic-consonant-with-stacker.tests \
+	tests/indic-init.tests \
 	tests/indic-joiner-candrabindu.tests \
+	tests/indic-joiners.tests \
 	tests/indic-old-spec.tests \
 	tests/indic-pref-blocking.tests \
+	tests/indic-script-extensions.tests \
+	tests/indic-special-cases.tests \
+	tests/indic-syllable.tests \
 	tests/language-tags.tests \
 	tests/ligature-id.tests \
+	tests/mark-attachment.tests \
 	tests/mark-filtering-sets.tests \
 	tests/mongolian-variation-selector.tests \
 	tests/spaces.tests \
 	tests/simple.tests \
+	tests/tibetan-contractions-1.tests \
+	tests/tibetan-contractions-2.tests \
+	tests/tibetan-vowels.tests \
 	tests/use.tests \
 	tests/use-marchen.tests \
+	tests/use-syllable.tests \
+	tests/variations-rvrn.tests \
 	tests/vertical.tests \
 	tests/zero-width-marks.tests \
 	$(NULL)
@@ -88,7 +104,7 @@
 	$(NULL)
 endif
 
-TESTS_LOG_COMPILER = sh $(srcdir)/run-tests.sh
+TESTS_LOG_COMPILER = python $(srcdir)/run-tests.py
 
 .PHONY: manifests
 
diff --git a/test/shaping/README.md b/test/shaping/README.md
index bf09909..d1df634 100644
--- a/test/shaping/README.md
+++ b/test/shaping/README.md
@@ -14,7 +14,7 @@
 
 To use `record-test.sh`, just put it right before the `hb-shape` invocation:
 ```sh
-$ ./hb-unicode-encode 41 42 43 627 | ./record-it.sh ../../util/hb-shape font.ttf
+$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh ../../util/hb-shape font.ttf
 ```
 what this does is:
   * Subset the font for the sequence of Unicode characters requested,
@@ -27,11 +27,11 @@
     and prints out the test case input, which you can then redirect to
     an existing or new test file in `tests`, eg.:
 ```sh
-$ ./hb-unicode-encode 41 42 43 627 | ./record-it.sh ../../util/hb-shape font.ttf >> tests/test-name.test
+$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh ../../util/hb-shape font.ttf >> tests/test-name.test
 ```
 
 If you created a new test file, add it to `Makefile.am` so it is run.
-Check that `make test` does indeed run it, and that the test passes.
+Check that `make check` does indeed run it, and that the test passes.
 When everything looks good, `git add` the new font as well as new
 test file if you created any.  You can see what new files are there
 by running `git status tests fonts/sha1sum`.  And commit!
diff --git a/test/shaping/fonts/COPYING b/test/shaping/fonts/COPYING
new file mode 100644
index 0000000..87faaca
--- /dev/null
+++ b/test/shaping/fonts/COPYING
@@ -0,0 +1,100 @@
+The following license applies to these fonts:
+
+    sha1sum/341421e629668b1a1242245d39238ca48432d35d.ttf
+    sha1sum/55c88ebbe938680b08f92c3de20713183e0c7481.ttf
+    sha1sum/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf
+    sha1sum/a014549f766436cf55b2ceb40e462038938ee899.ttf
+
+
+This Font Software is licensed under the SIL Open Font License,
+Version 1.1.
+
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font
+creation efforts of academic and linguistic communities, and to
+provide a free and open framework in which fonts may be shared and
+improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply to
+any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software
+components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to,
+deleting, or substituting -- in part or in whole -- any of the
+components of the Original Version, by changing formats or by porting
+the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed,
+modify, redistribute, and sell modified and unmodified copies of the
+Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in
+Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the
+corresponding Copyright Holder. This restriction only applies to the
+primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created using
+the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/test/shaping/fonts/sha1sum/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf b/test/shaping/fonts/sha1sum/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf
new file mode 100644
index 0000000..ad8ad84
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/1735326da89f0818cd8c51a0600e9789812c0f94.ttf b/test/shaping/fonts/sha1sum/1735326da89f0818cd8c51a0600e9789812c0f94.ttf
new file mode 100644
index 0000000..b1e4cdb
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/1735326da89f0818cd8c51a0600e9789812c0f94.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf b/test/shaping/fonts/sha1sum/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf
new file mode 100644
index 0000000..d060ea9
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/243798dd281c1c77c065958e1ff467420faa9bde.ttf b/test/shaping/fonts/sha1sum/243798dd281c1c77c065958e1ff467420faa9bde.ttf
new file mode 100644
index 0000000..dd8506e
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/243798dd281c1c77c065958e1ff467420faa9bde.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf b/test/shaping/fonts/sha1sum/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf
new file mode 100644
index 0000000..dc290ad
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf b/test/shaping/fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf
new file mode 100644
index 0000000..c4b4791
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/341421e629668b1a1242245d39238ca48432d35d.ttf b/test/shaping/fonts/sha1sum/341421e629668b1a1242245d39238ca48432d35d.ttf
new file mode 100644
index 0000000..5b82bb5
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/341421e629668b1a1242245d39238ca48432d35d.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/3493e92eaded2661cadde752a39f9d58b11f0326.ttf b/test/shaping/fonts/sha1sum/3493e92eaded2661cadde752a39f9d58b11f0326.ttf
new file mode 100644
index 0000000..006adb6
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/3493e92eaded2661cadde752a39f9d58b11f0326.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/373e67bf41ca264e260a9716162b71a23549e885.ttf b/test/shaping/fonts/sha1sum/373e67bf41ca264e260a9716162b71a23549e885.ttf
new file mode 100644
index 0000000..214a195
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/373e67bf41ca264e260a9716162b71a23549e885.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf b/test/shaping/fonts/sha1sum/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf
new file mode 100644
index 0000000..2cacb68
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/4fac3929fc3332834e93673780ec0fe94342d193.ttf b/test/shaping/fonts/sha1sum/4fac3929fc3332834e93673780ec0fe94342d193.ttf
new file mode 100644
index 0000000..0f691e1
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/4fac3929fc3332834e93673780ec0fe94342d193.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf b/test/shaping/fonts/sha1sum/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf
new file mode 100644
index 0000000..d7f2bdb
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf b/test/shaping/fonts/sha1sum/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf
new file mode 100644
index 0000000..837e8d2
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf b/test/shaping/fonts/sha1sum/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf
new file mode 100644
index 0000000..5d72fdf
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/55c88ebbe938680b08f92c3de20713183e0c7481.ttf b/test/shaping/fonts/sha1sum/55c88ebbe938680b08f92c3de20713183e0c7481.ttf
new file mode 100644
index 0000000..f654067
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/55c88ebbe938680b08f92c3de20713183e0c7481.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf b/test/shaping/fonts/sha1sum/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf
new file mode 100644
index 0000000..45f16fc
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/6466d38c62e73a39202435a4f73bf5d6acbb73c0.ttf b/test/shaping/fonts/sha1sum/6466d38c62e73a39202435a4f73bf5d6acbb73c0.ttf
deleted file mode 100644
index 33c4229..0000000
--- a/test/shaping/fonts/sha1sum/6466d38c62e73a39202435a4f73bf5d6acbb73c0.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf b/test/shaping/fonts/sha1sum/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf
new file mode 100644
index 0000000..8f7fda5
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/7ef276fc886ea502a03b9b0e5c8b547d5dc2b61c.ttf b/test/shaping/fonts/sha1sum/7ef276fc886ea502a03b9b0e5c8b547d5dc2b61c.ttf
deleted file mode 100644
index fb4534a..0000000
--- a/test/shaping/fonts/sha1sum/7ef276fc886ea502a03b9b0e5c8b547d5dc2b61c.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/81c368a33816fb20e9f647e8f24e2180f4720263.ttf b/test/shaping/fonts/sha1sum/81c368a33816fb20e9f647e8f24e2180f4720263.ttf
new file mode 100644
index 0000000..59198b2
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/81c368a33816fb20e9f647e8f24e2180f4720263.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf b/test/shaping/fonts/sha1sum/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf
new file mode 100644
index 0000000..a541546
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf b/test/shaping/fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf
new file mode 100644
index 0000000..a8fd495
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf b/test/shaping/fonts/sha1sum/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf
new file mode 100644
index 0000000..23da109
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf b/test/shaping/fonts/sha1sum/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf
new file mode 100644
index 0000000..6198614
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf b/test/shaping/fonts/sha1sum/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf
new file mode 100644
index 0000000..89b6257
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf b/test/shaping/fonts/sha1sum/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf
new file mode 100644
index 0000000..baf544f
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf b/test/shaping/fonts/sha1sum/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf
new file mode 100644
index 0000000..78518c0
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/98b7887cff91f722b92a8ff800120954606354f9.ttf b/test/shaping/fonts/sha1sum/98b7887cff91f722b92a8ff800120954606354f9.ttf
new file mode 100644
index 0000000..4835c76
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/98b7887cff91f722b92a8ff800120954606354f9.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf b/test/shaping/fonts/sha1sum/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf
new file mode 100644
index 0000000..3fb9951
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/a014549f766436cf55b2ceb40e462038938ee899.ttf b/test/shaping/fonts/sha1sum/a014549f766436cf55b2ceb40e462038938ee899.ttf
new file mode 100644
index 0000000..9a34ba5
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/a014549f766436cf55b2ceb40e462038938ee899.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf b/test/shaping/fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf
new file mode 100644
index 0000000..7d0809e
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/a34a9191d9376bda419836effeef7e75c1386016.ttf b/test/shaping/fonts/sha1sum/a34a9191d9376bda419836effeef7e75c1386016.ttf
new file mode 100644
index 0000000..a358833
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/a34a9191d9376bda419836effeef7e75c1386016.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf b/test/shaping/fonts/sha1sum/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf
new file mode 100644
index 0000000..3cd5b56
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf b/test/shaping/fonts/sha1sum/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf
new file mode 100644
index 0000000..7930a96
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf b/test/shaping/fonts/sha1sum/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf
new file mode 100644
index 0000000..531f255
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf b/test/shaping/fonts/sha1sum/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf
new file mode 100644
index 0000000..41897b6
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf b/test/shaping/fonts/sha1sum/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf
new file mode 100644
index 0000000..eb37400
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf b/test/shaping/fonts/sha1sum/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf
new file mode 100644
index 0000000..ce017a3
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf b/test/shaping/fonts/sha1sum/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf
new file mode 100644
index 0000000..4cf9a32
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf b/test/shaping/fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf
new file mode 100644
index 0000000..351fc3a
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf b/test/shaping/fonts/sha1sum/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf
new file mode 100644
index 0000000..112146e
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf b/test/shaping/fonts/sha1sum/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf
new file mode 100644
index 0000000..ba80928
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf b/test/shaping/fonts/sha1sum/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf
new file mode 100644
index 0000000..ada70f7
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf b/test/shaping/fonts/sha1sum/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf
new file mode 100644
index 0000000..e9884ea
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/ef2511f215aa3ca847cbfffbf861793b42170875.ttf b/test/shaping/fonts/sha1sum/ef2511f215aa3ca847cbfffbf861793b42170875.ttf
new file mode 100644
index 0000000..6a3af46
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/ef2511f215aa3ca847cbfffbf861793b42170875.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf b/test/shaping/fonts/sha1sum/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf
new file mode 100644
index 0000000..93c2f58
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf
Binary files differ
diff --git a/test/shaping/hb_test_tools.py b/test/shaping/hb_test_tools.py
index 7473982..c9bb1dd 100644
--- a/test/shaping/hb_test_tools.py
+++ b/test/shaping/hb_test_tools.py
@@ -7,6 +7,9 @@
 diff_symbols = "-+=*&^%$#@!~/"
 diff_colors = ['red', 'green', 'blue']
 
+def codepoints(s):
+	return (ord (u) for u in s)
+
 try:
 	unichr = unichr
 
@@ -43,9 +46,42 @@
 				except UnicodeDecodeError:
 					raise ValueError('unichr() arg not in range(0x110000)')
 
+		def codepoints(s):
+			high_surrogate = None
+			for u in s:
+				cp = ord (u)
+				if 0xDC00 <= cp <= 0xDFFF:
+					if high_surrogate:
+						yield 0x10000 + (high_surrogate - 0xD800) * 0x400 + (cp - 0xDC00)
+						high_surrogate = None
+					else:
+						yield 0xFFFC
+				else:
+					if high_surrogate:
+						yield 0xFFFC
+						high_surrogate = None
+					if 0xD800 <= cp <= 0xDBFF:
+						high_surrogate = cp
+					else:
+						yield cp
+						high_surrogate = None
+			if high_surrogate:
+				yield 0xFFFC
+
 except NameError:
 	unichr = chr
 
+try:
+	unicode = unicode
+except NameError:
+	unicode = str
+
+def tounicode(s, encoding='ascii', errors='strict'):
+	if not isinstance(s, unicode):
+		return s.decode(encoding, errors)
+	else:
+		return s
+
 class ColorFormatter:
 
 	class Null:
@@ -445,12 +481,12 @@
 
 	@staticmethod
 	def decode (s):
-		return u','.join ("U+%04X" % ord (u) for u in unicode (s, 'utf-8')).encode ('utf-8')
+		return u','.join ("U+%04X" % cp for cp in codepoints (tounicode (s, 'utf-8')))
 
 	@staticmethod
 	def parse (s):
 		s = re.sub (r"0[xX]", " ", s)
-		s = re.sub (r"[<+>{},;&#\\xXuUnNiI\n	]", " ", s)
+		s = re.sub (r"[<+>{},;&#\\xXuUnNiI\n\t]", " ", s)
 		return [int (x, 16) for x in s.split ()]
 
 	@staticmethod
diff --git a/test/shaping/record-test.sh b/test/shaping/record-test.sh
index b2a74f7..9a71cc8 100755
--- a/test/shaping/record-test.sh
+++ b/test/shaping/record-test.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-dir=`mktemp --directory`
+dir=`mktemp -d`
 
 hb_shape=$1
 shift
@@ -41,27 +41,30 @@
 	echo "hb-shape failed." >&2
 	exit 2
 fi
+glyph_names=`echo "$text" | $hb_shape $options --no-clusters --no-positions "$fontfile" | sed 's/[][]//g; s/|/,/g'`
 
 cp "$fontfile" "$dir/font.ttf"
-pyftsubset \
+fonttools subset \
 	--glyph-names \
 	--no-hinting \
+	--layout-features='*' \
 	"$dir/font.ttf" \
+	--glyphs="$glyph_names" \
 	--text="$text"
-if ! test -s "$dir/font.ttf.subset"; then
-	echo "Subsetter didn't produce nonempty subset font in $dir/font.ttf.subset" >&2
+if ! test -s "$dir/font.subset.ttf"; then
+	echo "Subsetter didn't produce nonempty subset font in $dir/font.subset.ttf" >&2
 	exit 2
 fi
 
 # Verify that subset font produces same glyphs!
-glyphs_subset=`echo "$text" | $hb_shape $options "$dir/font.ttf.subset"`
+glyphs_subset=`echo "$text" | $hb_shape $options "$dir/font.subset.ttf"`
 
 if ! test "x$glyphs" = "x$glyphs_subset"; then
 	echo "Subset font produced different glyphs!" >&2
 	echo "Perhaps font doesn't have glyph names; checking visually..." >&2
 	hb_view=${hb_shape/shape/view}
 	echo "$text" | $hb_view $options "$dir/font.ttf" --output-format=png --output-file="$dir/orig.png"
-	echo "$text" | $hb_view $options "$dir/font.ttf.subset" --output-format=png --output-file="$dir/subset.png"
+	echo "$text" | $hb_view $options "$dir/font.subset.ttf" --output-format=png --output-file="$dir/subset.png"
 	if ! cmp "$dir/orig.png" "$dir/subset.png"; then
 		echo "Images differ.  Please inspect $dir/*.png." >&2
 		echo "$glyphs"
@@ -74,9 +77,9 @@
 	glyphs=$glyphs_subset
 fi
 
-sha1sum=`sha1sum "$dir/font.ttf.subset" | cut -d' ' -f1`
+sha1sum=`sha1sum "$dir/font.subset.ttf" | cut -d' ' -f1`
 subset="fonts/sha1sum/$sha1sum.ttf"
-mv "$dir/font.ttf.subset" "$subset"
+mv "$dir/font.subset.ttf" "$subset"
 
 # There ought to be an easier way to do this, but it escapes me...
 unicodes_file=`mktemp`
diff --git a/test/shaping/run-tests.py b/test/shaping/run-tests.py
new file mode 100755
index 0000000..ebba75a
--- /dev/null
+++ b/test/shaping/run-tests.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+import sys, os, subprocess
+
+
+try:
+	input = raw_input
+except NameError:
+	pass
+
+
+def cmd(command):
+	p = subprocess.Popen (
+		command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+	p.wait ()
+	print (p.stderr.read (), file=sys.stderr)
+	return p.stdout.read ().decode ("utf-8"), p.returncode
+
+
+srcdir = os.environ.get ("srcdir", ".")
+builddir = os.environ.get ("builddir", ".")
+top_builddir = os.environ.get ("top_builddir",
+	os.path.normpath (os.path.join (os.getcwd (), "..", "..")))
+EXEEXT = os.environ.get ("EXEEXT", "")
+
+extra_options = "--verify"
+hb_shape = os.path.join (top_builddir, "util", "hb-shape" + EXEEXT)
+
+fails = 0
+args = sys.argv[1:]
+
+reference = False
+if len (args) and args[0] == "--reference":
+	reference = True
+	args = args[1:]
+
+if not len (args):
+	args = [sys.stdin]
+
+for f in args:
+	if not reference:
+		if f == sys.stdin:
+			print ("Running tests from standard input")
+		else:
+			print ("Running tests in " + f)
+
+	if f == sys.stdin:
+		def f():
+			while True:
+				try:
+					line = input ()
+				except EOFError:
+					break
+
+				if len (line):
+					yield line
+				else:
+					break
+		f = f()
+	else:
+		f = open (f)
+
+	for line in f:
+		fontfile, options, unicodes, glyphs_expected = line.split (":")
+
+		if line.startswith ("#"):
+			if not reference:
+				print ("# hb-shape %s --unicodes %s" % (fontfile, unicodes))
+			continue
+
+		if not reference:
+			print ("hb-shape %s %s %s --unicodes %s" %
+					 (fontfile, extra_options, options, unicodes))
+
+		glyphs1, returncode = cmd ([hb_shape, "--font-funcs=ft",
+			os.path.join (srcdir, fontfile), extra_options, "--unicodes",
+			unicodes] + (options.split (' ') if len(options) else []))
+
+		if returncode:
+			print ("hb-shape --font-funcs=ft failed.", file=sys.stderr)
+			fails = fails + 1
+			#continue
+
+		glyphs2, returncode = cmd ([hb_shape, "--font-funcs=ot",
+			os.path.join (srcdir, fontfile), extra_options, "--unicodes",
+			unicodes] + (options.split (' ') if len(options) else []))
+
+		if returncode:
+			print ("hb-shape --font-funcs=ot failed.", file=sys.stderr)
+			fails = fails + 1
+			#continue
+
+		if glyphs1 != glyphs2:
+			print ("FT funcs: " + glyphs1, file=sys.stderr)
+			print ("OT funcs: " + glyphs2, file=sys.stderr)
+			fails = fails + 1
+
+		if reference:
+			print (":".join ([fontfile, options, unicodes, glyphs1]))
+			continue
+
+		if glyphs1.strip() != glyphs_expected.strip():
+			print ("Actual:   " + glyphs1, file=sys.stderr)
+			print ("Expected: " + glyphs_expected, file=sys.stderr)
+			fails = fails + 1
+
+if fails != 0:
+	if not reference:
+		print (str (fails) + " tests failed.")
+	sys.exit (1)
+
+else:
+	if not reference:
+		print ("All tests passed.")
diff --git a/test/shaping/run-tests.sh b/test/shaping/run-tests.sh
deleted file mode 100755
index 021c6f8..0000000
--- a/test/shaping/run-tests.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-
-test "x$srcdir" = x && srcdir=.
-test "x$builddir" = x && builddir=.
-test "x$top_builddir" = x && top_builddir=../..
-
-hb_shape=$top_builddir/util/hb-shape$EXEEXT
-
-fails=0
-
-reference=false
-if test "x$1" = x--reference; then
-	reference=true
-	shift
-fi
-
-if test $# = 0; then
-	set /dev/stdin
-fi
-
-for f in "$@"; do
-	$reference || echo "Running tests in $f"
-	while IFS=: read fontfile options unicodes glyphs_expected; do
-		if echo "$fontfile" | grep -q '^#'; then
-			$reference || echo "Skipping $fontfile:$unicodes"
-			continue
-		fi
-		$reference || echo "Testing $fontfile:$unicodes"
-		glyphs=`$srcdir/hb-unicode-encode "$unicodes" | $hb_shape $options "$srcdir/$fontfile"`
-		if test $? != 0; then
-			echo "hb-shape failed." >&2
-			fails=$((fails+1))
-			continue
-		fi
-		if $reference; then
-			echo "$fontfile:$options:$unicodes:$glyphs"
-			continue
-		fi
-		if ! test "x$glyphs" = "x$glyphs_expected"; then
-			echo "Actual:   $glyphs" >&2
-			echo "Expected: $glyphs_expected" >&2
-			fails=$((fails+1))
-		fi
-	done < "$f"
-done
-
-if test $fails != 0; then
-	$reference || echo "$fails tests failed."
-	exit 1
-else
-	$reference || echo "All tests passed."
-fi
diff --git a/test/shaping/tests/arabic-feature-order.tests b/test/shaping/tests/arabic-feature-order.tests
index e60ab1a..58e741e 100644
--- a/test/shaping/tests/arabic-feature-order.tests
+++ b/test/shaping/tests/arabic-feature-order.tests
@@ -1,3 +1,4 @@
 fonts/sha1sum/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf::U+1820,U+180B:[uni2048.E81A=0+1550]
 fonts/sha1sum/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf::U+1820,U+180B:[uni2048.E81A=0+1550]
 fonts/sha1sum/a919b33197965846f21074b24e30250d67277bce.ttf::U+0644,U+0644,U+0647:[Lellah=0+1503]
+fonts/sha1sum/bf39b0e91ef9807f15a9e283a21a14a209fd2cfc.ttf::U+0644,U+064E,U+0670,U+0653,U+0626:[afii57414.zz04=4+1202|uni0670_uni0653=0@50,350+0|afii57454=0@550,1425+0|afii57444.calt=0+1065]
diff --git a/test/shaping/tests/arabic-like-joining.tests b/test/shaping/tests/arabic-like-joining.tests
new file mode 100644
index 0000000..ec994d0
--- /dev/null
+++ b/test/shaping/tests/arabic-like-joining.tests
@@ -0,0 +1 @@
+fonts/sha1sum/5dfad7735c6a67085f1b90d4d497e32907db4c78.ttf::U+1E922,U+1E923,U+1E924,U+1E925,U+1E926,U+1E927,U+1E928,U+1E929,U+1E92A,U+1E92B,U+1E92C,U+1E92D,U+1E92E,U+1E92F,U+1E930,U+1E931,U+1E932,U+1E933,U+1E934,U+1E935,U+1E936,U+1E937,U+1E938,U+1E939,U+1E93A,U+1E93B,U+1E93C,U+1E93D,U+1E93E,U+1E93F,U+1E940,U+1E941,U+1E942,U+1E943:[sha_adlam.fina=33+711|kpo_adlam.medi=32+573|zal_adlam.medi=31+773|gbe_adlam.medi=30+594|kha_adlam.medi=29+686|va_adlam.medi=28+621|nha_adlam.medi=27+587|tu_adlam.medi=26+772|nya_adlam.medi=25+577|ga_adlam.medi=24+552|qaaf_adlam.medi=23+694|ha_adlam.medi=22+600|chi_adlam.medi=21+662|jiim_adlam.medi=20+781|u_adlam.medi=19+678|ya_adlam.medi=18+553|kaf_adlam.medi=17+808|nun_adlam.medi=16+561|waw_adlam.medi=15+651|yhe_adlam.medi=14+674|dha_adlam.medi=13+674|o_adlam.medi=12+640|i_adlam.medi=11+657|fa_adlam.medi=10+590|e_adlam.medi=9+628|ra_adlam.medi=8+599|bhe_adlam.medi=7+594|pe_adlam.medi=6+492|sinnyiiyhe_adlam.medi=5+777|ba_adlam.medi=4+655|miim_adlam.medi=3+525|laam_adlam.medi=2+554|daali_adlam.medi=1+600|alif_adlam.init=0+597]
diff --git a/test/shaping/tests/arabic-mark-order.tests b/test/shaping/tests/arabic-mark-order.tests
new file mode 100644
index 0000000..b48c82f
--- /dev/null
+++ b/test/shaping/tests/arabic-mark-order.tests
@@ -0,0 +1,2 @@
+fonts/sha1sum/94a5d6fb15a27521fba9ea4aee9cb39b2d03322a.ttf::U+064A,U+064E,U+0670,U+0653,U+0640,U+0654,U+064E,U+0627:[afii57415.zz04=7+481|afii57454=4@25,975+0|uni0654=4@-50,50+0|afii57440=4+650|uni0670_uni0653=0@75,400+0|afii57454=0@750,1125+0|afii57450.calt=0+1331]
+fonts/sha1sum/24b8d24d00ae86f49791b746da4c9d3f717a51a8.ttf::U+0628,U+0618,U+0619,U+064E,U+064F,U+0654,U+0658,U+0653,U+0654,U+0651,U+0656,U+0651,U+065C,U+0655,U+0650:[uni0653.small=0@266,2508+0|uni0654=0@308,2151+0|uni0655=0@518,-1544+0|uni065C=0@501,-1453+0|uni0656=0@573,-659+0|uni0650=0@500,133+0|uni0619=0@300,1807+0|uni0618=0@357,1674+0|uni0651064E=0@387,1178+0|uni0651=0@402,764+0|uni0658=0@424,404+0|uni0654064F=0@540,-435+0|uni0628=0+1352]
diff --git a/test/shaping/tests/arabic-stch.tests b/test/shaping/tests/arabic-stch.tests
new file mode 100644
index 0000000..a21dfa2
--- /dev/null
+++ b/test/shaping/tests/arabic-stch.tests
@@ -0,0 +1 @@
+fonts/sha1sum/d9b8bc10985f24796826c29f7ccba3d0ae11ec02.ttf:--no-glyph-names:U+0718,U+070F,U+0718,U+0718,U+002E:[1=4+168|3=3+502|3=2+502|4=1@-1004,0+0|5=1@-876,0+0|5=1@-799,0+0|5=1@-722,0+0|5=1@-645,0+0|4=1@-566,0+0|5=1@-438,0+0|5=1@-361,0+0|5=1@-284,0+0|5=1@-207,0+0|4=1@-128,0+0|3=0+502]
diff --git a/test/shaping/tests/cluster.tests b/test/shaping/tests/cluster.tests
index 24f04dd..29580bf 100644
--- a/test/shaping/tests/cluster.tests
+++ b/test/shaping/tests/cluster.tests
@@ -1,2 +1,2 @@
-fonts/sha1sum/6466d38c62e73a39202435a4f73bf5d6acbb73c0.ttf:--cluster-level=2:U+0078,U+030A,U+0058,U+030A:[gid2=0+1083|gid4=1@-555,-8+0|gid1=2+1200|gid4=3@-614,349+0]
+fonts/sha1sum/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/sha1sum/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/tests/default-ignorables.tests b/test/shaping/tests/default-ignorables.tests
index 2d3ce97..66ee761 100644
--- a/test/shaping/tests/default-ignorables.tests
+++ b/test/shaping/tests/default-ignorables.tests
@@ -1 +1,2 @@
 fonts/sha1sum/051d92f8bc6ff724511b296c27623f824de256e9.ttf::U+0075,U+0361,U+034F,U+0301,U+0069:[gid2=0+1266|gid7=0@-617,442+0|gid5=0@-7,0+0|gid1=4+528]
+fonts/sha1sum/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf::U+0020,U+06CC,U+064E,U+034F,U+0651:[uni0651=1+0|space=1+0|uni064E=1@236,-432+0|uni06CC=1+1266|space=0+452]
diff --git a/test/shaping/tests/emoji-flag-tags.tests b/test/shaping/tests/emoji-flag-tags.tests
new file mode 100644
index 0000000..9b6da77
--- /dev/null
+++ b/test/shaping/tests/emoji-flag-tags.tests
@@ -0,0 +1,2 @@
+fonts/sha1sum/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/sha1sum/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0064,U+E0065,U+E007F:[de=0+3200]
diff --git a/test/shaping/tests/fallback-positioning.tests b/test/shaping/tests/fallback-positioning.tests
index 499db7d..86f5640 100644
--- a/test/shaping/tests/fallback-positioning.tests
+++ b/test/shaping/tests/fallback-positioning.tests
@@ -1,2 +1,2 @@
-fonts/sha1sum/7ef276fc886ea502a03b9b0e5c8b547d5dc2b61c.ttf:--font-funcs=ft:U+0078,U+0301,U+0058,U+0301:[x=0+1030|acutecomb=0@-45,-32+0|X=2+1295|acutecomb=2@-171,310+0]
-fonts/sha1sum/7ef276fc886ea502a03b9b0e5c8b547d5dc2b61c.ttf:--font-funcs=ot:U+0078,U+0301,U+0058,U+0301:[gid2=0+1030|gid4=0@-21,-27+0|gid1=2+1295|gid4=2@-147,321+0]
+fonts/sha1sum/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/sha1sum/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf::U+0061,U+035C,U+0062:[uni0061=0+512|uni035C=0@-64,-128+0|uni0062=2+512]
diff --git a/test/shaping/tests/fuzzed.tests b/test/shaping/tests/fuzzed.tests
index 771ac2b..4afb3b5 100644
--- a/test/shaping/tests/fuzzed.tests
+++ b/test/shaping/tests/fuzzed.tests
@@ -6,7 +6,17 @@
 fonts/sha1sum/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf:--font-funcs=ot:U+0041:[gid0=0+1024]
 fonts/sha1sum/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf:--font-funcs=ot:U+0041:[gid0=0+1000|gid1=0+1000|gid8=0+1000|gid3=0+1000|gid0=0+1000|gid1=0+1000|gid1=0+1000|gid8=0+1000|gid3=0+1000|gid0=0+1000|gid1=0+1000|gid8=0+1000|gid3=0+1000|gid0=0+1000|gid1=0+1000|gid1=0+1000]
 fonts/sha1sum/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-fonts/sha1sum/3511ff5c1647150595846ac414c595cccac34f18.ttf:--font-funcs=ot:U+0041:[gid0=0+1000|gid512=0+1000|gid15104=0+1000|gid11004=0+1000|gid3408=0+1000|gid18244=0+1000|gid17872=0+1000|gid17961=0+1000|gid0=0+1000|gid992=0+1000|gid15616=0+1000|gid0=0+1000|gid14151=0+1000|gid20559=0+1000|gid20992=0+1000|gid5440=0+1000|gid256=0+1000|gid0=0+1000|gid10=0+1000|gid8960=0+1000|gid256=0+1000|gid1024=0+1000|gid1490=0+1000|gid0=0+1000|gid768=0+1000|gid4096=0+1000|gid256=0+1000|gid2216=0+1000|gid0=0+1000|gid256=0+1000|gid256=0+1000|gid0=0+1000|gid768=0+1000|gid10752=0+1000|gid11004=0+1000|gid3408=0+1000|gid18244=0+1000|gid17734=0+1000|gid53248=0+1000|gid256=0+1000|gid0=0+1000|gid512=0+1000|gid14848=0+1000|gid10793=0+1000|gid57344=0+1000|gid768=0+1000|gid18227=0+1000|gid20285=0+1000|gid20480=0+1000|gid0=0+1000|gid256=0+1000|gid0=0+1000|gid810=0+1000|gid0=0+1000|gid11004=0+1000|gid3408=0+1000|gid18244=0+1000|gid17734=0+1000|gid53289=0+1000|gid57344=0+1000|gid768=0+1000|gid15667=0+1000|gid71=0+1000|gid0=0+1000|gid20559=0+1000|gid21248=0+1000|gid256=0+1000|gid0=0+1000|gid2816=0+1000|gid2776=0+1000|gid0=0+1000|gid51516=0+1000|gid0=0+1000|gid32=0+1000|gid26209=0+1000|gid28005=0+1000|gid65249=0+1000|gid29690=0+1000|gid0=0+1000|gid51548=0+1000|gid0=0+1000|gid2454=0+1000|gid28783=0+1000|gid29556=0+1000|gid1291=0+1000|gid3458=0+1000|gid80=0+1000|gid0=0+1000|gid2804=0+1000|gid210=0+1000|gid28786=0+1000|gid25968=0+1000|gid45763=0+1000|gid50546=0+1000|gid0=0+1000|gid59136=0+1000|gid0=0+1000|gid38144=0+1000|gid256=0+1000|gid0=0+1000|gid2560=0+1000|gid30208=0+1000|gid52224=0+1000|gid580=0+1000|gid17996=0+1000|gid21504=0+1000|gid6734=0+1000|gid108=0+1000|gid116=0+1000|gid24846=0+1000|gid1024=0+1000|gid0=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid0=0+1000|gid8704=0+1000|gid1345=0+1000|gid23109=0+1000|gid8192=0+1000|gid10823=0+1000|gid21076=0+1000|gid8192=0+1000|gid12877=0+1000|gid20300=0+1000|gid8192=0+1000|gid6738=0+1000|gid20301=0+1000|gid8192=0+1000|gid16980=0+1000|gid21067=0+1000|gid8251=0+1000|gid18944=0+1000|gid255=0+1000|gid65280=0+1000|gid15360=0+1000|gid256=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid768=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid768=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid1024=0+1000|gid12=0+1000|gid65280=0+1000|gid256=0+1000|gid1280=0+1000|gid255=0+1000|gid65280=0+1000|gid256=0+1000|gid1536=0+1000|gid1899=0+1000|gid25970=0+1000|gid110=0+1000|gid11264=0+1000|gid27502=0+1000|gid29285=0+1000|gid12907=0+1000|gid25974=0+1000|gid28160=0+1000|gid14443=0+1000|gid25970=0+1000|gid28288=0+1000|gid3=0+1000|gid118=0+1000|gid18259=0+1000|gid21826=0+1000|gid45716=0+1000|gid46369=0+1000|gid0=0+1000|gid0=0+1000|gid1=0+1000|gid16=0+1000|gid17=0+1000|gid256=0+1000|gid4=0+1000|gid16=0+1000|gid18244=0+1000|gid17734=0+1000|gid28=0+1000|gid12=0+1000|gid0=0+1000|gid284=0+1000|gid0=0+1000|gid28=0+1000|gid18256=0+1000|gid20307=0+1000|gid45114=0+1000|gid47616=0+1000|gid226=0+1000|gid10296=0+1000|gid0=0+1000|gid57927=0+1000|gid1=0+1000|gid0=0+1000|gid0=0+1000|gid21248=0+1000|gid5440=0+1000|gid256=0+1000|gid0=0+1000|gid10=0+1000|gid768=0+1000|gid256=0+1000|gid1024=0+1000|gid512=0+1000|gid0=0+1000|gid297=0+1000|gid16=0+1000|gid24833=0+1000|gid28774=0+1000|gid10794=0+1000|gid2304=0+1000|gid29=0+1000|gid32=0+1000|gid42=0+1000|gid64515=0+1000|gid42=0+1000|gid42=0+1000|gid64525=0+1000|gid20551=0+1000|gid17477=0+1000|gid18128=0+1000|gid10720=0+1000|gid3=0+1000|gid61=0+1000|gid3408=0+1000|gid18244=0+1000|gid17734=0+1000|gid53289=0+1000|gid57344=0+1000|gid768=0+1000|gid15616=0+1000|gid512=0+1000|gid55=0+1000|gid10576=0+1000|gid20307=0+1000|gid0=0+1000|gid255=0+1000|gid56063=0+1000|gid53504=0+1000|gid42=0+1000|gid42=0+1000|gid64525=0+1000|gid12288=0+1000|gid18176=0+1000|gid80=0+1000|gid20307=0+1000|gid1=0+1000|gid0=0+1000|gid62=0+1000]
+fonts/sha1sum/3511ff5c1647150595846ac414c595cccac34f18.ttf:--font-funcs=ot --no-positions --no-clusters --no-glyph-names:U+0041:[0|512|15104|11004|3408|18244|17872|17961|0|992|15616|0|14151|20559|20992|5440|256|0|10|8960|256|1024|1490|0|768|4096|256|2216|0|256|256|0|768|10752|11004|3408|18244|17734|53248|256|0|512|14848|10793|57344|768|18227|20285|20480|0|256|0|810|0|11004|3408|18244|17734|53289|57344|768|15667|71|0|20559|21248|256|0|2816|2776|0|51516|0|32|26209|28005|65249|29690|0|51548|0|2454|28783|29556|1291|3458|80|0|2804|210|28786|25968|45763|50546|0|59136|0|38144|256|0|2560|30208|52224|580|17996|21504|6734|108|116|24846|1024|0|255|65280|256|0|8704|1345|23109|8192|10823|21076|8192|12877|20300|8192|6738|20301|8192|16980|21067|8251|18944|255|65280|15360|256|255|65280|256|768|255|65280|256|768|255|65280|256|1024|12|65280|256|1280|255|65280|256|1536|1899|25970|110|11264|27502|29285|12907|25974|28160|14443|25970|28288|3|118|18259|21826|45716|46369|0|0|1|16|17|256|4|16|18244|17734|28|12|0|284|0|28|18256|20307|45114|47616|226|10296|0|57927|1|0|0|21248|5440|256|0|10|768|256|1024|512|0|297|16|24833|28774|10794|2304|29|32|42|64515|42|42|64525|20551|17477|18128|10720|3|61|3408|18244|17734|53289|57344|768|15616|512|55|10576|20307|0|255|56063|53504|42|42|64525|12288|18176|80|20307|1|0|62]
 fonts/sha1sum/fab39d60d758cb586db5a504f218442cd1395725.ttf:--font-funcs=ot:U+0041,U+0041:[gid0=0+1000|gid0=1+1000]
 fonts/sha1sum/205edd09bd3d141cc9580f650109556cc28b22cb.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
 fonts/sha1sum/217a934cfe15c548b572c203dceb2befdf026462.ttf:--font-funcs=ot:U+0061,U+0061,U+0061:[]
+fonts/sha1sum/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf:--font-funcs=ot:U+FFFD,U+E0100,U+FFFD,U+E0010:[]
+fonts/sha1sum/a34a9191d9376bda419836effeef7e75c1386016.ttf:--font-funcs=ot:U+0041:[]
+fonts/sha1sum/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf:--font-funcs=ot:U+0041:[gid0=0+1229]
+fonts/sha1sum/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/243798dd281c1c77c065958e1ff467420faa9bde.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf:--font-funcs=ot --no-positions --no-clusters --no-glyph-names:U+0041:[0|0|2|0|0|2|0|0|2|0|0|2|0|0|2|0|0|2|0|0|0|2|0|0|0|2|0|0|2|0|0|2|0|0|2|0|0|2|0|0|0|2|0|0|2|0|0|2|0|0|2|0]
+fonts/sha1sum/ef2511f215aa3ca847cbfffbf861793b42170875.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
diff --git a/test/shaping/tests/indic-consonant-with-stacker.tests b/test/shaping/tests/indic-consonant-with-stacker.tests
new file mode 100644
index 0000000..97dc040
--- /dev/null
+++ b/test/shaping/tests/indic-consonant-with-stacker.tests
@@ -0,0 +1,4 @@
+fonts/sha1sum/a014549f766436cf55b2ceb40e462038938ee899.ttf:--no-glyph-names:U+0CF1,U+0C95:[2=0+1129|3=1+358]
+fonts/sha1sum/55c88ebbe938680b08f92c3de20713183e0c7481.ttf:--no-glyph-names:U+0CF2,U+0CAA:[2=0+1539|3=1+245]
+fonts/sha1sum/341421e629668b1a1242245d39238ca48432d35d.ttf:--no-glyph-names:U+0CF1:[1=0+1129]
+fonts/sha1sum/663aef6b019dbf45ffd74089e2b5f2496ceceb18.ttf:--no-glyph-names:U+0CF2:[1=0+1539]
diff --git a/test/shaping/tests/indic-init.tests b/test/shaping/tests/indic-init.tests
new file mode 100644
index 0000000..1231eab
--- /dev/null
+++ b/test/shaping/tests/indic-init.tests
@@ -0,0 +1 @@
+fonts/sha1sum/1a3d8f381387dd29be1e897e4b5100ac8b4829e1.ttf:--no-glyph-names:U+09AC,U+09C7,U+09AC,U+09C7:[3=0+273|1=0+460|2=2+307|1=2+460]
diff --git a/test/shaping/tests/indic-joiners.tests b/test/shaping/tests/indic-joiners.tests
new file mode 100644
index 0000000..63f6729
--- /dev/null
+++ b/test/shaping/tests/indic-joiners.tests
@@ -0,0 +1,2 @@
+fonts/sha1sum/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+200C,U+17CA,U+17B8,U+0020:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|space=1+0|uni17ca=1+0|uni17b8=1@0,300+0|space=7+600]
+fonts/sha1sum/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+17CA,U+17B8:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|uni17bb=1@-75,-700+0|uni17b8=1+0]
diff --git a/test/shaping/tests/indic-script-extensions.tests b/test/shaping/tests/indic-script-extensions.tests
new file mode 100644
index 0000000..92bb978
--- /dev/null
+++ b/test/shaping/tests/indic-script-extensions.tests
@@ -0,0 +1,2 @@
+fonts/sha1sum/3493e92eaded2661cadde752a39f9d58b11f0326.ttf::U+0BA4,U+0BC6,U+1133C,U+0BAA,U+1133C,U+0BC6,U+1133C:[u0BC6=0+2093|u1133C=0+0|u0BA4=0+1863|u0BC6=3+2093|u1133C=3+0|u0BAA=3+1706|u1133C=3+0]
+fonts/sha1sum/b151cfcdaa77585d77f17a42158e0873fc8e2633.ttf:--no-glyph-names:U+0BAA,U+11301,U+11303:[1=0+535|2=0+0|3=0+310]
diff --git a/test/shaping/tests/indic-special-cases.tests b/test/shaping/tests/indic-special-cases.tests
new file mode 100644
index 0000000..d45ee8c
--- /dev/null
+++ b/test/shaping/tests/indic-special-cases.tests
@@ -0,0 +1,3 @@
+fonts/sha1sum/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf::U+0CB0,U+0CCD,U+0C95:[gid1=0+1176|gid5=0+1161]
+fonts/sha1sum/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf::U+0CB0,U+200D,U+0CCD,U+0C95:[gid2=0+1334|gid6=0+358]
+fonts/sha1sum/3cae6bfe5b57c07ba81ddbd54c02fe4f3a1e3bf6.ttf::U+0CB0,U+0CCD,U+200D,U+0C95:[gid2=0+1334|gid6=0+358]
diff --git a/test/shaping/tests/indic-syllable.tests b/test/shaping/tests/indic-syllable.tests
index 37eaadc..a8af26b 100644
--- a/test/shaping/tests/indic-syllable.tests
+++ b/test/shaping/tests/indic-syllable.tests
@@ -1,2 +1,8 @@
+fonts/sha1sum/54674a3111d209fb6be0ed31745314b7a8d2c244.ttf::U+0BA4,U+0BCD,U+00B3:[taprehalftamil=0+1509|uni00B3=2+674]
 fonts/sha1sum/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf::U+0CF1:[gid1=0+1129]
 fonts/sha1sum/3d0b77a2360aa6faa1385aaa510509ab70dfbeff.ttf::U+0CF2:[gid2=0+1539]
+fonts/sha1sum/87f85d17d26f1fe9ad28d7365101958edaefb967.ttf:--font-funcs=ot:U+0980,U+0981:[anjibeng=0+520|candrabindubeng=0+0]
+fonts/sha1sum/85fe0be440c64ac77699e21c2f1bd933a919167e.ttf::U+0A15,U+0A51,U+0A47:[kaguru=0+1273|udaatguru=0@75,0+0|eematraguru=0@-40,0+0]
+fonts/sha1sum/1735326da89f0818cd8c51a0600e9789812c0f94.ttf::U+0A51:[uni25CC=0+1044|udaatguru=0+0]
+fonts/sha1sum/1735326da89f0818cd8c51a0600e9789812c0f94.ttf::U+25CC,U+0A51:[uni25CC=0+1044|udaatguru=0+0]
+fonts/sha1sum/81c368a33816fb20e9f647e8f24e2180f4720263.ttf:--no-glyph-names:U+0C80,U+0C82:[1=0+502|2=0+502]
diff --git a/test/shaping/tests/ligature-id.tests b/test/shaping/tests/ligature-id.tests
index a1ce2bb..cd7f165 100644
--- a/test/shaping/tests/ligature-id.tests
+++ b/test/shaping/tests/ligature-id.tests
@@ -33,3 +33,4 @@
 fonts/sha1sum/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf::U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0020,U+0995,U+09CD,U+09B0,U+0995,U+09CD,U+09B2:[u0995_u09CD.half_u0995.pres=0+566|u0995_u09CD.half_u0995.pres=3+566|u0995_u09CD.half_u0995.pres=6+566|u0995_u09CD.half_u0995.pres=9+566|u0995_u09CD.half_u0995.pres=12+566|u0995_u09CD.half_u0995.pres=15+566|u0995_u09CD.half_u0995.pres=18+566|u0995_u09CD.half_u0995.pres=21+566|u0995_u09CD.half_u0995.pres=24+566|u0995_u09CD.half_u0995.pres=27+566|u0995_u09CD.half_u0995.pres=30+566|u0995_u09CD.half_u0995.pres=33+566|u0995_u09CD.half_u0995.pres=36+566|u0995_u09CD.half_u0995.pres=39+566|u0995_u09CD.half_u0995.pres=42+566|u0995_u09CD.half_u0995.pres=45+566|u0995_u09CD.half_u0995.pres=48+566|u0995_u09CD.half_u0995.pres=51+566|u0995_u09CD.half_u0995.pres=54+566|u0995_u09CD.half_u0995.pres=57+566|u0995_u09CD.half_u0995.pres=60+566|u0995_u09CD.half_u0995.pres=63+566|u0995_u09CD.half_u0995.pres=66+566|u0995_u09CD.half_u0995.pres=69+566|u0995_u09CD.half_u0995.pres=72+566|u0995_u09CD.half_u0995.pres=75+566|u0995_u09CD.half_u0995.pres=78+566|u0995_u09CD.half_u0995.pres=81+566|u0995_u09CD.half_u0995.pres=84+566|u0995_u09CD.half_u0995.pres=87+566|u0995_u09CD.half_u0995.pres=90+566|u0995_u09CD.half_u0995.pres=93+566|u0995_u09CD.half_u0995.pres=96+566|space=99+213|u0995_u09B0_u09CD.blwf.vatu=100+643|u0995_u09CD.half_u09B2.pres=103+602]
 fonts/sha1sum/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf::U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0020,U+0995,U+09CD,U+09B0,U+0995,U+09CD,U+09B2:[u0995_u09CD.half_u0995.pres=0+566|u0995_u09CD.half_u0995.pres=3+566|u0995_u09CD.half_u0995.pres=6+566|u0995_u09CD.half_u0995.pres=9+566|u0995_u09CD.half_u0995.pres=12+566|u0995_u09CD.half_u0995.pres=15+566|u0995_u09CD.half_u0995.pres=18+566|u0995_u09CD.half_u0995.pres=21+566|u0995_u09CD.half_u0995.pres=24+566|u0995_u09CD.half_u0995.pres=27+566|u0995_u09CD.half_u0995.pres=30+566|u0995_u09CD.half_u0995.pres=33+566|u0995_u09CD.half_u0995.pres=36+566|u0995_u09CD.half_u0995.pres=39+566|u0995_u09CD.half_u0995.pres=42+566|u0995_u09CD.half_u0995.pres=45+566|u0995_u09CD.half_u0995.pres=48+566|u0995_u09CD.half_u0995.pres=51+566|u0995_u09CD.half_u0995.pres=54+566|u0995_u09CD.half_u0995.pres=57+566|u0995_u09CD.half_u0995.pres=60+566|u0995_u09CD.half_u0995.pres=63+566|u0995_u09CD.half_u0995.pres=66+566|u0995_u09CD.half_u0995.pres=69+566|u0995_u09CD.half_u0995.pres=72+566|u0995_u09CD.half_u0995.pres=75+566|u0995_u09CD.half_u0995.pres=78+566|u0995_u09CD.half_u0995.pres=81+566|u0995_u09CD.half_u0995.pres=84+566|u0995_u09CD.half_u0995.pres=87+566|u0995_u09CD.half_u0995.pres=90+566|u0995_u09CD.half_u0995.pres=93+566|u0995_u09CD.half_u0995.pres=96+566|u0995_u09CD.half_u0995.pres=99+566|space=102+213|u0995_u09B0_u09CD.blwf.vatu=103+643|u0995_u09CD.half_u09B2.pres=106+602]
 fonts/sha1sum/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf::U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0995,U+09CD,U+0995,U+0020,U+0995,U+09CD,U+09B0,U+0995,U+09CD,U+09B2:[u0995_u09CD.half_u0995.pres=0+566|u0995_u09CD.half_u0995.pres=3+566|u0995_u09CD.half_u0995.pres=6+566|u0995_u09CD.half_u0995.pres=9+566|u0995_u09CD.half_u0995.pres=12+566|u0995_u09CD.half_u0995.pres=15+566|u0995_u09CD.half_u0995.pres=18+566|u0995_u09CD.half_u0995.pres=21+566|u0995_u09CD.half_u0995.pres=24+566|u0995_u09CD.half_u0995.pres=27+566|u0995_u09CD.half_u0995.pres=30+566|u0995_u09CD.half_u0995.pres=33+566|u0995_u09CD.half_u0995.pres=36+566|u0995_u09CD.half_u0995.pres=39+566|u0995_u09CD.half_u0995.pres=42+566|u0995_u09CD.half_u0995.pres=45+566|u0995_u09CD.half_u0995.pres=48+566|u0995_u09CD.half_u0995.pres=51+566|u0995_u09CD.half_u0995.pres=54+566|u0995_u09CD.half_u0995.pres=57+566|u0995_u09CD.half_u0995.pres=60+566|u0995_u09CD.half_u0995.pres=63+566|u0995_u09CD.half_u0995.pres=66+566|u0995_u09CD.half_u0995.pres=69+566|u0995_u09CD.half_u0995.pres=72+566|u0995_u09CD.half_u0995.pres=75+566|u0995_u09CD.half_u0995.pres=78+566|u0995_u09CD.half_u0995.pres=81+566|u0995_u09CD.half_u0995.pres=84+566|u0995_u09CD.half_u0995.pres=87+566|u0995_u09CD.half_u0995.pres=90+566|u0995_u09CD.half_u0995.pres=93+566|u0995_u09CD.half_u0995.pres=96+566|u0995_u09CD.half_u0995.pres=99+566|u0995_u09CD.half_u0995.pres=102+566|space=105+213|u0995_u09B0_u09CD.blwf.vatu=106+643|u0995_u09CD.half_u09B2.pres=109+602]
+fonts/sha1sum/a6c76d1bafde4a0b1026ebcc932d2e5c6fd02442.ttf::U+1004,U+103A,U+1039,U+101B,U+103D,U+102D:[uni101B103D=0+450|uni1004103A1039102D=0@-50,0+0]
diff --git a/test/shaping/tests/mark-attachment.tests b/test/shaping/tests/mark-attachment.tests
new file mode 100644
index 0000000..c3c2d27
--- /dev/null
+++ b/test/shaping/tests/mark-attachment.tests
@@ -0,0 +1 @@
+fonts/sha1sum/98b7887cff91f722b92a8ff800120954606354f9.ttf::U+100F,U+103C,U+102F,U+1036:[uni103C102F=0+150|uni100F=0+550|uni1036=0@-150,0+0]
diff --git a/test/shaping/tests/tibetan-contractions-1.tests b/test/shaping/tests/tibetan-contractions-1.tests
new file mode 100644
index 0000000..8577c9d
--- /dev/null
+++ b/test/shaping/tests/tibetan-contractions-1.tests
@@ -0,0 +1,60 @@
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+FEFF,U+0F40,U+0F72,U+0F72,U+0F0B,U+0F66,U+0FAD,U+0F7C,U+0F7C,U+0F0B:[uni0F40=0+680|uni0F720F72=0+0|uni0F0B=4+190|uni0F660FAD=5+680|uni0F7D=5+0|uni0F0B=9+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F72,U+0F66,U+0F0B:[uni0F400F740F72=0+680|uni0F66=3+680|uni0F0B=4+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F400F74=0+680|uni0F7A=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F7C,U+0F56,U+0F39,U+0F0B:[uni0F400F74=0+680|uni0F7C=0+0|uni0F56=3+610|uni0F39=3+0|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F72,U+0F42,U+0F66,U+0F0B:[uni0F400F740F72=0+680|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0F74,U+0F7A,U+0F66,U+0F0B:[uni0F400F74=0+680|uni0F7A=0+0|uni0F66=3+680|uni0F0B=4+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0FB3,U+0F74,U+0F7A,U+0F56,U+0F66,U+0F0B:[uni0F400FB30F740F7A=0+660|uni0F56=4+610|uni0F66=5+680|uni0F0B=6+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F40,U+0FB3,U+0F74,U+0F7C,U+0F42,U+0F0B:[uni0F400FB30F74=0+660|uni0F7C=0+0|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F40,U+0F7C,U+0F7C,U+0F42,U+0F0B:[uni0F51=0+600|uni0F400F7D=1+680|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F40,U+0F7C,U+0F7C,U+0F62,U+0F0B:[uni0F51=0+600|uni0F400F7D=1+680|uni0F62=4+620|uni0F0B=5@-65,0+130]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F40,U+0FB1,U+0F7C,U+0F72,U+0F62,U+0F0B:[uni0F51=0+600|uni0F400FB10F7C0F72=1+660|uni0F62=5+620|uni0F0B=6@-65,0+130]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F66,U+0F90,U+0FB1,U+0F74,U+0F7A,U+0F0B:[uni0F660F900FB10F74=0+680|uni0F7A=0+0|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F66,U+0F90,U+0FB1,U+0F7A,U+0F7A,U+0F51,U+0F0B:[uni0F56=0+610|uni0F660F900FB1=1+660|uni0F7B=1+0|uni0F51=6+600|uni0F0B=7@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F66,U+0F90,U+0FB1,U+0F7A,U+0F7A,U+0F7A,U+0F51,U+0F0B:[uni0F56=0+610|uni0F660F900FB1=1+660|uni0F7B0F7A=1+0|uni0F51=7+600|uni0F0B=8@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0F58,U+0F66,U+0F74,U+0F7E,U+0F0B:[uni0F41=0+660|uni0F58=1+660|uni0F660F740F7E=2+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0F74,U+0F7C,U+0F66,U+0F39,U+0F0B:[uni0F410F74=0+680|uni0F7C=0+0|uni0F66=3+680|uni0F39=3+0|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB1,U+0F74,U+0F7C,U+0F42,U+0F0B:[uni0F410FB10F74=0+670|uni0F7C=0+0|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB2,U+0F74,U+0F7A,U+0F51,U+0F0B:[uni0F410FB20F74=0+660|uni0F7A=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB2,U+0F74,U+0F72,U+0F44,U+0F0B:[uni0F410FB20F74=0+660|uni0F72=0+0|uni0F44=4+560|uni0F0B=5@-20,0+110]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB2,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F410FB20F74=0+660|uni0F7C=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F41,U+0FB2,U+0F74,U+0F7E,U+0F51,U+0F0B:[uni0F410FB20F740F7E=0+660|uni0F51=4+600|uni0F0B=5@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F58,U+0F41,U+0FB1,U+0F7A,U+0F7A,U+0F7A,U+0F53,U+0F0B:[uni0F58=0+660|uni0F410FB1=1+680|uni0F7B0F7A=1+0|uni0F53=6+590|uni0F0B=7@-30,0+160]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F60,U+0F41,U+0F7C,U+0F7C,U+0F62,U+0F0B:[uni0F60=0+600|uni0F410F7D=1+660|uni0F62=4+620|uni0F0B=5@-65,0+130]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0F74,U+0F7C,U+0F42,U+0F0B:[uni0F420F74=0+680|uni0F7C=0+0|uni0F42=3+680|uni0F0B=4+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB1,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F420FB10F74=0+700|uni0F72=0+0|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F74,U+0F72,U+0F53,U+0F0B:[uni0F420FB20F74=0+680|uni0F72=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F74,U+0F72,U+0F0B:[uni0F420FB20F74=0+680|uni0F72=0+0|uni0F0B=4+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F74,U+0F7C,U+0F53,U+0F0B:[uni0F420FB20F74=0+680|uni0F7C=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F74,U+0F7C,U+0F56,U+0F0B:[uni0F420FB20F74=0+680|uni0F7C=0+0|uni0F56=4+610|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F7C,U+0F72,U+0F53,U+0F0B:[uni0F420FB2=0+680|uni0F7C0F72=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0FB2,U+0F7C,U+0F7A,U+0F62,U+0F0B:[uni0F420FB2=0+680|uni0F7C0F7A=0+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F51=0+600|uni0F420F740F72=1+680|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F51=0+600|uni0F420F74=1+680|uni0F7A=1+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0F74,U+0F7A,U+0F42,U+0F66,U+0F0B:[uni0F51=0+600|uni0F420F74=1+680|uni0F7A=1+0|uni0F42=4+680|uni0F66=5+680|uni0F0B=6+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0FB3,U+0F7C,U+0F7A,U+0F44,U+0F0B:[uni0F51=0+600|uni0F420FB3=1+680|uni0F7C0F7A=1+0|uni0F44=5+560|uni0F0B=6@-20,0+110]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F58,U+0F42,U+0F7C,U+0F7C,U+0F53,U+0F0B:[uni0F58=0+660|uni0F420F7D=1+680|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F44,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F440F74=0+610|uni0F72=0+0|uni0F42=3+680|uni0F0B=4+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F51,U+0F42,U+0FB2,U+0F74,U+0F7C,U+0F56,U+0F0B:[uni0F51=0+600|uni0F420FB20F74=1+680|uni0F7C=1+0|uni0F56=5+610|uni0F0B=6+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F56=0+610|uni0F450F740F72=1+630|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0F74,U+0F72,U+0F66,U+0F0B:[uni0F56=0+610|uni0F450F740F72=1+630|uni0F66=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0FB2,U+0F74,U+0F42,U+0F0B:[uni0F56=0+610|uni0F450FB20F74=1+640|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0F74,U+0F72,U+0F0B:[uni0F56=0+610|uni0F450F740F72=1+630|uni0F0B=4+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F45,U+0F74,U+0F7E,U+0F0B:[uni0F56=0+610|uni0F450F740F7E=1+630|uni0F0B=4+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F74,U+0F72,U+0F63,U+0F0B:[uni0F460F74=0+650|uni0F72=0+0|uni0F63=3+700|uni0F0B=4+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F460F74=0+650|uni0F7C=0+0|uni0F51=3+600|uni0F0B=4@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F460F74=0+650|uni0F7C=0+0|uni0F51=3+600|uni0F0B=4@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F74,U+0F7E,U+0F51,U+0F0B:[uni0F460F740F7E=0+650|uni0F51=3+600|uni0F0B=4@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0F39,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F46=0+620|uni0F39=0+0|uni0F74=0+0|uni0F7C=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0FB2,U+0F74,U+0F72,U+0F53,U+0F0B:[uni0F460FB20F740F72=0+660|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F46,U+0FB2,U+0F74,U+0F7C,U+0F63,U+0F0B:[uni0F460FB20F74=0+660|uni0F7C=0+0|uni0F63=4+700|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F58,U+0F46,U+0F7C,U+0F7A,U+0F53,U+0F0B:[uni0F58=0+660|uni0F46=1+620|uni0F7C0F7A=1+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F60,U+0F46,U+0FB1,U+0F7C,U+0F72,U+0F62,U+0F0B:[uni0F60=0+600|uni0F460FB10F7C0F72=1+660|uni0F62=5+620|uni0F0B=6@-65,0+130]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F47,U+0F7C,U+0F7C,U+0F0B:[uni0F470F7D=0+570|uni0F0B=3+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F62,U+0F97,U+0F74,U+0F7A,U+0F53,U+0F39,U+0F0B:[uni0F620F970F74=0+600|uni0F7A=0+0|uni0F53=4+590|uni0F39=4+0|uni0F0B=6+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F49,U+0F74,U+0F72,U+0F0B:[uni0F490F74=0+580|uni0F72=0+0|uni0F0B=3+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F49,U+0F74,U+0F72,U+0F44,U+0F0B:[uni0F490F74=0+580|uni0F72=0+0|uni0F44=3+560|uni0F0B=4@-20,0+110]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F58,U+0F49,U+0F72,U+0F7E,U+0F51,U+0F0B:[uni0F58=0+660|uni0F49=1+580|uni0F720F7E=1+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F42,U+0F4F,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F42=0+680|uni0F4F0F740F72=1+600|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F56,U+0F4F,U+0F44,U+0F7C,U+0F7E,U+0F66,U+0F0B:[uni0F56=0+610|uni0F4F=1+560|uni0F44=2+560|uni0F7C0F7E=2+0|uni0F66=5+680|uni0F0B=6+190]
+fonts/sha1sum/a02a7f0ad42c2922cb37ad1358c9df4eb81f1bca.ttf::U+0F50,U+0F39,U+0F74,U+0F7A,U+0F4A,U+0F0B:[uni0F50=0+600|uni0F39=0+0|uni0F74=0+0|uni0F7A=0+0|uni0F4A=4+590|uni0F0B=5+190]
diff --git a/test/shaping/tests/tibetan-contractions-2.tests b/test/shaping/tests/tibetan-contractions-2.tests
new file mode 100644
index 0000000..ac15d52
--- /dev/null
+++ b/test/shaping/tests/tibetan-contractions-2.tests
@@ -0,0 +1,53 @@
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F50,U+0F74,U+0F72,U+0F53,U+0F0B:[uni0F500F74=0+600|uni0F72=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F50,U+0F74,U+0F7C,U+0F44,U+0F0B:[uni0F58=0+660|uni0F500F74=1+600|uni0F7C=1+0|uni0F44=4+560|uni0F0B=5@-20,0+110]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F50,U+0F7C,U+0F7A,U+0F44,U+0F0B:[uni0F58=0+660|uni0F50=1+600|uni0F7C0F7A=1+0|uni0F44=4+560|uni0F0B=5@-20,0+110]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F50,U+0F7C,U+0F72,U+0F66,U+0F0B:[uni0F58=0+660|uni0F50=1+600|uni0F7C0F72=1+0|uni0F66=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0F74,U+0F62,U+0FB2,U+0F7C,U+0F51,U+0F0B:[uni0F510F74=0+600|uni0F620FB2=2+600|uni0F7C=2+0|uni0F51=5+600|uni0F0B=6@-70,0+106]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0FB2,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F510FB20F74=0+600|uni0F72=0+0|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F51,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F42=0+680|uni0F510F740F7A=1+600|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0F51,U+0F7B,U+0F42,U+0F66,U+0F0B:[uni0F56=0+610|uni0F510F7B=1+579|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F60,U+0F51,U+0F74,U+0F7A,U+0F51,U+0F0B:[uni0F60=0+600|uni0F510F740F7A=1+600|uni0F51=4+600|uni0F0B=5@-70,0+106]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0FA1,U+0F7C,U+0F7A,U+0F0B:[uni0F620FA10F7C0F7A=0+580|uni0F0B=4+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0FA1,U+0F74,U+0F72,U+0F56,U+0F0B:[uni0F660FA10F74=0+680|uni0F72=0+0|uni0F56=4+610|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F53,U+0F74,U+0F7C,U+0F42,U+0F66,U+0F0B:[uni0F530F74=0+600|uni0F7C=0+0|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F53,U+0F74,U+0F7C,U+0F62,U+0F0B:[uni0F530F74=0+600|uni0F7C=0+0|uni0F62=3+620|uni0F0B=4@-65,0+130]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F53,U+0FB1,U+0F7C,U+0F7E,U+0F62,U+0F0B:[uni0F42=0+680|uni0F530FB1=1+600|uni0F7C0F7E=1+0|uni0F62=5+620|uni0F0B=6@-65,0+130]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0F54,U+0F74,U+0F7C,U+0F42,U+0F66,U+0F0B:[uni0F51=0+600|uni0F540F74=1+610|uni0F7C=1+0|uni0F42=4+680|uni0F66=5+680|uni0F0B=6+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0FB1,U+0F74,U+0F7E,U+0F56,U+0F0B:[uni0F560FB10F74=0+620|uni0F7E=0+0|uni0F56=4+610|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0FB3,U+0F74,U+0F7C,U+0F53,U+0F0B:[uni0F560FB30F74=0+650|uni0F7C=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0FB3,U+0F7C,U+0F7C,U+0F53,U+0F0B:[uni0F560FB3=0+650|uni0F7D=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0F56,U+0F74,U+0F7C,U+0F51,U+0F0B:[uni0F51=0+600|uni0F560F74=1+610|uni0F7C=1+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F51,U+0F56,U+0F74,U+0F7C,U+0F56,U+0F66,U+0F0B:[uni0F51=0+600|uni0F560F74=1+610|uni0F7C=1+0|uni0F56=4+610|uni0F66=5+680|uni0F0B=6+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F74,U+0F7A,U+0F42,U+0F66,U+0F0B:[uni0F580F74=0+680|uni0F7A=0+0|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F74,U+0F72,U+0F42,U+0F0B:[uni0F580F74=0+680|uni0F72=0+0|uni0F42=3+680|uni0F0B=4+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F74,U+0F7A,U+0F42,U+0F66,U+0F0B:[uni0F580F74=0+680|uni0F7A=0+0|uni0F42=3+680|uni0F66=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F580F74=0+680|uni0F7A=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F9F,U+0F7C,U+0F7A,U+0F42,U+0F0B:[uni0F580F9F0F7C0F7A=0+660|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F7C,U+0F7A,U+0F44,U+0F0B:[uni0F58=0+660|uni0F7C0F7A=0+0|uni0F44=3+560|uni0F0B=4@-20,0+110]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F59,U+0F74,U+0F7C,U+0F62,U+0F0B:[uni0F42=0+680|uni0F590F74=1+620|uni0F7C=1+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F58,U+0F5A,U+0FAE,U+0F74,U+0F7E,U+0F66,U+0F0B:[uni0F58=0+660|uni0F5A0FAE0F740F7E=1+620|uni0F66=5+680|uni0F0B=6+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0FAB,U+0F74,U+0F7A,U+0F66,U+0F0B:[uni0F620FAB0F74=0+660|uni0F7A=0+0|uni0F66=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0FAB,U+0F74,U+0F7A,U+0F53,U+0F0B:[uni0F620FAB0F74=0+660|uni0F7A=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F5E,U+0F74,U+0F7C,U+0F63,U+0F0B:[uni0F5E0F74=0+660|uni0F7C=0+0|uni0F63=3+700|uni0F0B=4+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5E,U+0F74,U+0F7C,U+0F42,U+0F0B:[uni0F42=0+680|uni0F5E0F74=1+660|uni0F7C=1+0|uni0F42=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5E,U+0F74,U+0F7C,U+0F58,U+0F66,U+0F0B:[uni0F42=0+680|uni0F5E0F74=1+660|uni0F7C=1+0|uni0F58=4+660|uni0F66=5+680|uni0F0B=6+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F7C,U+0F0B:[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7C=1+0|uni0F0B=4+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F72,U+0F44,U+0F0B:[uni0F42=0+680|uni0F5F0F740F72=1+610|uni0F44=4+560|uni0F0B=5@-20,0+110]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F7A,U+0F62,U+0F0B:[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7A=1+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F7A,U+0F62,U+0F0B:[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7A=1+0|uni0F62=4+620|uni0F0B=5@-65,0+130]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F42,U+0F5F,U+0F74,U+0F7A,U+0F51,U+0F0B:[uni0F42=0+680|uni0F5F0F74=1+610|uni0F7A=1+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F60,U+0F7C,U+0F7A,U+0F62,U+0F0B:[uni0F60=0+600|uni0F7C0F7A=0+0|uni0F62=3+620|uni0F0B=4@-65,0+130]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F61,U+0F72,U+0F7A,U+0F0B:[uni0F61=0+700|uni0F720F7A=0+0|uni0F0B=3+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F61,U+0F7A,U+0F7A,U+0F66,U+0F0B:[uni0F61=0+700|uni0F7B=0+0|uni0F66=3+680|uni0F0B=4+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0F72,U+0F53,U+0F7C,U+0F7A,U+0F0B:[uni0F620F72=0+620|uni0F530F7C0F7A=2+590|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F62,U+0F74,U+0F7C,U+0F63,U+0F0B:[uni0F620F74=0+601|uni0F7C=0+0|uni0F63=3+700|uni0F0B=4+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0F7A,U+0F7E,U+0F53,U+0F0B:[uni0F66=0+680|uni0F7A0F7E=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0F7A,U+0F7E,U+0F51,U+0F60,U+0F0B:[uni0F66=0+680|uni0F7A0F7E=0+0|uni0F51=3+600|uni0F60=4+600|uni0F0B=5@-40,0+150]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0F7C,U+0F7C,U+0F56,U+0F0B:[uni0F660F7D=0+680|uni0F56=3+610|uni0F0B=4+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0F7C,U+0F7C,U+0F62,U+0F0B:[uni0F660F7D=0+680|uni0F62=3+620|uni0F0B=4@-65,0+130]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0FB2,U+0F7C,U+0F7A,U+0F66,U+0F0B:[uni0F660FB2=0+680|uni0F7C0F7A=0+0|uni0F66=4+680|uni0F0B=5+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0FB3,U+0F7C,U+0F7C,U+0F51,U+0F0B:[uni0F660FB3=0+680|uni0F7D=0+0|uni0F51=4+600|uni0F0B=5@-70,0+106]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F66,U+0FB3,U+0F7C,U+0F7C,U+0F53,U+0F0B:[uni0F660FB3=0+680|uni0F7D=0+0|uni0F53=4+590|uni0F0B=5@-30,0+160]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F56,U+0F66,U+0F99,U+0F7C,U+0F7E,U+0F51,U+0F66,U+0F0B:[uni0F56=0+610|uni0F660F99=1+670|uni0F7C0F7E=1+0|uni0F51=5+600|uni0F66=6+680|uni0F0B=7+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F63,U+0FB7,U+0FB1,U+0F7C,U+0F42,U+0F66,U+0F0B:[uni0F630FB70FB1=0+680|uni0F7C=0+0|uni0F42=4+680|uni0F66=5+680|uni0F0B=6+190]
+fonts/sha1sum/2de1ab4907ab688c0cfc236b0bf51151db38bf2e.ttf::U+0F68,U+0FB1,U+0F7C,U+0F53,U+0F0B:[uni0F680FB1=0+740|uni0F7C=0+0|uni0F53=3+590|uni0F0B=4@-30,0+160]
diff --git a/test/shaping/tests/tibetan-vowels.tests b/test/shaping/tests/tibetan-vowels.tests
new file mode 100644
index 0000000..75e13c8
--- /dev/null
+++ b/test/shaping/tests/tibetan-vowels.tests
@@ -0,0 +1,11 @@
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F72:[uni0F680F72=0+730]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F74:[uni0F680F74=0+730]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7A:[uni0F680F7A=0+730]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7C:[uni0F680F7C=0+730]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F71,U+0F72:[uni0F680F710F72=0+720]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F71,U+0F74:[uni0F680F75=0+720]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7B:[uni0F680F7B=0+720]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7D:[uni0F680F7D=0+730]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7E:[uni0F680F7E=0+730]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F68,U+0F7F:[uni0F68=0+730|uni0F7F=0+408]
+fonts/sha1sum/82f4f3b57bb55344e72e70231380202a52af5805.ttf::U+0F00:[uni0F00=0+730]
diff --git a/test/shaping/tests/use-syllable.tests b/test/shaping/tests/use-syllable.tests
new file mode 100644
index 0000000..0661142
--- /dev/null
+++ b/test/shaping/tests/use-syllable.tests
@@ -0,0 +1,6 @@
+fonts/sha1sum/96490dd2ff81233b335a650e7eb660e0e7b2eeea.ttf::U+AA00,U+AA2D,U+AA29:[a_cham=0+1121|uSign_cham=0@14,0+0|.notdef=0+600]
+fonts/sha1sum/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf::U+AA00,U+AA34,U+AA36:[raMedial_cham_pre=0+400|a_cham=0+1121|waMedial_cham=0@-32,0+0]
+fonts/sha1sum/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf::U+AA00,U+AA35,U+AA33:[a_cham=0+1121|laMedial_cham=0@-32,0+0|yaMedial_cham=0+542]
+fonts/sha1sum/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf::U+AA00,U+AA35,U+AA36:[a_cham=0+1121|laMedial_waMedial_cham=0@43,0+0]
+fonts/sha1sum/074a5ae6b19de8f29772fdd5df2d3d833f81f5e6.ttf:--no-glyph-names:U+11320,U+20F0,U+11367:[3=0+502|1=0@33,0+0|4=0@300,8+0]
+fonts/sha1sum/373e67bf41ca264e260a9716162b71a23549e885.ttf:--no-glyph-names:U+A8AC,U+A8B4,U+A8B5:[2=0+377|3=0+242|4=0+210]
diff --git a/test/shaping/tests/use.tests b/test/shaping/tests/use.tests
index bfce117..6ffd126 100644
--- a/test/shaping/tests/use.tests
+++ b/test/shaping/tests/use.tests
@@ -1,4 +1,4 @@
 fonts/sha1sum/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf::U+1B1B,U+1B44,U+1B13,U+1B3E:[gid3=0+990|gid7=0+2473|gid5=0@-293,-400+0]
 fonts/sha1sum/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf::U+1A48,U+1A58,U+1A25,U+1A48,U+1A58,U+1A25,U+1A6E,U+1A63:[uni1A48=0+1212|uni1A25=0+1912|uni1A58=0+0|uni1A48=3+1212|uni1A6E=3+0|uni1A25=3+1912|uni1A58=3+0|uni1A63=3+1212]
 fonts/sha1sum/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.ttf::U+1A48,U+1A58,U+1A25,U+1A48,U+1A58,U+1A25,U+1A6E,U+1A63:[uni1A48=0+1212|uni1A25=0+1912|uni1A58=0+0|uni1A48=3+1212|uni1A6E=3+1211|uni1A25=3+1912|uni1A58=3+0|uni1A63=3+1212]
-fonts/sha1sum/6ff0fbead4462d9f229167b4e6839eceb8465058.ttf:--font-funcs=ot:U+11103,U+11128:[gid1=0+837|gid2=0+0]
+fonts/sha1sum/6ff0fbead4462d9f229167b4e6839eceb8465058.ttf:--font-funcs=ot:U+11103,U+11128:[u11103=0+837|u11128=0+0]
diff --git a/test/shaping/tests/variations-rvrn.tests b/test/shaping/tests/variations-rvrn.tests
new file mode 100644
index 0000000..a99c7f1
--- /dev/null
+++ b/test/shaping/tests/variations-rvrn.tests
@@ -0,0 +1,100 @@
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=1:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=11:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=21:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=31:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=41:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=51:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=61:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=71:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=81:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=91:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=101:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=111:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=121:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=131:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=141:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=151:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=161:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=171:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=181:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=191:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=201:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=211:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=221:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=231:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=241:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=251:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=261:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=271:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=281:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=291:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=301:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=311:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=321:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=331:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=341:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=351:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=361:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=371:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=381:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=391:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=401:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=411:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=421:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=431:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=441:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=451:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=461:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=471:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=481:U+0072:[rvrn_base=0+1529]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=491:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=501:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=511:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=521:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=531:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=541:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=551:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=561:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=571:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=581:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=591:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=601:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=611:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=621:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=631:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=641:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=651:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=661:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=671:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=681:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=691:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=701:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=711:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=721:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=731:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=741:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=751:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=761:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=771:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=781:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=791:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=801:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=811:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=821:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=831:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=841:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=851:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=861:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=871:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=881:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=891:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=901:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=911:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=921:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=931:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=941:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=951:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=961:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=971:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=981:U+0072:[rvrn_subst=0+1825]
+fonts/sha1sum/d23d76ea0909c14972796937ba072b5a40c1e257.ttf:--variations=FVTT=991:U+0072:[rvrn_subst=0+1825]
diff --git a/test/shaping/tests/vertical.tests b/test/shaping/tests/vertical.tests
index 3586080..e0b64d9 100644
--- a/test/shaping/tests/vertical.tests
+++ b/test/shaping/tests/vertical.tests
@@ -1,3 +1,3 @@
-fonts/sha1sum/191826b9643e3f124d865d617ae609db6a2ce203.ttf:--direction=t:U+300C:[uni300C.vert=0@-512,-578+0,-1024]
+fonts/sha1sum/191826b9643e3f124d865d617ae609db6a2ce203.ttf:--direction=t --font-funcs=ft:U+300C:[uni300C.vert=0@-512,-578+0,-1024]
 fonts/sha1sum/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ft:U+0041,U+0042:[gid1=0@-654,-2128+0,-2789|gid2=1@-665,-2125+0,-2789]
 fonts/sha1sum/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ot:U+0041,U+0042:[gid1=0@-654,-2189+0,-2789|gid2=1@-665,-2189+0,-2789]
diff --git a/util/ansi-print.cc b/util/ansi-print.cc
index e0ce7b3..0daee1f 100644
--- a/util/ansi-print.cc
+++ b/util/ansi-print.cc
@@ -353,7 +353,7 @@
 	} else
 	  qs += quad[i][j];
     if (qs < score) {
-      const char *c = NULL;
+      const char *c = nullptr;
       bool inv = false;
       switch (q) {
 	case 1:  c = "â–Ÿ"; inv = true;  break;
diff --git a/util/ansi-print.hh b/util/ansi-print.hh
index dad4d4c..1ea5b37 100644
--- a/util/ansi-print.hh
+++ b/util/ansi-print.hh
@@ -27,6 +27,7 @@
 #ifndef ANSI_PRINT_HH
 #define ANSI_PRINT_HH
 
+#include "hb-private.hh"
 #include <hb.h> /* for int types */
 
 void
diff --git a/util/hb-fc.cc b/util/hb-fc.cc
index e99b1ae..cb89991 100644
--- a/util/hb-fc.cc
+++ b/util/hb-fc.cc
@@ -82,7 +82,7 @@
   {
     hb_font_funcs_t *newfuncs = hb_font_funcs_create ();
 
-    hb_font_funcs_set_glyph_func (newfuncs, hb_fc_get_glyph, NULL, NULL);
+    hb_font_funcs_set_glyph_func (newfuncs, hb_fc_get_glyph, nullptr, nullptr);
 
     /* XXX MT-unsafe */
     if (fc_ffuncs)
@@ -121,7 +121,7 @@
 hb_bool_t
 hb_fc_can_render (hb_font_t *font, const char *text)
 {
-  static const char *ot[] = {"ot", NULL};
+  static const char *ot[] = {"ot", nullptr};
 
   hb_buffer_t *buffer = hb_buffer_create ();
   hb_buffer_add_utf8 (buffer, text, -1, 0, -1);
@@ -132,7 +132,7 @@
    * Might be better to force generic shaper perhaps. */
   hb_buffer_guess_segment_properties (buffer);
 
-  if (!hb_shape_full (font, buffer, NULL, 0, ot))
+  if (!hb_shape_full (font, buffer, nullptr, 0, ot))
     abort (); /* hb-ot shaper not enabled? */
 
   unsigned int len;
diff --git a/util/hb-ot-shape-closure.cc b/util/hb-ot-shape-closure.cc
index 859f9a6..77ca201 100644
--- a/util/hb-ot-shape-closure.cc
+++ b/util/hb-ot-shape-closure.cc
@@ -43,8 +43,8 @@
   {
     GOptionEntry entries[] =
     {
-      {"no-glyph-names",	0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,	&this->show_glyph_names,	"Use glyph indices instead of names",	NULL},
-      {NULL}
+      {"no-glyph-names",	0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,	&this->show_glyph_names,	"Use glyph indices instead of names",	nullptr},
+      {nullptr}
     };
     parser->add_group (entries,
 		       "format",
@@ -53,14 +53,15 @@
 		       this);
   }
 
-  void init (const font_options_t *font_opts)
+  void init (hb_buffer_t  *buffer_,
+	     const font_options_t *font_opts)
   {
     glyphs = hb_set_create ();
     font = hb_font_reference (font_opts->get_font ());
     failed = false;
+    buffer = hb_buffer_reference (buffer_);
   }
-  void consume_line (hb_buffer_t  *buffer,
-		     const char   *text,
+  void consume_line (const char   *text,
 		     unsigned int  text_len,
 		     const char   *text_before,
 		     const char   *text_after)
@@ -92,9 +93,11 @@
   {
     printf ("\n");
     hb_font_destroy (font);
-    font = NULL;
+    font = nullptr;
     hb_set_destroy (glyphs);
-    glyphs = NULL;
+    glyphs = nullptr;
+    hb_buffer_destroy (buffer);
+    buffer = nullptr;
   }
 
   bool failed;
@@ -105,6 +108,7 @@
 
   hb_set_t *glyphs;
   hb_font_t *font;
+  hb_buffer_t *buffer;
 };
 
 int
diff --git a/util/hb-shape.cc b/util/hb-shape.cc
index 3bd2184..dc9f446 100644
--- a/util/hb-shape.cc
+++ b/util/hb-shape.cc
@@ -33,14 +33,16 @@
   output_buffer_t (option_parser_t *parser)
 		  : options (parser, hb_buffer_serialize_list_formats ()),
 		    format (parser),
-		    gs (NULL),
+		    gs (nullptr),
 		    line_no (0),
-		    font (NULL) {}
+		    font (nullptr),
+		    output_format (HB_BUFFER_SERIALIZE_FORMAT_INVALID),
+		    format_flags (HB_BUFFER_SERIALIZE_FLAG_DEFAULT) {}
 
-  void init (const font_options_t *font_opts)
+  void init (hb_buffer_t *buffer, const font_options_t *font_opts)
   {
     options.get_file_handle ();
-    gs = g_string_new (NULL);
+    gs = g_string_new (nullptr);
     line_no = 0;
     font = hb_font_reference (font_opts->get_font ());
 
@@ -72,7 +74,12 @@
       flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
     if (format.show_extents)
       flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS;
+    if (format.show_flags)
+      flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS;
     format_flags = (hb_buffer_serialize_flags_t) flags;
+
+    if (format.trace)
+      hb_buffer_set_message_func (buffer, message_func, this, nullptr);
   }
   void new_line (void)
   {
@@ -87,13 +94,10 @@
     format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs);
     fprintf (options.fp, "%s", gs->str);
   }
-  void shape_failed (hb_buffer_t  *buffer,
-		     const char   *text,
-		     unsigned int  text_len,
-		     hb_bool_t     utf8_clusters)
+  void error (const char *message)
   {
     g_string_set_size (gs, 0);
-    format.serialize_message (line_no, "msg: all shapers failed", gs);
+    format.serialize_message (line_no, "error", message, gs);
     fprintf (options.fp, "%s", gs->str);
   }
   void consume_glyphs (hb_buffer_t  *buffer,
@@ -106,14 +110,40 @@
 				       output_format, format_flags, gs);
     fprintf (options.fp, "%s", gs->str);
   }
-  void finish (const font_options_t *font_opts)
+  void finish (hb_buffer_t *buffer, const font_options_t *font_opts)
   {
+    hb_buffer_set_message_func (buffer, nullptr, nullptr, nullptr);
     hb_font_destroy (font);
     g_string_free (gs, true);
-    gs = NULL;
-    font = NULL;
+    gs = nullptr;
+    font = nullptr;
   }
 
+  static hb_bool_t
+  message_func (hb_buffer_t *buffer,
+		hb_font_t *font,
+		const char *message,
+		void *user_data)
+  {
+    output_buffer_t *that = (output_buffer_t *) user_data;
+    that->trace (buffer, font, message);
+    return true;
+  }
+
+  void
+  trace (hb_buffer_t *buffer,
+	 hb_font_t *font,
+	 const char *message)
+  {
+    g_string_set_size (gs, 0);
+    format.serialize_line_no (line_no, gs);
+    g_string_append_printf (gs, "trace: %s	buffer: ", message);
+    format.serialize_glyphs (buffer, font, output_format, format_flags, gs);
+    g_string_append_c (gs, '\n');
+    fprintf (options.fp, "%s", gs->str);
+  }
+
+
   protected:
   output_options_t options;
   format_options_t format;
diff --git a/util/helper-cairo-ansi.hh b/util/helper-cairo-ansi.hh
index eeaaa50..cf18ea4 100644
--- a/util/helper-cairo-ansi.hh
+++ b/util/helper-cairo-ansi.hh
@@ -24,11 +24,12 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include <cairo.h>
-
 #ifndef HELPER_CAIRO_ANSI_HH
 #define HELPER_CAIRO_ANSI_HH
 
+#include "hb-private.hh"
+
+#include <cairo.h>
 
 cairo_status_t
 helper_cairo_surface_write_to_ansi_stream (cairo_surface_t	*surface,
diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc
index 2e2952b..b9f4985 100644
--- a/util/helper-cairo.cc
+++ b/util/helper-cairo.cc
@@ -79,7 +79,7 @@
   /* We cannot use the FT_Face from hb_font_t, as doing so will confuse hb_font_t because
    * cairo will reset the face size.  As such, create new face...
    * TODO Perhaps add API to hb-ft to encapsulate this code. */
-  FT_Face ft_face = NULL;//hb_ft_font_get_face (font);
+  FT_Face ft_face = nullptr;//hb_ft_font_get_face (font);
   if (!ft_face)
   {
     if (!ft_library)
@@ -103,6 +103,7 @@
   }
   else
   {
+#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
     unsigned int num_coords;
     const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
     if (num_coords)
@@ -116,6 +117,7 @@
 	free (ft_coords);
       }
     }
+#endif
 
     cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
   }
@@ -325,7 +327,7 @@
     "eps",
    #endif
   #endif
-  NULL
+  nullptr
 };
 
 cairo_t *
@@ -337,12 +339,12 @@
   cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
 				   void *closure,
 				   double width,
-				   double height) = NULL;
+				   double height) = nullptr;
   cairo_surface_t *(*constructor2) (cairo_write_func_t write_func,
 				    void *closure,
 				    double width,
 				    double height,
-				    cairo_content_t content) = NULL;
+				    cairo_content_t content) = nullptr;
 
   const char *extension = out_opts->output_format;
   if (!extension) {
@@ -471,8 +473,8 @@
   memset (l, 0, sizeof (*l));
 
   l->num_glyphs = hb_buffer_get_length (buffer);
-  hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, NULL);
-  hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, NULL);
+  hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr);
+  hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr);
   l->glyphs = cairo_glyph_allocate (l->num_glyphs + 1);
 
   if (text) {
diff --git a/util/helper-cairo.hh b/util/helper-cairo.hh
index 27b6eb3..50bc0af 100644
--- a/util/helper-cairo.hh
+++ b/util/helper-cairo.hh
@@ -24,13 +24,14 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#ifndef HELPER_CAIRO_HH
+#define HELPER_CAIRO_HH
+
+#include "hb-private.hh"
 #include "options.hh"
 
 #include <cairo.h>
 
-#ifndef HELPER_CAIRO_HH
-#define HELPER_CAIRO_HH
-
 
 cairo_scaled_font_t *
 helper_cairo_create_scaled_font (const font_options_t *font_opts);
diff --git a/util/main-font-text.hh b/util/main-font-text.hh
index 55de567..3390371 100644
--- a/util/main-font-text.hh
+++ b/util/main-font-text.hh
@@ -24,20 +24,21 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "options.hh"
-
 #ifndef HB_MAIN_FONT_TEXT_HH
 #define HB_MAIN_FONT_TEXT_HH
 
+#include "hb-private.hh"
+#include "options.hh"
+
 /* main() body for utilities taking font and processing text.*/
 
 static char *
 locale_to_utf8 (char *s)
 {
   char *t;
-  GError *error = NULL;
+  GError *error = nullptr;
 
-  t = g_locale_to_utf8 (s, -1, NULL, NULL, &error);
+  t = g_locale_to_utf8 (s, -1, nullptr, nullptr, &error);
   if (!t)
   {
      fail (true, "Failed converting text to UTF-8");
@@ -46,23 +47,6 @@
   return t;
 }
 
-static hb_bool_t
-message_func (hb_buffer_t *buffer,
-	      hb_font_t *font,
-	      const char *message,
-	      void *user_data)
-{
-  fprintf (stderr, "HB: %s\n", message);
-  char buf[4096];
-  hb_buffer_serialize_glyphs (buffer, 0, hb_buffer_get_length (buffer),
-			      buf, sizeof (buf), NULL,
-			      font,
-			      HB_BUFFER_SERIALIZE_FORMAT_TEXT,
-			      HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
-  fprintf (stderr, "HB: buffer [%s]\n", buf);
-  return true;
-}
-
 template <typename consumer_t, int default_font_size, int subpixel_bits>
 struct main_font_text_t
 {
@@ -87,16 +71,14 @@
     if (!input.text && !input.text_file)
       input.text_file = g_strdup ("-");
 
-    consumer.init (&font_opts);
-
     hb_buffer_t *buffer = hb_buffer_create ();
-    if (debug)
-      hb_buffer_set_message_func (buffer, message_func, NULL, NULL);
+    consumer.init (buffer, &font_opts);
+    hb_buffer_destroy (buffer);
+
     unsigned int text_len;
     const char *text;
     while ((text = input.get_line (&text_len)))
-      consumer.consume_line (buffer, text, text_len, input.text_before, input.text_after);
-    hb_buffer_destroy (buffer);
+      consumer.consume_line (text, text_len, input.text_before, input.text_after);
 
     consumer.finish (&font_opts);
 
diff --git a/util/options.cc b/util/options.cc
index 0f2e207..cba5206 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -70,7 +70,7 @@
 static gchar *
 shapers_to_string (void)
 {
-  GString *shapers = g_string_new (NULL);
+  GString *shapers = g_string_new (nullptr);
   const char **shaper_list = hb_shape_list_shapers ();
 
   for (; *shaper_list; shaper_list++) {
@@ -106,11 +106,11 @@
   GOptionEntry entries[] =
   {
     {"version",		0, G_OPTION_FLAG_NO_ARG,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &show_version,	"Show version numbers",			NULL},
-    {"debug",		0, 0, G_OPTION_ARG_NONE,	&debug,				"Free all resources before exit",	NULL},
-    {NULL}
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &show_version,	"Show version numbers",			nullptr},
+    {"debug",		0, 0, G_OPTION_ARG_NONE,	&debug,				"Free all resources before exit",	nullptr},
+    {nullptr}
   };
-  g_option_context_add_main_entries (context, entries, NULL);
+  g_option_context_add_main_entries (context, entries, nullptr);
 }
 
 static gboolean
@@ -121,7 +121,7 @@
 {
   option_group_t *option_group = (option_group_t *) data;
   option_group->pre_parse (error);
-  return *error == NULL;
+  return *error == nullptr;
 }
 
 static gboolean
@@ -132,7 +132,7 @@
 {
   option_group_t *option_group = static_cast<option_group_t *>(data);
   option_group->post_parse (error);
-  return *error == NULL;
+  return *error == nullptr;
 }
 
 void
@@ -143,7 +143,7 @@
 			    option_group_t *option_group)
 {
   GOptionGroup *group = g_option_group_new (name, description, help_description,
-					    static_cast<gpointer>(option_group), NULL);
+					    static_cast<gpointer>(option_group), nullptr);
   g_option_group_add_entries (group, entries);
   g_option_group_set_parse_hooks (group, pre_parse, post_parse);
   g_option_context_add_group (context, group);
@@ -154,10 +154,10 @@
 {
   setlocale (LC_ALL, "");
 
-  GError *parse_error = NULL;
+  GError *parse_error = nullptr;
   if (!g_option_context_parse (context, argc, argv, &parse_error))
   {
-    if (parse_error != NULL) {
+    if (parse_error != nullptr) {
       fail (true, "%s", parse_error->message);
       //g_error_free (parse_error);
     } else
@@ -225,7 +225,7 @@
 
   shape_opts->num_features = 0;
   g_free (shape_opts->features);
-  shape_opts->features = NULL;
+  shape_opts->features = nullptr;
 
   if (!*s)
     return true;
@@ -240,6 +240,8 @@
   } while (p);
 
   shape_opts->features = (hb_feature_t *) calloc (shape_opts->num_features, sizeof (*shape_opts->features));
+  if (!shape_opts->features)
+    return false;
 
   /* now do the actual parsing */
   p = s;
@@ -248,7 +250,7 @@
     char *end = strchr (p, ',');
     if (hb_feature_from_string (p, end ? end - p : -1, &shape_opts->features[shape_opts->num_features]))
       shape_opts->num_features++;
-    p = end ? end + 1 : NULL;
+    p = end ? end + 1 : nullptr;
   }
 
   return true;
@@ -266,7 +268,7 @@
 
   font_opts->num_variations = 0;
   g_free (font_opts->variations);
-  font_opts->variations = NULL;
+  font_opts->variations = nullptr;
 
   if (!*s)
     return true;
@@ -281,6 +283,8 @@
   } while (p);
 
   font_opts->variations = (hb_variation_t *) calloc (font_opts->num_variations, sizeof (*font_opts->variations));
+  if (!font_opts->variations)
+    return false;
 
   /* now do the actual parsing */
   p = s;
@@ -289,24 +293,86 @@
     char *end = strchr (p, ',');
     if (hb_variation_from_string (p, end ? end - p : -1, &font_opts->variations[font_opts->num_variations]))
       font_opts->num_variations++;
-    p = end ? end + 1 : NULL;
+    p = end ? end + 1 : nullptr;
   }
 
   return true;
 }
 
+static gboolean
+parse_text (const char *name G_GNUC_UNUSED,
+	    const char *arg,
+	    gpointer    data,
+	    GError    **error G_GNUC_UNUSED)
+{
+  text_options_t *text_opts = (text_options_t *) data;
+
+  if (text_opts->text)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text or --unicodes can be provided but not both");
+    return false;
+  }
+
+  text_opts->text = g_strdup (arg);
+  return true;
+}
+
+
+static gboolean
+parse_unicodes (const char *name G_GNUC_UNUSED,
+	        const char *arg,
+	        gpointer    data,
+	        GError    **error G_GNUC_UNUSED)
+{
+  text_options_t *text_opts = (text_options_t *) data;
+
+  if (text_opts->text)
+  {
+    g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+		 "Either --text or --unicodes can be provided but not both");
+    return false;
+  }
+
+  GString *gs = g_string_new (nullptr);
+  char *s = (char *) arg;
+  char *p;
+
+  while (s && *s)
+  {
+    while (*s && strchr ("<+>{},;&#\\xXuUnNiI\n\t", *s))
+      s++;
+
+    errno = 0;
+    hb_codepoint_t u = strtoul (s, &p, 16);
+    if (errno || s == p)
+    {
+      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;
+  }
+
+  text_opts->text = g_string_free (gs, FALSE);
+  return true;
+}
+
 
 void
 view_options_t::add_options (option_parser_t *parser)
 {
   GOptionEntry entries[] =
   {
-    {"annotate",	0, 0, G_OPTION_ARG_NONE,	&this->annotate,		"Annotate output rendering",				NULL},
+    {"annotate",	0, 0, G_OPTION_ARG_NONE,	&this->annotate,		"Annotate output rendering",				nullptr},
     {"background",	0, 0, G_OPTION_ARG_STRING,	&this->back,			"Set background color (default: " DEFAULT_BACK ")",	"rrggbb/rrggbbaa"},
     {"foreground",	0, 0, G_OPTION_ARG_STRING,	&this->fore,			"Set foreground color (default: " DEFAULT_FORE ")",	"rrggbb/rrggbbaa"},
     {"line-space",	0, 0, G_OPTION_ARG_DOUBLE,	&this->line_space,		"Set space between lines (default: 0)",			"units"},
     {"margin",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_margin,	"Margin around output (default: " G_STRINGIFY(DEFAULT_MARGIN) ")","one to four numbers"},
-    {NULL}
+    {nullptr}
   };
   parser->add_group (entries,
 		     "view",
@@ -321,21 +387,22 @@
   GOptionEntry entries[] =
   {
     {"list-shapers",	0, G_OPTION_FLAG_NO_ARG,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &list_shapers,	"List available shapers and quit",	NULL},
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &list_shapers,	"List available shapers and quit",	nullptr},
     {"shaper",		0, G_OPTION_FLAG_HIDDEN,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_shapers,	"Hidden duplicate of --shapers",	NULL},
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_shapers,	"Hidden duplicate of --shapers",	nullptr},
     {"shapers",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_shapers,	"Set comma-separated list of shapers to try","list"},
     {"direction",	0, 0, G_OPTION_ARG_STRING,	&this->direction,		"Set text direction (default: auto)",	"ltr/rtl/ttb/btt"},
     {"language",	0, 0, G_OPTION_ARG_STRING,	&this->language,		"Set text language (default: $LANG)",	"langstr"},
     {"script",		0, 0, G_OPTION_ARG_STRING,	&this->script,			"Set text script (default: auto)",	"ISO-15924 tag"},
-    {"bot",		0, 0, G_OPTION_ARG_NONE,	&this->bot,			"Treat text as beginning-of-paragraph",	NULL},
-    {"eot",		0, 0, G_OPTION_ARG_NONE,	&this->eot,			"Treat text as end-of-paragraph",	NULL},
-    {"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE,	&this->preserve_default_ignorables,	"Preserve Default-Ignorable characters",	NULL},
-    {"utf8-clusters",	0, 0, G_OPTION_ARG_NONE,	&this->utf8_clusters,		"Use UTF8 byte indices, not char indices",	NULL},
+    {"bot",		0, 0, G_OPTION_ARG_NONE,	&this->bot,			"Treat text as beginning-of-paragraph",	nullptr},
+    {"eot",		0, 0, G_OPTION_ARG_NONE,	&this->eot,			"Treat text as end-of-paragraph",	nullptr},
+    {"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE,	&this->preserve_default_ignorables,	"Preserve Default-Ignorable characters",	nullptr},
+    {"utf8-clusters",	0, 0, G_OPTION_ARG_NONE,	&this->utf8_clusters,		"Use UTF8 byte indices, not char indices",	nullptr},
     {"cluster-level",	0, 0, G_OPTION_ARG_INT,		&this->cluster_level,		"Cluster merging level (default: 0)",	"0/1/2"},
-    {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE,	&this->normalize_glyphs,	"Rearrange glyph clusters in nominal order",	NULL},
+    {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE,	&this->normalize_glyphs,	"Rearrange glyph clusters in nominal order",	nullptr},
+    {"verify",		0, 0, G_OPTION_ARG_NONE,	&this->verify,			"Perform sanity checks on shaping results",	nullptr},
     {"num-iterations",	0, 0, G_OPTION_ARG_INT,		&this->num_iterations,		"Run shaper N times (default: 1)",	"N"},
-    {NULL}
+    {nullptr}
   };
   parser->add_group (entries,
 		     "shape",
@@ -382,7 +449,7 @@
   GOptionEntry entries2[] =
   {
     {"features",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_features,	features_help,	"list"},
-    {NULL}
+    {nullptr}
   };
   parser->add_group (entries2,
 		     "features",
@@ -408,7 +475,7 @@
     case 2: return true;
     default:
       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
-		   "%s argument should be one to four space-separated numbers",
+		   "%s argument should be one or two space-separated numbers",
 		   name);
       return false;
   }
@@ -416,11 +483,12 @@
 void
 font_options_t::add_options (option_parser_t *parser)
 {
-  char *text = NULL;
+  char *text = nullptr;
 
   {
-    ASSERT_STATIC (ARRAY_LENGTH_CONST (supported_font_funcs) > 0);
-    GString *s = g_string_new (NULL);
+    static_assert ((ARRAY_LENGTH_CONST (supported_font_funcs) > 0),
+		   "No supported font-funcs found.");
+    GString *s = g_string_new (nullptr);
     g_string_printf (s, "Set font functions implementation to use (default: %s)\n\n    Supported font function implementations are: %s",
 		     supported_font_funcs[0].name,
 		     supported_font_funcs[0].name);
@@ -449,7 +517,7 @@
     {"font-size",	0, default_font_size ? 0 : G_OPTION_FLAG_HIDDEN,
 			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_font_size,	font_size_text,				"1/2 numbers or 'upem'"},
     {"font-funcs",	0, 0, G_OPTION_ARG_STRING,	&this->font_funcs,		text,					"impl"},
-    {NULL}
+    {nullptr}
   };
   parser->add_group (entries,
 		     "font",
@@ -472,7 +540,7 @@
   GOptionEntry entries2[] =
   {
     {"variations",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_variations,	variations_help,	"list"},
-    {NULL}
+    {nullptr}
   };
   parser->add_group (entries2,
 		     "variations",
@@ -486,11 +554,12 @@
 {
   GOptionEntry entries[] =
   {
-    {"text",		0, 0, G_OPTION_ARG_STRING,	&this->text,			"Set input text",			"string"},
+    {"text",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_text,		"Set input text",			"string"},
     {"text-file",	0, 0, G_OPTION_ARG_STRING,	&this->text_file,		"Set input text file-name\n\n    If no text is provided, standard input is used for input.\n",		"filename"},
+    {"unicodes",      'u', 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_unicodes,		"Set input Unicode codepoints",		"list of hex numbers"},
     {"text-before",	0, 0, G_OPTION_ARG_STRING,	&this->text_before,		"Set text context before each line",	"string"},
     {"text-after",	0, 0, G_OPTION_ARG_STRING,	&this->text_after,		"Set text context after each line",	"string"},
-    {NULL}
+    {nullptr}
   };
   parser->add_group (entries,
 		     "text",
@@ -504,7 +573,7 @@
 {
   const char *text;
 
-  if (NULL == supported_formats)
+  if (nullptr == supported_formats)
     text = "Set output serialization format";
   else
   {
@@ -516,9 +585,9 @@
 
   GOptionEntry entries[] =
   {
-    {"output-file",	0, 0, G_OPTION_ARG_STRING,	&this->output_file,		"Set output file-name (default: stdout)","filename"},
-    {"output-format",	0, 0, G_OPTION_ARG_STRING,	&this->output_format,		text,					"format"},
-    {NULL}
+    {"output-file",   'o', 0, G_OPTION_ARG_STRING,	&this->output_file,		"Set output file-name (default: stdout)","filename"},
+    {"output-format", 'O', 0, G_OPTION_ARG_STRING,	&this->output_format,		text,					"format"},
+    {nullptr}
   };
   parser->add_group (entries,
 		     "output",
@@ -535,7 +604,7 @@
   if (font)
     return font;
 
-  hb_blob_t *blob = NULL;
+  hb_blob_t *blob = nullptr;
 
   /* Create the blob */
   {
@@ -551,7 +620,7 @@
 
     if (0 == strcmp (font_file, "-")) {
       /* read it */
-      GString *gs = g_string_new (NULL);
+      GString *gs = g_string_new (nullptr);
       char buf[BUFSIZ];
 #if defined(_WIN32) || defined(__CYGWIN__)
       setmode (fileno (stdin), O_BINARY);
@@ -569,7 +638,7 @@
       destroy = (hb_destroy_func_t) g_free;
       mm = HB_MEMORY_MODE_WRITABLE;
     } else {
-      GError *error = NULL;
+      GError *error = nullptr;
       GMappedFile *mf = g_mapped_file_new (font_file, false, &error);
       if (mf) {
 	font_data = g_mapped_file_get_contents (mf);
@@ -588,7 +657,7 @@
 	/* GMappedFile is buggy, it doesn't fail if file isn't regular.
 	 * Try reading.
 	 * https://bugzilla.gnome.org/show_bug.cgi?id=659212 */
-        GError *error = NULL;
+        GError *error = nullptr;
 	gsize l;
 	if (g_file_get_contents (font_file, &font_data, &l, &error)) {
 	  len = l;
@@ -627,7 +696,7 @@
 
   hb_font_set_variations (font, variations, num_variations);
 
-  void (*set_font_funcs) (hb_font_t *) = NULL;
+  void (*set_font_funcs) (hb_font_t *) = nullptr;
   if (!font_funcs)
   {
     set_font_funcs = supported_font_funcs[0].func;
@@ -642,7 +711,7 @@
       }
     if (!set_font_funcs)
     {
-      GString *s = g_string_new (NULL);
+      GString *s = g_string_new (nullptr);
       for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
       {
         if (i)
@@ -673,7 +742,7 @@
 
     if (!line_len) {
       *len = 0;
-      return NULL;
+      return nullptr;
     }
 
     const char *ret = line;
@@ -706,7 +775,7 @@
       fail (false, "Failed opening text file `%s': %s",
 	    text_file, strerror (errno));
 
-    gs = g_string_new (NULL);
+    gs = g_string_new (nullptr);
   }
 
   g_string_set_size (gs, 0);
@@ -724,7 +793,7 @@
     fail (false, "Failed reading text: %s",
 	  strerror (errno));
   *len = gs->len;
-  return !*len && feof (fp) ? NULL : gs->str;
+  return !*len && feof (fp) ? nullptr : gs->str;
 }
 
 
@@ -765,19 +834,21 @@
 {
   GOptionEntry entries[] =
   {
-    {"show-text",	0, 0, G_OPTION_ARG_NONE,	&this->show_text,		"Prefix each line of output with its corresponding input text",		NULL},
-    {"show-unicode",	0, 0, G_OPTION_ARG_NONE,	&this->show_unicode,		"Prefix each line of output with its corresponding input codepoint(s)",	NULL},
-    {"show-line-num",	0, 0, G_OPTION_ARG_NONE,	&this->show_line_num,		"Prefix each line of output with its corresponding input line number",	NULL},
-    {"verbose",		0, G_OPTION_FLAG_NO_ARG,
-			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_verbose,	"Prefix each line of output with all of the above",			NULL},
+    {"show-text",	0, 0, G_OPTION_ARG_NONE,	&this->show_text,		"Prefix each line of output with its corresponding input text",		nullptr},
+    {"show-unicode",	0, 0, G_OPTION_ARG_NONE,	&this->show_unicode,		"Prefix each line of output with its corresponding input codepoint(s)",	nullptr},
+    {"show-line-num",	0, 0, G_OPTION_ARG_NONE,	&this->show_line_num,		"Prefix each line of output with its corresponding input line number",	nullptr},
+    {"verbose",	      'v', G_OPTION_FLAG_NO_ARG,
+			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_verbose,	"Prefix each line of output with all of the above",			nullptr},
     {"no-glyph-names",	0, G_OPTION_FLAG_REVERSE,
-			      G_OPTION_ARG_NONE,	&this->show_glyph_names,	"Output glyph indices instead of names",				NULL},
+			      G_OPTION_ARG_NONE,	&this->show_glyph_names,	"Output glyph indices instead of names",				nullptr},
     {"no-positions",	0, G_OPTION_FLAG_REVERSE,
-			      G_OPTION_ARG_NONE,	&this->show_positions,		"Do not output glyph positions",					NULL},
+			      G_OPTION_ARG_NONE,	&this->show_positions,		"Do not output glyph positions",					nullptr},
     {"no-clusters",	0, G_OPTION_FLAG_REVERSE,
-			      G_OPTION_ARG_NONE,	&this->show_clusters,		"Do not output cluster indices",					NULL},
-    {"show-extents",	0, 0, G_OPTION_ARG_NONE,	&this->show_extents,		"Output glyph extents",							NULL},
-    {NULL}
+			      G_OPTION_ARG_NONE,	&this->show_clusters,		"Do not output cluster indices",					nullptr},
+    {"show-extents",	0, 0, G_OPTION_ARG_NONE,	&this->show_extents,		"Output glyph extents",							nullptr},
+    {"show-flags",	0, 0, G_OPTION_ARG_NONE,	&this->show_flags,		"Output glyph flags",							nullptr},
+    {"trace",	      'V', 0, G_OPTION_ARG_NONE,	&this->trace,			"Output interim shaping results",					nullptr},
+    {nullptr}
   };
   parser->add_group (entries,
 		     "output-syntax",
@@ -794,7 +865,7 @@
 				     GString     *gs)
 {
   unsigned int num_glyphs = hb_buffer_get_length (buffer);
-  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
 
   g_string_append_c (gs, '<');
   for (unsigned int i = 0; i < num_glyphs; i++)
@@ -818,7 +889,8 @@
   unsigned int num_glyphs = hb_buffer_get_length (buffer);
   unsigned int start = 0;
 
-  while (start < num_glyphs) {
+  while (start < num_glyphs)
+  {
     char buf[1024];
     unsigned int consumed;
     start += hb_buffer_serialize_glyphs (buffer, start, num_glyphs,
@@ -845,7 +917,8 @@
 					    hb_font_t    *font,
 					    GString      *gs)
 {
-  if (show_text) {
+  if (show_text)
+  {
     serialize_line_no (line_no, gs);
     g_string_append_c (gs, '(');
     g_string_append_len (gs, text, text_len);
@@ -853,7 +926,8 @@
     g_string_append_c (gs, '\n');
   }
 
-  if (show_unicode) {
+  if (show_unicode)
+  {
     serialize_line_no (line_no, gs);
     serialize_unicode (buffer, gs);
     g_string_append_c (gs, '\n');
@@ -861,11 +935,12 @@
 }
 void
 format_options_t::serialize_message (unsigned int  line_no,
+				     const char   *type,
 				     const char   *msg,
 				     GString      *gs)
 {
   serialize_line_no (line_no, gs);
-  g_string_append_printf (gs, "%s", msg);
+  g_string_append_printf (gs, "%s: %s", type, msg);
   g_string_append_c (gs, '\n');
 }
 void
diff --git a/util/options.hh b/util/options.hh
index 9ed4fd0..4f9d85e 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -27,15 +27,13 @@
 #ifndef OPTIONS_HH
 #define OPTIONS_HH
 
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "hb-private.hh"
 
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
 #include <stdio.h>
+#include <assert.h>
 #include <math.h>
 #include <locale.h>
 #include <errno.h>
@@ -58,35 +56,8 @@
 # define g_mapped_file_unref g_mapped_file_free
 #endif
 
-
-/* A few macros copied from hb-private.hh. */
-
-#if __GNUC__ >= 4
-#define HB_UNUSED	__attribute__((unused))
-#else
-#define HB_UNUSED
-#endif
-
-#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; }
-
-#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])))
-
-#define _ASSERT_STATIC1(_line, _cond)	HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
-#define _ASSERT_STATIC0(_line, _cond)	_ASSERT_STATIC1 (_line, (_cond))
-#define ASSERT_STATIC(_cond)		_ASSERT_STATIC0 (__LINE__, (_cond))
-
-
 void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3);
 
-
 extern hb_bool_t debug;
 
 struct option_group_t
@@ -110,7 +81,7 @@
   }
   ~option_parser_t (void) {
     g_option_context_free (context);
-    g_ptr_array_foreach (to_free, (GFunc) g_free, NULL);
+    g_ptr_array_foreach (to_free, (GFunc) g_free, nullptr);
     g_ptr_array_free (to_free, TRUE);
   }
 
@@ -150,8 +121,8 @@
 {
   view_options_t (option_parser_t *parser) {
     annotate = false;
-    fore = NULL;
-    back = NULL;
+    fore = nullptr;
+    back = nullptr;
     line_space = 0;
     margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN;
 
@@ -179,14 +150,15 @@
 {
   shape_options_t (option_parser_t *parser)
   {
-    direction = language = script = NULL;
+    direction = language = script = nullptr;
     bot = eot = preserve_default_ignorables = false;
-    features = NULL;
+    features = nullptr;
     num_features = 0;
-    shapers = NULL;
+    shapers = nullptr;
     utf8_clusters = false;
     cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
     normalize_glyphs = false;
+    verify = false;
     num_iterations = 1;
 
     add_options (parser);
@@ -215,6 +187,15 @@
     hb_buffer_guess_segment_properties (buffer);
   }
 
+  static void copy_buffer_properties (hb_buffer_t *dst, hb_buffer_t *src)
+  {
+    hb_segment_properties_t props;
+    hb_buffer_get_segment_properties (src, &props);
+    hb_buffer_set_segment_properties (dst, &props);
+    hb_buffer_set_flags (dst, hb_buffer_get_flags (src));
+    hb_buffer_set_cluster_level (dst, hb_buffer_get_cluster_level (src));
+  }
+
   void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
 			const char *text_before, const char *text_after)
   {
@@ -232,7 +213,7 @@
       /* Reset cluster values to refer to Unicode character index
        * instead of UTF-8 index. */
       unsigned int num_glyphs = hb_buffer_get_length (buffer);
-      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
       for (unsigned int i = 0; i < num_glyphs; i++)
       {
 	info->cluster = i;
@@ -243,12 +224,182 @@
     setup_buffer (buffer);
   }
 
-  hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer)
+  hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=nullptr)
   {
-    hb_bool_t res = hb_shape_full (font, buffer, features, num_features, shapers);
+    hb_buffer_t *text_buffer = nullptr;
+    if (verify)
+    {
+      text_buffer = hb_buffer_create ();
+      hb_buffer_append (text_buffer, buffer, 0, -1);
+    }
+
+    if (!hb_shape_full (font, buffer, features, num_features, shapers))
+    {
+      if (error)
+        *error = "all shapers failed.";
+      return false;
+    }
+
     if (normalize_glyphs)
       hb_buffer_normalize_glyphs (buffer);
-    return res;
+
+    if (verify && !verify_buffer (buffer, text_buffer, font, error))
+      return false;
+
+    if (text_buffer)
+      hb_buffer_destroy (text_buffer);
+
+    return true;
+  }
+
+  bool verify_buffer (hb_buffer_t  *buffer,
+		      hb_buffer_t  *text_buffer,
+		      hb_font_t    *font,
+		      const char  **error=nullptr)
+  {
+    if (!verify_buffer_monotone (buffer, error))
+      return false;
+    if (!verify_buffer_safe_to_break (buffer, text_buffer, font, error))
+      return false;
+    return true;
+  }
+
+  bool verify_buffer_monotone (hb_buffer_t *buffer, const char **error=nullptr)
+  {
+    /* Check that clusters are monotone. */
+    if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
+	cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+    {
+      bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+
+      unsigned int num_glyphs;
+      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+      for (unsigned int i = 1; i < num_glyphs; i++)
+	if (info[i-1].cluster != info[i].cluster &&
+	    (info[i-1].cluster < info[i].cluster) != is_forward)
+	{
+	  if (error)
+	    *error = "clusters are not monotone.";
+	  return false;
+	}
+    }
+
+    return true;
+  }
+
+  bool verify_buffer_safe_to_break (hb_buffer_t  *buffer,
+				    hb_buffer_t  *text_buffer,
+				    hb_font_t    *font,
+				    const char  **error=nullptr)
+  {
+    if (cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES &&
+	cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+    {
+      /* Cannot perform this check without monotone clusters.
+       * Then again, unsafe-to-break flag is much harder to use without
+       * monotone clusters. */
+      return true;
+    }
+
+    /* Check that breaking up shaping at safe-to-break is indeed safe. */
+
+    hb_buffer_t *fragment = hb_buffer_create ();
+    hb_buffer_t *reconstruction = hb_buffer_create ();
+    copy_buffer_properties (reconstruction, buffer);
+
+    unsigned int num_glyphs;
+    hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);
+
+    unsigned int num_chars;
+    hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars);
+
+    /* Chop text and shape fragments. */
+    bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));
+    unsigned int start = 0;
+    unsigned int text_start = forward ? 0 : num_chars;
+    unsigned int text_end = text_start;
+    for (unsigned int end = 1; end < num_glyphs + 1; end++)
+    {
+      if (end < num_glyphs &&
+	  (info[end].cluster == info[end-1].cluster ||
+	   info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK))
+	  continue;
+
+      /* Shape segment corresponding to glyphs start..end. */
+      if (end == num_glyphs)
+      {
+        if (forward)
+	  text_end = num_chars;
+	else
+	  text_start = 0;
+      }
+      else
+      {
+	if (forward)
+	{
+	  unsigned int cluster = info[end].cluster;
+	  while (text_end < num_chars && text[text_end].cluster < cluster)
+	    text_end++;
+	}
+	else
+	{
+	  unsigned int cluster = info[end - 1].cluster;
+	  while (text_start && text[text_start - 1].cluster >= cluster)
+	    text_start--;
+	}
+      }
+      assert (text_start < text_end);
+
+      if (0)
+	printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+
+      hb_buffer_clear_contents (fragment);
+      copy_buffer_properties (fragment, buffer);
+
+      /* 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);
+      if (text_end < num_chars)
+        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);
+      if (!hb_shape_full (font, fragment, features, num_features, shapers))
+      {
+	if (error)
+	  *error = "all shapers failed while shaping fragment.";
+	hb_buffer_destroy (reconstruction);
+	hb_buffer_destroy (fragment);
+	return false;
+      }
+      hb_buffer_append (reconstruction, fragment, 0, -1);
+
+      start = end;
+      if (forward)
+	text_start = text_end;
+      else
+	text_end = text_start;
+    }
+
+    bool ret = true;
+    hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+    if (diff)
+    {
+      if (error)
+	*error = "Safe-to-break test failed.";
+      ret = false;
+
+      /* Return the reconstructed result instead so it can be inspected. */
+      hb_buffer_set_length (buffer, 0);
+      hb_buffer_append (buffer, reconstruction, 0, -1);
+    }
+
+    hb_buffer_destroy (reconstruction);
+    hb_buffer_destroy (fragment);
+
+    return ret;
   }
 
   void shape_closure (const char *text, int text_len,
@@ -277,6 +428,7 @@
   hb_bool_t utf8_clusters;
   hb_buffer_cluster_level_t cluster_level;
   hb_bool_t normalize_glyphs;
+  hb_bool_t verify;
   unsigned int num_iterations;
 };
 
@@ -287,16 +439,16 @@
 		  int default_font_size_,
 		  unsigned int subpixel_bits_)
   {
-    variations = NULL;
+    variations = nullptr;
     num_variations = 0;
     default_font_size = default_font_size_;
     subpixel_bits = subpixel_bits_;
-    font_file = NULL;
+    font_file = nullptr;
     face_index = 0;
     font_size_x = font_size_y = default_font_size;
-    font_funcs = NULL;
+    font_funcs = nullptr;
 
-    font = NULL;
+    font = nullptr;
 
     add_options (parser);
   }
@@ -329,15 +481,15 @@
 struct text_options_t : option_group_t
 {
   text_options_t (option_parser_t *parser) {
-    text_before = NULL;
-    text_after = NULL;
+    text_before = nullptr;
+    text_after = nullptr;
 
-    text = NULL;
-    text_file = NULL;
+    text = nullptr;
+    text_file = nullptr;
 
-    fp = NULL;
-    gs = NULL;
-    line = NULL;
+    fp = nullptr;
+    gs = nullptr;
+    line = nullptr;
     line_len = (unsigned int) -1;
 
     add_options (parser);
@@ -380,13 +532,13 @@
 struct output_options_t : option_group_t
 {
   output_options_t (option_parser_t *parser,
-		    const char **supported_formats_ = NULL) {
-    output_file = NULL;
-    output_format = NULL;
+		    const char **supported_formats_ = nullptr) {
+    output_file = nullptr;
+    output_format = nullptr;
     supported_formats = supported_formats_;
     explicit_output_format = false;
 
-    fp = NULL;
+    fp = nullptr;
 
     add_options (parser);
   }
@@ -414,7 +566,7 @@
     }
 
     if (output_file && 0 == strcmp (output_file, "-"))
-      output_file = NULL; /* STDOUT */
+      output_file = nullptr; /* STDOUT */
   }
 
   FILE *get_file_handle (void);
@@ -437,6 +589,8 @@
     show_unicode = false;
     show_line_num = false;
     show_extents = false;
+    show_flags = false;
+    trace = false;
 
     add_options (parser);
   }
@@ -459,6 +613,7 @@
 				 hb_font_t    *font,
 				 GString      *gs);
   void serialize_message (unsigned int  line_no,
+			  const char   *type,
 			  const char   *msg,
 			  GString      *gs);
   void serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
@@ -478,6 +633,8 @@
   hb_bool_t show_unicode;
   hb_bool_t show_line_num;
   hb_bool_t show_extents;
+  hb_bool_t show_flags;
+  hb_bool_t trace;
 };
 
 /* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */
diff --git a/util/shape-consumer.hh b/util/shape-consumer.hh
index 422c8cd..fa419f1 100644
--- a/util/shape-consumer.hh
+++ b/util/shape-consumer.hh
@@ -24,11 +24,12 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "options.hh"
-
 #ifndef HB_SHAPE_CONSUMER_HH
 #define HB_SHAPE_CONSUMER_HH
 
+#include "hb-private.hh"
+#include "options.hh"
+
 
 template <typename output_t>
 struct shape_consumer_t
@@ -37,16 +38,19 @@
 		  : failed (false),
 		    shaper (parser),
 		    output (parser),
-		    font (NULL) {}
+		    font (nullptr),
+		    buffer (nullptr) {}
 
-  void init (const font_options_t *font_opts)
+  void init (hb_buffer_t  *buffer_,
+	     const font_options_t *font_opts)
   {
     font = hb_font_reference (font_opts->get_font ());
-    output.init (font_opts);
     failed = false;
+    buffer = hb_buffer_reference (buffer_);
+
+    output.init (buffer, font_opts);
   }
-  void consume_line (hb_buffer_t  *buffer,
-		     const char   *text,
+  void consume_line (const char   *text,
 		     unsigned int  text_len,
 		     const char   *text_before,
 		     const char   *text_after)
@@ -55,14 +59,19 @@
 
     for (unsigned int n = shaper.num_iterations; n; n--)
     {
+      const char *error = nullptr;
+
       shaper.populate_buffer (buffer, text, text_len, text_before, text_after);
       if (n == 1)
 	output.consume_text (buffer, text, text_len, shaper.utf8_clusters);
-      if (!shaper.shape (font, buffer)) {
+      if (!shaper.shape (font, buffer, &error))
+      {
 	failed = true;
-	hb_buffer_set_length (buffer, 0);
-	output.shape_failed (buffer, text, text_len, shaper.utf8_clusters);
-	return;
+	output.error (error);
+	if (hb_buffer_get_content_type (buffer) == HB_BUFFER_CONTENT_TYPE_GLYPHS)
+	  break;
+	else
+	  return;
       }
     }
 
@@ -70,9 +79,11 @@
   }
   void finish (const font_options_t *font_opts)
   {
-    output.finish (font_opts);
+    output.finish (buffer, font_opts);
     hb_font_destroy (font);
-    font = NULL;
+    font = nullptr;
+    hb_buffer_destroy (buffer);
+    buffer = nullptr;
   }
 
   public:
@@ -83,6 +94,7 @@
   output_t output;
 
   hb_font_t *font;
+  hb_buffer_t *buffer;
 };
 
 
diff --git a/util/view-cairo.hh b/util/view-cairo.hh
index f55d4bb..d28c3cd 100644
--- a/util/view-cairo.hh
+++ b/util/view-cairo.hh
@@ -24,12 +24,13 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "options.hh"
-#include "helper-cairo.hh"
-
 #ifndef VIEW_CAIRO_HH
 #define VIEW_CAIRO_HH
 
+#include "hb-private.hh"
+#include "options.hh"
+#include "helper-cairo.hh"
+
 
 struct view_cairo_t
 {
@@ -43,7 +44,7 @@
       cairo_debug_reset_static_data ();
   }
 
-  void init (const font_options_t *font_opts)
+  void init (hb_buffer_t *buffer, const font_options_t *font_opts)
   {
     lines = g_array_new (false, false, sizeof (helper_cairo_line_t));
     scale_bits = -font_opts->subpixel_bits;
@@ -57,12 +58,9 @@
 		     hb_bool_t     utf8_clusters)
   {
   }
-  void shape_failed (hb_buffer_t  *buffer,
-		     const char   *text,
-		     unsigned int  text_len,
-		     hb_bool_t     utf8_clusters)
+  void error (const char *message)
   {
-    fail (false, "all shapers failed");
+    g_printerr ("%s: %s\n", g_get_prgname (), message);
   }
   void consume_glyphs (hb_buffer_t  *buffer,
 		       const char   *text,
@@ -74,7 +72,7 @@
     helper_cairo_line_from_buffer (&l, buffer, text, text_len, scale_bits, utf8_clusters);
     g_array_append_val (lines, l);
   }
-  void finish (const font_options_t *font_opts)
+  void finish (hb_buffer_t *buffer, const font_options_t *font_opts)
   {
     render (font_opts);
 
diff --git a/win32/Makefile.am b/win32/Makefile.am
deleted file mode 100644
index 63ba468..0000000
--- a/win32/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-EXTRA_DIST = \
-	build-rules-msvc.mak \
-	config-msvc.mak \
-	config.h.win32 \
-	create-lists.bat \
-	create-lists-msvc.mak \
-	detectenv-msvc.mak \
-	generate-msvc.mak \
-	hb-introspection-msvc.mak \
-	info-msvc.mak \
-	install.mak \
-	introspection-msvc.mak \
-	Makefile.vc \
-	README.txt
-
--include $(top_srcdir)/git.mk
diff --git a/win32/Makefile.vc b/win32/Makefile.vc
deleted file mode 100644
index fdde7a7..0000000
--- a/win32/Makefile.vc
+++ /dev/null
@@ -1,52 +0,0 @@
-# NMake Makefile for building HarfBuzz as a DLL on Windows
-
-# The items below this line should not be changed, unless one is maintaining
-# the NMake Makefiles.  Customizations can be done in the following NMake Makefile
-# portions (please see comments in the these files to see what can be customized):
-#
-# detectenv-msvc.mak
-# config-msvc.mak
-
-!include detectenv-msvc.mak
-
-# Include the Makefile portions with the source listings
-!include ..\src\Makefile.sources
-!include ..\src\hb-ucdn\Makefile.sources
-!include ..\util\Makefile.sources
-
-# Include the Makefile portion that enables features based on user input
-!include config-msvc.mak
-
-!if "$(VALID_CFGSET)" == "TRUE"
-
-# Include the Makefile portion to convert the source and header lists
-# into the lists we need for compilation and introspection
-!include create-lists-msvc.mak
-
-all: $(HB_LIBS) $(HB_UTILS) $(EXTRA_TARGETS) all-build-info
-
-tests: all $(HB_TESTS)
-
-# Include the build rules for sources, DLLs and executables
-!include build-rules-msvc.mak
-
-# Include the rules for build directory creation and code generation
-!include generate-msvc.mak
-
-# Generate the introspection files
-
-!if "$(INTROSPECTION)" == "1"
-# Include the rules for building the introspection files
-!include introspection-msvc.mak
-!include hb-introspection-msvc.mak
-!endif
-
-!include install.mak
-
-!else
-all: help
-	@echo You need to specify a valid configuration, via
-	@echo CFG=release or CFG=debug
-!endif
-
-!include info-msvc.mak
diff --git a/win32/README.txt b/win32/README.txt
deleted file mode 100644
index af0dc15..0000000
--- a/win32/README.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-Instructions for building HarfBuzz on Visual Studio

-===================================================

-Building the HarfBuzz DLL on Windows is now also supported using Visual Studio

-versions 2008 through 2015, in both 32-bit and 64-bit (x64) flavors, via NMake

-Makefiles.

-

-The following are instructions for performing such a build, as there is a

-number of build configurations supported for the build.  Note that for all

-build configurations, the OpenType and Simple TrueType layout (fallback)

-backends are enabled, and this is the base configuration that is built if no

-options (see below) are specified.  A 'clean' target is provided-it is recommended

-that one cleans the build and redo the build if any configuration option changed.

-An 'install' target is also provided to copy the built items in their appropriate

-locations under $(PREFIX), which is described below.

-

-Invoke the build by issuing the command:

-nmake /f Makefile.vc CFG=[release|debug] [PREFIX=...] <option1=1 option2=1 ...>

-where:

-

-CFG: Required.  Choose from a release or debug build.  Note that 

-     all builds generate a .pdb file for each .dll and .exe built--this refers

-     to the C/C++ runtime that the build uses.

-

-PREFIX: Optional.  Base directory of where the third-party headers, libraries

-        and needed tools can be found, i.e. headers in $(PREFIX)\include,

-        libraries in $(PREFIX)\lib and tools in $(PREFIX)\bin.  If not

-        specified, $(PREFIX) is set as $(srcroot)\..\vs$(X)\$(platform), where

-        $(platform) is win32 for 32-bit builds or x64 for 64-bit builds, and

-        $(X) is the short version of the Visual Studio used, as follows:

-        2008: 9

-        2010: 10

-        2012: 11

-        2013: 12

-        2015: 14

-

-Explanation of options, set by <option>=1:

-------------------------------------------

-GLIB: Enable GLib support in HarfBuzz, which also uses the GLib unicode

-      callback instead of the bundled UCDN unicode callback.  This requires the

-      GLib libraries, and is required for building all tool and test programs.

-

-GOBJECT: Enable building the HarfBuzz-GObject DLL, and thus implies GLib

-         support.  This requires the GObject libraries and glib-mkenums script,

-         along with PERL to generate the enum sources and headers, which is

-         required for the build.

-

-INTROSPECTION: Enable build of introspection files, for making HarfBuzz

-               bindings for other programming languages available, such as

-               Python, available.  This requires the GObject-Introspection

-               libraries and tools, along with the Python interpretor that was

-               used during the build of GObject-Introspection.  Please see

-               $(srcroot)\README.python for more related details.  This implies

-               the build of the HarfBuzz-GObject DLL, along with GLib support.

-

-FREETYPE: Enable the FreeType font callbacks.  Requires the FreeType2 library.

-

-CAIRO: Enable Cairo support.  Requires the Cairo library.

-

-CAIRO_FT: Enable the build of the hb-view tool, which makes use of Cairo, and

-          thus implies FreeType font callback support and Cairo support.

-          Requires Cairo libraries built with FreeType support.  Note that the

-          hb-view tool requires GLib support as well.

-

-GRAPHITE2: Enable the Graphite2 shaper, requires the SIL Graphite2 library.

-

-ICU: Enables the build of ICU Unicode functions. Requires the ICU libraries.
-

-UNISCRIBE: Enable Uniscribe platform shaper support.

-

-DIRECTWRITE: Enable DirectWrite platform shaper support,

-             requires a rather recent Windows SDK, and at least Windows Vista/

-             Server 2008 with SP2 and platform update.

-

-PYTHON: Full path to the Python interpretor to be used, if it is not in %PATH%.

-

-PERL: Full path to the PERL interpretor to be used, if it is not in %PATH%.

-

-LIBTOOL_DLL_NAME: Enable libtool-style DLL names.
\ No newline at end of file
diff --git a/win32/build-rules-msvc.mak b/win32/build-rules-msvc.mak
deleted file mode 100644
index bfe0286..0000000
--- a/win32/build-rules-msvc.mak
+++ /dev/null
@@ -1,127 +0,0 @@
-# NMake Makefile portion for compilation rules
-# Items in here should not need to be edited unless
-# one is maintaining the NMake build files.  The format
-# of NMake Makefiles here are different from the GNU
-# Makefiles.  Please see the comments about these formats.
-
-# Inference rules for compiling the .obj files.
-# Used for libs and programs with more than a single source file.
-# Format is as follows
-# (all dirs must have a trailing '\'):
-#
-# {$(srcdir)}.$(srcext){$(destdir)}.obj::
-# 	$(CC)|$(CXX) $(cflags) /Fo$(destdir) /c @<<
-# $<
-# <<
-{..\src\}.cc{$(CFG)\$(PLAT)\harfbuzz\}.obj::
-	$(CXX) $(CFLAGS) $(HB_DEFINES) $(HB_LIB_CFLAGS) /Fo$(CFG)\$(PLAT)\harfbuzz\ /c @<<
-$<
-<<
-
-{..\src\hb-ucdn\}.c{$(CFG)\$(PLAT)\harfbuzz\}.obj::
-	$(CC) $(CFLAGS) /Fo$(CFG)\$(PLAT)\harfbuzz\ /c @<<
-$<
-<<
-
-{..\util\}.cc{$(CFG)\$(PLAT)\util\}.obj::
-	$(CXX) $(CFLAGS) $(HB_DEFINES) $(HB_CFLAGS) /Fo$(CFG)\$(PLAT)\util\ /c @<<
-$<
-<<
-
-# Inference rules for building the test programs
-# Used for programs with a single source file.
-# Format is as follows
-# (all dirs must have a trailing '\'):
-#
-# {$(srcdir)}.$(srcext){$(destdir)}.exe::
-# 	$(CC)|$(CXX) $(cflags) $< /Fo$*.obj  /Fe$@ [/link $(linker_flags) $(dep_libs)]
-{..\src\}.cc{$(CFG)\$(PLAT)\}.exe:
-	$(CXX) $(CFLAGS) $(HB_DEFINES) $(HB_CFLAGS) $< /Fo$*.obj  /Fe$@ /link $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_TESTS_DEP_LIBS)
-
-{..\test\api\}.c{$(CFG)\$(PLAT)\}.exe:
-	$(CXX) $(CFLAGS) $(HB_DEFINES) $(HB_CFLAGS) /DSRCDIR="\"../../../test/api\"" $< /Fo$*.obj /Fe$@ /link $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_TESTS_DEP_LIBS)
-
-# Rules for building .lib files
-$(CFG)\$(PLAT)\harfbuzz.lib: $(HARFBUZZ_DLL_FILENAME).dll
-$(CFG)\$(PLAT)\harfbuzz-gobject.lib: $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll
-
-# Rules for linking DLLs
-# Format is as follows (the mt command is needed for MSVC 2005/2008 builds):
-# $(dll_name_with_path): $(dependent_libs_files_objects_and_items)
-#	link /DLL [$(linker_flags)] [$(dependent_libs)] [/def:$(def_file_if_used)] [/implib:$(lib_name_if_needed)] -out:$@ @<<
-# $(dependent_objects)
-# <<
-# 	@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;2
-$(HARFBUZZ_DLL_FILENAME).dll: config.h $(harfbuzz_dll_OBJS) $(CFG)\$(PLAT)\harfbuzz
-	link /DLL $(LDFLAGS) $(HB_DEP_LIBS) /implib:$(CFG)\$(PLAT)\harfbuzz.lib -out:$@ @<<
-$(harfbuzz_dll_OBJS)
-<<
-	@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;2
-
-$(HARFBUZZ_GOBJECT_DLL_FILENAME).dll: $(CFG)\$(PLAT)\harfbuzz.lib $(harfbuzz_gobject_OBJS) $(CFG)\$(PLAT)\harfbuzz-gobject
-	link /DLL $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_GOBJECT_DEP_LIBS) /implib:$(CFG)\$(PLAT)\harfbuzz-gobject.lib -out:$@ @<<
-$(harfbuzz_gobject_OBJS)
-<<
-	@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;2
-
-# Rules for linking Executables
-# Format is as follows (the mt command is needed for MSVC 2005/2008 builds):
-# $(dll_name_with_path): $(dependent_libs_files_objects_and_items)
-#	link [$(linker_flags)] [$(dependent_libs)] -out:$@ @<<
-# $(dependent_objects)
-# <<
-# 	@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;1
-$(CFG)\$(PLAT)\hb-view.exe: $(CFG)\$(PLAT)\harfbuzz.lib $(CFG)\$(PLAT)\util $(hb_view_OBJS)
-	link $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_UTILS_DEP_LIBS) -out:$@ @<<
-$(hb_view_OBJS)
-<<
-	@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;1
-
-$(CFG)\$(PLAT)\hb-shape.exe: $(CFG)\$(PLAT)\harfbuzz.lib $(CFG)\$(PLAT)\util $(hb_shape_OBJS)
-	link $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_UTILS_DEP_LIBS) -out:$@ @<<
-$(hb_shape_OBJS)
-<<
-	@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;1
-
-$(CFG)\$(PLAT)\hb-ot-shape-closure.exe: $(CFG)\$(PLAT)\harfbuzz.lib $(CFG)\$(PLAT)\util $(hb_ot_shape_closure_OBJS)
-	link $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_UTILS_DEP_LIBS) -out:$@ @<<
-$(hb_ot_shape_closure_OBJS)
-<<
-	@-if exist $@.manifest mt /manifest $@.manifest /outputresource:$@;1
-
-# Other .obj files requiring individual attention, that could not be covered by the inference rules.
-# Format is as follows (all dirs must have a trailing '\'):
-#
-# $(obj_file):
-# 	$(CC)|$(CXX) $(cflags) /Fo$(obj_destdir) /c @<<
-# $(srcfile)
-# <<
-$(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-structs.obj:	$(CFG)\$(PLAT)\harfbuzz-gobject $(HB_GOBJECT_ENUM_GENERATED_SOURCES)
-	$(CXX) $(CFLAGS) $(HB_DEFINES) $(HB_LIB_CFLAGS) /I$(CFG)\$(PLAT)\harfbuzz-gobject /Fo$(CFG)\$(PLAT)\harfbuzz-gobject\ /c @<<
-..\src\hb-gobject-structs.cc
-<<
-
-$(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.obj: $(CFG)\$(PLAT)\harfbuzz-gobject $(HB_GOBJECT_ENUM_GENERATED_SOURCES)
-	$(CXX) $(CFLAGS) $(HB_DEFINES) $(HB_LIB_CFLAGS) /I$(CFG)\$(PLAT)\harfbuzz-gobject /Fo$(CFG)\$(PLAT)\harfbuzz-gobject\ /c @<<
-$(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.cc
-<<
-
-clean:
-	@-if exist $(CFG)\$(PLAT)\HarfBuzz-0.0.typelib del /f /q $(CFG)\$(PLAT)\HarfBuzz-0.0.typelib
-	@-if exist $(CFG)\$(PLAT)\HarfBuzz-0.0.gir del /f /q $(CFG)\$(PLAT)\HarfBuzz-0.0.gir
-	@-if exist $(CFG)\$(PLAT)\hb_list del /f /q $(CFG)\$(PLAT)\hb_list
-	@-del /f /q $(CFG)\$(PLAT)\*.pdb
-	@-if exist $(CFG)\$(PLAT)\.exe.manifest del /f /q $(CFG)\$(PLAT)\*.exe.manifest
-	@-if exist $(CFG)\$(PLAT)\.exe del /f /q $(CFG)\$(PLAT)\*.exe
-	@-del /f /q $(CFG)\$(PLAT)\*.dll.manifest
-	@-del /f /q $(CFG)\$(PLAT)\*.dll
-	@-del /f /q $(CFG)\$(PLAT)\*.ilk
-	@-del /f /q $(CFG)\$(PLAT)\*.obj
-	@-if exist $(CFG)\$(PLAT)\util del /f /q $(CFG)\$(PLAT)\util\*.obj
-	@-if exist $(CFG)\$(PLAT)\harfbuzz-gobject del /f /q $(CFG)\$(PLAT)\harfbuzz-gobject\*.obj
-	@-del /f /q $(CFG)\$(PLAT)\harfbuzz\*.obj
-	@-rmdir /s /q $(CFG)\$(PLAT)
-	@-if exist $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h del $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h
-	@-if exist $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.cc del $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.cc
-	@-del vc$(VSVER)0.pdb
-	@-del config.h
diff --git a/win32/config-msvc.mak b/win32/config-msvc.mak
deleted file mode 100644
index 4cffaea..0000000
--- a/win32/config-msvc.mak
+++ /dev/null
@@ -1,217 +0,0 @@
-# NMake Makefile portion for enabling features for Windows builds
-
-# You may change these lines to customize the .lib files that will be linked to
-# Additional Libraries for building HarfBuzz-ICU
-# icudt.lib may be required for static ICU builds
-HB_ICU_DEP_LIBS = icuuc.lib
-
-# GLib is required for all utility programs and tests
-HB_GLIB_LIBS = glib-2.0.lib
-
-# Needed for building HarfBuzz-GObject
-HB_GOBJECT_DEP_LIBS = gobject-2.0.lib $(HB_GLIB_LIBS)
-
-# Freetype is needed for building FreeType support and hb-view
-!if "$(CFG)" == "debug"
-FREETYPE_LIB = freetyped.lib
-!else
-FREETYPE_LIB = freetype.lib
-!endif
-
-# Cairo is needed for building hb-view
-CAIRO_LIB = cairo.lib
-
-# Graphite2 is needed for building SIL Graphite2 support
-GRAPHITE2_LIB = graphite2.lib
-
-# Uniscribe is needed for Uniscribe shaping support
-UNISCRIBE_LIB = usp10.lib gdi32.lib rpcrt4.lib user32.lib
-
-# Directwrite is needed for DirectWrite shaping support
-DIRECTWRITE_LIB = dwrite.lib
-
-# Please do not change anything beneath this line unless maintaining the NMake Makefiles
-# Bare minimum features and sources built into HarfBuzz on Windows
-HB_DEFINES =
-HB_CFLAGS = /DHAVE_CONFIG_H
-HB_UCDN_CFLAGS = /I..\src\hb-ucdn
-HB_SOURCES =	\
-	$(HB_BASE_sources)		\
-	$(HB_FALLBACK_sources)	\
-	$(HB_OT_sources)
-
-HB_HEADERS =	\
-	$(HB_BASE_headers)		\
-	$(HB_NODIST_headers)	\
-	$(HB_OT_headers)
-
-# Minimal set of (system) libraries needed for the HarfBuzz DLL
-HB_DEP_LIBS =
-
-# We build the HarfBuzz DLL/LIB at least
-HB_LIBS = $(CFG)\$(PLAT)\harfbuzz.lib
-
-# Note: All the utility and test programs require GLib support to be present!
-HB_UTILS =
-HB_UTILS_DEP_LIBS = $(HB_GLIB_LIBS)
-HB_TESTS =
-HB_TESTS_DEP_LIBS = $(HB_GLIB_LIBS)
-
-# Use libtool-style DLL names, if desired
-!if "$(LIBTOOL_DLL_NAME)" == "1"
-HARFBUZZ_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-0
-HARFBUZZ_GOBJECT_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-gobject-0
-!else
-HARFBUZZ_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-vs$(VSVER)
-HARFBUZZ_GOBJECT_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-gobject-vs$(VSVER)
-!endif
-
-# Enable Introspection (enables HarfBuzz-Gobject as well)
-!if "$(INTROSPECTION)" == "1"
-GOBJECT = 1
-CHECK_PACKAGE = gobject-2.0
-EXTRA_TARGETS = $(CFG)\$(PLAT)\HarfBuzz-0.0.gir $(CFG)\$(PLAT)\HarfBuzz-0.0.typelib
-!else
-EXTRA_TARGETS =
-!endif
-
-# Enable HarfBuzz-GObject (enables GLib support as well)
-!if "$(GOBJECT)" == "1"
-GLIB = 1
-HB_LIBS =	\
-	$(HB_LIBS)	\
-	$(CFG)\$(PLAT)\harfbuzz-gobject.lib
-
-HB_GOBJECT_ENUM_GENERATED_SOURCES = \
-	$(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.cc	\
-	$(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h
-
-!endif
-
-# Enable cairo-ft (enables cairo and freetype as well)
-!if "$(CAIRO_FT)" == "1"
-HB_DEFINES = $(HB_DEFINES) /DHAVE_CAIRO_FT=1
-CAIRO = 1
-FREETYPE = 1
-!if "$(GLIB)" == "1"
-HB_UTILS = \
-	$(HB_UTILS)	\
-	$(CFG)\$(PLAT)\hb-view.exe
-
-HB_UTILS_DEP_LIBS = $(HB_UTILS_DEP_LIBS) $(CAIRO_LIB) $(FREETYPE_LIB)
-!else
-!if [echo Warning: GLib support not enabled, hb-view not built]
-!endif
-!endif
-!endif
-
-# Enable cairo
-!if "$(CAIRO)" == "1"
-HB_DEFINES = $(HB_DEFINES) /DHAVE_CAIRO=1
-!endif
-
-# Enable freetype if desired
-!if "$(FREETYPE)" == "1"
-!if "$(FREETYPE_DIR)" != ""
-HB_CFLAGS = $(HB_CFLAGS) /I$(FREETYPE_DIR)
-!endif
-HB_DEFINES = $(HB_DEFINES) /DHAVE_FREETYPE=1
-HB_SOURCES = $(HB_SOURCES) $(HB_FT_sources)
-HB_HEADERS = $(HB_HEADERS) $(HB_FT_headers)
-HB_DEP_LIBS = $(HB_DEP_LIBS) $(FREETYPE_LIB)
-!endif
-
-# Enable graphite2 if desired
-!if "$(GRAPHITE2)" == "1"
-HB_DEFINES = $(HB_DEFINES) /DHAVE_GRAPHITE2=1
-HB_SOURCES = $(HB_SOURCES) $(HB_GRAPHITE2_sources)
-HB_HEADERS = $(HB_HEADERS) $(HB_GRAPHITE2_headers)
-HB_DEP_LIBS = $(HB_DEP_LIBS) $(GRAPHITE2_LIB)
-!endif
-
-# Enable GLib if desired
-!if "$(GLIB)" == "1"
-HB_DEFINES = $(HB_DEFINES) /DHAVE_GLIB=1
-HB_CFLAGS =	\
-	$(HB_CFLAGS)					\
-	/FImsvc_recommended_pragmas.h	\
-	/I$(PREFIX)\include\glib-2.0	\
-	/I$(PREFIX)\lib\glib-2.0\include
-
-HB_SOURCES = $(HB_SOURCES) $(HB_GLIB_sources)
-HB_HEADERS = $(HB_HEADERS) $(HB_GLIB_headers)
-HB_DEP_LIBS = $(HB_DEP_LIBS) $(HB_GLIB_LIBS)
-
-HB_UTILS = \
-	$(HB_UTILS)					\
-	$(CFG)\$(PLAT)\hb-shape.exe	\
-	$(CFG)\$(PLAT)\hb-ot-shape-closure.exe
-
-HB_TESTS = \
-	$(HB_TESTS)	\
-	$(CFG)\$(PLAT)\main.exe						\
-	$(CFG)\$(PLAT)\test.exe						\
-	$(CFG)\$(PLAT)\test-buffer-serialize.exe	\
-	$(CFG)\$(PLAT)\test-size-params.exe			\
-	$(CFG)\$(PLAT)\test-would-substitute.exe	\
-	$(CFG)\$(PLAT)\test-blob.exe				\
-	$(CFG)\$(PLAT)\test-buffer.exe				\
-	$(CFG)\$(PLAT)\test-common.exe				\
-	$(CFG)\$(PLAT)\test-font.exe				\
-	$(CFG)\$(PLAT)\test-object.exe				\
-	$(CFG)\$(PLAT)\test-set.exe					\
-	$(CFG)\$(PLAT)\test-shape.exe				\
-	$(CFG)\$(PLAT)\test-unicode.exe				\
-	$(CFG)\$(PLAT)\test-version.exe
-
-!elseif "$(ICU)" == "1"
-# use ICU for Unicode functions
-# and define some of the macros in GLib's msvc_recommended_pragmas.h
-# to reduce some unneeded build-time warnings
-HB_DEFINES = $(HB_DEFINES) /DHAVE_ICU=1 /DHAVE_ICU_BUILTIN=1
-HB_CFLAGS =	\
-	$(HB_CFLAGS)					\
-	/wd4244							\
-	/D_CRT_SECURE_NO_WARNINGS		\
-	/D_CRT_NONSTDC_NO_WARNINGS
-
-# We don't want ICU to re-define int8_t in VS 2008, will cause build breakage
-# as we define it in hb-common.h, and we ought to use the definitions there.
-!if "$(VSVER)" == "9"
-HB_CFLAGS =	$(HB_CFLAGS) /DU_HAVE_INT8_T
-!endif
-
-HB_SOURCES = $(HB_SOURCES) $(HB_ICU_sources)
-HB_HEADERS = $(HB_HEADERS) $(HB_ICU_headers)
-HB_DEP_LIBS = $(HB_DEP_LIBS) $(HB_ICU_DEP_LIBS)
-!endif
-
-!if "$(UCDN)" != "0"
-# Define some of the macros in GLib's msvc_recommended_pragmas.h
-# to reduce some unneeded build-time warnings
-HB_DEFINES = $(HB_DEFINES) /DHAVE_UCDN=1
-HB_CFLAGS =	\
-	$(HB_CFLAGS)					\
-	$(HB_UCDN_CFLAGS)				\
-	/wd4244							\
-	/D_CRT_SECURE_NO_WARNINGS		\
-	/D_CRT_NONSTDC_NO_WARNINGS
-
-HB_SOURCES = $(HB_SOURCES) $(LIBHB_UCDN_sources) $(HB_UCDN_sources)
-!endif
-
-!if "$(UNISCRIBE)" == "1"
-HB_CFLAGS = $(HB_CFLAGS) /DHAVE_UNISCRIBE
-HB_SOURCES = $(HB_SOURCES) $(HB_UNISCRIBE_sources)
-HB_HEADERS = $(HB_HEADERS) $(HB_UNISCRIBE_headers)
-HB_DEP_LIBS = $(HB_DEP_LIBS) $(UNISCRIBE_LIB)
-!endif
-
-!if "$(DIRECTWRITE)" == "1"
-HB_CFLAGS = $(HB_CFLAGS) /DHAVE_DIRECTWRITE
-HB_SOURCES = $(HB_SOURCES) $(HB_DIRECTWRITE_sources)
-HB_HEADERS = $(HB_HEADERS) $(HB_DIRECTWRITE_headers)
-HB_DEP_LIBS = $(HB_DEP_LIBS) $(DIRECTWRITE_LIB)
-!endif
-
-HB_LIB_CFLAGS = $(HB_CFLAGS) /DHB_EXTERN="__declspec (dllexport) extern"
diff --git a/win32/config.h.win32.in b/win32/config.h.win32.in
deleted file mode 100644
index d45cefb..0000000
--- a/win32/config.h.win32.in
+++ /dev/null
@@ -1,158 +0,0 @@
-/* config.h.in.  Generated from configure.ac by autoheader.  */
-
-/* The normal alignment of `struct{char;}', in bytes. */
-#define ALIGNOF_STRUCT_CHAR__ 1
-
-/* Define to 1 if you have the `atexit' function. */
-#define HAVE_ATEXIT 1
-
-/* Have cairo graphics library */
-/* #undef HAVE_CAIRO */
-
-/* Have cairo-ft support in cairo graphics library */
-/* #undef HAVE_CAIRO_FT */
-
-/* Have Core Text backend */
-/* #undef HAVE_CORETEXT */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-/* #undef HAVE_DLFCN_H */
-
-/* Have DirectWrite Library */
-/* #undef HAVE_DIRECTWRITE */
-
-/* Have simple TrueType Layout backend */
-#define HAVE_FALLBACK 1
-
-/* Have fontconfig library */
-/* #undef HAVE_FONTCONFIG */
-
-/* Have FreeType 2 library */
-/* #undef HAVE_FREETYPE */
-
-/* Define to 1 if you have the `getpagesize' function. */
-/* #undef HAVE_GETPAGESIZE */
-
-/* Have glib2 library */
-/* #undef HAVE_GLIB */
-
-/* Have gobject2 library */
-/* #undef HAVE_GOBJECT */
-
-/* Have Graphite2 library */
-/* #undef HAVE_GRAPHITE2 */
-
-/* Have ICU library */
-/* #undef HAVE_ICU */
-
-/* Have Intel __sync_* atomic primitives */
-/* #undef HAVE_INTEL_ATOMIC_PRIMITIVES */
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#if !defined (_MSC_VER) || (_MSC_VER >= 1800)
-#define HAVE_INTTYPES_H 1
-#endif
-
-/* Define to 1 if you have the `isatty' function. */
-#define HAVE_ISATTY 1
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the `mmap' function. */
-/* #undef HAVE_MMAP */
-
-/* Define to 1 if you have the `mprotect' function. */
-/* #undef HAVE_MPROTECT */
-
-/* Have native OpenType Layout backend */
-#define HAVE_OT 1
-
-/* Have POSIX threads */
-/* #undef HAVE_PTHREAD */
-
-/* Have PTHREAD_PRIO_INHERIT. */
-/* #undef HAVE_PTHREAD_PRIO_INHERIT */
-
-/* Define to 1 if you have the <sched.h> header file. */
-/* #undef HAVE_SCHED_H */
-
-/* Have sched_yield */
-/* #undef HAVE_SCHED_YIELD */
-
-/* Have Solaris __machine_*_barrier and atomic_* operations */
-/* #undef HAVE_SOLARIS_ATOMIC_OPS */
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#if !defined (_MSC_VER) || (_MSC_VER >= 1600)
-#define HAVE_STDINT_H 1
-#endif
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#ifndef _MSC_VER
-#define HAVE_STRINGS_H 1
-#endif
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the `sysconf' function. */
-/* #undef HAVE_SYSCONF */
-
-/* Define to 1 if you have the <sys/mman.h> header file. */
-/* #undef HAVE_SYS_MMAN_H */
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Have UCDN Unicode functions */
-#define HAVE_UCDN 1
-
-/* Have Uniscribe library */
-/* #undef HAVE_UNISCRIBE */
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#ifndef _MSC_VER
-#define HAVE_UNISTD_H 1
-#endif
-
-/* Define to 1 if you have the <usp10.h> header file. */
-#define HAVE_USP10_H 1
-
-/* Define to 1 if you have the <windows.h> header file. */
-#define HAVE_WINDOWS_H 1
-
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
-   */
-#define LT_OBJDIR ".libs/"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "@PACKAGE_NAME@"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "@PACKAGE_NAME@ @PACKAGE_VERSION@"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "@PACKAGE_TARNAME@"
-
-/* Define to the home page for this package. */
-#define PACKAGE_URL "@PACKAGE_URL@"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "@PACKAGE_VERSION@"
-
-/* Define to necessary symbol if this constant uses a non-standard name on
-   your system. */
-/* #undef PTHREAD_CREATE_JOINABLE */
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
diff --git a/win32/create-lists-msvc.mak b/win32/create-lists-msvc.mak
deleted file mode 100644
index dbd2a57..0000000
--- a/win32/create-lists-msvc.mak
+++ /dev/null
@@ -1,138 +0,0 @@
-# Convert the source listing to object (.obj) listing in
-# another NMake Makefile module, include it, and clean it up.
-# This is a "fact-of-life" regarding NMake Makefiles...
-# This file does not need to be changed unless one is maintaining the NMake Makefiles
-
-# For those wanting to add things here:
-# To add a list, do the following:
-# # $(description_of_list)
-# if [call create-lists.bat header $(makefile_snippet_file) $(variable_name)]
-# endif
-#
-# if [call create-lists.bat file $(makefile_snippet_file) $(file_name)]
-# endif
-#
-# if [call create-lists.bat footer $(makefile_snippet_file)]
-# endif
-# ... (repeat the if [call ...] lines in the above order if needed)
-# !include $(makefile_snippet_file)
-#
-# (add the following after checking the entries in $(makefile_snippet_file) is correct)
-# (the batch script appends to $(makefile_snippet_file), you will need to clear the file unless the following line is added)
-#!if [del /f /q $(makefile_snippet_file)]
-#!endif
-
-# In order to obtain the .obj filename that is needed for NMake Makefiles to build DLLs/static LIBs or EXEs, do the following
-# instead when doing 'if [call create-lists.bat file $(makefile_snippet_file) $(file_name)]'
-# (repeat if there are multiple $(srcext)'s in $(source_list), ignore any headers):
-# !if [for %c in ($(source_list)) do @if "%~xc" == ".$(srcext)" @call create-lists.bat file $(makefile_snippet_file) $(intdir)\%~nc.obj]
-#
-# $(intdir)\%~nc.obj needs to correspond to the rules added in build-rules-msvc.mak
-# %~xc gives the file extension of a given file, %c in this case, so if %c is a.cc, %~xc means .cc
-# %~nc gives the file name of a given file without extension, %c in this case, so if %c is a.cc, %~nc means a
-
-NULL=
-
-# For HarfBuzz
-!if [call create-lists.bat header hb_objs.mak harfbuzz_dll_OBJS]
-!endif
-
-!if [for %c in ($(HB_SOURCES)) do @if "%~xc" == ".cc" @call create-lists.bat file hb_objs.mak ^$(CFG)\^$(PLAT)\harfbuzz\%~nc.obj]
-!endif
-
-!if [for %c in ($(HB_SOURCES)) do @if "%~xc" == ".c" @call create-lists.bat file hb_objs.mak ^$(CFG)\^$(PLAT)\harfbuzz\%~nc.obj]
-!endif
-
-!if [call create-lists.bat footer hb_objs.mak]
-!endif
-
-# For HarfBuzz-GObject
-!if "$(GOBJECT)" == "1"
-
-!if [call create-lists.bat header hb_objs.mak harfbuzz_gobject_OBJS]
-!endif
-
-!if [for %c in ($(HB_GOBJECT_sources) $(HB_GOBJECT_ENUM_sources)) do @if "%~xc" == ".cc" @call create-lists.bat file hb_objs.mak ^$(CFG)\^$(PLAT)\harfbuzz-gobject\%~nc.obj]
-!endif
-
-!if [call create-lists.bat footer hb_objs.mak]
-!endif
-!endif
-
-# For the utility programs (GLib support is required)
-!if "$(GLIB)" == "1"
-
-# For hb-view, Cairo-FT support is required
-!if "$(CAIRO_FT)" == "1"
-
-!if [call create-lists.bat header hb_objs.mak hb_view_OBJS]
-!endif
-
-!if [for %c in ($(HB_VIEW_sources)) do @if "%~xc" == ".cc" @call create-lists.bat file hb_objs.mak ^$(CFG)\^$(PLAT)\util\%~nc.obj]
-!endif
-
-!if [call create-lists.bat footer hb_objs.mak]
-!endif
-!endif
-
-# For hb-shape
-!if [call create-lists.bat header hb_objs.mak hb_shape_OBJS]
-!endif
-
-!if [for %c in ($(HB_SHAPE_sources)) do @if "%~xc" == ".cc" @call create-lists.bat file hb_objs.mak ^$(CFG)\^$(PLAT)\util\%~nc.obj]
-!endif
-
-!if [call create-lists.bat footer hb_objs.mak]
-!endif
-
-# For hb-ot-shape-closure
-
-!if [call create-lists.bat header hb_objs.mak hb_ot_shape_closure_OBJS]
-!endif
-
-!if [for %c in ($(HB_OT_SHAPE_CLOSURE_sources)) do @if "%~xc" == ".cc" @call create-lists.bat file hb_objs.mak ^$(CFG)\^$(PLAT)\util\%~nc.obj]
-!endif
-
-!if [call create-lists.bat footer hb_objs.mak]
-!endif
-
-!endif
-
-!include hb_objs.mak
-
-!if [del /f /q hb_objs.mak]
-!endif
-
-# Gather the list of headers and sources for introspection and glib-mkenums
-!if [call create-lists.bat header hb_srcs.mak HB_ACTUAL_HEADERS]
-!endif
-
-!if [for %h in ($(HB_HEADERS)) do @call create-lists.bat file hb_srcs.mak ..\src\%h]
-!endif
-
-!if [call create-lists.bat footer hb_srcs.mak]
-!endif
-
-# Gather the lists of sources for introspection
-!if [call create-lists.bat header hb_srcs.mak HB_ACTUAL_SOURCES]
-!endif
-
-!if [for %s in ($(HB_SOURCES)) do @call create-lists.bat file hb_srcs.mak ..\src\%s]
-!endif
-
-!if [call create-lists.bat footer hb_srcs.mak]
-!endif
-
-!if [call create-lists.bat header hb_srcs.mak HB_GOBJECT_ACTUAL_SOURCES]
-!endif
-
-!if [for %s in ($(HB_GOBJECT_sources) $(HB_GOBJECT_STRUCTS_headers)) do @call create-lists.bat file hb_srcs.mak ..\src\%s]
-!endif
-
-!if [call create-lists.bat footer hb_srcs.mak]
-!endif
-
-!include hb_srcs.mak
-
-!if [del /f /q hb_srcs.mak]
-!endif
diff --git a/win32/create-lists.bat b/win32/create-lists.bat
deleted file mode 100644
index ef60d5c..0000000
--- a/win32/create-lists.bat
+++ /dev/null
@@ -1,42 +0,0 @@
-@echo off
-rem Simple .bat script for creating the NMake Makefile snippets.
-
-if not "%1" == "header" if not "%1" == "file" if not "%1" == "footer" goto :error_cmd
-if "%2" == "" goto error_no_destfile
-
-if "%1" == "header" goto :header
-if "%1" == "file" goto :addfile
-if "%1" == "footer" goto :footer
-
-:header
-if "%3" == "" goto error_var
-echo %3 =	\>>%2
-goto done
-
-:addfile
-if "%3" == "" goto error_file
-echo.	%3	\>>%2
-goto done
-
-:footer
-echo.	$(NULL)>>%2
-echo.>>%2
-goto done
-
-:error_cmd
-echo Specified command '%1' was invalid.  Valid commands are: header file footer.
-goto done
-
-:error_no_destfile
-echo Destination NMake snippet file must be specified
-goto done
-
-:error_var
-echo A name must be specified for using '%1'.
-goto done
-
-:error_file
-echo A file must be specified for using '%1'.
-goto done
-
-:done
\ No newline at end of file
diff --git a/win32/detectenv-msvc.mak b/win32/detectenv-msvc.mak
deleted file mode 100644
index ca09793..0000000
--- a/win32/detectenv-msvc.mak
+++ /dev/null
@@ -1,144 +0,0 @@
-# Change this (or specify PREFIX= when invoking this NMake Makefile) if
-# necessary, so that the libs and headers of the dependent third-party
-# libraries can be located.  For instance, if building from GLib's
-# included Visual Studio projects, this should be able to locate the GLib
-# build out-of-the-box if they were not moved.  GLib's headers will be
-# found in $(GLIB_PREFIX)\include\glib-2.0 and
-# $(GLIB_PREFIX)\lib\glib-2.0\include and its import library will be found
-# in $(GLIB_PREFIX)\lib.
-
-!if "$(PREFIX)" == ""
-PREFIX = ..\..\vs$(VSVER)\$(PLAT)
-!endif
-
-# Location of the PERL interpretor, for running glib-mkenums.  glib-mkenums
-# needs to be found in $(PREFIX)\bin.  Using either a 32-bit or x64 PERL
-# interpretor are supported for either a 32-bit or x64 build.
-
-!if "$(PERL)" == ""
-PERL = perl
-!endif
-
-# Location of the Python interpretor, for building introspection.  The complete set
-# of Python Modules for introspection (the giscanner Python scripts and the _giscanner.pyd
-# compiled module) needs to be found in $(PREFIX)\lib\gobject-introspection\giscanner, and
-# the g-ir-scanner Python script and g-ir-compiler utility program needs to be found
-# in $(PREFIX)\bin, together with any DLLs they will depend on, if those DLLs are not already
-# in your PATH.
-# Note that the Python interpretor and the introspection modules and utility progam must
-# correspond to the build type (i.e. 32-bit Release for 32-bit Release builds, and so on).
-#
-# For introspection, currently only Python 2.7.x is supported.  This may change when Python 3.x
-# support is added upstream in gobject-introspection--when this happens, the _giscanner.pyd must
-# be the one that is built against the release series of Python that is used here.
-
-!if "$(PYTHON)" == ""
-PYTHON = python
-!endif
-
-# Location of the pkg-config utility program, for building introspection.  It needs to be able
-# to find the pkg-config (.pc) files so that the correct libraries and headers for the needed libraries
-# can be located, using PKG_CONFIG_PATH.  Using either a 32-bit or x64 pkg-config are supported for
-# either a 32-bit or x64 build.
-
-!if "$(PKG_CONFIG)" == ""
-PKG_CONFIG = pkg-config
-!endif
-
-# The items below this line should not be changed, unless one is maintaining
-# the NMake Makefiles.  The exception is for the CFLAGS_ADD line(s) where one
-# could use his/her desired compiler optimization flags, if he/she knows what is
-# being done.
-
-# Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or
-# VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir)
-!if !defined(VCINSTALLDIR) && !defined(WINDOWSSDKDIR)
-MSG = ^
-This Makefile is only for Visual Studio 2008 and later.^
-You need to ensure that the Visual Studio Environment is properly set up^
-before running this Makefile.
-!error $(MSG)
-!endif
-
-ERRNUL  = 2>NUL
-_HASH=^#
-
-!if ![echo VCVERSION=_MSC_VER > vercl.x] \
-    && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \
-    && ![echo PLAT=Win32 >> vercl.x] \
-    && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \
-    && ![echo PLAT=x64 >> vercl.x] \
-    && ![echo $(_HASH)endif >> vercl.x] \
-    && ![cl -nologo -TC -P vercl.x $(ERRNUL)]
-!include vercl.i
-!if ![echo VCVER= ^\> vercl.vc] \
-    && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc]
-!include vercl.vc
-!endif
-!endif
-!if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc]
-!endif
-
-!if $(VCVERSION) > 1499 && $(VCVERSION) < 1600
-VSVER = 9
-!elseif $(VCVERSION) > 1599 && $(VCVERSION) < 1700
-VSVER = 10
-!elseif $(VCVERSION) > 1699 && $(VCVERSION) < 1800
-VSVER = 11
-!elseif $(VCVERSION) > 1799 && $(VCVERSION) < 1900
-VSVER = 12
-!elseif $(VCVERSION) > 1899 && $(VCVERSION) < 2000
-VSVER = 14
-!else
-VSVER = 0
-!endif
-
-!if "$(VSVER)" == "0"
-MSG = ^
-This NMake Makefile set supports Visual Studio^
-9 (2008) through 14 (2015).  Your Visual Studio^
-version is not supported.
-!error $(MSG)
-!endif
-
-VALID_CFGSET = FALSE
-!if "$(CFG)" == "release" || "$(CFG)" == "debug"
-VALID_CFGSET = TRUE
-!endif
-
-# One may change these items, but be sure to test
-# the resulting binaries
-!if "$(CFG)" == "release"
-CFLAGS_ADD = /MD /O2 /GL /MP
-!if $(VSVER) > 9 && $(VSVER) < 14
-# Undocumented "enhance optimized debugging" switch. Became documented
-# as "/Zo" in VS 2013 Update 3, and is turned on by default in VS 2015.
-CFLAGS_ADD = $(CFLAGS_ADD) /d2Zi+
-!endif
-!else
-CFLAGS_ADD = /MDd /Od
-!endif
-
-!if "$(PLAT)" == "x64"
-LDFLAGS_ARCH = /machine:x64
-!elseif "$(PLAT)" == "arm"
-LDFLAGS_ARCH = /machine:arm
-CFLAGS_ADD = $(CFLAGS_ADD) /DWINAPI_FAMILY=3
-!else
-LDFLAGS_ARCH = /machine:x86
-!endif
-
-!if "$(VALID_CFGSET)" == "TRUE"
-CFLAGS = $(CFLAGS_ADD) /W3 /Zi /I.. /I..\src /I. /I$(PREFIX)\include
-
-!if "$(ADDITIONAL_LIB_DIR)" != ""
-ADDITIONAL_LIB_ARG = /libpath:$(ADDITIONAL_LIB_DIR)
-!endif
-LDFLAGS_BASE = $(LDFLAGS_ARCH) /libpath:$(PREFIX)\lib $(ADDITIONAL_LIB_ARG) /DEBUG
-
-!if "$(CFG)" == "debug"
-LDFLAGS = $(LDFLAGS_BASE)
-!else
-LDFLAGS = $(LDFLAGS_BASE) /opt:ref /LTCG
-!endif
-!endif
diff --git a/win32/generate-msvc.mak b/win32/generate-msvc.mak
deleted file mode 100644
index 32214eb..0000000
--- a/win32/generate-msvc.mak
+++ /dev/null
@@ -1,26 +0,0 @@
-# NMake Makefile portion for code generation and
-# intermediate build directory creation
-# Items in here should not need to be edited unless
-# one is maintaining the NMake build files.
-
-# Copy the pre-defined config.h.win32
-config.h: config.h.win32
-	@-copy $@.win32 $@
-
-# Generate the enumeration sources and headers
-# sed is not normally available on Windows, but since
-# we are already using PERL, use PERL one-liners.
-!if "$(GOBJECT)" == "1"
-$(HB_GOBJECT_ENUM_GENERATED_SOURCES): ..\src\hb-gobject-enums.h.tmpl ..\src\hb-gobject-enums.cc.tmpl $(HB_ACTUAL_HEADERS)
-	$(PERL) $(PREFIX)\bin\glib-mkenums \
-		--identifier-prefix hb_ --symbol-prefix hb_gobject \
-		--template ..\src\$(@F).tmpl  $(HB_ACTUAL_HEADERS) > $@
-	$(PERL) -p -i.tmp1 -e "s/_t_get_type/_get_type/g" $@
-	$(PERL) -p -i.tmp2 -e "s/_T \(/ (/g" $@
-	@-del $@.tmp1
-	@-del $@.tmp2
-!endif
-
-# Create the build directories
-$(CFG)\$(PLAT)\harfbuzz $(CFG)\$(PLAT)\harfbuzz-gobject $(CFG)\$(PLAT)\util:
-	@-md $@
diff --git a/win32/hb-introspection-msvc.mak b/win32/hb-introspection-msvc.mak
deleted file mode 100644
index 67a0c5e..0000000
--- a/win32/hb-introspection-msvc.mak
+++ /dev/null
@@ -1,42 +0,0 @@
-
-!if "$(BUILD_INTROSPECTION)" == "TRUE"
-# Create the file list for introspection (to avoid the dreaded command-line-too-long problem on Windows)
-$(CFG)\$(PLAT)\hb_list: $(HB_ACTUAL_HEADERS) $(HB_ACTUAL_SOURCES) $(HB_GOBJECT_ENUM_GENERATED_SOURCES) $(HB_GOBJECT_ACTUAL_SOURCES)
-	@for %f in ($(HB_ACTUAL_HEADERS) $(HB_ACTUAL_SOURCES) $(HB_GOBJECT_ENUM_GENERATED_SOURCES) $(HB_GOBJECT_ACTUAL_SOURCES)) do @echo %f >> $@
-
-$(CFG)\$(PLAT)\HarfBuzz-0.0.gir: $(CFG)\$(PLAT)\harfbuzz-gobject.lib $(CFG)\$(PLAT)\hb_list
-	@set LIB=$(CFG)\$(PLAT);$(PREFIX)\lib;$(LIB)
-	@set PATH=$(CFG)\$(PLAT);$(PREFIX)\bin;$(PATH)
-	@-echo Generating $@...
-	$(PYTHON) $(G_IR_SCANNER)	\
-	--verbose -no-libtool	\
-	-I..\src -n hb --identifier-prefix=hb_ --warn-all	\
-	--namespace=HarfBuzz	\
-	--nsversion=0.0	\
-	--include=GObject-2.0	\
-	--library=harfbuzz-gobject	\
-	--library=harfbuzz	\
-	--add-include-path=$(G_IR_INCLUDEDIR)	\
-	--pkg-export=harfbuzz	\
-	--cflags-begin	\
-	$(CFLAGS) $(HB_DEFINES) $(HB_CFLAGS)	\
-	-DHB_H \
-	-DHB_H_IN \
-	-DHB_OT_H \
-	-DHB_OT_H_IN \
-	-DHB_GOBJECT_H \
-	-DHB_GOBJECT_H_IN \
-	--cflags-end	\
-	--filelist=$(CFG)\$(PLAT)\hb_list	\
-	-o $@
-
-$(CFG)\$(PLAT)\HarfBuzz-0.0.typelib: $(CFG)\$(PLAT)\HarfBuzz-0.0.gir
-	@copy $*.gir $(@B).gir
-	$(PREFIX)\bin\g-ir-compiler	\
-	--includedir=$(CFG)\$(PLAT) --debug --verbose	\
-	$(@B).gir	\
-	-o $@
-	@del $(@B).gir
-!else
-!error $(ERROR_MSG)
-!endif
diff --git a/win32/info-msvc.mak b/win32/info-msvc.mak
deleted file mode 100644
index 3ec11d4..0000000
--- a/win32/info-msvc.mak
+++ /dev/null
@@ -1,142 +0,0 @@
-# NMake Makefile portion for displaying config info
-
-INC_FEATURES = Fallback OT
-BUILT_TOOLS =
-BUILT_LIBRARIES = HarfBuzz
-
-!if "$(GLIB)" == "1"
-UNICODE_IMPL = GLib
-INC_FEATURES = $(INC_FEATURES) GLib
-BUILT_TOOLS = hb-shape.exe hb-ot-shape-closure.exe
-!if "$(CAIRO_FT)" == "1"
-BUILT_TOOLS = hb-view.exe $(BUILT_TOOLS)
-!endif
-!elseif "$(ICU)" == "1"
-UNICODE_IMPL = ICU
-!else
-UNICODE_IMPL = ucdn
-!endif
-
-!if "$(FREETYPE)" == "1"
-INC_FEATURES = $(INC_FEATURES) FreeType
-!endif
-
-!if "$(GRAPHITE2)" == "1"
-INC_FEATURES = $(INC_FEATURES) Graphite2
-!endif
-
-!if "$(UNISCRIBE)" == "1"
-INC_FEATURES = $(INC_FEATURES) Uniscribe
-!endif
-
-!if "$(DIRECTWRITE)" == "1"
-INC_FEATURES = $(INC_FEATURES) DirectWrite
-!endif
-
-!if "$(GOBJECT)" == "1"
-BUILT_LIBRARIES = $(BUILT_LIBRARIES) HarfBuzz-GObject
-!endif
-
-!if "$(INTROSPECTION)" == "1"
-BUILD_INTROSPECTION = yes
-!else
-BUILD_INTROSPECTION = no
-!endif
-
-build-info-hb:
-	@echo.
-	@echo ==================================
-	@echo Configuration for HarfBuzz Library
-	@echo ==================================
-	@echo Unicode Implementation: $(UNICODE_IMPL)
-	@echo Enabled Features: $(INC_FEATURES)
-
-all-build-info: build-info-hb
-	@echo.
-	@echo ----------------
-	@echo Other build info
-	@echo ----------------
-	@echo Built Libraries: $(BUILT_LIBRARIES)
-	@echo Built Tools: $(BUILT_TOOLS)
-	@echo Introspection: $(BUILD_INTROSPECTION)
-
-help:
-	@echo.
-	@echo =============================
-	@echo Building HarfBuzz Using NMake
-	@echo =============================
-	@echo nmake /f Makefile.vc CFG=[release^|debug] ^<PREFIX=PATH^> OPTION=1 ...
-	@echo.
-	@echo Where:
-	@echo ------
-	@echo CFG: Required, use CFG=release for an optimized build and CFG=debug
-	@echo for a debug build.  PDB files are generated for all builds.
-	@echo.
-	@echo PREFIX: Optional, the path where dependent libraries and tools may be
-	@echo found, default is ^$(srcrootdir)\..\vs^$(short_vs_ver)\^$(platform),
-	@echo where ^$(short_vs_ver) is 9 for VS 2008, 10 for VS 2010 and so on; and
-	@echo ^$(platform) is Win32 for 32-bit builds and x64 for x64 builds.
-	@echo.
-	@echo OPTION: Optional, may be any of the following, use OPTION=1 to enable;
-	@echo multiple OPTION's may be used.  If no OPTION is specified, a default
-	@echo HarfBuzz DLL is built with OpenType and fallback support
-	@echo with a bundled Unicode implementation (UCDN).
-	@echo ======
-	@echo UNISCRIBE:
-	@echo Enable Uniscribe support.
-	@echo.
-	@echo DIRECTWRITE:
-	@echo Enable DirectWrite support, requires a recent enough Windows SDK.
-	@echo.
-	@echo GRAPHITE2:
-	@echo Enable graphite2 support, requires the SIL Graphite2 library
-	@echo.
-	@echo FREETYPE:
-	@echo Enable FreeType2 support, requires the FreeType2 library
-	@echo.
-	@echo GLIB:
-	@echo Enable GLib2 support, with GLib Unicode support, requires the GNOME GLib2
-	@echo library.  Enables the build of utility programs.
-	@echo.
-	@echo ICU:
-	@echo Enable build with ICU Unicode functions, requires the International
-	@echo Components for Unicode (ICU) libraries.
-	@echo.
-	@echo GOBJECT:
-	@echo Enable the HarfBuzz-GObject library, also implies GLib2 support,
-	@echo requires the GNOME GLib2 libraries and tools, notably the glib-mkenums
-	@echo tool script, which will require a PERL interpreter (use
-	@echo PERL=^$(PATH_TO_PERL_INTERPRETOR)) if it is not already in your PATH).
-	@echo.
-	@echo INTROSPECTION:
-	@echo Enable the build of introspection files, also implies GObject/GLib2 support,
-	@echo requires the GNOME gobject-introspection libraries and tools.  You will need
-	@echo to ensure the pkg-config (.pc) files can be found for GObject-2.0 and the
-	@echo Python interpreter (that was used to build the gobject-introspection tools)
-	@echo can be found by setting PKG_CONFIG_PATH beforehand, and passing in PYTHON=
-	@echo ^$(PATH_TO_PYTHON_INTERPRETOR) respectively, if python.exe is not already
-	@echo in your PATH.
-	@echo.
-	@echo CAIRO_FT:
-	@echo Enables Cairo-Freetype support, needed for the build of the hb-view utility.
-	@echo Implies FreeType2 support and also requires Cairo built with FreeType2
-	@echo support; GLib2 support must also be enabled.
-	@echo.
-	@echo LIBTOOL_DLL_NAME:
-	@echo Use a libtool-style DLL name to mimic the DLL file naming generated by
-	@echo MinGW builds.
-	@echo.
-	@echo Note that GLib2 support is required for all utility and test programs.
-	@echo ======
-	@echo A 'clean' target is supported to remove all generated files, intermediate
-	@echo object files and binaries for the specified configuration.
-	@echo.
-	@echo A 'tests' target is supported to build the test programs, if GLib2 support
-	@echo is enabled.  Use after building the libraries and utilities.
-	@echo.
-	@echo An 'install' target is supported to copy the build (DLLs, utility programs,
-	@echo LIBs, along with the introspection files if applicable) to appropriate
-	@echo locations under ^$(PREFIX).
-	@echo ======
-	@echo.
-	
diff --git a/win32/install.mak b/win32/install.mak
deleted file mode 100644
index e0a38e3..0000000
--- a/win32/install.mak
+++ /dev/null
@@ -1,25 +0,0 @@
-# NMake Makefile snippet for copying the built libraries, utilities and headers to
-# a path under $(PREFIX).
-
-install: all
-	@if not exist $(PREFIX)\bin\ mkdir $(PREFIX)\bin
-	@if not exist $(PREFIX)\lib\ mkdir $(PREFIX)\lib
-	@if not exist $(PREFIX)\include\harfbuzz\ mkdir $(PREFIX)\include\harfbuzz
-	@copy /b $(HARFBUZZ_DLL_FILENAME).dll $(PREFIX)\bin
-	@copy /b $(HARFBUZZ_DLL_FILENAME).pdb $(PREFIX)\bin
-	@copy /b $(CFG)\$(PLAT)\harfbuzz.lib $(PREFIX)\lib
-	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy /b $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll $(PREFIX)\bin
-	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy /b $(HARFBUZZ_GOBJECT_DLL_FILENAME).pdb $(PREFIX)\bin
-	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy /b $(CFG)\$(PLAT)\harfbuzz-gobject.lib $(PREFIX)\lib
-	@if exist $(CFG)\$(PLAT)\hb-view.exe copy /b $(CFG)\$(PLAT)\hb-view.exe $(PREFIX)\bin
-	@if exist $(CFG)\$(PLAT)\hb-view.exe copy /b $(CFG)\$(PLAT)\hb-view.pdb $(PREFIX)\bin
-	@if exist $(CFG)\$(PLAT)\hb-ot-shape-closure.exe copy /b $(CFG)\$(PLAT)\hb-ot-shape-closure.exe $(PREFIX)\bin
-	@if exist $(CFG)\$(PLAT)\hb-ot-shape-closure.exe copy /b $(CFG)\$(PLAT)\hb-ot-shape-closure.pdb $(PREFIX)\bin
-	@if exist $(CFG)\$(PLAT)\hb-shape.exe copy /b $(CFG)\$(PLAT)\hb-shape.exe $(PREFIX)\bin
-	@if exist $(CFG)\$(PLAT)\hb-shape.exe copy /b $(CFG)\$(PLAT)\hb-shape.pdb $(PREFIX)\bin
-	@for %h in ($(HB_ACTUAL_HEADERS)) do @copy %h $(PREFIX)\include\harfbuzz
-	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll for %h in ($(HB_GOBJECT_headers)) do @copy ..\src\%h $(PREFIX)\include\harfbuzz
-	@if exist $(HARFBUZZ_GOBJECT_DLL_FILENAME).dll copy $(CFG)\$(PLAT)\harfbuzz-gobject\hb-gobject-enums.h $(PREFIX)\include\harfbuzz
-	@rem Copy the generated introspection files
-	@if exist $(CFG)\$(PLAT)\HarfBuzz-0.0.gir copy $(CFG)\$(PLAT)\HarfBuzz-0.0.gir $(PREFIX)\share\gir-1.0
-	@if exist $(CFG)\$(PLAT)\HarfBuzz-0.0.typelib copy /b $(CFG)\$(PLAT)\HarfBuzz-0.0.typelib $(PREFIX)\lib\girepository-1.0
diff --git a/win32/introspection-msvc.mak b/win32/introspection-msvc.mak
deleted file mode 100644
index d32f7cf..0000000
--- a/win32/introspection-msvc.mak
+++ /dev/null
@@ -1,73 +0,0 @@
-# Common NMake Makefile module for checking the build environment is sane
-# for building introspection files under MSVC/NMake.
-# This can be copied from $(gi_srcroot)\build\win32 for GNOME items
-# that support MSVC builds and introspection under MSVC.
-
-# Can override with env vars as needed
-# You will need to have built gobject-introspection for this to work.
-# Change or pass in or set the following to suit your environment
-
-!if "$(PREFIX)" == ""
-PREFIX = ..\..\..\vs$(VSVER)\$(PLAT)
-!endif
-
-# Note: The PYTHON must be the Python release series that was used to build
-# the GObject-introspection scanner Python module!
-# Either having python.exe your PATH will work or passing in
-# PYTHON=<full path to your Python interpretor> will do
-
-# This is required, and gobject-introspection needs to be built
-# before this can be successfully run.
-!if "$(PYTHON)" == ""
-PYTHON=python
-!endif
-
-# Don't change anything following this line!
-
-GIR_SUBDIR = share\gir-1.0
-GIR_TYPELIBDIR = lib\girepository-1.0
-G_IR_SCANNER = $(PREFIX)\bin\g-ir-scanner
-G_IR_COMPILER = $(PREFIX)\bin\g-ir-compiler.exe
-G_IR_INCLUDEDIR = $(PREFIX)\$(GIR_SUBDIR)
-G_IR_TYPELIBDIR = $(PREFIX)\$(GIR_TYPELIBDIR)
-
-VALID_PKG_CONFIG_PATH = FALSE
-
-MSG_INVALID_PKGCONFIG = You must set or specifiy a valid PKG_CONFIG_PATH
-MSG_INVALID_CFG = You need to specify or set CFG to be release or debug to use this Makefile to build the Introspection Files
-
-ERROR_MSG =
-
-BUILD_INTROSPECTION = TRUE
-
-!if ![pkg-config --print-errors --errors-to-stdout $(CHECK_PACKAGE) > pkgconfig.x]	\
-	&& ![setlocal]	\
-	&& ![set file="pkgconfig.x"]	\
-	&& ![FOR %A IN (%file%) DO @echo PKG_CHECK_SIZE=%~zA > pkgconfig.chksize]	\
-	&& ![del $(ERRNUL) /q/f pkgconfig.x]
-!endif
-
-!include pkgconfig.chksize
-!if "$(PKG_CHECK_SIZE)" == "0"
-VALID_PKG_CONFIG_PATH = TRUE
-!else
-VALID_PKG_CONFIG_PATH = FALSE
-!endif
-
-!if ![del $(ERRNUL) /q/f pkgconfig.chksize]
-!endif
-
-VALID_CFGSET = FALSE
-!if "$(CFG)" == "release" || "$(CFG)" == "debug"
-VALID_CFGSET = TRUE
-!endif
-
-!if "$(VALID_PKG_CONFIG_PATH)" != "TRUE"
-BUILD_INTROSPECTION = FALSE
-ERROR_MSG = $(MSG_INVALID_PKGCONFIG)
-!endif
-
-!if "$(VALID_CFGSET)" != "TRUE"
-BUILD_INTROSPECTION = FALSE
-ERROR_MSG = $(MSG_INVALID_CFG)
-!endif