Update harfbuzz to 1.2.1 from the upstream

This updates harfbuzz from 0.9.38 (Feb 2015) to 1.2.1 (Feb 2016; dabf32a)

There have been numerous improvements and changes including
the switch to USE(Universal Shaping Engine) for a number of scripts.

The header files generated from rl files (rangel) and hb-version.h
are copied manually from the 1.2.1 tar ball.

for f in *rl
do
  cp "$(basename $f rl)hh" "${TREE_TOP}/external/harfbuzz_ng/src/"
done

cp hb-version.h "${HB_TREE_TOP}/external/harfbuzz_ng/src/"

Besides, remove header files corresponding to removed rl files:

for f in $(git status | egrep 'deleted:.*rl$' | awk '{print $2;}')
do
    git rm "$(basename $f rl)hh"
done

Bug: 26797521
Change-Id: Iff91c3ca6718e36402d380192385caca696653c3
diff --git a/.ci/deploy-docs.sh b/.ci/deploy-docs.sh
new file mode 100755
index 0000000..e4dbad4
--- /dev/null
+++ b/.ci/deploy-docs.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -x
+set -o errexit -o nounset
+
+BRANCH="$TRAVIS_BRANCH"
+if test "x$BRANCH" != xmaster; then exit; fi
+
+TAG="$(git describe --exact-match --match "[0-9]*" HEAD 2>/dev/null || true)"
+
+DOCSDIR=build-docs
+REVISION=$(git rev-parse --short HEAD)
+
+rm -rf $DOCSDIR || exit
+mkdir $DOCSDIR
+cd $DOCSDIR
+
+cp ../docs/html/* .
+
+git init
+git config user.name "Travis CI"
+git config user.email "[email protected]"
+set +x
+echo "git remote add upstream \"https://\[email protected]/$TRAVIS_REPO_SLUG.git\""
+git remote add upstream "https://[email protected]/$TRAVIS_REPO_SLUG.git"
+set -x
+git fetch upstream
+git reset upstream/gh-pages
+
+touch .
+git add -A .
+git commit -m "Rebuild docs for $REVISION"
+git push -q upstream HEAD:gh-pages
diff --git a/.travis.yml b/.travis.yml
index 4b3e0f8..f37b4b2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,9 @@
+# Build Configuration for Travis
+sudo: required # For Trusty beta
+os:
+  - linux
+  - osx
+dist: trusty
 language: cpp
 compiler:
   - clang
@@ -6,20 +12,39 @@
   global:
     - CPPFLAGS=""
     - CFLAGS="-Werror --coverage"
-    - CXXFLAGS="-Werror --coverage"
+    - CXXFLAGS="-Werror -Wno-deprecated-register --coverage" # glib uses register and clang raises a warning
     - LDFLAGS="--coverage"
 install:
-  - sudo apt-get install pkg-config ragel gtk-doc-tools # for autogen.sh
-  - sudo apt-get install libfreetype6-dev # for font functions
-  - sudo apt-get install libglib2.0-dev # for font functions / tests / utils
-  - sudo apt-get install libcairo2-dev # for utils
-  - sudo apt-get install libicu-dev # for extra unicode functions
-  - sudo apt-get install libgraphite2-dev # for extra shapers
-  - sudo pip install cpp-coveralls # for coveralls.io code coverage tracking
+  - 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 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
-  - ./configure --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
-  - make && make check && { rm -f src/.libs/NONE.gcov; touch src/NONE; test $CC != gcc || coveralls; }
+  - 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
 notifications:
   irc: "irc.freenode.org#harfbuzz"
   email: [email protected]
+
+addons:
+  apt:
+    packages:
+      - pkg-config # for autogen.sh
+      - ragel
+      - gtk-doc-tools
+      - libfreetype6-dev # for font function
+      - libglib2.0-dev # for font functions / tests / utils
+      - libcairo2-dev # for utils
+      - libicu-dev # for extra unicode functions
+      - libgraphite2-dev # for extra shapers
+      - # libgirepository1.0-dev # for gobject-introspection
diff --git a/Android.mk b/Android.mk
index 418b6c0..c8cc501 100644
--- a/Android.mk
+++ b/Android.mk
@@ -75,9 +75,10 @@
 	src/hb-ot-shape-complex-indic.cc \
 	src/hb-ot-shape-complex-indic-table.cc \
 	src/hb-ot-shape-complex-myanmar.cc \
-	src/hb-ot-shape-complex-sea.cc \
 	src/hb-ot-shape-complex-thai.cc \
 	src/hb-ot-shape-complex-tibetan.cc \
+	src/hb-ot-shape-complex-use.cc \
+	src/hb-ot-shape-complex-use-table.cc \
 	src/hb-ot-shape-normalize.cc \
 	src/hb-ot-shape-fallback.cc \
 	$(NULL)
diff --git a/BUILD.md b/BUILD.md
new file mode 100644
index 0000000..86285c6
--- /dev/null
+++ b/BUILD.md
@@ -0,0 +1,33 @@
+On Linux, install the development packages for
+[FreeType](http://www.freedesktop.org/wiki/Software/FreeType/),
+Cairo, and GLib. For example, on Ubuntu / Debian, you would do:
+* sudo apt-get install gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
+
+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:
+* sudo port install freetype glib2 cairo
+
+or using Homebrew:
+* brew install freetype glib cairo
+
+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.
+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:
+* sudo apt-get install autoconf automake libtool pkg-config ragel gtk-doc-tools
+
+and on Fedora, RHEL, CentOS:
+* sudo yum install autoconf automake libtool pkgconfig ragel gtk-doc
+
+on the Mac, using MacPorts:
+* sudo port install autoconf automake libtool pkgconfig ragel gtk-doc
+
+or using Homebrew:
+* brew port install autoconf automake libtool pkgconfig ragel gtk-doc
diff --git a/Makefile.am b/Makefile.am
index 58afd9b..d56a151 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,13 +4,14 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = src util test docs
+SUBDIRS = src util test docs win32
 
 EXTRA_DIST = \
 	autogen.sh \
 	harfbuzz.doap \
 	Android.mk \
 	README.python \
+	BUILD.md \
 	$(NULL)
 
 MAINTAINERCLEANFILES = \
@@ -19,6 +20,8 @@
 	$(GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN) \
 	$(srcdir)/INSTALL \
 	$(srcdir)/ChangeLog \
+	$(srcdir)/gtk-doc.make \
+	$(srcdir)/m4/gtk-doc.m4 \
 	$(NULL)
 
 
diff --git a/NEWS b/NEWS
index 3a33bdf..b1b63b2 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,242 @@
+Overview of changes leading to 1.2.1
+Friday, February 23, 2016
+====================================
+
+- CoreText: Fix bug with wrong scale if font scale was changed later.
+  https://github.com/libass/libass/issues/212
+- 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
+- Add test/shaping/README.md about how to add tests to the suite.
+
+
+Overview of changes leading to 1.2.0
+Friday, February 19, 2016
+====================================
+
+- Fix various issues (hangs mostly) in case of memory allocation failure.
+- Change mark zeroing types of most shapers from BY_UNICODE_LATE to
+  BY_GDEF_LATE.  This seems to be what Uniscribe does.
+- Change mark zeroing of USE shaper from NONE to BY_GDEF_EARLY.  That's
+  what Windows does.
+- 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
+- Graphite2 shaper: improved negative advance handling (eg. Nastaliq).
+- Add nmake-based build system for Windows.
+- Minor speedup.
+- Misc. improvements.
+
+
+Overview of changes leading to 1.1.3
+Monday, January 11, 2016
+====================================
+
+- Ported Indic shaper to Unicode 8.0 data.
+- Universal Shaping Engine fixes.
+- Speed up CoreText shaper when font fallback happens in CoreText.
+- Documentation improvements, thanks to Khaled Hosny.
+- Very rough directwrite shaper for testing, thanks to Ebrahim Byagowi.
+- Misc bug fixes.
+- New API:
+
+  * Font extents:
+      hb_font_extents_t
+      hb_font_get_font_extents_func_t
+      hb_font_get_font_h_extents_func_t
+      hb_font_get_font_v_extents_func_t
+      hb_font_funcs_set_font_h_extents_func
+      hb_font_funcs_set_font_v_extents_func
+      hb_font_get_h_extents
+      hb_font_get_v_extents
+      hb_font_get_extents_for_direction
+
+  * Buffer message (aka debug):
+      hb_buffer_message_func_t
+      hb_buffer_set_message_func()
+    Actual message protocol to be fleshed out later.
+
+
+Overview of changes leading to 1.1.2
+Wednesday, November 26, 2015
+====================================
+
+- Fix badly-broken fallback shaper that affected terminology.
+  https://github.com/behdad/harfbuzz/issues/187
+- Fix y_scaling in Graphite shaper.
+- API changes:
+  * An unset glyph_h_origin() function in font-funcs now (sensibly)
+    implies horizontal origin at 0,0.  Ie, the nil callback returns
+    true instead of false.  As such, implementations that have a
+    glyph_h_origin() that simply returns true, can remove that function
+    with HarfBuzz >= 1.1.2.  This results in a tiny speedup.
+
+
+Overview of changes leading to 1.1.1
+Wednesday, November 24, 2015
+====================================
+
+- Build fixes, specially for hb-coretext.
+
+
+Overview of changes leading to 1.1.0
+Wednesday, November 18, 2015
+====================================
+
+- Implement 'stch' stretch feature for Syriac Abbreviation Mark.
+  https://github.com/behdad/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
+- If font does not support U+2011 NO-BREAK HYPHEN, fallback to
+  U+2010 HYPHEN.
+- Changes resulting from libFuzzer continuous fuzzing:
+  * Reject font tables that need more than 8 edits,
+  * Bound buffer growth during shaping to 32x,
+  * Fix assertions and other issues at OOM / buffer max-growth.
+- Misc fixes and optimizations.
+- API changes:
+  * All fonts created with hb_font_create() now inherit from
+    (ie. have parent) hb_font_get_empty().
+
+
+Overview of changes leading to 1.0.6
+Thursday, October 15, 2015
+====================================
+
+- Reduce max nesting level in OT lookups from 8 to 6.
+  Should not affect any real font as far as I know.
+- Fix memory access issue in ot-font.
+- 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
+
+
+Overview of changes leading to 1.0.5
+Tuesday, October 13, 2015
+====================================
+
+- Fix multiple memory access bugs discovered using libFuzzer.
+  https://github.com/behdad/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.
+- Misc fixes.
+
+- New API:
+  * hb_font_set_parent().
+  * hb_ft_font_[sg]et_load_flags()
+    The default flags for fonts created using hb_ft_font_create()
+    has changed to default to FT_LOAD_DEFAULT now.  Previously it
+    was defaulting to FT_LOAD_DFEAULT|FT_LOAD_NO_HINTING.
+
+- API changes:
+  * Fonts now default to units-per-EM as their scale, instead of 0.
+  * hb_font_create_sub_font() does NOT make parent font immutable
+    anymore.  hb_font_make_immutable() does.
+
+
+Overview of changes leading to 1.0.4
+Wednesday, September 30, 2015
+====================================
+
+- Fix minor out-of-bounds read error.
+
+
+Overview of changes leading to 1.0.3
+Tuesday, September 1, 2015
+====================================
+
+- Start of user documentation, from Simon Cozens!
+- Implement glyph_extents() for TrueType fonts in hb-ot-font.
+- Improve GPOS cursive attachments with conflicting lookups.
+- More fixes for cluster-level = 1.
+- Uniscribe positioning fix.
+
+
+Overview of changes leading to 1.0.2
+Wednesday, August 19, 2015
+====================================
+
+- Fix shaping with cluster-level > 0.
+- Fix Uniscribe backend font-size scaling.
+- Declare dependencies in harfbuzz.pc.
+  FreeType is not declared though, to avoid bugs in pkg-config
+  0.26 with recursive dependencies.
+- Slightly improved debug infrastructure.  More to come later.
+- Misc build fixes.
+
+
+Overview of changes leading to 1.0.1
+Monday, July 27, 2015
+====================================
+
+- Fix out-of-bounds access in USE shaper.
+
+
+Overview of changes leading to 1.0.0
+Sunday, July 26, 2015
+====================================
+
+- Implement Universal Shaping Engine:
+  https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm
+  http://blogs.windows.com/bloggingwindows/2015/02/23/windows-shapes-the-worlds-languages/
+- Bump version to 1.0.0.  The soname was NOT bumped.
+
+
+Overview of changes leading to 0.9.42
+Thursday, July 26, 2015
+=====================================
+
+- New API to allow for retrieving finer-grained cluster
+  mappings if the client desires to handle them.  Default
+  behavior is unchanged.
+- Fix cluster merging when removing default-ignorables.
+- Update to Unicode 8.0
+- hb-graphite2 fixes.
+- Misc fixes.
+- Removed HB_NO_MERGE_CLUSTERS hack.
+- New API:
+  hb_buffer_cluster_level_t enum
+  hb_buffer_get_cluster_level()
+  hb_buffer_set_cluster_level()
+  hb-shape / hb-view --cluster-level
+
+
+Overview of changes leading to 0.9.41
+Thursday, June 18, 2015
+=====================================
+
+- Fix hb-coretext with trailing whitespace in right-to-left.
+- New API: hb_buffer_reverse_range().
+- Allow implementing atomic ops in config.h.
+- Fix hb_language_t in language bindings.
+- Misc fixes.
+
+
+Overview of changes leading to 0.9.40
+Friday, March 20, 2015
+=====================================
+
+- Another hb-coretext crasher fix.  Ouch!
+- Happy Norouz!
+
+
+Overview of changes leading to 0.9.39
+Wednesday, March 4, 2015
+=====================================
+
+- Critical hb-coretext fixes.
+- Optimizations and refactoring; no functional change
+  expected.
+- Misc build fixes.
+
+
 Overview of changes leading to 0.9.38
 Friday, January 23, 2015
 =====================================
diff --git a/README b/README
index d34bc74..3fcdfb4 100644
--- a/README
+++ b/README
@@ -1,5 +1,6 @@
 [![Build Status](https://travis-ci.org/behdad/harfbuzz.svg)](https://travis-ci.org/behdad/harfbuzz)
 [![Coverage Status](https://img.shields.io/coveralls/behdad/harfbuzz.svg)](https://coveralls.io/r/behdad/harfbuzz)
+[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
 
 This is HarfBuzz, a text shaping library.
 
diff --git a/README.python b/README.python
index eabdf5b..cd31264 100644
--- a/README.python
+++ b/README.python
@@ -1,6 +1,10 @@
 To enable HarfBuzz bindings for Python among other languages, make sure
-you have latest version of gobject-introspection compiled, and then
-run autogen.sh (if building from git), and then:
+you have latest version of gobject-introspection available.  On Ubuntu,
+you can install that this way:
+
+  sudo apt-get install libgirepository1.0-dev
+
+And then run autogen.sh (if building from git), and then:
 
   ./configure --with-gobject --enable-introspection
 
diff --git a/README.version b/README.version
index 62c97b8..65ac146 100644
--- a/README.version
+++ b/README.version
@@ -1,3 +1,3 @@
-URL: http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-0.9.33.tar.bz2
-Version: 0.9.33
+URL: http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-1.2.1.tar.bz2
+Version: 1.2.1
 BugComponent: 25699
diff --git a/autogen.sh b/autogen.sh
index a267f29..ff1b0c0 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -19,17 +19,22 @@
 	exit 1
 }
 
+echo -n "checking for libtoolize... "
+which glibtoolize || which libtoolize || {
+	echo "*** No libtoolize (libtool) found, please install it ***"
+	exit 1
+}
 echo -n "checking for gtkdocize... "
 if which gtkdocize ; then
 	gtkdocize --copy || exit 1
 else
-	echo "*** No gtkdocize found, skipping documentation ***"
+	echo "*** No gtkdocize (gtk-doc) found, skipping documentation ***"
 	echo "EXTRA_DIST = " > gtk-doc.make
 fi
 
 echo -n "checking for autoreconf... "
 which autoreconf || {
-	echo "*** No autoreconf found, please install it ***"
+	echo "*** No autoreconf (autoconf) found, please install it ***"
 	exit 1
 }
 
diff --git a/configure.ac b/configure.ac
index 3e42d95..d12d4b8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [0.9.38],
+        [1.2.1],
         [http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz],
         [harfbuzz],
         [http://harfbuzz.org/])
@@ -51,7 +51,7 @@
 m4_define([hb_libtool_age],
 	  m4_eval(hb_version_int - hb_libtool_revision))
 m4_define([hb_libtool_current],
-	  m4_eval(hb_version_major + hb_libtool_age))
+	  m4_eval(hb_libtool_age))
 HB_LIBTOOL_VERSION_INFO=hb_libtool_current:hb_libtool_revision:hb_libtool_age
 AC_SUBST(HB_LIBTOOL_VERSION_INFO)
 
@@ -145,8 +145,10 @@
 			[Use glib @<:@default=auto@:>@])],,
 	[with_glib=auto])
 have_glib=false
+GLIB_DEPS="glib-2.0 >= 2.16"
+AC_SUBST(GLIB_DEPS)
 if test "x$with_glib" = "xyes" -o "x$with_glib" = "xauto"; then
-	PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, have_glib=true, :)
+	PKG_CHECK_MODULES(GLIB, $GLIB_DEPS, have_glib=true, :)
 fi
 if test "x$with_glib" = "xyes" -a "x$have_glib" != "xtrue"; then
 	AC_MSG_ERROR([glib support requested but glib-2.0 not found])
@@ -235,6 +237,24 @@
 
 dnl ==========================================================================
 
+AC_ARG_WITH(fontconfig,
+	[AS_HELP_STRING([--with-fontconfig=@<:@yes/no/auto@:>@],
+			[Use fontconfig @<:@default=auto@:>@])],,
+	[with_fontconfig=auto])
+have_fontconfig=false
+if test "x$with_fontconfig" = "xyes" -o "x$with_fontconfig" = "xauto"; then
+	PKG_CHECK_MODULES(FONTCONFIG, fontconfig, have_fontconfig=true, :)
+fi
+if test "x$with_fontconfig" = "xyes" -a "x$have_fontconfig" != "xtrue"; then
+	AC_MSG_ERROR([fontconfig support requested but not found])
+fi
+if $have_fontconfig; then
+	AC_DEFINE(HAVE_FONTCONFIG, 1, [Have fontconfig library])
+fi
+AM_CONDITIONAL(HAVE_FONTCONFIG, $have_fontconfig)
+
+dnl ==========================================================================
+
 AC_ARG_WITH(icu,
 	[AS_HELP_STRING([--with-icu=@<:@yes/no/auto@:>@],
 			[Use ICU @<:@default=auto@:>@])],,
@@ -278,8 +298,10 @@
 			[Use the graphite2 library @<:@default=no@:>@])],,
 	[with_graphite2=no])
 have_graphite2=false
+GRAPHITE2_DEPS="graphite2"
+AC_SUBST(GRAPHITE2_DEPS)
 if test "x$with_graphite2" = "xyes" -o "x$with_graphite2" = "xauto"; then
-	PKG_CHECK_MODULES(GRAPHITE2, graphite2, have_graphite2=true, :)
+	PKG_CHECK_MODULES(GRAPHITE2, $GRAPHITE2_DEPS, have_graphite2=true, :)
 fi
 if test "x$with_graphite2" = "xyes" -a "x$have_graphite2" != "xtrue"; then
 	AC_MSG_ERROR([graphite2 support requested but libgraphite2 not found])
@@ -296,9 +318,11 @@
 			[Use the FreeType library @<:@default=auto@:>@])],,
 	[with_freetype=auto])
 have_freetype=false
+FREETYPE_DEPS="freetype2 >= 12.0.6"
+AC_SUBST(FREETYPE_DEPS)
 if test "x$with_freetype" = "xyes" -o "x$with_freetype" = "xauto"; then
 	# See freetype/docs/VERSION.DLL; 12.0.6 means freetype-2.4.2
-	PKG_CHECK_MODULES(FREETYPE, freetype2 >= 12.0.6, have_freetype=true, :)
+	PKG_CHECK_MODULES(FREETYPE, $FREETYPE_DEPS, have_freetype=true, :)
 fi
 if test "x$with_freetype" = "xyes" -a "x$have_freetype" != "xtrue"; then
 	AC_MSG_ERROR([FreeType support requested but libfreetype2 not found])
@@ -332,6 +356,30 @@
 
 dnl ===========================================================================
 
+AC_ARG_WITH(directwrite,
+	[AS_HELP_STRING([--with-directwrite=@<:@yes/no/auto@:>@],
+			[Use the DirectWrite library (experimental) @<:@default=no@:>@])],,
+	[with_directwrite=no])
+have_directwrite=false
+AC_LANG_PUSH([C++])
+if test "x$with_directwrite" = "xyes" -o "x$with_directwrite" = "xauto"; then
+	AC_CHECK_HEADERS(dwrite.h, have_directwrite=true)
+fi
+AC_LANG_POP([C++])
+if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then
+	AC_MSG_ERROR([directwrite support requested but not found])
+fi
+if $have_directwrite; then
+	DIRECTWRITE_CXXFLAGS=
+	DIRECTWRITE_LIBS="-ldwrite"
+	AC_SUBST(DIRECTWRITE_CXXFLAGS)
+	AC_SUBST(DIRECTWRITE_LIBS)
+	AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
+fi
+AM_CONDITIONAL(HAVE_DIRECTWRITE, $have_directwrite)
+
+dnl ===========================================================================
+
 AC_ARG_WITH(coretext,
 	[AS_HELP_STRING([--with-coretext=@<:@yes/no/auto@:>@],
 			[Use CoreText @<:@default=no@:>@])],,
@@ -416,10 +464,12 @@
 util/Makefile
 test/Makefile
 test/api/Makefile
+test/fuzzing/Makefile
 test/shaping/Makefile
 docs/Makefile
-docs/reference/Makefile
-docs/reference/version.xml
+docs/version.xml
+win32/Makefile
+win32/config.h.win32
 ])
 
 AC_OUTPUT
@@ -438,6 +488,7 @@
 
 Tools used for command-line utilities:
 	Cairo:			${have_cairo}
+	Fontconfig:		${have_fontconfig}
 
 Additional shapers (the more the better):
 	Graphite2:		${have_graphite2}
@@ -445,6 +496,7 @@
 Platform shapers (not normally needed):
 	CoreText:		${have_coretext}
 	Uniscribe:		${have_uniscribe}
+	DirectWrite:		${have_directwrite}
 
 Other features:
 	Documentation:		${have_gtk_doc}
diff --git a/docs/HarfBuzz.png b/docs/HarfBuzz.png
new file mode 100644
index 0000000..d58d9fc
--- /dev/null
+++ b/docs/HarfBuzz.png
Binary files differ
diff --git a/docs/Makefile.am b/docs/Makefile.am
index f3ddc22..3916801 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -1 +1,122 @@
-SUBDIRS = reference
+# Process this file with automake to produce Makefile.in
+
+# We require automake 1.6 at least.
+AUTOMAKE_OPTIONS = 1.6
+
+# This is a blank Makefile.am for using gtk-doc.
+# Copy this to your project's API docs directory and modify the variables to
+# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
+# of using the various options.
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=harfbuzz
+
+# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
+#DOC_MODULE_VERSION=$(HB_VERSION_MAJOR)
+
+# The top-level SGML file. You can change this if you want to.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
+
+# Directories containing the source code.
+# gtk-doc will search all .c and .h files beneath these paths
+# for inline comments documenting functions and macros.
+# e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk
+DOC_SOURCE_DIR=$(top_srcdir)/src $(top_builddir)/src
+
+# Extra options to pass to gtkdoc-scangobj. Not normally needed.
+SCANGOBJ_OPTIONS=
+
+# Extra options to supply to gtkdoc-scan.
+# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
+SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \
+	--ignore-decorators="HB_EXTERN"
+
+# Header files or dirs to ignore when scanning. Use base file/dir names
+# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
+IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './hb-*/*.h' | sed 's@^.*/@@'`
+if HAVE_GOBJECT
+else
+IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h
+endif
+
+# Extra options to supply to gtkdoc-mkdb.
+# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
+MKDB_OPTIONS=--source-suffixes=h,cc --xml-mode --output-format=xml --ignore-files="$(IGNORE_HFILES)"
+
+# Extra options to supply to gtkdoc-mktmpl
+# e.g. MKTMPL_OPTIONS=--only-section-tmpl
+MKTMPL_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkhtml
+MKHTML_OPTIONS=
+
+# Extra options to supply to gtkdoc-fixref. Not normally needed.
+# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
+FIXXREF_OPTIONS=
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
+# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
+HFILE_GLOB=$(top_srcdir)/src/hb.h $(top_srcdir)/src/hb-*.h
+CFILE_GLOB=$(top_srcdir)/src/hb-*.cc
+
+# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
+# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
+EXTRA_HFILES=$(top_builddir)/src/hb-version.h
+
+# Images to copy into HTML directory.
+# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
+HTML_IMAGES=  \
+	HarfBuzz.png
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
+content_files=	\
+	usermanual-buffers-language-script-and-direction.xml \
+	usermanual-clusters.xml \
+	usermanual-fonts-and-faces.xml \
+	usermanual-glyph-information.xml \
+	usermanual-hello-harfbuzz.xml \
+	usermanual-install-harfbuzz.xml \
+	usermanual-opentype-features.xml \
+	usermanual-what-is-harfbuzz.xml \
+	version.xml
+
+# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# These files must be listed here *and* in content_files
+# e.g. expand_content_files=running.sgml
+expand_content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+GTKDOC_CFLAGS=
+GTKDOC_LIBS=$(top_builddir)/src/libharfbuzz.la
+if HAVE_GOBJECT
+GTKDOC_LIBS+=$(top_builddir)/src/libharfbuzz-gobject.la
+endif
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+EXTRA_DIST += version.xml.in
+
+# Files not to distribute
+# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
+# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
+#DISTCLEANFILES +=
+
+# Comment this out if you want 'make check' to test you doc status
+# and run some sanity checks
+if ENABLE_GTK_DOC
+TESTS_ENVIRONMENT = cd $(srcdir) && \
+  DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
+  SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
+#TESTS = $(GTKDOC_CHECK)
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml
new file mode 100644
index 0000000..2c43c46
--- /dev/null
+++ b/docs/harfbuzz-docs.xml
@@ -0,0 +1,185 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
+  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
+  <!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index">
+  <bookinfo>
+    <title>HarfBuzz Manual</title>
+    <abstract>
+      <title>HarfBuzz</title>
+      <graphic fileref="HarfBuzz.png" format="PNG" align="center"/>
+      <para>
+        HarfBuzz is an <ulink url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>
+        text shaping engine.
+      </para>
+      <para>
+        The current HarfBuzz codebase, formerly known as harfbuzz-ng, is
+        versioned 1.x.x and is stable and under active maintenance. This is
+        what is used in latest versions of Firefox, GNOME, ChromeOS, Chrome,
+        LibreOffice, XeTeX, Android, and KDE, among other places. 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>.
+        See <xref linkend="download" endterm="download.title"/> for release tarballs.
+      </para>
+      <para>
+        The old HarfBuzz codebase, these days known as harfbuzz-old, was
+        derived from <ulink url="http://freetype.org/">FreeType</ulink>,
+        <ulink url="http://pango.org/">Pango</ulink>, and
+        <ulink url="http://qt-project.org/">Qt</ulink> and is available
+        <ulink url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>.
+        It is not actively developed or maintained, and is extremely buggy. All
+        users are encouraged to switch over to the new HarfBuzz as soon as
+        possible.  There are no release tarballs of old HarfBuzz whatsoever.
+      </para>
+    </abstract>
+  </bookinfo>
+
+  <part>
+    <title>User's manual</title>
+      <xi:include href="usermanual-what-is-harfbuzz.xml"/>
+      <xi:include href="usermanual-install-harfbuzz.xml"/>
+      <xi:include href="usermanual-hello-harfbuzz.xml"/>
+      <xi:include href="usermanual-buffers-language-script-and-direction.xml"/>
+      <xi:include href="usermanual-fonts-and-faces.xml"/>
+      <xi:include href="usermanual-clusters.xml"/>
+      <xi:include href="usermanual-opentype-features.xml"/>
+      <xi:include href="usermanual-glyph-information.xml"/>
+  </part>
+
+  <part>
+    <partinfo>
+      <releaseinfo>
+        This document is for HarfBuzz &version;.
+        <!--The latest version of this documentation can be found on-line at
+        <ulink role="online-location" url="http://[SERVER]/libharfbuzz/index.html">http://[SERVER]/libharfbuzz/</ulink>.-->
+      </releaseinfo>
+    </partinfo>
+    <title>Reference manual</title>
+      <chapter>
+        <title>Harfbuzz API</title>
+        <xi:include href="xml/hb.xml"/>
+        <xi:include href="xml/hb-common.xml"/>
+        <xi:include href="xml/hb-unicode.xml"/>
+        <xi:include href="xml/hb-buffer.xml"/>
+        <xi:include href="xml/hb-blob.xml"/>
+        <xi:include href="xml/hb-face.xml"/>
+        <xi:include href="xml/hb-font.xml"/>
+        <xi:include href="xml/hb-shape.xml"/>
+
+        <xi:include href="xml/hb-version.xml"/>
+        <xi:include href="xml/hb-deprecated.xml"/>
+
+        <xi:include href="xml/hb-set.xml"/>
+
+        <xi:include href="xml/hb-ot.xml"/>
+        <xi:include href="xml/hb-ot-layout.xml"/>
+        <xi:include href="xml/hb-ot-tag.xml"/>
+        <xi:include href="xml/hb-ot-font.xml"/>
+        <xi:include href="xml/hb-ot-shape.xml"/>
+
+        <xi:include href="xml/hb-shape-plan.xml"/>
+
+        <xi:include href="xml/hb-glib.xml"/>
+        <xi:include href="xml/hb-icu.xml"/>
+
+        <xi:include href="xml/hb-ft.xml"/>
+
+        <xi:include href="xml/hb-graphite2.xml"/>
+        <xi:include href="xml/hb-uniscribe.xml"/>
+        <xi:include href="xml/hb-coretext.xml"/>
+
+        <xi:include href="xml/hb-gobject.xml"/>
+
+      </chapter>
+      <chapter id="object-tree">
+        <title>Object Hierarchy</title>
+         <xi:include href="xml/tree_index.sgml"/>
+      </chapter>
+      <index id="api-index-full">
+        <title>API Index</title>
+        <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-2" role="0.9.2">
+        <title>Index of new symbols in 0.9.2</title>
+        <xi:include href="xml/api-index-0.9.2.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-5" role="0.9.5">
+        <title>Index of new symbols in 0.9.5</title>
+        <xi:include href="xml/api-index-0.9.5.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-7" role="0.9.7">
+        <title>Index of new symbols in 0.9.7</title>
+        <xi:include href="xml/api-index-0.9.7.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-8" role="0.9.8">
+        <title>Index of new symbols in 0.9.8</title>
+        <xi:include href="xml/api-index-0.9.8.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-10" role="0.9.10">
+        <title>Index of new symbols in 0.9.10</title>
+        <xi:include href="xml/api-index-0.9.10.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-11" role="0.9.11">
+        <title>Index of new symbols in 0.9.11</title>
+        <xi:include href="xml/api-index-0.9.11.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-20" role="0.9.20">
+        <title>Index of new symbols in 0.9.20</title>
+        <xi:include href="xml/api-index-0.9.20.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-22" role="0.9.22">
+        <title>Index of new symbols in 0.9.22</title>
+        <xi:include href="xml/api-index-0.9.22.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-28" role="0.9.28">
+        <title>Index of new symbols in 0.9.28</title>
+        <xi:include href="xml/api-index-0.9.28.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-30" role="0.9.30">
+        <title>Index of new symbols in 0.9.30</title>
+        <xi:include href="xml/api-index-0.9.30.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-31" role="0.9.31">
+        <title>Index of new symbols in 0.9.31</title>
+        <xi:include href="xml/api-index-0.9.31.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-38" role="0.9.38">
+        <title>Index of new symbols in 0.9.38</title>
+        <xi:include href="xml/api-index-0.9.38.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-39" role="0.9.39">
+        <title>Index of new symbols in 0.9.39</title>
+        <xi:include href="xml/api-index-0.9.39.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-41" role="0.9.41">
+        <title>Index of new symbols in 0.9.41</title>
+        <xi:include href="xml/api-index-0.9.41.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-0-9-42" role="0.9.42">
+        <title>Index of new symbols in 0.9.42</title>
+        <xi:include href="xml/api-index-0.9.42.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-1-0-5" role="1.0.5">
+        <title>Index of new symbols in 1.0.5</title>
+        <xi:include href="xml/api-index-1.0.5.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-1-1-2" role="1.1.2">
+        <title>Index of new symbols in 1.1.2</title>
+        <xi:include href="xml/api-index-1.1.2.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="api-index-1-1-3" role="1.1.3">
+        <title>Index of new symbols in 1.1.3</title>
+        <xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include>
+      </index>
+      <index id="deprecated-api-index" role="deprecated">
+        <title>Index of deprecated API</title>
+        <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
+      </index>
+
+      <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
+  </part>
+</book>
diff --git a/docs/reference/harfbuzz-overrides.txt b/docs/harfbuzz-overrides.txt
similarity index 100%
rename from docs/reference/harfbuzz-overrides.txt
rename to docs/harfbuzz-overrides.txt
diff --git a/docs/reference/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
similarity index 89%
rename from docs/reference/harfbuzz-sections.txt
rename to docs/harfbuzz-sections.txt
index 3612dad..e0dc23d 100644
--- a/docs/reference/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -2,6 +2,7 @@
 <FILE>hb</FILE>
 <SUBSECTION Private>
 HB_H_IN
+HB_EXTERN
 </SECTION>
 
 <SECTION>
@@ -25,94 +26,106 @@
 <SECTION>
 <FILE>hb-buffer</FILE>
 HB_SEGMENT_PROPERTIES_DEFAULT
-hb_buffer_add
-hb_buffer_add_utf16
-hb_buffer_add_utf32
-hb_buffer_add_utf8
-hb_buffer_allocation_successful
-hb_buffer_clear_contents
-hb_buffer_content_type_t
+HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
 hb_buffer_create
-hb_buffer_deserialize_glyphs
-hb_buffer_destroy
-hb_buffer_flags_t
-hb_buffer_get_content_type
-hb_buffer_get_direction
+hb_buffer_reference
 hb_buffer_get_empty
+hb_buffer_destroy
+hb_buffer_reset
+hb_buffer_clear_contents
+hb_buffer_pre_allocate
+hb_buffer_allocation_successful
+hb_buffer_add
+hb_buffer_add_codepoints
+hb_buffer_add_utf32
+hb_buffer_add_utf16
+hb_buffer_add_utf8
+hb_buffer_add_latin1
+hb_buffer_set_content_type
+hb_buffer_get_content_type
+hb_buffer_set_direction
+hb_buffer_get_direction
+hb_buffer_set_script
+hb_buffer_get_script
+hb_buffer_set_language
+hb_buffer_get_language
+hb_buffer_set_flags
 hb_buffer_get_flags
+hb_buffer_set_cluster_level
+hb_buffer_get_cluster_level
+hb_buffer_set_length
+hb_buffer_get_length
+hb_buffer_set_segment_properties
+hb_buffer_get_segment_properties
+hb_buffer_guess_segment_properties
+hb_buffer_set_unicode_funcs
+hb_buffer_get_unicode_funcs
+hb_buffer_set_user_data
+hb_buffer_get_user_data
 hb_buffer_get_glyph_infos
 hb_buffer_get_glyph_positions
-hb_buffer_get_language
-hb_buffer_get_length
-hb_buffer_get_script
-hb_buffer_get_segment_properties
-hb_buffer_get_unicode_funcs
-hb_buffer_get_user_data
-hb_buffer_guess_segment_properties
+hb_buffer_set_replacement_codepoint
+hb_buffer_get_replacement_codepoint
 hb_buffer_normalize_glyphs
-hb_buffer_pre_allocate
-hb_buffer_reference
-hb_buffer_reset
 hb_buffer_reverse
+hb_buffer_reverse_range
 hb_buffer_reverse_clusters
-hb_buffer_serialize_flags_t
-hb_buffer_serialize_format_from_string
-hb_buffer_serialize_format_t
-hb_buffer_serialize_format_to_string
 hb_buffer_serialize_glyphs
+hb_buffer_deserialize_glyphs
+hb_buffer_serialize_format_from_string
+hb_buffer_serialize_format_to_string
 hb_buffer_serialize_list_formats
-hb_buffer_set_content_type
-hb_buffer_set_direction
-hb_buffer_set_flags
-hb_buffer_set_language
-hb_buffer_set_length
-hb_buffer_set_script
-hb_buffer_set_segment_properties
-hb_buffer_set_unicode_funcs
-hb_buffer_set_user_data
+hb_segment_properties_equal
+hb_segment_properties_hash
+hb_buffer_set_message_func
 hb_buffer_t
 hb_glyph_info_t
 hb_glyph_position_t
-hb_segment_properties_equal
-hb_segment_properties_hash
+hb_buffer_content_type_t
+hb_buffer_flags_t
+hb_buffer_cluster_level_t
 hb_segment_properties_t
+hb_buffer_serialize_format_t
+hb_buffer_serialize_flags_t
+hb_buffer_message_func_t
 </SECTION>
 
 <SECTION>
 <FILE>hb-common</FILE>
-HB_DIRECTION_REVERSE
-HB_LANGUAGE_INVALID
-HB_TAG
-HB_TAG_NONE
-HB_TAG_MAX
-HB_UNTAG
+hb_tag_from_string
+hb_tag_to_string
+hb_direction_from_string
+hb_direction_to_string
+hb_script_from_iso15924_tag
+hb_script_from_string
+hb_script_to_iso15924_tag
+hb_script_get_horizontal_direction
+hb_language_from_string
+hb_language_to_string
+hb_language_get_default
 hb_bool_t
 hb_codepoint_t
 hb_destroy_func_t
-hb_direction_from_string
 hb_direction_t
-hb_direction_to_string
-hb_language_from_string
-hb_language_get_default
 hb_language_t
-hb_language_to_string
 hb_mask_t
 hb_position_t
-hb_script_from_iso15924_tag
-hb_script_from_string
-hb_script_get_horizontal_direction
-hb_script_t
-hb_script_to_iso15924_tag
-hb_tag_from_string
 hb_tag_t
-hb_tag_to_string
+hb_script_t
 hb_user_data_key_t
 hb_var_int_t
+HB_TAG
+HB_TAG_NONE
+HB_TAG_MAX
+HB_TAG_MAX_SIGNED
+HB_UNTAG
+HB_DIRECTION_REVERSE
 HB_DIRECTION_IS_BACKWARD
 HB_DIRECTION_IS_FORWARD
 HB_DIRECTION_IS_HORIZONTAL
 HB_DIRECTION_IS_VALID
 HB_DIRECTION_IS_VERTICAL
+HB_LANGUAGE_INVALID
 <SUBSECTION Private>
 HB_BEGIN_DECLS
 HB_END_DECLS
@@ -239,14 +252,27 @@
 hb_font_subtract_glyph_origin_for_direction
 hb_font_t
 hb_reference_table_func_t
+hb_font_funcs_set_font_h_extents_func
+hb_font_funcs_set_font_v_extents_func
+hb_font_get_extents_for_direction
+hb_font_get_font_extents_func_t
+hb_font_get_font_h_extents_func_t
+hb_font_get_font_v_extents_func_t
+hb_font_get_h_extents
+hb_font_get_v_extents
+hb_font_set_parent
 </SECTION>
 
 <SECTION>
 <FILE>hb-ft</FILE>
 hb_ft_face_create
 hb_ft_face_create_cached
+hb_ft_face_create_referenced
 hb_ft_font_create
+hb_ft_font_create_referenced
 hb_ft_font_get_face
+hb_ft_font_set_load_flags
+hb_ft_font_get_load_flags
 hb_ft_font_set_funcs
 </SECTION>
 
@@ -255,6 +281,7 @@
 hb_glib_get_unicode_funcs
 hb_glib_script_from_script
 hb_glib_script_to_script
+hb_glib_blob_create
 </SECTION>
 
 <SECTION>
@@ -276,6 +303,13 @@
 HB_GOBJECT_TYPE_UNICODE_COMBINING_CLASS
 HB_GOBJECT_TYPE_UNICODE_FUNCS
 HB_GOBJECT_TYPE_UNICODE_GENERAL_CATEGORY
+HB_GOBJECT_TYPE_BUFFER_CLUSTER_LEVEL
+HB_GOBJECT_TYPE_FEATURE
+HB_GOBJECT_TYPE_GLYPH_INFO
+HB_GOBJECT_TYPE_GLYPH_POSITION
+HB_GOBJECT_TYPE_SEGMENT_PROPERTIES
+HB_GOBJECT_TYPE_SET
+HB_GOBJECT_TYPE_USER_DATA_KEY
 hb_gobject_blob_get_type
 hb_gobject_buffer_content_type_get_type
 hb_gobject_buffer_flags_get_type
@@ -293,6 +327,13 @@
 hb_gobject_unicode_combining_class_get_type
 hb_gobject_unicode_funcs_get_type
 hb_gobject_unicode_general_category_get_type
+hb_gobject_buffer_cluster_level_get_type
+hb_gobject_feature_get_type
+hb_gobject_glyph_info_get_type
+hb_gobject_glyph_position_get_type
+hb_gobject_segment_properties_get_type
+hb_gobject_set_get_type
+hb_gobject_user_data_key_get_type
 <SUBSECTION Private>
 HB_GOBJECT_H_IN
 </SECTION>
@@ -340,6 +381,7 @@
 HB_OT_TAG_GDEF
 HB_OT_TAG_GPOS
 HB_OT_TAG_GSUB
+HB_OT_TAG_JSTF
 hb_ot_layout_collect_lookups
 hb_ot_layout_feature_get_lookups
 hb_ot_layout_get_attach_points
@@ -367,6 +409,7 @@
 hb_ot_layout_table_get_script_tags
 hb_ot_layout_table_get_lookup_count
 hb_ot_shape_plan_collect_lookups
+hb_ot_layout_language_get_required_feature_index
 <SUBSECTION Private>
 Xhb_ot_layout_lookup_enumerate_sequences
 Xhb_ot_layout_lookup_position
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
deleted file mode 100644
index f7a4ad6..0000000
--- a/docs/reference/Makefile.am
+++ /dev/null
@@ -1,111 +0,0 @@
-# Process this file with automake to produce Makefile.in
-
-# We require automake 1.6 at least.
-AUTOMAKE_OPTIONS = 1.6
-
-# This is a blank Makefile.am for using gtk-doc.
-# Copy this to your project's API docs directory and modify the variables to
-# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
-# of using the various options.
-
-# The name of the module, e.g. 'glib'.
-DOC_MODULE=harfbuzz
-
-# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
-#DOC_MODULE_VERSION=$(HB_VERSION_MAJOR)
-
-# The top-level SGML file. You can change this if you want to.
-DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
-
-# Directories containing the source code.
-# gtk-doc will search all .c and .h files beneath these paths
-# for inline comments documenting functions and macros.
-# e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk
-DOC_SOURCE_DIR=$(top_srcdir)/src $(top_builddir)/src
-
-# Extra options to pass to gtkdoc-scangobj. Not normally needed.
-SCANGOBJ_OPTIONS=
-
-# Extra options to supply to gtkdoc-scan.
-# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
-SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED"
-
-# Header files or dirs to ignore when scanning. Use base file/dir names
-# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
-IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './hb-*/*.h' | sed 's@^.*/@@'`
-if HAVE_GOBJECT
-else
-IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h
-endif
-
-# Extra options to supply to gtkdoc-mkdb.
-# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
-MKDB_OPTIONS=--source-suffixes=h,cc --xml-mode --output-format=xml --ignore-files="$(IGNORE_HFILES)"
-
-# Extra options to supply to gtkdoc-mktmpl
-# e.g. MKTMPL_OPTIONS=--only-section-tmpl
-MKTMPL_OPTIONS=
-
-# Extra options to supply to gtkdoc-mkhtml
-MKHTML_OPTIONS=
-
-# Extra options to supply to gtkdoc-fixref. Not normally needed.
-# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
-FIXXREF_OPTIONS=
-
-# Used for dependencies. The docs will be rebuilt if any of these change.
-# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
-# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
-HFILE_GLOB=$(top_srcdir)/src/hb.h $(top_srcdir)/src/hb-*.h
-CFILE_GLOB=$(top_srcdir)/src/hb-*.cc
-
-# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
-# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
-EXTRA_HFILES=$(top_builddir)/src/hb-version.h
-
-# Images to copy into HTML directory.
-# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
-HTML_IMAGES=
-
-# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
-# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
-content_files= version.xml
-
-# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
-# These files must be listed here *and* in content_files
-# e.g. expand_content_files=running.sgml
-expand_content_files=
-
-# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
-# Only needed if you are using gtkdoc-scangobj to dynamically query widget
-# signals and properties.
-# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
-# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
-GTKDOC_CFLAGS=
-GTKDOC_LIBS=$(top_builddir)/src/libharfbuzz.la
-if HAVE_GOBJECT
-GTKDOC_LIBS+=$(top_builddir)/src/libharfbuzz-gobject.la
-endif
-
-# This includes the standard gtk-doc make rules, copied by gtkdocize.
-include $(top_srcdir)/gtk-doc.make
-
-# Other files to distribute
-# e.g. EXTRA_DIST += version.xml.in
-EXTRA_DIST += version.xml.in
-
-# Files not to distribute
-# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
-# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
-#DISTCLEANFILES +=
-
-# Comment this out if you want 'make check' to test you doc status
-# and run some sanity checks
-if ENABLE_GTK_DOC
-TESTS_ENVIRONMENT = cd $(srcdir) && \
-  DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
-  SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
-#TESTS = $(GTKDOC_CHECK)
-endif
-
--include $(top_srcdir)/git.mk
diff --git a/docs/reference/harfbuzz-docs.xml b/docs/reference/harfbuzz-docs.xml
deleted file mode 100644
index 2731fab..0000000
--- a/docs/reference/harfbuzz-docs.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
-               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
-  <!ENTITY version SYSTEM "version.xml">
-]>
-<book id="index">
-  <bookinfo>
-    <title>HarfBuzz Reference Manual</title>
-    <releaseinfo>
-      for HarfBuzz &version;.
-      <!--The latest version of this documentation can be found on-line at
-      <ulink role="online-location" url="http://[SERVER]/libharfbuzz/index.html">http://[SERVER]/libharfbuzz/</ulink>.-->
-    </releaseinfo>
-  </bookinfo>
-
-  <chapter>
-    <title>[Insert title here]</title>
-    <xi:include href="xml/hb.xml"/>
-    <xi:include href="xml/hb-common.xml"/>
-    <xi:include href="xml/hb-unicode.xml"/>
-    <xi:include href="xml/hb-buffer.xml"/>
-    <xi:include href="xml/hb-blob.xml"/>
-    <xi:include href="xml/hb-face.xml"/>
-    <xi:include href="xml/hb-font.xml"/>
-    <xi:include href="xml/hb-shape.xml"/>
-
-    <xi:include href="xml/hb-version.xml"/>
-    <xi:include href="xml/hb-deprecated.xml"/>
-
-    <xi:include href="xml/hb-set.xml"/>
-
-    <xi:include href="xml/hb-ot.xml"/>
-    <xi:include href="xml/hb-ot-layout.xml"/>
-    <xi:include href="xml/hb-ot-tag.xml"/>
-
-    <xi:include href="xml/hb-shape-plan.xml"/>
-
-    <xi:include href="xml/hb-glib.xml"/>
-    <xi:include href="xml/hb-icu.xml"/>
-
-    <xi:include href="xml/hb-ft.xml"/>
-
-    <xi:include href="xml/hb-graphite2.xml"/>
-    <xi:include href="xml/hb-uniscribe.xml"/>
-    <xi:include href="xml/hb-coretext.xml"/>
-
-    <xi:include href="xml/hb-gobject.xml"/>
-
-  </chapter>
-  <chapter id="object-tree">
-    <title>Object Hierarchy</title>
-     <xi:include href="xml/tree_index.sgml"/>
-  </chapter>
-  <index id="api-index-full">
-    <title>API Index</title>
-    <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
-  </index>
-  <index id="deprecated-api-index" role="deprecated">
-    <title>Index of deprecated API</title>
-    <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
-  </index>
-
-  <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
-</book>
diff --git a/docs/usermanual-buffers-language-script-and-direction.xml b/docs/usermanual-buffers-language-script-and-direction.xml
new file mode 100644
index 0000000..3a26c55
--- /dev/null
+++ b/docs/usermanual-buffers-language-script-and-direction.xml
@@ -0,0 +1,77 @@
+<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
+    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.
+  </para>
+  <section id="creating-and-destroying-buffers">
+    <title>Creating and destroying buffers</title>
+    <para>
+      As we saw in our initial example, a buffer is created and
+      initialized with <literal>hb_buffer_create()</literal>. This
+      produces a new, empty buffer object, instantiated with some
+      default values and ready to accept your Unicode strings.
+    </para>
+    <para>
+      Harfbuzz manages the memory of objects that it creates (such as
+      buffers), so you don't have to. When you have finished working on
+      a buffer, you can call <literal>hb_buffer_destroy()</literal>:
+    </para>
+    <programlisting language="C">
+  hb_buffer_t *buffer = hb_buffer_create();
+  ...
+  hb_buffer_destroy(buffer);
+</programlisting>
+    <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
+      and want to ensure that it is not garbage collected by someone
+      else destroying it, you should increase its reference count:
+    </para>
+    <programlisting language="C">
+void somefunc(hb_buffer_t *buffer) {
+  buffer = hb_buffer_reference(buffer);
+  ...
+</programlisting>
+    <para>
+      And then decrease it once you're done with it:
+    </para>
+    <programlisting language="C">
+  hb_buffer_destroy(buffer);
+}
+</programlisting>
+    <para>
+      To throw away all the data in your buffer and start from scratch,
+      call <literal>hb_buffer_reset(buffer)</literal>. If you want to
+      throw away the string in the buffer but keep the options, you can
+      instead call <literal>hb_buffer_clear_contents(buffer)</literal>.
+    </para>
+  </section>
+  <section id="adding-text-to-the-buffer">
+    <title>Adding text to the buffer</title>
+    <para>
+      Now we have a brand new Harfbuzz buffer. Let's start filling it
+      with text! From Harfbuzz's perspective, a buffer is just a stream
+      of Unicode codepoints, but your input string is probably in one of
+      the standard Unicode character encodings (UTF-8, UTF-16, UTF-32)
+    </para>
+  </section>
+  <section id="setting-buffer-properties">
+    <title>Setting buffer properties</title>
+    <para>
+    </para>
+  </section>
+  <section id="what-about-the-other-scripts">
+    <title>What about the other scripts?</title>
+    <para>
+    </para>
+  </section>
+  <section id="customizing-unicode-functions">
+    <title>Customizing Unicode functions</title>
+    <para>
+    </para>
+  </section>
+</chapter>
\ No newline at end of file
diff --git a/docs/usermanual-clusters.xml b/docs/usermanual-clusters.xml
new file mode 100644
index 0000000..8b64bde
--- /dev/null
+++ b/docs/usermanual-clusters.xml
@@ -0,0 +1,304 @@
+<chapter id="clusters">
+<sect1 id="clusters">
+  <title>Clusters</title>
+  <para>
+    In shaping text, a <emphasis>cluster</emphasis> is a sequence of
+    code points that needs to be treated as a single, indivisible unit.
+  </para>
+  <para>
+    When you add text to a HB buffer, each character is associated with
+    a <emphasis>cluster value</emphasis>. This is an arbitrary number as
+    far as HB is concerned.
+  </para>
+  <para>
+    Most clients will use UTF-8, UTF-16, or UTF-32 indices, but the
+    actual number does not matter. Moreover, it is not required for the
+    cluster values to be monotonically increasing, but pretty much all
+    of HB's tests are performed on monotonically increasing cluster
+    numbers. Nevertheless, there is no such assumption in the code
+    itself. With that in mind, let's examine what happens with cluster
+    values during shaping under each cluster-level.
+  </para>
+  <para>
+    HarfBuzz provides three <emphasis>levels</emphasis> of clustering
+    support. Level 0 is the default behavior and reproduces the behavior
+    of the old HarfBuzz library. Level 1 tweaks this behavior slightly
+    to produce better results, so level 1 clustering is recommended for
+    code that is not required to implement backward compatibility with
+    the old HarfBuzz.
+  </para>
+  <para>
+    Level 2 differs significantly in how it treats cluster values.
+    Levels 0 and 1 both process ligatures and glyph decomposition by
+    merging clusters; level 2 does not.
+  </para>
+  <para>
+    The conceptual model for what the cluster values mean, in levels 0
+    and 1, is this:
+  </para>
+  <itemizedlist spacing="compact">
+    <listitem>
+      <para>
+        the sequence of cluster values will always remain monotone
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+        each value represents a single cluster
+      </para>
+    </listitem>
+    <listitem>
+      <para>
+        each cluster contains one or more glyphs and one or more
+        characters
+      </para>
+    </listitem>
+  </itemizedlist>
+  <para>
+    Assuming that initial cluster numbers were monotonically increasing
+    and distinct, then all adjacent glyphs having the same cluster
+    number belong to the same cluster, and all characters belong to the
+    cluster that has the highest number not larger than their initial
+    cluster number. This will become clearer with an example.
+  </para>
+</sect1>
+<sect1 id="a-clustering-example-for-levels-0-and-1">
+  <title>A clustering example for levels 0 and 1</title>
+  <para>
+    Let's say we start with the following character sequence and cluster
+    values:
+  </para>
+  <programlisting>
+   A,B,C,D,E
+   0,1,2,3,4
+</programlisting>
+  <para>
+    We then map the characters to glyphs. For simplicity, let's assume
+    that each character maps to the corresponding, identical-looking
+    glyph:
+  </para>
+  <programlisting>
+   A,B,C,D,E
+   0,1,2,3,4
+</programlisting>
+  <para>
+    Now if, for example, <literal>B</literal> and <literal>C</literal>
+    ligate, then the clusters to which they belong &quot;merge&quot;.
+    This merged cluster takes for its cluster number the minimum of all
+    the cluster numbers of the clusters that went in. In this case, we
+    get:
+  </para>
+  <programlisting>
+   A,BC,D,E
+   0,1 ,3,4
+</programlisting>
+  <para>
+    Now let's assume that the <literal>BC</literal> glyph decomposes
+    into three components, and <literal>D</literal> also decomposes into
+    two. The components each inherit the cluster value of their parent:
+  </para>
+  <programlisting>
+   A,BC0,BC1,BC2,D0,D1,E
+   0,1  ,1  ,1  ,3 ,3 ,4
+</programlisting>
+  <para>
+    Now if <literal>BC2</literal> and <literal>D0</literal> ligate, then
+    their clusters (numbers 1 and 3) merge into
+    <literal>min(1,3) = 1</literal>:
+  </para>
+  <programlisting>
+   A,BC0,BC1,BC2D0,D1,E
+   0,1  ,1  ,1    ,1 ,4
+</programlisting>
+  <para>
+    At this point, cluster 1 means: the character sequence
+    <literal>BCD</literal> is represented by glyphs
+    <literal>BC0,BC1,BC2D0,D1</literal> and cannot be broken down any
+    further.
+  </para>
+</sect1>
+<sect1 id="reordering-in-levels-0-and-1">
+  <title>Reordering in levels 0 and 1</title>
+  <para>
+    Another common operation in the more complex shapers is when things
+    reorder. In those cases, to maintain monotone clusters, HB merges
+    the clusters of everything in the reordering sequence. For example,
+    let's again start with the character sequence:
+  </para>
+  <programlisting>
+   A,B,C,D,E
+   0,1,2,3,4
+</programlisting>
+  <para>
+    If <literal>D</literal> is reordered before <literal>B</literal>,
+    then the <literal>B</literal>, <literal>C</literal>, and
+    <literal>D</literal> clusters merge, and we get:
+  </para>
+  <programlisting>
+   A,D,B,C,E
+   0,1,1,1,4
+</programlisting>
+  <para>
+    This is clearly not ideal, but it is the only sensible way to
+    maintain monotone indices and retain the true relationship between
+    glyphs and characters.
+  </para>
+</sect1>
+<sect1 id="the-distinction-between-levels-0-and-1">
+  <title>The distinction between levels 0 and 1</title>
+  <para>
+    So, the above is pretty much what cluster levels 0 and 1 do. The
+    only difference between the two is this: in level 0, at the very
+    beginning of the shaping process, we also merge clusters between
+    base characters and all Unicode marks (combining or not) following
+    them. E.g.:
+  </para>
+  <programlisting>
+  A,acute,B
+  0,1    ,2
+</programlisting>
+  <para>
+    will become:
+  </para>
+  <programlisting>
+  A,acute,B
+  0,0    ,2
+</programlisting>
+  <para>
+    This is the default behavior. We do it because Windows did it and
+    old HarfBuzz did it, so this remained the default. But this behavior
+    makes it impossible to color diacritic marks differently from their
+    base characters. That's why in level 1 we do not perform this
+    initial merging step.
+  </para>
+  <para>
+    For clients, level 0 is more convenient if they rely on HarfBuzz
+    clusters for cursor positioning. But that's wrong anyway: cursor
+    positions should be determined based on Unicode grapheme boundaries,
+    NOT shaping clusters. As such, level 1 clusters are preferred.
+  </para>
+  <para>
+    One last note about levels 0 and 1. We currently don't allow a
+    <literal>MultipleSubst</literal> lookup to replace a glyph with zero
+    glyphs (i.e., to delete a glyph). But in some other situations,
+    glyphs can be deleted. In those cases, if the glyph being deleted is
+    the last glyph of its cluster, we make sure to merge the cluster
+    with a neighboring cluster.
+  </para>
+  <para>
+    This is, primarily, to make sure that the starting cluster of the
+    text always has the cluster index pointing to the start of the text
+    for the run; more than one client currently relies on this
+    guarantee.
+  </para>
+  <para>
+    Incidentally, Apple's CoreText does something else to maintain the
+    same promise: it inserts a glyph with id 65535 at the beginning of
+    the glyph string if the glyph corresponding to the first character
+    in the run was deleted. HarfBuzz might do something similar in the
+    future.
+  </para>
+</sect1>
+<sect1 id="level-2">
+  <title>Level 2</title>
+  <para>
+    Level 2 is a different beast from levels 0 and 1. It is simple to
+    describe, but hard to make sense of. It simply doesn't do any
+    cluster merging whatsoever. When things ligate or otherwise multiple
+    glyphs turn into one, the cluster value of the first glyph is
+    retained.
+  </para>
+  <para>
+    Here are a few examples of why processing cluster values produced at
+    this level might be tricky:
+  </para>
+  <sect2 id="ligatures-with-combining-marks">
+    <title>Ligatures with combining marks</title>
+    <para>
+      Imagine capital letters are bases and lower case letters are
+      combining marks. With an input sequence like this:
+    </para>
+    <programlisting>
+  A,a,B,b,C,c
+  0,1,2,3,4,5
+</programlisting>
+    <para>
+      if <literal>A,B,C</literal> ligate, then here are the cluster
+      values one would get under the various levels:
+    </para>
+    <para>
+      level 0:
+    </para>
+    <programlisting>
+  ABC,a,b,c
+  0  ,0,0,0
+</programlisting>
+    <para>
+      level 1:
+    </para>
+    <programlisting>
+  ABC,a,b,c
+  0  ,0,0,5
+</programlisting>
+    <para>
+      level 2:
+    </para>
+    <programlisting>
+  ABC,a,b,c
+  0  ,1,3,5
+</programlisting>
+    <para>
+      Making sense of the last example is the hardest for a client,
+      because there is nothing in the cluster values to suggest that
+      <literal>B</literal> and <literal>C</literal> ligated with
+      <literal>A</literal>.
+    </para>
+  </sect2>
+  <sect2 id="reordering">
+    <title>Reordering</title>
+    <para>
+      Another tricky case is when things reorder. Under level 2:
+    </para>
+    <programlisting>
+  A,B,C,D,E
+  0,1,2,3,4
+</programlisting>
+    <para>
+      Now imagine <literal>D</literal> moves before
+      <literal>B</literal>:
+    </para>
+    <programlisting>
+  A,D,B,C,E
+  0,3,1,2,4
+</programlisting>
+    <para>
+      Now, if <literal>D</literal> ligates with <literal>B</literal>, we
+      get:
+    </para>
+    <programlisting>
+  A,DB,C,E
+  0,3 ,2,4
+</programlisting>
+    <para>
+      In a different scenario, <literal>A</literal> and
+      <literal>B</literal> could have ligated
+      <emphasis>before</emphasis> <literal>D</literal> reordered; that
+      would have resulted in:
+    </para>
+    <programlisting>
+  AB,D,C,E
+  0 ,3,2,4   
+</programlisting>
+    <para>
+      There's no way to differentitate between these two scenarios based
+      on the cluster numbers alone.
+    </para>
+    <para>
+      Another problem appens with ligatures under level 2 if the
+      direction of the text is forced to opposite of its natural
+      direction (e.g. left-to-right Arabic). But that's too much of a
+      corner case to worry about.
+    </para>
+  </sect2>
+</sect1>
+</chapter>
diff --git a/docs/usermanual-fonts-and-faces.xml b/docs/usermanual-fonts-and-faces.xml
new file mode 100644
index 0000000..01fcdc9
--- /dev/null
+++ b/docs/usermanual-fonts-and-faces.xml
@@ -0,0 +1,18 @@
+<chapter id="fonts-and-faces">
+  <title>Fonts and faces</title>
+  <section id="using-freetype">
+    <title>Using FreeType</title>
+    <para>
+    </para>
+  </section>
+  <section id="using-harfbuzzs-native-opentype-implementation">
+    <title>Using Harfbuzz's native OpenType implementation</title>
+    <para>
+    </para>
+  </section>
+  <section id="using-your-own-font-functions">
+    <title>Using your own font functions</title>
+    <para>
+    </para>
+  </section>
+</chapter>
\ No newline at end of file
diff --git a/docs/usermanual-glyph-information.xml b/docs/usermanual-glyph-information.xml
new file mode 100644
index 0000000..ca674c0
--- /dev/null
+++ b/docs/usermanual-glyph-information.xml
@@ -0,0 +1,8 @@
+<sect1 id="glyph-information">
+  <title>Glyph information</title>
+  <sect2 id="names-and-numbers">
+    <title>Names and numbers</title>
+    <para>
+    </para>
+  </sect2>
+</sect1>
\ No newline at end of file
diff --git a/docs/usermanual-hello-harfbuzz.xml b/docs/usermanual-hello-harfbuzz.xml
new file mode 100644
index 0000000..34db017
--- /dev/null
+++ b/docs/usermanual-hello-harfbuzz.xml
@@ -0,0 +1,183 @@
+<chapter id="hello-harfbuzz">
+  <title>Hello, Harfbuzz</title>
+  <para>
+    Here's the simplest Harfbuzz that can possibly work. We will improve
+    it later.
+  </para>
+  <orderedlist numeration="arabic">
+    <listitem>
+      <para>
+        Create a buffer and put your text in it.
+      </para>
+    </listitem>
+  </orderedlist>
+  <programlisting language="C">
+  #include &lt;hb.h&gt;
+  hb_buffer_t *buf;
+  buf = hb_buffer_create();
+  hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
+</programlisting>
+  <orderedlist numeration="arabic">
+    <listitem override="2">
+      <para>
+        Guess the script, language and direction of the buffer.
+      </para>
+    </listitem>
+  </orderedlist>
+  <programlisting language="C">
+  hb_buffer_guess_segment_properties(buf);
+</programlisting>
+  <orderedlist numeration="arabic">
+    <listitem override="3">
+      <para>
+        Create a face and a font, using FreeType for now.
+      </para>
+    </listitem>
+  </orderedlist>
+  <programlisting language="C">
+  #include &lt;hb-ft.h&gt;
+  FT_New_Face(ft_library, font_path, index, &amp;face)
+  hb_font_t *font = hb_ft_font_create(face);
+</programlisting>
+  <orderedlist numeration="arabic">
+    <listitem override="4">
+      <para>
+        Shape!
+      </para>
+    </listitem>
+  </orderedlist>
+  <programlisting>
+  hb_shape(font, buf, NULL, 0);
+</programlisting>
+  <orderedlist numeration="arabic">
+    <listitem override="5">
+      <para>
+        Get the glyph and position information.
+      </para>
+    </listitem>
+  </orderedlist>
+  <programlisting language="C">
+  hb_glyph_info_t *glyph_info    = hb_buffer_get_glyph_infos(buf, &amp;glyph_count);
+  hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
+</programlisting>
+  <orderedlist numeration="arabic">
+    <listitem override="6">
+      <para>
+        Iterate over each glyph.
+      </para>
+    </listitem>
+  </orderedlist>
+  <programlisting language="C">
+  for (i = 0; i &lt; glyph_count; ++i) {
+    glyphid = glyph_info[i].codepoint;
+    x_offset = glyph_pos[i].x_offset / 64.0;
+    y_offset = glyph_pos[i].y_offset / 64.0;
+    x_advance = glyph_pos[i].x_advance / 64.0;
+    y_advance = glyph_pos[i].y_advance / 64.0;
+    draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
+    cursor_x += x_advance;
+    cursor_y += y_advance;
+  }
+</programlisting>
+  <orderedlist numeration="arabic">
+    <listitem override="7">
+      <para>
+        Tidy up.
+      </para>
+    </listitem>
+  </orderedlist>
+  <programlisting language="C">
+  hb_buffer_destroy(buf);
+  hb_font_destroy(hb_ft_font);
+</programlisting>
+  <section id="what-harfbuzz-doesnt-do">
+    <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.
+    </para>
+    <para>
+      If you are implementing a text layout engine you may have other
+      responsibilities, that Harfbuzz will not help you with:
+    </para>
+    <itemizedlist>
+      <listitem>
+        <para>
+          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
+          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
+          sequence:
+        </para>
+        <programlisting>
+A B C [space] ג ב א [space] D E F
+        </programlisting>
+        <para>
+          but will expect to see in the output:
+        </para>
+        <programlisting>
+ABC אבג DEF
+        </programlisting>
+        <para>
+          This reordering is called <emphasis>bidi processing</emphasis>
+          (&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
+          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
+          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;
+          <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
+          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
+          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
+          word, sentence and line break points are in your text, you
+          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
+          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
+          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.
+        </para>
+      </listitem>
+    </itemizedlist>
+    <para>
+      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
+      capabilities.
+    </para>
+  </section>
+</chapter>
\ No newline at end of file
diff --git a/docs/usermanual-install-harfbuzz.xml b/docs/usermanual-install-harfbuzz.xml
new file mode 100644
index 0000000..be8ac8d
--- /dev/null
+++ b/docs/usermanual-install-harfbuzz.xml
@@ -0,0 +1,70 @@
+<chapter id="install-harfbuzz">
+  <title>Install Harfbuzz</title>
+  <section id="download">
+    <title id="download.title">Download</title>
+    <para>
+      For tarball releases of HarfBuzz, look
+      <ulink url="http://www.freedesktop.org/software/harfbuzz/release/">here</ulink>.
+      At the same place you will
+      also find Win32 binary bundles that include libharfbuzz DLL, hb-view.exe,
+      hb-shape.exe, and all dependencies.
+    </para>
+    <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>.
+    </para>
+    <para>
+      The API that comes with <filename class='headerfile'>hb.h</filename> will
+      not change incompatibly. Other, peripheral, headers are more likely to go
+      through minor modifications, but again, will do our best to never change
+      API in an incompatible way. We will never break the ABI.
+    </para>
+    <para>
+      If you are not sure whether Pango or HarfBuzz is right for you, read
+      <ulink url="http://mces.blogspot.in/2009/11/pango-vs-harfbuzz.html">this</ulink>.
+    </para>
+  </section>
+  <section id="building">
+    <title>Building</title>
+    <para>
+      On Linux, install the development packages for FreeType, Cairo, and GLib.
+      For example, on Ubuntu / Debian, you would do:
+      <programlisting>
+<command>sudo apt-get install</command> <package>gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev</package>
+      </programlisting>
+      whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
+      <programlisting>
+<command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package>
+      </programlisting>
+      or using MacPorts:
+      <programlisting>
+<command>sudo port install</command> <package>freetype glib2 cairo</package>
+      </programlisting>
+    </para>
+    <para>
+      If you are using a tarball, you can now proceed to running
+      <command>configure</command> and <command>make</command> as with any
+      other standard package. That should leave you with a shared library in
+      <filename>src/</filename>, and a few utility programs including hb-view
+      and hb-shape under <filename>util/</filename>.
+    </para>
+    <para>
+      If you are bootstraping from git, you need a few more tools before you
+      can run <filename>autogen.sh</filename> for the first time. Namely,
+      pkg-config and <ulink url="http://www.complang.org/ragel/">ragel</ulink>.
+      Again, on Ubuntu / Debian:
+      <programlisting>
+<command>sudo apt-get install</command> <package>autoconf automake libtool pkg-config ragel gtk-doc-tools</package>
+      </programlisting>
+      and on Fedora, RHEL, CentOS:
+      <programlisting>
+<command>sudo yum install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
+      </programlisting>
+      or using MacPorts:
+      <programlisting>
+<command>sudo port install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
+      </programlisting>
+    </para>
+  </section>
+</chapter>
diff --git a/docs/usermanual-opentype-features.xml b/docs/usermanual-opentype-features.xml
new file mode 100644
index 0000000..470bab8
--- /dev/null
+++ b/docs/usermanual-opentype-features.xml
@@ -0,0 +1,13 @@
+<chapter id="shaping-and-shape-plans">
+  <title>Shaping and shape plans</title>
+  <section id="opentype-features">
+    <title>OpenType features</title>
+    <para>
+    </para>
+  </section>
+  <section id="plans-and-caching">
+    <title>Plans and caching</title>
+    <para>
+    </para>
+  </section>
+</chapter>
\ No newline at end of file
diff --git a/docs/usermanual-what-is-harfbuzz.xml b/docs/usermanual-what-is-harfbuzz.xml
new file mode 100644
index 0000000..3574d75
--- /dev/null
+++ b/docs/usermanual-what-is-harfbuzz.xml
@@ -0,0 +1,115 @@
+<chapter id="what-is-harfbuzz">
+  <title>What is Harfbuzz?</title>
+  <para>
+    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>
+  <section id="why-do-i-need-it">
+    <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
+      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
+      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
+      reasons why you need it:
+    </para>
+    <itemizedlist>
+      <listitem>
+        <para>
+          OpenType fonts contain a set of glyphs, indexed by glyph ID.
+          The glyph ID within the font does not necessarily relate to a
+          Unicode codepoint. For instance, some fonts have the letter
+          &quot;a&quot; as glyph ID 1. To pull the right glyph out of
+          the font in order to display it, you need to consult a table
+          within the font (the &quot;cmap&quot; table) which maps
+          Unicode codepoints to glyph IDs. Text shaping turns codepoints
+          into glyph IDs.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Many OpenType fonts contain ligatures: combinations of
+          characters which are rendered together. For instance, it's
+          common for the <literal>fi</literal> combination to appear in
+          print as the single ligature &quot;fi&quot;. Whether you should
+          render text as <literal>fi</literal> or &quot;fi&quot; does not
+          depend on the input text, but on the capabilities of the font
+          and the level of ligature application you wish to perform.
+          Text shaping involves querying the font's ligature tables and
+          determining what substitutions should be made.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          While ligatures like &quot;fi&quot; are typographic
+          refinements, some languages <emphasis>require</emphasis> such
+          substitutions to be made in order to display text correctly.
+          In Tamil, when the letter &quot;TTA&quot; (ட) letter is
+          followed by &quot;U&quot; (உ), the combination should appear
+          as the single glyph &quot;டு&quot;. The sequence of Unicode
+          characters &quot;டஉ&quot; needs to be rendered as a single
+          glyph from the font - text shaping chooses the correct glyph
+          from the sequence of characters provided.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Similarly, each Arabic character has four different variants:
+          within a font, there will be glyphs for the initial, medial,
+          final, and isolated forms of each letter. Unicode only encodes
+          one codepoint per character, and so a Unicode string will not
+          tell you which glyph to use. Text shaping chooses the correct
+          form of the letter and returns the correct glyph from the font
+          that you need to render.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Other languages have marks and accents which need to be
+          rendered in certain positions around a base character. For
+          instance, the Moldovan language has the Cyrillic letter
+          &quot;zhe&quot; (ж) with a breve accent, like so: ӂ. Some
+          fonts will contain this character as an individual glyph,
+          whereas other fonts will not contain a zhe-with-breve glyph
+          but expect the rendering engine to form the character by
+          overlaying the two glyphs ж and ˘. Where you should draw the
+          combining breve depends on the height of the preceding glyph.
+          Again, for Arabic, the correct positioning of vowel marks
+          depends on the height of the character on which you are
+          placing the mark. Text shaping tells you whether you have a
+          precomposed glyph within your font or if you need to compose a
+          glyph yourself out of combining marks, and if so, where to
+          position those marks.
+        </para>
+      </listitem>
+    </itemizedlist>
+    <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
+      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>
+    <para>
+      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
+      for &quot;open type&quot;.
+    </para>
+  </section>
+</chapter>
\ No newline at end of file
diff --git a/docs/reference/version.xml.in b/docs/version.xml.in
similarity index 100%
rename from docs/reference/version.xml.in
rename to docs/version.xml.in
diff --git a/git.mk b/git.mk
index 18c07f6..bd39ae1 100644
--- a/git.mk
+++ b/git.mk
@@ -1,4 +1,5 @@
-# git.mk
+# git.mk, a small Makefile to autogenerate .gitignore files
+# for autotools-based projects.
 #
 # Copyright 2009, Red Hat, Inc.
 # Copyright 2010,2011,2012,2013 Behdad Esfahbod
@@ -9,7 +10,8 @@
 # notice and this notice are preserved.
 #
 # The latest version of this file can be downloaded from:
-#   https://raw.github.com/behdad/git.mk/master/git.mk
+GIT_MK_URL = https://raw.githubusercontent.com/behdad/git.mk/master/git.mk
+#
 # Bugs, etc, should be reported upstream at:
 #   https://github.com/behdad/git.mk
 #
@@ -45,7 +47,8 @@
 # build dir.
 #
 # This file knows how to handle autoconf, automake, libtool, gtk-doc,
-# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu.
+# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu, appdata,
+# appstream.
 #
 # This makefile provides the following targets:
 #
@@ -90,6 +93,7 @@
 		missing \
 		mkinstalldirs \
 		test-driver \
+		ylwrap \
 	 ; do echo "$$AUX_DIR/$$x"; done` \
 	`cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_HEADERS:$$1' ./configure.ac | \
 	head -n 1 | while read f; do echo "$(srcdir)/$$f.in"; done`
@@ -147,7 +151,10 @@
 			fi; \
 	fi; done; test -z "$$any_failed"
 
-.PHONY: git-all git-mk-install
+git-mk-update:
+	wget $(GIT_MK_URL) -O $(top_srcdir)/git.mk
+
+.PHONY: git-all git-mk-install git-mk-update
 
 
 
@@ -164,10 +171,24 @@
 				$(DOC_MODULE)-decl.txt \
 				tmpl/$(DOC_MODULE)-unused.sgml \
 				"tmpl/*.bak" \
+				$(REPORT_FILES) \
+				$(DOC_MODULE).pdf \
 				xml html \
 			; do echo "/$$x"; done; \
 			FLAVOR=$$(cd $(top_srcdir); $(AUTOCONF) --trace 'GTK_DOC_CHECK:$$2' ./configure.ac); \
 			case $$FLAVOR in *no-tmpl*) echo /tmpl;; esac; \
+			if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-types"; then \
+				echo "/$(DOC_MODULE).types"; \
+			fi; \
+			if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-sections"; then \
+				echo "/$(DOC_MODULE)-sections.txt"; \
+			fi; \
+			if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
+				for x in \
+					$(SETUP_FILES) \
+					$(DOC_MODULE).types \
+				; do echo "/$$x"; done; \
+			fi; \
 		fi; \
 		if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
 			for lc in $(DOC_LINGUAS); do \
@@ -202,6 +223,16 @@
 				$(gsettings__enum_file) \
 			; do echo "/$$x"; done; \
 		fi; \
+		if test "x$(appdata_XML)" = x; then :; else \
+			for x in \
+				$(appdata_XML:.xml=.valid) \
+			; do echo "/$$x"; done; \
+		fi; \
+		if test "x$(appstream_XML)" = x; then :; else \
+			for x in \
+				$(appstream_XML:.xml=.valid) \
+			; do echo "/$$x"; done; \
+		fi; \
 		if test -f $(srcdir)/po/Makefile.in.in; then \
 			for x in \
 				po/Makefile.in.in \
@@ -243,7 +274,7 @@
 		if test "x$(am__dirstamp)" = x; then :; else \
 			echo "$(am__dirstamp)"; \
 		fi; \
-		if test "x$(LTCOMPILE)" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
+		if test "x$(LTCOMPILE)" = x -a "x$(LTCXXCOMPILE)" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
 			for x in \
 				"*.lo" \
 				".libs" "_libs" \
@@ -261,7 +292,9 @@
 			$(TEST_LOGS) \
 			$(TEST_LOGS:.log=.trs) \
 			$(TEST_SUITE_LOG) \
-			"*.$(OBJEXT)" \
+			$(TESTS:=.test) \
+			"*.gcda" \
+			"*.gcno" \
 			$(DISTCLEANFILES) \
 			$(am__CONFIG_DISTCLEAN_FILES) \
 			$(CONFIG_CLEAN_FILES) \
@@ -269,11 +302,10 @@
 			"*.tab.c" \
 			$(MAINTAINERCLEANFILES) \
 			$(BUILT_SOURCES) \
-			$(DEPDIR) \
 			$(patsubst %.vala,%.c,$(filter %.vala,$(SOURCES))) \
 			$(filter %_vala.stamp,$(DIST_COMMON)) \
 			$(filter %.vapi,$(DIST_COMMON)) \
-			$(filter %$(patsubst %.vapi,%.h,$(filter %.vapi,$(DIST_COMMON))),$(DIST_COMMON)) \
+			$(filter $(addprefix %,$(notdir $(patsubst %.vapi,%.h,$(filter %.vapi,$(DIST_COMMON))))),$(DIST_COMMON)) \
 			Makefile \
 			Makefile.in \
 			"*.orig" \
@@ -283,6 +315,10 @@
 			".*.sw[nop]" \
 			".dirstamp" \
 		; do echo "/$$x"; done; \
+		for x in \
+			"*.$(OBJEXT)" \
+			$(DEPDIR) \
+		; do echo "$$x"; done; \
 	} | \
 	sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
 	sed 's@/[.]/@/@g' | \
diff --git a/src/Makefile.am b/src/Makefile.am
index c99967f..bb085ad 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,5 @@
 # Process this file with automake to produce Makefile.in
 
-NULL =
 SUBDIRS =
 DIST_SUBDIRS =
 BUILT_SOURCES =
@@ -14,171 +13,98 @@
 #AM_CXXFLAGS =
 
 # Convenience targets:
-lib: libharfbuzz.la
+lib: $(BUILT_SOURCES) libharfbuzz.la
+fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la
 
 lib_LTLIBRARIES = libharfbuzz.la
 
+include Makefile.sources
+
 HBCFLAGS =
 HBLIBS =
-HBSOURCES =  \
-	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-face-private.hh \
-	hb-face.cc \
-	hb-font-private.hh \
-	hb-font.cc \
-	hb-mutex-private.hh \
-	hb-object-private.hh \
-	hb-open-file-private.hh \
-	hb-open-type-private.hh \
-	hb-ot-cmap-table.hh \
-	hb-ot-head-table.hh \
-	hb-ot-hhea-table.hh \
-	hb-ot-hmtx-table.hh \
-	hb-ot-maxp-table.hh \
-	hb-ot-name-table.hh \
-	hb-ot-tag.cc \
-	hb-private.hh \
-	hb-set-private.hh \
-	hb-set.cc \
-	hb-shape.cc \
-	hb-shape-plan-private.hh \
-	hb-shape-plan.cc \
-	hb-shaper-list.hh \
-	hb-shaper-impl-private.hh \
-	hb-shaper-private.hh \
-	hb-shaper.cc \
-	hb-unicode-private.hh \
-	hb-unicode.cc \
-	hb-utf-private.hh \
-	hb-warning.cc \
-	$(NULL)
-HBHEADERS = \
-	hb.h \
-	hb-blob.h \
-	hb-buffer.h \
-	hb-common.h \
-	hb-deprecated.h \
-	hb-face.h \
-	hb-font.h \
-	hb-set.h \
-	hb-shape.h \
-	hb-shape-plan.h \
-	hb-unicode.h \
-	$(NULL)
-HBNODISTHEADERS = \
-	hb-version.h \
-	$(NULL)
+HBNONPCLIBS =
+HBDEPS =
+HBSOURCES =  $(HB_BASE_sources)
+HBHEADERS = $(HB_BASE_headers)
+HBNODISTHEADERS = $(HB_NODIST_headers)
 
 if HAVE_OT
-HBSOURCES += \
-	hb-ot-font.cc \
-	hb-ot-layout.cc \
-	hb-ot-layout-common-private.hh \
-	hb-ot-layout-gdef-table.hh \
-	hb-ot-layout-gpos-table.hh \
-	hb-ot-layout-gsubgpos-private.hh \
-	hb-ot-layout-gsub-table.hh \
-	hb-ot-layout-jstf-table.hh \
-	hb-ot-layout-private.hh \
-	hb-ot-map.cc \
-	hb-ot-map-private.hh \
-	hb-ot-shape.cc \
-	hb-ot-shape-complex-arabic.cc \
-	hb-ot-shape-complex-arabic-fallback.hh \
-	hb-ot-shape-complex-arabic-table.hh \
-	hb-ot-shape-complex-arabic-win1256.hh \
-	hb-ot-shape-complex-default.cc \
-	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-sea.cc \
-	hb-ot-shape-complex-sea-machine.hh \
-	hb-ot-shape-complex-thai.cc \
-	hb-ot-shape-complex-tibetan.cc \
-	hb-ot-shape-complex-private.hh \
-	hb-ot-shape-normalize-private.hh \
-	hb-ot-shape-normalize.cc \
-	hb-ot-shape-fallback-private.hh \
-	hb-ot-shape-fallback.cc \
-	hb-ot-shape-private.hh \
-	$(NULL)
-HBHEADERS += \
-	hb-ot.h \
-	hb-ot-font.h \
-	hb-ot-layout.h \
-	hb-ot-shape.h \
-	hb-ot-tag.h \
-	$(NULL)
+HBSOURCES += $(HB_OT_sources)
+HBHEADERS += $(HB_OT_headers)
 endif
 
 if HAVE_FALLBACK
-HBSOURCES += hb-fallback-shape.cc
+HBSOURCES += $(HB_FALLBACK_sources)
 endif
 
 if HAVE_PTHREAD
 HBCFLAGS += $(PTHREAD_CFLAGS)
-HBLIBS   += $(PTHREAD_LIBS)
+HBNONPCLIBS += $(PTHREAD_LIBS)
 endif
 
 if HAVE_GLIB
 HBCFLAGS += $(GLIB_CFLAGS)
 HBLIBS   += $(GLIB_LIBS)
-HBSOURCES += hb-glib.cc
-HBHEADERS += hb-glib.h
+HBDEPS   += $(GLIB_DEPS)
+HBSOURCES += $(HB_GLIB_sources)
+HBHEADERS += $(HB_GLIB_headers)
 endif
 
 if HAVE_FREETYPE
 HBCFLAGS += $(FREETYPE_CFLAGS)
 HBLIBS   += $(FREETYPE_LIBS)
-HBSOURCES += hb-ft.cc
-HBHEADERS += hb-ft.h
+# XXX
+# The following creates a recursive dependency on FreeType if FreeType is
+# built with HarfBuzz support enabled.  Newer pkg-config handles that just
+# fine but pkg-config 0.26 as shipped in Ubuntu 14.04 crashes.  Remove
+# in a year or two, or otherwise work around it...
+#HBDEPS   += $(FREETYPE_DEPS)
+HBSOURCES += $(HB_FT_sources)
+HBHEADERS += $(HB_FT_headers)
 endif
 
 if HAVE_GRAPHITE2
 HBCFLAGS += $(GRAPHITE2_CFLAGS)
 HBLIBS   += $(GRAPHITE2_LIBS)
-HBSOURCES += hb-graphite2.cc
-HBHEADERS += hb-graphite2.h
+HBDEPS   += $(GRAPHITE2_DEPS)
+HBSOURCES += $(HB_GRAPHITE2_sources)
+HBHEADERS += $(HB_GRAPHITE2_headers)
 endif
 
 if HAVE_UNISCRIBE
 HBCFLAGS += $(UNISCRIBE_CFLAGS)
-HBLIBS   += $(UNISCRIBE_LIBS)
-HBSOURCES += hb-uniscribe.cc
-HBHEADERS += hb-uniscribe.h
+HBNONPCLIBS += $(UNISCRIBE_LIBS)
+HBSOURCES += $(HB_UNISCRIBE_sources)
+HBHEADERS += $(HB_UNISCRIBE_headers)
+endif
+
+if HAVE_DIRECTWRITE
+HBCFLAGS += $(DIRECTWRITE_CXXFLAGS)
+HBNONPCLIBS += $(DIRECTWRITE_LIBS)
+HBSOURCES += $(HB_DIRECTWRITE_sources)
+HBHEADERS += $(HB_DIRECTWRITE_headers)
 endif
 
 if HAVE_CORETEXT
 HBCFLAGS += $(CORETEXT_CFLAGS)
-HBLIBS   += $(CORETEXT_LIBS)
-HBSOURCES += hb-coretext.cc
-HBHEADERS += hb-coretext.h
+HBNONPCLIBS += $(CORETEXT_LIBS)
+HBSOURCES += $(HB_CORETEXT_sources)
+HBHEADERS += $(HB_CORETEXT_headers)
 endif
 
 if HAVE_UCDN
 SUBDIRS += hb-ucdn
 HBCFLAGS += -I$(srcdir)/hb-ucdn
 HBLIBS   += hb-ucdn/libhb-ucdn.la
-HBSOURCES += hb-ucdn.cc
+HBSOURCES += $(HB_UCDN_sources)
 endif
 DIST_SUBDIRS += hb-ucdn
 
 
 # Put the library together
 
+HBLIBS += $(HBNONPCLIBS)
+
 if OS_WIN32
 export_symbols = -export-symbols harfbuzz.def
 harfbuzz_def_dependency = harfbuzz.def
@@ -203,35 +129,51 @@
 pkgconfig_DATA = harfbuzz.pc
 EXTRA_DIST += harfbuzz.pc.in
 
+FUZZING_CPPFLAGS= \
+	-DHB_MAX_NESTING_LEVEL=3 \
+	-DHB_SANITIZE_MAX_EDITS=3 \
+	-DHB_BUFFER_MAX_EXPANSION_FACTOR=3 \
+	-DHB_BUFFER_MAX_LEN_MIN=8 \
+	-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
+	$(NULL)
+EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
+libharfbuzz_fuzzing_la_LINK = $(libharfbuzz_la_LINK)
+libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
+libharfbuzz_fuzzing_la_CPPFLAGS = $(libharfbuzz_la_CPPFLAGS) $(FUZZING_CPPFLAGS)
+libharfbuzz_fuzzing_la_LDFLAGS = $(libharfbuzz_la_LDFLAGS)
+libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
+EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
+CLEANFILES += libharfbuzz-fuzzing.la
+
 if HAVE_ICU
 lib_LTLIBRARIES += libharfbuzz-icu.la
-libharfbuzz_icu_la_SOURCES = hb-icu.cc
+libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
 libharfbuzz_icu_la_CPPFLAGS = $(ICU_CFLAGS)
 libharfbuzz_icu_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
 libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
-pkginclude_HEADERS += hb-icu.h
+pkginclude_HEADERS += $(HB_ICU_headers)
 pkgconfig_DATA += harfbuzz-icu.pc
 endif
 EXTRA_DIST += harfbuzz-icu.pc.in
 
 if HAVE_GOBJECT
 lib_LTLIBRARIES += libharfbuzz-gobject.la
-libharfbuzz_gobject_la_SOURCES = hb-gobject-structs.cc
-nodist_libharfbuzz_gobject_la_SOURCES = hb-gobject-enums.cc
+libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_sources)
+nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_ENUM_sources)
 libharfbuzz_gobject_la_CPPFLAGS = $(GOBJECT_CFLAGS)
 libharfbuzz_gobject_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
 libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
-pkginclude_HEADERS += hb-gobject.h hb-gobject-structs.h
-nodist_pkginclude_HEADERS += hb-gobject-enums.h
+pkginclude_HEADERS += $(HB_GOBJECT_headers)
+nodist_pkginclude_HEADERS += $(HB_GOBJECT_ENUM_headers)
 pkgconfig_DATA += harfbuzz-gobject.pc
 
 BUILT_SOURCES += \
-	hb-gobject-enums.cc \
-	hb-gobject-enums.h \
+	$(HB_GOBJECT_ENUM_sources) \
+	$(HB_GOBJECT_ENUM_headers) \
 	$(NULL)
 DISTCLEANFILES += \
-	hb-gobject-enums.cc \
-	hb-gobject-enums.h \
+	$(HB_GOBJECT_ENUM_sources) \
+	$(HB_GOBJECT_ENUM_headers) \
 	$(NULL)
 hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
 	$(AM_V_GEN) $(GLIB_MKENUMS) \
@@ -253,6 +195,8 @@
 		-e 's@%exec_prefix%@$(exec_prefix)@g' \
 		-e 's@%libdir%@$(libdir)@g' \
 		-e 's@%includedir%@$(includedir)@g' \
+		-e 's@%libs_private%@$(HBNONPCLIBS)@g' \
+		-e 's@%requires_private%@$(HBDEPS)@g' \
 		-e 's@%VERSION%@$(VERSION)@g' \
 	"$<" > "$@" \
 	|| ($(RM) "$@"; false)
@@ -267,7 +211,7 @@
 	$(EGREP) '^hb_.* \(' | \
 	sed -e 's/ (.*//' | \
 	LANG=C sort; \
-	echo LIBRARY libharfbuzz-$(HB_VERSION_MAJOR).dll; \
+	echo LIBRARY libharfbuzz-0.dll; \
 	) >"$@"
 	@ ! grep -q hb_ERROR "$@" \
 	|| ($(RM) "$@"; false)
@@ -276,29 +220,34 @@
 GENERATORS = \
 	gen-arabic-table.py \
 	gen-indic-table.py \
+	gen-use-table.py \
 	$(NULL)
 EXTRA_DIST += $(GENERATORS)
 
-unicode-tables: arabic-table indic-table
-
-indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
-	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc \
-	|| ($(RM) hb-ot-shape-complex-indic-table.cc; false)
+unicode-tables: arabic-table indic-table use-table
 
 arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
 	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh \
 	|| ($(RM) hb-ot-shape-complex-arabic-table.hh; false)
 
+indic-table: gen-indic-table.py IndicSyllabicCategory-7.0.0.txt IndicMatraCategory-7.0.0.txt Blocks.txt
+	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc \
+	|| ($(RM) hb-ot-shape-complex-indic-table.cc; false)
+
+use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
+	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-use-table.cc \
+	|| ($(RM) hb-ot-shape-complex-use-table.cc; false)
+
 built-sources: $(BUILT_SOURCES)
 
-.PHONY: unicode-tables arabic-table indic-table built-sources
+.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-sea-machine.hh \
+	$(srcdir)/hb-ot-shape-complex-use-machine.hh \
 	$(NULL)
 BUILT_SOURCES += $(RAGEL_GENERATED)
 EXTRA_DIST += \
@@ -306,7 +255,7 @@
 	hb-buffer-deserialize-text.rl \
 	hb-ot-shape-complex-indic-machine.rl \
 	hb-ot-shape-complex-myanmar-machine.rl \
-	hb-ot-shape-complex-sea-machine.rl \
+	hb-ot-shape-complex-use-machine.rl \
 	$(NULL)
 MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
 $(srcdir)/%.hh: $(srcdir)/%.rl
@@ -352,7 +301,14 @@
 	check-symbols.sh \
 	$(NULL)
 
-TESTS = $(dist_check_SCRIPTS)
+check_PROGRAMS = \
+	test-ot-tag \
+	$(NULL)
+test_ot_tag_SOURCES = hb-ot-tag.cc
+test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
+test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
+
+TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS)
 TESTS_ENVIRONMENT = \
 	srcdir="$(srcdir)" \
 	MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
@@ -363,7 +319,7 @@
 if HAVE_INTROSPECTION
 
 -include $(INTROSPECTION_MAKEFILE)
-INTROSPECTION_GIRS = HarfBuzz-$(HB_VERSION_MAJOR).0.gir # What does the 0 mean anyway?!
+INTROSPECTION_GIRS = HarfBuzz-0.0.gir # What does the 0 mean anyway?!
 INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
 INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
 INTROSPECTION_SCANNER_ENV = CC="$(CC)"
@@ -379,6 +335,7 @@
 	-DHB_OT_H_IN \
 	-DHB_GOBJECT_H \
 	-DHB_GOBJECT_H_IN \
+	-DHB_EXTERN= \
 	$(NULL)
 HarfBuzz_0_0_gir_LIBS = \
 	libharfbuzz.la \
@@ -388,10 +345,10 @@
 	$(HBHEADERS) \
 	$(HBNODISTHEADERS) \
 	$(HBSOURCES) \
-	hb-gobject-enums.cc \
-	hb-gobject-enums.h \
-	hb-gobject-structs.cc \
-	hb-gobject-structs.h \
+	$(HB_GOBJECT_ENUM_sources) \
+	$(HB_GOBJECT_ENUM_headers) \
+	$(HB_GOBJECT_sources) \
+	$(HB_GOBJECT_STRUCTS_headers) \
 	$(NULL)
 
 girdir = $(datadir)/gir-1.0
diff --git a/src/Makefile.sources b/src/Makefile.sources
new file mode 100644
index 0000000..171c513
--- /dev/null
+++ b/src/Makefile.sources
@@ -0,0 +1,150 @@
+NULL =
+
+# Base and default-included sources and headers
+
+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-face-private.hh \
+	hb-face.cc \
+	hb-font-private.hh \
+	hb-font.cc \
+	hb-mutex-private.hh \
+	hb-object-private.hh \
+	hb-open-file-private.hh \
+	hb-open-type-private.hh \
+	hb-ot-cmap-table.hh \
+	hb-ot-glyf-table.hh \
+	hb-ot-head-table.hh \
+	hb-ot-hhea-table.hh \
+	hb-ot-hmtx-table.hh \
+	hb-ot-maxp-table.hh \
+	hb-ot-name-table.hh \
+	hb-ot-os2-table.hh \
+	hb-ot-tag.cc \
+	hb-private.hh \
+	hb-set-private.hh \
+	hb-set.cc \
+	hb-shape.cc \
+	hb-shape-plan-private.hh \
+	hb-shape-plan.cc \
+	hb-shaper-list.hh \
+	hb-shaper-impl-private.hh \
+	hb-shaper-private.hh \
+	hb-shaper.cc \
+	hb-unicode-private.hh \
+	hb-unicode.cc \
+	hb-utf-private.hh \
+	hb-warning.cc \
+	$(NULL)
+
+HB_BASE_headers = \
+	hb.h \
+	hb-blob.h \
+	hb-buffer.h \
+	hb-common.h \
+	hb-deprecated.h \
+	hb-face.h \
+	hb-font.h \
+	hb-set.h \
+	hb-shape.h \
+	hb-shape-plan.h \
+	hb-unicode.h \
+	$(NULL)
+
+HB_NODIST_headers = \
+	hb-version.h \
+	$(NULL)
+
+HB_FALLBACK_sources = hb-fallback-shape.cc
+
+HB_OT_sources = \
+	hb-ot-font.cc \
+	hb-ot-layout.cc \
+	hb-ot-layout-common-private.hh \
+	hb-ot-layout-gdef-table.hh \
+	hb-ot-layout-gpos-table.hh \
+	hb-ot-layout-gsubgpos-private.hh \
+	hb-ot-layout-gsub-table.hh \
+	hb-ot-layout-jstf-table.hh \
+	hb-ot-layout-private.hh \
+	hb-ot-map.cc \
+	hb-ot-map-private.hh \
+	hb-ot-shape.cc \
+	hb-ot-shape-complex-arabic.cc \
+	hb-ot-shape-complex-arabic-fallback.hh \
+	hb-ot-shape-complex-arabic-private.hh \
+	hb-ot-shape-complex-arabic-table.hh \
+	hb-ot-shape-complex-arabic-win1256.hh \
+	hb-ot-shape-complex-default.cc \
+	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 \
+	hb-ot-shape-normalize-private.hh \
+	hb-ot-shape-normalize.cc \
+	hb-ot-shape-fallback-private.hh \
+	hb-ot-shape-fallback.cc \
+	hb-ot-shape-private.hh \
+	$(NULL)
+
+HB_OT_headers = \
+	hb-ot.h \
+	hb-ot-font.h \
+	hb-ot-layout.h \
+	hb-ot-shape.h \
+	hb-ot-tag.h \
+	$(NULL)
+
+# Optional Sources and Headers with external deps
+
+HB_FT_sources = hb-ft.cc
+HB_FT_headers = hb-ft.h
+
+HB_GLIB_sources = hb-glib.cc
+HB_GLIB_headers = hb-glib.h
+
+HB_GRAPHITE2_sources = hb-graphite2.cc
+HB_GRAPHITE2_headers = hb-graphite2.h
+
+# System-dependent sources and headers
+
+HB_CORETEXT_sources = hb-coretext.cc
+HB_CORETEXT_headers = hb-coretext.h
+
+HB_DIRECTWRITE_sources = hb-directwrite.cc
+HB_DIRECTWRITE_headers = hb-directwrite.h
+
+HB_UNISCRIBE_sources = hb-uniscribe.cc
+HB_UNISCRIBE_headers = hb-uniscribe.h
+
+# Additional supplemental sources
+HB_UCDN_sources  = hb-ucdn.cc
+
+# Sources for libharfbuzz-gobject and libharfbuzz-icu
+HB_ICU_sources = hb-icu.cc
+HB_ICU_headers = hb-icu.h
+
+HB_GOBJECT_sources = hb-gobject-structs.cc
+HB_GOBJECT_STRUCTS_headers = hb-gobject-structs.h
+HB_GOBJECT_headers = hb-gobject.h $(HB_GOBJECT_STRUCTS_headers)
+HB_GOBJECT_ENUM_sources = hb-gobject-enums.cc
+HB_GOBJECT_ENUM_headers = hb-gobject-enums.h
diff --git a/src/check-header-guards.sh b/src/check-header-guards.sh
index 9a3302c..09c5ea8 100755
--- a/src/check-header-guards.sh
+++ b/src/check-header-guards.sh
@@ -9,13 +9,12 @@
 test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
 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"
-	echo "$x" | grep '[^h]$' -q && continue;
+	echo "$x" | grep -q '[^h]$' && continue;
 	xx=`echo "$x" | sed 's@.*/@@'`
 	tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'`
-	lines=`grep "\<$tag\>" "$x" | wc -l | sed 's/[ 	]*//g'`
+	lines=`grep -w "$tag" "$x" | wc -l | sed 's/[ 	]*//g'`
 	if test "x$lines" != x3; then
 		echo "Ouch, header file $x does not have correct preprocessor guards"
 		stat=1
diff --git a/src/check-libstdc++.sh b/src/check-libstdc++.sh
index 27deb42..b541828 100755
--- a/src/check-libstdc++.sh
+++ b/src/check-libstdc++.sh
@@ -19,9 +19,9 @@
 	so=.libs/libharfbuzz.$suffix
 	if ! test -f "$so"; then continue; fi
 
-	echo "Checking that we are not linking to libstdc++"
-	if ldd $so | grep 'libstdc[+][+]'; then
-		echo "Ouch, linked to libstdc++"
+	echo "Checking that we are not linking to libstdc++ or libc++"
+	if ldd $so | grep 'libstdc[+][+]\|libc[+][+]'; then
+		echo "Ouch, linked to libstdc++ or libc++"
 		stat=1
 	fi
 	tested=true
diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py
index f5716bd..c055163 100755
--- a/src/gen-indic-table.py
+++ b/src/gen-indic-table.py
@@ -91,6 +91,7 @@
 	"Visarga":		'Vs',
 	"Vowel":		'Vo',
 	"Vowel_Dependent":	'M',
+	"Consonant_Prefixed":	'CPrf',
 	"Other":		'x',
 },{
 	"Not_Applicable":	'x',
diff --git a/src/gen-use-table.py b/src/gen-use-table.py
new file mode 100755
index 0000000..be04e4b
--- /dev/null
+++ b/src/gen-use-table.py
@@ -0,0 +1,476 @@
+#!/usr/bin/python
+
+import sys
+
+if len (sys.argv) != 5:
+	print >>sys.stderr, "usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt"
+	sys.exit (1)
+
+BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"]
+
+files = [file (x) for x in sys.argv[1:]]
+
+headers = [[f.readline () for i in range (2)] for j,f in enumerate(files) if j != 2]
+headers.append (["UnicodeData.txt does not have a header."])
+
+data = [{} for f in files]
+values = [{} for f in files]
+for i, f in enumerate (files):
+	for line in f:
+
+		j = line.find ('#')
+		if j >= 0:
+			line = line[:j]
+
+		fields = [x.strip () for x in line.split (';')]
+		if len (fields) == 1:
+			continue
+
+		uu = fields[0].split ('..')
+		start = int (uu[0], 16)
+		if len (uu) == 1:
+			end = start
+		else:
+			end = int (uu[1], 16)
+
+		t = fields[1 if i != 2 else 2]
+
+		for u in range (start, end + 1):
+			data[i][u] = t
+		values[i][t] = values[i].get (t, 0) + end - start + 1
+
+defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
+
+# TODO Characters that are not in Unicode Indic files, but used in USE
+data[0][0x034F] = defaults[0]
+data[0][0x2060] = defaults[0]
+for u in range (0xFE00, 0xFE0F + 1):
+	data[0][u] = defaults[0]
+
+# Merge data into one dict:
+for i,v in enumerate (defaults):
+	values[i][v] = values[i].get (v, 0) + 1
+combined = {}
+for i,d in enumerate (data):
+	for u,v in d.items ():
+		if i >= 2 and not u in combined:
+			continue
+		if not u in combined:
+			combined[u] = list (defaults)
+		combined[u][i] = v
+combined = {k:v for k,v in combined.items() if v[3] not in BLACKLISTED_BLOCKS}
+data = combined
+del combined
+num = len (data)
+
+
+property_names = [
+	# General_Category
+	'Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu', 'Mc',
+	'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf', 'Pi', 'Po',
+	'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',
+	# Indic_Syllabic_Category
+	'Other',
+	'Bindu',
+	'Visarga',
+	'Avagraha',
+	'Nukta',
+	'Virama',
+	'Pure_Killer',
+	'Invisible_Stacker',
+	'Vowel_Independent',
+	'Vowel_Dependent',
+	'Vowel',
+	'Consonant_Placeholder',
+	'Consonant',
+	'Consonant_Dead',
+	'Consonant_With_Stacker',
+	'Consonant_Prefixed',
+	'Consonant_Preceding_Repha',
+	'Consonant_Succeeding_Repha',
+	'Consonant_Subjoined',
+	'Consonant_Medial',
+	'Consonant_Final',
+	'Consonant_Head_Letter',
+	'Modifying_Letter',
+	'Tone_Letter',
+	'Tone_Mark',
+	'Gemination_Mark',
+	'Cantillation_Mark',
+	'Register_Shifter',
+	'Syllable_Modifier',
+	'Consonant_Killer',
+	'Non_Joiner',
+	'Joiner',
+	'Number_Joiner',
+	'Number',
+	'Brahmi_Joining_Number',
+	# Indic_Positional_Category
+	'Not_Applicable',
+	'Right',
+	'Left',
+	'Visual_Order_Left',
+	'Left_And_Right',
+	'Top',
+	'Bottom',
+	'Top_And_Bottom',
+	'Top_And_Right',
+	'Top_And_Left',
+	'Top_And_Left_And_Right',
+	'Bottom_And_Right',
+	'Top_And_Bottom_And_Right',
+	'Overstruck',
+]
+
+class PropertyValue(object):
+	def __init__(self, name_):
+		self.name = name_
+	def __str__(self):
+		return self.name
+	def __eq__(self, other):
+		return self.name == (other if isinstance(other, basestring) else other.name)
+	def __ne__(self, other):
+		return not (self == other)
+
+property_values = {}
+
+for name in property_names:
+	value = PropertyValue(name)
+	assert value not in property_values
+	assert value not in globals()
+	property_values[name] = value
+globals().update(property_values)
+
+
+def is_BASE(U, UISC, UGC):
+	return (UISC in [Number, Consonant, Consonant_Head_Letter,
+			#SPEC-OUTDATED Consonant_Placeholder,
+			Tone_Letter] or
+		(UGC == Lo and UISC in [Avagraha, Bindu, Consonant_Final, Consonant_Medial,
+					Consonant_Subjoined, Vowel, Vowel_Dependent]))
+def is_BASE_VOWEL(U, UISC, UGC):
+	return UISC == Vowel_Independent
+def is_BASE_IND(U, UISC, UGC):
+	#SPEC-BROKEN return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po)
+	return (UISC in [Consonant_Dead, Modifying_Letter] or
+		(UGC == Po and not is_BASE_OTHER(U, UISC, UGC))) # for 104E
+def is_BASE_NUM(U, UISC, UGC):
+	return UISC == Brahmi_Joining_Number
+def is_BASE_OTHER(U, UISC, UGC):
+	if UISC == Consonant_Placeholder: return True #SPEC-OUTDATED
+	return U in [0x00A0, 0x00D7, 0x2015, 0x2022, 0x25CC,
+		     0x25FB, 0x25FC, 0x25FD, 0x25FE]
+def is_CGJ(U, UISC, UGC):
+	return U == 0x034F
+def is_CONS_FINAL(U, UISC, UGC):
+	return ((UISC == Consonant_Final and UGC != Lo) or
+		UISC == Consonant_Succeeding_Repha)
+def is_CONS_FINAL_MOD(U, UISC, UGC):
+	#SPEC-OUTDATED return  UISC in [Consonant_Final_Modifier, Syllable_Modifier]
+	return  UISC == Syllable_Modifier
+def is_CONS_MED(U, UISC, UGC):
+	return UISC == Consonant_Medial and UGC != Lo
+def is_CONS_MOD(U, UISC, UGC):
+	return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
+def is_CONS_SUB(U, UISC, UGC):
+	#SPEC-OUTDATED return UISC == Consonant_Subjoined
+	return UISC == Consonant_Subjoined and UGC != Lo
+def is_HALANT(U, UISC, UGC):
+	return UISC in [Virama, Invisible_Stacker]
+def is_HALANT_NUM(U, UISC, UGC):
+	return UISC == Number_Joiner
+def is_ZWNJ(U, UISC, UGC):
+	return UISC == Non_Joiner
+def is_ZWJ(U, UISC, UGC):
+	return UISC == Joiner
+def is_Word_Joiner(U, UISC, UGC):
+	return U == 0x2060
+def is_OTHER(U, UISC, UGC):
+	#SPEC-OUTDATED return UGC == Zs # or any other SCRIPT_COMMON characters
+	return (UISC == Other
+		and not is_SYM_MOD(U, UISC, UGC)
+		and not is_CGJ(U, UISC, UGC)
+		and not is_Word_Joiner(U, UISC, UGC)
+		and not is_VARIATION_SELECTOR(U, UISC, UGC)
+	)
+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]
+def is_SYM(U, UISC, UGC):
+	if U == 0x25CC: return False #SPEC-OUTDATED
+	#SPEC-OUTDATED return UGC in [So, Sc] or UISC == Symbol_Letter
+	return UGC in [So, Sc]
+def is_SYM_MOD(U, UISC, UGC):
+	return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73]
+def is_VARIATION_SELECTOR(U, UISC, UGC):
+	return 0xFE00 <= U <= 0xFE0F
+def is_VOWEL(U, UISC, UGC):
+	return (UISC == Pure_Killer or
+		(UGC != Lo and UISC in [Vowel, Vowel_Dependent]))
+def is_VOWEL_MOD(U, UISC, UGC):
+	return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
+		(UGC != Lo and UISC == Bindu))
+
+use_mapping = {
+	'B':	is_BASE,
+	'IV':	is_BASE_VOWEL,
+	'IND':	is_BASE_IND,
+	'N':	is_BASE_NUM,
+	'GB':	is_BASE_OTHER,
+	'CGJ':	is_CGJ,
+	'F':	is_CONS_FINAL,
+	'FM':	is_CONS_FINAL_MOD,
+	'M':	is_CONS_MED,
+	'CM':	is_CONS_MOD,
+	'SUB':	is_CONS_SUB,
+	'H':	is_HALANT,
+	'HN':	is_HALANT_NUM,
+	'ZWNJ':	is_ZWNJ,
+	'ZWJ':	is_ZWJ,
+	'WJ':	is_Word_Joiner,
+	'O':	is_OTHER,
+	'Rsv':	is_Reserved,
+	'R':	is_REPHA,
+	'S':	is_SYM,
+	'SM':	is_SYM_MOD,
+	'VS':	is_VARIATION_SELECTOR,
+	'V':	is_VOWEL,
+	'VM':	is_VOWEL_MOD,
+}
+
+use_positions = {
+	'F': {
+		'Abv': [Top],
+		'Blw': [Bottom],
+		'Pst': [Right],
+	},
+	'M': {
+		'Abv': [Top],
+		'Blw': [Bottom],
+		'Pst': [Right],
+		'Pre': [Left],
+	},
+	'CM': {
+		'Abv': [Top],
+		'Blw': [Bottom],
+	},
+	'V': {
+		'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right],
+		'Blw': [Bottom, Overstruck, Bottom_And_Right],
+		'Pst': [Right],
+		'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right],
+	},
+	'VM': {
+		'Abv': [Top],
+		'Blw': [Bottom, Overstruck],
+		'Pst': [Right],
+		'Pre': [Left],
+	},
+	'SM': {
+		'Abv': [Top],
+		'Blw': [Bottom],
+	},
+	'H': None,
+	'B': None,
+	'FM': None,
+	'SUB': None,
+}
+
+def map_to_use(data):
+	out = {}
+	items = use_mapping.items()
+	for U,(UISC,UIPC,UGC,UBlock) in data.items():
+
+		# Resolve Indic_Syllabic_Category
+
+		# TODO: These don't have UISC assigned in Unicode 8.0, but
+		# have UIPC
+		if U == 0x17DD: UISC = Vowel_Dependent
+		if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
+
+		# TODO: U+1CED should only be allowed after some of
+		# 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]
+		assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
+		USE = values[0]
+
+		# Resolve Indic_Positional_Category
+
+		# TODO: Not in Unicode 8.0 yet, but in spec.
+		if U == 0x1B6C: UIPC = Bottom
+
+		# TODO: These should die, but have UIPC in Unicode 8.0
+		if U in [0x953, 0x954]: UIPC = Not_Applicable
+
+		# TODO: In USE's override list but not in Unicode 8.0
+		if U == 0x103C: UIPC = Left
+
+		# TODO: These are not in USE's override list that we have, nor are they in Unicode 8.0
+		if 0xA926 <= U <= 0xA92A: UIPC = Top
+		if U == 0x111CA: UIPC = Bottom
+		if U == 0x11300: UIPC = Top
+		if U == 0x1133C: UIPC = Bottom
+		if U == 0x1171E: UIPC = Left # Correct?!
+		if 0x1CF2 <= U <= 0x1CF3: UIPC = Right
+		if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
+
+		assert (UIPC in [Not_Applicable, Visual_Order_Left] or
+			USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC)
+
+		pos_mapping = use_positions.get(USE, None)
+		if pos_mapping:
+			values = [k for k,v in pos_mapping.items() if v and UIPC in v]
+			assert len(values) == 1, "%s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC, values)
+			USE = USE + values[0]
+
+		out[U] = (USE, UBlock)
+	return out
+
+defaults = ('O', 'No_Block')
+data = map_to_use(data)
+
+# Remove the outliers
+singles = {}
+for u in [0x034F, 0x25CC, 0x1107F]:
+	singles[u] = data[u]
+	del data[u]
+
+print "/* == Start of generated table == */"
+print "/*"
+print " * The following table is generated by running:"
+print " *"
+print " *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt"
+print " *"
+print " * on files with these headers:"
+print " *"
+for h in headers:
+	for l in h:
+		print " * %s" % (l.strip())
+print " */"
+print
+print '#include "hb-ot-shape-complex-use-private.hh"'
+print
+
+total = 0
+used = 0
+last_block = None
+def print_block (block, start, end, data):
+	global total, used, last_block
+	if block and block != last_block:
+		print
+		print
+		print "  /* %s */" % block
+		if start % 16:
+			print ' ' * (20 + (start % 16 * 6)),
+	num = 0
+	assert start % 8 == 0
+	assert (end+1) % 8 == 0
+	for u in range (start, end+1):
+		if u % 16 == 0:
+			print
+			print "  /* %04X */" % u,
+		if u in data:
+			num += 1
+		d = data.get (u, defaults)
+		sys.stdout.write ("%6s," % d[0])
+
+	total += end - start + 1
+	used += num
+	if block:
+		last_block = block
+
+uu = data.keys ()
+uu.sort ()
+
+last = -100000
+num = 0
+offset = 0
+starts = []
+ends = []
+for k,v in sorted(use_mapping.items()):
+	if k in use_positions and use_positions[k]: continue
+	print "#define %s	USE_%s	/* %s */" % (k, k, v.__name__[3:])
+for k,v in sorted(use_positions.items()):
+	if not v: continue
+	for suf in v.keys():
+		tag = k + suf
+		print "#define %s	USE_%s" % (tag, tag)
+print ""
+print "static const USE_TABLE_ELEMENT_TYPE use_table[] = {"
+for u in uu:
+	if u <= last:
+		continue
+	block = data[u][1]
+
+	start = u//8*8
+	end = start+1
+	while end in uu and block == data[end][1]:
+		end += 1
+	end = (end-1)//8*8 + 7
+
+	if start != last + 1:
+		if start - last <= 1+16*3:
+			print_block (None, last+1, start-1, data)
+			last = start-1
+		else:
+			if last >= 0:
+				ends.append (last + 1)
+				offset += ends[-1] - starts[-1]
+			print
+			print
+			print "#define use_offset_0x%04xu %d" % (start, offset)
+			starts.append (start)
+
+	print_block (block, start, end, data)
+	last = end
+ends.append (last + 1)
+offset += ends[-1] - starts[-1]
+print
+print
+occupancy = used * 100. / total
+page_bits = 12
+print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
+print
+print "USE_TABLE_ELEMENT_TYPE"
+print "hb_use_get_categories (hb_codepoint_t u)"
+print "{"
+print "  switch (u >> %d)" % page_bits
+print "  {"
+pages = set([u>>page_bits for u in starts+ends+singles.keys()])
+for p in sorted(pages):
+	print "    case 0x%0Xu:" % p
+	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)
+	for u,d in singles.items ():
+		if p != u>>page_bits: continue
+		print "      if (unlikely (u == 0x%04Xu)) return %s;" % (u, d[0])
+	print "      break;"
+	print ""
+print "    default:"
+print "      break;"
+print "  }"
+print "  return USE_O;"
+print "}"
+print
+for k in sorted(use_mapping.keys()):
+	if k in use_positions and use_positions[k]: continue
+	print "#undef %s" % k
+for k,v in sorted(use_positions.items()):
+	if not v: continue
+	for suf in v.keys():
+		tag = k + suf
+		print "#undef %s" % tag
+print
+print "/* == End of generated table == */"
+
+# Maintain at least 50% occupancy in the table */
+if occupancy < 50:
+	raise Exception ("Table too sparse, please investigate: ", occupancy)
diff --git a/src/harfbuzz.pc.in b/src/harfbuzz.pc.in
index 7f27bbb..b3e124a 100644
--- a/src/harfbuzz.pc.in
+++ b/src/harfbuzz.pc.in
@@ -8,4 +8,6 @@
 Version: %VERSION%
 
 Libs: -L${libdir} -lharfbuzz
+Libs.private: %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 e6738b7..100ba53 100644
--- a/src/hb-atomic-private.hh
+++ b/src/hb-atomic-private.hh
@@ -39,7 +39,11 @@
 
 /* We need external help for these */
 
-#if 0
+#if defined(hb_atomic_int_impl_add) \
+ && defined(hb_atomic_ptr_impl_get) \
+ && defined(hb_atomic_ptr_impl_cmpexch)
+
+/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */
 
 
 #elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
@@ -58,11 +62,12 @@
 #endif
 }
 
-typedef LONG hb_atomic_int_t;
-#define hb_atomic_int_add(AI, V)	InterlockedExchangeAdd (&(AI), (V))
+typedef LONG hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)		InterlockedExchangeAdd (&(AI), (V))
 
-#define hb_atomic_ptr_get(P)		(_HBMemoryBarrier (), (void *) *(P))
-#define hb_atomic_ptr_cmpexch(P,O,N)	(InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
+#define hb_atomic_ptr_impl_get(P)		(_HBMemoryBarrier (), (void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	(InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
 
 
 #elif !defined(HB_NO_MT) && defined(__APPLE__)
@@ -74,28 +79,31 @@
 #include <Availability.h>
 #endif
 
-typedef int32_t hb_atomic_int_t;
-#define hb_atomic_int_add(AI, V)	(OSAtomicAdd32Barrier ((V), &(AI)) - (V))
 
-#define hb_atomic_ptr_get(P)		(OSMemoryBarrier (), (void *) *(P))
+typedef int32_t hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)		(OSAtomicAdd32Barrier ((V), &(AI)) - (V))
+
+#define hb_atomic_ptr_impl_get(P)		(OSMemoryBarrier (), (void *) *(P))
 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
-#define hb_atomic_ptr_cmpexch(P,O,N)	OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
+#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_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) (O), (int64_t) (N), (int64_t*) (P))
 #else
-#define hb_atomic_ptr_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) (O), (int32_t) (N), (int32_t*) (P))
 #endif
 #endif
 
 
 #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
 
-typedef int hb_atomic_int_t;
-#define hb_atomic_int_add(AI, V)	__sync_fetch_and_add (&(AI), (V))
+typedef int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)		__sync_fetch_and_add (&(AI), (V))
 
-#define hb_atomic_ptr_get(P)		(void *) (__sync_synchronize (), *(P))
-#define hb_atomic_ptr_cmpexch(P,O,N)	__sync_bool_compare_and_swap ((P), (O), (N))
+#define hb_atomic_ptr_impl_get(P)		(void *) (__sync_synchronize (), *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	__sync_bool_compare_and_swap ((P), (O), (N))
 
 
 #elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
@@ -103,33 +111,79 @@
 #include <atomic.h>
 #include <mbarrier.h>
 
-typedef unsigned int hb_atomic_int_t;
-#define hb_atomic_int_add(AI, V)	( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
+typedef unsigned int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)		( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
 
-#define hb_atomic_ptr_get(P)		( ({__machine_rw_barrier ();}), (void *) *(P))
-#define hb_atomic_ptr_cmpexch(P,O,N)	( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
+#define hb_atomic_ptr_impl_get(P)		( ({__machine_rw_barrier ();}), (void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
 
 
+#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__)
+
+#include <builtins.h>
+
+
+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) {
+  __sync();
+  int result = __compare_and_swaplp (P, &O, N);
+  __sync();
+  return result;
+}
+
+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_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))
+
 #elif !defined(HB_NO_MT)
 
 #define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
-typedef volatile int hb_atomic_int_t;
-#define hb_atomic_int_add(AI, V)	(((AI) += (V)) - (V))
 
-#define hb_atomic_ptr_get(P)		((void *) *(P))
-#define hb_atomic_ptr_cmpexch(P,O,N)	(* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
+typedef volatile int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V)		(((AI) += (V)) - (V))
+
+#define hb_atomic_ptr_impl_get(P)		((void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
 
 
 #else /* HB_NO_MT */
 
-typedef int hb_atomic_int_t;
-#define hb_atomic_int_add(AI, V)	(((AI) += (V)) - (V))
+typedef int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V)		(V)
+#define hb_atomic_int_impl_add(AI, V)		(((AI) += (V)) - (V))
 
-#define hb_atomic_ptr_get(P)		((void *) *(P))
-#define hb_atomic_ptr_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
+#define hb_atomic_ptr_impl_get(P)		((void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
+
 
 #endif
 
-/* TODO Add tracing. */
+
+#define HB_ATOMIC_INT_INIT(V)		{HB_ATOMIC_INT_IMPL_INIT(V)}
+
+struct hb_atomic_int_t
+{
+  hb_atomic_int_impl_t v;
+
+  inline void set_unsafe (int v_) { v = v_; }
+  inline int get_unsafe (void) const { return v; }
+  inline int inc (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v),  1); }
+  inline int dec (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), -1); }
+};
+
+
+#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get(P)
+#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N))
+
 
 #endif /* HB_ATOMIC_PRIVATE_HH */
diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index 8759a25..fb48f03 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -91,7 +91,7 @@
  * Return value: New blob, or the empty blob if something failed or if @length is
  * zero.  Destroy with hb_blob_destroy().
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_blob_t *
 hb_blob_create (const char        *data,
@@ -104,7 +104,6 @@
 
   if (!length ||
       length >= 1u << 31 ||
-      data + length < data /* overflows */ ||
       !(blob = hb_object_create<hb_blob_t> ())) {
     if (destroy)
       destroy (user_data);
@@ -147,7 +146,7 @@
  * @length is zero or @offset is beyond the end of @parent's data.  Destroy
  * with hb_blob_destroy().
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_blob_t *
 hb_blob_create_sub_blob (hb_blob_t    *parent,
@@ -179,7 +178,7 @@
  *
  * Return value: (transfer full): the empty blob.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_blob_t *
 hb_blob_get_empty (void)
@@ -210,7 +209,7 @@
  *
  * Return value: @blob.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_blob_t *
 hb_blob_reference (hb_blob_t *blob)
@@ -228,7 +227,7 @@
  *
  * See TODO:link object types for more information.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_blob_destroy (hb_blob_t *blob)
@@ -250,7 +249,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_blob_set_user_data (hb_blob_t          *blob,
@@ -271,7 +270,7 @@
  *
  * Return value: (transfer none): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void *
 hb_blob_get_user_data (hb_blob_t          *blob,
@@ -287,7 +286,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_blob_make_immutable (hb_blob_t *blob)
@@ -306,7 +305,7 @@
  *
  * Return value: TODO
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_blob_is_immutable (hb_blob_t *blob)
@@ -323,7 +322,7 @@
  *
  * Return value: the length of blob data in bytes.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 unsigned int
 hb_blob_get_length (hb_blob_t *blob)
@@ -340,7 +339,7 @@
  *
  * Returns: (transfer none) (array length=length): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 const char *
 hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
@@ -365,7 +364,7 @@
  * Returns: (transfer none) (array length=length): Writable blob data,
  * or %NULL if failed.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
diff --git a/src/hb-blob.h b/src/hb-blob.h
index b2419ab..ef3fc98 100644
--- a/src/hb-blob.h
+++ b/src/hb-blob.h
@@ -64,7 +64,7 @@
 
 typedef struct hb_blob_t hb_blob_t;
 
-hb_blob_t *
+HB_EXTERN hb_blob_t *
 hb_blob_create (const char        *data,
 		unsigned int       length,
 		hb_memory_mode_t   mode,
@@ -77,21 +77,21 @@
  * modify the parent data as that data may be
  * shared among multiple sub-blobs.
  */
-hb_blob_t *
+HB_EXTERN hb_blob_t *
 hb_blob_create_sub_blob (hb_blob_t    *parent,
 			 unsigned int  offset,
 			 unsigned int  length);
 
-hb_blob_t *
+HB_EXTERN hb_blob_t *
 hb_blob_get_empty (void);
 
-hb_blob_t *
+HB_EXTERN hb_blob_t *
 hb_blob_reference (hb_blob_t *blob);
 
-void
+HB_EXTERN void
 hb_blob_destroy (hb_blob_t *blob);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_blob_set_user_data (hb_blob_t          *blob,
 		       hb_user_data_key_t *key,
 		       void *              data,
@@ -99,25 +99,25 @@
 		       hb_bool_t           replace);
 
 
-void *
+HB_EXTERN void *
 hb_blob_get_user_data (hb_blob_t          *blob,
 		       hb_user_data_key_t *key);
 
 
-void
+HB_EXTERN void
 hb_blob_make_immutable (hb_blob_t *blob);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_blob_is_immutable (hb_blob_t *blob);
 
 
-unsigned int
+HB_EXTERN unsigned int
 hb_blob_get_length (hb_blob_t *blob);
 
-const char *
+HB_EXTERN const char *
 hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
 
-char *
+HB_EXTERN char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
 
 
diff --git a/src/hb-buffer-deserialize-json.hh b/src/hb-buffer-deserialize-json.hh
index dead700..3f626bd 100644
--- a/src/hb-buffer-deserialize-json.hh
+++ b/src/hb-buffer-deserialize-json.hh
@@ -1,5 +1,5 @@
 
-#line 1 "../../src/hb-buffer-deserialize-json.rl"
+#line 1 "hb-buffer-deserialize-json.rl"
 /*
  * Copyright © 2013  Google, Inc.
  *
@@ -32,7 +32,7 @@
 #include "hb-private.hh"
 
 
-#line 36 "hb-buffer-deserialize-json.hh.tmp"
+#line 36 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
 	0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 
 	48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
@@ -435,7 +435,7 @@
 static const int deserialize_json_en_main = 1;
 
 
-#line 97 "../../src/hb-buffer-deserialize-json.rl"
+#line 97 "hb-buffer-deserialize-json.rl"
 
 
 static hb_bool_t
@@ -459,15 +459,15 @@
 
   const char *tok = NULL;
   int cs;
-  hb_glyph_info_t info;
-  hb_glyph_position_t pos;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
   
-#line 466 "hb-buffer-deserialize-json.hh.tmp"
+#line 466 "hb-buffer-deserialize-json.hh"
 	{
 	cs = deserialize_json_start;
 	}
 
-#line 471 "hb-buffer-deserialize-json.hh.tmp"
+#line 471 "hb-buffer-deserialize-json.hh"
 	{
 	int _slen;
 	int _trans;
@@ -493,14 +493,14 @@
 
 	switch ( _deserialize_json_trans_actions[_trans] ) {
 	case 1:
-#line 38 "../../src/hb-buffer-deserialize-json.rl"
+#line 38 "hb-buffer-deserialize-json.rl"
 	{
 	memset (&info, 0, sizeof (info));
 	memset (&pos , 0, sizeof (pos ));
 }
 	break;
 	case 5:
-#line 43 "../../src/hb-buffer-deserialize-json.rl"
+#line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -510,13 +510,13 @@
 }
 	break;
 	case 2:
-#line 51 "../../src/hb-buffer-deserialize-json.rl"
+#line 51 "hb-buffer-deserialize-json.rl"
 	{
 	tok = p;
 }
 	break;
 	case 14:
-#line 55 "../../src/hb-buffer-deserialize-json.rl"
+#line 55 "hb-buffer-deserialize-json.rl"
 	{
 	if (!hb_font_glyph_from_string (font,
 					tok, p - tok,
@@ -525,33 +525,33 @@
 }
 	break;
 	case 15:
-#line 62 "../../src/hb-buffer-deserialize-json.rl"
+#line 62 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 	break;
 	case 8:
-#line 63 "../../src/hb-buffer-deserialize-json.rl"
+#line 63 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 	break;
 	case 10:
-#line 64 "../../src/hb-buffer-deserialize-json.rl"
+#line 64 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
 	case 12:
-#line 65 "../../src/hb-buffer-deserialize-json.rl"
+#line 65 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
 	case 3:
-#line 66 "../../src/hb-buffer-deserialize-json.rl"
+#line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
 	case 6:
-#line 67 "../../src/hb-buffer-deserialize-json.rl"
+#line 67 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 	break;
 	case 16:
-#line 62 "../../src/hb-buffer-deserialize-json.rl"
+#line 62 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-json.rl"
+#line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -561,9 +561,9 @@
 }
 	break;
 	case 9:
-#line 63 "../../src/hb-buffer-deserialize-json.rl"
+#line 63 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-json.rl"
+#line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -573,9 +573,9 @@
 }
 	break;
 	case 11:
-#line 64 "../../src/hb-buffer-deserialize-json.rl"
+#line 64 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-json.rl"
+#line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -585,9 +585,9 @@
 }
 	break;
 	case 13:
-#line 65 "../../src/hb-buffer-deserialize-json.rl"
+#line 65 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-json.rl"
+#line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -597,9 +597,9 @@
 }
 	break;
 	case 4:
-#line 66 "../../src/hb-buffer-deserialize-json.rl"
+#line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-json.rl"
+#line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -609,9 +609,9 @@
 }
 	break;
 	case 7:
-#line 67 "../../src/hb-buffer-deserialize-json.rl"
+#line 67 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-json.rl"
+#line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -620,7 +620,7 @@
 	*end_ptr = p;
 }
 	break;
-#line 624 "hb-buffer-deserialize-json.hh.tmp"
+#line 624 "hb-buffer-deserialize-json.hh"
 	}
 
 _again:
@@ -632,7 +632,7 @@
 	_out: {}
 	}
 
-#line 125 "../../src/hb-buffer-deserialize-json.rl"
+#line 125 "hb-buffer-deserialize-json.rl"
 
 
   *end_ptr = p;
diff --git a/src/hb-buffer-deserialize-text.hh b/src/hb-buffer-deserialize-text.hh
index a38efe3..d2d8daa 100644
--- a/src/hb-buffer-deserialize-text.hh
+++ b/src/hb-buffer-deserialize-text.hh
@@ -1,5 +1,5 @@
 
-#line 1 "../../src/hb-buffer-deserialize-text.rl"
+#line 1 "hb-buffer-deserialize-text.rl"
 /*
  * Copyright © 2013  Google, Inc.
  *
@@ -32,7 +32,7 @@
 #include "hb-private.hh"
 
 
-#line 36 "hb-buffer-deserialize-text.hh.tmp"
+#line 36 "hb-buffer-deserialize-text.hh"
 static const unsigned char _deserialize_text_trans_keys[] = {
 	0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 
 	48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 
@@ -312,7 +312,7 @@
 static const int deserialize_text_en_main = 1;
 
 
-#line 91 "../../src/hb-buffer-deserialize-text.rl"
+#line 91 "hb-buffer-deserialize-text.rl"
 
 
 static hb_bool_t
@@ -336,15 +336,15 @@
 
   const char *eof = pe, *tok = NULL;
   int cs;
-  hb_glyph_info_t info;
-  hb_glyph_position_t pos;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
   
-#line 343 "hb-buffer-deserialize-text.hh.tmp"
+#line 343 "hb-buffer-deserialize-text.hh"
 	{
 	cs = deserialize_text_start;
 	}
 
-#line 348 "hb-buffer-deserialize-text.hh.tmp"
+#line 348 "hb-buffer-deserialize-text.hh"
 	{
 	int _slen;
 	int _trans;
@@ -370,13 +370,13 @@
 
 	switch ( _deserialize_text_trans_actions[_trans] ) {
 	case 2:
-#line 51 "../../src/hb-buffer-deserialize-text.rl"
+#line 51 "hb-buffer-deserialize-text.rl"
 	{
 	tok = p;
 }
 	break;
 	case 5:
-#line 55 "../../src/hb-buffer-deserialize-text.rl"
+#line 55 "hb-buffer-deserialize-text.rl"
 	{
 	if (!hb_font_glyph_from_string (font,
 					tok, p - tok,
@@ -385,41 +385,41 @@
 }
 	break;
 	case 10:
-#line 62 "../../src/hb-buffer-deserialize-text.rl"
+#line 62 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 	break;
 	case 3:
-#line 63 "../../src/hb-buffer-deserialize-text.rl"
+#line 63 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 	break;
 	case 12:
-#line 64 "../../src/hb-buffer-deserialize-text.rl"
+#line 64 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 	break;
 	case 7:
-#line 65 "../../src/hb-buffer-deserialize-text.rl"
+#line 65 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 	break;
 	case 1:
-#line 38 "../../src/hb-buffer-deserialize-text.rl"
+#line 38 "hb-buffer-deserialize-text.rl"
 	{
 	memset (&info, 0, sizeof (info));
 	memset (&pos , 0, sizeof (pos ));
 }
-#line 51 "../../src/hb-buffer-deserialize-text.rl"
+#line 51 "hb-buffer-deserialize-text.rl"
 	{
 	tok = p;
 }
 	break;
 	case 4:
-#line 55 "../../src/hb-buffer-deserialize-text.rl"
+#line 55 "hb-buffer-deserialize-text.rl"
 	{
 	if (!hb_font_glyph_from_string (font,
 					tok, p - tok,
 					&info.codepoint))
 	  return false;
 }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -429,9 +429,9 @@
 }
 	break;
 	case 9:
-#line 62 "../../src/hb-buffer-deserialize-text.rl"
+#line 62 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -441,9 +441,9 @@
 }
 	break;
 	case 11:
-#line 64 "../../src/hb-buffer-deserialize-text.rl"
+#line 64 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -453,9 +453,9 @@
 }
 	break;
 	case 6:
-#line 65 "../../src/hb-buffer-deserialize-text.rl"
+#line 65 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -465,9 +465,9 @@
 }
 	break;
 	case 8:
-#line 66 "../../src/hb-buffer-deserialize-text.rl"
+#line 66 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -476,7 +476,7 @@
 	*end_ptr = p;
 }
 	break;
-#line 480 "hb-buffer-deserialize-text.hh.tmp"
+#line 480 "hb-buffer-deserialize-text.hh"
 	}
 
 _again:
@@ -489,14 +489,14 @@
 	{
 	switch ( _deserialize_text_eof_actions[cs] ) {
 	case 4:
-#line 55 "../../src/hb-buffer-deserialize-text.rl"
+#line 55 "hb-buffer-deserialize-text.rl"
 	{
 	if (!hb_font_glyph_from_string (font,
 					tok, p - tok,
 					&info.codepoint))
 	  return false;
 }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -506,9 +506,9 @@
 }
 	break;
 	case 9:
-#line 62 "../../src/hb-buffer-deserialize-text.rl"
+#line 62 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -518,9 +518,9 @@
 }
 	break;
 	case 11:
-#line 64 "../../src/hb-buffer-deserialize-text.rl"
+#line 64 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -530,9 +530,9 @@
 }
 	break;
 	case 6:
-#line 65 "../../src/hb-buffer-deserialize-text.rl"
+#line 65 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -542,9 +542,9 @@
 }
 	break;
 	case 8:
-#line 66 "../../src/hb-buffer-deserialize-text.rl"
+#line 66 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
 	if (buffer->in_error)
@@ -553,14 +553,14 @@
 	*end_ptr = p;
 }
 	break;
-#line 557 "hb-buffer-deserialize-text.hh.tmp"
+#line 557 "hb-buffer-deserialize-text.hh"
 	}
 	}
 
 	_out: {}
 	}
 
-#line 119 "../../src/hb-buffer-deserialize-text.rl"
+#line 119 "hb-buffer-deserialize-text.rl"
 
 
   *end_ptr = p;
diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl
index 8856580..8a682f7 100644
--- a/src/hb-buffer-deserialize-text.rl
+++ b/src/hb-buffer-deserialize-text.rl
@@ -111,8 +111,8 @@
 
   const char *eof = pe, *tok = NULL;
   int cs;
-  hb_glyph_info_t info;
-  hb_glyph_position_t pos;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
   %%{
     write init;
     write exec;
diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index 069f925..c8eec3c 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -35,9 +35,36 @@
 #include "hb-unicode-private.hh"
 
 
+#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
+#define HB_BUFFER_MAX_EXPANSION_FACTOR 32
+#endif
+#ifndef HB_BUFFER_MAX_LEN_MIN
+#define HB_BUFFER_MAX_LEN_MIN 8192
+#endif
+#ifndef HB_BUFFER_MAX_LEN_DEFAULT
+#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));
 
+HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
+HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
+
+enum hb_buffer_scratch_flags_t {
+  HB_BUFFER_SCRATCH_FLAG_DEFAULT			= 0x00000000u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII			= 0x00000001u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES		= 0x00000002u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK		= 0x00000004u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT		= 0x00000008u,
+  /* Reserved for complex shapers' internal use. */
+  HB_BUFFER_SCRATCH_FLAG_COMPLEX0			= 0x01000000u,
+  HB_BUFFER_SCRATCH_FLAG_COMPLEX1			= 0x02000000u,
+  HB_BUFFER_SCRATCH_FLAG_COMPLEX2			= 0x04000000u,
+  HB_BUFFER_SCRATCH_FLAG_COMPLEX3			= 0x08000000u,
+};
+HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
+
 
 /*
  * hb_buffer_t
@@ -50,7 +77,10 @@
   /* Information about how the text in the buffer should be treated */
   hb_unicode_funcs_t *unicode; /* Unicode functions */
   hb_buffer_flags_t flags; /* BOT / EOT / etc. */
+  hb_buffer_cluster_level_t cluster_level;
   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. */
 
   /* Buffer contents */
   hb_buffer_content_type_t content_type;
@@ -75,8 +105,8 @@
   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 - 1]; }
-  inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
+  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; }
 
@@ -93,6 +123,11 @@
   hb_codepoint_t context[2][CONTEXT_LENGTH];
   unsigned int context_len[2];
 
+  /* Debugging */
+  hb_buffer_message_func_t message_func;
+  void *message_data;
+  hb_destroy_func_t message_destroy;
+
 
   /* Methods */
 
@@ -171,9 +206,18 @@
 			      unsigned int cluster_end);
 
   HB_INTERNAL void merge_clusters (unsigned int start,
-				   unsigned int end);
+				   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);
+  /* Merge clusters for deleting current glyph, and skip it. */
+  HB_INTERNAL void delete_glyph (void);
 
   /* Internal methods */
   HB_INTERNAL bool enlarge (unsigned int size);
@@ -191,6 +235,21 @@
   HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
 
   inline void clear_context (unsigned int side) { context_len[side] = 0; }
+
+  HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
+
+  inline bool messaging (void) { return unlikely (message_func); }
+  inline bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
+  {
+    if (!messaging ())
+      return true;
+    va_list ap;
+    va_start (ap, fmt);
+    bool ret = message_impl (font, fmt, ap);
+    va_end (ap);
+    return ret;
+  }
+  HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
 };
 
 
diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc
index 406d69d..63a0f34 100644
--- a/src/hb-buffer-serialize.cc
+++ b/src/hb-buffer-serialize.cc
@@ -36,11 +36,12 @@
 /**
  * hb_buffer_serialize_list_formats:
  *
- * 
+ * Returns a list of supported buffer serialization formats.
  *
  * Return value: (transfer none):
+ * A string array of buffer serialization formats. Should not be freed.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 const char **
 hb_buffer_serialize_list_formats (void)
@@ -50,14 +51,17 @@
 
 /**
  * hb_buffer_serialize_format_from_string:
- * @str: 
- * @len: 
+ * @str: (array length=len) (element-type uint8_t): a string to parse
+ * @len: length of @str, or -1 if string is %NULL terminated
  *
- * 
+ * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
+ * @str is a valid buffer serialization format, use
+ * hb_buffer_serialize_list_formats() to get the list of supported formats.
  *
  * Return value: 
+ * The parsed #hb_buffer_serialize_format_t.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_buffer_serialize_format_t
 hb_buffer_serialize_format_from_string (const char *str, int len)
@@ -68,13 +72,15 @@
 
 /**
  * hb_buffer_serialize_format_to_string:
- * @format: 
+ * @format: an #hb_buffer_serialize_format_t to convert.
  *
- * 
+ * Converts @format to the string corresponding it, or %NULL if it is not a valid
+ * #hb_buffer_serialize_format_t.
  *
- * Return value: 
+ * Return value: (transfer none):
+ * A %NULL terminated string corresponding to @format. Should not be freed.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 const char *
 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
@@ -99,7 +105,8 @@
 				  hb_buffer_serialize_flags_t flags)
 {
   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
-  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
+  hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
+			     NULL : hb_buffer_get_glyph_positions (buffer, NULL);
 
   *buf_consumed = 0;
   for (unsigned int i = start; i < end; i++)
@@ -144,6 +151,16 @@
 		     pos[i].x_advance, pos[i].y_advance);
     }
 
+    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
+    {
+      hb_glyph_extents_t extents;
+      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
+        extents.x_bearing, extents.y_bearing));
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
+        extents.width, extents.height));
+    }
+
     *p++ = '}';
 
     unsigned int l = p - b;
@@ -172,7 +189,8 @@
 				  hb_buffer_serialize_flags_t flags)
 {
   hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
-  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
+  hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
+			     NULL : hb_buffer_get_glyph_positions (buffer, NULL);
 
   *buf_consumed = 0;
   for (unsigned int i = start; i < end; i++)
@@ -208,6 +226,13 @@
 	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
     }
 
+    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
+    {
+      hb_glyph_extents_t extents;
+      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
+    }
+
     unsigned int l = p - b;
     if (buf_size > l)
     {
@@ -223,24 +248,51 @@
   return end - start;
 }
 
-/* Returns number of items, starting at start, that were serialized. */
 /**
  * hb_buffer_serialize_glyphs:
- * @buffer: a buffer.
- * @start: 
- * @end: 
- * @buf: (array length=buf_size):
- * @buf_size: 
- * @buf_consumed: (out):
- * @font: 
- * @format: 
- * @flags: 
+ * @buffer: an #hb_buffer_t buffer.
+ * @start: the first item in @buffer to serialize.
+ * @end: the last item in @buffer to serialize.
+ * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
+ *       write serialized buffer into.
+ * @buf_size: the size of @buf.
+ * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
+ * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
+ *        read glyph names and extents. If %NULL, and empty font will be used.
+ * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
+ * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
+ *         to serialize.
  *
- * 
+ * Serializes @buffer into a textual representation of its glyph content,
+ * useful for showing the contents of the buffer, for example during debugging.
+ * There are currently two supported serialization formats:
+ *
+ * ## text
+ * A human-readable, plain text format.
+ * The serialized glyphs will look something like:
+ *
+ * ```
+ * [uni0651=0@518,0+0|uni0628=0+1897]
+ * ```
+ * - The serialized glyphs are delimited with `[` and `]`.
+ * - Glyphs are separated with `|`
+ * - Each glyph starts with glyph name, or glyph index if
+ *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
+ *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
+ *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
+ *     - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
+ *     - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
+ *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the
+ *     #hb_glyph_extents_t in the format
+ *     `&lt;x_bearing,y_bearing,width,height&gt;`
+ *
+ * ## json
+ * TODO.
  *
  * Return value: 
+ * The number of serialized items.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 unsigned int
 hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
@@ -248,8 +300,8 @@
 			    unsigned int end,
 			    char *buf,
 			    unsigned int buf_size,
-			    unsigned int *buf_consumed, /* May be NULL */
-			    hb_font_t *font, /* May be NULL */
+			    unsigned int *buf_consumed,
+			    hb_font_t *font,
 			    hb_buffer_serialize_format_t format,
 			    hb_buffer_serialize_flags_t flags)
 {
@@ -263,6 +315,9 @@
   assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
 	  buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
 
+  if (!buffer->have_positions)
+    flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
+
   if (unlikely (start == end))
     return 0;
 
@@ -336,7 +391,7 @@
 
 /**
  * hb_buffer_deserialize_glyphs:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t buffer.
  * @buf: (array length=buf_len):
  * @buf_len: 
  * @end_ptr: (out):
@@ -347,7 +402,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_bool_t
 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 7bf232d..5f320bd 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -35,7 +35,28 @@
 #define HB_DEBUG_BUFFER (HB_DEBUG+0)
 #endif
 
+/**
+ * SECTION: hb-buffer
+ * @title: Buffers
+ * @short_description: Input and output buffers
+ * @include: hb.h
+ *
+ * Buffers serve dual role in HarfBuzz; they hold the input characters that are
+ * passed hb_shape(), and after shaping they hold the output glyphs.
+ **/
 
+/**
+ * hb_segment_properties_equal:
+ * @a: first #hb_segment_properties_t to compare.
+ * @b: second #hb_segment_properties_t to compare.
+ *
+ * Checks the equality of two #hb_segment_properties_t's.
+ *
+ * Return value: (transfer full):
+ * %true if all properties of @a equal those of @b, false otherwise.
+ *
+ * Since: 0.9.7
+ **/
 hb_bool_t
 hb_segment_properties_equal (const hb_segment_properties_t *a,
 			     const hb_segment_properties_t *b)
@@ -48,6 +69,17 @@
 
 }
 
+/**
+ * hb_segment_properties_hash:
+ * @p: #hb_segment_properties_t to hash.
+ *
+ * Creates a hash representing @p.
+ *
+ * Return value:
+ * A hash of @p.
+ *
+ * Since: 0.9.7
+ **/
 unsigned int
 hb_segment_properties_hash (const hb_segment_properties_t *p)
 {
@@ -85,6 +117,11 @@
 {
   if (unlikely (in_error))
     return false;
+  if (unlikely (size > max_len))
+  {
+    in_error = true;
+    return false;
+  }
 
   unsigned int new_allocated = allocated;
   hb_glyph_position_t *new_pos = NULL;
@@ -192,6 +229,7 @@
 
   hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
   props = default_props;
+  scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
 
   content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
   in_error = false;
@@ -369,6 +407,8 @@
     idx = i;
     return true;
   }
+  if (unlikely (in_error))
+    return false;
 
   assert (i <= out_len + (len - idx));
 
@@ -443,7 +483,7 @@
 {
   unsigned int i, j;
 
-  if (start == end - 1)
+  if (end - start < 2)
     return;
 
   for (i = start, j = end - 1; i < j; i++, j--) {
@@ -454,7 +494,7 @@
     info[j] = t;
   }
 
-  if (pos) {
+  if (have_positions) {
     for (i = start, j = end - 1; i < j; i++, j--) {
       hb_glyph_position_t t;
 
@@ -498,14 +538,10 @@
 }
 
 void
-hb_buffer_t::merge_clusters (unsigned int start,
-			     unsigned int end)
+hb_buffer_t::merge_clusters_impl (unsigned int start,
+				  unsigned int end)
 {
-#ifdef HB_NO_MERGE_CLUSTERS
-  return;
-#endif
-
-  if (unlikely (end - start < 2))
+  if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
     return;
 
   unsigned int cluster = info[start].cluster;
@@ -523,7 +559,7 @@
 
   /* If we hit the start of buffer, continue in out-buffer. */
   if (idx == start)
-    for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
+    for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
       out_info[i - 1].cluster = cluster;
 
   for (unsigned int i = start; i < end; i++)
@@ -533,9 +569,8 @@
 hb_buffer_t::merge_out_clusters (unsigned int start,
 				 unsigned int end)
 {
-#ifdef HB_NO_MERGE_CLUSTERS
-  return;
-#endif
+  if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+    return;
 
   if (unlikely (end - start < 2))
     return;
@@ -555,12 +590,44 @@
 
   /* If we hit the end of out-buffer, continue in buffer. */
   if (end == out_len)
-    for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
+    for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
       info[i].cluster = cluster;
 
   for (unsigned int i = start; i < end; i++)
     out_info[i].cluster = cluster;
 }
+void
+hb_buffer_t::delete_glyph ()
+{
+  unsigned int cluster = info[idx].cluster;
+  if (idx + 1 < len && cluster == info[idx + 1].cluster)
+  {
+    /* Cluster survives; do nothing. */
+    goto done;
+  }
+
+  if (out_len)
+  {
+    /* Merge cluster backward. */
+    if (cluster < out_info[out_len - 1].cluster)
+    {
+      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;
+    }
+    goto done;
+  }
+
+  if (idx + 1 < len)
+  {
+    /* Merge cluster forward. */
+    merge_clusters (idx, idx + 2);
+    goto done;
+  }
+
+done:
+  skip_glyph ();
+}
 
 void
 hb_buffer_t::guess_segment_properties (void)
@@ -667,11 +734,16 @@
 /**
  * hb_buffer_create: (Xconstructor)
  *
- * 
+ * Creates a new #hb_buffer_t with all properties to defaults.
  *
- * Return value: (transfer full)
+ * Return value: (transfer full):
+ * A newly allocated #hb_buffer_t with a reference count of 1. The initial
+ * reference count should be released with hb_buffer_destroy() when you are done
+ * using the #hb_buffer_t. This function never returns %NULL. If memory cannot
+ * be allocated, a special #hb_buffer_t object will be returned on which
+ * hb_buffer_allocation_successful() returns %false.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_buffer_t *
 hb_buffer_create (void)
@@ -681,6 +753,8 @@
   if (!(buffer = hb_object_create<hb_buffer_t> ()))
     return hb_buffer_get_empty ();
 
+  buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+
   buffer->reset ();
 
   return buffer;
@@ -693,7 +767,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_buffer_t *
 hb_buffer_get_empty (void)
@@ -703,7 +777,10 @@
 
     const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
     HB_BUFFER_FLAG_DEFAULT,
+    HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
     HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
+    HB_BUFFER_SCRATCH_FLAG_DEFAULT,
+    HB_BUFFER_MAX_LEN_DEFAULT,
 
     HB_BUFFER_CONTENT_TYPE_INVALID,
     HB_SEGMENT_PROPERTIES_DEFAULT,
@@ -719,13 +796,15 @@
 
 /**
  * hb_buffer_reference: (skip)
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * Increases the reference count on @buffer by one. This prevents @buffer from
+ * being destroyed until a matching call to hb_buffer_destroy() is made.
  *
  * Return value: (transfer full):
+ * The referenced #hb_buffer_t.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_buffer_t *
 hb_buffer_reference (hb_buffer_t *buffer)
@@ -735,11 +814,13 @@
 
 /**
  * hb_buffer_destroy: (skip)
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * Deallocate the @buffer.
+ * Decreases the reference count on @buffer by one. If the result is zero, then
+ * @buffer and all associated resources are freed. See hb_buffer_reference().
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_buffer_destroy (hb_buffer_t *buffer)
@@ -750,13 +831,15 @@
 
   free (buffer->info);
   free (buffer->pos);
+  if (buffer->message_destroy)
+    buffer->message_destroy (buffer->message_data);
 
   free (buffer);
 }
 
 /**
  * hb_buffer_set_user_data: (skip)
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  * @key: 
  * @data: 
  * @destroy: 
@@ -766,7 +849,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_buffer_set_user_data (hb_buffer_t        *buffer,
@@ -780,14 +863,14 @@
 
 /**
  * hb_buffer_get_user_data: (skip)
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  * @key: 
  *
  * 
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void *
 hb_buffer_get_user_data (hb_buffer_t        *buffer,
@@ -799,12 +882,13 @@
 
 /**
  * hb_buffer_set_content_type:
- * @buffer: a buffer.
- * @content_type: 
+ * @buffer: an #hb_buffer_t.
+ * @content_type: the type of buffer contents to set
  *
- * 
+ * Sets the type of @buffer contents, buffers are either empty, contain
+ * characters (before shaping) or glyphs (the result of shaping).
  *
- * Since: 1.0
+ * Since: 0.9.5
  **/
 void
 hb_buffer_set_content_type (hb_buffer_t              *buffer,
@@ -815,13 +899,14 @@
 
 /**
  * hb_buffer_get_content_type:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * see hb_buffer_set_content_type().
  *
- * Return value: 
+ * Return value:
+ * The type of @buffer contents.
  *
- * Since: 1.0
+ * Since: 0.9.5
  **/
 hb_buffer_content_type_t
 hb_buffer_get_content_type (hb_buffer_t *buffer)
@@ -832,12 +917,12 @@
 
 /**
  * hb_buffer_set_unicode_funcs:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  * @unicode_funcs: 
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
@@ -857,13 +942,13 @@
 
 /**
  * hb_buffer_get_unicode_funcs:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
  * 
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_unicode_funcs_t *
 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
@@ -873,12 +958,18 @@
 
 /**
  * hb_buffer_set_direction:
- * @buffer: a buffer.
- * @direction: 
+ * @buffer: an #hb_buffer_t.
+ * @direction: the #hb_direction_t of the @buffer
  *
- * 
+ * Set the text flow direction of the buffer. No shaping can happen without
+ * setting @buffer direction, and it controls the visual direction for the
+ * output glyphs; for RTL direction the glyphs will be reversed. Many layout
+ * features depend on the proper setting of the direction, for example,
+ * reversing RTL text before shaping, then shaping with LTR direction is not
+ * the same as keeping the text in logical order and shaping with RTL
+ * direction.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_buffer_set_direction (hb_buffer_t    *buffer,
@@ -893,13 +984,14 @@
 
 /**
  * hb_buffer_get_direction:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * See hb_buffer_set_direction()
  *
- * Return value: 
+ * Return value:
+ * The direction of the @buffer.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_direction_t
 hb_buffer_get_direction (hb_buffer_t    *buffer)
@@ -909,12 +1001,20 @@
 
 /**
  * hb_buffer_set_script:
- * @buffer: a buffer.
- * @script: 
+ * @buffer: an #hb_buffer_t.
+ * @script: an #hb_script_t to set.
  *
- * 
+ * Sets the script of @buffer to @script.
  *
- * Since: 1.0
+ * Script is crucial for choosing the proper shaping behaviour for scripts that
+ * require it (e.g. Arabic) and the which OpenType features defined in the font
+ * to be applied.
+ *
+ * You can pass one of the predefined #hb_script_t values, or use
+ * hb_script_from_string() or hb_script_from_iso15924_tag() to get the
+ * corresponding script from an ISO 15924 script tag.
+ *
+ * Since: 0.9.2
  **/
 void
 hb_buffer_set_script (hb_buffer_t *buffer,
@@ -928,13 +1028,14 @@
 
 /**
  * hb_buffer_get_script:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * See hb_buffer_set_script().
  *
- * Return value: 
+ * Return value:
+ * The #hb_script_t of the @buffer.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_script_t
 hb_buffer_get_script (hb_buffer_t *buffer)
@@ -944,12 +1045,20 @@
 
 /**
  * hb_buffer_set_language:
- * @buffer: a buffer.
- * @language: 
+ * @buffer: an #hb_buffer_t.
+ * @language: an hb_language_t to set.
  *
- * 
+ * Sets the language of @buffer to @language.
  *
- * Since: 1.0
+ * Languages are crucial for selecting which OpenType feature to apply to the
+ * buffer which can result in applying language-specific behaviour. Languages
+ * are orthogonal to the scripts, and though they are related, they are
+ * different concepts and should not be confused with each other.
+ *
+ * Use hb_language_from_string() to convert from ISO 639 language codes to
+ * #hb_language_t.
+ *
+ * Since: 0.9.2
  **/
 void
 hb_buffer_set_language (hb_buffer_t   *buffer,
@@ -963,13 +1072,14 @@
 
 /**
  * hb_buffer_get_language:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * See hb_buffer_set_language().
  *
- * Return value: 
+ * Return value: (transfer none):
+ * The #hb_language_t of the buffer. Must not be freed by the caller.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_language_t
 hb_buffer_get_language (hb_buffer_t *buffer)
@@ -979,12 +1089,14 @@
 
 /**
  * hb_buffer_set_segment_properties:
- * @buffer: a buffer.
- * @props: 
+ * @buffer: an #hb_buffer_t.
+ * @props: an #hb_segment_properties_t to use.
  *
- * 
+ * Sets the segment properties of the buffer, a shortcut for calling
+ * hb_buffer_set_direction(), hb_buffer_set_script() and
+ * hb_buffer_set_language() individually.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 void
 hb_buffer_set_segment_properties (hb_buffer_t *buffer,
@@ -998,12 +1110,12 @@
 
 /**
  * hb_buffer_get_segment_properties:
- * @buffer: a buffer.
- * @props: 
+ * @buffer: an #hb_buffer_t.
+ * @props: (out): the output #hb_segment_properties_t.
  *
- * 
+ * Sets @props to the #hb_segment_properties_t of @buffer.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 void
 hb_buffer_get_segment_properties (hb_buffer_t *buffer,
@@ -1015,12 +1127,12 @@
 
 /**
  * hb_buffer_set_flags:
- * @buffer: a buffer.
- * @flags: 
+ * @buffer: an #hb_buffer_t.
+ * @flags: the buffer flags to set.
  *
- * 
+ * Sets @buffer flags to @flags. See #hb_buffer_flags_t.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 void
 hb_buffer_set_flags (hb_buffer_t       *buffer,
@@ -1034,13 +1146,14 @@
 
 /**
  * hb_buffer_get_flags:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * See hb_buffer_set_flags().
  *
  * Return value: 
+ * The @buffer flags.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_buffer_flags_t
 hb_buffer_get_flags (hb_buffer_t *buffer)
@@ -1048,15 +1161,53 @@
   return buffer->flags;
 }
 
-
 /**
- * hb_buffer_set_replacement_codepoint:
- * @buffer: a buffer.
- * @replacement: 
+ * hb_buffer_set_cluster_level:
+ * @buffer: an #hb_buffer_t.
+ * @cluster_level: 
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.42
+ **/
+void
+hb_buffer_set_cluster_level (hb_buffer_t       *buffer,
+		     hb_buffer_cluster_level_t  cluster_level)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->cluster_level = cluster_level;
+}
+
+/**
+ * hb_buffer_get_cluster_level:
+ * @buffer: an #hb_buffer_t.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 0.9.42
+ **/
+hb_buffer_cluster_level_t
+hb_buffer_get_cluster_level (hb_buffer_t *buffer)
+{
+  return buffer->cluster_level;
+}
+
+
+/**
+ * hb_buffer_set_replacement_codepoint:
+ * @buffer: an #hb_buffer_t.
+ * @replacement: the replacement #hb_codepoint_t
+ *
+ * Sets the #hb_codepoint_t that replaces invalid entries for a given encoding
+ * when adding text to @buffer.
+ *
+ * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
+ *
+ * Since: 0.9.31
  **/
 void
 hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
@@ -1070,13 +1221,14 @@
 
 /**
  * hb_buffer_get_replacement_codepoint:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * See hb_buffer_set_replacement_codepoint().
  *
  * Return value: 
+ * The @buffer replacement #hb_codepoint_t.
  *
- * Since: 1.0
+ * Since: 0.9.31
  **/
 hb_codepoint_t
 hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer)
@@ -1087,11 +1239,12 @@
 
 /**
  * hb_buffer_reset:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * Resets the buffer to its initial status, as if it was just newly created
+ * with hb_buffer_create().
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_buffer_reset (hb_buffer_t *buffer)
@@ -1101,11 +1254,12 @@
 
 /**
  * hb_buffer_clear_contents:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * Similar to hb_buffer_reset(), but does not clear the Unicode functions and
+ * the replacement code point.
  *
- * Since: 1.0
+ * Since: 0.9.11
  **/
 void
 hb_buffer_clear_contents (hb_buffer_t *buffer)
@@ -1115,14 +1269,15 @@
 
 /**
  * hb_buffer_pre_allocate:
- * @buffer: a buffer.
- * @size: 
+ * @buffer: an #hb_buffer_t.
+ * @size: number of items to pre allocate.
  *
- * 
+ * Pre allocates memory for @buffer to fit at least @size number of items.
  *
- * Return value: 
+ * Return value:
+ * %true if @buffer memory allocation succeeded, %false otherwise.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
@@ -1132,13 +1287,14 @@
 
 /**
  * hb_buffer_allocation_successful:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * Check if allocating memory for the buffer succeeded.
  *
- * Return value: 
+ * Return value:
+ * %true if @buffer memory allocation succeeded, %false otherwise.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_buffer_allocation_successful (hb_buffer_t  *buffer)
@@ -1148,13 +1304,20 @@
 
 /**
  * hb_buffer_add:
- * @buffer: a buffer.
- * @codepoint: 
- * @cluster: 
+ * @buffer: an #hb_buffer_t.
+ * @codepoint: a Unicode code point.
+ * @cluster: the cluster value of @codepoint.
  *
- * 
+ * Appends a character with the Unicode value of @codepoint to @buffer, and
+ * gives it the initial cluster value of @cluster. Clusters can be any thing
+ * the client wants, they are usually used to refer to the index of the
+ * character in the input text stream and are output in
+ * #hb_glyph_info_t.cluster field.
  *
- * Since: 1.0
+ * This function does not check the validity of @codepoint, it is up to the
+ * caller to ensure it is a valid Unicode code point.
+ *
+ * Since: 0.9.7
  **/
 void
 hb_buffer_add (hb_buffer_t    *buffer,
@@ -1167,14 +1330,16 @@
 
 /**
  * hb_buffer_set_length:
- * @buffer: a buffer.
- * @length: 
+ * @buffer: an #hb_buffer_t.
+ * @length: the new length of @buffer.
  *
- * 
+ * Similar to hb_buffer_pre_allocate(), but clears any new items added at the
+ * end.
  *
  * Return value: 
+ * %true if @buffer memory allocation succeeded, %false otherwise.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_buffer_set_length (hb_buffer_t  *buffer,
@@ -1207,13 +1372,15 @@
 
 /**
  * hb_buffer_get_length:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
  * Returns the number of items in the buffer.
  *
- * Return value: buffer length.
+ * Return value:
+ * The @buffer length.
+ * The value valid as long as buffer has not been modified.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 unsigned int
 hb_buffer_get_length (hb_buffer_t *buffer)
@@ -1223,15 +1390,17 @@
 
 /**
  * hb_buffer_get_glyph_infos:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  * @length: (out): output array length.
  *
- * Returns buffer glyph information array.  Returned pointer
- * is valid as long as buffer contents are not modified.
+ * Returns @buffer glyph information array.  Returned pointer
+ * is valid as long as @buffer contents are not modified.
  *
- * Return value: (transfer none) (array length=length): buffer glyph information array.
+ * Return value: (transfer none) (array length=length):
+ * The @buffer glyph information array.
+ * The value valid as long as buffer has not been modified.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_glyph_info_t *
 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
@@ -1245,15 +1414,17 @@
 
 /**
  * hb_buffer_get_glyph_positions:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  * @length: (out): output length.
  *
- * Returns buffer glyph position array.  Returned pointer
- * is valid as long as buffer contents are not modified.
+ * Returns @buffer glyph position array.  Returned pointer
+ * is valid as long as @buffer contents are not modified.
  *
- * Return value: (transfer none) (array length=length): buffer glyph position array.
+ * Return value: (transfer none) (array length=length):
+ * The @buffer glyph position array.
+ * The value valid as long as buffer has not been modified.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_glyph_position_t *
 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
@@ -1270,11 +1441,11 @@
 
 /**
  * hb_buffer_reverse:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
  * Reverses buffer contents.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_buffer_reverse (hb_buffer_t *buffer)
@@ -1283,14 +1454,31 @@
 }
 
 /**
+ * hb_buffer_reverse_range:
+ * @buffer: an #hb_buffer_t.
+ * @start: start index.
+ * @end: end index.
+ *
+ * Reverses buffer contents between start to end.
+ *
+ * Since: 0.9.41
+ **/
+void
+hb_buffer_reverse_range (hb_buffer_t *buffer,
+			 unsigned int start, unsigned int end)
+{
+  buffer->reverse_range (start, end);
+}
+
+/**
  * hb_buffer_reverse_clusters:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
  * Reverses buffer clusters.  That is, the buffer contents are
  * reversed, then each cluster (consecutive items having the
  * same cluster number) are reversed again.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
@@ -1300,7 +1488,7 @@
 
 /**
  * hb_buffer_guess_segment_properties:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
  * Sets unset buffer segment properties based on buffer Unicode
  * contents.  If buffer is not empty, it must have content type
@@ -1320,7 +1508,7 @@
  * hb_language_get_default().  This may change in the future by
  * taking buffer script into consideration when choosing a language.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 void
 hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
@@ -1328,15 +1516,15 @@
   buffer->guess_segment_properties ();
 }
 
-template <bool validate, typename T>
+template <typename utf_t>
 static inline void
 hb_buffer_add_utf (hb_buffer_t  *buffer,
-		   const T      *text,
+		   const typename utf_t::codepoint_t *text,
 		   int           text_length,
 		   unsigned int  item_offset,
 		   int           item_length)
 {
-  typedef hb_utf_t<T, true> utf_t;
+  typedef typename utf_t::codepoint_t T;
   const hb_codepoint_t replacement = buffer->replacement;
 
   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
@@ -1399,15 +1587,20 @@
 
 /**
  * hb_buffer_add_utf8:
- * @buffer: a buffer.
- * @text: (array length=text_length) (element-type uint8_t):
- * @text_length: 
- * @item_offset: 
- * @item_length: 
+ * @buffer: an #hb_buffer_t.
+ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
+ *               characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
  *
- * 
+ * See hb_buffer_add_codepoints().
  *
- * Since: 1.0
+ * Replaces invalid UTF-8 characters with the @buffer replacement code point,
+ * see hb_buffer_set_replacement_codepoint().
+ *
+ * Since: 0.9.2
  **/
 void
 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
@@ -1416,20 +1609,24 @@
 		    unsigned int  item_offset,
 		    int           item_length)
 {
-  hb_buffer_add_utf<true> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
+  hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
 }
 
 /**
  * hb_buffer_add_utf16:
- * @buffer: a buffer.
- * @text: (array length=text_length):
- * @text_length: 
- * @item_offset: 
- * @item_length: 
+ * @buffer: an #hb_buffer_t.
+ * @text: (array length=text_length): an array of UTF-16 characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
  *
- * 
+ * See hb_buffer_add_codepoints().
  *
- * Since: 1.0
+ * Replaces invalid UTF-16 characters with the @buffer replacement code point,
+ * see hb_buffer_set_replacement_codepoint().
+ *
+ * Since: 0.9.2
  **/
 void
 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
@@ -1438,20 +1635,24 @@
 		     unsigned int    item_offset,
 		     int             item_length)
 {
-  hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
+  hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);
 }
 
 /**
  * hb_buffer_add_utf32:
- * @buffer: a buffer.
- * @text: (array length=text_length):
- * @text_length: 
- * @item_offset: 
- * @item_length: 
+ * @buffer: an #hb_buffer_t.
+ * @text: (array length=text_length): an array of UTF-32 characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
  *
- * 
+ * See hb_buffer_add_codepoints().
  *
- * Since: 1.0
+ * Replaces invalid UTF-32 characters with the @buffer replacement code point,
+ * see hb_buffer_set_replacement_codepoint().
+ *
+ * Since: 0.9.2
  **/
 void
 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
@@ -1460,20 +1661,59 @@
 		     unsigned int    item_offset,
 		     int             item_length)
 {
-  hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
+  hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
+}
+
+/**
+ * hb_buffer_add_latin1:
+ * @buffer: an #hb_buffer_t.
+ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
+ *               characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
+ *
+ * Similar to hb_buffer_add_codepoints(), but allows only access to first 256
+ * Unicode code points that can fit in 8-bit strings.
+ *
+ * <note>Has nothing to do with non-Unicode Latin-1 encoding.</note>
+ *
+ * Since: 0.9.39
+ **/
+void
+hb_buffer_add_latin1 (hb_buffer_t   *buffer,
+		      const uint8_t *text,
+		      int            text_length,
+		      unsigned int   item_offset,
+		      int            item_length)
+{
+  hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);
 }
 
 /**
  * hb_buffer_add_codepoints:
- * @buffer: a buffer.
- * @text: (array length=text_length):
- * @text_length: 
- * @item_offset: 
- * @item_length: 
+ * @buffer: a #hb_buffer_t to append characters to.
+ * @text: (array length=text_length): an array of Unicode code points to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first code point to add to the @buffer.
+ * @item_length: the number of code points to add to the @buffer, or -1 for the
+ *               end of @text (assuming it is %NULL terminated).
  *
- * 
+ * Appends characters from @text array to @buffer. The @item_offset is the
+ * position of the first character from @text that will be appended, and
+ * @item_length is the number of character. When shaping part of a larger text
+ * (e.g. a run of text from a paragraph), instead of passing just the substring
+ * corresponding to the run, it is preferable to pass the whole
+ * paragraph and specify the run start and length as @item_offset and
+ * @item_length, respectively, to give HarfBuzz the full context to be able,
+ * for example, to do cross-run Arabic shaping or properly handle combining
+ * marks at stat of run.
  *
- * Since: 1.0
+ * This function does not check the validity of @text, it is up to the caller
+ * to ensure it contains a valid Unicode code points.
+ *
+ * Since: 0.9.31
  **/
 void
 hb_buffer_add_codepoints (hb_buffer_t          *buffer,
@@ -1482,7 +1722,7 @@
 			  unsigned int          item_offset,
 			  int                   item_length)
 {
-  hb_buffer_add_utf<false> (buffer, text, text_length, item_offset, item_length);
+  hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
 }
 
 
@@ -1528,7 +1768,7 @@
     pos[end - 1].x_advance = total_x_advance;
     pos[end - 1].y_advance = total_y_advance;
 
-    hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
+    hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
   } else {
     /* Transfer all cluster advance to the first glyph. */
     pos[start].x_advance += total_x_advance;
@@ -1537,17 +1777,20 @@
       pos[i].x_offset -= total_x_advance;
       pos[i].y_offset -= total_y_advance;
     }
-    hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
+    hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
   }
 }
 
 /**
  * hb_buffer_normalize_glyphs:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
  *
- * 
+ * Reorders a glyph buffer to have canonical in-cluster glyph order / position.
+ * The resulting clusters should behave identical to pre-reordering clusters.
  *
- * Since: 1.0
+ * <note>This has nothing to do with Unicode normalization.</note>
+ *
+ * Since: 0.9.2
  **/
 void
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
@@ -1570,3 +1813,66 @@
     }
   normalize_glyphs_cluster (buffer, start, end, backward);
 }
+
+void
+hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))
+{
+  assert (!have_positions);
+  for (unsigned int i = start + 1; i < end; i++)
+  {
+    unsigned int j = i;
+    while (j > start && compar (&info[j - 1], &info[i]) > 0)
+      j--;
+    if (i == j)
+      continue;
+    /* Move item i to occupy place for item j, shift what's in between. */
+    merge_clusters (j, i + 1);
+    {
+      hb_glyph_info_t t = info[i];
+      memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));
+      info[j] = t;
+    }
+  }
+}
+
+/*
+ * Debugging.
+ */
+
+/**
+ * hb_buffer_set_message_func:
+ * @buffer: an #hb_buffer_t.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.1.3
+ **/
+void
+hb_buffer_set_message_func (hb_buffer_t *buffer,
+			    hb_buffer_message_func_t func,
+			    void *user_data, hb_destroy_func_t destroy)
+{
+  if (buffer->message_destroy)
+    buffer->message_destroy (buffer->message_data);
+
+  if (func) {
+    buffer->message_func = func;
+    buffer->message_data = user_data;
+    buffer->message_destroy = destroy;
+  } else {
+    buffer->message_func = NULL;
+    buffer->message_data = NULL;
+    buffer->message_destroy = NULL;
+  }
+}
+
+bool
+hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
+{
+  char buf[100];
+  vsnprintf (buf, sizeof (buf),  fmt, ap);
+  return (bool) this->message_func (this, font, buf, this->message_data);
+}
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index 7b0c920..bf289c1 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -40,7 +40,27 @@
 
 HB_BEGIN_DECLS
 
-
+/**
+ * hb_glyph_info_t:
+ * @codepoint: either a Unicode code point (before shaping) or a glyph index
+ *             (after shaping).
+ * @mask: 
+ * @cluster: the index of the character in the original text that corresponds
+ *           to this #hb_glyph_info_t, or whatever the client passes to
+ *           hb_buffer_add(). More than one #hb_glyph_info_t can have the same
+ *           @cluster value, if they resulted from the same character (e.g. one
+ *           to many glyph substitution), and when more than one character gets
+ *           merged in the same glyph (e.g. many to one glyph substitution) the
+ *           #hb_glyph_info_t will have the smallest cluster value of them.
+ *           By default some characters are merged into the same cluster
+ *           (e.g. combining marks have the same cluster as their bases)
+ *           even if they are separate glyphs, hb_buffer_set_cluster_level()
+ *           allow selecting more fine-grained cluster handling.
+ *
+ * The #hb_glyph_info_t is the structure that holds information about the
+ * glyphs and their relation to input text.
+ *
+ */
 typedef struct hb_glyph_info_t {
   hb_codepoint_t codepoint;
   hb_mask_t      mask;
@@ -51,6 +71,22 @@
   hb_var_int_t   var2;
 } hb_glyph_info_t;
 
+/**
+ * hb_glyph_position_t:
+ * @x_advance: how much the line advances after drawing this glyph when setting
+ *             text in horizontal direction.
+ * @y_advance: how much the line advances after drawing this glyph when setting
+ *             text in vertical direction.
+ * @x_offset: how much the glyph moves on the X-axis before drawing it, this
+ *            should not affect how much the line advances.
+ * @y_offset: how much the glyph moves on the Y-axis before drawing it, this
+ *            should not affect how much the line advances.
+ *
+ * The #hb_glyph_position_t is the structure that holds the positions of the
+ * glyph in both horizontal and vertical directions. All positions in
+ * #hb_glyph_position_t are relative to the current point.
+ *
+ */
 typedef struct hb_glyph_position_t {
   hb_position_t  x_advance;
   hb_position_t  y_advance;
@@ -61,7 +97,16 @@
   hb_var_int_t   var;
 } hb_glyph_position_t;
 
-
+/**
+ * hb_segment_properties_t:
+ * @direction: the #hb_direction_t of the buffer, see hb_buffer_set_direction().
+ * @script: the #hb_script_t of the buffer, see hb_buffer_set_script().
+ * @language: the #hb_language_t of the buffer, see hb_buffer_set_language().
+ *
+ * The structure that holds various text properties of an #hb_buffer_t. Can be
+ * set and retrieved using hb_buffer_set_segment_properties() and
+ * hb_buffer_get_segment_properties(), respectively.
+ */
 typedef struct hb_segment_properties_t {
   hb_direction_t  direction;
   hb_script_t     script;
@@ -77,100 +122,127 @@
 				       NULL, \
 				       NULL}
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_segment_properties_equal (const hb_segment_properties_t *a,
 			     const hb_segment_properties_t *b);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_segment_properties_hash (const hb_segment_properties_t *p);
 
 
 
-/*
- * hb_buffer_t
+/**
+ * hb_buffer_t:
+ *
+ * The main structure holding the input text and its properties before shaping,
+ * and output glyphs and their information after shaping.
  */
 
 typedef struct hb_buffer_t hb_buffer_t;
 
-hb_buffer_t *
+HB_EXTERN hb_buffer_t *
 hb_buffer_create (void);
 
-hb_buffer_t *
+HB_EXTERN hb_buffer_t *
 hb_buffer_get_empty (void);
 
-hb_buffer_t *
+HB_EXTERN hb_buffer_t *
 hb_buffer_reference (hb_buffer_t *buffer);
 
-void
+HB_EXTERN void
 hb_buffer_destroy (hb_buffer_t *buffer);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_buffer_set_user_data (hb_buffer_t        *buffer,
 			 hb_user_data_key_t *key,
 			 void *              data,
 			 hb_destroy_func_t   destroy,
 			 hb_bool_t           replace);
 
-void *
+HB_EXTERN void *
 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.
+ * @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping).
+ * @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping).
+ */
 typedef enum {
   HB_BUFFER_CONTENT_TYPE_INVALID = 0,
   HB_BUFFER_CONTENT_TYPE_UNICODE,
   HB_BUFFER_CONTENT_TYPE_GLYPHS
 } hb_buffer_content_type_t;
 
-void
+HB_EXTERN void
 hb_buffer_set_content_type (hb_buffer_t              *buffer,
 			    hb_buffer_content_type_t  content_type);
 
-hb_buffer_content_type_t
+HB_EXTERN hb_buffer_content_type_t
 hb_buffer_get_content_type (hb_buffer_t *buffer);
 
 
-void
+HB_EXTERN void
 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
 			     hb_unicode_funcs_t *unicode_funcs);
 
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer);
 
-void
+HB_EXTERN void
 hb_buffer_set_direction (hb_buffer_t    *buffer,
 			 hb_direction_t  direction);
 
-hb_direction_t
+HB_EXTERN hb_direction_t
 hb_buffer_get_direction (hb_buffer_t *buffer);
 
-void
+HB_EXTERN void
 hb_buffer_set_script (hb_buffer_t *buffer,
 		      hb_script_t  script);
 
-hb_script_t
+HB_EXTERN hb_script_t
 hb_buffer_get_script (hb_buffer_t *buffer);
 
-void
+HB_EXTERN void
 hb_buffer_set_language (hb_buffer_t   *buffer,
 			hb_language_t  language);
 
 
-hb_language_t
+HB_EXTERN hb_language_t
 hb_buffer_get_language (hb_buffer_t *buffer);
 
-void
+HB_EXTERN void
 hb_buffer_set_segment_properties (hb_buffer_t *buffer,
 				  const hb_segment_properties_t *props);
 
-void
+HB_EXTERN void
 hb_buffer_get_segment_properties (hb_buffer_t *buffer,
 				  hb_segment_properties_t *props);
 
-void
+HB_EXTERN void
 hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
 
 
+/**
+ * hb_buffer_flags_t:
+ * @HB_BUFFER_FLAG_DEFAULT: the default buffer flag.
+ * @HB_BUFFER_FLAG_BOT: flag indicating that special handling of the beginning
+ *                      of text paragraph can be applied to this buffer. Should usually
+ *                      be set, unless you are passing to the buffer only part
+ *                      of the text without the full context.
+ * @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text
+ *                      paragraph can be applied to this buffer, similar to
+ *                      @HB_BUFFER_FLAG_EOT.
+ * @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES:
+ *                      flag indication that character with Default_Ignorable
+ *                      Unicode property should use the corresponding glyph
+ *                      from the font, instead of hiding them (currently done
+ *                      by replacing them with the space glyph and zeroing the
+ *                      advance width.)
+ *
+ * Since: 0.9.20
+ */
 typedef enum { /*< flags >*/
   HB_BUFFER_FLAG_DEFAULT			= 0x00000000u,
   HB_BUFFER_FLAG_BOT				= 0x00000001u, /* Beginning-of-text */
@@ -178,83 +250,109 @@
   HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES	= 0x00000004u
 } hb_buffer_flags_t;
 
-void
+HB_EXTERN void
 hb_buffer_set_flags (hb_buffer_t       *buffer,
 		     hb_buffer_flags_t  flags);
 
-hb_buffer_flags_t
+HB_EXTERN hb_buffer_flags_t
 hb_buffer_get_flags (hb_buffer_t *buffer);
 
+/*
+ * Since: 0.9.42
+ */
+typedef enum {
+  HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES	= 0,
+  HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS	= 1,
+  HB_BUFFER_CLUSTER_LEVEL_CHARACTERS		= 2,
+  HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
+} hb_buffer_cluster_level_t;
 
+HB_EXTERN void
+hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
+			     hb_buffer_cluster_level_t  cluster_level);
 
+HB_EXTERN hb_buffer_cluster_level_t
+hb_buffer_get_cluster_level (hb_buffer_t *buffer);
+
+/**
+ * HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT:
+ *
+ * The default code point for replacing invalid characters in a given encoding.
+ * Set to U+FFFD REPLACEMENT CHARACTER.
+ *
+ * Since: 0.9.31
+ */
 #define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
 
-/* Sets codepoint used to replace invalid UTF-8/16/32 entries.
- * Default is 0xFFFDu. */
-void
+HB_EXTERN void
 hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
 				     hb_codepoint_t  replacement);
 
-hb_codepoint_t
+HB_EXTERN hb_codepoint_t
 hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer);
 
 
-/* Resets the buffer.  Afterwards it's as if it was just created,
- * except that it has a larger buffer allocated perhaps... */
-void
+HB_EXTERN void
 hb_buffer_reset (hb_buffer_t *buffer);
 
-/* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */
-void
+HB_EXTERN void
 hb_buffer_clear_contents (hb_buffer_t *buffer);
 
-/* Returns false if allocation failed */
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_buffer_pre_allocate (hb_buffer_t  *buffer,
 		        unsigned int  size);
 
 
-/* Returns false if allocation has failed before */
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_buffer_allocation_successful (hb_buffer_t  *buffer);
 
-void
+HB_EXTERN void
 hb_buffer_reverse (hb_buffer_t *buffer);
 
-void
+HB_EXTERN void
+hb_buffer_reverse_range (hb_buffer_t *buffer,
+			 unsigned int start, unsigned int end);
+
+HB_EXTERN void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer);
 
 
 /* Filling the buffer in */
 
-void
+HB_EXTERN void
 hb_buffer_add (hb_buffer_t    *buffer,
 	       hb_codepoint_t  codepoint,
 	       unsigned int    cluster);
 
-void
+HB_EXTERN void
 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
 		    const char   *text,
 		    int           text_length,
 		    unsigned int  item_offset,
 		    int           item_length);
 
-void
+HB_EXTERN void
 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
 		     const uint16_t *text,
 		     int             text_length,
 		     unsigned int    item_offset,
 		     int             item_length);
 
-void
+HB_EXTERN void
 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
 		     const uint32_t *text,
 		     int             text_length,
 		     unsigned int    item_offset,
 		     int             item_length);
 
-/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */
-void
+HB_EXTERN void
+hb_buffer_add_latin1 (hb_buffer_t   *buffer,
+		      const uint8_t *text,
+		      int            text_length,
+		      unsigned int   item_offset,
+		      int            item_length);
+
+HB_EXTERN void
 hb_buffer_add_codepoints (hb_buffer_t          *buffer,
 			  const hb_codepoint_t *text,
 			  int                   text_length,
@@ -262,32 +360,25 @@
 			  int                   item_length);
 
 
-/* Clears any new items added at the end */
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_buffer_set_length (hb_buffer_t  *buffer,
 		      unsigned int  length);
 
-/* Return value valid as long as buffer not modified */
-unsigned int
+HB_EXTERN unsigned int
 hb_buffer_get_length (hb_buffer_t *buffer);
 
 /* Getting glyphs out of the buffer */
 
-/* Return value valid as long as buffer not modified */
-hb_glyph_info_t *
+HB_EXTERN hb_glyph_info_t *
 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
                            unsigned int *length);
 
-/* Return value valid as long as buffer not modified */
-hb_glyph_position_t *
+HB_EXTERN hb_glyph_position_t *
 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
                                unsigned int *length);
 
 
-/* Reorders a glyph buffer to have canonical in-cluster glyph order / position.
- * The resulting clusters should behave identical to pre-reordering clusters.
- * NOTE: This has nothing to do with Unicode normalization. */
-void
+HB_EXTERN void
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
 
 
@@ -295,50 +386,87 @@
  * Serialize
  */
 
+/**
+ * hb_buffer_serialize_flags_t:
+ * @HB_BUFFER_SERIALIZE_FLAG_DEFAULT: serialize glyph names, clusters and positions.
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS: do not serialize glyph cluster.
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information.
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name.
+ * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents.
+ *
+ * Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
+ *
+ * Since: 0.9.20
+ */
 typedef enum { /*< flags >*/
   HB_BUFFER_SERIALIZE_FLAG_DEFAULT		= 0x00000000u,
   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_NO_GLYPH_NAMES	= 0x00000004u,
+  HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS	= 0x00000008u
 } hb_buffer_serialize_flags_t;
 
+/**
+ * hb_buffer_serialize_format_t:
+ * @HB_BUFFER_SERIALIZE_FORMAT_TEXT: a human-readable, plain text format.
+ * @HB_BUFFER_SERIALIZE_FORMAT_JSON: a machine-readable JSON format.
+ * @HB_BUFFER_SERIALIZE_FORMAT_INVALID: invalid format.
+ *
+ * The buffer serialization and de-serialization format used in
+ * hb_buffer_serialize_glyphs() and hb_buffer_deserialize_glyphs().
+ *
+ * Since: 0.9.2
+ */
 typedef enum {
   HB_BUFFER_SERIALIZE_FORMAT_TEXT	= HB_TAG('T','E','X','T'),
   HB_BUFFER_SERIALIZE_FORMAT_JSON	= HB_TAG('J','S','O','N'),
   HB_BUFFER_SERIALIZE_FORMAT_INVALID	= HB_TAG_NONE
 } hb_buffer_serialize_format_t;
 
-/* len=-1 means str is NUL-terminated. */
-hb_buffer_serialize_format_t
+HB_EXTERN hb_buffer_serialize_format_t
 hb_buffer_serialize_format_from_string (const char *str, int len);
 
-const char *
+HB_EXTERN const char *
 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
 
-const char **
+HB_EXTERN const char **
 hb_buffer_serialize_list_formats (void);
 
-/* Returns number of items, starting at start, that were serialized. */
-unsigned int
+HB_EXTERN unsigned int
 hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
 			    unsigned int start,
 			    unsigned int end,
 			    char *buf,
 			    unsigned int buf_size,
-			    unsigned int *buf_consumed, /* May be NULL */
-			    hb_font_t *font, /* May be NULL */
+			    unsigned int *buf_consumed,
+			    hb_font_t *font,
 			    hb_buffer_serialize_format_t format,
 			    hb_buffer_serialize_flags_t flags);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 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 */
+			      int buf_len,
+			      const char **end_ptr,
+			      hb_font_t *font,
 			      hb_buffer_serialize_format_t format);
 
 
+/*
+ * Debugging.
+ */
+
+typedef hb_bool_t	(*hb_buffer_message_func_t)	(hb_buffer_t *buffer,
+							 hb_font_t   *font,
+							 const char  *message,
+							 void        *user_data);
+
+HB_EXTERN void
+hb_buffer_set_message_func (hb_buffer_t *buffer,
+			    hb_buffer_message_func_t func,
+			    void *user_data, hb_destroy_func_t destroy);
+
+
 HB_END_DECLS
 
 #endif /* HB_BUFFER_H */
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 8837cef..140ee0a 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -57,14 +57,14 @@
 
 /**
  * hb_tag_from_string:
- * @str: (array length=len): 
+ * @str: (array length=len) (element-type uint8_t): 
  * @len: 
  *
  * 
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_tag_t
 hb_tag_from_string (const char *str, int len)
@@ -92,7 +92,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.5
  **/
 void
 hb_tag_to_string (hb_tag_t tag, char *buf)
@@ -115,14 +115,14 @@
 
 /**
  * hb_direction_from_string:
- * @str: (array length=len): 
+ * @str: (array length=len) (element-type uint8_t): 
  * @len: 
  *
  * 
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_direction_t
 hb_direction_from_string (const char *str, int len)
@@ -149,7 +149,7 @@
  *
  * Return value: (transfer none): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 const char *
 hb_direction_to_string (hb_direction_t direction)
@@ -179,7 +179,7 @@
   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
 };
 
-static hb_bool_t
+static bool
 lang_equal (hb_language_t  v1,
 	    const void    *v2)
 {
@@ -265,6 +265,7 @@
   *lang = key;
 
   if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
+    lang->finish ();
     free (lang);
     goto retry;
   }
@@ -280,46 +281,51 @@
 
 /**
  * hb_language_from_string:
- * @str: (array length=len): 
- * @len: 
+ * @str: (array length=len) (element-type uint8_t): a string representing
+ *       ISO 639 language code
+ * @len: length of the @str, or -1 if it is %NULL-terminated.
  *
- * 
+ * Converts @str representing an ISO 639 language code to the corresponding
+ * #hb_language_t.
  *
- * Return value: 
+ * Return value: (transfer none):
+ * The #hb_language_t corresponding to the ISO 639 language code.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_language_t
 hb_language_from_string (const char *str, int len)
 {
-  char strbuf[64];
-
   if (!str || !len || !*str)
     return HB_LANGUAGE_INVALID;
 
+  hb_language_item_t *item = NULL;
   if (len >= 0)
   {
     /* NUL-terminate it. */
+    char strbuf[64];
     len = MIN (len, (int) sizeof (strbuf) - 1);
     memcpy (strbuf, str, len);
     strbuf[len] = '\0';
-    str = strbuf;
+    item = lang_find_or_insert (strbuf);
   }
-
-  hb_language_item_t *item = lang_find_or_insert (str);
+  else
+    item = lang_find_or_insert (str);
 
   return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
 }
 
 /**
  * hb_language_to_string:
- * @language: 
+ * @language: an #hb_language_t to convert.
  *
- * 
+ * See hb_language_from_string().
  *
- * Return value: (transfer none): 
+ * Return value: (transfer none):
+ * A %NULL-terminated string representing the @language. Must not be freed by
+ * the caller.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 const char *
 hb_language_to_string (hb_language_t language)
@@ -333,9 +339,9 @@
  *
  * 
  *
- * Return value: 
+ * Return value: (transfer none):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_language_t
 hb_language_get_default (void)
@@ -356,13 +362,14 @@
 
 /**
  * hb_script_from_iso15924_tag:
- * @tag: 
+ * @tag: an #hb_tag_t representing an ISO 15924 tag.
  *
- * 
+ * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
  *
  * Return value: 
+ * An #hb_script_t corresponding to the ISO 15924 tag.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag)
@@ -400,30 +407,35 @@
 
 /**
  * hb_script_from_string:
- * @s: (array length=len): 
- * @len: 
+ * @str: (array length=len) (element-type uint8_t): a string representing an
+ *       ISO 15924 tag.
+ * @len: length of the @str, or -1 if it is %NULL-terminated.
  *
- * 
+ * Converts a string @str representing an ISO 15924 script tag to a
+ * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
+ * hb_script_from_iso15924_tag().
  *
  * Return value: 
+ * An #hb_script_t corresponding to the ISO 15924 tag.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_script_t
-hb_script_from_string (const char *s, int len)
+hb_script_from_string (const char *str, int len)
 {
-  return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
+  return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
 }
 
 /**
  * hb_script_to_iso15924_tag:
- * @script: 
+ * @script: an #hb_script_ to convert.
  *
- * 
+ * See hb_script_from_iso15924_tag().
  *
- * Return value: 
+ * Return value:
+ * An #hb_tag_t representing an ISO 15924 script tag.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_tag_t
 hb_script_to_iso15924_tag (hb_script_t script)
@@ -439,7 +451,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_direction_t
 hb_script_get_horizontal_direction (hb_script_t script)
@@ -492,6 +504,9 @@
     case HB_SCRIPT_PALMYRENE:
     case HB_SCRIPT_PSALTER_PAHLAVI:
 
+    /* Unicode-8.0 additions */
+    case HB_SCRIPT_OLD_HUNGARIAN:
+
       return HB_DIRECTION_RTL;
   }
 
@@ -517,7 +532,7 @@
     }
   }
   hb_user_data_item_t item = {key, data, destroy};
-  bool ret = !!items.replace_or_insert (item, lock, replace);
+  bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
 
   return ret;
 }
@@ -525,7 +540,7 @@
 void *
 hb_user_data_array_t::get (hb_user_data_key_t *key)
 {
-  hb_user_data_item_t item = {NULL };
+  hb_user_data_item_t item = {NULL, NULL, NULL};
 
   return items.find (key, &item, lock) ? item.data : NULL;
 }
@@ -541,7 +556,7 @@
  *
  * Returns library version as three integer components.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_version (unsigned int *major,
@@ -560,7 +575,7 @@
  *
  * Return value: library version string.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 const char *
 hb_version_string (void)
@@ -578,7 +593,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.30
  **/
 hb_bool_t
 hb_version_atleast (unsigned int major,
diff --git a/src/hb-common.h b/src/hb-common.h
index b6ce3f7..5b0a0b6 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -98,16 +98,22 @@
 #define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
 
 /* len=-1 means str is NUL-terminated. */
-hb_tag_t
+HB_EXTERN hb_tag_t
 hb_tag_from_string (const char *str, int len);
 
 /* buf should have 4 bytes. */
-void
+HB_EXTERN void
 hb_tag_to_string (hb_tag_t tag, char *buf);
 
 
-/* hb_direction_t */
-
+/**
+ * hb_direction_t:
+ * @HB_DIRECTION_INVALID: Initial, unset direction.
+ * @HB_DIRECTION_LTR: Text is set horizontally from left to right.
+ * @HB_DIRECTION_RTL: Text is set horizontally from right to left.
+ * @HB_DIRECTION_TTB: Text is set vertically from top to bottom.
+ * @HB_DIRECTION_BTT: Text is set vertically from bottom to top.
+ */
 typedef enum {
   HB_DIRECTION_INVALID = 0,
   HB_DIRECTION_LTR = 4,
@@ -117,10 +123,10 @@
 } hb_direction_t;
 
 /* len=-1 means str is NUL-terminated */
-hb_direction_t
+HB_EXTERN hb_direction_t
 hb_direction_from_string (const char *str, int len);
 
-const char *
+HB_EXTERN const char *
 hb_direction_to_string (hb_direction_t direction);
 
 #define HB_DIRECTION_IS_VALID(dir)	((((unsigned int) (dir)) & ~3U) == 4)
@@ -136,16 +142,15 @@
 
 typedef const struct hb_language_impl_t *hb_language_t;
 
-/* len=-1 means str is NUL-terminated */
-hb_language_t
+HB_EXTERN hb_language_t
 hb_language_from_string (const char *str, int len);
 
-const char *
+HB_EXTERN const char *
 hb_language_to_string (hb_language_t language);
 
 #define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
 
-hb_language_t
+HB_EXTERN hb_language_t
 hb_language_get_default (void);
 
 
@@ -272,6 +277,9 @@
   /*6.1*/ HB_SCRIPT_SORA_SOMPENG		= HB_TAG ('S','o','r','a'),
   /*6.1*/ HB_SCRIPT_TAKRI			= HB_TAG ('T','a','k','r'),
 
+  /*
+   * Since: 0.9.30
+   */
   /*7.0*/ HB_SCRIPT_BASSA_VAH			= HB_TAG ('B','a','s','s'),
   /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN		= HB_TAG ('A','g','h','b'),
   /*7.0*/ HB_SCRIPT_DUPLOYAN			= HB_TAG ('D','u','p','l'),
@@ -296,6 +304,13 @@
   /*7.0*/ HB_SCRIPT_TIRHUTA			= HB_TAG ('T','i','r','h'),
   /*7.0*/ HB_SCRIPT_WARANG_CITI			= HB_TAG ('W','a','r','a'),
 
+  /*8.0*/ HB_SCRIPT_AHOM                        = HB_TAG ('A','h','o','m'),
+  /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS       = HB_TAG ('H','l','u','w'),
+  /*8.0*/ HB_SCRIPT_HATRAN                      = HB_TAG ('H','a','t','r'),
+  /*8.0*/ HB_SCRIPT_MULTANI                     = HB_TAG ('M','u','l','t'),
+  /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN               = HB_TAG ('H','u','n','g'),
+  /*8.0*/ HB_SCRIPT_SIGNWRITING                 = HB_TAG ('S','g','n','w'),
+
   /* No script set. */
   HB_SCRIPT_INVALID				= HB_TAG_NONE,
 
@@ -314,18 +329,16 @@
 
 /* Script functions */
 
-hb_script_t
+HB_EXTERN hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag);
 
-/* sugar for tag_from_string() then script_from_iso15924_tag */
-/* len=-1 means s is NUL-terminated */
-hb_script_t
-hb_script_from_string (const char *s, int len);
+HB_EXTERN hb_script_t
+hb_script_from_string (const char *str, int len);
 
-hb_tag_t
+HB_EXTERN hb_tag_t
 hb_script_to_iso15924_tag (hb_script_t script);
 
-hb_direction_t
+HB_EXTERN hb_direction_t
 hb_script_get_horizontal_direction (hb_script_t script);
 
 
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index 16e069d..90c6653 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -27,7 +27,6 @@
  */
 
 #define HB_SHAPER coretext
-#define hb_coretext_shaper_face_data_t CGFont
 #include "hb-shaper-impl-private.hh"
 
 #include "hb-coretext.h"
@@ -78,6 +77,29 @@
  * shaper face data
  */
 
+static CTFontDescriptorRef
+get_last_resort_font_desc (void)
+{
+  // TODO Handle allocation failures?
+  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
+  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
+					   (const void **) &last_resort,
+					   1,
+					   &kCFTypeArrayCallBacks);
+  CFRelease (last_resort);
+  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+						   (const void **) &kCTFontCascadeListAttribute,
+						   (const void **) &cascade_list,
+						   1,
+						   &kCFTypeDictionaryKeyCallBacks,
+						   &kCFTypeDictionaryValueCallBacks);
+  CFRelease (cascade_list);
+
+  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+  CFRelease (attributes);
+  return font_desc;
+}
+
 static void
 release_data (void *info, const void *data, size_t size)
 {
@@ -87,14 +109,13 @@
   hb_blob_destroy ((hb_blob_t *) info);
 }
 
-hb_coretext_shaper_face_data_t *
-_hb_coretext_shaper_face_data_create (hb_face_t *face)
+static CGFontRef
+create_cg_font (hb_face_t *face)
 {
-  hb_coretext_shaper_face_data_t *data = NULL;
-
+  CGFontRef cg_font = NULL;
   if (face->destroy == (hb_destroy_func_t) CGFontRelease)
   {
-    data = CGFontRetain ((CGFontRef) face->user_data);
+    cg_font = CGFontRetain ((CGFontRef) face->user_data);
   }
   else
   {
@@ -107,67 +128,74 @@
     CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
     if (likely (provider))
     {
-      data = CGFontCreateWithDataProvider (provider);
+      cg_font = CGFontCreateWithDataProvider (provider);
+      if (unlikely (!cg_font))
+	DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
       CGDataProviderRelease (provider);
     }
   }
+  return cg_font;
+}
 
-  if (unlikely (!data)) {
-    DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
+static CTFontRef
+create_ct_font (CGFontRef cg_font, CGFloat font_size)
+{
+  CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
+  if (unlikely (!ct_font)) {
+    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
+    return NULL;
   }
 
-  return data;
+  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
+   * 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);
+    CFRelease (last_resort_font_desc);
+    if (new_ct_font)
+    {
+      CFRelease (ct_font);
+      ct_font = new_ct_font;
+    }
+    else
+      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
+  }
+
+ return ct_font;
 }
 
-void
-_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
-{
-  CFRelease (data);
-}
-
-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;
-}
-
-
-/*
- * shaper font data
- */
-
-struct hb_coretext_shaper_font_data_t {
+struct hb_coretext_shaper_face_data_t {
+  CGFontRef cg_font;
   CTFontRef ct_font;
-  CGFloat x_mult, y_mult; /* From CT space to HB space. */
 };
 
-hb_coretext_shaper_font_data_t *
-_hb_coretext_shaper_font_data_create (hb_font_t *font)
+hb_coretext_shaper_face_data_t *
+_hb_coretext_shaper_face_data_create (hb_face_t *face)
 {
-  if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
-
-  hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
+  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;
 
-  hb_face_t *face = font->face;
-  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  data->cg_font = create_cg_font (face);
+  if (unlikely (!data->cg_font))
+  {
+    DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
+    free (data);
+    return NULL;
+  }
 
-  /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */
-  CGFloat font_size = 36.; /* Default... */
-  /* No idea if the following is even a good idea. */
-  if (font->y_ppem)
-    font_size = font->y_ppem;
-
-  if (font_size < 0)
-    font_size = -font_size;
-  data->x_mult = (CGFloat) font->x_scale / font_size;
-  data->y_mult = (CGFloat) font->y_scale / font_size;
-  data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL);
-  if (unlikely (!data->ct_font)) {
-    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
+  /* 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;
   }
@@ -176,12 +204,42 @@
 }
 
 void
-_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
+_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
 {
   CFRelease (data->ct_font);
+  CFRelease (data->cg_font);
   free (data);
 }
 
+/*
+ * Since: 0.9.10
+ */
+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;
+}
+
+
+/*
+ * 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)
+{
+  return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
+{
+}
+
 
 /*
  * shaper shape_plan data
@@ -205,9 +263,10 @@
 CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font)
 {
-  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
-  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
-  return font_data->ct_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;
 }
 
 
@@ -440,7 +499,10 @@
 {
   hb_face_t *face = font->face;
   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+  CGFloat ct_font_size = CTFontGetSize (face_data->ct_font);
+  CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
+  CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
 
   /* Attach marks to their bases, to match the 'ot' shaper.
    * Adapted from hb-ot-shape:hb_form_clusters().
@@ -449,6 +511,7 @@
    * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
    * continue pointing to B2 even though B2 was merged into B1's
    * cluster... */
+  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
   {
     hb_unicode_funcs_t *unicode = buffer->unicode;
     unsigned int count = buffer->len;
@@ -571,7 +634,7 @@
 	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
 	  CFRelease (attributes);
 
-	  range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
+	  range->font = CTFontCreateCopyWithAttributes (face_data->ct_font, 0.0, NULL, font_desc);
 	  CFRelease (font_desc);
 	}
 	else
@@ -689,7 +752,6 @@
     scratch += old_scratch_used;
     scratch_size -= old_scratch_used;
   }
-retry:
   {
     string_ref = CFStringCreateWithCharactersNoCopy (NULL,
 						     pchars, chars_len,
@@ -729,7 +791,7 @@
 	CFRelease (lang);
       }
       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
-				      kCTFontAttributeName, font_data->ct_font);
+				      kCTFontAttributeName, face_data->ct_font);
 
       if (num_features)
       {
@@ -787,6 +849,18 @@
 
     buffer->len = 0;
     uint32_t status_and = ~0, status_or = 0;
+    double advances_so_far = 0;
+    /* For right-to-left runs, CoreText returns the glyphs positioned such that
+     * any trailing whitespace is to the left of (0,0).  Adjust coordinate system
+     * to fix for that.  Test with any RTL string with trailing spaces.
+     * https://code.google.com/p/chromium/issues/detail?id=469028
+     */
+    if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+    {
+      advances_so_far -= CTLineGetTrailingWhitespaceWidth (line);
+      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
+	  advances_so_far = -advances_so_far;
+    }
 
     const CFRange range_all = CFRangeMake (0, 0);
 
@@ -797,6 +871,10 @@
       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);
+      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
+	  run_advance = -run_advance;
+      DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
 
       /* CoreText does automatic font fallback (AKA "cascading") for  characters
        * not supported by the requested font, and provides no way to turn it off,
@@ -806,7 +884,7 @@
        */
       CFDictionaryRef attributes = CTRunGetAttributes (run);
       CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
-      if (!CFEqual (run_ct_font, font_data->ct_font))
+      if (!CFEqual (run_ct_font, face_data->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
@@ -828,11 +906,9 @@
 	 * However, even that wouldn't work if we were passed in the CGFont to
 	 * begin with.
 	 *
-	 * Webkit uses a slightly different approach: it installs LastResort
-	 * as fallback chain, and then checks PS name of used font against
-	 * LastResort.  That one is safe for any font except for LastResort,
-	 * as opposed to ours, which can fail if we are using any uninstalled
-	 * font that has the same name as an installed font.
+	 * We might switch to checking PS name against "LastResort".  That would
+	 * be safe for all fonts except for those named "Last Resort".  Might be
+	 * better than what we have right now.
 	 *
 	 * See: http://github.com/behdad/harfbuzz/pull/36
 	 */
@@ -848,13 +924,13 @@
 	  CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
 	  if (run_cg_font)
 	  {
-	    matched = CFEqual (run_cg_font, face_data);
+	    matched = CFEqual (run_cg_font, face_data->cg_font);
 	    CFRelease (run_cg_font);
 	  }
 	}
 	if (!matched)
 	{
-	  CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
+	  CFStringRef font_ps_name = CTFontCopyName (face_data->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);
@@ -892,19 +968,22 @@
 		   * for this one. */
 		  continue;
 	      }
+	      if (buffer->unicode->is_default_ignorable (ch))
+	        continue;
 
 	      info->codepoint = notdef;
 	      info->cluster = log_clusters[j];
 
 	      info->mask = advance;
-	      info->var1.u32 = x_offset;
-	      info->var2.u32 = y_offset;
+	      info->var1.i32 = x_offset;
+	      info->var2.i32 = y_offset;
 
 	      info++;
 	      buffer->len++;
 	  }
 	  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
 	    buffer->reverse_range (old_len, buffer->len);
+	  advances_so_far += run_advance;
 	  continue;
 	}
       }
@@ -934,7 +1013,7 @@
   scratch_size = scratch_size_saved; \
   scratch = scratch_saved;
 
-      {
+      { /* Setup glyphs */
         SCRATCH_SAVE();
 	const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
 	if (!glyphs) {
@@ -958,6 +1037,11 @@
 	SCRATCH_RESTORE();
       }
       {
+        /* Setup positions.
+	 * Note that CoreText does not return advances for glyphs.  As such,
+	 * for all but last glyph, we use the delta position to next glyph as
+	 * advance (in the advance direction only), and for last glyph we set
+	 * whatever is needed to make the whole run's advance add up. */
         SCRATCH_SAVE();
 	const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
 	if (!positions) {
@@ -965,34 +1049,41 @@
 	  CTRunGetPositions (run, range_all, position_buf);
 	  positions = position_buf;
 	}
-	double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
-	DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
 	hb_glyph_info_t *info = run_info;
-	CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult;
 	if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
 	{
+	  hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
 	  for (unsigned int j = 0; j < num_glyphs; j++)
 	  {
-	    double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_advance) - positions[j].x;
+	    double advance;
+	    if (likely (j + 1 < num_glyphs))
+	      advance = positions[j + 1].x - positions[j].x;
+	    else /* last glyph */
+	      advance = run_advance - (positions[j].x - positions[0].x);
 	    info->mask = advance * x_mult;
-	    info->var1.u32 = positions[0].x * x_mult; /* Yes, zero. */
-	    info->var2.u32 = positions[j].y * y_mult;
+	    info->var1.i32 = x_offset;
+	    info->var2.i32 = positions[j].y * y_mult;
 	    info++;
 	  }
 	}
 	else
 	{
-	  run_advance = -run_advance;
+	  hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
 	  for (unsigned int j = 0; j < num_glyphs; j++)
 	  {
-	    double advance = (j + 1 < num_glyphs ? positions[j + 1].y : positions[0].y + run_advance) - positions[j].y;
+	    double advance;
+	    if (likely (j + 1 < num_glyphs))
+	      advance = positions[j + 1].y - positions[j].y;
+	    else /* last glyph */
+	      advance = run_advance - (positions[j].y - positions[0].y);
 	    info->mask = advance * y_mult;
-	    info->var1.u32 = positions[j].x * x_mult;
-	    info->var2.u32 = positions[0].y * y_mult; /* Yes, zero. */
+	    info->var1.i32 = positions[j].x * x_mult;
+	    info->var2.i32 = y_offset;
 	    info++;
 	  }
 	}
 	SCRATCH_RESTORE();
+	advances_so_far += run_advance;
       }
 #undef SCRATCH_RESTORE
 #undef SCRATCH_SAVE
@@ -1002,10 +1093,20 @@
       buffer->len += num_glyphs;
     }
 
-    /* Make sure all runs had the expected direction. */
-    bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
-    assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
-    assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
+    /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
+     * or if it does, it doesn't resepct it.  So we get runs with wrong
+     * directions.  As such, disable the assert...  It wouldn't crash, but
+     * cursoring will be off...
+     *
+     * http://crbug.com/419769
+     */
+    if (0)
+    {
+      /* Make sure all runs had the expected direction. */
+      bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+      assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
+      assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
+    }
 
     buffer->clear_positions ();
 
@@ -1016,16 +1117,16 @@
       for (unsigned int i = 0; i < count; i++)
       {
 	pos->x_advance = info->mask;
-	pos->x_offset = info->var1.u32;
-	pos->y_offset = info->var2.u32;
+	pos->x_offset = info->var1.i32;
+	pos->y_offset = info->var2.i32;
 	info++, pos++;
       }
     else
       for (unsigned int i = 0; i < count; i++)
       {
 	pos->y_advance = info->mask;
-	pos->x_offset = info->var1.u32;
-	pos->y_offset = info->var2.u32;
+	pos->x_offset = info->var1.i32;
+	pos->y_offset = info->var2.i32;
 	info++, pos++;
       }
 
@@ -1083,10 +1184,6 @@
  * AAT shaper
  */
 
-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
-
-
 /*
  * shaper face data
  */
diff --git a/src/hb-coretext.h b/src/hb-coretext.h
index 25267bc..82066e4 100644
--- a/src/hb-coretext.h
+++ b/src/hb-coretext.h
@@ -44,14 +44,14 @@
 #define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
 
 
-hb_face_t *
+HB_EXTERN hb_face_t *
 hb_coretext_face_create (CGFontRef cg_font);
 
 
-CGFontRef
+HB_EXTERN CGFontRef
 hb_coretext_face_get_cg_font (hb_face_t *face);
 
-CTFontRef
+HB_EXTERN CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font);
 
 
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
new file mode 100644
index 0000000..af0fd3d
--- /dev/null
+++ b/src/hb-directwrite.cc
@@ -0,0 +1,827 @@
+/*
+ * Copyright © 2015  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#define HB_SHAPER directwrite
+#include "hb-shaper-impl-private.hh"
+
+#include <dwrite.h>
+
+#include "hb-directwrite.h"
+
+#include "hb-open-file-private.hh"
+#include "hb-ot-name-table.hh"
+#include "hb-ot-tag.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)
+
+/*
+* shaper face data
+*/
+
+struct hb_directwrite_shaper_face_data_t {
+  HANDLE fh;
+  wchar_t face_name[LF_FACESIZE];
+};
+
+/* face_name should point to a wchar_t[LF_FACESIZE] object. */
+static void
+_hb_generate_unique_face_name(wchar_t *face_name, unsigned int *plen)
+{
+  /* We'll create a private name for the font from a UUID using a simple,
+  * somewhat base64-like encoding scheme */
+  const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
+  UUID id;
+  UuidCreate ((UUID*)&id);
+  ASSERT_STATIC (2 + 3 * (16 / 2) < LF_FACESIZE);
+  unsigned int name_str_len = 0;
+  face_name[name_str_len++] = 'F';
+  face_name[name_str_len++] = '_';
+  unsigned char *p = (unsigned char *)&id;
+  for (unsigned int i = 0; i < 16; i += 2)
+  {
+    /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
+    * using the bits in groups of 5,5,6 to select chars from enc.
+    * This will generate 24 characters; with the 'F_' prefix we already provided,
+    * the name will be 26 chars (plus the NUL terminator), so will always fit within
+    * face_name (LF_FACESIZE = 32). */
+    face_name[name_str_len++] = enc[p[i] >> 3];
+    face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
+    face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
+  }
+  face_name[name_str_len] = 0;
+  if (plen)
+    *plen = name_str_len;
+}
+
+/* Destroys blob. */
+static hb_blob_t *
+_hb_rename_font(hb_blob_t *blob, wchar_t *new_name)
+{
+  /* Create a copy of the font data, with the 'name' table replaced by a
+   * table that names the font with our private F_* name created above.
+   * For simplicity, we just append a new 'name' table and update the
+   * sfnt directory; the original table is left in place, but unused.
+   *
+   * The new table will contain just 5 name IDs: family, style, unique,
+   * full, PS. All of them point to the same name data with our unique name.
+   */
+
+  blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
+
+  unsigned int length, new_length, name_str_len;
+  const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
+
+  _hb_generate_unique_face_name (new_name, &name_str_len);
+
+  static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
+
+  unsigned int name_table_length = OT::name::min_size +
+    ARRAY_LENGTH(name_IDs) * OT::NameRecord::static_size +
+    name_str_len * 2; /* for name data in UTF16BE form */
+  unsigned int name_table_offset = (length + 3) & ~3;
+
+  new_length = name_table_offset + ((name_table_length + 3) & ~3);
+  void *new_sfnt_data = calloc(1, new_length);
+  if (!new_sfnt_data)
+  {
+    hb_blob_destroy (blob);
+    return NULL;
+  }
+
+  memcpy(new_sfnt_data, orig_sfnt_data, length);
+
+  OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
+  name.format.set (0);
+  name.count.set (ARRAY_LENGTH (name_IDs));
+  name.stringOffset.set (name.get_size());
+  for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
+  {
+    OT::NameRecord &record = name.nameRecord[i];
+    record.platformID.set(3);
+    record.encodingID.set(1);
+    record.languageID.set(0x0409u); /* English */
+    record.nameID.set(name_IDs[i]);
+    record.length.set(name_str_len * 2);
+    record.offset.set(0);
+  }
+
+  /* Copy string data from new_name, converting wchar_t to UTF16BE. */
+  unsigned char *p = &OT::StructAfter<unsigned char>(name);
+  for (unsigned int i = 0; i < name_str_len; i++)
+  {
+    *p++ = new_name[i] >> 8;
+    *p++ = new_name[i] & 0xff;
+  }
+
+  /* Adjust name table entry to point to new name table */
+  const OT::OpenTypeFontFile &file = *(OT::OpenTypeFontFile *) (new_sfnt_data);
+  unsigned int face_count = file.get_face_count ();
+  for (unsigned int face_index = 0; face_index < face_count; face_index++)
+  {
+    /* Note: doing multiple edits (ie. TTC) can be unsafe.  There may be
+    * toe-stepping.  But we don't really care. */
+    const OT::OpenTypeFontFace &face = file.get_face (face_index);
+    unsigned int index;
+    if (face.find_table_index (HB_OT_TAG_name, &index))
+    {
+      OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
+      record.checkSum.set_for_data (&name, name_table_length);
+      record.offset.set (name_table_offset);
+      record.length.set (name_table_length);
+    }
+    else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
+    {
+      free (new_sfnt_data);
+      hb_blob_destroy (blob);
+      return NULL;
+    }
+  }
+
+  /* The checkSumAdjustment field in the 'head' table is now wrong,
+  * but that doesn't actually seem to cause any problems so we don't
+  * bother. */
+
+  hb_blob_destroy (blob);
+  return hb_blob_create ((const char *)new_sfnt_data, new_length,
+    HB_MEMORY_MODE_WRITABLE, NULL, free);
+}
+
+hb_directwrite_shaper_face_data_t *
+_hb_directwrite_shaper_face_data_create(hb_face_t *face)
+{
+  hb_directwrite_shaper_face_data_t *data = (hb_directwrite_shaper_face_data_t *)calloc(1, sizeof (hb_directwrite_shaper_face_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  hb_blob_t *blob = hb_face_reference_blob (face);
+  if (unlikely (!hb_blob_get_length (blob)))
+    DEBUG_MSG(DIRECTWRITE, face, "Face has empty blob");
+
+  blob = _hb_rename_font (blob, data->face_name);
+  if (unlikely (!blob))
+  {
+    free(data);
+    return NULL;
+  }
+
+  DWORD num_fonts_installed;
+  data->fh = AddFontMemResourceEx ((void *)hb_blob_get_data(blob, NULL),
+    hb_blob_get_length (blob),
+    0, &num_fonts_installed);
+  if (unlikely (!data->fh))
+  {
+    DEBUG_MSG (DIRECTWRITE, face, "Face AddFontMemResourceEx() failed");
+    free (data);
+    return NULL;
+  }
+
+  return data;
+}
+
+void
+_hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
+{
+  RemoveFontMemResourceEx(data->fh);
+  free(data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_directwrite_shaper_font_data_t {
+  HDC hdc;
+  LOGFONTW log_font;
+  HFONT hfont;
+};
+
+static bool
+populate_log_font (LOGFONTW  *lf,
+       hb_font_t *font)
+{
+  memset (lf, 0, sizeof (*lf));
+  lf->lfHeight = -font->y_scale;
+  lf->lfCharSet = DEFAULT_CHARSET;
+
+  hb_face_t *face = font->face;
+  hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+  memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
+
+  return true;
+}
+
+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;
+
+  hb_directwrite_shaper_font_data_t *data = (hb_directwrite_shaper_font_data_t *) calloc (1, sizeof (hb_directwrite_shaper_font_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  data->hdc = GetDC (NULL);
+
+  if (unlikely (!populate_log_font (&data->log_font, font))) {
+    DEBUG_MSG (DIRECTWRITE, font, "Font populate_log_font() failed");
+    _hb_directwrite_shaper_font_data_destroy (data);
+    return NULL;
+  }
+
+  data->hfont = CreateFontIndirectW (&data->log_font);
+  if (unlikely (!data->hfont)) {
+    DEBUG_MSG (DIRECTWRITE, font, "Font CreateFontIndirectW() failed");
+    _hb_directwrite_shaper_font_data_destroy (data);
+     return NULL;
+  }
+
+  if (!SelectObject (data->hdc, data->hfont)) {
+    DEBUG_MSG (DIRECTWRITE, font, "Font SelectObject() failed");
+    _hb_directwrite_shaper_font_data_destroy (data);
+     return NULL;
+  }
+
+  return data;
+}
+
+void
+_hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
+{
+  if (data->hdc)
+    ReleaseDC (NULL, data->hdc);
+  if (data->hfont)
+    DeleteObject (data->hfont);
+  free (data);
+}
+
+LOGFONTW *
+hb_directwrite_font_get_logfontw (hb_font_t *font)
+{
+  if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
+  hb_directwrite_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
+  return &font_data->log_font;
+}
+
+HFONT
+hb_directwrite_font_get_hfont (hb_font_t *font)
+{
+  if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
+  hb_directwrite_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
+  return font_data->hfont;
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_directwrite_shaper_shape_plan_data_t {};
+
+hb_directwrite_shaper_shape_plan_data_t *
+_hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+               const hb_feature_t *user_features HB_UNUSED,
+               unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+// Most of here TextAnalysis is originally written by Bas Schouten for Mozilla project
+// but now is relicensed to MIT for HarfBuzz use
+class TextAnalysis
+  : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
+{
+public:
+
+  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
+  IFACEMETHOD_(ULONG, AddRef)() { return 1; }
+  IFACEMETHOD_(ULONG, Release)() { return 1; }
+
+  // A single contiguous run of characters containing the same analysis 
+  // results.
+  struct Run
+  {
+    UINT32 mTextStart;   // starting text position of this run
+    UINT32 mTextLength;  // number of contiguous code units covered
+    UINT32 mGlyphStart;  // starting glyph in the glyphs array
+    UINT32 mGlyphCount;  // number of glyphs associated with this run of 
+    // text
+    DWRITE_SCRIPT_ANALYSIS mScript;
+    UINT8 mBidiLevel;
+    bool mIsSideways;
+
+    inline bool ContainsTextPosition(UINT32 aTextPosition) const
+    {
+      return aTextPosition >= mTextStart
+        && aTextPosition <  mTextStart + mTextLength;
+    }
+
+    Run *nextRun;
+  };
+
+public:
+  TextAnalysis(const wchar_t* text,
+    UINT32 textLength,
+    const wchar_t* localeName,
+    DWRITE_READING_DIRECTION readingDirection)
+    : mText(text)
+    , mTextLength(textLength)
+    , mLocaleName(localeName)
+    , mReadingDirection(readingDirection)
+    , mCurrentRun(NULL) { };
+
+  ~TextAnalysis() {
+    // delete runs, except mRunHead which is part of the TextAnalysis object
+    for (Run *run = mRunHead.nextRun; run;) {
+      Run *origRun = run;
+      run = run->nextRun;
+      delete origRun;
+    }
+  }
+
+  STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
+    Run **runHead) {
+    // Analyzes the text using the script analyzer and returns
+    // the result as a series of runs.
+
+    HRESULT hr = S_OK;
+
+    // Initially start out with one result that covers the entire range.
+    // This result will be subdivided by the analysis processes.
+    mRunHead.mTextStart = 0;
+    mRunHead.mTextLength = mTextLength;
+    mRunHead.mBidiLevel =
+      (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
+    mRunHead.nextRun = NULL;
+    mCurrentRun = &mRunHead;
+
+    // Call each of the analyzers in sequence, recording their results.
+    if (SUCCEEDED(hr = textAnalyzer->AnalyzeScript(this,
+      0,
+      mTextLength,
+      this))) {
+      *runHead = &mRunHead;
+    }
+
+    return hr;
+  }
+
+  // IDWriteTextAnalysisSource implementation
+
+  IFACEMETHODIMP GetTextAtPosition(UINT32 textPosition,
+    OUT WCHAR const** textString,
+    OUT UINT32* textLength)
+  {
+    if (textPosition >= mTextLength) {
+      // No text at this position, valid query though.
+      *textString = NULL;
+      *textLength = 0;
+    }
+    else {
+      *textString = mText + textPosition;
+      *textLength = mTextLength - textPosition;
+    }
+    return S_OK;
+  }
+
+  IFACEMETHODIMP GetTextBeforePosition(UINT32 textPosition,
+    OUT WCHAR const** textString,
+    OUT UINT32* textLength)
+  {
+    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;
+      *textLength = 0;
+    }
+    else {
+      *textString = mText;
+      *textLength = textPosition;
+    }
+    return S_OK;
+  }
+
+  IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
+    GetParagraphReadingDirection() { return mReadingDirection; }
+
+  IFACEMETHODIMP GetLocaleName(UINT32 textPosition,
+    UINT32* textLength,
+    WCHAR const** localeName) {
+    return S_OK;
+  }
+
+  IFACEMETHODIMP
+    GetNumberSubstitution(UINT32 textPosition,
+    OUT UINT32* textLength,
+    OUT IDWriteNumberSubstitution** numberSubstitution)
+  {
+    // We do not support number substitution.
+    *numberSubstitution = NULL;
+    *textLength = mTextLength - textPosition;
+
+    return S_OK;
+  }
+
+  // IDWriteTextAnalysisSink implementation
+
+  IFACEMETHODIMP
+    SetScriptAnalysis(UINT32 textPosition,
+    UINT32 textLength,
+    DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
+  {
+    SetCurrentRun(textPosition);
+    SplitCurrentRun(textPosition);
+    while (textLength > 0) {
+      Run *run = FetchNextRun(&textLength);
+      run->mScript = *scriptAnalysis;
+    }
+
+    return S_OK;
+  }
+
+  IFACEMETHODIMP
+    SetLineBreakpoints(UINT32 textPosition,
+    UINT32 textLength,
+    const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
+
+  IFACEMETHODIMP SetBidiLevel(UINT32 textPosition,
+    UINT32 textLength,
+    UINT8 explicitLevel,
+    UINT8 resolvedLevel) { return S_OK; }
+
+  IFACEMETHODIMP
+    SetNumberSubstitution(UINT32 textPosition,
+    UINT32 textLength,
+    IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
+
+protected:
+  Run *FetchNextRun(IN OUT UINT32* textLength)
+  {
+    // Used by the sink setters, this returns a reference to the next run.
+    // Position and length are adjusted to now point after the current run
+    // being returned.
+
+    Run *origRun = mCurrentRun;
+    // Split the tail if needed (the length remaining is less than the
+    // current run's size).
+    if (*textLength < mCurrentRun->mTextLength) {
+      SplitCurrentRun(mCurrentRun->mTextStart + *textLength);
+    }
+    else {
+      // Just advance the current run.
+      mCurrentRun = mCurrentRun->nextRun;
+    }
+    *textLength -= origRun->mTextLength;
+
+    // Return a reference to the run that was just current.
+    return origRun;
+  }
+
+  void SetCurrentRun(UINT32 textPosition)
+  {
+    // Move the current run to the given position.
+    // Since the analyzers generally return results in a forward manner,
+    // this will usually just return early. If not, find the
+    // corresponding run for the text position.
+
+    if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) {
+      return;
+    }
+
+    for (Run *run = &mRunHead; run; run = run->nextRun) {
+      if (run->ContainsTextPosition(textPosition)) {
+        mCurrentRun = run;
+        return;
+      }
+    }
+    //NS_NOTREACHED("We should always be able to find the text position in one \
+            //                of our runs");
+  }
+
+  void SplitCurrentRun(UINT32 splitPosition)
+  {
+    if (!mCurrentRun) {
+      //NS_ASSERTION(false, "SplitCurrentRun called without current run.");
+      // Shouldn't be calling this when no current run is set!
+      return;
+    }
+    // Split the current run.
+    if (splitPosition <= mCurrentRun->mTextStart) {
+      // No need to split, already the start of a run
+      // or before it. Usually the first.
+      return;
+    }
+    Run *newRun = new Run;
+
+    *newRun = *mCurrentRun;
+
+    // Insert the new run in our linked list.
+    newRun->nextRun = mCurrentRun->nextRun;
+    mCurrentRun->nextRun = newRun;
+
+    // Adjust runs' text positions and lengths.
+    UINT32 splitPoint = splitPosition - mCurrentRun->mTextStart;
+    newRun->mTextStart += splitPoint;
+    newRun->mTextLength -= splitPoint;
+    mCurrentRun->mTextLength = splitPoint;
+    mCurrentRun = newRun;
+  }
+
+protected:
+  // Input
+  // (weak references are fine here, since this class is a transient
+  //  stack-based helper that doesn't need to copy data)
+  UINT32 mTextLength;
+  const WCHAR* mText;
+  const WCHAR* mLocaleName;
+  DWRITE_READING_DIRECTION mReadingDirection;
+
+  // Current processing state.
+  Run *mCurrentRun;
+
+  // Output is a list of runs starting here
+  Run  mRunHead;
+};
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
+  hb_font_t          *font,
+  hb_buffer_t        *buffer,
+  const hb_feature_t *features,
+  unsigned int        num_features)
+{
+  hb_face_t *face = font->face;
+  hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+  // factory probably should be cached
+  IDWriteFactory* dwriteFactory;
+  DWriteCreateFactory(
+    DWRITE_FACTORY_TYPE_SHARED,
+    __uuidof(IDWriteFactory),
+    reinterpret_cast<IUnknown**>(&dwriteFactory)
+    );
+
+  IDWriteGdiInterop *gdiInterop;
+  dwriteFactory->GetGdiInterop (&gdiInterop);
+  IDWriteFontFace* fontFace;
+  gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace);
+
+  IDWriteTextAnalyzer* analyzer;
+  dwriteFactory->CreateTextAnalyzer (&analyzer);
+
+  unsigned int scratch_size;
+  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+#define ALLOCATE_ARRAY(Type, name, len) \
+  Type *name = (Type *) scratch; \
+  { \
+    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+    assert (_consumed <= scratch_size); \
+    scratch += _consumed; \
+    scratch_size -= _consumed; \
+  }
+
+#define utf16_index() var1.u32
+
+  ALLOCATE_ARRAY(WCHAR, pchars, buffer->len * 2);
+
+  unsigned int chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    buffer->info[i].utf16_index() = chars_len;
+    if (likely(c <= 0xFFFFu))
+      pchars[chars_len++] = c;
+    else if (unlikely(c > 0x10FFFFu))
+      pchars[chars_len++] = 0xFFFDu;
+    else {
+      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
+    }
+  }
+
+  ALLOCATE_ARRAY(WORD, log_clusters, chars_len);
+  if (num_features)
+  {
+    /* Need log_clusters to assign features. */
+    chars_len = 0;
+    for (unsigned int i = 0; i < buffer->len; i++)
+    {
+      hb_codepoint_t c = buffer->info[i].codepoint;
+      unsigned int cluster = buffer->info[i].cluster;
+      log_clusters[chars_len++] = cluster;
+      if (hb_in_range(c, 0x10000u, 0x10FFFFu))
+        log_clusters[chars_len++] = cluster; /* Surrogates. */
+    }
+  }
+
+  HRESULT hr;
+  // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
+
+  DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ? 
+    DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
+    DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
+
+  /*
+  * There's an internal 16-bit limit on some things inside the analyzer,
+  * but we never attempt to shape a word longer than 64K characters
+  * in a single gfxShapedWord, so we cannot exceed that limit.
+  */
+  UINT32 length = buffer->len;
+
+  TextAnalysis analysis(pchars, length, NULL, readingDirection);
+  TextAnalysis::Run *runHead;
+  hr = analysis.GenerateResults(analyzer, &runHead);
+
+  if (FAILED(hr)) {
+    //NS_WARNING("Analyzer failed to generate results.");
+    return false;
+  }
+
+  UINT32 maxGlyphs = 3 * length / 2 + 16;
+
+#define INITIAL_GLYPH_SIZE 400
+  UINT16* clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+  UINT16* glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
+    malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
+  DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
+    malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
+
+  UINT32 actualGlyphs;
+
+  bool backward = HB_DIRECTION_IS_BACKWARD(buffer->props.direction);
+
+  wchar_t lang[4];
+  mbstowcs(lang, hb_language_to_string(buffer->props.language), 4);
+  hr = analyzer->GetGlyphs(pchars, length,
+    fontFace, FALSE,
+    buffer->props.direction,
+    &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
+    maxGlyphs, clusters, textProperties,
+    glyphs, glyphProperties, &actualGlyphs);
+
+  if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
+    free(clusters);
+    free(glyphs);
+    free(textProperties);
+    free(glyphProperties);
+
+    clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+    glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+    textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
+      malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
+    glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
+      malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
+
+    hr = analyzer->GetGlyphs(pchars, length,
+      fontFace, FALSE,
+      buffer->props.direction,
+      &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
+      maxGlyphs, clusters, textProperties,
+      glyphs, glyphProperties, &actualGlyphs);
+  }
+  if (FAILED(hr)) {
+    //NS_WARNING("Analyzer failed to get glyphs.");
+    return false;
+  }
+
+  FLOAT advances[400];
+  DWRITE_GLYPH_OFFSET offsets[400];
+
+
+  /* The -2 in the following is to compensate for possible
+   * alignment needed after the WORD array.  sizeof(WORD) == 2. */
+  unsigned int glyphs_size = (scratch_size * sizeof (int)-2)
+    / (sizeof (WORD) +
+    4 + // sizeof (SCRIPT_GLYPHPROP) +
+    sizeof (int) +
+    8 + // sizeof (GOFFSET) +
+    sizeof (uint32_t));
+  ALLOCATE_ARRAY(uint32_t, vis_clusters, glyphs_size);
+
+#undef ALLOCATE_ARRAY
+
+  hr = analyzer->GetGlyphPlacements(pchars,
+    clusters,
+    textProperties,
+    length,
+    glyphs,
+    glyphProperties,
+    actualGlyphs,
+    fontFace,
+    face->get_upem(),
+    FALSE,
+    FALSE,
+    &runHead->mScript,
+    NULL,
+    NULL,
+    NULL,
+    0,
+    advances,
+    offsets);
+
+  if (FAILED(hr)) {
+    //NS_WARNING("Analyzer failed to get glyph placements.");
+    return false;
+  }
+
+  unsigned int glyphs_len = actualGlyphs;
+
+  /* Ok, we've got everything we need, now compose output buffer,
+   * very, *very*, carefully! */
+
+  /* Calculate visual-clusters.  That's what we ship. */
+  for (unsigned int i = 0; i < glyphs_len; i++)
+    vis_clusters[i] = -1;
+  for (unsigned int i = 0; i < buffer->len; i++) {
+    uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
+    //*p = MIN (*p, buffer->info[i].cluster);
+  }
+  for (unsigned int i = 1; i < glyphs_len; i++)
+    if (vis_clusters[i] == -1)
+      vis_clusters[i] = vis_clusters[i - 1];
+
+#undef utf16_index
+
+  //if (unlikely (!buffer->ensure (glyphs_len)))
+  //  FAIL ("Buffer in error");
+
+#undef FAIL
+
+  /* Set glyph infos */
+  buffer->len = 0;
+  for (unsigned int i = 0; i < glyphs_len; i++)
+  {
+    hb_glyph_info_t *info = &buffer->info[buffer->len++];
+
+    info->codepoint = glyphs[i];
+    info->cluster = vis_clusters[i];
+
+    /* The rest is crap.  Let's store position info there for now. */
+    info->mask = advances[i];
+    info->var1.u32 = offsets[i].ascenderOffset;
+    info->var2.u32 = -offsets[i].advanceOffset;
+  }
+
+  free(clusters);
+  free(glyphs);
+  free(textProperties);
+  free(glyphProperties);
+
+  /* Set glyph positions */
+  buffer->clear_positions ();
+  for (unsigned int i = 0; i < glyphs_len; i++)
+  {
+    hb_glyph_info_t *info = &buffer->info[i];
+    hb_glyph_position_t *pos = &buffer->pos[i];
+
+    /* TODO vertical */
+    pos->x_advance = info->mask;
+    pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
+    pos->y_offset = info->var2.u32;
+  }
+
+  if (backward)
+    hb_buffer_reverse (buffer);
+
+  /* Wow, done! */
+  return true;
+}
diff --git a/src/hb-directwrite.h b/src/hb-directwrite.h
new file mode 100644
index 0000000..adf33df
--- /dev/null
+++ b/src/hb-directwrite.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2015  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_DIRECTWRITE_H
+#define HB_DIRECTWRITE_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+HB_END_DECLS
+
+#endif /* HB_UNISCRIBE_H */
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 9348af7..9effc41 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -77,7 +77,7 @@
  *
  * Return value: (transfer full)
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_face_t *
 hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
@@ -113,7 +113,7 @@
 {
   hb_face_for_data_closure_t *closure;
 
-  closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
+  closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
   if (unlikely (!closure))
     return NULL;
 
@@ -157,7 +157,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_face_t *
 hb_face_create (hb_blob_t    *blob,
@@ -165,8 +165,8 @@
 {
   hb_face_t *face;
 
-  if (unlikely (!blob || !hb_blob_get_length (blob)))
-    return hb_face_get_empty ();
+  if (unlikely (!blob))
+    blob = hb_blob_get_empty ();
 
   hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
 
@@ -189,7 +189,7 @@
  *
  * Return value: (transfer full)
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_face_t *
 hb_face_get_empty (void)
@@ -206,7 +206,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_face_t *
 hb_face_reference (hb_face_t *face)
@@ -220,7 +220,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_face_destroy (hb_face_t *face)
@@ -257,7 +257,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_face_set_user_data (hb_face_t          *face,
@@ -278,7 +278,7 @@
  *
  * Return value: (transfer none):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void *
 hb_face_get_user_data (hb_face_t          *face,
@@ -293,7 +293,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_face_make_immutable (hb_face_t *face)
@@ -312,7 +312,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_face_is_immutable (hb_face_t *face)
@@ -330,7 +330,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_blob_t *
 hb_face_reference_table (hb_face_t *face,
@@ -347,7 +347,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_blob_t *
 hb_face_reference_blob (hb_face_t *face)
@@ -362,7 +362,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_face_set_index (hb_face_t    *face,
@@ -382,7 +382,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 unsigned int
 hb_face_get_index (hb_face_t    *face)
@@ -397,7 +397,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_face_set_upem (hb_face_t    *face,
@@ -417,7 +417,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 unsigned int
 hb_face_get_upem (hb_face_t *face)
@@ -441,7 +441,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 void
 hb_face_set_glyph_count (hb_face_t    *face,
@@ -461,7 +461,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 unsigned int
 hb_face_get_glyph_count (hb_face_t *face)
diff --git a/src/hb-face.h b/src/hb-face.h
index f682c46..91237b7 100644
--- a/src/hb-face.h
+++ b/src/hb-face.h
@@ -43,28 +43,28 @@
 
 typedef struct hb_face_t hb_face_t;
 
-hb_face_t *
+HB_EXTERN hb_face_t *
 hb_face_create (hb_blob_t    *blob,
 		unsigned int  index);
 
 typedef hb_blob_t * (*hb_reference_table_func_t)  (hb_face_t *face, hb_tag_t tag, void *user_data);
 
 /* calls destroy() when not needing user_data anymore */
-hb_face_t *
+HB_EXTERN hb_face_t *
 hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
 			   void                      *user_data,
 			   hb_destroy_func_t          destroy);
 
-hb_face_t *
+HB_EXTERN hb_face_t *
 hb_face_get_empty (void);
 
-hb_face_t *
+HB_EXTERN hb_face_t *
 hb_face_reference (hb_face_t *face);
 
-void
+HB_EXTERN void
 hb_face_destroy (hb_face_t *face);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_face_set_user_data (hb_face_t          *face,
 		       hb_user_data_key_t *key,
 		       void *              data,
@@ -72,43 +72,43 @@
 		       hb_bool_t           replace);
 
 
-void *
+HB_EXTERN void *
 hb_face_get_user_data (hb_face_t          *face,
 		       hb_user_data_key_t *key);
 
-void
+HB_EXTERN void
 hb_face_make_immutable (hb_face_t *face);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_face_is_immutable (hb_face_t *face);
 
 
-hb_blob_t *
+HB_EXTERN hb_blob_t *
 hb_face_reference_table (hb_face_t *face,
 			 hb_tag_t   tag);
 
-hb_blob_t *
+HB_EXTERN hb_blob_t *
 hb_face_reference_blob (hb_face_t *face);
 
-void
+HB_EXTERN void
 hb_face_set_index (hb_face_t    *face,
 		   unsigned int  index);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_face_get_index (hb_face_t    *face);
 
-void
+HB_EXTERN void
 hb_face_set_upem (hb_face_t    *face,
 		  unsigned int  upem);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_face_get_upem (hb_face_t *face);
 
-void
+HB_EXTERN void
 hb_face_set_glyph_count (hb_face_t    *face,
 			 unsigned int  glyph_count);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_face_get_glyph_count (hb_face_t *face);
 
 
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index 9d061a9..b5ebfc0 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -106,7 +106,7 @@
    */
 
   hb_codepoint_t space;
-  bool has_space = font->get_glyph (' ', 0, &space);
+  bool has_space = (bool) font->get_glyph (' ', 0, &space);
 
   buffer->clear_positions ();
 
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 33bbf71..9138c23 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -42,6 +42,8 @@
  */
 
 #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
+  HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
+  HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
   HB_FONT_FUNC_IMPLEMENT (glyph) \
   HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
   HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
@@ -61,14 +63,6 @@
 
   hb_bool_t immutable;
 
-  /* Don't access these directly.  Call hb_font_get_*() instead. */
-
-  struct {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  } get;
-
   struct {
 #define HB_FONT_FUNC_IMPLEMENT(name) void *name;
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
@@ -80,6 +74,16 @@
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   } destroy;
+
+  /* Don't access these directly.  Call font->get_*() instead. */
+  union get_t {
+    struct get_funcs_t {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+    } f;
+    void (*array[VAR]) (void);
+  } get;
 };
 
 
@@ -144,7 +148,36 @@
 
   /* Public getters */
 
-  inline hb_bool_t has_glyph (hb_codepoint_t unicode)
+  HB_INTERNAL bool has_func (unsigned int i);
+
+  /* has_* ... */
+#define HB_FONT_FUNC_IMPLEMENT(name) \
+  bool \
+  has_##name##_func (void) \
+  { \
+    hb_font_funcs_t *funcs = this->klass; \
+    unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
+    return has_func (i); \
+  }
+  HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+
+  inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
+  {
+    memset (extents, 0, sizeof (*extents));
+    return klass->get.f.font_h_extents (this, user_data,
+					extents,
+					klass->user_data.font_h_extents);
+  }
+  inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
+  {
+    memset (extents, 0, sizeof (*extents));
+    return klass->get.f.font_v_extents (this, user_data,
+					extents,
+					klass->user_data.font_v_extents);
+  }
+
+  inline bool has_glyph (hb_codepoint_t unicode)
   {
     hb_codepoint_t glyph;
     return get_glyph (unicode, 0, &glyph);
@@ -154,85 +187,85 @@
 			      hb_codepoint_t *glyph)
   {
     *glyph = 0;
-    return klass->get.glyph (this, user_data,
-			     unicode, variation_selector, glyph,
-			     klass->user_data.glyph);
+    return klass->get.f.glyph (this, user_data,
+			       unicode, variation_selector, glyph,
+			       klass->user_data.glyph);
   }
 
   inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
   {
-    return klass->get.glyph_h_advance (this, user_data,
-				       glyph,
-				       klass->user_data.glyph_h_advance);
+    return klass->get.f.glyph_h_advance (this, user_data,
+					 glyph,
+					 klass->user_data.glyph_h_advance);
   }
 
   inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
   {
-    return klass->get.glyph_v_advance (this, user_data,
-				       glyph,
-				       klass->user_data.glyph_v_advance);
+    return klass->get.f.glyph_v_advance (this, user_data,
+					 glyph,
+					 klass->user_data.glyph_v_advance);
   }
 
   inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
 				       hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
-    return klass->get.glyph_h_origin (this, user_data,
-				      glyph, x, y,
-				      klass->user_data.glyph_h_origin);
+    return klass->get.f.glyph_h_origin (this, user_data,
+					glyph, x, y,
+					klass->user_data.glyph_h_origin);
   }
 
   inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
 				       hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
-    return klass->get.glyph_v_origin (this, user_data,
-				      glyph, x, y,
-				      klass->user_data.glyph_v_origin);
+    return klass->get.f.glyph_v_origin (this, user_data,
+					glyph, x, y,
+					klass->user_data.glyph_v_origin);
   }
 
   inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
   {
-    return klass->get.glyph_h_kerning (this, user_data,
-				       left_glyph, right_glyph,
-				       klass->user_data.glyph_h_kerning);
+    return klass->get.f.glyph_h_kerning (this, user_data,
+					 left_glyph, right_glyph,
+					 klass->user_data.glyph_h_kerning);
   }
 
   inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
   {
-    return klass->get.glyph_v_kerning (this, user_data,
-				       top_glyph, bottom_glyph,
-				       klass->user_data.glyph_v_kerning);
+    return klass->get.f.glyph_v_kerning (this, user_data,
+					 top_glyph, bottom_glyph,
+					 klass->user_data.glyph_v_kerning);
   }
 
   inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
 				      hb_glyph_extents_t *extents)
   {
     memset (extents, 0, sizeof (*extents));
-    return klass->get.glyph_extents (this, user_data,
-				     glyph,
-				     extents,
-				     klass->user_data.glyph_extents);
+    return klass->get.f.glyph_extents (this, user_data,
+				       glyph,
+				       extents,
+				       klass->user_data.glyph_extents);
   }
 
   inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
 					    hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
-    return klass->get.glyph_contour_point (this, user_data,
-					   glyph, point_index,
-					   x, y,
-					   klass->user_data.glyph_contour_point);
+    return klass->get.f.glyph_contour_point (this, user_data,
+					     glyph, point_index,
+					     x, y,
+					     klass->user_data.glyph_contour_point);
   }
 
   inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
 				   char *name, unsigned int size)
   {
     if (size) *name = '\0';
-    return klass->get.glyph_name (this, user_data,
-				  glyph,
-				  name, size,
-				  klass->user_data.glyph_name);
+    return klass->get.f.glyph_name (this, user_data,
+				    glyph,
+				    name, size,
+				    klass->user_data.glyph_name);
   }
 
   inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
@@ -240,15 +273,35 @@
   {
     *glyph = 0;
     if (len == -1) len = strlen (name);
-    return klass->get.glyph_from_name (this, user_data,
-				       name, len,
-				       glyph,
-				       klass->user_data.glyph_from_name);
+    return klass->get.f.glyph_from_name (this, user_data,
+					 name, len,
+					 glyph,
+					 klass->user_data.glyph_from_name);
   }
 
 
   /* A bit higher-level, and with fallback */
 
+  inline void get_extents_for_direction (hb_direction_t direction,
+					 hb_font_extents_t *extents)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      if (!get_font_h_extents (extents))
+      {
+	extents->ascender = y_scale * .8;
+	extents->descender = y_scale - extents->ascender;
+	extents->line_gap = 0;
+      }
+    } else {
+      if (!get_font_v_extents (extents))
+      {
+	extents->ascender = x_scale / 2;
+	extents->descender = x_scale - extents->ascender;
+	extents->line_gap = 0;
+      }
+    }
+  }
+
   inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
 					       hb_direction_t direction,
 					       hb_position_t *x, hb_position_t *y)
@@ -268,7 +321,7 @@
   {
     *x = get_glyph_h_advance (glyph) / 2;
 
-    /* TODO use font_metics.ascent */
+    /* TODO use font_extents.ascender */
     *y = y_scale;
   }
 
@@ -298,6 +351,26 @@
     }
   }
 
+  inline void add_glyph_h_origin (hb_codepoint_t glyph,
+				  hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_h_origin (glyph, &origin_x, &origin_y);
+
+    *x += origin_x;
+    *y += origin_y;
+  }
+  inline void add_glyph_v_origin (hb_codepoint_t glyph,
+				  hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_v_origin (glyph, &origin_x, &origin_y);
+
+    *x += origin_x;
+    *y += origin_y;
+  }
   inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
 					      hb_direction_t direction,
 					      hb_position_t *x, hb_position_t *y)
@@ -310,6 +383,26 @@
     *y += origin_y;
   }
 
+  inline void subtract_glyph_h_origin (hb_codepoint_t glyph,
+				       hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_h_origin (glyph, &origin_x, &origin_y);
+
+    *x -= origin_x;
+    *y -= origin_y;
+  }
+  inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
+				       hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_v_origin (glyph, &origin_x, &origin_y);
+
+    *x -= origin_x;
+    *y -= origin_y;
+  }
   inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
 						   hb_direction_t direction,
 						   hb_position_t *x, hb_position_t *y)
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 4364ca7..c038b10 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -45,130 +45,224 @@
  */
 
 static hb_bool_t
-hb_font_get_glyph_nil (hb_font_t *font,
+hb_font_get_font_h_extents_nil (hb_font_t *font,
+				void *font_data HB_UNUSED,
+				hb_font_extents_t *metrics,
+				void *user_data HB_UNUSED)
+{
+  memset (metrics, 0, sizeof (*metrics));
+  return false;
+}
+static hb_bool_t
+hb_font_get_font_h_extents_parent (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   hb_font_extents_t *metrics,
+				   void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_font_h_extents (metrics);
+  if (ret) {
+    metrics->ascender = font->parent_scale_y_distance (metrics->ascender);
+    metrics->descender = font->parent_scale_y_distance (metrics->descender);
+    metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap);
+  }
+  return ret;
+}
+
+static hb_bool_t
+hb_font_get_font_v_extents_nil (hb_font_t *font,
+				void *font_data HB_UNUSED,
+				hb_font_extents_t *metrics,
+				void *user_data HB_UNUSED)
+{
+  memset (metrics, 0, sizeof (*metrics));
+  return false;
+}
+static hb_bool_t
+hb_font_get_font_v_extents_parent (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   hb_font_extents_t *metrics,
+				   void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_font_v_extents (metrics);
+  if (ret) {
+    metrics->ascender = font->parent_scale_x_distance (metrics->ascender);
+    metrics->descender = font->parent_scale_x_distance (metrics->descender);
+    metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap);
+  }
+  return ret;
+}
+
+static hb_bool_t
+hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
 		       void *font_data HB_UNUSED,
 		       hb_codepoint_t unicode,
 		       hb_codepoint_t variation_selector,
 		       hb_codepoint_t *glyph,
 		       void *user_data HB_UNUSED)
 {
-  if (font->parent)
-    return font->parent->get_glyph (unicode, variation_selector, glyph);
-
   *glyph = 0;
   return false;
 }
+static hb_bool_t
+hb_font_get_glyph_parent (hb_font_t *font,
+			  void *font_data HB_UNUSED,
+			  hb_codepoint_t unicode,
+			  hb_codepoint_t variation_selector,
+			  hb_codepoint_t *glyph,
+			  void *user_data HB_UNUSED)
+{
+  return font->parent->get_glyph (unicode, variation_selector, glyph);
+}
 
 static hb_position_t
-hb_font_get_glyph_h_advance_nil (hb_font_t *font,
+hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t glyph,
 				 void *user_data HB_UNUSED)
 {
-  if (font->parent)
-    return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
-
   return font->x_scale;
 }
+static hb_position_t
+hb_font_get_glyph_h_advance_parent (hb_font_t *font,
+				    void *font_data HB_UNUSED,
+				    hb_codepoint_t glyph,
+				    void *user_data HB_UNUSED)
+{
+  return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
+}
 
 static hb_position_t
-hb_font_get_glyph_v_advance_nil (hb_font_t *font,
+hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t glyph,
 				 void *user_data HB_UNUSED)
 {
-  if (font->parent)
-    return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
-
   return font->y_scale;
 }
-
-static hb_bool_t
-hb_font_get_glyph_h_origin_nil (hb_font_t *font,
-				void *font_data HB_UNUSED,
-				hb_codepoint_t glyph,
-				hb_position_t *x,
-				hb_position_t *y,
-				void *user_data HB_UNUSED)
+static hb_position_t
+hb_font_get_glyph_v_advance_parent (hb_font_t *font,
+				    void *font_data HB_UNUSED,
+				    hb_codepoint_t glyph,
+				    void *user_data HB_UNUSED)
 {
-  if (font->parent) {
-    hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
-    if (ret)
-      font->parent_scale_position (x, y);
-    return ret;
-  }
-
-  *x = *y = 0;
-  return false;
+  return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
 }
 
 static hb_bool_t
-hb_font_get_glyph_v_origin_nil (hb_font_t *font,
+hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
 				void *font_data HB_UNUSED,
 				hb_codepoint_t glyph,
 				hb_position_t *x,
 				hb_position_t *y,
 				void *user_data HB_UNUSED)
 {
-  if (font->parent) {
-    hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
-    if (ret)
-      font->parent_scale_position (x, y);
-    return ret;
-  }
+  *x = *y = 0;
+  return true;
+}
+static hb_bool_t
+hb_font_get_glyph_h_origin_parent (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   hb_codepoint_t glyph,
+				   hb_position_t *x,
+				   hb_position_t *y,
+				   void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
+  if (ret)
+    font->parent_scale_position (x, y);
+  return ret;
+}
 
+static hb_bool_t
+hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
+				void *font_data HB_UNUSED,
+				hb_codepoint_t glyph,
+				hb_position_t *x,
+				hb_position_t *y,
+				void *user_data HB_UNUSED)
+{
   *x = *y = 0;
   return false;
 }
+static hb_bool_t
+hb_font_get_glyph_v_origin_parent (hb_font_t *font,
+				   void *font_data HB_UNUSED,
+				   hb_codepoint_t glyph,
+				   hb_position_t *x,
+				   hb_position_t *y,
+				   void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
+  if (ret)
+    font->parent_scale_position (x, y);
+  return ret;
+}
 
 static hb_position_t
-hb_font_get_glyph_h_kerning_nil (hb_font_t *font,
+hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t left_glyph,
 				 hb_codepoint_t right_glyph,
 				 void *user_data HB_UNUSED)
 {
-  if (font->parent)
-    return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
-
   return 0;
 }
+static hb_position_t
+hb_font_get_glyph_h_kerning_parent (hb_font_t *font,
+				    void *font_data HB_UNUSED,
+				    hb_codepoint_t left_glyph,
+				    hb_codepoint_t right_glyph,
+				    void *user_data HB_UNUSED)
+{
+  return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
+}
 
 static hb_position_t
-hb_font_get_glyph_v_kerning_nil (hb_font_t *font,
+hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t top_glyph,
 				 hb_codepoint_t bottom_glyph,
 				 void *user_data HB_UNUSED)
 {
-  if (font->parent)
-    return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
-
   return 0;
 }
+static hb_position_t
+hb_font_get_glyph_v_kerning_parent (hb_font_t *font,
+				    void *font_data HB_UNUSED,
+				    hb_codepoint_t top_glyph,
+				    hb_codepoint_t bottom_glyph,
+				    void *user_data HB_UNUSED)
+{
+  return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
+}
 
 static hb_bool_t
-hb_font_get_glyph_extents_nil (hb_font_t *font,
+hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
 			       void *font_data HB_UNUSED,
 			       hb_codepoint_t glyph,
 			       hb_glyph_extents_t *extents,
 			       void *user_data HB_UNUSED)
 {
-  if (font->parent) {
-    hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
-    if (ret) {
-      font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
-      font->parent_scale_distance (&extents->width, &extents->height);
-    }
-    return ret;
-  }
-
   memset (extents, 0, sizeof (*extents));
   return false;
 }
+static hb_bool_t
+hb_font_get_glyph_extents_parent (hb_font_t *font,
+				  void *font_data HB_UNUSED,
+				  hb_codepoint_t glyph,
+				  hb_glyph_extents_t *extents,
+				  void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
+  if (ret) {
+    font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
+    font->parent_scale_distance (&extents->width, &extents->height);
+  }
+  return ret;
+}
 
 static hb_bool_t
-hb_font_get_glyph_contour_point_nil (hb_font_t *font,
+hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
 				     void *font_data HB_UNUSED,
 				     hb_codepoint_t glyph,
 				     unsigned int point_index,
@@ -176,45 +270,63 @@
 				     hb_position_t *y,
 				     void *user_data HB_UNUSED)
 {
-  if (font->parent) {
-    hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
-    if (ret)
-      font->parent_scale_position (x, y);
-    return ret;
-  }
-
   *x = *y = 0;
   return false;
 }
+static hb_bool_t
+hb_font_get_glyph_contour_point_parent (hb_font_t *font,
+					void *font_data HB_UNUSED,
+					hb_codepoint_t glyph,
+					unsigned int point_index,
+					hb_position_t *x,
+					hb_position_t *y,
+					void *user_data HB_UNUSED)
+{
+  hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
+  if (ret)
+    font->parent_scale_position (x, y);
+  return ret;
+}
 
 static hb_bool_t
-hb_font_get_glyph_name_nil (hb_font_t *font,
+hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
 			    void *font_data HB_UNUSED,
 			    hb_codepoint_t glyph,
 			    char *name, unsigned int size,
 			    void *user_data HB_UNUSED)
 {
-  if (font->parent)
-    return font->parent->get_glyph_name (glyph, name, size);
-
   if (size) *name = '\0';
   return false;
 }
+static hb_bool_t
+hb_font_get_glyph_name_parent (hb_font_t *font,
+			       void *font_data HB_UNUSED,
+			       hb_codepoint_t glyph,
+			       char *name, unsigned int size,
+			       void *user_data HB_UNUSED)
+{
+  return font->parent->get_glyph_name (glyph, name, size);
+}
 
 static hb_bool_t
-hb_font_get_glyph_from_name_nil (hb_font_t *font,
+hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
 				 void *font_data HB_UNUSED,
 				 const char *name, int len, /* -1 means nul-terminated */
 				 hb_codepoint_t *glyph,
 				 void *user_data HB_UNUSED)
 {
-  if (font->parent)
-    return font->parent->get_glyph_from_name (name, len, glyph);
-
   *glyph = 0;
   return false;
 }
-
+static hb_bool_t
+hb_font_get_glyph_from_name_parent (hb_font_t *font,
+				    void *font_data HB_UNUSED,
+				    const char *name, int len, /* -1 means nul-terminated */
+				    hb_codepoint_t *glyph,
+				    void *user_data HB_UNUSED)
+{
+  return font->parent->get_glyph_from_name (name, len, glyph);
+}
 
 static const hb_font_funcs_t _hb_font_funcs_nil = {
   HB_OBJECT_HEADER_STATIC,
@@ -222,9 +334,44 @@
   true, /* immutable */
 
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
+  },
+  {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  },
+  {
+    {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
+      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+    }
+  }
+};
+static const hb_font_funcs_t _hb_font_funcs_parent = {
+  HB_OBJECT_HEADER_STATIC,
+
+  true, /* immutable */
+
+  {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  },
+  {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  },
+  {
+    {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent,
+      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+    }
   }
 };
 
@@ -236,7 +383,7 @@
  *
  * Return value: (transfer full): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_font_funcs_t *
 hb_font_funcs_create (void)
@@ -246,7 +393,7 @@
   if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
     return hb_font_funcs_get_empty ();
 
-  ffuncs->get = _hb_font_funcs_nil.get;
+  ffuncs->get = _hb_font_funcs_parent.get;
 
   return ffuncs;
 }
@@ -258,12 +405,12 @@
  *
  * Return value: (transfer full): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_font_funcs_t *
 hb_font_funcs_get_empty (void)
 {
-  return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
+  return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_parent);
 }
 
 /**
@@ -274,7 +421,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_font_funcs_t *
 hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
@@ -288,7 +435,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
@@ -315,7 +462,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
@@ -336,7 +483,7 @@
  *
  * Return value: (transfer none): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void *
 hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
@@ -352,7 +499,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
@@ -371,7 +518,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
@@ -398,11 +545,11 @@
     ffuncs->destroy.name (ffuncs->user_data.name);                       \
                                                                          \
   if (func) {                                                            \
-    ffuncs->get.name = func;                                             \
+    ffuncs->get.f.name = func;                                           \
     ffuncs->user_data.name = user_data;                                  \
     ffuncs->destroy.name = destroy;                                      \
   } else {                                                               \
-    ffuncs->get.name = hb_font_get_##name##_nil;                         \
+    ffuncs->get.f.name = hb_font_get_##name##_parent;                    \
     ffuncs->user_data.name = NULL;                                       \
     ffuncs->destroy.name = NULL;                                         \
   }                                                                      \
@@ -411,10 +558,53 @@
 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
+bool
+hb_font_t::has_func (unsigned int i)
+{
+  if (parent && parent != hb_font_get_empty () && parent->has_func (i))
+    return true;
+  return this->klass->get.array[i] != _hb_font_funcs_parent.get.array[i];
+}
 
 /* Public getters */
 
 /**
+ * hb_font_get_h_extents:
+ * @font: a font.
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.1.3
+ **/
+hb_bool_t
+hb_font_get_h_extents (hb_font_t *font,
+		       hb_font_extents_t *extents)
+{
+  return font->get_font_h_extents (extents);
+}
+
+/**
+ * hb_font_get_v_extents:
+ * @font: a font.
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.1.3
+ **/
+hb_bool_t
+hb_font_get_v_extents (hb_font_t *font,
+		       hb_font_extents_t *extents)
+{
+  return font->get_font_v_extents (extents);
+}
+
+/**
  * hb_font_get_glyph:
  * @font: a font.
  * @unicode: 
@@ -425,7 +615,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph (hb_font_t *font,
@@ -444,7 +634,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_position_t
 hb_font_get_glyph_h_advance (hb_font_t *font,
@@ -462,7 +652,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_position_t
 hb_font_get_glyph_v_advance (hb_font_t *font,
@@ -482,7 +672,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph_h_origin (hb_font_t *font,
@@ -503,7 +693,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph_v_origin (hb_font_t *font,
@@ -523,7 +713,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_position_t
 hb_font_get_glyph_h_kerning (hb_font_t *font,
@@ -542,7 +732,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_position_t
 hb_font_get_glyph_v_kerning (hb_font_t *font,
@@ -561,7 +751,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph_extents (hb_font_t *font,
@@ -583,7 +773,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph_contour_point (hb_font_t *font,
@@ -604,7 +794,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph_name (hb_font_t *font,
@@ -625,7 +815,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph_from_name (hb_font_t *font,
@@ -639,6 +829,23 @@
 /* A bit higher-level, and with fallback */
 
 /**
+ * hb_font_get_extents_for_direction:
+ * @font: a font.
+ * @direction:
+ * @extents:
+ *
+ *
+ *
+ * Since: 1.1.3
+ **/
+void
+hb_font_get_extents_for_direction (hb_font_t *font,
+				   hb_direction_t direction,
+				   hb_font_extents_t *extents)
+{
+  return font->get_extents_for_direction (direction, extents);
+}
+/**
  * hb_font_get_glyph_advance_for_direction:
  * @font: a font.
  * @glyph: 
@@ -648,7 +855,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_get_glyph_advance_for_direction (hb_font_t *font,
@@ -669,7 +876,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_get_glyph_origin_for_direction (hb_font_t *font,
@@ -690,7 +897,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_add_glyph_origin_for_direction (hb_font_t *font,
@@ -711,7 +918,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
@@ -733,7 +940,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
@@ -755,7 +962,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph_extents_for_origin (hb_font_t *font,
@@ -779,7 +986,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
@@ -800,7 +1007,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_glyph_to_string (hb_font_t *font,
@@ -814,7 +1021,7 @@
 /**
  * hb_font_glyph_from_string:
  * @font: a font.
- * @s: (array length=len): 
+ * @s: (array length=len) (element-type uint8_t): 
  * @len: 
  * @glyph: (out): 
  *
@@ -822,7 +1029,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_glyph_from_string (hb_font_t *font,
@@ -845,7 +1052,7 @@
  *
  * Return value: (transfer full): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_font_t *
 hb_font_create (hb_face_t *face)
@@ -854,15 +1061,16 @@
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
-  if (unlikely (hb_object_is_inert (face)))
-    return hb_font_get_empty ();
   if (!(font = hb_object_create<hb_font_t> ()))
     return hb_font_get_empty ();
 
   hb_face_make_immutable (face);
+  font->parent = hb_font_get_empty ();
   font->face = hb_face_reference (face);
   font->klass = hb_font_funcs_get_empty ();
 
+  font->x_scale = font->y_scale = hb_face_get_upem (face);
+
   return font;
 }
 
@@ -874,20 +1082,19 @@
  *
  * Return value: (transfer full): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_font_t *
 hb_font_create_sub_font (hb_font_t *parent)
 {
   if (unlikely (!parent))
-    return hb_font_get_empty ();
+    parent = hb_font_get_empty ();
 
   hb_font_t *font = hb_font_create (parent->face);
 
   if (unlikely (hb_object_is_inert (font)))
     return font;
 
-  hb_font_make_immutable (parent);
   font->parent = hb_font_reference (parent);
 
   font->x_scale = parent->x_scale;
@@ -905,7 +1112,7 @@
  *
  * Return value: (transfer full)
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_font_t *
 hb_font_get_empty (void)
@@ -918,8 +1125,8 @@
     NULL, /* parent */
     const_cast<hb_face_t *> (&_hb_face_nil),
 
-    0, /* x_scale */
-    0, /* y_scale */
+    1000, /* x_scale */
+    1000, /* y_scale */
 
     0, /* x_ppem */
     0, /* y_ppem */
@@ -946,7 +1153,7 @@
  *
  * Return value: (transfer full): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_font_t *
 hb_font_reference (hb_font_t *font)
@@ -960,7 +1167,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_destroy (hb_font_t *font)
@@ -993,7 +1200,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_set_user_data (hb_font_t          *font,
@@ -1014,7 +1221,7 @@
  *
  * Return value: (transfer none): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void *
 hb_font_get_user_data (hb_font_t          *font,
@@ -1029,7 +1236,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_make_immutable (hb_font_t *font)
@@ -1037,6 +1244,9 @@
   if (unlikely (hb_object_is_inert (font)))
     return;
 
+  if (font->parent)
+    hb_font_make_immutable (font->parent);
+
   font->immutable = true;
 }
 
@@ -1048,7 +1258,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_font_is_immutable (hb_font_t *font)
@@ -1057,6 +1267,32 @@
 }
 
 /**
+ * hb_font_set_parent:
+ * @font: a font.
+ * @parent: new parent.
+ *
+ * Sets parent font of @font.
+ *
+ * Since: 1.0.5
+ **/
+void
+hb_font_set_parent (hb_font_t *font,
+		    hb_font_t *parent)
+{
+  if (font->immutable)
+    return;
+
+  if (!parent)
+    parent = hb_font_get_empty ();
+
+  hb_font_t *old = font->parent;
+
+  font->parent = hb_font_reference (parent);
+
+  hb_font_destroy (old);
+}
+
+/**
  * hb_font_get_parent:
  * @font: a font.
  *
@@ -1064,7 +1300,7 @@
  *
  * Return value: (transfer none): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_font_t *
 hb_font_get_parent (hb_font_t *font)
@@ -1080,7 +1316,7 @@
  *
  * Return value: (transfer none): 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_face_t *
 hb_font_get_face (hb_font_t *font)
@@ -1098,7 +1334,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_set_funcs (hb_font_t         *font,
@@ -1133,7 +1369,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_set_funcs_data (hb_font_t         *font,
@@ -1163,7 +1399,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_set_scale (hb_font_t *font,
@@ -1185,7 +1421,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_get_scale (hb_font_t *font,
@@ -1204,7 +1440,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_set_ppem (hb_font_t *font,
@@ -1226,7 +1462,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_font_get_ppem (hb_font_t *font,
diff --git a/src/hb-font.h b/src/hb-font.h
index 7273db4..82d056c 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -46,19 +46,19 @@
 
 typedef struct hb_font_funcs_t hb_font_funcs_t;
 
-hb_font_funcs_t *
+HB_EXTERN hb_font_funcs_t *
 hb_font_funcs_create (void);
 
-hb_font_funcs_t *
+HB_EXTERN hb_font_funcs_t *
 hb_font_funcs_get_empty (void);
 
-hb_font_funcs_t *
+HB_EXTERN hb_font_funcs_t *
 hb_font_funcs_reference (hb_font_funcs_t *ffuncs);
 
-void
+HB_EXTERN void
 hb_font_funcs_destroy (hb_font_funcs_t *ffuncs);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
 			     hb_user_data_key_t *key,
 			     void *              data,
@@ -66,31 +66,56 @@
 			     hb_bool_t           replace);
 
 
-void *
+HB_EXTERN void *
 hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
 			     hb_user_data_key_t *key);
 
 
-void
+HB_EXTERN void
 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
 
 
-/* glyph extents */
+/* font and glyph extents */
 
+/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */
+typedef struct hb_font_extents_t
+{
+  hb_position_t ascender; /* typographic ascender. */
+  hb_position_t descender; /* typographic descender. */
+  hb_position_t line_gap; /* suggested line spacing gap. */
+  /*< private >*/
+  hb_position_t reserved9;
+  hb_position_t reserved8;
+  hb_position_t reserved7;
+  hb_position_t reserved6;
+  hb_position_t reserved5;
+  hb_position_t reserved4;
+  hb_position_t reserved3;
+  hb_position_t reserved2;
+  hb_position_t reserved1;
+} hb_font_extents_t;
+
+/* Note that height is negative in coordinate systems that grow up. */
 typedef struct hb_glyph_extents_t
 {
-  hb_position_t x_bearing;
-  hb_position_t y_bearing;
-  hb_position_t width;
-  hb_position_t height;
+  hb_position_t x_bearing; /* left side of glyph from origin. */
+  hb_position_t y_bearing; /* top side of glyph from origin. */
+  hb_position_t width; /* distance from left to right side. */
+  hb_position_t height; /* distance from top to bottom side. */
 } hb_glyph_extents_t;
 
-
 /* func types */
 
+typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
+						       hb_font_extents_t *metrics,
+						       void *user_data);
+typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
+typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
+
+
 typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
 					       hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 					       hb_codepoint_t *glyph,
@@ -140,6 +165,38 @@
 /* func setters */
 
 /**
+ * hb_font_funcs_set_font_h_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs,
+				       hb_font_get_font_h_extents_func_t func,
+				       void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_font_v_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
+				       hb_font_get_font_v_extents_func_t func,
+				       void *user_data, hb_destroy_func_t destroy);
+
+/**
  * hb_font_funcs_set_glyph_func:
  * @ffuncs: font functions.
  * @func: (closure user_data) (destroy destroy) (scope notified):
@@ -148,9 +205,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
 			      hb_font_get_glyph_func_t func,
 			      void *user_data, hb_destroy_func_t destroy);
@@ -164,9 +221,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_h_advance_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
@@ -180,9 +237,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_v_advance_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
@@ -196,9 +253,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
 				       hb_font_get_glyph_h_origin_func_t func,
 				       void *user_data, hb_destroy_func_t destroy);
@@ -212,9 +269,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
 				       hb_font_get_glyph_v_origin_func_t func,
 				       void *user_data, hb_destroy_func_t destroy);
@@ -228,9 +285,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_h_kerning_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
@@ -244,9 +301,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_v_kerning_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
@@ -260,9 +317,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
 				      hb_font_get_glyph_extents_func_t func,
 				      void *user_data, hb_destroy_func_t destroy);
@@ -276,9 +333,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
 					    hb_font_get_glyph_contour_point_func_t func,
 					    void *user_data, hb_destroy_func_t destroy);
@@ -292,9 +349,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
 				   hb_font_get_glyph_name_func_t func,
 				   void *user_data, hb_destroy_func_t destroy);
@@ -308,59 +365,65 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_from_name_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
 
-
 /* func dispatch */
 
-hb_bool_t
+HB_EXTERN hb_bool_t
+hb_font_get_h_extents (hb_font_t *font,
+		       hb_font_extents_t *extents);
+HB_EXTERN hb_bool_t
+hb_font_get_v_extents (hb_font_t *font,
+		       hb_font_extents_t *extents);
+
+HB_EXTERN hb_bool_t
 hb_font_get_glyph (hb_font_t *font,
 		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 		   hb_codepoint_t *glyph);
 
-hb_position_t
+HB_EXTERN hb_position_t
 hb_font_get_glyph_h_advance (hb_font_t *font,
 			     hb_codepoint_t glyph);
-hb_position_t
+HB_EXTERN hb_position_t
 hb_font_get_glyph_v_advance (hb_font_t *font,
 			     hb_codepoint_t glyph);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_get_glyph_h_origin (hb_font_t *font,
 			    hb_codepoint_t glyph,
 			    hb_position_t *x, hb_position_t *y);
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_get_glyph_v_origin (hb_font_t *font,
 			    hb_codepoint_t glyph,
 			    hb_position_t *x, hb_position_t *y);
 
-hb_position_t
+HB_EXTERN hb_position_t
 hb_font_get_glyph_h_kerning (hb_font_t *font,
 			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
-hb_position_t
+HB_EXTERN hb_position_t
 hb_font_get_glyph_v_kerning (hb_font_t *font,
 			     hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_get_glyph_extents (hb_font_t *font,
 			   hb_codepoint_t glyph,
 			   hb_glyph_extents_t *extents);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_get_glyph_contour_point (hb_font_t *font,
 				 hb_codepoint_t glyph, unsigned int point_index,
 				 hb_position_t *x, hb_position_t *y);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_get_glyph_name (hb_font_t *font,
 			hb_codepoint_t glyph,
 			char *name, unsigned int size);
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_get_glyph_from_name (hb_font_t *font,
 			     const char *name, int len, /* -1 means nul-terminated */
 			     hb_codepoint_t *glyph);
@@ -368,52 +431,56 @@
 
 /* high-level funcs, with fallback */
 
-void
+HB_EXTERN void
+hb_font_get_extents_for_direction (hb_font_t *font,
+				   hb_direction_t direction,
+				   hb_font_extents_t *extents);
+HB_EXTERN void
 hb_font_get_glyph_advance_for_direction (hb_font_t *font,
 					 hb_codepoint_t glyph,
 					 hb_direction_t direction,
 					 hb_position_t *x, hb_position_t *y);
-void
+HB_EXTERN void
 hb_font_get_glyph_origin_for_direction (hb_font_t *font,
 					hb_codepoint_t glyph,
 					hb_direction_t direction,
 					hb_position_t *x, hb_position_t *y);
-void
+HB_EXTERN void
 hb_font_add_glyph_origin_for_direction (hb_font_t *font,
 					hb_codepoint_t glyph,
 					hb_direction_t direction,
 					hb_position_t *x, hb_position_t *y);
-void
+HB_EXTERN void
 hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
 					     hb_codepoint_t glyph,
 					     hb_direction_t direction,
 					     hb_position_t *x, hb_position_t *y);
 
-void
+HB_EXTERN void
 hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
 					 hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
 					 hb_direction_t direction,
 					 hb_position_t *x, hb_position_t *y);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_get_glyph_extents_for_origin (hb_font_t *font,
 				      hb_codepoint_t glyph,
 				      hb_direction_t direction,
 				      hb_glyph_extents_t *extents);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
 					    hb_codepoint_t glyph, unsigned int point_index,
 					    hb_direction_t direction,
 					    hb_position_t *x, hb_position_t *y);
 
 /* Generates gidDDD if glyph has no name. */
-void
+HB_EXTERN void
 hb_font_glyph_to_string (hb_font_t *font,
 			 hb_codepoint_t glyph,
 			 char *s, unsigned int size);
 /* Parses gidDDD and uniUUUU strings automatically. */
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_glyph_from_string (hb_font_t *font,
 			   const char *s, int len, /* -1 means nul-terminated */
 			   hb_codepoint_t *glyph);
@@ -425,22 +492,22 @@
 
 /* Fonts are very light-weight objects */
 
-hb_font_t *
+HB_EXTERN hb_font_t *
 hb_font_create (hb_face_t *face);
 
-hb_font_t *
+HB_EXTERN hb_font_t *
 hb_font_create_sub_font (hb_font_t *parent);
 
-hb_font_t *
+HB_EXTERN hb_font_t *
 hb_font_get_empty (void);
 
-hb_font_t *
+HB_EXTERN hb_font_t *
 hb_font_reference (hb_font_t *font);
 
-void
+HB_EXTERN void
 hb_font_destroy (hb_font_t *font);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_set_user_data (hb_font_t          *font,
 		       hb_user_data_key_t *key,
 		       void *              data,
@@ -448,42 +515,46 @@
 		       hb_bool_t           replace);
 
 
-void *
+HB_EXTERN void *
 hb_font_get_user_data (hb_font_t          *font,
 		       hb_user_data_key_t *key);
 
-void
+HB_EXTERN void
 hb_font_make_immutable (hb_font_t *font);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_font_is_immutable (hb_font_t *font);
 
-hb_font_t *
+HB_EXTERN void
+hb_font_set_parent (hb_font_t *font,
+		    hb_font_t *parent);
+
+HB_EXTERN hb_font_t *
 hb_font_get_parent (hb_font_t *font);
 
-hb_face_t *
+HB_EXTERN hb_face_t *
 hb_font_get_face (hb_font_t *font);
 
 
-void
+HB_EXTERN void
 hb_font_set_funcs (hb_font_t         *font,
 		   hb_font_funcs_t   *klass,
 		   void              *font_data,
 		   hb_destroy_func_t  destroy);
 
 /* Be *very* careful with this function! */
-void
+HB_EXTERN void
 hb_font_set_funcs_data (hb_font_t         *font,
 		        void              *font_data,
 		        hb_destroy_func_t  destroy);
 
 
-void
+HB_EXTERN void
 hb_font_set_scale (hb_font_t *font,
 		   int x_scale,
 		   int y_scale);
 
-void
+HB_EXTERN void
 hb_font_get_scale (hb_font_t *font,
 		   int *x_scale,
 		   int *y_scale);
@@ -491,12 +562,12 @@
 /*
  * A zero value means "no hinting in that direction"
  */
-void
+HB_EXTERN void
 hb_font_set_ppem (hb_font_t *font,
 		  unsigned int x_ppem,
 		  unsigned int y_ppem);
 
-void
+HB_EXTERN void
 hb_font_get_ppem (hb_font_t *font,
 		  unsigned int *x_ppem,
 		  unsigned int *y_ppem);
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index f57f566..eed1787 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -1,6 +1,7 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
  * Copyright © 2009  Keith Stribley
+ * Copyright © 2015  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -23,6 +24,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
@@ -46,17 +48,15 @@
  * In general, this file does a fine job of what it's supposed to do.
  * There are, however, things that need more work:
  *
- *   - We don't handle any load_flags.  That definitely has API implications. :(
- *     I believe hb_ft_font_create() should take load_flags input.
- *     In particular, FT_Get_Advance() without the NO_HINTING flag seems to be
- *     buggy.
+ *   - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
+ *     Have not investigated.
  *
- *     FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
+ *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
  *     would work fine.  However, we also abuse this API for performing in font-space,
  *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
  *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
- *     pass NO_HINTING around.  This seems to work best, until we go ahead and add a full
- *     load_flags API.
+ *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
+ *     ourselves, like we do in uniscribe, etc.
  *
  *   - We don't handle / allow for emboldening / obliqueing.
  *
@@ -66,6 +66,94 @@
  */
 
 
+struct hb_ft_font_t
+{
+  FT_Face ft_face;
+  int load_flags;
+  bool unref; /* Whether to destroy ft_face when done. */
+};
+
+static hb_ft_font_t *
+_hb_ft_font_create (FT_Face ft_face, bool unref)
+{
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
+
+  if (unlikely (!ft_font))
+    return NULL;
+
+  ft_font->ft_face = ft_face;
+  ft_font->unref = unref;
+
+  ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
+
+  return ft_font;
+}
+
+static void
+_hb_ft_font_destroy (hb_ft_font_t *ft_font)
+{
+  if (ft_font->unref)
+    FT_Done_Face (ft_font->ft_face);
+
+  free (ft_font);
+}
+
+/**
+ * hb_ft_font_set_load_flags:
+ * @font:
+ * @load_flags:
+ *
+ * 
+ *
+ * Since: 1.0.5
+ **/
+void
+hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
+{
+  if (font->immutable)
+    return;
+
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+    return;
+
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+
+  ft_font->load_flags = load_flags;
+}
+
+/**
+ * hb_ft_font_get_load_flags:
+ * @font:
+ *
+ * 
+ *
+ * Return value:
+ * Since: 1.0.5
+ **/
+int
+hb_ft_font_get_load_flags (hb_font_t *font)
+{
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+    return 0;
+
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
+
+  return ft_font->load_flags;
+}
+
+FT_Face
+hb_ft_font_get_face (hb_font_t *font)
+{
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+    return NULL;
+
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
+
+  return ft_font->ft_face;
+}
+
+
+
 static hb_bool_t
 hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
 		 void *font_data,
@@ -75,15 +163,19 @@
 		 void *user_data HB_UNUSED)
 
 {
-  FT_Face ft_face = (FT_Face) font_data;
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  unsigned int g;
 
-  if (unlikely (variation_selector)) {
-    *glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
-    return *glyph != 0;
-  }
+  if (likely (!variation_selector))
+    g = FT_Get_Char_Index (ft_font->ft_face, unicode);
+  else
+    g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
 
-  *glyph = FT_Get_Char_Index (ft_face, unicode);
-  return *glyph != 0;
+  if (unlikely (!g))
+    return false;
+
+  *glyph = g;
+  return true;
 }
 
 static hb_position_t
@@ -92,11 +184,10 @@
 			   hb_codepoint_t glyph,
 			   void *user_data HB_UNUSED)
 {
-  FT_Face ft_face = (FT_Face) font_data;
-  int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   FT_Fixed v;
 
-  if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
+  if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
     return 0;
 
   if (font->x_scale < 0)
@@ -111,31 +202,21 @@
 			   hb_codepoint_t glyph,
 			   void *user_data HB_UNUSED)
 {
-  FT_Face ft_face = (FT_Face) font_data;
-  int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT;
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   FT_Fixed v;
 
-  if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
+  if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
     return 0;
 
+  if (font->y_scale < 0)
+    v = -v;
+
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
   return (-v + (1<<9)) >> 10;
 }
 
 static hb_bool_t
-hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
-			  void *font_data HB_UNUSED,
-			  hb_codepoint_t glyph HB_UNUSED,
-			  hb_position_t *x HB_UNUSED,
-			  hb_position_t *y HB_UNUSED,
-			  void *user_data HB_UNUSED)
-{
-  /* We always work in the horizontal coordinates. */
-  return true;
-}
-
-static hb_bool_t
 hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
 			  void *font_data,
 			  hb_codepoint_t glyph,
@@ -143,10 +224,10 @@
 			  hb_position_t *y,
 			  void *user_data HB_UNUSED)
 {
-  FT_Face ft_face = (FT_Face) font_data;
-  int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
 
-  if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
     return false;
 
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
@@ -154,6 +235,11 @@
   *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
   *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
 
+  if (font->x_scale < 0)
+    *x = -*x;
+  if (font->y_scale < 0)
+    *y = -*y;
+
   return true;
 }
 
@@ -164,27 +250,16 @@
 			   hb_codepoint_t right_glyph,
 			   void *user_data HB_UNUSED)
 {
-  FT_Face ft_face = (FT_Face) font_data;
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   FT_Vector kerningv;
 
   FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
-  if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, mode, &kerningv))
+  if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
     return 0;
 
   return kerningv.x;
 }
 
-static hb_position_t
-hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
-			   void *font_data HB_UNUSED,
-			   hb_codepoint_t top_glyph HB_UNUSED,
-			   hb_codepoint_t bottom_glyph HB_UNUSED,
-			   void *user_data HB_UNUSED)
-{
-  /* FreeType API doesn't support vertical kerning */
-  return 0;
-}
-
 static hb_bool_t
 hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
 			 void *font_data,
@@ -192,16 +267,26 @@
 			 hb_glyph_extents_t *extents,
 			 void *user_data HB_UNUSED)
 {
-  FT_Face ft_face = (FT_Face) font_data;
-  int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
 
-  if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
     return false;
 
   extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
   extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
   extents->width = ft_face->glyph->metrics.width;
   extents->height = -ft_face->glyph->metrics.height;
+  if (font->x_scale < 0)
+  {
+    extents->x_bearing = -extents->x_bearing;
+    extents->width = -extents->width;
+  }
+  if (font->y_scale < 0)
+  {
+    extents->y_bearing = -extents->y_bearing;
+    extents->height = -extents->height;
+  }
   return true;
 }
 
@@ -214,10 +299,10 @@
 			       hb_position_t *y,
 			       void *user_data HB_UNUSED)
 {
-  FT_Face ft_face = (FT_Face) font_data;
-  int load_flags = FT_LOAD_DEFAULT;
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
 
-  if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
       return false;
 
   if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
@@ -239,9 +324,9 @@
 		      char *name, unsigned int size,
 		      void *user_data HB_UNUSED)
 {
-  FT_Face ft_face = (FT_Face) font_data;
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
 
-  hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
+  hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
   if (ret && (size && !*name))
     ret = false;
 
@@ -255,7 +340,8 @@
 			   hb_codepoint_t *glyph,
 			   void *user_data HB_UNUSED)
 {
-  FT_Face ft_face = (FT_Face) font_data;
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
 
   if (len < 0)
     *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
@@ -280,23 +366,76 @@
   return *glyph != 0;
 }
 
-
-static hb_font_funcs_t *
-_hb_ft_get_font_funcs (void)
+static hb_bool_t
+hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
+			  void *font_data,
+			  hb_font_extents_t *metrics,
+			  void *user_data HB_UNUSED)
 {
-  static const hb_font_funcs_t ft_ffuncs = {
-    HB_OBJECT_HEADER_STATIC,
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Face ft_face = ft_font->ft_face;
+  metrics->ascender = ft_face->size->metrics.ascender;
+  metrics->descender = ft_face->size->metrics.descender;
+  metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
+  if (font->y_scale < 0)
+  {
+    metrics->ascender = -metrics->ascender;
+    metrics->descender = -metrics->descender;
+    metrics->line_gap = -metrics->line_gap;
+  }
+  return true;
+}
 
-    true, /* immutable */
+static hb_font_funcs_t *static_ft_funcs = NULL;
 
-    {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name,
-      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
+#ifdef HB_USE_ATEXIT
+static
+void free_static_ft_funcs (void)
+{
+  hb_font_funcs_destroy (static_ft_funcs);
+}
+#endif
+
+static void
+_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
+{
+retry:
+  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
+
+  if (unlikely (!funcs))
+  {
+    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_glyph_func (funcs, hb_ft_get_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_make_immutable (funcs);
+
+    if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
+      hb_font_funcs_destroy (funcs);
+      goto retry;
     }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
+#endif
   };
 
-  return const_cast<hb_font_funcs_t *> (&ft_ffuncs);
+  hb_font_set_funcs (font,
+		     funcs,
+		     _hb_ft_font_create (ft_face, unref),
+		     (hb_destroy_func_t) _hb_ft_font_destroy);
 }
 
 
@@ -335,7 +474,7 @@
  * 
  *
  * Return value: (transfer full): 
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_face_t *
 hb_ft_face_create (FT_Face           ft_face,
@@ -369,7 +508,7 @@
  * 
  *
  * Return value: (transfer full): 
- * Since: 1.0
+ * Since: 0.9.38
  **/
 hb_face_t *
 hb_ft_face_create_referenced (FT_Face ft_face)
@@ -391,7 +530,7 @@
  * 
  *
  * Return value: (transfer full): 
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_face_t *
 hb_ft_face_create_cached (FT_Face ft_face)
@@ -408,11 +547,6 @@
   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
 }
 
-static void
-_do_nothing (void)
-{
-}
-
 
 /**
  * hb_ft_font_create:
@@ -422,7 +556,7 @@
  * 
  *
  * Return value: (transfer full): 
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_font_t *
 hb_ft_font_create (FT_Face           ft_face,
@@ -434,9 +568,7 @@
   face = hb_ft_face_create (ft_face, destroy);
   font = hb_font_create (face);
   hb_face_destroy (face);
-  hb_font_set_funcs (font,
-		     _hb_ft_get_font_funcs (),
-		     ft_face, (hb_destroy_func_t) _do_nothing);
+  _hb_ft_font_set_funcs (font, ft_face, false);
   hb_font_set_scale (font,
 		     (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16),
 		     (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16));
@@ -456,7 +588,7 @@
  * 
  *
  * Return value: (transfer full): 
- * Since: 1.0
+ * Since: 0.9.38
  **/
 hb_font_t *
 hb_ft_font_create_referenced (FT_Face ft_face)
@@ -550,18 +682,6 @@
   ft_face->generic.data = blob;
   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
 
-  hb_font_set_funcs (font,
-		     _hb_ft_get_font_funcs (),
-		     ft_face,
-		     (hb_destroy_func_t) FT_Done_Face);
-}
-
-FT_Face
-hb_ft_font_get_face (hb_font_t *font)
-{
-  if (font->destroy == (hb_destroy_func_t) FT_Done_Face ||
-      font->destroy == (hb_destroy_func_t) _do_nothing)
-    return (FT_Face) font->user_data;
-
-  return NULL;
+  _hb_ft_font_set_funcs (font, ft_face, true);
+  hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
 }
diff --git a/src/hb-ft.h b/src/hb-ft.h
index 92f4b36..dc8ef85 100644
--- a/src/hb-ft.h
+++ b/src/hb-ft.h
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2015  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -22,6 +23,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_FT_H
@@ -57,7 +59,7 @@
  * probably should use (the more recent) hb_ft_face_create_referenced()
  * instead.
  */
-hb_face_t *
+HB_EXTERN hb_face_t *
 hb_ft_face_create (FT_Face           ft_face,
 		   hb_destroy_func_t destroy);
 
@@ -69,7 +71,7 @@
  * Client is still responsible for making sure that ft-face is destroyed
  * after hb-face is.
  */
-hb_face_t *
+HB_EXTERN hb_face_t *
 hb_ft_face_create_cached (FT_Face ft_face);
 
 /* This version is like hb_ft_face_create(), except that it calls
@@ -79,7 +81,7 @@
  * This is the most convenient version to use.  Use it unless you have
  * very good reasons not to.
  */
-hb_face_t *
+HB_EXTERN hb_face_t *
 hb_ft_face_create_referenced (FT_Face ft_face);
 
 
@@ -96,23 +98,28 @@
 
 /* See notes on hb_ft_face_create().  Same issues re lifecycle-management
  * apply here.  Use hb_ft_font_create_referenced() if you can. */
-hb_font_t *
+HB_EXTERN hb_font_t *
 hb_ft_font_create (FT_Face           ft_face,
 		   hb_destroy_func_t destroy);
 
 /* See notes on hb_ft_face_create_referenced() re lifecycle-management
  * issues. */
-hb_font_t *
+HB_EXTERN hb_font_t *
 hb_ft_font_create_referenced (FT_Face ft_face);
 
+HB_EXTERN FT_Face
+hb_ft_font_get_face (hb_font_t *font);
+
+HB_EXTERN void
+hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
+
+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. */
-void
+HB_EXTERN void
 hb_ft_font_set_funcs (hb_font_t *font);
 
-FT_Face
-hb_ft_font_get_face (hb_font_t *font);
-
 
 HB_END_DECLS
 
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 61dff5e..e203524 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -382,6 +382,11 @@
   return const_cast<hb_unicode_funcs_t *> (&_hb_glib_unicode_funcs);
 }
 
+/**
+ * hb_glib_blob_create:
+ *
+ * Since: 0.9.38
+ **/
 hb_blob_t *
 hb_glib_blob_create (GBytes *gbytes)
 {
diff --git a/src/hb-glib.h b/src/hb-glib.h
index 1a8f42e..12c3e3b 100644
--- a/src/hb-glib.h
+++ b/src/hb-glib.h
@@ -36,17 +36,17 @@
 HB_BEGIN_DECLS
 
 
-hb_script_t
+HB_EXTERN hb_script_t
 hb_glib_script_to_script (GUnicodeScript script);
 
-GUnicodeScript
+HB_EXTERN GUnicodeScript
 hb_glib_script_from_script (hb_script_t script);
 
 
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void);
 
-hb_blob_t *
+HB_EXTERN hb_blob_t *
 hb_glib_blob_create (GBytes *gbytes);
 
 
diff --git a/src/hb-gobject-enums.h.tmpl b/src/hb-gobject-enums.h.tmpl
index 6ecda06..e28510c 100644
--- a/src/hb-gobject-enums.h.tmpl
+++ b/src/hb-gobject-enums.h.tmpl
@@ -42,7 +42,7 @@
 /*** END file-header ***/
 
 /*** BEGIN value-header ***/
-GType @enum_name@_get_type (void) G_GNUC_CONST;
+HB_EXTERN GType @enum_name@_get_type (void) G_GNUC_CONST;
 #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
 
 /*** END value-header ***/
diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc
index 2451b66..6bd6336 100644
--- a/src/hb-gobject-structs.cc
+++ b/src/hb-gobject-structs.cc
@@ -54,6 +54,17 @@
 #define HB_DEFINE_OBJECT_TYPE(name) \
 	HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy);
 
+#define HB_DEFINE_VALUE_TYPE(name) \
+	static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
+	{ \
+	  hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
+	  if (unlikely (!c)) return NULL; \
+	  *c = *l; \
+	  return c; \
+	} \
+	static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \
+	HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy);
+
 HB_DEFINE_OBJECT_TYPE (buffer)
 HB_DEFINE_OBJECT_TYPE (blob)
 HB_DEFINE_OBJECT_TYPE (face)
@@ -62,59 +73,8 @@
 HB_DEFINE_OBJECT_TYPE (set)
 HB_DEFINE_OBJECT_TYPE (shape_plan)
 HB_DEFINE_OBJECT_TYPE (unicode_funcs)
-
-
-static hb_feature_t *feature_reference (hb_feature_t *g)
-{
-  hb_feature_t *c = (hb_feature_t *) calloc (1, sizeof (hb_feature_t));
-  if (unlikely (!c)) return NULL;
-  *c = *g;
-  return c;
-}
-static void feature_destroy (hb_feature_t *g) { free (g); }
-HB_DEFINE_BOXED_TYPE (feature, feature_reference, feature_destroy)
-
-static hb_glyph_info_t *glyph_info_reference (hb_glyph_info_t *g)
-{
-  hb_glyph_info_t *c = (hb_glyph_info_t *) calloc (1, sizeof (hb_glyph_info_t));
-  if (unlikely (!c)) return NULL;
-  *c = *g;
-  return c;
-}
-static void glyph_info_destroy (hb_glyph_info_t *g) { free (g); }
-HB_DEFINE_BOXED_TYPE (glyph_info, glyph_info_reference, glyph_info_destroy)
-
-static hb_glyph_position_t *glyph_position_reference (hb_glyph_position_t *g)
-{
-  hb_glyph_position_t *c = (hb_glyph_position_t *) calloc (1, sizeof (hb_glyph_position_t));
-  if (unlikely (!c)) return NULL;
-  *c = *g;
-  return c;
-}
-static void glyph_position_destroy (hb_glyph_position_t *g) { free (g); }
-HB_DEFINE_BOXED_TYPE (glyph_position, glyph_position_reference, glyph_position_destroy)
-
-static hb_segment_properties_t *segment_properties_reference (hb_segment_properties_t *g)
-{
-  hb_segment_properties_t *c = (hb_segment_properties_t *) calloc (1, sizeof (hb_segment_properties_t));
-  if (unlikely (!c)) return NULL;
-  *c = *g;
-  return c;
-}
-static void segment_properties_destroy (hb_segment_properties_t *g) { free (g); }
-HB_DEFINE_BOXED_TYPE (segment_properties, segment_properties_reference, segment_properties_destroy)
-
-static hb_user_data_key_t user_data_key_reference (hb_user_data_key_t l) { return l; }
-static void user_data_key_destroy (hb_user_data_key_t l) { }
-HB_DEFINE_BOXED_TYPE (user_data_key, user_data_key_reference, user_data_key_destroy)
-
-
-static hb_language_t *language_reference (hb_language_t *l)
-{
-  hb_language_t *c = (hb_language_t *) calloc (1, sizeof (hb_language_t));
-  if (unlikely (!c)) return NULL;
-  *c = *l;
-  return c;
-}
-static void language_destroy (hb_language_t *l) { free (l); }
-HB_DEFINE_BOXED_TYPE (language, language_reference, language_destroy)
+HB_DEFINE_VALUE_TYPE (feature)
+HB_DEFINE_VALUE_TYPE (glyph_info)
+HB_DEFINE_VALUE_TYPE (glyph_position)
+HB_DEFINE_VALUE_TYPE (segment_properties)
+HB_DEFINE_VALUE_TYPE (user_data_key)
diff --git a/src/hb-gobject-structs.h b/src/hb-gobject-structs.h
index 4a88d56..0ea3b12 100644
--- a/src/hb-gobject-structs.h
+++ b/src/hb-gobject-structs.h
@@ -40,55 +40,65 @@
 
 /* Object types */
 
-GType hb_gobject_blob_get_type (void);
+/**
+ * Since: 0.9.2
+ **/
+HB_EXTERN GType hb_gobject_blob_get_type (void);
 #define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
 
-GType hb_gobject_buffer_get_type (void);
+/**
+ * Since: 0.9.2
+ **/
+HB_EXTERN GType hb_gobject_buffer_get_type (void);
 #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
 
-GType hb_gobject_face_get_type (void);
+/**
+ * Since: 0.9.2
+ **/
+HB_EXTERN GType hb_gobject_face_get_type (void);
 #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
 
-GType hb_gobject_font_get_type (void);
+/**
+ * Since: 0.9.2
+ **/
+HB_EXTERN GType hb_gobject_font_get_type (void);
 #define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
 
-GType hb_gobject_font_funcs_get_type (void);
+/**
+ * Since: 0.9.2
+ **/
+HB_EXTERN GType hb_gobject_font_funcs_get_type (void);
 #define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
 
-GType hb_gobject_set_get_type (void);
+HB_EXTERN GType hb_gobject_set_get_type (void);
 #define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ())
 
-GType hb_gobject_shape_plan_get_type (void);
+HB_EXTERN GType hb_gobject_shape_plan_get_type (void);
 #define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
 
-GType hb_gobject_unicode_funcs_get_type (void);
+/**
+ * Since: 0.9.2
+ **/
+HB_EXTERN GType hb_gobject_unicode_funcs_get_type (void);
 #define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
 
 /* Value types */
 
-GType hb_gobject_feature_get_type (void);
+HB_EXTERN GType hb_gobject_feature_get_type (void);
 #define HB_GOBJECT_TYPE_FEATURE (hb_gobject_feature_get_type ())
 
-GType hb_gobject_glyph_info_get_type (void);
+HB_EXTERN GType hb_gobject_glyph_info_get_type (void);
 #define HB_GOBJECT_TYPE_GLYPH_INFO (hb_gobject_glyph_info_get_type ())
 
-GType hb_gobject_glyph_position_get_type (void);
+HB_EXTERN GType hb_gobject_glyph_position_get_type (void);
 #define HB_GOBJECT_TYPE_GLYPH_POSITION (hb_gobject_glyph_position_get_type ())
 
-GType hb_gobject_segment_properties_get_type (void);
+HB_EXTERN GType hb_gobject_segment_properties_get_type (void);
 #define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ())
 
-GType hb_gobject_user_data_key_get_type (void);
+HB_EXTERN GType hb_gobject_user_data_key_get_type (void);
 #define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ())
 
-/* Currently gobject-introspection doesn't understand that hb_language_t
- * can be passed by-value.  As such we box it up.  May remove in the
- * future.
- *
- *   https://bugzilla.gnome.org/show_bug.cgi?id=707656
- */
-GType hb_gobject_language_get_type (void);
-#define HB_GOBJECT_TYPE_LANGUAGE (hb_gobject_language_get_type ())
 
 HB_END_DECLS
 
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index 807c330..c32318d 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -138,6 +138,9 @@
   free (data);
 }
 
+/*
+ * Since: 0.9.10
+ */
 gr_face *
 hb_graphite2_face_get_gr_face (hb_face_t *face)
 {
@@ -172,6 +175,9 @@
   gr_font_destroy (data);
 }
 
+/*
+ * Since: 0.9.10
+ */
 gr_font *
 hb_graphite2_font_get_gr_font (hb_font_t *font)
 {
@@ -210,6 +216,7 @@
   unsigned int base_glyph;
   unsigned int num_glyphs;
   unsigned int cluster;
+  float advance;
 };
 
 hb_bool_t
@@ -228,12 +235,11 @@
   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);
 
-  while (num_features--)
+  for (unsigned int i = 0; i < num_features; i++)
   {
-    const gr_feature_ref *fref = gr_face_find_fref (grface, features->tag);
+    const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag);
     if (fref)
-      gr_fref_set_feature_value (fref, features->value, feats);
-    features++;
+      gr_fref_set_feature_value (fref, features[i].value, feats);
   }
 
   gr_segment *seg = NULL;
@@ -249,6 +255,8 @@
   for (unsigned int i = 0; i < buffer->len; ++i)
     chars[i] = buffer->info[i].codepoint;
 
+  /* TODO ensure_native_direction. */
+
   hb_tag_t script_tag[2];
   hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
 
@@ -267,9 +275,11 @@
   if (unlikely (!glyph_count)) {
     if (feats) gr_featureval_destroy (feats);
     gr_seg_destroy (seg);
-    return false;
+    buffer->len = 0;
+    return true;
   }
 
+  buffer->ensure (glyph_count);
   scratch = buffer->get_scratch_buffer (&scratch_size);
   while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
 	  DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
@@ -301,6 +311,12 @@
 
   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.;
+  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;
+  }
   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);
@@ -311,6 +327,7 @@
     {
       clusters[ci-1].num_chars += clusters[ci].num_chars;
       clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
+      clusters[ci-1].advance += clusters[ci].advance;
       ci--;
     }
 
@@ -322,16 +339,26 @@
       c->num_chars = before - c->base_char;
       c->base_glyph = ic;
       c->num_glyphs = 0;
-      ci++;
+      if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+      {
+        ci++;
+        clusters[ci].advance = curradv - gr_slot_origin_X(is);
+      } else {
+        clusters[ci].advance = gr_slot_origin_X(is) - curradv;
+        ci++;
+      }
+      curradv = gr_slot_origin_X(is);
     }
     clusters[ci].num_glyphs++;
 
     if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
 	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;
   ci++;
 
-  //buffer->clear_output ();
   for (unsigned int i = 0; i < ci; ++i)
   {
     for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
@@ -339,35 +366,57 @@
       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->var1.i32 = clusters[i].advance;     // all glyphs in the cluster get the same advance
     }
   }
   buffer->len = glyph_count;
-  //buffer->swap_buffers ();
 
-  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
-    curradvx = gr_seg_advance_X(seg);
-
-  hb_glyph_position_t *pPos;
-  for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
-       is; pPos++, is = gr_slot_next_in_segment (is))
+  float yscale = font->y_scale / font->x_scale;
+  /* Positioning. */
+  if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
   {
-    pPos->x_offset = gr_slot_origin_X (is) - curradvx;
-    pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
-    pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
-    pPos->y_advance = gr_slot_advance_Y (is, grface, grfont);
-    if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
-      curradvx -= pPos->x_advance;
-    pPos->x_offset = gr_slot_origin_X (is) - curradvx;
-    if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
-      curradvx += pPos->x_advance;
-    pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
-    curradvy += pPos->y_advance;
-  }
-  if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
-    pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
+    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->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
+      if (info->cluster != currclus) {
+        pPos->x_advance = info->var1.i32;
+        curradvx += pPos->x_advance;
+        currclus = info->cluster;
+      } else
+        pPos->x_advance = 0.;
 
-  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+      pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * 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);
+    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;
+        currclus = info->cluster;
+      } else
+      pPos->x_advance = 0.;
+
+      pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
+      curradvy -= pPos->y_advance;
+      pPos->x_offset = gr_slot_origin_X (is) - curradvx + pPos->x_advance;
+      pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
+    }
     hb_buffer_reverse_clusters (buffer);
+  }
 
   if (feats) gr_featureval_destroy (feats);
   gr_seg_destroy (seg);
diff --git a/src/hb-graphite2.h b/src/hb-graphite2.h
index 3eae54a..122c3e4 100644
--- a/src/hb-graphite2.h
+++ b/src/hb-graphite2.h
@@ -36,10 +36,10 @@
 #define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f')
 
 
-gr_face *
+HB_EXTERN gr_face *
 hb_graphite2_face_get_gr_face (hb_face_t *face);
 
-gr_font *
+HB_EXTERN gr_font *
 hb_graphite2_font_get_gr_font (hb_font_t *font);
 
 
diff --git a/src/hb-icu.h b/src/hb-icu.h
index f2f35f0..2db6a7b 100644
--- a/src/hb-icu.h
+++ b/src/hb-icu.h
@@ -36,14 +36,14 @@
 HB_BEGIN_DECLS
 
 
-hb_script_t
+HB_EXTERN hb_script_t
 hb_icu_script_to_script (UScriptCode script);
 
-UScriptCode
+HB_EXTERN UScriptCode
 hb_icu_script_from_script (hb_script_t script);
 
 
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void);
 
 
diff --git a/src/hb-mutex-private.hh b/src/hb-mutex-private.hh
index 6281201..ed27035 100644
--- a/src/hb-mutex-private.hh
+++ b/src/hb-mutex-private.hh
@@ -39,7 +39,13 @@
 
 /* We need external help for these */
 
-#if 0
+#if defined(HB_MUTEX_IMPL_INIT) \
+ && defined(hb_mutex_impl_init) \
+ && defined(hb_mutex_impl_lock) \
+ && defined(hb_mutex_impl_unlock) \
+ && defined(hb_mutex_impl_finish)
+
+/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
 
 
 #elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
@@ -47,7 +53,11 @@
 #include <windows.h>
 typedef CRITICAL_SECTION hb_mutex_impl_t;
 #define HB_MUTEX_IMPL_INIT	{0}
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#define hb_mutex_impl_init(M)	InitializeCriticalSectionEx (M, 0, 0)
+#else
 #define hb_mutex_impl_init(M)	InitializeCriticalSection (M)
+#endif
 #define hb_mutex_impl_lock(M)	EnterCriticalSection (M)
 #define hb_mutex_impl_unlock(M)	LeaveCriticalSection (M)
 #define hb_mutex_impl_finish(M)	DeleteCriticalSection (M)
@@ -109,10 +119,12 @@
 #define hb_mutex_impl_unlock(M)	HB_STMT_START {} HB_STMT_END
 #define hb_mutex_impl_finish(M)	HB_STMT_START {} HB_STMT_END
 
+
 #endif
 
 
 #define HB_MUTEX_INIT		{HB_MUTEX_IMPL_INIT}
+
 struct hb_mutex_t
 {
   /* TODO Add tracing. */
diff --git a/src/hb-object-private.hh b/src/hb-object-private.hh
index 7bd0f16..6b73ff9 100644
--- a/src/hb-object-private.hh
+++ b/src/hb-object-private.hh
@@ -47,19 +47,22 @@
 
 /* reference_count */
 
-#define HB_REFERENCE_COUNT_INVALID_VALUE ((hb_atomic_int_t) -1)
-#define HB_REFERENCE_COUNT_INVALID {HB_REFERENCE_COUNT_INVALID_VALUE}
+#define HB_REFERENCE_COUNT_INERT_VALUE -1
+#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
+#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)}
+
 struct hb_reference_count_t
 {
   hb_atomic_int_t ref_count;
 
-  inline void init (int v) { ref_count = v; }
-  inline int inc (void) { return hb_atomic_int_add (const_cast<hb_atomic_int_t &> (ref_count),  1); }
-  inline int dec (void) { return hb_atomic_int_add (const_cast<hb_atomic_int_t &> (ref_count), -1); }
-  inline void finish (void) { ref_count = HB_REFERENCE_COUNT_INVALID_VALUE; }
+  inline void init (int v) { ref_count.set_unsafe (v); }
+  inline int get_unsafe (void) const { return ref_count.get_unsafe (); }
+  inline int inc (void) { return ref_count.inc (); }
+  inline int dec (void) { return ref_count.dec (); }
+  inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); }
 
-  inline bool is_invalid (void) const { return ref_count == HB_REFERENCE_COUNT_INVALID_VALUE; }
-
+  inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; }
+  inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; }
 };
 
 
@@ -102,7 +105,7 @@
   hb_reference_count_t ref_count;
   hb_user_data_array_t user_data;
 
-#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_USER_DATA_ARRAY_INIT}
+#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_USER_DATA_ARRAY_INIT}
 
   private:
   ASSERT_POD ();
@@ -117,7 +120,7 @@
   DEBUG_MSG (OBJECT, (void *) obj,
 	     "%s refcount=%d",
 	     function,
-	     obj ? obj->header.ref_count.ref_count : 0);
+	     obj ? obj->header.ref_count.get_unsafe () : 0);
 }
 
 template <typename Type>
@@ -141,7 +144,12 @@
 template <typename Type>
 static inline bool hb_object_is_inert (const Type *obj)
 {
-  return unlikely (obj->header.ref_count.is_invalid ());
+  return unlikely (obj->header.ref_count.is_inert ());
+}
+template <typename Type>
+static inline bool hb_object_is_valid (const Type *obj)
+{
+  return likely (obj->header.ref_count.is_valid ());
 }
 template <typename Type>
 static inline Type *hb_object_reference (Type *obj)
@@ -149,6 +157,7 @@
   hb_object_trace (obj, HB_FUNC);
   if (unlikely (!obj || hb_object_is_inert (obj)))
     return obj;
+  assert (hb_object_is_valid (obj));
   obj->header.ref_count.inc ();
   return obj;
 }
@@ -158,6 +167,7 @@
   hb_object_trace (obj, HB_FUNC);
   if (unlikely (!obj || hb_object_is_inert (obj)))
     return false;
+  assert (hb_object_is_valid (obj));
   if (obj->header.ref_count.dec () != 1)
     return false;
 
@@ -174,6 +184,7 @@
 {
   if (unlikely (!obj || hb_object_is_inert (obj)))
     return false;
+  assert (hb_object_is_valid (obj));
   return obj->header.user_data.set (key, data, destroy, replace);
 }
 
@@ -183,6 +194,7 @@
 {
   if (unlikely (!obj || hb_object_is_inert (obj)))
     return NULL;
+  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 7500c32..5357ddc 100644
--- a/src/hb-open-file-private.hh
+++ b/src/hb-open-file-private.hh
@@ -53,9 +53,10 @@
 
 typedef struct TableRecord
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   Tag		tag;		/* 4-byte identifier. */
@@ -102,9 +103,10 @@
   }
 
   public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
+    return_trace (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
   }
 
   protected:
@@ -130,14 +132,15 @@
   inline unsigned int get_face_count (void) const { return table.len; }
   inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (table.sanitize (c, this));
+    return_trace (table.sanitize (c, this));
   }
 
   protected:
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
-  FixedVersion	version;	/* Version of the TTC Header (1.0),
+  FixedVersion<>version;	/* Version of the TTC Header (1.0),
 				 * 0x00010000u */
   ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
 		table;		/* Array of offsets to the OffsetTable for each font
@@ -169,13 +172,14 @@
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false);
+    if (unlikely (!u.header.version.sanitize (c))) return_trace (false);
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
-    case 1: return TRACE_RETURN (u.version1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (u.version1.sanitize (c));
+    default:return_trace (true);
     }
   }
 
@@ -183,7 +187,7 @@
   union {
   struct {
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
-  FixedVersion	version;	/* Version of the TTC Header (1.0 or 2.0),
+  FixedVersion<>version;	/* Version of the TTC Header (1.0 or 2.0),
 				 * 0x00010000u or 0x00020000u */
   }			header;
   TTCHeaderVersion1	version1;
@@ -233,16 +237,17 @@
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false);
+    if (unlikely (!u.tag.sanitize (c))) return_trace (false);
     switch (u.tag) {
     case CFFTag:	/* All the non-collection tags */
     case TrueTag:
     case Typ1Tag:
-    case TrueTypeTag:	return TRACE_RETURN (u.fontFace.sanitize (c));
-    case TTCTag:	return TRACE_RETURN (u.ttcHeader.sanitize (c));
-    default:		return TRACE_RETURN (true);
+    case TrueTypeTag:	return_trace (u.fontFace.sanitize (c));
+    case TTCTag:	return_trace (u.ttcHeader.sanitize (c));
+    default:		return_trace (true);
     }
   }
 
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 477d9e2..6a52000 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -103,9 +103,6 @@
   static const unsigned int static_size = (size); \
   static const unsigned int min_size = (size)
 
-/* Size signifying variable-sized array */
-#define VAR 1
-
 #define DEFINE_SIZE_UNION(size, _member) \
   DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \
   static const unsigned int min_size = (size)
@@ -154,6 +151,20 @@
 #define Null(Type) Null<Type>()
 
 
+/*
+ * Dispatch
+ */
+
+template <typename Context, typename Return, unsigned int MaxDebugDepth>
+struct hb_dispatch_context_t
+{
+  static const unsigned int max_debug_depth = MaxDebugDepth;
+  typedef Return return_t;
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format) { return true; }
+  static return_t no_dispatch_return_value (void) { return Context::default_return_value (); }
+};
+
 
 /*
  * Sanitize
@@ -171,18 +182,27 @@
 
 /* This limits sanitizing time on really broken fonts. */
 #ifndef HB_SANITIZE_MAX_EDITS
-#define HB_SANITIZE_MAX_EDITS 100
+#define HB_SANITIZE_MAX_EDITS 32
 #endif
 
-struct hb_sanitize_context_t
+struct hb_sanitize_context_t :
+       hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
 {
+  inline hb_sanitize_context_t (void) :
+	debug_depth (0),
+	start (NULL), end (NULL),
+	writable (false), edit_count (0),
+	blob (NULL) {}
+
   inline const char *get_name (void) { return "SANITIZE"; }
-  static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE;
-  typedef bool return_t;
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format)
+  { return format->sanitize (this); }
   template <typename T>
   inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
   static return_t default_return_value (void) { return true; }
-  bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; }
+  static return_t no_dispatch_return_value (void) { return false; }
+  bool stop_sublookup_iteration (const return_t r) const { return !r; }
 
   inline void init (hb_blob_t *b)
   {
@@ -270,9 +290,9 @@
   }
 
   template <typename Type, typename ValueType>
-  inline bool try_set (Type *obj, const ValueType &v) {
+  inline bool try_set (const Type *obj, const ValueType &v) {
     if (this->may_edit (obj, obj->static_size)) {
-      obj->set (v);
+      const_cast<Type *> (obj)->set (v);
       return true;
     }
     return false;
@@ -292,7 +312,7 @@
 struct Sanitizer
 {
   static hb_blob_t *sanitize (hb_blob_t *blob) {
-    hb_sanitize_context_t c[1] = {{0, NULL, NULL, false, 0, NULL}};
+    hb_sanitize_context_t c[1];
     bool sane;
 
     /* TODO is_sane() stuff */
@@ -376,9 +396,9 @@
 
 struct hb_serialize_context_t
 {
-  inline hb_serialize_context_t (void *start, unsigned int size)
+  inline hb_serialize_context_t (void *start_, unsigned int size)
   {
-    this->start = (char *) start;
+    this->start = (char *) start_;
     this->end = this->start + size;
 
     this->ran_out_of_room = false;
@@ -472,10 +492,10 @@
     return reinterpret_cast<Type *> (&obj);
   }
 
-  inline void truncate (void *head)
+  inline void truncate (void *new_head)
   {
-    assert (this->start < head && head <= this->head);
-    this->head = (char *) head;
+    assert (this->start < new_head && new_head <= this->head);
+    this->head = (char *) new_head;
   }
 
   unsigned int debug_depth;
@@ -533,6 +553,20 @@
 template <typename Type, int Bytes> struct BEInt;
 
 template <typename Type>
+struct BEInt<Type, 1>
+{
+  public:
+  inline void set (Type V)
+  {
+    v = V;
+  }
+  inline operator Type (void) const
+  {
+    return v;
+  }
+  private: uint8_t v;
+};
+template <typename Type>
 struct BEInt<Type, 2>
 {
   public:
@@ -546,12 +580,6 @@
     return (v[0] <<  8)
          + (v[1]      );
   }
-  inline bool operator == (const BEInt<Type, 2>& o) const
-  {
-    return v[0] == o.v[0]
-        && v[1] == o.v[1];
-  }
-  inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
   private: uint8_t v[2];
 };
 template <typename Type>
@@ -570,13 +598,6 @@
          + (v[1] <<  8)
          + (v[2]      );
   }
-  inline bool operator == (const BEInt<Type, 3>& o) const
-  {
-    return v[0] == o.v[0]
-        && v[1] == o.v[1]
-        && v[2] == o.v[2];
-  }
-  inline bool operator != (const BEInt<Type, 3>& o) const { return !(*this == o); }
   private: uint8_t v[3];
 };
 template <typename Type>
@@ -597,14 +618,6 @@
          + (v[2] <<  8)
          + (v[3]      );
   }
-  inline bool operator == (const BEInt<Type, 4>& o) const
-  {
-    return v[0] == o.v[0]
-        && v[1] == o.v[1]
-        && v[2] == o.v[2]
-        && v[3] == o.v[3];
-  }
-  inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
   private: uint8_t v[4];
 };
 
@@ -614,14 +627,21 @@
 {
   inline void set (Type i) { v.set (i); }
   inline operator Type(void) const { return v; }
-  inline bool operator == (const IntType<Type,Size> &o) const { return v == o.v; }
-  inline bool operator != (const IntType<Type,Size> &o) const { return v != o.v; }
+  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 (IntType<Type,Size> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
-  inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline int cmp (Type a) const
+  {
+    Type b = v;
+    if (sizeof (Type) < sizeof (int))
+      return (int) a - (int) b;
+    else
+      return a < b ? -1 : a == b ? 0 : +1;
+  }
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (likely (c->check_struct (this)));
+    return_trace (likely (c->check_struct (this)));
   }
   protected:
   BEInt<Type, Size> v;
@@ -629,7 +649,7 @@
   DEFINE_SIZE_STATIC (Size);
 };
 
-typedef		uint8_t	     BYTE;	/* 8-bit unsigned integer. */
+typedef	IntType<uint8_t	, 1> BYTE;	/* 8-bit unsigned 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. */
@@ -646,9 +666,10 @@
  * 1904. The value is represented as a signed 64-bit integer. */
 struct LONGDATETIME
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (likely (c->check_struct (this)));
+    return_trace (likely (c->check_struct (this)));
   }
   protected:
   LONG major;
@@ -670,7 +691,10 @@
 DEFINE_NULL_DATA (Tag, "    ");
 
 /* Glyph index number, same as uint16 (length = 16 bits) */
-typedef USHORT GlyphID;
+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; }
+};
 
 /* Script/language-system/feature index */
 struct Index : USHORT {
@@ -715,19 +739,21 @@
  * Version Numbers
  */
 
+template <typename FixedType=USHORT>
 struct FixedVersion
 {
-  inline uint32_t to_int (void) const { return (major << 16) + minor; }
+  inline uint32_t to_int (void) const { return (major << sizeof(FixedType)) + minor; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
-  USHORT major;
-  USHORT minor;
+  FixedType major;
+  FixedType minor;
   public:
-  DEFINE_SIZE_STATIC (4);
+  DEFINE_SIZE_STATIC (2 * sizeof(FixedType));
 };
 
 
@@ -747,33 +773,35 @@
     return StructAtOffset<Type> (base, offset);
   }
 
-  inline Type& serialize (hb_serialize_context_t *c, void *base)
+  inline Type& serialize (hb_serialize_context_t *c, const void *base)
   {
     Type *t = c->start_embed<Type> ();
     this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
     return *t;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
+    if (unlikely (!c->check_struct (this))) return_trace (false);
     unsigned int offset = *this;
-    if (unlikely (!offset)) return TRACE_RETURN (true);
-    Type &obj = StructAtOffset<Type> (base, offset);
-    return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c));
+    if (unlikely (!offset)) return_trace (true);
+    const Type &obj = StructAtOffset<Type> (base, offset);
+    return_trace (likely (obj.sanitize (c)) || neuter (c));
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
+    if (unlikely (!c->check_struct (this))) return_trace (false);
     unsigned int offset = *this;
-    if (unlikely (!offset)) return TRACE_RETURN (true);
-    Type &obj = StructAtOffset<Type> (base, offset);
-    return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
+    if (unlikely (!offset)) return_trace (true);
+    const Type &obj = StructAtOffset<Type> (base, offset);
+    return_trace (likely (obj.sanitize (c, user_data)) || neuter (c));
   }
 
   /* Set the offset to Null */
-  inline bool neuter (hb_sanitize_context_t *c) {
+  inline bool neuter (hb_sanitize_context_t *c) const {
     return c->try_set (this, 0);
   }
   DEFINE_SIZE_STATIC (sizeof(OffsetType));
@@ -820,10 +848,10 @@
 			 unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
     len.set (items_len); /* TODO(serialize) Overflow? */
-    if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+    if (unlikely (!c->extend (*this))) return_trace (false);
+    return_trace (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -831,16 +859,17 @@
 			 unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false);
+    if (unlikely (!serialize (c, items_len))) return_trace (false);
     for (unsigned int i = 0; i < items_len; i++)
       array[i] = items[i];
     items.advance (items_len);
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
 
     /* Note: for structs that do not reference other structs,
      * we do not need to call their sanitize() as we already did
@@ -851,26 +880,28 @@
      */
     (void) (false && array[0].sanitize (c));
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!array[i].sanitize (c, base)))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+        return_trace (false);
+    return_trace (true);
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!array[i].sanitize (c, base, user_data)))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+        return_trace (false);
+    return_trace (true);
   }
 
   template <typename SearchType>
@@ -884,9 +915,10 @@
   }
 
   private:
-  inline bool sanitize_shallow (hb_sanitize_context_t *c) {
+  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
+    return_trace (c->check_struct (this) && c->check_array (array, Type::static_size, len));
   }
 
   public:
@@ -910,14 +942,16 @@
     return this+this->array[i];
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
+    return_trace (OffsetArrayOf<Type>::sanitize (c, this));
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
+  inline bool sanitize (hb_sanitize_context_t *c, T user_data) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
+    return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
   }
 };
 
@@ -939,24 +973,26 @@
 			 unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
     len.set (items_len); /* TODO(serialize) Overflow? */
-    if (unlikely (!items_len)) return TRACE_RETURN (true);
-    if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
+    if (unlikely (!items_len)) return_trace (true);
+    if (unlikely (!c->extend (*this))) return_trace (false);
     for (unsigned int i = 0; i < items_len - 1; i++)
       array[i] = items[i];
     items.advance (items_len - 1);
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize_shallow (hb_sanitize_context_t *c) {
+  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) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
+    if (unlikely (!sanitize_shallow (c))) return_trace (false);
 
     /* Note: for structs that do not reference other structs,
      * we do not need to call their sanitize() as we already did
@@ -967,7 +1003,7 @@
      */
     (void) (false && array[0].sanitize (c));
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   LenType len;
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index d531411..c9161f0 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -51,9 +51,10 @@
     return true;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -125,11 +126,11 @@
     return true;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c)
+  inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this)))
-      return TRACE_RETURN (false);
+      return_trace (false);
 
     if (unlikely (!c->check_range (this, length)))
     {
@@ -140,10 +141,10 @@
 					    (uintptr_t) (c->end -
 							 (char *) this));
       if (!c->try_set (&length, new_length))
-	return TRACE_RETURN (false);
+	return_trace (false);
     }
 
-    return TRACE_RETURN (16 + 4 * (unsigned int) segCountX2 <= length);
+    return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
   }
 
   protected:
@@ -183,9 +184,10 @@
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   private:
@@ -210,9 +212,10 @@
     return true;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c));
+    return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
   }
 
   protected:
@@ -242,9 +245,10 @@
     return true;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c));
+    return_trace (c->check_struct (this) && groups.sanitize (c));
   }
 
   protected:
@@ -288,9 +292,10 @@
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   UINT24	startUnicodeValue;	/* First value in this range. */
@@ -309,9 +314,10 @@
     return unicodeValue.cmp (codepoint);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   UINT24	unicodeValue;	/* Base Unicode value of the UVS */
@@ -348,11 +354,12 @@
     return varSelector.cmp (variation_selector);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) &&
-			 defaultUVS.sanitize (c, base) &&
-			 nonDefaultUVS.sanitize (c, base));
+    return_trace (c->check_struct (this) &&
+		  defaultUVS.sanitize (c, base) &&
+		  nonDefaultUVS.sanitize (c, base));
   }
 
   UINT24	varSelector;	/* Variation selector. */
@@ -373,10 +380,11 @@
     return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) &&
-			 record.sanitize (c, this));
+    return_trace (c->check_struct (this) &&
+		  record.sanitize (c, this));
   }
 
   protected:
@@ -418,18 +426,19 @@
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    if (!u.format.sanitize (c)) return_trace (false);
     switch (u.format) {
-    case  0: return TRACE_RETURN (u.format0 .sanitize (c));
-    case  4: return TRACE_RETURN (u.format4 .sanitize (c));
-    case  6: return TRACE_RETURN (u.format6 .sanitize (c));
-    case 10: return TRACE_RETURN (u.format10.sanitize (c));
-    case 12: return TRACE_RETURN (u.format12.sanitize (c));
-    case 13: return TRACE_RETURN (u.format13.sanitize (c));
-    case 14: return TRACE_RETURN (u.format14.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case  0: return_trace (u.format0 .sanitize (c));
+    case  4: return_trace (u.format4 .sanitize (c));
+    case  6: return_trace (u.format6 .sanitize (c));
+    case 10: return_trace (u.format10.sanitize (c));
+    case 12: return_trace (u.format12.sanitize (c));
+    case 13: return_trace (u.format13.sanitize (c));
+    case 14: return_trace (u.format14.sanitize (c));
+    default:return_trace (true);
     }
   }
 
@@ -461,10 +470,11 @@
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) &&
-			 subtable.sanitize (c, base));
+    return_trace (c->check_struct (this) &&
+		  subtable.sanitize (c, base));
   }
 
   USHORT	platformID;	/* Platform ID. */
@@ -496,11 +506,12 @@
     return &(this+encodingRecord[result].subtable);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) &&
-			 likely (version == 0) &&
-			 encodingRecord.sanitize (c, this));
+    return_trace (c->check_struct (this) &&
+		  likely (version == 0) &&
+		  encodingRecord.sanitize (c, this));
   }
 
   USHORT		version;	/* Table version number (0). */
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 2af2f54..e7b57b8 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -31,8 +31,11 @@
 #include "hb-font-private.hh"
 
 #include "hb-ot-cmap-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"
 
 
 struct hb_ot_face_metrics_accelerator_t
@@ -40,24 +43,58 @@
   unsigned int num_metrics;
   unsigned int num_advances;
   unsigned int default_advance;
+  unsigned short ascender;
+  unsigned short descender;
+  unsigned short line_gap;
+
   const OT::_mtx *table;
   hb_blob_t *blob;
 
   inline void init (hb_face_t *face,
-		    hb_tag_t _hea_tag, hb_tag_t _mtx_tag,
-		    unsigned int default_advance)
+		    hb_tag_t _hea_tag,
+		    hb_tag_t _mtx_tag,
+		    hb_tag_t os2_tag)
   {
-    this->default_advance = default_advance;
-    this->num_metrics = face->get_num_glyphs ();
+    this->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;
+    }
     hb_blob_destroy (_hea_blob);
 
     this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
-    if (unlikely (!this->num_advances ||
-		  2 * (this->num_advances + this->num_metrics) < hb_blob_get_length (this->blob)))
+
+    /* 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);
@@ -76,8 +113,8 @@
     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 one EM.  Otherwise, it means that the glyph
-       * index is out of bound: return zero. */
+       * 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
@@ -91,6 +128,79 @@
   }
 };
 
+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_cmap_accelerator_t
 {
   const OT::CmapSubtable *table;
@@ -114,6 +224,7 @@
     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);
     /* Meh. */
     if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
 
@@ -157,23 +268,22 @@
   hb_ot_face_cmap_accelerator_t cmap;
   hb_ot_face_metrics_accelerator_t h_metrics;
   hb_ot_face_metrics_accelerator_t v_metrics;
+  hb_ot_face_glyf_accelerator_t glyf;
 };
 
 
 static hb_ot_font_t *
-_hb_ot_font_create (hb_font_t *font)
+_hb_ot_font_create (hb_face_t *face)
 {
   hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
-  hb_face_t *face = font->face;
 
   if (unlikely (!ot_font))
     return NULL;
 
-  unsigned int upem = face->get_upem ();
-
   ot_font->cmap.init (face);
-  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1);
-  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */
+  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
+  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /* TODO Can we do this lazily? */
+  ot_font->glyf.init (face);
 
   return ot_font;
 }
@@ -184,6 +294,7 @@
   ot_font->cmap.fini ();
   ot_font->h_metrics.fini ();
   ot_font->v_metrics.fini ();
+  ot_font->glyf.fini ();
 
   free (ot_font);
 }
@@ -219,53 +330,7 @@
 			   void *user_data HB_UNUSED)
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
-  return font->em_scale_y (-ot_font->v_metrics.get_advance (glyph));
-}
-
-static hb_bool_t
-hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
-			  void *font_data HB_UNUSED,
-			  hb_codepoint_t glyph HB_UNUSED,
-			  hb_position_t *x HB_UNUSED,
-			  hb_position_t *y HB_UNUSED,
-			  void *user_data HB_UNUSED)
-{
-  /* We always work in the horizontal coordinates. */
-  return true;
-}
-
-static hb_bool_t
-hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
-			  void *font_data,
-			  hb_codepoint_t glyph,
-			  hb_position_t *x,
-			  hb_position_t *y,
-			  void *user_data HB_UNUSED)
-{
-  /* TODO */
-  return false;
-}
-
-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)
-{
-  /* TODO */
-  return 0;
-}
-
-static hb_position_t
-hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
-			   void *font_data HB_UNUSED,
-			   hb_codepoint_t top_glyph HB_UNUSED,
-			   hb_codepoint_t bottom_glyph HB_UNUSED,
-			   void *user_data HB_UNUSED)
-{
-  /* OpenType doesn't have vertical-kerning other than GPOS. */
-  return 0;
+  return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
 }
 
 static hb_bool_t
@@ -275,69 +340,100 @@
 			 hb_glyph_extents_t *extents,
 			 void *user_data HB_UNUSED)
 {
-  /* TODO */
-  return false;
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  bool ret = ot_font->glyf.get_extents (glyph, extents);
+  extents->x_bearing = font->em_scale_x (extents->x_bearing);
+  extents->y_bearing = font->em_scale_y (extents->y_bearing);
+  extents->width     = font->em_scale_x (extents->width);
+  extents->height    = font->em_scale_y (extents->height);
+  return ret;
 }
 
 static hb_bool_t
-hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
-			       void *font_data,
-			       hb_codepoint_t glyph,
-			       unsigned int point_index,
-			       hb_position_t *x,
-			       hb_position_t *y,
-			       void *user_data HB_UNUSED)
+hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
+			  void *font_data,
+			  hb_font_extents_t *metrics,
+			  void *user_data HB_UNUSED)
 {
-  /* TODO */
-  return false;
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
+  metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
+  metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
+  return true;
 }
 
 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)
+hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
+			  void *font_data,
+			  hb_font_extents_t *metrics,
+			  void *user_data HB_UNUSED)
 {
-  /* TODO */
-  return false;
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
+  metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
+  metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
+  return true;
 }
 
-static hb_bool_t
-hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
-			   void *font_data,
-			   const char *name, int len, /* -1 means nul-terminated */
-			   hb_codepoint_t *glyph,
-			   void *user_data HB_UNUSED)
-{
-  /* TODO */
-  return false;
-}
+static hb_font_funcs_t *static_ot_funcs = NULL;
 
+#ifdef HB_USE_ATEXIT
+static
+void free_static_ot_funcs (void)
+{
+  hb_font_funcs_destroy (static_ot_funcs);
+}
+#endif
 
 static hb_font_funcs_t *
 _hb_ot_get_font_funcs (void)
 {
-  static const hb_font_funcs_t ot_ffuncs = {
-    HB_OBJECT_HEADER_STATIC,
+retry:
+  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
 
-    true, /* immutable */
+  if (unlikely (!funcs))
+  {
+    funcs = hb_font_funcs_create ();
 
-    {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name,
-      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
+    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_glyph_func (funcs, hb_ot_get_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_make_immutable (funcs);
+
+    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
+      hb_font_funcs_destroy (funcs);
+      goto retry;
     }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
+#endif
   };
 
-  return const_cast<hb_font_funcs_t *> (&ot_ffuncs);
+  return funcs;
 }
 
 
+/**
+ * hb_ot_font_set_funcs:
+ *
+ * Since: 0.9.28
+ **/
 void
 hb_ot_font_set_funcs (hb_font_t *font)
 {
-  hb_ot_font_t *ot_font = _hb_ot_font_create (font);
+  hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
   if (unlikely (!ot_font))
     return;
 
diff --git a/src/hb-ot-font.h b/src/hb-ot-font.h
index 7a8c04a..80eaa54 100644
--- a/src/hb-ot-font.h
+++ b/src/hb-ot-font.h
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
  */
 
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
 #ifndef HB_OT_FONT_H
 #define HB_OT_FONT_H
 
@@ -32,7 +36,7 @@
 HB_BEGIN_DECLS
 
 
-void
+HB_EXTERN void
 hb_ot_font_set_funcs (hb_font_t *font);
 
 
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
new file mode 100644
index 0000000..9e5af6d
--- /dev/null
+++ b/src/hb-ot-glyf-table.hh
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2015  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_GLYF_TABLE_HH
+#define HB_OT_GLYF_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * loca -- Index to Location
+ */
+
+#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
+
+
+struct loca
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_loca;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    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);
+};
+
+
+/*
+ * glyf -- TrueType Glyph Data
+ */
+
+#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
+
+
+struct glyf
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_glyf;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    /* We don't check for anything specific here.  The users of the
+     * struct do all the hard work... */
+    return_trace (true);
+  }
+
+  public:
+  BYTE		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. */
+  SHORT		xMin;			/* Minimum x for coordinate data. */
+  SHORT		yMin;			/* Minimum y for coordinate data. */
+  SHORT		xMax;			/* Maximum x for coordinate data. */
+  SHORT		yMax;			/* Maximum y for coordinate data. */
+
+  DEFINE_SIZE_STATIC (10);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_GLYF_TABLE_HH */
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index ec4e8c9..9c3e51e 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -45,21 +45,25 @@
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_head;
 
-  inline unsigned int get_upem (void) const {
+  inline unsigned int get_upem (void) const
+  {
     unsigned int upem = unitsPerEm;
     /* If no valid head table found, assume 1000, which matches typical Type1 usage. */
     return 16 <= upem && upem <= 16384 ? upem : 1000;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
+    return_trace (c->check_struct (this) &&
+		  version.major == 1 &&
+		  magicNumber == 0x5F0F3CF5u);
   }
 
   protected:
-  FixedVersion	version;		/* Version of the head table--currently
+  FixedVersion<>version;		/* Version of the head table--currently
 					 * 0x00010000u for version 1.0. */
-  FixedVersion	fontRevision;		/* Set by font manufacturer. */
+  FixedVersion<>fontRevision;		/* Set by font manufacturer. */
   ULONG		checkSumAdjustment;	/* To compute: set it to 0, sum the
 					 * entire font as ULONG, then store
 					 * 0xB1B0AFBAu - sum. */
@@ -136,9 +140,10 @@
 					 * 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. */
-  public:
+
   DEFINE_SIZE_STATIC (54);
 };
 
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index edc0e29..c8e9536 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -49,13 +49,14 @@
   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) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
+    return_trace (c->check_struct (this) && likely (version.major == 1));
   }
 
   public:
-  FixedVersion	version;		/* 0x00010000u for version 1.0. */
+  FixedVersion<>version;		/* 0x00010000u for version 1.0. */
   FWORD		ascender;		/* Typographic ascent. */
   FWORD		descender;		/* Typographic descent. */
   FWORD		lineGap;		/* Typographic line gap. */
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 317854c..49056e6 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -57,11 +57,12 @@
   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) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
      * struct do all the hard work... */
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   public:
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index abd063c..6c7bac0 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -34,12 +34,24 @@
 #include "hb-set-private.hh"
 
 
+#ifndef HB_MAX_NESTING_LEVEL
+#define HB_MAX_NESTING_LEVEL	6
+#endif
+#ifndef HB_MAX_CONTEXT_LENGTH
+#define HB_MAX_CONTEXT_LENGTH	64
+#endif
+
+
 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)
-#define MAX_NESTING_LEVEL	8
-#define MAX_CONTEXT_LENGTH	64
 
 
 
@@ -63,12 +75,13 @@
 
   struct sanitize_closure_t {
     hb_tag_t tag;
-    void *list_base;
+    const void *list_base;
   };
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
     TRACE_SANITIZE (this);
     const sanitize_closure_t closure = {tag, base};
-    return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
+    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
   }
 
   Tag		tag;		/* 4-byte Tag identifier */
@@ -121,9 +134,10 @@
   inline const Type& operator [] (unsigned int i) const
   { return this+RecordArrayOf<Type>::operator [](i).offset; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
+    return_trace (RecordArrayOf<Type>::sanitize (c, this));
   }
 };
 
@@ -134,9 +148,10 @@
     return g < start ? -1 : g <= end ? 0 : +1 ;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   inline bool intersects (const hb_set_t *glyphs) const {
@@ -199,9 +214,10 @@
   }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<LangSys>::sanitize_closure_t * = NULL) {
+			const Record<LangSys>::sanitize_closure_t * = NULL) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
+    return_trace (c->check_struct (this) && featureIndex.sanitize (c));
   }
 
   Offset<>	lookupOrderZ;	/* = Null (reserved for an offset to a
@@ -238,9 +254,10 @@
   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 Record<Script>::sanitize_closure_t * = NULL) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
+    return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
   }
 
   protected:
@@ -260,9 +277,10 @@
 /* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
 struct FeatureParamsSize
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
+    if (unlikely (!c->check_struct (this))) return_trace (false);
 
     /* This subtable has some "history", if you will.  Some earlier versions of
      * Adobe tools calculated the offset of the FeatureParams sutable from the
@@ -314,19 +332,19 @@
      */
 
     if (!designSize)
-      return TRACE_RETURN (false);
+      return_trace (false);
     else if (subfamilyID == 0 &&
 	     subfamilyNameID == 0 &&
 	     rangeStart == 0 &&
 	     rangeEnd == 0)
-      return TRACE_RETURN (true);
+      return_trace (true);
     else if (designSize < rangeStart ||
 	     designSize > rangeEnd ||
 	     subfamilyNameID < 256 ||
 	     subfamilyNameID > 32767)
-      return TRACE_RETURN (false);
+      return_trace (false);
     else
-      return TRACE_RETURN (true);
+      return_trace (true);
   }
 
   USHORT	designSize;	/* Represents the design size in 720/inch
@@ -371,11 +389,12 @@
 /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
 struct FeatureParamsStylisticSet
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
     /* Right now minorVersion is at zero.  Which means, any table supports
      * the uiNameID field. */
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   USHORT	version;	/* (set to 0): This corresponds to a “minor”
@@ -404,10 +423,11 @@
 /* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
 struct FeatureParamsCharacterVariants
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) &&
-			 characters.sanitize (c));
+    return_trace (c->check_struct (this) &&
+		  characters.sanitize (c));
   }
 
   USHORT	format;			/* Format number is set to 0. */
@@ -444,15 +464,16 @@
 
 struct FeatureParams
 {
-  inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) {
+  inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
+  {
     TRACE_SANITIZE (this);
     if (tag == HB_TAG ('s','i','z','e'))
-      return TRACE_RETURN (u.size.sanitize (c));
+      return_trace (u.size.sanitize (c));
     if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
-      return TRACE_RETURN (u.stylisticSet.sanitize (c));
+      return_trace (u.stylisticSet.sanitize (c));
     if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
-      return TRACE_RETURN (u.characterVariants.sanitize (c));
-    return TRACE_RETURN (true);
+      return_trace (u.characterVariants.sanitize (c));
+    return_trace (true);
   }
 
   inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
@@ -486,10 +507,11 @@
   { return this+featureParams; }
 
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<Feature>::sanitize_closure_t *closure) {
+			const Record<Feature>::sanitize_closure_t *closure) const
+  {
     TRACE_SANITIZE (this);
     if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
-      return TRACE_RETURN (false);
+      return_trace (false);
 
     /* Some earlier versions of Adobe tools calculated the offset of the
      * FeatureParams subtable from the beginning of the FeatureList table!
@@ -504,10 +526,10 @@
 
     OffsetTo<FeatureParams> orig_offset = featureParams;
     if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
-      return TRACE_RETURN (false);
+      return_trace (false);
 
     if (likely (orig_offset.is_null ()))
-      return TRACE_RETURN (true);
+      return_trace (true);
 
     if (featureParams == 0 && closure &&
 	closure->tag == HB_TAG ('s','i','z','e') &&
@@ -522,10 +544,13 @@
       if (new_offset == new_offset_int &&
 	  c->try_set (&featureParams, new_offset) &&
 	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
-	return TRACE_RETURN (false);
+	return_trace (false);
+
+      if (c->edit_count > 1)
+        c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
     }
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   OffsetTo<FeatureParams>
@@ -557,10 +582,26 @@
   DEFINE_SIZE_STATIC (2);
 };
 
+} /* namespace OT */
+/* This has to be outside the namespace. */
+HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
+namespace OT {
+
 struct Lookup
 {
   inline unsigned int get_subtable_count (void) const { return subTable.len; }
 
+  template <typename SubTableType>
+  inline const SubTableType& get_subtable (unsigned int i) const
+  { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
+
+  template <typename SubTableType>
+  inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
+  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+  template <typename SubTableType>
+  inline OffsetArrayOf<SubTableType>& get_subtables (void)
+  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+
   inline unsigned int get_type (void) const { return lookupType; }
 
   /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
@@ -577,36 +618,52 @@
     return flag;
   }
 
+  template <typename SubTableType, typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    unsigned int lookup_type = get_type ();
+    TRACE_DISPATCH (this, lookup_type);
+    unsigned int count = get_subtable_count ();
+    for (unsigned int i = 0; i < count; i++) {
+      typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
+      if (c->stop_sublookup_iteration (r))
+        return_trace (r);
+    }
+    return_trace (c->default_return_value ());
+  }
+
   inline bool serialize (hb_serialize_context_t *c,
 			 unsigned int lookup_type,
 			 uint32_t lookup_props,
 			 unsigned int num_subtables)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
     lookupType.set (lookup_type);
     lookupFlag.set (lookup_props & 0xFFFFu);
-    if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
+    if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
       markFilteringSet.set (lookup_props >> 16);
     }
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
-    if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
+    if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
-      if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
+      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      if (!markFilteringSet.sanitize (c)) return_trace (false);
     }
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
+  private:
   USHORT	lookupType;		/* Different enumerations for GSUB and GPOS */
   USHORT	lookupFlag;		/* Lookup qualifiers */
   ArrayOf<Offset<> >
@@ -642,18 +699,19 @@
 			 unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
     glyphArray.len.set (num_glyphs);
-    if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend (glyphArray))) return_trace (false);
     for (unsigned int i = 0; i < num_glyphs; i++)
       glyphArray[i] = glyphs[i];
     glyphs.advance (num_glyphs);
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (glyphArray.sanitize (c));
+    return_trace (glyphArray.sanitize (c));
   }
 
   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
@@ -710,16 +768,16 @@
 			 unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
+    if (unlikely (!num_glyphs)) return_trace (true);
 
     unsigned int num_ranges = 1;
     for (unsigned int i = 1; i < num_glyphs; i++)
       if (glyphs[i - 1] + 1 != glyphs[i])
         num_ranges++;
     rangeRecord.len.set (num_ranges);
-    if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
 
     unsigned int range = 0;
     rangeRecord[range].start = glyphs[0];
@@ -734,12 +792,13 @@
         rangeRecord[range].end = glyphs[i];
       }
     glyphs.advance (num_glyphs);
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (rangeRecord.sanitize (c));
+    return_trace (rangeRecord.sanitize (c));
   }
 
   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
@@ -819,26 +878,27 @@
 			 unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
     unsigned int num_ranges = 1;
     for (unsigned int i = 1; i < num_glyphs; i++)
       if (glyphs[i - 1] + 1 != glyphs[i])
         num_ranges++;
     u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
-    case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
-    default:return TRACE_RETURN (false);
+    case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs));
+    case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs));
+    default:return_trace (false);
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    if (!u.format.sanitize (c)) return_trace (false);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    default:return_trace (true);
     }
   }
 
@@ -938,14 +998,16 @@
   private:
   inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
-    if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len))
-      return classValue[glyph_id - startGlyph];
+    unsigned int i = (unsigned int) (glyph_id - startGlyph);
+    if (unlikely (i < classValue.len))
+      return classValue[i];
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
+    return_trace (c->check_struct (this) && classValue.sanitize (c));
   }
 
   template <typename set_t>
@@ -994,14 +1056,15 @@
   inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
     int i = rangeRecord.bsearch (glyph_id);
-    if (i != -1)
+    if (unlikely (i != -1))
       return rangeRecord[i].value;
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (rangeRecord.sanitize (c));
+    return_trace (rangeRecord.sanitize (c));
   }
 
   template <typename set_t>
@@ -1056,13 +1119,14 @@
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    if (!u.format.sanitize (c)) return_trace (false);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    default:return_trace (true);
     }
   }
 
@@ -1106,6 +1170,21 @@
   inline hb_position_t get_y_delta (hb_font_t *font) const
   { return get_delta (font->y_ppem, font->y_scale); }
 
+  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)));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
+  }
+
+  private:
+
   inline int get_delta (unsigned int ppem, int scale) const
   {
     if (!ppem) return 0;
@@ -1116,8 +1195,6 @@
 
     return (int) (pixels * (int64_t) scale / ppem);
   }
-
-
   inline int get_delta_pixels (unsigned int ppem_size) const
   {
     unsigned int f = deltaFormat;
@@ -1141,18 +1218,6 @@
     return delta;
   }
 
-  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)));
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
-  }
-
   protected:
   USHORT	startSize;		/* Smallest size to correct--in ppem */
   USHORT	endSize;		/* Largest size to correct--in ppem */
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 84a5e79..2b4bc5a 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -71,9 +71,10 @@
     return points.len;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
   }
 
   protected:
@@ -101,9 +102,10 @@
     return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -127,9 +129,10 @@
       return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -150,9 +153,10 @@
            font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this));
+    return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
   }
 
   protected:
@@ -178,14 +182,15 @@
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    if (!u.format.sanitize (c)) return_trace (false);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    case 3: return TRACE_RETURN (u.format3.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 3: return_trace (u.format3.sanitize (c));
+    default:return_trace (true);
     }
   }
 
@@ -219,9 +224,10 @@
     return carets.len;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (carets.sanitize (c, this));
+    return_trace (carets.sanitize (c, this));
   }
 
   protected:
@@ -253,9 +259,10 @@
     return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
   }
 
   protected:
@@ -275,9 +282,10 @@
   inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this));
   }
 
   protected:
@@ -299,12 +307,13 @@
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    if (!u.format.sanitize (c)) return_trace (false);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (u.format1.sanitize (c));
+    default:return_trace (true);
     }
   }
 
@@ -364,15 +373,16 @@
   inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (version.sanitize (c) &&
-			 likely (version.major == 1) &&
-			 glyphClassDef.sanitize (c, this) &&
-			 attachList.sanitize (c, this) &&
-			 ligCaretList.sanitize (c, this) &&
-			 markAttachClassDef.sanitize (c, this) &&
-			 (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
+    return_trace (version.sanitize (c) &&
+		  likely (version.major == 1) &&
+		  glyphClassDef.sanitize (c, this) &&
+		  attachList.sanitize (c, this) &&
+		  ligCaretList.sanitize (c, this) &&
+		  markAttachClassDef.sanitize (c, this) &&
+		  (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
   }
 
 
@@ -399,7 +409,7 @@
 
 
   protected:
-  FixedVersion	version;		/* Version of the GDEF table--currently
+  FixedVersion<>version;		/* Version of the GDEF table--currently
 					 * 0x00010002u */
   OffsetTo<ClassDef>
 		glyphClassDef;		/* Offset to class definition table
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index f7fef52..59dddcf 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -36,8 +36,17 @@
 
 
 /* buffer **position** var allocations */
-#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
-#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
+#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
+#define attach_type() var.u8[2] /* attachment type */
+/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
+
+enum attach_type_t {
+  ATTACH_TYPE_NONE	= 0X00,
+
+  /* Each attachment should be either a mark or a cursive; can't be both. */
+  ATTACH_TYPE_MARK	= 0X01,
+  ATTACH_TYPE_CURSIVE	= 0X02,
+};
 
 
 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
@@ -146,7 +155,8 @@
   }
 
   private:
-  inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
+  inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
     unsigned int format = *this;
 
     if (format & xPlacement) values++;
@@ -177,41 +187,44 @@
     return (format & devices) != 0;
   }
 
-  inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
+  inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+    return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
   }
 
-  inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
+  inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
+  {
     TRACE_SANITIZE (this);
     unsigned int len = get_len ();
 
-    if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
+    if (!c->check_array (values, get_size (), count)) return_trace (false);
 
-    if (!has_device ()) return TRACE_RETURN (true);
+    if (!has_device ()) return_trace (true);
 
     for (unsigned int i = 0; i < count; i++) {
       if (!sanitize_value_devices (c, base, values))
-        return TRACE_RETURN (false);
+        return_trace (false);
       values += len;
     }
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
-  inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
+  inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
+  {
     TRACE_SANITIZE (this);
 
-    if (!has_device ()) return TRACE_RETURN (true);
+    if (!has_device ()) return_trace (true);
 
     for (unsigned int i = 0; i < count; i++) {
       if (!sanitize_value_devices (c, base, values))
-        return TRACE_RETURN (false);
+        return_trace (false);
       values += stride;
     }
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 };
 
@@ -225,9 +238,10 @@
       *y = font->em_scale_y (yCoordinate);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -254,9 +268,10 @@
       *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   protected:
@@ -282,9 +297,10 @@
 	*y += (this+yDeviceTable).get_x_delta (font);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+    return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
   protected:
@@ -317,14 +333,15 @@
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    if (!u.format.sanitize (c)) return_trace (false);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    case 3: return TRACE_RETURN (u.format3.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 3: return_trace (u.format3.sanitize (c));
+    default:return_trace (true);
     }
   }
 
@@ -349,15 +366,16 @@
     return this+matrixZ[row * cols + col];
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
+  {
     TRACE_SANITIZE (this);
-    if (!c->check_struct (this)) return TRACE_RETURN (false);
-    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
+    if (!c->check_struct (this)) return_trace (false);
+    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
     unsigned int count = rows * cols;
-    if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
+    if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
     for (unsigned int i = 0; i < count; i++)
-      if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+      if (!matrixZ[i].sanitize (c, this)) return_trace (false);
+    return_trace (true);
   }
 
   USHORT	rows;			/* Number of rows */
@@ -374,9 +392,10 @@
 {
   friend struct MarkArray;
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
+    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
   }
 
   protected:
@@ -405,7 +424,7 @@
     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
     /* If this subtable doesn't have an anchor for this base and this class,
      * return false such that the subsequent subtables have a chance at it. */
-    if (unlikely (!found)) return TRACE_RETURN (false);
+    if (unlikely (!found)) return_trace (false);
 
     hb_position_t mark_x, mark_y, base_x, base_y;
 
@@ -415,15 +434,34 @@
     hb_glyph_position_t &o = buffer->cur_pos();
     o.x_offset = base_x - mark_x;
     o.y_offset = base_y - mark_y;
-    o.attach_lookback() = buffer->idx - glyph_pos;
+    o.attach_type() = ATTACH_TYPE_MARK;
+    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+    {
+      unsigned int i = buffer->idx;
+      unsigned int j = glyph_pos;
+      hb_glyph_position_t *pos = buffer->pos;
+      assert (j < i);
+      if (HB_DIRECTION_IS_FORWARD (c->direction))
+	for (unsigned int k = j; k < i; k++) {
+	  pos[i].x_offset -= pos[k].x_advance;
+	  pos[i].y_offset -= pos[k].y_advance;
+	}
+      else
+	for (unsigned int k = j + 1; k < i + 1; k++) {
+	  pos[i].x_offset += pos[k].x_advance;
+	  pos[i].y_offset += pos[k].y_advance;
+	}
+    }
 
     buffer->idx++;
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
+    return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
   }
 };
 
@@ -448,18 +486,21 @@
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     valueFormat.apply_value (c->font, c->direction, this,
 			     values, buffer->cur_pos());
 
     buffer->idx++;
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
+    return_trace (c->check_struct (this) &&
+		  coverage.sanitize (c, this) &&
+		  valueFormat.sanitize_value (c, this, values));
   }
 
   protected:
@@ -494,21 +535,24 @@
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
-    if (likely (index >= valueCount)) return TRACE_RETURN (false);
+    if (likely (index >= valueCount)) return_trace (false);
 
     valueFormat.apply_value (c->font, c->direction, this,
 			     &values[index * valueFormat.get_len ()],
 			     buffer->cur_pos());
 
     buffer->idx++;
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
+    return_trace (c->check_struct (this) &&
+		  coverage.sanitize (c, this) &&
+		  valueFormat.sanitize_values (c, this, values, valueCount));
   }
 
   protected:
@@ -531,20 +575,11 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    case 2: return TRACE_RETURN (c->dispatch (u.format2));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -607,7 +642,7 @@
 
     /* Hand-coded bsearch. */
     if (unlikely (!count))
-      return TRACE_RETURN (false);
+      return_trace (false);
     hb_codepoint_t x = buffer->info[pos].codepoint;
     int min = 0, max = (int) count - 1;
     while (min <= max)
@@ -628,29 +663,30 @@
 	if (len2)
 	  pos++;
 	buffer->idx = pos;
-	return TRACE_RETURN (true);
+	return_trace (true);
       }
     }
 
-    return TRACE_RETURN (false);
+    return_trace (false);
   }
 
   struct sanitize_closure_t {
-    void *base;
-    ValueFormat *valueFormats;
+    const void *base;
+    const ValueFormat *valueFormats;
     unsigned int len1; /* valueFormats[0].get_len() */
     unsigned int stride; /* 1 + len1 + len2 */
   };
 
-  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
+  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
+  {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
-       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
+       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false);
 
     unsigned int count = len;
-    PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
-    return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
-		      && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
+    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
+		  closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
   }
 
   protected:
@@ -681,20 +717,22 @@
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
-    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
-    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
-
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
-    if (!skippy_iter.next ()) return TRACE_RETURN (false);
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    if (!skippy_iter.next ()) return_trace (false);
 
-    return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
+    return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
 
+    if (!c->check_struct (this)) return_trace (false);
+
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     PairSet::sanitize_closure_t closure = {
@@ -704,7 +742,7 @@
       1 + len1 + len2
     };
 
-    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
+    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
   }
 
   protected:
@@ -730,7 +768,7 @@
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    /* (this+coverage).add_coverage (c->input); // Don't need this. */
+    (this+coverage).add_coverage (c->input);
 
     unsigned int count1 = class1Count;
     const ClassDef &klass1 = this+classDef1;
@@ -752,13 +790,12 @@
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
-    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
-    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
-
     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
-    if (!skippy_iter.next ()) return TRACE_RETURN (false);
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    if (!skippy_iter.next ()) return_trace (false);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
@@ -766,7 +803,7 @@
 
     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
     unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
-    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
+    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
 
     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
     valueFormat1.apply_value (c->font, c->direction, this,
@@ -778,24 +815,25 @@
     if (len2)
       buffer->idx++;
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
        && coverage.sanitize (c, this)
        && classDef1.sanitize (c, this)
-       && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
+       && classDef2.sanitize (c, this))) return_trace (false);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     unsigned int stride = len1 + len2;
     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
-    return TRACE_RETURN (c->check_array (values, record_size, count) &&
-			 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
-			 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+    return_trace (c->check_array (values, record_size, count) &&
+		  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+		  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
   }
 
   protected:
@@ -834,20 +872,11 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    case 2: return TRACE_RETURN (c->dispatch (u.format2));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -864,9 +893,10 @@
 {
   friend struct CursivePosFormat1;
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
+    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
   }
 
   protected:
@@ -882,6 +912,9 @@
   DEFINE_SIZE_STATIC (4);
 };
 
+static void
+reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
+
 struct CursivePosFormat1
 {
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -900,19 +933,15 @@
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
 
-    /* We don't handle mark glyphs here. */
-    if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
-
-    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
-    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
-
     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
-    if (!this_record.exitAnchor) return TRACE_RETURN (false);
+    if (!this_record.exitAnchor) return_trace (false);
 
-    if (!skippy_iter.next ()) return TRACE_RETURN (false);
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
+    if (!skippy_iter.next ()) return_trace (false);
 
     const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
-    if (!next_record.entryAnchor) return TRACE_RETURN (false);
+    if (!next_record.entryAnchor) return_trace (false);
 
     unsigned int i = buffer->idx;
     unsigned int j = skippy_iter.idx;
@@ -960,27 +989,49 @@
     }
 
     /* Cross-direction adjustment */
-    if  (c->lookup_props & LookupFlag::RightToLeft) {
-      pos[i].cursive_chain() = j - i;
-      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
-	pos[i].y_offset = entry_y - exit_y;
-      else
-	pos[i].x_offset = entry_x - exit_x;
-    } else {
-      pos[j].cursive_chain() = i - j;
-      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
-	pos[j].y_offset = exit_y - entry_y;
-      else
-	pos[j].x_offset = exit_x - entry_x;
+
+    /* We attach child to parent (think graph theory and rooted trees whereas
+     * the root stays on baseline and each node aligns itself against its
+     * parent.
+     *
+     * Optimize things for the case of RightToLeft, as that's most common in
+     * Arabinc. */
+    unsigned int child  = i;
+    unsigned int parent = j;
+    hb_position_t x_offset = entry_x - exit_x;
+    hb_position_t y_offset = entry_y - exit_y;
+    if  (!(c->lookup_props & LookupFlag::RightToLeft))
+    {
+      unsigned int k = child;
+      child = parent;
+      parent = k;
+      x_offset = -x_offset;
+      y_offset = -y_offset;
     }
 
+    /* If child was already connected to someone else, walk through its old
+     * chain and reverse the link direction, such that the whole tree of its
+     * previous connection now attaches to new parent.  Watch out for case
+     * where new parent is on the path from old chain...
+     */
+    reverse_cursive_minor_offset (pos, child, c->direction, parent);
+
+    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
+    pos[child].attach_chain() = (int) parent - (int) child;
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+      pos[child].y_offset = y_offset;
+    else
+      pos[child].x_offset = x_offset;
+
     buffer->idx = j;
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
   }
 
   protected:
@@ -1001,18 +1052,10 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -1048,31 +1091,36 @@
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (mark_index == NOT_COVERED)) return_trace (false);
 
-    /* now we search backwards for a non-mark glyph */
-    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
+    /* Now we search backwards for a non-mark glyph */
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     do {
-      if (!skippy_iter.prev ()) return TRACE_RETURN (false);
+      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;
       skippy_iter.reject ();
     } while (1);
 
     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
-    if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
+    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
 
     unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
-    if (base_index == NOT_COVERED) return TRACE_RETURN (false);
+    if (base_index == NOT_COVERED) return_trace (false);
 
-    return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
+    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
-			 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
+    return_trace (c->check_struct (this) &&
+		  markCoverage.sanitize (c, this) &&
+		  baseCoverage.sanitize (c, this) &&
+		  markArray.sanitize (c, this) &&
+		  baseArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
@@ -1100,18 +1148,10 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -1152,26 +1192,27 @@
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (mark_index == NOT_COVERED)) return_trace (false);
 
-    /* now we search backwards for a non-mark glyph */
-    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
+    /* Now we search backwards for a non-mark glyph */
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
-    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
+    if (!skippy_iter.prev ()) return_trace (false);
 
     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
-    if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
+    //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
 
     unsigned int j = skippy_iter.idx;
     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
-    if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
+    if (lig_index == NOT_COVERED) return_trace (false);
 
     const LigatureArray& lig_array = this+ligatureArray;
     const LigatureAttach& lig_attach = lig_array[lig_index];
 
     /* Find component to attach to */
     unsigned int comp_count = lig_attach.rows;
-    if (unlikely (!comp_count)) return TRACE_RETURN (false);
+    if (unlikely (!comp_count)) return_trace (false);
 
     /* We must now check whether the ligature ID of the current mark glyph
      * is identical to the ligature ID of the found ligature.  If yes, we
@@ -1186,13 +1227,17 @@
     else
       comp_index = comp_count - 1;
 
-    return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
+    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
-			 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
+    return_trace (c->check_struct (this) &&
+		  markCoverage.sanitize (c, this) &&
+		  ligatureCoverage.sanitize (c, this) &&
+		  markArray.sanitize (c, this) &&
+		  ligatureArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
@@ -1221,18 +1266,10 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -1268,14 +1305,15 @@
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
     unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
-    if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
-    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
-    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
+    if (!skippy_iter.prev ()) return_trace (false);
 
-    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
+    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
 
     unsigned int j = skippy_iter.idx;
 
@@ -1297,20 +1335,23 @@
     }
 
     /* Didn't match. */
-    return TRACE_RETURN (false);
+    return_trace (false);
 
     good:
     unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
-    if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
+    if (mark2_index == NOT_COVERED) return_trace (false);
 
-    return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
+    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
-			 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
-			 && mark2Array.sanitize (c, this, (unsigned int) classCount));
+    return_trace (c->check_struct (this) &&
+		  mark1Coverage.sanitize (c, this) &&
+		  mark2Coverage.sanitize (c, this) &&
+		  mark1Array.sanitize (c, this) &&
+		  mark2Array.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
@@ -1340,18 +1381,10 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -1399,43 +1432,24 @@
   inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
   {
     TRACE_DISPATCH (this, lookup_type);
+    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
     switch (lookup_type) {
-    case Single:		return TRACE_RETURN (u.single.dispatch (c));
-    case Pair:			return TRACE_RETURN (u.pair.dispatch (c));
-    case Cursive:		return TRACE_RETURN (u.cursive.dispatch (c));
-    case MarkBase:		return TRACE_RETURN (u.markBase.dispatch (c));
-    case MarkLig:		return TRACE_RETURN (u.markLig.dispatch (c));
-    case MarkMark:		return TRACE_RETURN (u.markMark.dispatch (c));
-    case Context:		return TRACE_RETURN (u.context.dispatch (c));
-    case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
-    case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
-    default:			return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
-    TRACE_SANITIZE (this);
-    if (!u.header.sub_format.sanitize (c))
-      return TRACE_RETURN (false);
-    switch (lookup_type) {
-    case Single:		return TRACE_RETURN (u.single.sanitize (c));
-    case Pair:			return TRACE_RETURN (u.pair.sanitize (c));
-    case Cursive:		return TRACE_RETURN (u.cursive.sanitize (c));
-    case MarkBase:		return TRACE_RETURN (u.markBase.sanitize (c));
-    case MarkLig:		return TRACE_RETURN (u.markLig.sanitize (c));
-    case MarkMark:		return TRACE_RETURN (u.markMark.sanitize (c));
-    case Context:		return TRACE_RETURN (u.context.sanitize (c));
-    case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
-    case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
-    default:			return TRACE_RETURN (true);
+    case Single:		return_trace (u.single.dispatch (c));
+    case Pair:			return_trace (u.pair.dispatch (c));
+    case Cursive:		return_trace (u.cursive.dispatch (c));
+    case MarkBase:		return_trace (u.markBase.dispatch (c));
+    case MarkLig:		return_trace (u.markLig.dispatch (c));
+    case MarkMark:		return_trace (u.markMark.dispatch (c));
+    case Context:		return_trace (u.context.dispatch (c));
+    case ChainContext:		return_trace (u.chainContext.dispatch (c));
+    case Extension:		return_trace (u.extension.dispatch (c));
+    default:			return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  struct {
-    USHORT		sub_format;
-  } header;
+  USHORT		sub_format;
   SinglePos		single;
   PairPos		pair;
   CursivePos		cursive;
@@ -1447,48 +1461,37 @@
   ExtensionPos		extension;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, header.sub_format);
+  DEFINE_SIZE_UNION (2, sub_format);
 };
 
 
 struct PosLookup : Lookup
 {
   inline const PosLookupSubTable& get_subtable (unsigned int i) const
-  { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
+  { return Lookup::get_subtable<PosLookupSubTable> (i); }
 
   inline bool is_reverse (void) const
   {
     return false;
   }
 
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    return_trace (dispatch (c));
+  }
+
   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    c->set_recurse_func (NULL);
-    return TRACE_RETURN (dispatch (c));
+    return_trace (dispatch (c));
   }
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
   {
-    hb_get_coverage_context_t c;
-    const Coverage *last = NULL;
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++) {
-      const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
-      if (coverage != last) {
-        coverage->add_coverage (glyphs);
-        last = coverage;
-      }
-    }
-  }
-
-  inline bool apply_once (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
-      return TRACE_RETURN (false);
-    return TRACE_RETURN (dispatch (c));
+    hb_add_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
   }
 
   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
@@ -1498,23 +1501,13 @@
 
   template <typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
-  {
-    unsigned int lookup_type = get_type ();
-    TRACE_DISPATCH (this, lookup_type);
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++) {
-      typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
-      if (c->stop_sublookup_iteration (r))
-        return TRACE_RETURN (r);
-    }
-    return TRACE_RETURN (c->default_return_value ());
-  }
+  { return Lookup::dispatch<PosLookupSubTable> (c); }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
-    OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
-    return TRACE_RETURN (list.sanitize (c, this, get_type ()));
+    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
+    return_trace (dispatch (c));
   }
 };
 
@@ -1532,13 +1525,15 @@
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
 
   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
+  static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
+  static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
-    OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
-    return TRACE_RETURN (list.sanitize (c, this));
+    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
+    const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
+    return_trace (list.sanitize (c, this));
   }
   public:
   DEFINE_SIZE_STATIC (10);
@@ -1546,59 +1541,77 @@
 
 
 static void
-fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
+reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
 {
-  unsigned int j = pos[i].cursive_chain();
-  if (likely (!j))
+  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
     return;
 
-  j += i;
+  pos[i].attach_chain() = 0;
 
-  pos[i].cursive_chain() = 0;
+  unsigned int j = (int) i + chain;
 
-  fix_cursive_minor_offset (pos, j, direction);
+  /* Stop if we see new parent in the chain. */
+  if (j == new_parent)
+    return;
+
+  reverse_cursive_minor_offset (pos, j, direction, new_parent);
 
   if (HB_DIRECTION_IS_HORIZONTAL (direction))
-    pos[i].y_offset += pos[j].y_offset;
+    pos[j].y_offset = -pos[i].y_offset;
   else
-    pos[i].x_offset += pos[j].x_offset;
-}
+    pos[j].x_offset = -pos[i].x_offset;
 
+  pos[j].attach_chain() = -chain;
+  pos[j].attach_type() = type;
+}
 static void
-fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
+propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
 {
-  if (likely (!(pos[i].attach_lookback())))
+  /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
+   * offset of glyph they are attached to. */
+  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+  if (likely (!chain))
     return;
 
-  unsigned int j = i - pos[i].attach_lookback();
+  unsigned int j = (int) i + chain;
 
-  pos[i].x_offset += pos[j].x_offset;
-  pos[i].y_offset += pos[j].y_offset;
+  pos[i].attach_chain() = 0;
 
-  if (HB_DIRECTION_IS_FORWARD (direction))
-    for (unsigned int k = j; k < i; k++) {
-      pos[i].x_offset -= pos[k].x_advance;
-      pos[i].y_offset -= pos[k].y_advance;
-    }
-  else
-    for (unsigned int k = j + 1; k < i + 1; k++) {
-      pos[i].x_offset += pos[k].x_advance;
-      pos[i].y_offset += pos[k].y_advance;
-    }
+  propagate_attachment_offsets (pos, j, direction);
+
+  assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
+
+  if (type & ATTACH_TYPE_CURSIVE)
+  {
+    if (HB_DIRECTION_IS_HORIZONTAL (direction))
+      pos[i].y_offset += pos[j].y_offset;
+    else
+      pos[i].x_offset += pos[j].x_offset;
+  }
+  else /*if (type & ATTACH_TYPE_MARK)*/
+  {
+    pos[i].x_offset += pos[j].x_offset;
+    pos[i].y_offset += pos[j].y_offset;
+  }
 }
 
 void
 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
 {
-  buffer->clear_positions ();
-
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
-    buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
+    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
 }
 
 void
-GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+{
+  //_hb_buffer_assert_gsubgpos_vars (buffer);
+}
+
+void
+GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
@@ -1606,13 +1619,10 @@
   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
   hb_direction_t direction = buffer->props.direction;
 
-  /* Handle cursive connections */
-  for (unsigned int i = 0; i < len; i++)
-    fix_cursive_minor_offset (pos, i, direction);
-
   /* Handle attachments */
-  for (unsigned int i = 0; i < len; i++)
-    fix_mark_attachment (pos, i, direction);
+  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
+    for (unsigned int i = 0; i < len; i++)
+      propagate_attachment_offsets (pos, i, direction);
 }
 
 
@@ -1631,15 +1641,18 @@
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
-  c->set_lookup (l);
-  bool ret = l.apply_once (c);
-  c->lookup_props = saved_lookup_props;
+  unsigned int saved_lookup_index = c->lookup_index;
+  c->set_lookup_index (lookup_index);
+  c->set_lookup_props (l.get_props ());
+  bool ret = l.dispatch (c);
+  c->set_lookup_index (saved_lookup_index);
+  c->set_lookup_props (saved_lookup_props);
   return ret;
 }
 
 
-#undef attach_lookback
-#undef cursive_chain
+#undef attach_chain
+#undef attach_type
 
 
 } /* namespace OT */
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 5d67be0..38c2c64 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -67,7 +67,7 @@
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
-    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -75,14 +75,14 @@
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
     unsigned int index = (this+coverage).get_coverage (glyph_id);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     /* According to the Adobe Annotated OpenType Suite, result is always
      * limited to 16bit. */
     glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
     c->replace_glyph (glyph_id);
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -91,15 +91,16 @@
 			 int delta)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
-    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
     deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
+    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
   }
 
   protected:
@@ -143,7 +144,7 @@
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
-    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -151,14 +152,14 @@
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
     unsigned int index = (this+coverage).get_coverage (glyph_id);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
-    if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
+    if (unlikely (index >= substitute.len)) return_trace (false);
 
     glyph_id = substitute[index];
     c->replace_glyph (glyph_id);
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -167,15 +168,16 @@
 			 unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
-    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
-    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
+    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
   }
 
   protected:
@@ -198,7 +200,7 @@
 			 unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 2;
     int delta = 0;
     if (num_glyphs) {
@@ -213,9 +215,9 @@
     }
     u.format.set (format);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
-    case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
-    default:return TRACE_RETURN (false);
+    case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
+    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
+    default:return_trace (false);
     }
   }
 
@@ -223,20 +225,11 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    case 2: return TRACE_RETURN (c->dispatch (u.format2));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -280,14 +273,14 @@
      * buffer->move_to() makes assumptions about this too.  Perhaps fix
      * in the future after figuring out what to do with the clusters.
      */
-    if (unlikely (!count)) return TRACE_RETURN (false);
+    if (unlikely (!count)) return_trace (false);
 
     /* Special-case to make it in-place and not consider this
      * as a "multiplied" substitution. */
     if (unlikely (count == 1))
     {
       c->replace_glyph (substitute.array[0]);
-      return TRACE_RETURN (true);
+      return_trace (true);
     }
 
     unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
@@ -299,7 +292,7 @@
     }
     c->buffer->skip_glyph ();
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -307,14 +300,15 @@
 			 unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
-    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (substitute.sanitize (c));
+    return_trace (substitute.sanitize (c));
   }
 
   protected:
@@ -353,7 +347,7 @@
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
-    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -361,9 +355,9 @@
     TRACE_APPLY (this);
 
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
-    return TRACE_RETURN ((this+sequence[index]).apply (c));
+    return_trace ((this+sequence[index]).apply (c));
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -373,20 +367,21 @@
 			 Supplier<GlyphID> &substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
-    if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
     for (unsigned int i = 0; i < num_glyphs; i++)
       if (unlikely (!sequence[i].serialize (c, this).serialize (c,
 								substitute_glyphs_list,
-								substitute_len_list[i]))) return TRACE_RETURN (false);
+								substitute_len_list[i]))) return_trace (false);
     substitute_len_list.advance (num_glyphs);
-    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
   }
 
   protected:
@@ -410,12 +405,12 @@
 			 Supplier<GlyphID> &substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 1;
     u.format.set (format);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
-    default:return TRACE_RETURN (false);
+    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
+    default:return_trace (false);
     }
   }
 
@@ -423,18 +418,10 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -486,7 +473,7 @@
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
-    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -495,11 +482,11 @@
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
     unsigned int index = (this+coverage).get_coverage (glyph_id);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     const AlternateSet &alt_set = this+alternateSet[index];
 
-    if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
+    if (unlikely (!alt_set.len)) return_trace (false);
 
     hb_mask_t glyph_mask = c->buffer->cur().mask;
     hb_mask_t lookup_mask = c->lookup_mask;
@@ -508,13 +495,13 @@
     unsigned int shift = _hb_ctz (lookup_mask);
     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
 
-    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
+    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
 
     glyph_id = alt_set[alt_index - 1];
 
     c->replace_glyph (glyph_id);
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -524,20 +511,21 @@
 			 Supplier<GlyphID> &alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
-    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
     for (unsigned int i = 0; i < num_glyphs; i++)
       if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
 								    alternate_glyphs_list,
-								    alternate_len_list[i]))) return TRACE_RETURN (false);
+								    alternate_len_list[i]))) return_trace (false);
     alternate_len_list.advance (num_glyphs);
-    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
   }
 
   protected:
@@ -561,12 +549,12 @@
 			 Supplier<GlyphID> &alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 1;
     u.format.set (format);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
-    default:return TRACE_RETURN (false);
+    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
+    default:return_trace (false);
     }
   }
 
@@ -574,18 +562,10 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -622,13 +602,13 @@
   {
     TRACE_WOULD_APPLY (this);
     if (c->len != component.len)
-      return TRACE_RETURN (false);
+      return_trace (false);
 
     for (unsigned int i = 1; i < c->len; i++)
       if (likely (c->glyphs[i] != component[i]))
-	return TRACE_RETURN (false);
+	return_trace (false);
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -636,21 +616,21 @@
     TRACE_APPLY (this);
     unsigned int count = component.len;
 
-    if (unlikely (!count)) return TRACE_RETURN (false);
+    if (unlikely (!count)) return_trace (false);
 
     /* Special-case to make it in-place and not consider this
      * as a "ligated" substitution. */
     if (unlikely (count == 1))
     {
       c->replace_glyph (ligGlyph);
-      return TRACE_RETURN (true);
+      return_trace (true);
     }
 
     bool is_mark_ligature = false;
     unsigned int total_component_count = 0;
 
     unsigned int match_length = 0;
-    unsigned int match_positions[MAX_CONTEXT_LENGTH];
+    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
 
     if (likely (!match_input (c, count,
 			      &component[1],
@@ -660,7 +640,7 @@
 			      match_positions,
 			      &is_mark_ligature,
 			      &total_component_count)))
-      return TRACE_RETURN (false);
+      return_trace (false);
 
     ligate_input (c,
 		  count,
@@ -670,7 +650,7 @@
 		  is_mark_ligature,
 		  total_component_count);
 
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -679,16 +659,17 @@
 			 unsigned int num_components /* Including first component */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
     ligGlyph = ligature;
-    if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
+    return_trace (true);
   }
 
   public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
+    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
   }
 
   protected:
@@ -727,9 +708,9 @@
     {
       const Ligature &lig = this+ligature[i];
       if (lig.would_apply (c))
-        return TRACE_RETURN (true);
+        return_trace (true);
     }
-    return TRACE_RETURN (false);
+    return_trace (false);
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -739,10 +720,10 @@
     for (unsigned int i = 0; i < num_ligs; i++)
     {
       const Ligature &lig = this+ligature[i];
-      if (lig.apply (c)) return TRACE_RETURN (true);
+      if (lig.apply (c)) return_trace (true);
     }
 
-    return TRACE_RETURN (false);
+    return_trace (false);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -752,21 +733,22 @@
 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
-    if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
     for (unsigned int i = 0; i < num_ligatures; i++)
       if (unlikely (!ligature[i].serialize (c, this).serialize (c,
 								ligatures[i],
 								component_list,
-								component_count_list[i]))) return TRACE_RETURN (false);
+								component_count_list[i]))) return_trace (false);
     ligatures.advance (num_ligatures);
     component_count_list.advance (num_ligatures);
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (ligature.sanitize (c, this));
+    return_trace (ligature.sanitize (c, this));
   }
 
   protected:
@@ -808,10 +790,10 @@
   {
     TRACE_WOULD_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LigatureSet &lig_set = this+ligatureSet[index];
-    return TRACE_RETURN (lig_set.would_apply (c));
+    return_trace (lig_set.would_apply (c));
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -820,10 +802,10 @@
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
     unsigned int index = (this+coverage).get_coverage (glyph_id);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LigatureSet &lig_set = this+ligatureSet[index];
-    return TRACE_RETURN (lig_set.apply (c));
+    return_trace (lig_set.apply (c));
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -835,22 +817,23 @@
 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
-    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
     for (unsigned int i = 0; i < num_first_glyphs; i++)
       if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
 								   ligatures_list,
 								   component_count_list,
 								   ligature_per_first_glyph_count_list[i],
-								   component_list))) return TRACE_RETURN (false);
+								   component_list))) return_trace (false);
     ligature_per_first_glyph_count_list.advance (num_first_glyphs);
-    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
   }
 
   protected:
@@ -876,13 +859,18 @@
 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+    if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 1;
     u.format.set (format);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
-						      ligatures_list, component_count_list, component_list));
-    default:return TRACE_RETURN (false);
+    case 1: return_trace (u.format1.serialize (c,
+					       first_glyphs,
+					       ligature_per_first_glyph_count_list,
+					       num_first_glyphs,
+					       ligatures_list,
+					       component_count_list,
+					       component_list));
+    default:return_trace (false);
     }
   }
 
@@ -890,18 +878,10 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -984,17 +964,17 @@
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
     TRACE_WOULD_APPLY (this);
-    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
-      return TRACE_RETURN (false); /* No chaining to this type */
+    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
+      return_trace (false); /* No chaining to this type */
 
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
@@ -1011,21 +991,22 @@
       /* Note: We DON'T decrease buffer->idx.  The main loop does it
        * for us.  This is useful for preventing surprises if someone
        * calls us through a Context lookup. */
-      return TRACE_RETURN (true);
+      return_trace (true);
     }
 
-    return TRACE_RETURN (false);
+    return_trace (false);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
-      return TRACE_RETURN (false);
-    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+      return_trace (false);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     if (!lookahead.sanitize (c, this))
-      return TRACE_RETURN (false);
-    ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
-    return TRACE_RETURN (substitute.sanitize (c));
+      return_trace (false);
+    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    return_trace (substitute.sanitize (c));
   }
 
   protected:
@@ -1054,18 +1035,10 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -1101,41 +1074,23 @@
   inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
   {
     TRACE_DISPATCH (this, lookup_type);
+    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
     switch (lookup_type) {
-    case Single:		return TRACE_RETURN (u.single.dispatch (c));
-    case Multiple:		return TRACE_RETURN (u.multiple.dispatch (c));
-    case Alternate:		return TRACE_RETURN (u.alternate.dispatch (c));
-    case Ligature:		return TRACE_RETURN (u.ligature.dispatch (c));
-    case Context:		return TRACE_RETURN (u.context.dispatch (c));
-    case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
-    case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
-    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c));
-    default:			return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
-    TRACE_SANITIZE (this);
-    if (!u.header.sub_format.sanitize (c))
-      return TRACE_RETURN (false);
-    switch (lookup_type) {
-    case Single:		return TRACE_RETURN (u.single.sanitize (c));
-    case Multiple:		return TRACE_RETURN (u.multiple.sanitize (c));
-    case Alternate:		return TRACE_RETURN (u.alternate.sanitize (c));
-    case Ligature:		return TRACE_RETURN (u.ligature.sanitize (c));
-    case Context:		return TRACE_RETURN (u.context.sanitize (c));
-    case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
-    case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
-    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
-    default:			return TRACE_RETURN (true);
+    case Single:		return_trace (u.single.dispatch (c));
+    case Multiple:		return_trace (u.multiple.dispatch (c));
+    case Alternate:		return_trace (u.alternate.dispatch (c));
+    case Ligature:		return_trace (u.ligature.dispatch (c));
+    case Context:		return_trace (u.context.dispatch (c));
+    case ChainContext:		return_trace (u.chainContext.dispatch (c));
+    case Extension:		return_trace (u.extension.dispatch (c));
+    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c));
+    default:			return_trace (c->default_return_value ());
     }
   }
 
   protected:
   union {
-  struct {
-    USHORT			sub_format;
-  } header;
+  USHORT			sub_format;
   SingleSubst			single;
   MultipleSubst			multiple;
   AlternateSubst		alternate;
@@ -1146,14 +1101,14 @@
   ReverseChainSingleSubst	reverseChainContextSingle;
   } u;
   public:
-  DEFINE_SIZE_UNION (2, header.sub_format);
+  DEFINE_SIZE_UNION (2, sub_format);
 };
 
 
 struct SubstLookup : Lookup
 {
   inline const SubstLookupSubTable& get_subtable (unsigned int i) const
-  { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
+  { return Lookup::get_subtable<SubstLookupSubTable> (i); }
 
   inline static bool lookup_type_is_reverse (unsigned int lookup_type)
   { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
@@ -1166,56 +1121,47 @@
     return lookup_type_is_reverse (type);
   }
 
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    return_trace (dispatch (c));
+  }
+
   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
-    return TRACE_RETURN (dispatch (c));
+    return_trace (dispatch (c));
   }
 
   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
-    return TRACE_RETURN (dispatch (c));
+    return_trace (dispatch (c));
   }
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
   {
-    hb_get_coverage_context_t c;
-    const Coverage *last = NULL;
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++) {
-      const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
-      if (coverage != last) {
-        coverage->add_coverage (glyphs);
-        last = coverage;
-      }
-    }
+    hb_add_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
   }
 
-  inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
+  inline bool would_apply (hb_would_apply_context_t *c,
+			   const hb_ot_layout_lookup_accelerator_t *accel) const
   {
     TRACE_WOULD_APPLY (this);
-    if (unlikely (!c->len))  return TRACE_RETURN (false);
-    if (!digest->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
-      return TRACE_RETURN (dispatch (c));
-  }
-
-  inline bool apply_once (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY (this);
-    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
-      return TRACE_RETURN (false);
-    return TRACE_RETURN (dispatch (c));
+    if (unlikely (!c->len))  return_trace (false);
+    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
+      return_trace (dispatch (c));
   }
 
   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
 
   inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
 						  unsigned int i)
-  { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
+  { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
 
   inline bool serialize_single (hb_serialize_context_t *c,
 				uint32_t lookup_props,
@@ -1224,8 +1170,8 @@
 			        unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
-    return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
+    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
   }
 
   inline bool serialize_multiple (hb_serialize_context_t *c,
@@ -1236,9 +1182,12 @@
 				  Supplier<GlyphID> &substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
-    return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
-									 substitute_glyphs_list));
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
+    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
+								  glyphs,
+								  substitute_len_list,
+								  num_glyphs,
+								  substitute_glyphs_list));
   }
 
   inline bool serialize_alternate (hb_serialize_context_t *c,
@@ -1249,9 +1198,12 @@
 				   Supplier<GlyphID> &alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
-    return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
-									  alternate_glyphs_list));
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
+    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
+								   glyphs,
+								   alternate_len_list,
+								   num_glyphs,
+								   alternate_glyphs_list));
   }
 
   inline bool serialize_ligature (hb_serialize_context_t *c,
@@ -1264,9 +1216,14 @@
 				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
-    return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
-									 ligatures_list, component_count_list, component_list));
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
+    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
+								  first_glyphs,
+								  ligature_per_first_glyph_count_list,
+								  num_first_glyphs,
+								  ligatures_list,
+								  component_count_list,
+								  component_list));
   }
 
   template <typename context_t>
@@ -1274,24 +1231,13 @@
 
   template <typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
-  {
-    unsigned int lookup_type = get_type ();
-    TRACE_DISPATCH (this, lookup_type);
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++) {
-      typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
-      if (c->stop_sublookup_iteration (r))
-        return TRACE_RETURN (r);
-    }
-    return TRACE_RETURN (c->default_return_value ());
-  }
+  { return Lookup::dispatch<SubstLookupSubTable> (c); }
 
-  inline bool sanitize (hb_sanitize_context_t *c)
+  inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
-    OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
-    if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
+    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
+    if (unlikely (!dispatch (c))) return_trace (false);
 
     if (unlikely (get_type () == SubstLookupSubTable::Extension))
     {
@@ -1302,9 +1248,9 @@
       unsigned int count = get_subtable_count ();
       for (unsigned int i = 1; i < count; i++)
         if (get_subtable (i).u.extension.get_type () != type)
-	  return TRACE_RETURN (false);
+	  return_trace (false);
     }
-    return TRACE_RETURN (true);
+    return_trace (true);
   }
 };
 
@@ -1322,13 +1268,13 @@
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
-    OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
-    return TRACE_RETURN (list.sanitize (c, this));
+    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
+    const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
+    return_trace (list.sanitize (c, this));
   }
   public:
   DEFINE_SIZE_STATIC (10);
@@ -1350,11 +1296,6 @@
   }
 }
 
-void
-GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
-{
-}
-
 
 /* Out-of-class implementation for methods recursing */
 
@@ -1362,7 +1303,7 @@
 {
   unsigned int type = get_type ();
   if (unlikely (type == SubstLookupSubTable::Extension))
-    return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
+    return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
   return SubstLookup::lookup_type_is_reverse (type);
 }
 
@@ -1379,9 +1320,12 @@
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
-  c->set_lookup (l);
-  bool ret = l.apply_once (c);
-  c->lookup_props = saved_lookup_props;
+  unsigned int saved_lookup_index = c->lookup_index;
+  c->set_lookup_index (lookup_index);
+  c->set_lookup_props (l.get_props ());
+  bool ret = l.dispatch (c);
+  c->set_lookup_index (saved_lookup_index);
+  c->set_lookup_props (saved_lookup_props);
   return ret;
 }
 
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 57fc1e0..691334c 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -37,12 +37,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);
-
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
@@ -52,11 +46,10 @@
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
 
-struct hb_closure_context_t
+struct hb_closure_context_t :
+       hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
 {
   inline const char *get_name (void) { return "CLOSURE"; }
-  static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
-  typedef hb_void_t return_t;
   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
   template <typename T>
   inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
@@ -81,7 +74,7 @@
 
   hb_closure_context_t (hb_face_t *face_,
 			hb_set_t *glyphs_,
-		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+		        unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
 			  face (face_),
 			  glyphs (glyphs_),
 			  recurse_func (NULL),
@@ -102,11 +95,10 @@
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "%d glyphs", c->len);
 
-struct hb_would_apply_context_t
+struct hb_would_apply_context_t :
+       hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
 {
   inline const char *get_name (void) { return "WOULD_APPLY"; }
-  static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
-  typedef bool return_t;
   template <typename T>
   inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
   static return_t default_return_value (void) { return false; }
@@ -140,11 +132,10 @@
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
 
-struct hb_collect_glyphs_context_t
+struct hb_collect_glyphs_context_t :
+       hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
 {
   inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
-  static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
-  typedef hb_void_t return_t;
   typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
   template <typename T>
   inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
@@ -205,7 +196,7 @@
 			       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 */
-			       unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+			       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 ()),
@@ -232,18 +223,28 @@
 #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
 #endif
 
-struct hb_get_coverage_context_t
+/* XXX Can we remove this? */
+
+template <typename set_t>
+struct hb_add_coverage_context_t :
+       hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
 {
   inline const char *get_name (void) { return "GET_COVERAGE"; }
-  static const unsigned int max_debug_depth = HB_DEBUG_GET_COVERAGE;
   typedef const Coverage &return_t;
   template <typename T>
   inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
   static return_t default_return_value (void) { return Null(Coverage); }
+  bool stop_sublookup_iteration (return_t r) const
+  {
+    r.add_coverage (set);
+    return false;
+  }
 
-  hb_get_coverage_context_t (void) :
+  hb_add_coverage_context_t (set_t *set_) :
+			    set (set_),
 			    debug_depth (0) {}
 
+  set_t *set;
   unsigned int debug_depth;
 };
 
@@ -256,65 +257,12 @@
 #define TRACE_APPLY(this) \
 	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+	 "idx %d gid %u lookup %d", \
+	 c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index);
 
-struct hb_apply_context_t
+struct hb_apply_context_t :
+       hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
 {
-  inline const char *get_name (void) { return "APPLY"; }
-  static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
-  typedef bool return_t;
-  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
-  template <typename T>
-  inline return_t dispatch (const T &obj) { return obj.apply (this); }
-  static return_t default_return_value (void) { return false; }
-  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))
-      return default_return_value ();
-
-    nesting_level_left--;
-    bool ret = recurse_func (this, lookup_index);
-    nesting_level_left++;
-    return ret;
-  }
-
-  unsigned int table_index; /* GSUB/GPOS */
-  hb_font_t *font;
-  hb_face_t *face;
-  hb_buffer_t *buffer;
-  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;
-  unsigned int debug_depth;
-
-
-  hb_apply_context_t (unsigned int table_index_,
-		      hb_font_t *font_,
-		      hb_buffer_t *buffer_) :
-			table_index (table_index_),
-			font (font_), face (font->face), buffer (buffer_),
-			direction (buffer_->props.direction),
-			lookup_mask (1),
-			auto_zwj (true),
-			recurse_func (NULL),
-			nesting_level_left (MAX_NESTING_LEVEL),
-			lookup_props (0),
-			gdef (*hb_ot_layout_from_face (face)->gdef),
-			has_glyph_classes (gdef.has_glyph_classes ()),
-			debug_depth (0) {}
-
-  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_recurse_func (recurse_func_t func) { recurse_func = func; }
-  inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
-  inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
-
   struct matcher_t
   {
     inline matcher_t (void) :
@@ -373,8 +321,7 @@
 
       if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
 		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
-		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
-		    !_hb_glyph_info_ligated (&info)))
+		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
 	return SKIP_MAYBE;
 
       return SKIP_NO;
@@ -390,43 +337,47 @@
     const void *match_data;
   };
 
-  struct skipping_forward_iterator_t
+  struct skipping_iterator_t
   {
-    inline skipping_forward_iterator_t (hb_apply_context_t *c_,
-					unsigned int start_index_,
-					unsigned int num_items_,
-					bool context_match = false) :
-					 idx (start_index_),
-					 c (c_),
-					 match_glyph_data (NULL),
-					 num_items (num_items_),
-					 end (c->buffer->len)
+    inline void init (hb_apply_context_t *c_, bool context_match = false)
     {
+      c = c_;
+      match_glyph_data = NULL,
+      matcher.set_match_func (NULL, NULL);
       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);
       /* 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);
-      if (!context_match)
-	matcher.set_mask (c->lookup_mask);
-      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+      matcher.set_mask (context_match ? -1 : c->lookup_mask);
     }
-    inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
-    inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
-    inline void set_match_func (matcher_t::match_func_t match_func,
-				const void *match_data,
+    inline void set_lookup_props (unsigned int lookup_props)
+    {
+      matcher.set_lookup_props (lookup_props);
+    }
+    inline void set_match_func (matcher_t::match_func_t match_func_,
+				const void *match_data_,
 				const USHORT glyph_data[])
     {
-      matcher.set_match_func (match_func, match_data);
+      matcher.set_match_func (match_func_, match_data_);
       match_glyph_data = glyph_data;
     }
 
-    inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); }
+    inline void reset (unsigned int start_index_,
+		       unsigned int num_items_)
+    {
+      idx = start_index_;
+      num_items = num_items_;
+      end = c->buffer->len;
+      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+    }
+
     inline void reject (void) { num_items++; match_glyph_data--; }
+
     inline bool next (void)
     {
       assert (num_items > 0);
-      while (!has_no_chance ())
+      while (idx + num_items < end)
       {
 	idx++;
 	const hb_glyph_info_t &info = c->buffer->info[idx];
@@ -450,53 +401,10 @@
       }
       return false;
     }
-
-    unsigned int idx;
-    protected:
-    hb_apply_context_t *c;
-    matcher_t matcher;
-    const USHORT *match_glyph_data;
-
-    unsigned int num_items;
-    unsigned int end;
-  };
-
-  struct skipping_backward_iterator_t
-  {
-    inline skipping_backward_iterator_t (hb_apply_context_t *c_,
-					 unsigned int start_index_,
-					 unsigned int num_items_,
-					 bool context_match = false) :
-					  idx (start_index_),
-					  c (c_),
-					  match_glyph_data (NULL),
-					  num_items (num_items_)
-    {
-      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);
-      /* 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);
-      if (!context_match)
-	matcher.set_mask (c->lookup_mask);
-      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
-    }
-    inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
-    inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
-    inline void set_match_func (matcher_t::match_func_t match_func,
-				const void *match_data,
-				const USHORT glyph_data[])
-    {
-      matcher.set_match_func (match_func, match_data);
-      match_glyph_data = glyph_data;
-    }
-
-    inline bool has_no_chance (void) const { return unlikely (idx < num_items); }
-    inline void reject (void) { num_items++; }
     inline bool prev (void)
     {
       assert (num_items > 0);
-      while (!has_no_chance ())
+      while (idx >= num_items)
       {
 	idx--;
 	const hb_glyph_info_t &info = c->buffer->out_info[idx];
@@ -528,44 +436,109 @@
     const USHORT *match_glyph_data;
 
     unsigned int num_items;
+    unsigned int end;
   };
 
+
+  inline const char *get_name (void) { return "APPLY"; }
+  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.apply (this); }
+  static return_t default_return_value (void) { return false; }
+  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))
+      return default_return_value ();
+
+    nesting_level_left--;
+    bool ret = recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return ret;
+  }
+
+  unsigned int table_index; /* GSUB/GPOS */
+  hb_font_t *font;
+  hb_face_t *face;
+  hb_buffer_t *buffer;
+  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;
+  skipping_iterator_t iter_input, iter_context;
+  unsigned int lookup_index;
+  unsigned int debug_depth;
+
+
+  hb_apply_context_t (unsigned int table_index_,
+		      hb_font_t *font_,
+		      hb_buffer_t *buffer_) :
+			table_index (table_index_),
+			font (font_), face (font->face), buffer (buffer_),
+			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 ()),
+			iter_input (),
+			iter_context (),
+			lookup_index ((unsigned int) -1),
+			debug_depth (0) {}
+
+  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_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_)
+  {
+    lookup_props = lookup_props_;
+    iter_input.init (this, false);
+    iter_context.init (this, true);
+  }
+
   inline bool
   match_properties_mark (hb_codepoint_t  glyph,
 			 unsigned int    glyph_props,
-			 unsigned int    lookup_props) const
+			 unsigned int    match_props) const
   {
     /* If using mark filtering sets, the high short of
-     * lookup_props has the set index.
+     * match_props has the set index.
      */
-    if (lookup_props & LookupFlag::UseMarkFilteringSet)
-      return gdef.mark_set_covers (lookup_props >> 16, glyph);
+    if (match_props & LookupFlag::UseMarkFilteringSet)
+      return gdef.mark_set_covers (match_props >> 16, glyph);
 
-    /* The second byte of lookup_props has the meaning
+    /* The second byte of match_props has the meaning
      * "ignore marks of attachment type different than
      * the attachment type specified."
      */
-    if (lookup_props & LookupFlag::MarkAttachmentType)
-      return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
+    if (match_props & LookupFlag::MarkAttachmentType)
+      return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
 
     return true;
   }
 
   inline bool
   check_glyph_property (const hb_glyph_info_t *info,
-			unsigned int  lookup_props) const
+			unsigned int  match_props) const
   {
     hb_codepoint_t glyph = info->codepoint;
     unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
 
     /* Not covered, if, for example, glyph class is ligature and
-     * lookup_props includes LookupFlags::IgnoreLigatures
+     * match_props includes LookupFlags::IgnoreLigatures
      */
-    if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
+    if (glyph_props & match_props & LookupFlag::IgnoreFlags)
       return false;
 
     if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
-      return match_properties_mark (glyph, glyph_props, lookup_props);
+      return match_properties_mark (glyph, glyph_props, match_props);
 
     return true;
   }
@@ -731,19 +704,19 @@
 				match_func_t match_func,
 				const void *match_data,
 				unsigned int *end_offset,
-				unsigned int match_positions[MAX_CONTEXT_LENGTH],
+				unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
 				bool *p_is_mark_ligature = NULL,
 				unsigned int *p_total_component_count = NULL)
 {
   TRACE_APPLY (NULL);
 
-  if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
+  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
 
   hb_buffer_t *buffer = c->buffer;
 
-  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1);
+  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+  skippy_iter.reset (buffer->idx, count - 1);
   skippy_iter.set_match_func (match_func, match_data, input);
-  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
   /*
    * This is perhaps the trickiest part of OpenType...  Remarks:
@@ -774,7 +747,7 @@
   match_positions[0] = buffer->idx;
   for (unsigned int i = 1; i < count; i++)
   {
-    if (!skippy_iter.next ()) return TRACE_RETURN (false);
+    if (!skippy_iter.next ()) return_trace (false);
 
     match_positions[i] = skippy_iter.idx;
 
@@ -786,13 +759,13 @@
        * all subsequent components should be attached to the same ligature
        * component, otherwise we shouldn't ligate them. */
       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
-	return TRACE_RETURN (false);
+	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! */
       if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
-	return TRACE_RETURN (false);
+	return_trace (false);
     }
 
     is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
@@ -807,11 +780,11 @@
   if (p_total_component_count)
     *p_total_component_count = total_component_count;
 
-  return TRACE_RETURN (true);
+  return_trace (true);
 }
-static inline void ligate_input (hb_apply_context_t *c,
+static inline bool ligate_input (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
-				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
+				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
 				 unsigned int match_length,
 				 hb_codepoint_t lig_glyph,
 				 bool is_mark_ligature,
@@ -863,19 +836,21 @@
     if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     {
       _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
-      _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
     }
   }
   c->replace_glyph_with_ligature (lig_glyph, klass);
 
   for (unsigned int i = 1; i < count; i++)
   {
-    while (buffer->idx < match_positions[i])
+    while (buffer->idx < match_positions[i] && !buffer->in_error)
     {
       if (!is_mark_ligature) {
+        unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+	if (this_comp == 0)
+	  this_comp = last_num_components;
 	unsigned int new_lig_comp = components_so_far - last_num_components +
-				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
-	_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
+				    MIN (this_comp, last_num_components);
+	  _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
       }
       buffer->next_glyph ();
     }
@@ -892,14 +867,17 @@
     /* Re-adjust components for any marks following. */
     for (unsigned int i = buffer->idx; i < buffer->len; i++) {
       if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
+        unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
+	if (!this_comp)
+	  break;
 	unsigned int new_lig_comp = components_so_far - last_num_components +
-				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
+				    MIN (this_comp, last_num_components);
 	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
       } else
 	break;
     }
   }
-  TRACE_RETURN (true);
+  return_trace (true);
 }
 
 static inline bool match_backtrack (hb_apply_context_t *c,
@@ -910,15 +888,15 @@
 {
   TRACE_APPLY (NULL);
 
-  hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
+  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  skippy_iter.reset (c->buffer->backtrack_len (), count);
   skippy_iter.set_match_func (match_func, match_data, backtrack);
-  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
   for (unsigned int i = 0; i < count; i++)
     if (!skippy_iter.prev ())
-      return TRACE_RETURN (false);
+      return_trace (false);
 
-  return TRACE_RETURN (true);
+  return_trace (true);
 }
 
 static inline bool match_lookahead (hb_apply_context_t *c,
@@ -930,24 +908,25 @@
 {
   TRACE_APPLY (NULL);
 
-  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
+  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+  skippy_iter.reset (c->buffer->idx + offset - 1, count);
   skippy_iter.set_match_func (match_func, match_data, lookahead);
-  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
   for (unsigned int i = 0; i < count; i++)
     if (!skippy_iter.next ())
-      return TRACE_RETURN (false);
+      return_trace (false);
 
-  return TRACE_RETURN (true);
+  return_trace (true);
 }
 
 
 
 struct LookupRecord
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this));
   }
 
   USHORT	sequenceIndex;		/* Index into current glyph
@@ -970,7 +949,7 @@
 
 static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
-				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
+				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
 				 unsigned int lookupCount,
 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
 				 unsigned int match_length)
@@ -992,12 +971,17 @@
       match_positions[j] += delta;
   }
 
-  for (unsigned int i = 0; i < lookupCount; i++)
+  for (unsigned int i = 0; i < lookupCount && !buffer->in_error; i++)
   {
     unsigned int idx = lookupRecord[i].sequenceIndex;
     if (idx >= count)
       continue;
 
+    /* Don't recurse to ourself at same position.
+     * Note that this test is too naive, it doesn't catch longer loops. */
+    if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
+      continue;
+
     buffer->move_to (match_positions[idx]);
 
     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
@@ -1015,13 +999,13 @@
     /* end can't go back past the current match position.
      * Note: this is only true because we do NOT allow MultipleSubst
      * with zero sequence len. */
-    end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
+    end = MAX (MIN((int) match_positions[idx] + 1, (int) new_len), int (end) + delta);
 
     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
 
     if (delta > 0)
     {
-      if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
+      if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
 	break;
     }
     else
@@ -1048,7 +1032,7 @@
 
   buffer->move_to (end);
 
-  return TRACE_RETURN (true);
+  return_trace (true);
 }
 
 
@@ -1120,7 +1104,7 @@
 					 ContextApplyLookupContext &lookup_context)
 {
   unsigned int match_length = 0;
-  unsigned int match_positions[MAX_CONTEXT_LENGTH];
+  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data,
@@ -1157,18 +1141,19 @@
   {
     TRACE_WOULD_APPLY (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
-    return TRACE_RETURN (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+    return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
   }
 
   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
-    return TRACE_RETURN (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+    return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
   }
 
   public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
     return inputCount.sanitize (c)
 	&& lookupCount.sanitize (c)
@@ -1215,9 +1200,9 @@
     for (unsigned int i = 0; i < num_rules; i++)
     {
       if ((this+rule[i]).would_apply (c, lookup_context))
-        return TRACE_RETURN (true);
+        return_trace (true);
     }
-    return TRACE_RETURN (false);
+    return_trace (false);
   }
 
   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
@@ -1227,14 +1212,15 @@
     for (unsigned int i = 0; i < num_rules; i++)
     {
       if ((this+rule[i]).apply (c, lookup_context))
-        return TRACE_RETURN (true);
+        return_trace (true);
     }
-    return TRACE_RETURN (false);
+    return_trace (false);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (rule.sanitize (c, this));
+    return_trace (rule.sanitize (c, this));
   }
 
   protected:
@@ -1291,7 +1277,7 @@
       {match_glyph},
       NULL
     };
-    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+    return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1304,19 +1290,20 @@
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED))
-      return TRACE_RETURN (false);
+      return_trace (false);
 
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
       {match_glyph},
       NULL
     };
-    return TRACE_RETURN (rule_set.apply (c, lookup_context));
+    return_trace (rule_set.apply (c, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
@@ -1382,7 +1369,7 @@
       {match_class},
       &class_def
     };
-    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+    return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1394,7 +1381,7 @@
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     const ClassDef &class_def = this+classDef;
     index = class_def.get_class (c->buffer->cur().codepoint);
@@ -1403,12 +1390,13 @@
       {match_class},
       &class_def
     };
-    return TRACE_RETURN (rule_set.apply (c, lookup_context));
+    return_trace (rule_set.apply (c, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
@@ -1472,7 +1460,7 @@
       {match_coverage},
       this
     };
-    return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1484,26 +1472,27 @@
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
       {match_coverage},
       this
     };
-    return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+    return_trace (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (!c->check_struct (this)) return TRACE_RETURN (false);
+    if (!c->check_struct (this)) return_trace (false);
     unsigned int count = glyphCount;
-    if (!count) return TRACE_RETURN (false); /* We want to access coverageZ[0] freely. */
-    if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return TRACE_RETURN (false);
+    if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
+    if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
     for (unsigned int i = 0; i < count; i++)
-      if (!coverageZ[i].sanitize (c, this)) return TRACE_RETURN (false);
-    LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
-    return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
+      if (!coverageZ[i].sanitize (c, this)) return_trace (false);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
+    return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
   }
 
   protected:
@@ -1526,22 +1515,12 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    case 2: return TRACE_RETURN (c->dispatch (u.format2));
-    case 3: return TRACE_RETURN (c->dispatch (u.format3));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    case 3: return TRACE_RETURN (u.format3.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    case 3: return_trace (c->dispatch (u.format3));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -1652,7 +1631,7 @@
 					       ChainContextApplyLookupContext &lookup_context)
 {
   unsigned int match_length = 0;
-  unsigned int match_positions[MAX_CONTEXT_LENGTH];
+  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data[1],
@@ -1706,11 +1685,11 @@
     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
-    return TRACE_RETURN (chain_context_would_apply_lookup (c,
-							   backtrack.len, backtrack.array,
-							   input.len, input.array,
-							   lookahead.len, lookahead.array, lookup.len,
-							   lookup.array, lookup_context));
+    return_trace (chain_context_would_apply_lookup (c,
+						    backtrack.len, backtrack.array,
+						    input.len, input.array,
+						    lookahead.len, lookahead.array, lookup.len,
+						    lookup.array, lookup_context));
   }
 
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
@@ -1719,22 +1698,23 @@
     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
-    return TRACE_RETURN (chain_context_apply_lookup (c,
-						     backtrack.len, backtrack.array,
-						     input.len, input.array,
-						     lookahead.len, lookahead.array, lookup.len,
-						     lookup.array, lookup_context));
+    return_trace (chain_context_apply_lookup (c,
+					      backtrack.len, backtrack.array,
+					      input.len, input.array,
+					      lookahead.len, lookahead.array, lookup.len,
+					      lookup.array, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
-    HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    if (!input.sanitize (c)) return TRACE_RETURN (false);
-    ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
-    if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
-    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
-    return TRACE_RETURN (lookup.sanitize (c));
+    if (!backtrack.sanitize (c)) return_trace (false);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    if (!input.sanitize (c)) return_trace (false);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    if (!lookahead.sanitize (c)) return_trace (false);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    return_trace (lookup.sanitize (c));
   }
 
   protected:
@@ -1779,9 +1759,9 @@
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       if ((this+rule[i]).would_apply (c, lookup_context))
-        return TRACE_RETURN (true);
+        return_trace (true);
 
-    return TRACE_RETURN (false);
+    return_trace (false);
   }
 
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
@@ -1790,14 +1770,15 @@
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       if ((this+rule[i]).apply (c, lookup_context))
-        return TRACE_RETURN (true);
+        return_trace (true);
 
-    return TRACE_RETURN (false);
+    return_trace (false);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (rule.sanitize (c, this));
+    return_trace (rule.sanitize (c, this));
   }
 
   protected:
@@ -1852,7 +1833,7 @@
       {match_glyph},
       {NULL, NULL, NULL}
     };
-    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+    return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1864,19 +1845,20 @@
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
       {match_glyph},
       {NULL, NULL, NULL}
     };
-    return TRACE_RETURN (rule_set.apply (c, lookup_context));
+    return_trace (rule_set.apply (c, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
@@ -1955,7 +1937,7 @@
        &input_class_def,
        &lookahead_class_def}
     };
-    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+    return_trace (rule_set.would_apply (c, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
@@ -1967,7 +1949,7 @@
   {
     TRACE_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
@@ -1981,14 +1963,17 @@
        &input_class_def,
        &lookahead_class_def}
     };
-    return TRACE_RETURN (rule_set.apply (c, lookup_context));
+    return_trace (rule_set.apply (c, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
-			 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
-			 ruleSet.sanitize (c, this));
+    return_trace (coverage.sanitize (c, this) &&
+		  backtrackClassDef.sanitize (c, this) &&
+		  inputClassDef.sanitize (c, this) &&
+		  lookaheadClassDef.sanitize (c, this) &&
+		  ruleSet.sanitize (c, this));
   }
 
   protected:
@@ -2071,11 +2056,11 @@
       {match_coverage},
       {this, this, this}
     };
-    return TRACE_RETURN (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,
-							   lookup.len, lookup.array, lookup_context));
+    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,
+						    lookup.len, lookup.array, lookup_context));
   }
 
   inline const Coverage &get_coverage (void) const
@@ -2090,7 +2075,7 @@
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
-    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+    if (likely (index == NOT_COVERED)) return_trace (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
@@ -2098,23 +2083,24 @@
       {match_coverage},
       {this, this, this}
     };
-    return TRACE_RETURN (chain_context_apply_lookup (c,
-						     backtrack.len, (const USHORT *) backtrack.array,
-						     input.len, (const USHORT *) input.array + 1,
-						     lookahead.len, (const USHORT *) lookahead.array,
-						     lookup.len, lookup.array, lookup_context));
+    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,
+					      lookup.len, lookup.array, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
-    OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
-    if (!input.sanitize (c, this)) return TRACE_RETURN (false);
-    if (!input.len) return TRACE_RETURN (false); /* To be consistent with Context. */
-    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
-    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
-    return TRACE_RETURN (lookup.sanitize (c));
+    if (!backtrack.sanitize (c, this)) return_trace (false);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    if (!input.sanitize (c, this)) return_trace (false);
+    if (!input.len) return_trace (false); /* To be consistent with Context. */
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    if (!lookahead.sanitize (c, this)) return_trace (false);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    return_trace (lookup.sanitize (c));
   }
 
   protected:
@@ -2144,22 +2130,12 @@
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (c->dispatch (u.format1));
-    case 2: return TRACE_RETURN (c->dispatch (u.format2));
-    case 3: return TRACE_RETURN (c->dispatch (u.format3));
-    default:return TRACE_RETURN (c->default_return_value ());
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    case 3: return TRACE_RETURN (u.format3.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (c->dispatch (u.format1));
+    case 2: return_trace (c->dispatch (u.format2));
+    case 3: return_trace (c->dispatch (u.format3));
+    default:return_trace (c->default_return_value ());
     }
   }
 
@@ -2173,14 +2149,32 @@
 };
 
 
+template <typename T>
 struct ExtensionFormat1
 {
   inline unsigned int get_type (void) const { return extensionLookupType; }
-  inline unsigned int get_offset (void) const { return extensionOffset; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  template <typename X>
+  inline const X& get_subtable (void) const
+  {
+    unsigned int offset = extensionOffset;
+    if (unlikely (!offset)) return Null(typename T::LookupSubTable);
+    return StructAtOffset<typename T::LookupSubTable> (this, offset);
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, format);
+    if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
+    return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
+  }
+
+  /* This is called from may_dispatch() above with hb_sanitize_context_t. */
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this));
+    return_trace (c->check_struct (this) && extensionOffset != 0);
   }
 
   protected:
@@ -2204,49 +2198,30 @@
     default:return 0;
     }
   }
-  inline unsigned int get_offset (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_offset ();
-    default:return 0;
-    }
-  }
-
   template <typename X>
   inline const X& get_subtable (void) const
   {
-    unsigned int offset = get_offset ();
-    if (unlikely (!offset)) return Null(typename T::LookupSubTable);
-    return StructAtOffset<typename T::LookupSubTable> (this, offset);
+    switch (u.format) {
+    case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
+    default:return Null(typename T::LookupSubTable);
+    }
   }
 
   template <typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
   {
-    return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
-  }
-
-  inline bool sanitize_self (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return_trace (u.format1.dispatch (c));
+    default:return_trace (c->default_return_value ());
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE (this);
-    if (!sanitize_self (c)) return TRACE_RETURN (false);
-    unsigned int offset = get_offset ();
-    if (unlikely (!offset)) return TRACE_RETURN (true);
-    return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
-  }
-
   protected:
   union {
   USHORT		format;		/* Format identifier */
-  ExtensionFormat1	format1;
+  ExtensionFormat1<T>	format1;
   } u;
 };
 
@@ -2291,16 +2266,18 @@
   inline const Lookup& get_lookup (unsigned int i) const
   { return (this+lookupList)[i]; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
-			 scriptList.sanitize (c, this) &&
-			 featureList.sanitize (c, this) &&
-			 lookupList.sanitize (c, this));
+    return_trace (version.sanitize (c) &&
+		  likely (version.major == 1) &&
+		  scriptList.sanitize (c, this) &&
+		  featureList.sanitize (c, this) &&
+		  lookupList.sanitize (c, this));
   }
 
   protected:
-  FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
+  FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
 				 * to 0x00010000u */
   OffsetTo<ScriptList>
 		scriptList;  	/* ScriptList table */
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
index 67a6df5..c306849 100644
--- a/src/hb-ot-layout-jstf-table.hh
+++ b/src/hb-ot-layout-jstf-table.hh
@@ -54,19 +54,20 @@
 
 struct JstfPriority
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) &&
-			 shrinkageEnableGSUB.sanitize (c, this) &&
-			 shrinkageDisableGSUB.sanitize (c, this) &&
-			 shrinkageEnableGPOS.sanitize (c, this) &&
-			 shrinkageDisableGPOS.sanitize (c, this) &&
-			 shrinkageJstfMax.sanitize (c, this) &&
-			 extensionEnableGSUB.sanitize (c, this) &&
-			 extensionDisableGSUB.sanitize (c, this) &&
-			 extensionEnableGPOS.sanitize (c, this) &&
-			 extensionDisableGPOS.sanitize (c, this) &&
-			 extensionJstfMax.sanitize (c, this));
+    return_trace (c->check_struct (this) &&
+		  shrinkageEnableGSUB.sanitize (c, this) &&
+		  shrinkageDisableGSUB.sanitize (c, this) &&
+		  shrinkageEnableGPOS.sanitize (c, this) &&
+		  shrinkageDisableGPOS.sanitize (c, this) &&
+		  shrinkageJstfMax.sanitize (c, this) &&
+		  extensionEnableGSUB.sanitize (c, this) &&
+		  extensionDisableGSUB.sanitize (c, this) &&
+		  extensionEnableGPOS.sanitize (c, this) &&
+		  extensionDisableGPOS.sanitize (c, this) &&
+		  extensionJstfMax.sanitize (c, this));
   }
 
   protected:
@@ -123,9 +124,10 @@
 struct JstfLangSys : OffsetListOf<JstfPriority>
 {
   inline bool sanitize (hb_sanitize_context_t *c,
-			const Record<JstfLangSys>::sanitize_closure_t * = NULL) {
+			const Record<JstfLangSys>::sanitize_closure_t * = NULL) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (OffsetListOf<JstfPriority>::sanitize (c));
+    return_trace (OffsetListOf<JstfPriority>::sanitize (c));
   }
 };
 
@@ -163,11 +165,12 @@
   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 Record<JstfScript>::sanitize_closure_t * = NULL) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (extenderGlyphs.sanitize (c, this) &&
-			 defaultLangSys.sanitize (c, this) &&
-			 langSys.sanitize (c, this));
+    return_trace (extenderGlyphs.sanitize (c, this) &&
+		  defaultLangSys.sanitize (c, this) &&
+		  langSys.sanitize (c, this));
   }
 
   protected:
@@ -206,14 +209,16 @@
   inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
   { return scriptList.find_index (tag, index); }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
-			 scriptList.sanitize (c, this));
+    return_trace (version.sanitize (c) &&
+		  likely (version.major == 1) &&
+		  scriptList.sanitize (c, this));
   }
 
   protected:
-  FixedVersion	version;	/* Version of the JSTF table--initially set
+  FixedVersion<>version;	/* Version of the JSTF table--initially set
 				 * to 0x00010000u */
   RecordArrayOf<JstfScript>
 		scriptList;  	/* Array of JstfScripts--listed
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index 3f7c858..b5c670f 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -36,11 +36,20 @@
 #include "hb-set-private.hh"
 
 
+/* Private API corresponding to hb-ot-layout.h: */
+
+HB_INTERNAL hb_bool_t
+hb_ot_layout_table_find_feature (hb_face_t    *face,
+				 hb_tag_t      table_tag,
+				 hb_tag_t      feature_tag,
+				 unsigned int *feature_index);
+
+
 /*
  * GDEF
  */
 
-typedef enum
+enum hb_ot_layout_glyph_props_flags_t
 {
   /* The following three match LookupFlags::Ignore* numbers. */
   HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH	= 0x02u,
@@ -55,7 +64,8 @@
   HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE     = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
 					  HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
 					  HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
-} hb_ot_layout_glyph_class_mask_t;
+};
+HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);
 
 
 /*
@@ -89,21 +99,20 @@
 				const hb_ot_layout_lookup_accelerator_t &accel);
 
 
-/* Should be called after all the substitute_lookup's are done */
-HB_INTERNAL void
-hb_ot_layout_substitute_finish (hb_font_t    *font,
-				hb_buffer_t  *buffer);
-
-
-/* Should be called before all the position_lookup's are done.  Resets positions to zero. */
+/* Should be called before all the position_lookup's are done. */
 HB_INTERNAL void
 hb_ot_layout_position_start (hb_font_t    *font,
 			     hb_buffer_t  *buffer);
 
-/* Should be called after all the position_lookup's are done */
+/* Should be called after all the position_lookup's are done, to finish advances. */
 HB_INTERNAL void
-hb_ot_layout_position_finish (hb_font_t    *font,
-			      hb_buffer_t  *buffer);
+hb_ot_layout_position_finish_advances (hb_font_t    *font,
+				       hb_buffer_t  *buffer);
+
+/* Should be called after hb_ot_layout_position_finish_advances, to finish offsets. */
+HB_INTERNAL void
+hb_ot_layout_position_finish_offsets (hb_font_t    *font,
+				      hb_buffer_t  *buffer);
 
 
 
@@ -130,6 +139,11 @@
   {
   }
 
+  inline bool may_have (hb_codepoint_t g) const {
+    return digest.may_have (g);
+  }
+
+  private:
   hb_set_digest_t digest;
 };
 
@@ -166,82 +180,201 @@
  */
 
 /* buffer var allocations, used during the entire shaping process */
-#define unicode_props0()	var2.u8[0]
-#define unicode_props1()	var2.u8[1]
+#define unicode_props()		var2.u16[0]
 
 /* buffer var allocations, used during the GSUB/GPOS processing */
 #define glyph_props()		var1.u16[0] /* GDEF glyph properties */
 #define lig_props()		var1.u8[2] /* GSUB/GPOS ligature tracking */
 #define syllable()		var1.u8[3] /* GSUB/GPOS shaping boundaries */
 
+
+/* loop over syllables */
+
+#define foreach_syllable(buffer, start, end) \
+  for (unsigned int \
+       _count = buffer->len, \
+       start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \
+       start < _count; \
+       start = end, end = _next_syllable (buffer, start))
+
+static inline unsigned int
+_next_syllable (hb_buffer_t *buffer, unsigned int start)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+
+  unsigned int syllable = info[start].syllable();
+  while (++start < count && syllable == info[start].syllable())
+    ;
+
+  return start;
+}
+
+
 /* unicode_props */
 
-enum {
-  MASK0_ZWJ       = 0x20u,
-  MASK0_ZWNJ      = 0x40u,
-  MASK0_IGNORABLE = 0x80u,
-  MASK0_GEN_CAT   = 0x1Fu
+/* Design:
+ * unicode_props() is a two-byte number.  The low byte includes:
+ * - General_Category: 5 bits.
+ * - A bit each for:
+ *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
+ *   * Is it U+200D ZWJ?
+ *   * Is it U+200C ZWNJ?
+ *
+ * The high-byte has different meanings, switched by the Gen-Cat:
+ * - For Mn,Mc,Me: the modified Combining_Class.
+ * - For Ws: index of which space character this is, if space fallback
+ *   is needed, ie. we don't set this by default, only if asked to.
+ *
+ * If needed, we can use the ZWJ/ZWNJ to use the high byte as well,
+ * freeing two more bits.
+ */
+
+enum hb_unicode_props_flags_t {
+  UPROPS_MASK_ZWJ       = 0x20u,
+  UPROPS_MASK_ZWNJ      = 0x40u,
+  UPROPS_MASK_IGNORABLE = 0x80u,
+  UPROPS_MASK_GEN_CAT   = 0x1Fu
 };
+HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
 
 static inline void
-_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
+_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
 {
-  /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
-  info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
-			   (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
-			   (info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
-			   (info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
-  info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
+  hb_unicode_funcs_t *unicode = buffer->unicode;
+  unsigned int u = info->codepoint;
+  unsigned int gen_cat = (unsigned int) unicode->general_category (u);
+  unsigned int props = gen_cat;
+
+  if (u >= 0x80)
+  {
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
+    if (unlikely (unicode->is_default_ignorable (u)))
+    {
+      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
+      props |=  UPROPS_MASK_IGNORABLE;
+      if (u == 0x200Cu) props |= UPROPS_MASK_ZWNJ;
+      if (u == 0x200Du) props |= UPROPS_MASK_ZWJ;
+    }
+    else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
+    {
+      /* The above check is just an optimization to let in only things we need further
+       * processing on. */
+
+      /* Only Mn and Mc can have non-zero ccc:
+       * http://www.unicode.org/policies/stability_policy.html#Property_Value
+       * """
+       * Canonical_Combining_Class, General_Category
+       * All characters other than those with General_Category property values
+       * Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class
+       * property value 0.
+       * 1.1.5+
+       * """
+       *
+       * Also, all Mn's that are Default_Ignorable, have ccc=0, hence
+       * the "else if".
+       */
+      props |= unicode->modified_combining_class (info->codepoint)<<8;
+
+      /* 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
+       */
+      if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
+      {
+	props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
+      }
+    }
+  }
+
+  info->unicode_props() = props;
 }
 
 static inline void
 _hb_glyph_info_set_general_category (hb_glyph_info_t *info,
 				     hb_unicode_general_category_t gen_cat)
 {
-  info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
+  /* Clears top-byte. */
+  info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
 }
 
 static inline hb_unicode_general_category_t
 _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
 {
-  return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
+  return (hb_unicode_general_category_t) (info->unicode_props() & UPROPS_MASK_GEN_CAT);
 }
 
+static inline bool
+_hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
+{
+  return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
+}
 static inline void
 _hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
 					     unsigned int modified_class)
 {
-  info->unicode_props1() = modified_class;
+  if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
+    return;
+  info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
 }
-
 static inline unsigned int
 _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
 {
-  return info->unicode_props1();
+  return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
 }
 
+static inline bool
+_hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_get_general_category (info) ==
+	 HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
+}
+static inline void
+_hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
+{
+  if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
+    return;
+  info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
+}
+static inline hb_unicode_funcs_t::space_t
+_hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_is_unicode_space (info) ?
+	 (hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
+	 hb_unicode_funcs_t::NOT_SPACE;
+}
+
+static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
+
 static inline hb_bool_t
 _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
 {
-  return !!(info->unicode_props0() & MASK0_IGNORABLE);
+  return (info->unicode_props() & UPROPS_MASK_IGNORABLE) && !_hb_glyph_info_ligated (info);
 }
 
 static inline hb_bool_t
 _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
 {
-  return !!(info->unicode_props0() & MASK0_ZWNJ);
+  return !!(info->unicode_props() & UPROPS_MASK_ZWNJ);
 }
 
 static inline hb_bool_t
 _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
 {
-  return !!(info->unicode_props0() & MASK0_ZWJ);
+  return !!(info->unicode_props() & UPROPS_MASK_ZWJ);
+}
+
+static inline hb_bool_t
+_hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props() & (UPROPS_MASK_ZWNJ | UPROPS_MASK_ZWJ));
 }
 
 static inline void
 _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
 {
-  info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
+  info->unicode_props() ^= UPROPS_MASK_ZWNJ | UPROPS_MASK_ZWJ;
 }
 
 /* lig_props: aka lig_id / lig_comp
@@ -401,28 +534,31 @@
 			   HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
 }
 
+static inline void
+_hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
+{
+  info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+}
+
 
 /* Allocation / deallocation. */
 
 static inline void
 _hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
 {
-  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
-  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
+  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
 }
 
 static inline void
 _hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
 {
-  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
-  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
 }
 
 static inline void
 _hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
 {
-  HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
-  HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
+  HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
 }
 
 static inline void
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 602b94e..adf232b 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -28,6 +28,7 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb-open-type-private.hh"
 #include "hb-ot-layout-private.hh"
 
 #include "hb-ot-layout-gdef-table.hh"
@@ -128,6 +129,11 @@
   return _get_gdef (face).has_glyph_classes ();
 }
 
+/**
+ * hb_ot_layout_get_glyph_class:
+ *
+ * Since: 0.9.7
+ **/
 hb_ot_layout_glyph_class_t
 hb_ot_layout_get_glyph_class (hb_face_t      *face,
 			      hb_codepoint_t  glyph)
@@ -135,6 +141,11 @@
   return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
 }
 
+/**
+ * hb_ot_layout_get_glyphs_in_class:
+ *
+ * Since: 0.9.7
+ **/
 void
 hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
 				  hb_ot_layout_glyph_class_t  klass,
@@ -285,6 +296,28 @@
   return g.get_feature_tags (start_offset, feature_count, feature_tags);
 }
 
+hb_bool_t
+hb_ot_layout_table_find_feature (hb_face_t    *face,
+				 hb_tag_t      table_tag,
+				 hb_tag_t      feature_tag,
+				 unsigned int *feature_index)
+{
+  ASSERT_STATIC (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 ();
+  for (unsigned int i = 0; i < num_features; i++)
+  {
+    if (feature_tag == g.get_feature_tag (i)) {
+      if (feature_index) *feature_index = i;
+      return true;
+    }
+  }
+
+  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
+  return false;
+}
+
 
 unsigned int
 hb_ot_layout_script_get_language_tags (hb_face_t    *face,
@@ -335,6 +368,11 @@
 						     NULL);
 }
 
+/**
+ * hb_ot_layout_language_get_required_feature:
+ *
+ * Since: 0.9.30
+ **/
 hb_bool_t
 hb_ot_layout_language_get_required_feature (hb_face_t    *face,
 					    hb_tag_t      table_tag,
@@ -419,6 +457,11 @@
   return false;
 }
 
+/**
+ * hb_ot_layout_feature_get_lookups:
+ *
+ * Since: 0.9.7
+ **/
 unsigned int
 hb_ot_layout_feature_get_lookups (hb_face_t    *face,
 				  hb_tag_t      table_tag,
@@ -433,6 +476,11 @@
   return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
 }
 
+/**
+ * hb_ot_layout_table_get_lookup_count:
+ *
+ * Since: 0.9.22
+ **/
 unsigned int
 hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
 				     hb_tag_t      table_tag)
@@ -590,6 +638,11 @@
   }
 }
 
+/**
+ * hb_ot_layout_collect_lookups:
+ *
+ * Since: 0.9.8
+ **/
 void
 hb_ot_layout_collect_lookups (hb_face_t      *face,
 			      hb_tag_t        table_tag,
@@ -631,6 +684,11 @@
   }
 }
 
+/**
+ * hb_ot_layout_lookup_collect_glyphs:
+ *
+ * Since: 0.9.7
+ **/
 void
 hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
 				    hb_tag_t      table_tag,
@@ -676,6 +734,11 @@
   return &_get_gsub (face) != &OT::Null(OT::GSUB);
 }
 
+/**
+ * hb_ot_layout_lookup_would_substitute:
+ *
+ * Since: 0.9.7
+ **/
 hb_bool_t
 hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
 				      unsigned int          lookup_index,
@@ -695,11 +758,11 @@
 					   hb_bool_t             zero_context)
 {
   if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
-  OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
+  OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
 
   const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
 
-  return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest);
+  return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
 }
 
 void
@@ -708,12 +771,11 @@
   OT::GSUB::substitute_start (font, buffer);
 }
 
-void
-hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
-{
-  OT::GSUB::substitute_finish (font, buffer);
-}
-
+/**
+ * hb_ot_layout_lookup_substitute_closure:
+ *
+ * Since: 0.9.7
+ **/
 void
 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 				        unsigned int  lookup_index,
@@ -743,11 +805,22 @@
 }
 
 void
-hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
+hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
 {
-  OT::GPOS::position_finish (font, buffer);
+  OT::GPOS::position_finish_advances (font, buffer);
 }
 
+void
+hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
+{
+  OT::GPOS::position_finish_offsets (font, buffer);
+}
+
+/**
+ * hb_ot_layout_get_size_params:
+ *
+ * Since: 0.9.10
+ **/
 hb_bool_t
 hb_ot_layout_get_size_params (hb_face_t    *face,
 			      unsigned int *design_size,       /* OUT.  May be NULL */
@@ -829,28 +902,130 @@
 };
 
 
-template <typename Lookup>
-static inline bool apply_once (OT::hb_apply_context_t *c,
-			       const Lookup &lookup)
+struct hb_get_subtables_context_t :
+       OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
 {
-  if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
-    return false;
-  return lookup.dispatch (c);
+  template <typename Type>
+  static inline bool apply_to (const void *obj, OT::hb_apply_context_t *c)
+  {
+    const Type *typed_obj = (const Type *) obj;
+    return typed_obj->apply (c);
+  }
+
+  typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_apply_context_t *c);
+
+  struct hb_applicable_t
+  {
+    inline void init (const void *obj_, hb_apply_func_t apply_func_)
+    {
+      obj = obj_;
+      apply_func = apply_func_;
+    }
+
+    inline bool apply (OT::hb_apply_context_t *c) const { return apply_func (obj, c); }
+
+    private:
+    const void *obj;
+    hb_apply_func_t apply_func;
+  };
+
+  typedef hb_auto_array_t<hb_applicable_t> array_t;
+
+  /* Dispatch interface. */
+  inline const char *get_name (void) { return "GET_SUBTABLES"; }
+  template <typename T>
+  inline return_t dispatch (const T &obj)
+  {
+    hb_applicable_t *entry = array.push();
+    if (likely (entry))
+      entry->init (&obj, apply_to<T>);
+    return HB_VOID;
+  }
+  static return_t default_return_value (void) { return HB_VOID; }
+  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+
+  hb_get_subtables_context_t (array_t &array_) :
+			      array (array_),
+			      debug_depth (0) {}
+
+  array_t &array;
+  unsigned int debug_depth;
+};
+
+static inline bool
+apply_forward (OT::hb_apply_context_t *c,
+	       const hb_ot_layout_lookup_accelerator_t &accel,
+	       const hb_get_subtables_context_t::array_t &subtables)
+{
+  bool ret = false;
+  hb_buffer_t *buffer = c->buffer;
+  while (buffer->idx < buffer->len && !buffer->in_error)
+  {
+    bool applied = false;
+    if (accel.may_have (buffer->cur().codepoint) &&
+	(buffer->cur().mask & c->lookup_mask) &&
+	c->check_glyph_property (&buffer->cur(), c->lookup_props))
+     {
+       for (unsigned int i = 0; i < subtables.len; i++)
+         if (subtables[i].apply (c))
+	 {
+	   applied = true;
+	   break;
+	 }
+     }
+
+    if (applied)
+      ret = true;
+    else
+      buffer->next_glyph ();
+  }
+  return ret;
+}
+
+static inline bool
+apply_backward (OT::hb_apply_context_t *c,
+	       const hb_ot_layout_lookup_accelerator_t &accel,
+	       const hb_get_subtables_context_t::array_t &subtables)
+{
+  bool ret = false;
+  hb_buffer_t *buffer = c->buffer;
+  do
+  {
+    if (accel.may_have (buffer->cur().codepoint) &&
+	(buffer->cur().mask & c->lookup_mask) &&
+	c->check_glyph_property (&buffer->cur(), c->lookup_props))
+    {
+     for (unsigned int i = 0; i < subtables.len; i++)
+       if (subtables[i].apply (c))
+       {
+	 ret = true;
+	 break;
+       }
+    }
+    /* The reverse lookup doesn't "advance" cursor (for good reason). */
+    buffer->idx--;
+
+  }
+  while ((int) buffer->idx >= 0);
+  return ret;
 }
 
 template <typename Proxy>
-static inline bool
+static inline void
 apply_string (OT::hb_apply_context_t *c,
 	      const typename Proxy::Lookup &lookup,
 	      const hb_ot_layout_lookup_accelerator_t &accel)
 {
-  bool ret = false;
   hb_buffer_t *buffer = c->buffer;
 
   if (unlikely (!buffer->len || !c->lookup_mask))
-    return false;
+    return;
 
-  c->set_lookup (lookup);
+  c->set_lookup_props (lookup.get_props ());
+
+  hb_get_subtables_context_t::array_t subtables;
+  hb_get_subtables_context_t c_get_subtables (subtables);
+  lookup.dispatch (&c_get_subtables);
 
   if (likely (!lookup.is_reverse ()))
   {
@@ -859,21 +1034,14 @@
       buffer->clear_output ();
     buffer->idx = 0;
 
-    while (buffer->idx < buffer->len)
-    {
-      if (accel.digest.may_have (buffer->cur().codepoint) &&
-	  (buffer->cur().mask & c->lookup_mask) &&
-	  apply_once (c, lookup))
-	ret = true;
-      else
-	buffer->next_glyph ();
-    }
+    bool ret;
+    ret = apply_forward (c, accel, subtables);
     if (ret)
     {
       if (!Proxy::inplace)
 	buffer->swap_buffers ();
       else
-        assert (!buffer->has_separate_output ());
+	assert (!buffer->has_separate_output ());
     }
   }
   else
@@ -882,20 +1050,9 @@
     if (Proxy::table_index == 0)
       buffer->remove_output ();
     buffer->idx = buffer->len - 1;
-    do
-    {
-      if (accel.digest.may_have (buffer->cur().codepoint) &&
-	  (buffer->cur().mask & c->lookup_mask) &&
-	  apply_once (c, lookup))
-	ret = true;
-      /* The reverse lookup doesn't "advance" cursor (for good reason). */
-      buffer->idx--;
 
-    }
-    while ((int) buffer->idx >= 0);
+    apply_backward (c, accel, subtables);
   }
-
-  return ret;
 }
 
 template <typename Proxy>
@@ -914,11 +1071,14 @@
     for (; i < stage->last_lookup; i++)
     {
       unsigned int lookup_index = lookups[table_index][i].index;
+      if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
+      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);
       apply_string<Proxy> (&c,
 			   proxy.table.get_lookup (lookup_index),
 			   proxy.accels[lookup_index]);
+      (void) buffer->message (font, "end lookup %d", lookup_index);
     }
 
     if (stage->pause_func)
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index 949678a..eb23d45 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -48,7 +48,7 @@
  * GDEF
  */
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face);
 
 typedef enum {
@@ -59,11 +59,11 @@
   HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT	= 4
 } hb_ot_layout_glyph_class_t;
 
-hb_ot_layout_glyph_class_t
+HB_EXTERN hb_ot_layout_glyph_class_t
 hb_ot_layout_get_glyph_class (hb_face_t      *face,
 			      hb_codepoint_t  glyph);
 
-void
+HB_EXTERN void
 hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
 				  hb_ot_layout_glyph_class_t  klass,
 				  hb_set_t                   *glyphs /* OUT */);
@@ -71,7 +71,7 @@
 
 /* Not that useful.  Provides list of attach points for a glyph that a
  * client may want to cache */
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
 				hb_codepoint_t  glyph,
 				unsigned int    start_offset,
@@ -79,7 +79,7 @@
 				unsigned int   *point_array /* OUT */);
 
 /* Ligature caret positions */
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_layout_get_ligature_carets (hb_font_t      *font,
 				  hb_direction_t  direction,
 				  hb_codepoint_t  glyph,
@@ -96,35 +96,35 @@
 #define HB_OT_LAYOUT_NO_FEATURE_INDEX		0xFFFFu
 #define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX	0xFFFFu
 
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_layout_table_get_script_tags (hb_face_t    *face,
 				    hb_tag_t      table_tag,
 				    unsigned int  start_offset,
 				    unsigned int *script_count /* IN/OUT */,
 				    hb_tag_t     *script_tags /* OUT */);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_table_find_script (hb_face_t    *face,
 				hb_tag_t      table_tag,
 				hb_tag_t      script_tag,
 				unsigned int *script_index);
 
 /* Like find_script, but takes zero-terminated array of scripts to test */
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_table_choose_script (hb_face_t      *face,
 				  hb_tag_t        table_tag,
 				  const hb_tag_t *script_tags,
 				  unsigned int   *script_index,
 				  hb_tag_t       *chosen_script);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
 				     hb_tag_t      table_tag,
 				     unsigned int  start_offset,
 				     unsigned int *feature_count /* IN/OUT */,
 				     hb_tag_t     *feature_tags /* OUT */);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_layout_script_get_language_tags (hb_face_t    *face,
 				       hb_tag_t      table_tag,
 				       unsigned int  script_index,
@@ -132,21 +132,21 @@
 				       unsigned int *language_count /* IN/OUT */,
 				       hb_tag_t     *language_tags /* OUT */);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_script_find_language (hb_face_t    *face,
 				   hb_tag_t      table_tag,
 				   unsigned int  script_index,
 				   hb_tag_t      language_tag,
 				   unsigned int *language_index);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
 						  hb_tag_t      table_tag,
 						  unsigned int  script_index,
 						  unsigned int  language_index,
 						  unsigned int *feature_index);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_language_get_required_feature (hb_face_t    *face,
 					    hb_tag_t      table_tag,
 					    unsigned int  script_index,
@@ -154,7 +154,7 @@
 					    unsigned int *feature_index,
 					    hb_tag_t     *feature_tag);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
 					   hb_tag_t      table_tag,
 					   unsigned int  script_index,
@@ -163,7 +163,7 @@
 					   unsigned int *feature_count /* IN/OUT */,
 					   unsigned int *feature_indexes /* OUT */);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
 					hb_tag_t      table_tag,
 					unsigned int  script_index,
@@ -172,7 +172,7 @@
 					unsigned int *feature_count /* IN/OUT */,
 					hb_tag_t     *feature_tags /* OUT */);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_language_find_feature (hb_face_t    *face,
 				    hb_tag_t      table_tag,
 				    unsigned int  script_index,
@@ -180,7 +180,7 @@
 				    hb_tag_t      feature_tag,
 				    unsigned int *feature_index);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_layout_feature_get_lookups (hb_face_t    *face,
 				  hb_tag_t      table_tag,
 				  unsigned int  feature_index,
@@ -188,12 +188,12 @@
 				  unsigned int *lookup_count /* IN/OUT */,
 				  unsigned int *lookup_indexes /* OUT */);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
 				     hb_tag_t      table_tag);
 
 
-void
+HB_EXTERN void
 hb_ot_layout_collect_lookups (hb_face_t      *face,
 			      hb_tag_t        table_tag,
 			      const hb_tag_t *scripts,
@@ -201,7 +201,7 @@
 			      const hb_tag_t *features,
 			      hb_set_t       *lookup_indexes /* OUT */);
 
-void
+HB_EXTERN void
 hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
 				    hb_tag_t      table_tag,
 				    unsigned int  lookup_index,
@@ -228,7 +228,7 @@
 				       const hb_ot_layout_glyph_sequence_t *sequence,
 				       void         *user_data);
 
-void
+HB_EXTERN void
 Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t    *face,
 					 hb_tag_t      table_tag,
 					 unsigned int  lookup_index,
@@ -241,17 +241,17 @@
  * GSUB
  */
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
 				      unsigned int          lookup_index,
 				      const hb_codepoint_t *glyphs,
 				      unsigned int          glyphs_length,
 				      hb_bool_t             zero_context);
 
-void
+HB_EXTERN void
 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 				        unsigned int  lookup_index,
 				        hb_set_t     *glyphs
@@ -259,7 +259,7 @@
 
 #ifdef HB_NOT_IMPLEMENTED
 /* Note: You better have GDEF when using this API, or marks won't do much. */
-hb_bool_t
+HB_EXTERN hb_bool_t
 Xhb_ot_layout_lookup_substitute (hb_font_t            *font,
 				unsigned int          lookup_index,
 				const hb_ot_layout_glyph_sequence_t *sequence,
@@ -274,12 +274,12 @@
  * GPOS
  */
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face);
 
 #ifdef HB_NOT_IMPLEMENTED
 /* Note: You better have GDEF when using this API, or marks won't do much. */
-hb_bool_t
+HB_EXTERN hb_bool_t
 Xhb_ot_layout_lookup_position (hb_font_t            *font,
 			      unsigned int          lookup_index,
 			      const hb_ot_layout_glyph_sequence_t *sequence,
@@ -288,7 +288,7 @@
 
 /* Optical 'size' feature info.  Returns true if found.
  * http://www.microsoft.com/typography/otspec/features_pt.htm#size */
-hb_bool_t
+HB_EXTERN 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 */
diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 86b7e9f..8692caa 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -154,27 +154,14 @@
 
 enum hb_ot_map_feature_flags_t {
   F_NONE		= 0x0000u,
-  F_GLOBAL		= 0x0001u,
-  F_HAS_FALLBACK	= 0x0002u,
-  F_MANUAL_ZWJ		= 0x0004u
+  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. */
 };
+HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
 /* Macro version for where const is desired. */
 #define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
-static inline hb_ot_map_feature_flags_t
-operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
-{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
-static inline hb_ot_map_feature_flags_t
-operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
-{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
-static inline hb_ot_map_feature_flags_t
-operator ~ (hb_ot_map_feature_flags_t r)
-{ return hb_ot_map_feature_flags_t (~(unsigned int) r); }
-static inline hb_ot_map_feature_flags_t&
-operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
-{ l = l | r; return l; }
-static inline hb_ot_map_feature_flags_t&
-operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
-{ l = l & r; return l; }
 
 
 struct hb_ot_map_builder_t
@@ -216,7 +203,8 @@
     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 : 1); }
+    { 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 4985eb2..7bdeddb 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -89,7 +89,7 @@
 
   for (unsigned int table_index = 0; table_index < 2; table_index++) {
     hb_tag_t table_tag = table_tags[table_index];
-    found_script[table_index] = hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
+    found_script[table_index] = (bool) hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
     hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
   }
 }
@@ -216,6 +216,16 @@
 						   info->tag,
 						   &feature_index[table_index]);
     }
+    if (!found && (info->flags & F_GLOBAL_SEARCH))
+    {
+      for (unsigned int table_index = 0; table_index < 2; table_index++)
+      {
+	found |= hb_ot_layout_table_find_feature (face,
+						  table_tags[table_index],
+						  info->tag,
+						  &feature_index[table_index]);
+      }
+    }
     if (!found && !(info->flags & F_HAS_FALLBACK))
       continue;
 
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index b1f8328..943e390 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -43,19 +43,22 @@
 {
   static const hb_tag_t tableTag	= HB_OT_TAG_maxp;
 
-  inline unsigned int get_num_glyphs (void) const {
+  inline unsigned int get_num_glyphs (void) const
+  {
     return numGlyphs;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) &&
-			 likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000u)));
+    return_trace (c->check_struct (this) &&
+		  likely (version.major == 1 ||
+			  (version.major == 0 && version.minor == 0x5000u)));
   }
 
   /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
   protected:
-  FixedVersion	version;		/* Version of the maxp table (0.5 or 1.0),
+  FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000u or 0x00010000u. */
   USHORT	numGlyphs;		/* The number of glyphs in the font. */
   public:
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 31d9fac..870f123 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -56,10 +56,11 @@
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
     TRACE_SANITIZE (this);
     /* We can check from base all the way up to the end of string... */
-    return TRACE_RETURN (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
+    return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
   }
 
   USHORT	platformID;	/* Platform ID. */
@@ -101,21 +102,22 @@
   inline unsigned int get_size (void) const
   { return min_size + count * nameRecord[0].min_size; }
 
-  inline bool sanitize_records (hb_sanitize_context_t *c) {
+  inline bool sanitize_records (hb_sanitize_context_t *c) const {
     TRACE_SANITIZE (this);
     char *string_pool = (char *) this + stringOffset;
     unsigned int _count = count;
     for (unsigned int i = 0; i < _count; i++)
-      if (!nameRecord[i].sanitize (c, string_pool)) return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
+      if (!nameRecord[i].sanitize (c, string_pool)) return_trace (false);
+    return_trace (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
     TRACE_SANITIZE (this);
-    return TRACE_RETURN (c->check_struct (this) &&
-			 likely (format == 0 || format == 1) &&
-			 c->check_array (nameRecord, nameRecord[0].static_size, count) &&
-			 sanitize_records (c));
+    return_trace (c->check_struct (this) &&
+		  likely (format == 0 || format == 1) &&
+		  c->check_array (nameRecord, nameRecord[0].static_size, count) &&
+		  sanitize_records (c));
   }
 
   /* We only implement format 0 for now. */
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
new file mode 100644
index 0000000..4709cd6
--- /dev/null
+++ b/src/hb-ot-os2-table.hh
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2011,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_OT_OS2_TABLE_HH
+#define HB_OT_OS2_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+/*
+ * OS/2 and Windows Metrics
+ * http://www.microsoft.com/typography/otspec/os2.htm
+ */
+
+#define HB_OT_TAG_os2 HB_TAG('O','S','/','2')
+
+struct os2
+{
+  static const hb_tag_t tableTag = HB_OT_TAG_os2;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  public:
+  USHORT	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];
+  Tag		achVendID;
+  USHORT	fsSelection;
+  USHORT	usFirstCharIndex;
+  USHORT	usLastCharIndex;
+  SHORT		sTypoAscender;
+  SHORT		sTypoDescender;
+  SHORT		sTypoLineGap;
+  USHORT	usWinAscent;
+  USHORT	usWinDescent;
+
+  /* Version 1 */
+  //ULONG ulCodePageRange1;
+  //ULONG ulCodePageRange2;
+
+  /* Version 2 */
+  //SHORT sxHeight;
+  //SHORT sCapHeight;
+  //USHORT  usDefaultChar;
+  //USHORT  usBreakChar;
+  //USHORT  usMaxContext;
+
+  /* Version 5 */
+  //USHORT  usLowerOpticalPointSize;
+  //USHORT  usUpperOpticalPointSize;
+
+  public:
+  DEFINE_SIZE_STATIC (78);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_OS2_TABLE_HH */
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index a77f24e..d97d285 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -75,9 +75,9 @@
   if (!num_glyphs)
     return NULL;
 
-  /* Bubble-sort!
+  /* Bubble-sort or something equally good!
    * May not be good-enough for presidential candidate interviews, but good-enough for us... */
-  hb_bubble_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
+  hb_stable_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
 
   OT::Supplier<OT::GlyphID> glyphs_supplier      (glyphs, num_glyphs);
   OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
@@ -126,7 +126,7 @@
     first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
     num_first_glyphs++;
   }
-  hb_bubble_sort (&first_glyphs[0], num_first_glyphs, OT::GlyphID::cmp, &first_glyphs_indirection[0]);
+  hb_stable_sort (&first_glyphs[0], num_first_glyphs, 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++)
diff --git a/src/hb-ot-shape-complex-arabic-private.hh b/src/hb-ot-shape-complex-arabic-private.hh
new file mode 100644
index 0000000..fcedc7d
--- /dev/null
+++ b/src/hb-ot-shape-complex-arabic-private.hh
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
+#define HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+struct arabic_shape_plan_t;
+
+HB_INTERNAL void *
+data_create_arabic (const hb_ot_shape_plan_t *plan);
+
+HB_INTERNAL void
+data_destroy_arabic (void *data);
+
+HB_INTERNAL void
+setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
+			 hb_buffer_t               *buffer,
+			 hb_script_t                script);
+
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH */
diff --git a/src/hb-ot-shape-complex-arabic-table.hh b/src/hb-ot-shape-complex-arabic-table.hh
index 1710049..80d5044 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-7.0.0.txt
- * # Date: 2014-02-14, 21:00:00 GMT [RP, KW, LI]
- * # Blocks-7.0.0.txt
- * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
+ * # ArabicShaping-8.0.0.txt
+ * # Date: 2015-02-17, 23:33:00 GMT [RP]
+ * # Blocks-8.0.0.txt
+ * # Date: 2014-11-10, 23:04:00 GMT [KW]
  * UnicodeData.txt does not have a header.
  */
 
@@ -76,9 +76,9 @@
 
   /* Arabic Extended-A */
 
-  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,
+  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,
 
-#define joining_offset_0x1806u 691
+#define joining_offset_0x1806u 693
 
   /* Mongolian */
 
@@ -89,40 +89,40 @@
   /* 1880 */ U,U,U,U,U,U,U,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,
   /* 18A0 */ D,D,D,D,D,D,D,D,D,X,D,
 
-#define joining_offset_0x200cu 856
+#define joining_offset_0x200cu 858
 
   /* General Punctuation */
 
   /* 2000 */                         U,C,
 
-#define joining_offset_0x2066u 858
+#define joining_offset_0x2066u 860
 
   /* General Punctuation */
 
   /* 2060 */             U,U,U,U,
 
-#define joining_offset_0xa840u 862
+#define joining_offset_0xa840u 864
 
   /* Phags-pa */
 
   /* A840 */ 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,
   /* A860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,L,U,
 
-#define joining_offset_0x10ac0u 914
+#define joining_offset_0x10ac0u 916
 
   /* Manichaean */
 
   /* 10AC0 */ D,D,D,D,D,R,U,R,U,R,R,U,U,L,R,R,R,R,R,D,D,D,D,L,D,D,D,D,D,R,D,D,
   /* 10AE0 */ D,R,U,U,R,X,X,X,X,X,X,D,D,D,D,R,
 
-#define joining_offset_0x10b80u 962
+#define joining_offset_0x10b80u 964
 
   /* Psalter Pahlavi */
 
   /* 10B80 */ D,R,D,R,R,R,D,D,D,R,D,D,R,D,R,R,D,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
   /* 10BA0 */ X,X,X,X,X,X,X,X,X,R,R,R,R,D,D,U,
 
-}; /* Table items: 1010; occupancy: 57% */
+}; /* Table items: 1012; occupancy: 57% */
 
 
 static unsigned int
@@ -131,7 +131,7 @@
   switch (u >> 12)
   {
     case 0x0u:
-      if (hb_in_range (u, 0x0600u, 0x08B2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
+      if (hb_in_range (u, 0x0600u, 0x08B4u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
       break;
 
     case 0x1u:
diff --git a/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shape-complex-arabic-win1256.hh
index 3a20b50..e70c48f 100644
--- a/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -133,7 +133,6 @@
  */
 
 #define OT_LOOKUP_TYPE_SUBST_SINGLE	1u
-#define OT_LOOKUP_TYPE_SUBST_MULTIPLE	2u
 #define OT_LOOKUP_TYPE_SUBST_LIGATURE	4u
 
 #define OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(Name, FromGlyphs, ToGlyphs) \
@@ -143,7 +142,7 @@
 		OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
 	) \
 	OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
-	/* ASSERT_STATIC_EXPR len(FromGlyphs) == len(ToGlyphs) */
+	/* ASSERT_STATIC_EXPR_ZERO (len(FromGlyphs) == len(ToGlyphs)) */
 
 #define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
 	OT_SUBLOOKUP(Name, 1, \
@@ -152,7 +151,7 @@
 		OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
 	) \
 	OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
-	/* ASSERT_STATIC_EXPR len(FirstGlyphs) == len(LigatureSetOffsets) */
+	/* ASSERT_STATIC_EXPR_ZERO (len(FirstGlyphs) == len(LigatureSetOffsets)) */
 
 #define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
 	OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index ae90864..4da8990 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -24,18 +24,51 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-ot-shape-complex-private.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 */
+#define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
+	(FLAG_SAFE (gen_cat) & \
+	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
+	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
+	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |*/ \
+	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |*/ \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL)))
+
+
+/*
+ * Joining types:
+ */
 
 /*
  * Bits used in the joining tables
  */
-enum {
+enum hb_arabic_joining_type_t {
   JOINING_TYPE_U		= 0,
   JOINING_TYPE_L		= 1,
   JOINING_TYPE_R		= 2,
@@ -49,10 +82,6 @@
   JOINING_TYPE_X = 8  /* means: use general-category to choose between U or T. */
 };
 
-/*
- * Joining types:
- */
-
 #include "hb-ot-shape-complex-arabic-table.hh"
 
 static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
@@ -61,7 +90,7 @@
   if (likely (j_type != JOINING_TYPE_X))
     return j_type;
 
-  return (FLAG(gen_cat) &
+  return (FLAG_SAFE(gen_cat) &
 	  (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
 	   FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
 	   FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
@@ -84,7 +113,7 @@
 
 
 /* Same order as the feature array */
-enum {
+enum arabic_action_t {
   ISOL,
   FINA,
   FIN2,
@@ -95,7 +124,11 @@
 
   NONE,
 
-  ARABIC_NUM_FEATURES = NONE
+  ARABIC_NUM_FEATURES = NONE,
+
+  /* We abuse the same byte for other things... */
+  STCH_FIXED,
+  STCH_REPEATING,
 };
 
 static const struct arabic_state_table_entry {
@@ -140,6 +173,11 @@
 		       hb_buffer_t *buffer);
 
 static void
+record_stch (const hb_ot_shape_plan_t *plan,
+	     hb_font_t *font,
+	     hb_buffer_t *buffer);
+
+static void
 collect_features_arabic (hb_ot_shape_planner_t *plan)
 {
   hb_ot_map_builder_t *map = &plan->map;
@@ -165,6 +203,9 @@
 
   map->add_gsub_pause (nuke_joiners);
 
+  map->add_global_bool_feature (HB_TAG('s','t','c','h'));
+  map->add_gsub_pause (record_stch);
+
   map->add_global_bool_feature (HB_TAG('c','c','m','p'));
   map->add_global_bool_feature (HB_TAG('l','o','c','l'));
 
@@ -182,7 +223,6 @@
     map->add_gsub_pause (arabic_fallback_shape);
 
   map->add_global_bool_feature (HB_TAG('c','a','l','t'));
-  map->add_gsub_pause (NULL);
 
   /* The spec includes 'cswh'.  Earlier versions of Windows
    * used to enable this by default, but testing suggests
@@ -192,6 +232,7 @@
    * 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'));
 }
@@ -208,11 +249,13 @@
    * mask_array[NONE] == 0. */
   hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
 
-  bool do_fallback;
   arabic_fallback_plan_t *fallback_plan;
+
+  unsigned int do_fallback : 1;
+  unsigned int has_stch : 1;
 };
 
-static void *
+void *
 data_create_arabic (const hb_ot_shape_plan_t *plan)
 {
   arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
@@ -220,6 +263,7 @@
     return NULL;
 
   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'));
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
     arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
     arabic_plan->do_fallback = arabic_plan->do_fallback &&
@@ -230,7 +274,7 @@
   return arabic_plan;
 }
 
-static void
+void
 data_destroy_arabic (void *data)
 {
   arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
@@ -305,25 +349,30 @@
       info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
 }
 
-static void
-setup_masks_arabic (const hb_ot_shape_plan_t *plan,
-		    hb_buffer_t              *buffer,
-		    hb_font_t                *font HB_UNUSED)
+void
+setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
+			 hb_buffer_t               *buffer,
+			 hb_script_t                script)
 {
   HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
 
-  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
-
   arabic_joining (buffer);
-  if (plan->props.script == HB_SCRIPT_MONGOLIAN)
+  if (script == HB_SCRIPT_MONGOLIAN)
     mongolian_variation_selectors (buffer);
 
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
     info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
+}
 
-  HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
+static void
+setup_masks_arabic (const hb_ot_shape_plan_t *plan,
+		    hb_buffer_t              *buffer,
+		    hb_font_t                *font HB_UNUSED)
+{
+  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+  setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script);
 }
 
 
@@ -364,6 +413,197 @@
   arabic_fallback_plan_shape (fallback_plan, font, buffer);
 }
 
+/*
+ * Stretch feature: "stch".
+ * See example here:
+ * https://www.microsoft.com/typography/OpenTypeDev/syriac/intro.htm
+ * We implement this in a generic way, such that the Arabic subtending
+ * marks can use it as well.
+ */
+
+static void
+record_stch (const hb_ot_shape_plan_t *plan,
+	     hb_font_t *font,
+	     hb_buffer_t *buffer)
+{
+  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+  if (!arabic_plan->has_stch)
+    return;
+
+  /* 'stch' feature was just applied.  Look for anything that multiplied,
+   * and record it for stch treatment later.  Note that rtlm, frac, etc
+   * are applied before stch, but we assume that they didn't result in
+   * anything multiplying into 5 pieces, so it's safe-ish... */
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if (unlikely (_hb_glyph_info_multiplied (&info[i])))
+    {
+      unsigned int comp = _hb_glyph_info_get_lig_comp (&info[i]);
+      info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
+      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
+    }
+}
+
+static void
+apply_stch (const hb_ot_shape_plan_t *plan,
+	    hb_buffer_t              *buffer,
+	    hb_font_t                *font)
+{
+  if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
+    return;
+
+  /* The Arabic shaper currently always processes in RTL mode, so we should
+   * stretch / position the stretched pieces to the left / preceding glyphs. */
+
+  /* We do a two pass implementation:
+   * First pass calculates the exact number of extra glyphs we need,
+   * We then enlarge buffer to have that much room,
+   * Second pass applies the stretch, copying things to the end of buffer.
+   */
+
+  int sign = font->x_scale < 0 ? -1 : +1;
+  unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT
+  typedef enum { MEASURE, CUT } step_t;
+
+  for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1))
+  {
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    hb_glyph_position_t *pos = buffer->pos;
+    unsigned int new_len = count + extra_glyphs_needed; // write head during CUT
+    unsigned int j = new_len;
+    for (unsigned int i = count; i; i--)
+    {
+      if (!hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+      {
+        if (step == CUT)
+	{
+	  --j;
+	  info[j] = info[i - 1];
+	  pos[j] = pos[i - 1];
+	}
+        continue;
+      }
+
+      /* Yay, justification! */
+
+      hb_position_t w_total = 0; // Total to be filled
+      hb_position_t w_fixed = 0; // Sum of fixed tiles
+      hb_position_t w_repeating = 0; // Sum of repeating tiles
+      int n_fixed = 0;
+      int n_repeating = 0;
+
+      unsigned int end = i;
+      while (i &&
+	     hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+      {
+	i--;
+	hb_position_t width = font->get_glyph_h_advance (info[i].codepoint);
+	if (info[i].arabic_shaping_action() == STCH_FIXED)
+	{
+	  w_fixed += width;
+	  n_fixed++;
+	}
+	else
+	{
+	  w_repeating += width;
+	  n_repeating++;
+	}
+      }
+      unsigned int start = i;
+      unsigned int context = i;
+      while (context &&
+	     !hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
+	     (_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
+	      HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
+      {
+	context--;
+	w_total += pos[context].x_advance;
+      }
+      i++; // Don't touch i again.
+
+      DEBUG_MSG (ARABIC, NULL, "%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);
+
+      /* Number of additional times to repeat each repeating tile. */
+      int n_copies = 0;
+
+      hb_position_t w_remaining = w_total - w_fixed;
+      if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0)
+	n_copies = (sign * w_remaining) / (sign * w_repeating) - 1;
+
+      /* 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)
+      {
+        ++n_copies;
+        hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
+        if (excess > 0)
+          extra_repeat_overlap = excess / (n_copies * n_repeating);
+      }
+
+      if (step == MEASURE)
+      {
+	extra_glyphs_needed += n_copies * n_repeating;
+	DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
+      }
+      else
+      {
+	hb_position_t x_offset = 0;
+	for (unsigned int k = end; k > start; k--)
+	{
+	  hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
+
+	  unsigned int repeat = 1;
+	  if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
+	    repeat += n_copies;
+
+	  DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
+		     repeat, info[k - 1].codepoint, j);
+	  for (unsigned int n = 0; n < repeat; n++)
+	  {
+	    x_offset -= width;
+	    if (n > 0)
+	      x_offset += extra_repeat_overlap;
+	    pos[k - 1].x_offset = x_offset;
+	    /* Append copy. */
+	    --j;
+	    info[j] = info[k - 1];
+	    pos[j] = pos[k - 1];
+	  }
+	}
+      }
+    }
+
+    if (step == MEASURE)
+    {
+      if (unlikely (!buffer->ensure (count + extra_glyphs_needed)))
+        break;
+    }
+    else
+    {
+      assert (j == 0);
+      buffer->len = new_len;
+    }
+  }
+}
+
+
+static void
+postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
+			   hb_buffer_t              *buffer,
+			   hb_font_t                *font)
+{
+  apply_stch (plan, buffer, font);
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
+}
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
 {
@@ -372,7 +612,8 @@
   NULL, /* override_features */
   data_create_arabic,
   data_destroy_arabic,
-  NULL, /* preprocess_text_arabic */
+  NULL, /* preprocess_text */
+  postprocess_glyphs_arabic,
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
diff --git a/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shape-complex-default.cc
index f7f097e..be60e56 100644
--- a/src/hb-ot-shape-complex-default.cc
+++ b/src/hb-ot-shape-complex-default.cc
@@ -35,10 +35,11 @@
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
   NULL, /* setup_masks */
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+  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 6ac18b0..5f4d98b 100644
--- a/src/hb-ot-shape-complex-hangul.cc
+++ b/src/hb-ot-shape-complex-hangul.cc
@@ -188,7 +188,7 @@
 				    */
   unsigned int count = buffer->len;
 
-  for (buffer->idx = 0; buffer->idx < count;)
+  for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
   {
     hb_codepoint_t u = buffer->cur().codepoint;
 
@@ -205,17 +205,12 @@
 	buffer->next_glyph ();
 	if (!is_zero_width_char (font, u))
 	{
+	  buffer->merge_out_clusters (start, end + 1);
 	  hb_glyph_info_t *info = buffer->out_info;
 	  hb_glyph_info_t tone = info[end];
 	  memmove (&info[start + 1], &info[start], (end - start) * sizeof (hb_glyph_info_t));
 	  info[start] = tone;
 	}
-	/* Merge clusters across the (possibly reordered) syllable+tone.
-	 * We want to merge even in the zero-width tone mark case here,
-	 * so that clustering behavior isn't dependent on how the tone mark
-	 * is handled by the font.
-	 */
-	buffer->merge_out_clusters (start, end + 1);
       }
       else
       {
@@ -296,7 +291,8 @@
 	}
 	else
 	  end = start + 2;
-	buffer->merge_out_clusters (start, end);
+	if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+	  buffer->merge_out_clusters (start, end);
 	continue;
       }
     }
@@ -368,7 +364,8 @@
 	  info[i++].hangul_shaping_feature() = VJMO;
 	  if (i < end)
 	    info[i++].hangul_shaping_feature() = TJMO;
-	  buffer->merge_out_clusters (start, end);
+	  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+	    buffer->merge_out_clusters (start, end);
 	  continue;
 	}
       }
@@ -414,13 +411,14 @@
   "hangul",
   collect_features_hangul,
   override_features_hangul,
-  data_create_hangul, /* data_create */
-  data_destroy_hangul, /* data_destroy */
+  data_create_hangul,
+  data_destroy_hangul,
   preprocess_text_hangul,
+  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   NULL, /* decompose */
   NULL, /* compose */
-  setup_masks_hangul, /* setup_masks */
+  setup_masks_hangul,
   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 c7b7a5e..3215900 100644
--- a/src/hb-ot-shape-complex-hebrew.cc
+++ b/src/hb-ot-shape-complex-hebrew.cc
@@ -68,7 +68,7 @@
     0xFB4Au /* TAV */
   };
 
-  bool found = c->unicode->compose (a, b, ab);
+  bool found = (bool) c->unicode->compose (a, b, ab);
 
   if (!found && !c->plan->has_mark)
   {
@@ -163,6 +163,7 @@
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   compose_hebrew,
diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh
index 5fbdcc8..f652d4f 100644
--- a/src/hb-ot-shape-complex-indic-machine.hh
+++ b/src/hb-ot-shape-complex-indic-machine.hh
@@ -1,5 +1,5 @@
 
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 1 "hb-ot-shape-complex-indic-machine.rl"
 /*
  * Copyright © 2011,2012  Google, Inc.
  *
@@ -32,1281 +32,1304 @@
 #include "hb-private.hh"
 
 
-#line 36 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 36 "hb-ot-shape-complex-indic-machine.hh"
 static const unsigned char _indic_syllable_machine_trans_keys[] = {
-	1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 
-	5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u, 
-	16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 
-	6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 
-	4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 
-	7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 
-	5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 
-	4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 
+	8u, 8u, 1u, 16u, 8u, 13u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 
+	7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 
+	6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 
+	4u, 8u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 
+	4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 8u, 8u, 1u, 16u, 8u, 13u, 
+	5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 
+	7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 
+	6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 
 	4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 
-	1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 
-	5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u, 
-	16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 
-	6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 
-	4u, 14u, 4u, 14u, 4u, 14u, 1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u, 
-	5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 
-	7u, 7u, 4u, 4u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 
-	6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 
-	4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 
-	4u, 14u, 5u, 7u, 5u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 
-	7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 1u, 16u, 13u, 13u, 4u, 4u, 6u, 6u, 
-	16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 
-	6u, 6u, 16u, 16u, 1u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 
+	4u, 14u, 4u, 14u, 8u, 8u, 1u, 16u, 8u, 13u, 5u, 8u, 5u, 7u, 7u, 7u, 
+	5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 
+	7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 
+	6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 
+	4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 8u, 8u, 1u, 16u, 
+	8u, 13u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 
+	5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 
+	4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 
+	16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 
+	4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 5u, 8u, 4u, 14u, 4u, 14u, 5u, 8u, 
+	5u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 
+	5u, 7u, 7u, 7u, 8u, 8u, 1u, 16u, 8u, 13u, 4u, 8u, 6u, 6u, 16u, 16u, 
+	4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 
+	16u, 16u, 8u, 8u, 1u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 
 	3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 
-	3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 8u, 14u, 
+	3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u, 
 	5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 
-	3u, 10u, 8u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
+	3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
 	3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 
-	6u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u, 
+	5u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 3u, 31u, 3u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 
 	3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 
-	3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 8u, 14u, 
+	3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u, 
 	5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 
-	3u, 10u, 8u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
+	3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
 	3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 
-	6u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u, 
+	5u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	4u, 14u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 
 	4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 
-	4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 8u, 14u, 5u, 10u, 
+	4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u, 5u, 10u, 
 	9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 3u, 10u, 
-	8u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 
-	4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u, 
+	5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 
+	4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
 	3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	4u, 14u, 3u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 
 	3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 
-	3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 8u, 14u, 
+	3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u, 
 	5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 
-	3u, 10u, 8u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
+	3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
 	3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 
-	6u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u, 
+	5u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 
-	1u, 16u, 3u, 31u, 1u, 31u, 3u, 31u, 1u, 31u, 4u, 14u, 1u, 16u, 3u, 31u, 
-	3u, 31u, 4u, 31u, 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 
-	5u, 10u, 3u, 31u, 3u, 31u, 1u, 16u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 
-	4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 8u, 14u, 
-	3u, 13u, 3u, 10u, 8u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 3u, 10u, 8u, 10u, 
+	1u, 16u, 3u, 31u, 1u, 31u, 3u, 31u, 1u, 31u, 4u, 14u, 5u, 10u, 9u, 10u, 
+	9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 1u, 16u, 3u, 31u, 3u, 31u, 
+	4u, 31u, 3u, 31u, 3u, 31u, 1u, 16u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 
+	4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
+	3u, 13u, 3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 3u, 10u, 5u, 10u, 
 	5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 0
 };
 
 static const char _indic_syllable_machine_key_spans[] = {
-	16, 1, 3, 3, 1, 3, 3, 1, 
-	3, 3, 1, 3, 3, 1, 1, 1, 
-	1, 4, 1, 1, 4, 1, 1, 4, 
-	1, 1, 11, 11, 11, 11, 11, 11, 
-	11, 11, 11, 11, 16, 1, 3, 3, 
-	1, 3, 3, 1, 3, 3, 1, 3, 
-	3, 1, 1, 1, 1, 4, 1, 1, 
-	4, 1, 1, 4, 1, 1, 11, 11, 
+	1, 16, 6, 4, 3, 1, 4, 3, 
+	1, 4, 3, 1, 4, 3, 1, 5, 
+	1, 1, 5, 1, 1, 5, 1, 1, 
+	5, 1, 1, 11, 11, 11, 11, 11, 
+	11, 11, 11, 11, 11, 1, 16, 6, 
+	4, 3, 1, 4, 3, 1, 4, 3, 
+	1, 4, 3, 1, 5, 1, 1, 5, 
+	1, 1, 5, 1, 1, 5, 1, 1, 
 	11, 11, 11, 11, 11, 11, 11, 11, 
-	16, 1, 3, 3, 1, 3, 3, 1, 
-	3, 3, 1, 3, 3, 1, 1, 1, 
-	1, 4, 1, 1, 4, 1, 1, 4, 
-	1, 1, 11, 11, 11, 11, 11, 11, 
-	11, 11, 11, 16, 1, 3, 3, 1, 
-	3, 3, 1, 3, 3, 1, 3, 3, 
-	1, 1, 1, 1, 4, 1, 1, 4, 
-	1, 1, 4, 1, 1, 11, 11, 11, 
-	11, 11, 11, 11, 11, 11, 11, 11, 
-	11, 3, 3, 3, 3, 1, 3, 3, 
-	1, 3, 3, 1, 16, 1, 1, 1, 
-	1, 4, 1, 1, 4, 1, 1, 4, 
+	11, 11, 1, 16, 6, 4, 3, 1, 
+	4, 3, 1, 4, 3, 1, 4, 3, 
+	1, 5, 1, 1, 5, 1, 1, 5, 
+	1, 1, 5, 1, 1, 11, 11, 11, 
+	11, 11, 11, 11, 11, 11, 1, 16, 
+	6, 4, 3, 1, 4, 3, 1, 4, 
+	3, 1, 4, 3, 1, 5, 1, 1, 
+	5, 1, 1, 5, 1, 1, 5, 1, 
+	1, 11, 11, 11, 11, 11, 11, 11, 
+	11, 11, 11, 11, 4, 11, 11, 4, 
+	3, 4, 3, 1, 4, 3, 1, 4, 
+	3, 1, 1, 16, 6, 5, 1, 1, 
+	5, 1, 1, 5, 1, 1, 5, 1, 
 	1, 1, 31, 29, 29, 28, 16, 29, 
 	29, 28, 16, 29, 29, 28, 16, 29, 
-	29, 28, 16, 29, 29, 28, 10, 7, 
+	29, 28, 16, 29, 29, 28, 10, 10, 
 	6, 2, 1, 2, 2, 1, 6, 11, 
-	8, 3, 8, 11, 12, 12, 11, 10, 
+	8, 6, 8, 11, 12, 12, 11, 10, 
 	12, 11, 10, 12, 11, 10, 12, 11, 
-	9, 12, 16, 28, 11, 29, 29, 16, 
+	10, 12, 16, 28, 11, 29, 29, 16, 
 	16, 16, 16, 16, 29, 29, 16, 16, 
 	16, 16, 16, 29, 29, 16, 16, 16, 
 	16, 16, 29, 29, 16, 16, 16, 16, 
 	16, 29, 29, 29, 29, 28, 16, 29, 
 	29, 28, 16, 29, 29, 28, 16, 29, 
-	29, 28, 16, 29, 29, 28, 10, 7, 
+	29, 28, 16, 29, 29, 28, 10, 10, 
 	6, 2, 1, 2, 2, 1, 6, 11, 
-	8, 3, 8, 11, 12, 12, 11, 10, 
+	8, 6, 8, 11, 12, 12, 11, 10, 
 	12, 11, 10, 12, 11, 10, 12, 11, 
-	9, 12, 16, 28, 11, 29, 29, 16, 
+	10, 12, 16, 28, 11, 29, 29, 16, 
 	16, 16, 16, 16, 29, 29, 16, 16, 
 	16, 16, 16, 29, 29, 16, 16, 16, 
 	16, 16, 29, 29, 16, 16, 16, 16, 
 	11, 16, 29, 29, 28, 16, 29, 29, 
 	28, 16, 29, 29, 28, 16, 29, 29, 
-	28, 16, 29, 29, 28, 10, 7, 6, 
+	28, 16, 29, 29, 28, 10, 10, 6, 
 	2, 1, 2, 2, 1, 6, 11, 8, 
-	3, 8, 11, 12, 12, 11, 10, 12, 
-	11, 10, 12, 11, 10, 12, 11, 9, 
+	6, 8, 11, 12, 12, 11, 10, 12, 
+	11, 10, 12, 11, 10, 12, 11, 10, 
 	12, 16, 28, 11, 29, 29, 16, 16, 
 	16, 16, 16, 29, 29, 16, 16, 16, 
 	16, 16, 29, 29, 16, 16, 16, 16, 
 	16, 29, 29, 16, 16, 16, 16, 16, 
 	11, 29, 11, 29, 29, 28, 16, 29, 
 	29, 28, 16, 29, 29, 28, 16, 29, 
-	29, 28, 16, 29, 29, 28, 10, 7, 
+	29, 28, 16, 29, 29, 28, 10, 10, 
 	6, 2, 1, 2, 2, 1, 6, 11, 
-	8, 3, 8, 11, 12, 12, 11, 10, 
+	8, 6, 8, 11, 12, 12, 11, 10, 
 	12, 11, 10, 12, 11, 10, 12, 11, 
-	9, 12, 16, 28, 11, 29, 29, 16, 
+	10, 12, 16, 28, 11, 29, 29, 16, 
 	16, 16, 16, 16, 29, 29, 16, 16, 
 	16, 16, 16, 29, 29, 16, 16, 16, 
 	16, 16, 29, 29, 16, 16, 16, 16, 
-	16, 29, 31, 29, 31, 11, 16, 29, 
-	29, 28, 6, 2, 1, 2, 2, 1, 
-	6, 29, 29, 16, 12, 11, 10, 12, 
-	11, 10, 12, 11, 10, 12, 11, 7, 
-	11, 8, 3, 8, 11, 16, 8, 3, 
+	16, 29, 31, 29, 31, 11, 6, 2, 
+	1, 2, 2, 1, 6, 16, 29, 29, 
+	28, 29, 29, 16, 12, 11, 10, 12, 
+	11, 10, 12, 11, 10, 12, 11, 10, 
+	11, 8, 6, 8, 11, 16, 8, 6, 
 	6, 2, 1, 2, 2, 1, 6
 };
 
 static const short _indic_syllable_machine_index_offsets[] = {
-	0, 17, 19, 23, 27, 29, 33, 37, 
-	39, 43, 47, 49, 53, 57, 59, 61, 
-	63, 65, 70, 72, 74, 79, 81, 83, 
-	88, 90, 92, 104, 116, 128, 140, 152, 
-	164, 176, 188, 200, 212, 229, 231, 235, 
-	239, 241, 245, 249, 251, 255, 259, 261, 
-	265, 269, 271, 273, 275, 277, 282, 284, 
-	286, 291, 293, 295, 300, 302, 304, 316, 
-	328, 340, 352, 364, 376, 388, 400, 412, 
-	424, 441, 443, 447, 451, 453, 457, 461, 
-	463, 467, 471, 473, 477, 481, 483, 485, 
-	487, 489, 494, 496, 498, 503, 505, 507, 
-	512, 514, 516, 528, 540, 552, 564, 576, 
-	588, 600, 612, 624, 641, 643, 647, 651, 
-	653, 657, 661, 663, 667, 671, 673, 677, 
-	681, 683, 685, 687, 689, 694, 696, 698, 
-	703, 705, 707, 712, 714, 716, 728, 740, 
-	752, 764, 776, 788, 800, 812, 824, 836, 
-	848, 860, 864, 868, 872, 876, 878, 882, 
-	886, 888, 892, 896, 898, 915, 917, 919, 
-	921, 923, 928, 930, 932, 937, 939, 941, 
-	946, 948, 950, 982, 1012, 1042, 1071, 1088, 
-	1118, 1148, 1177, 1194, 1224, 1254, 1283, 1300, 
-	1330, 1360, 1389, 1406, 1436, 1466, 1495, 1506, 
-	1514, 1521, 1524, 1526, 1529, 1532, 1534, 1541, 
-	1553, 1562, 1566, 1575, 1587, 1600, 1613, 1625, 
-	1636, 1649, 1661, 1672, 1685, 1697, 1708, 1721, 
-	1733, 1743, 1756, 1773, 1802, 1814, 1844, 1874, 
-	1891, 1908, 1925, 1942, 1959, 1989, 2019, 2036, 
-	2053, 2070, 2087, 2104, 2134, 2164, 2181, 2198, 
-	2215, 2232, 2249, 2279, 2309, 2326, 2343, 2360, 
-	2377, 2394, 2424, 2454, 2484, 2514, 2543, 2560, 
-	2590, 2620, 2649, 2666, 2696, 2726, 2755, 2772, 
-	2802, 2832, 2861, 2878, 2908, 2938, 2967, 2978, 
-	2986, 2993, 2996, 2998, 3001, 3004, 3006, 3013, 
-	3025, 3034, 3038, 3047, 3059, 3072, 3085, 3097, 
-	3108, 3121, 3133, 3144, 3157, 3169, 3180, 3193, 
-	3205, 3215, 3228, 3245, 3274, 3286, 3316, 3346, 
-	3363, 3380, 3397, 3414, 3431, 3461, 3491, 3508, 
-	3525, 3542, 3559, 3576, 3606, 3636, 3653, 3670, 
-	3687, 3704, 3721, 3751, 3781, 3798, 3815, 3832, 
-	3849, 3861, 3878, 3908, 3938, 3967, 3984, 4014, 
-	4044, 4073, 4090, 4120, 4150, 4179, 4196, 4226, 
-	4256, 4285, 4302, 4332, 4362, 4391, 4402, 4410, 
-	4417, 4420, 4422, 4425, 4428, 4430, 4437, 4449, 
-	4458, 4462, 4471, 4483, 4496, 4509, 4521, 4532, 
-	4545, 4557, 4568, 4581, 4593, 4604, 4617, 4629, 
-	4639, 4652, 4669, 4698, 4710, 4740, 4770, 4787, 
-	4804, 4821, 4838, 4855, 4885, 4915, 4932, 4949, 
-	4966, 4983, 5000, 5030, 5060, 5077, 5094, 5111, 
-	5128, 5145, 5175, 5205, 5222, 5239, 5256, 5273, 
-	5290, 5302, 5332, 5344, 5374, 5404, 5433, 5450, 
-	5480, 5510, 5539, 5556, 5586, 5616, 5645, 5662, 
-	5692, 5722, 5751, 5768, 5798, 5828, 5857, 5868, 
-	5876, 5883, 5886, 5888, 5891, 5894, 5896, 5903, 
-	5915, 5924, 5928, 5937, 5949, 5962, 5975, 5987, 
-	5998, 6011, 6023, 6034, 6047, 6059, 6070, 6083, 
-	6095, 6105, 6118, 6135, 6164, 6176, 6206, 6236, 
-	6253, 6270, 6287, 6304, 6321, 6351, 6381, 6398, 
-	6415, 6432, 6449, 6466, 6496, 6526, 6543, 6560, 
-	6577, 6594, 6611, 6641, 6671, 6688, 6705, 6722, 
-	6739, 6756, 6786, 6818, 6848, 6880, 6892, 6909, 
-	6939, 6969, 6998, 7005, 7008, 7010, 7013, 7016, 
-	7018, 7025, 7055, 7085, 7102, 7115, 7127, 7138, 
-	7151, 7163, 7174, 7187, 7199, 7210, 7223, 7235, 
-	7243, 7255, 7264, 7268, 7277, 7289, 7306, 7315, 
-	7319, 7326, 7329, 7331, 7334, 7337, 7339
+	0, 2, 19, 26, 31, 35, 37, 42, 
+	46, 48, 53, 57, 59, 64, 68, 70, 
+	76, 78, 80, 86, 88, 90, 96, 98, 
+	100, 106, 108, 110, 122, 134, 146, 158, 
+	170, 182, 194, 206, 218, 230, 232, 249, 
+	256, 261, 265, 267, 272, 276, 278, 283, 
+	287, 289, 294, 298, 300, 306, 308, 310, 
+	316, 318, 320, 326, 328, 330, 336, 338, 
+	340, 352, 364, 376, 388, 400, 412, 424, 
+	436, 448, 460, 462, 479, 486, 491, 495, 
+	497, 502, 506, 508, 513, 517, 519, 524, 
+	528, 530, 536, 538, 540, 546, 548, 550, 
+	556, 558, 560, 566, 568, 570, 582, 594, 
+	606, 618, 630, 642, 654, 666, 678, 680, 
+	697, 704, 709, 713, 715, 720, 724, 726, 
+	731, 735, 737, 742, 746, 748, 754, 756, 
+	758, 764, 766, 768, 774, 776, 778, 784, 
+	786, 788, 800, 812, 824, 836, 848, 860, 
+	872, 884, 896, 908, 920, 925, 937, 949, 
+	954, 958, 963, 967, 969, 974, 978, 980, 
+	985, 989, 991, 993, 1010, 1017, 1023, 1025, 
+	1027, 1033, 1035, 1037, 1043, 1045, 1047, 1053, 
+	1055, 1057, 1059, 1091, 1121, 1151, 1180, 1197, 
+	1227, 1257, 1286, 1303, 1333, 1363, 1392, 1409, 
+	1439, 1469, 1498, 1515, 1545, 1575, 1604, 1615, 
+	1626, 1633, 1636, 1638, 1641, 1644, 1646, 1653, 
+	1665, 1674, 1681, 1690, 1702, 1715, 1728, 1740, 
+	1751, 1764, 1776, 1787, 1800, 1812, 1823, 1836, 
+	1848, 1859, 1872, 1889, 1918, 1930, 1960, 1990, 
+	2007, 2024, 2041, 2058, 2075, 2105, 2135, 2152, 
+	2169, 2186, 2203, 2220, 2250, 2280, 2297, 2314, 
+	2331, 2348, 2365, 2395, 2425, 2442, 2459, 2476, 
+	2493, 2510, 2540, 2570, 2600, 2630, 2659, 2676, 
+	2706, 2736, 2765, 2782, 2812, 2842, 2871, 2888, 
+	2918, 2948, 2977, 2994, 3024, 3054, 3083, 3094, 
+	3105, 3112, 3115, 3117, 3120, 3123, 3125, 3132, 
+	3144, 3153, 3160, 3169, 3181, 3194, 3207, 3219, 
+	3230, 3243, 3255, 3266, 3279, 3291, 3302, 3315, 
+	3327, 3338, 3351, 3368, 3397, 3409, 3439, 3469, 
+	3486, 3503, 3520, 3537, 3554, 3584, 3614, 3631, 
+	3648, 3665, 3682, 3699, 3729, 3759, 3776, 3793, 
+	3810, 3827, 3844, 3874, 3904, 3921, 3938, 3955, 
+	3972, 3984, 4001, 4031, 4061, 4090, 4107, 4137, 
+	4167, 4196, 4213, 4243, 4273, 4302, 4319, 4349, 
+	4379, 4408, 4425, 4455, 4485, 4514, 4525, 4536, 
+	4543, 4546, 4548, 4551, 4554, 4556, 4563, 4575, 
+	4584, 4591, 4600, 4612, 4625, 4638, 4650, 4661, 
+	4674, 4686, 4697, 4710, 4722, 4733, 4746, 4758, 
+	4769, 4782, 4799, 4828, 4840, 4870, 4900, 4917, 
+	4934, 4951, 4968, 4985, 5015, 5045, 5062, 5079, 
+	5096, 5113, 5130, 5160, 5190, 5207, 5224, 5241, 
+	5258, 5275, 5305, 5335, 5352, 5369, 5386, 5403, 
+	5420, 5432, 5462, 5474, 5504, 5534, 5563, 5580, 
+	5610, 5640, 5669, 5686, 5716, 5746, 5775, 5792, 
+	5822, 5852, 5881, 5898, 5928, 5958, 5987, 5998, 
+	6009, 6016, 6019, 6021, 6024, 6027, 6029, 6036, 
+	6048, 6057, 6064, 6073, 6085, 6098, 6111, 6123, 
+	6134, 6147, 6159, 6170, 6183, 6195, 6206, 6219, 
+	6231, 6242, 6255, 6272, 6301, 6313, 6343, 6373, 
+	6390, 6407, 6424, 6441, 6458, 6488, 6518, 6535, 
+	6552, 6569, 6586, 6603, 6633, 6663, 6680, 6697, 
+	6714, 6731, 6748, 6778, 6808, 6825, 6842, 6859, 
+	6876, 6893, 6923, 6955, 6985, 7017, 7029, 7036, 
+	7039, 7041, 7044, 7047, 7049, 7056, 7073, 7103, 
+	7133, 7162, 7192, 7222, 7239, 7252, 7264, 7275, 
+	7288, 7300, 7311, 7324, 7336, 7347, 7360, 7372, 
+	7383, 7395, 7404, 7411, 7420, 7432, 7449, 7458, 
+	7465, 7472, 7475, 7477, 7480, 7483, 7485
 };
 
 static const short _indic_syllable_machine_indicies[] = {
-	1, 2, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 1, 
-	0, 3, 0, 4, 4, 5, 0, 6, 
-	6, 5, 0, 5, 0, 7, 7, 8, 
-	0, 9, 9, 8, 0, 8, 0, 10, 
-	10, 11, 0, 12, 12, 11, 0, 11, 
-	0, 13, 13, 14, 0, 15, 15, 14, 
-	0, 14, 0, 16, 0, 17, 0, 18, 
-	0, 19, 13, 13, 14, 0, 20, 0, 
-	21, 0, 22, 10, 10, 11, 0, 23, 
-	0, 24, 0, 25, 7, 7, 8, 0, 
-	26, 0, 27, 0, 28, 4, 4, 5, 
-	0, 0, 0, 0, 0, 0, 28, 0, 
-	28, 4, 4, 5, 0, 0, 0, 0, 
-	0, 29, 28, 0, 30, 4, 4, 5, 
-	0, 0, 0, 0, 0, 0, 30, 0, 
-	30, 4, 4, 5, 0, 0, 0, 0, 
-	0, 31, 30, 0, 32, 4, 4, 5, 
-	0, 0, 0, 0, 0, 0, 32, 0, 
-	32, 4, 4, 5, 0, 0, 0, 0, 
-	0, 33, 32, 0, 34, 4, 4, 5, 
-	0, 0, 0, 0, 0, 0, 34, 0, 
-	34, 4, 4, 5, 0, 0, 0, 0, 
-	0, 35, 34, 0, 36, 4, 4, 5, 
-	0, 0, 0, 0, 0, 0, 36, 0, 
-	36, 4, 4, 5, 0, 0, 0, 0, 
-	0, 37, 36, 0, 39, 40, 38, 38, 
-	38, 38, 38, 38, 38, 38, 38, 38, 
-	38, 38, 38, 39, 38, 41, 38, 42, 
-	42, 43, 38, 44, 44, 43, 38, 43, 
-	38, 45, 45, 46, 38, 47, 47, 46, 
-	38, 46, 38, 48, 48, 49, 38, 50, 
-	50, 49, 38, 49, 38, 51, 51, 52, 
-	38, 53, 53, 52, 38, 52, 38, 54, 
-	38, 55, 38, 56, 38, 57, 51, 51, 
-	52, 38, 58, 38, 59, 38, 60, 48, 
-	48, 49, 38, 61, 38, 62, 38, 63, 
-	45, 45, 46, 38, 64, 38, 65, 38, 
-	66, 42, 42, 43, 38, 38, 38, 38, 
-	38, 38, 66, 38, 66, 42, 42, 43, 
-	38, 38, 38, 38, 38, 67, 66, 38, 
-	68, 42, 42, 43, 38, 38, 38, 38, 
-	38, 38, 68, 38, 68, 42, 42, 43, 
-	38, 38, 38, 38, 38, 69, 68, 38, 
-	70, 42, 42, 43, 38, 38, 38, 38, 
-	38, 38, 70, 38, 70, 42, 42, 43, 
-	38, 38, 38, 38, 38, 71, 70, 38, 
-	72, 42, 42, 43, 38, 38, 38, 38, 
-	38, 38, 72, 38, 72, 42, 42, 43, 
-	38, 38, 38, 38, 38, 73, 72, 38, 
-	74, 42, 42, 43, 38, 38, 38, 38, 
-	38, 38, 74, 38, 74, 42, 42, 43, 
-	38, 38, 38, 38, 38, 75, 74, 38, 
-	77, 78, 76, 76, 76, 76, 76, 76, 
-	76, 76, 76, 76, 76, 76, 76, 77, 
-	76, 79, 76, 80, 80, 81, 76, 83, 
-	83, 81, 82, 81, 82, 84, 84, 85, 
-	76, 86, 86, 85, 76, 85, 76, 87, 
-	87, 88, 76, 89, 89, 88, 76, 88, 
-	76, 90, 90, 91, 76, 92, 92, 91, 
-	76, 91, 76, 93, 76, 94, 76, 95, 
-	76, 96, 90, 90, 91, 76, 97, 76, 
-	98, 76, 99, 87, 87, 88, 76, 100, 
-	76, 101, 76, 102, 84, 84, 85, 76, 
-	103, 76, 104, 76, 105, 80, 80, 81, 
-	76, 76, 76, 76, 76, 76, 105, 76, 
-	105, 80, 80, 81, 76, 76, 76, 76, 
-	76, 106, 105, 76, 107, 80, 80, 81, 
-	76, 76, 76, 76, 76, 76, 107, 76, 
-	107, 80, 80, 81, 76, 76, 76, 76, 
-	76, 108, 107, 76, 109, 80, 80, 81, 
-	76, 76, 76, 76, 76, 76, 109, 76, 
-	109, 80, 80, 81, 76, 76, 76, 76, 
-	76, 110, 109, 76, 111, 80, 80, 81, 
-	82, 82, 82, 82, 82, 82, 111, 82, 
-	111, 80, 80, 81, 76, 76, 76, 76, 
-	76, 112, 111, 76, 113, 80, 80, 81, 
-	76, 76, 76, 76, 76, 76, 113, 76, 
-	115, 116, 114, 114, 114, 114, 114, 114, 
-	114, 114, 114, 114, 114, 114, 114, 115, 
-	114, 117, 114, 118, 118, 119, 114, 120, 
-	120, 119, 114, 119, 114, 121, 121, 122, 
-	114, 123, 123, 122, 114, 122, 114, 124, 
-	124, 125, 114, 126, 126, 125, 114, 125, 
-	114, 127, 127, 128, 114, 129, 129, 128, 
-	114, 128, 114, 130, 114, 131, 114, 132, 
-	114, 133, 127, 127, 128, 114, 134, 114, 
-	135, 114, 136, 124, 124, 125, 114, 137, 
-	114, 138, 114, 139, 121, 121, 122, 114, 
-	140, 114, 141, 114, 142, 118, 118, 119, 
-	114, 114, 114, 114, 114, 114, 142, 114, 
-	142, 118, 118, 119, 114, 114, 114, 114, 
-	114, 143, 142, 114, 144, 118, 118, 119, 
-	114, 114, 114, 114, 114, 114, 144, 114, 
-	144, 118, 118, 119, 114, 114, 114, 114, 
-	114, 145, 144, 114, 146, 118, 118, 119, 
-	114, 114, 114, 114, 114, 114, 146, 114, 
-	146, 118, 118, 119, 114, 114, 114, 114, 
-	114, 147, 146, 114, 148, 118, 118, 119, 
-	114, 114, 114, 114, 114, 114, 148, 114, 
-	148, 118, 118, 119, 114, 114, 114, 114, 
-	114, 149, 148, 114, 150, 118, 118, 119, 
-	114, 114, 114, 114, 114, 114, 150, 114, 
-	150, 118, 118, 119, 114, 114, 114, 114, 
-	114, 151, 150, 114, 113, 80, 80, 81, 
-	76, 76, 76, 76, 76, 152, 113, 76, 
-	111, 80, 80, 81, 0, 0, 0, 0, 
-	0, 153, 111, 0, 154, 154, 155, 0, 
-	6, 6, 155, 0, 156, 156, 157, 0, 
-	158, 158, 157, 0, 157, 0, 159, 159, 
-	160, 0, 161, 161, 160, 0, 160, 0, 
-	162, 162, 163, 0, 164, 164, 163, 0, 
-	163, 0, 165, 166, 0, 0, 0, 0, 
+	1, 0, 2, 3, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 165, 0, 167, 0, 168, 0, 169, 
-	0, 170, 0, 171, 162, 162, 163, 0, 
-	172, 0, 173, 0, 174, 159, 159, 160, 
-	0, 175, 0, 176, 0, 177, 156, 156, 
-	157, 0, 178, 0, 179, 0, 181, 182, 
-	183, 184, 185, 186, 81, 187, 188, 189, 
-	190, 190, 152, 191, 192, 193, 194, 195, 
-	180, 180, 180, 180, 180, 180, 180, 180, 
-	180, 180, 180, 180, 196, 180, 198, 199, 
-	200, 201, 5, 202, 203, 204, 197, 197, 
-	37, 205, 197, 197, 206, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 207, 197, 208, 199, 209, 209, 
-	5, 202, 203, 204, 197, 197, 197, 205, 
-	197, 197, 206, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	207, 197, 199, 209, 209, 5, 202, 203, 
-	204, 197, 197, 197, 205, 197, 197, 206, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 207, 197, 210, 
-	197, 197, 197, 18, 211, 197, 202, 203, 
-	204, 197, 197, 197, 212, 197, 210, 197, 
-	213, 214, 215, 216, 5, 202, 203, 204, 
-	197, 197, 35, 217, 197, 197, 206, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 207, 197, 218, 214, 
-	219, 219, 5, 202, 203, 204, 197, 197, 
-	197, 217, 197, 197, 206, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 207, 197, 214, 219, 219, 5, 
-	202, 203, 204, 197, 197, 197, 217, 197, 
-	197, 206, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 207, 
-	197, 220, 197, 197, 197, 18, 221, 197, 
-	202, 203, 204, 197, 197, 197, 212, 197, 
-	220, 197, 222, 223, 224, 225, 5, 202, 
-	203, 204, 197, 197, 33, 226, 197, 197, 
-	206, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 207, 197, 
-	227, 223, 228, 228, 5, 202, 203, 204, 
-	197, 197, 197, 226, 197, 197, 206, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 207, 197, 223, 228, 
-	228, 5, 202, 203, 204, 197, 197, 197, 
-	226, 197, 197, 206, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 207, 197, 229, 197, 197, 197, 18, 
-	230, 197, 202, 203, 204, 197, 197, 197, 
-	212, 197, 229, 197, 231, 232, 233, 234, 
-	5, 202, 203, 204, 197, 197, 31, 235, 
-	197, 197, 206, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	207, 197, 236, 232, 237, 237, 5, 202, 
-	203, 204, 197, 197, 197, 235, 197, 197, 
-	206, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 207, 197, 
-	232, 237, 237, 5, 202, 203, 204, 197, 
-	197, 197, 235, 197, 197, 206, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 207, 197, 238, 197, 197, 
-	197, 18, 239, 197, 202, 203, 204, 197, 
-	197, 197, 212, 197, 238, 197, 240, 241, 
-	242, 243, 5, 202, 203, 204, 197, 197, 
-	29, 244, 197, 197, 206, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 207, 197, 245, 241, 246, 246, 
-	5, 202, 203, 204, 197, 197, 197, 244, 
-	197, 197, 206, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	207, 197, 241, 246, 246, 5, 202, 203, 
-	204, 197, 197, 197, 244, 197, 197, 206, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 207, 197, 18, 
-	247, 197, 202, 203, 204, 197, 197, 197, 
-	212, 197, 202, 203, 204, 197, 197, 197, 
-	212, 197, 248, 197, 197, 249, 203, 204, 
-	197, 203, 204, 197, 250, 197, 203, 251, 
-	197, 203, 252, 197, 203, 197, 248, 197, 
-	197, 197, 203, 204, 197, 253, 197, 254, 
-	255, 197, 202, 203, 204, 197, 197, 3, 
-	197, 2, 197, 197, 197, 197, 202, 203, 
-	204, 197, 202, 203, 204, 197, 253, 197, 
-	197, 197, 197, 202, 203, 204, 197, 253, 
-	197, 254, 197, 197, 202, 203, 204, 197, 
-	197, 3, 197, 18, 197, 256, 256, 5, 
-	202, 203, 204, 197, 197, 197, 212, 197, 
-	257, 27, 258, 259, 8, 202, 203, 204, 
-	197, 197, 197, 212, 197, 27, 258, 259, 
-	8, 202, 203, 204, 197, 197, 197, 212, 
-	197, 258, 258, 8, 202, 203, 204, 197, 
-	197, 197, 212, 197, 260, 24, 261, 262, 
-	11, 202, 203, 204, 197, 197, 197, 212, 
-	197, 24, 261, 262, 11, 202, 203, 204, 
-	197, 197, 197, 212, 197, 261, 261, 11, 
-	202, 203, 204, 197, 197, 197, 212, 197, 
-	263, 21, 264, 265, 14, 202, 203, 204, 
-	197, 197, 197, 212, 197, 21, 264, 265, 
-	14, 202, 203, 204, 197, 197, 197, 212, 
-	197, 264, 264, 14, 202, 203, 204, 197, 
-	197, 197, 212, 197, 266, 18, 197, 267, 
-	197, 202, 203, 204, 197, 197, 197, 212, 
-	197, 18, 197, 267, 197, 202, 203, 204, 
-	197, 197, 197, 212, 197, 268, 197, 202, 
-	203, 204, 197, 197, 197, 212, 197, 18, 
-	197, 197, 197, 197, 202, 203, 204, 197, 
-	197, 197, 212, 197, 1, 2, 197, 197, 
-	18, 247, 197, 202, 203, 204, 197, 197, 
-	197, 212, 197, 1, 197, 241, 246, 246, 
-	5, 202, 203, 204, 197, 197, 197, 244, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	207, 197, 241, 246, 246, 5, 202, 203, 
-	204, 197, 197, 197, 244, 197, 240, 241, 
-	246, 246, 5, 202, 203, 204, 197, 197, 
-	197, 244, 197, 197, 206, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 207, 197, 240, 241, 242, 246, 
-	5, 202, 203, 204, 197, 197, 29, 244, 
-	197, 197, 206, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	207, 197, 238, 197, 269, 197, 256, 256, 
-	5, 202, 203, 204, 197, 197, 197, 212, 
-	197, 238, 197, 238, 197, 197, 197, 197, 
-	197, 197, 202, 203, 204, 197, 197, 197, 
-	212, 197, 238, 197, 238, 197, 197, 197, 
-	197, 270, 197, 202, 203, 204, 197, 197, 
-	197, 212, 197, 238, 197, 238, 197, 269, 
-	197, 197, 197, 197, 202, 203, 204, 197, 
-	197, 197, 212, 197, 238, 197, 238, 2, 
-	197, 197, 18, 239, 197, 202, 203, 204, 
-	197, 197, 197, 212, 197, 238, 197, 231, 
-	232, 237, 237, 5, 202, 203, 204, 197, 
-	197, 197, 235, 197, 197, 206, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 207, 197, 231, 232, 233, 
-	237, 5, 202, 203, 204, 197, 197, 31, 
-	235, 197, 197, 206, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 207, 197, 229, 197, 271, 197, 256, 
-	256, 5, 202, 203, 204, 197, 197, 197, 
-	212, 197, 229, 197, 229, 197, 197, 197, 
-	197, 197, 197, 202, 203, 204, 197, 197, 
-	197, 212, 197, 229, 197, 229, 197, 197, 
-	197, 197, 272, 197, 202, 203, 204, 197, 
-	197, 197, 212, 197, 229, 197, 229, 197, 
-	271, 197, 197, 197, 197, 202, 203, 204, 
-	197, 197, 197, 212, 197, 229, 197, 229, 
-	2, 197, 197, 18, 230, 197, 202, 203, 
-	204, 197, 197, 197, 212, 197, 229, 197, 
-	222, 223, 228, 228, 5, 202, 203, 204, 
-	197, 197, 197, 226, 197, 197, 206, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 207, 197, 222, 223, 
-	224, 228, 5, 202, 203, 204, 197, 197, 
-	33, 226, 197, 197, 206, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 207, 197, 220, 197, 273, 197, 
-	256, 256, 5, 202, 203, 204, 197, 197, 
-	197, 212, 197, 220, 197, 220, 197, 197, 
-	197, 197, 197, 197, 202, 203, 204, 197, 
-	197, 197, 212, 197, 220, 197, 220, 197, 
-	197, 197, 197, 274, 197, 202, 203, 204, 
-	197, 197, 197, 212, 197, 220, 197, 220, 
-	197, 273, 197, 197, 197, 197, 202, 203, 
-	204, 197, 197, 197, 212, 197, 220, 197, 
-	220, 2, 197, 197, 18, 221, 197, 202, 
-	203, 204, 197, 197, 197, 212, 197, 220, 
-	197, 213, 214, 219, 219, 5, 202, 203, 
-	204, 197, 197, 197, 217, 197, 197, 206, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 207, 197, 213, 
-	214, 215, 219, 5, 202, 203, 204, 197, 
-	197, 35, 217, 197, 197, 206, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 207, 197, 210, 197, 275, 
-	197, 256, 256, 5, 202, 203, 204, 197, 
-	197, 197, 212, 197, 210, 197, 210, 197, 
-	197, 197, 197, 197, 197, 202, 203, 204, 
-	197, 197, 197, 212, 197, 210, 197, 210, 
-	197, 197, 197, 197, 276, 197, 202, 203, 
-	204, 197, 197, 197, 212, 197, 210, 197, 
-	210, 197, 275, 197, 197, 197, 197, 202, 
-	203, 204, 197, 197, 197, 212, 197, 210, 
-	197, 210, 2, 197, 197, 18, 211, 197, 
-	202, 203, 204, 197, 197, 197, 212, 197, 
-	210, 197, 198, 199, 209, 209, 5, 202, 
-	203, 204, 197, 197, 197, 205, 197, 197, 
-	206, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 207, 197, 
-	198, 199, 200, 209, 5, 202, 203, 204, 
-	197, 197, 37, 205, 197, 197, 206, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 207, 197, 278, 279, 
-	280, 281, 43, 282, 283, 284, 277, 277, 
-	75, 285, 277, 277, 286, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 287, 277, 288, 279, 289, 281, 
-	43, 282, 283, 284, 277, 277, 277, 285, 
-	277, 277, 286, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	287, 277, 279, 289, 281, 43, 282, 283, 
-	284, 277, 277, 277, 285, 277, 277, 286, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 287, 277, 290, 
-	277, 277, 277, 56, 291, 277, 282, 283, 
-	284, 277, 277, 277, 292, 277, 290, 277, 
-	293, 294, 295, 296, 43, 282, 283, 284, 
-	277, 277, 73, 297, 277, 277, 286, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 287, 277, 298, 294, 
-	299, 299, 43, 282, 283, 284, 277, 277, 
-	277, 297, 277, 277, 286, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 287, 277, 294, 299, 299, 43, 
-	282, 283, 284, 277, 277, 277, 297, 277, 
-	277, 286, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 287, 
-	277, 300, 277, 277, 277, 56, 301, 277, 
-	282, 283, 284, 277, 277, 277, 292, 277, 
-	300, 277, 302, 303, 304, 305, 43, 282, 
-	283, 284, 277, 277, 71, 306, 277, 277, 
-	286, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 287, 277, 
-	307, 303, 308, 308, 43, 282, 283, 284, 
-	277, 277, 277, 306, 277, 277, 286, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 287, 277, 303, 308, 
-	308, 43, 282, 283, 284, 277, 277, 277, 
-	306, 277, 277, 286, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 287, 277, 309, 277, 277, 277, 56, 
-	310, 277, 282, 283, 284, 277, 277, 277, 
-	292, 277, 309, 277, 311, 312, 313, 314, 
-	43, 282, 283, 284, 277, 277, 69, 315, 
-	277, 277, 286, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	287, 277, 316, 312, 317, 317, 43, 282, 
-	283, 284, 277, 277, 277, 315, 277, 277, 
-	286, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 287, 277, 
-	312, 317, 317, 43, 282, 283, 284, 277, 
-	277, 277, 315, 277, 277, 286, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 287, 277, 318, 277, 277, 
-	277, 56, 319, 277, 282, 283, 284, 277, 
-	277, 277, 292, 277, 318, 277, 320, 321, 
-	322, 323, 43, 282, 283, 284, 277, 277, 
-	67, 324, 277, 277, 286, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 287, 277, 325, 321, 326, 326, 
-	43, 282, 283, 284, 277, 277, 277, 324, 
-	277, 277, 286, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	287, 277, 321, 326, 326, 43, 282, 283, 
-	284, 277, 277, 277, 324, 277, 277, 286, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 287, 277, 56, 
-	327, 277, 282, 283, 284, 277, 277, 277, 
-	292, 277, 282, 283, 284, 277, 277, 277, 
-	292, 277, 328, 277, 277, 329, 283, 284, 
-	277, 283, 284, 277, 330, 277, 283, 331, 
-	277, 283, 332, 277, 283, 277, 328, 277, 
-	277, 277, 283, 284, 277, 333, 277, 334, 
-	335, 277, 282, 283, 284, 277, 277, 41, 
-	277, 40, 277, 277, 277, 277, 282, 283, 
-	284, 277, 282, 283, 284, 277, 333, 277, 
-	277, 277, 277, 282, 283, 284, 277, 333, 
-	277, 334, 277, 277, 282, 283, 284, 277, 
-	277, 41, 277, 56, 277, 336, 336, 43, 
-	282, 283, 284, 277, 277, 277, 292, 277, 
-	337, 65, 338, 339, 46, 282, 283, 284, 
-	277, 277, 277, 292, 277, 65, 338, 339, 
-	46, 282, 283, 284, 277, 277, 277, 292, 
-	277, 338, 338, 46, 282, 283, 284, 277, 
-	277, 277, 292, 277, 340, 62, 341, 342, 
-	49, 282, 283, 284, 277, 277, 277, 292, 
-	277, 62, 341, 342, 49, 282, 283, 284, 
-	277, 277, 277, 292, 277, 341, 341, 49, 
-	282, 283, 284, 277, 277, 277, 292, 277, 
-	343, 59, 344, 345, 52, 282, 283, 284, 
-	277, 277, 277, 292, 277, 59, 344, 345, 
-	52, 282, 283, 284, 277, 277, 277, 292, 
-	277, 344, 344, 52, 282, 283, 284, 277, 
-	277, 277, 292, 277, 346, 56, 277, 347, 
-	277, 282, 283, 284, 277, 277, 277, 292, 
-	277, 56, 277, 347, 277, 282, 283, 284, 
-	277, 277, 277, 292, 277, 348, 277, 282, 
-	283, 284, 277, 277, 277, 292, 277, 56, 
-	277, 277, 277, 277, 282, 283, 284, 277, 
-	277, 277, 292, 277, 39, 40, 277, 277, 
-	56, 327, 277, 282, 283, 284, 277, 277, 
-	277, 292, 277, 39, 277, 321, 326, 326, 
-	43, 282, 283, 284, 277, 277, 277, 324, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	287, 277, 321, 326, 326, 43, 282, 283, 
-	284, 277, 277, 277, 324, 277, 320, 321, 
-	326, 326, 43, 282, 283, 284, 277, 277, 
-	277, 324, 277, 277, 286, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 287, 277, 320, 321, 322, 326, 
-	43, 282, 283, 284, 277, 277, 67, 324, 
-	277, 277, 286, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	287, 277, 318, 277, 349, 277, 336, 336, 
-	43, 282, 283, 284, 277, 277, 277, 292, 
-	277, 318, 277, 318, 277, 277, 277, 277, 
-	277, 277, 282, 283, 284, 277, 277, 277, 
-	292, 277, 318, 277, 318, 277, 277, 277, 
-	277, 350, 277, 282, 283, 284, 277, 277, 
-	277, 292, 277, 318, 277, 318, 277, 349, 
-	277, 277, 277, 277, 282, 283, 284, 277, 
-	277, 277, 292, 277, 318, 277, 318, 40, 
-	277, 277, 56, 319, 277, 282, 283, 284, 
-	277, 277, 277, 292, 277, 318, 277, 311, 
-	312, 317, 317, 43, 282, 283, 284, 277, 
-	277, 277, 315, 277, 277, 286, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 287, 277, 311, 312, 313, 
-	317, 43, 282, 283, 284, 277, 277, 69, 
-	315, 277, 277, 286, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 287, 277, 309, 277, 351, 277, 336, 
-	336, 43, 282, 283, 284, 277, 277, 277, 
-	292, 277, 309, 277, 309, 277, 277, 277, 
-	277, 277, 277, 282, 283, 284, 277, 277, 
-	277, 292, 277, 309, 277, 309, 277, 277, 
-	277, 277, 352, 277, 282, 283, 284, 277, 
-	277, 277, 292, 277, 309, 277, 309, 277, 
-	351, 277, 277, 277, 277, 282, 283, 284, 
-	277, 277, 277, 292, 277, 309, 277, 309, 
-	40, 277, 277, 56, 310, 277, 282, 283, 
-	284, 277, 277, 277, 292, 277, 309, 277, 
-	302, 303, 308, 308, 43, 282, 283, 284, 
-	277, 277, 277, 306, 277, 277, 286, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 287, 277, 302, 303, 
-	304, 308, 43, 282, 283, 284, 277, 277, 
-	71, 306, 277, 277, 286, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 287, 277, 300, 277, 353, 277, 
-	336, 336, 43, 282, 283, 284, 277, 277, 
-	277, 292, 277, 300, 277, 300, 277, 277, 
-	277, 277, 277, 277, 282, 283, 284, 277, 
-	277, 277, 292, 277, 300, 277, 300, 277, 
-	277, 277, 277, 354, 277, 282, 283, 284, 
-	277, 277, 277, 292, 277, 300, 277, 300, 
-	277, 353, 277, 277, 277, 277, 282, 283, 
-	284, 277, 277, 277, 292, 277, 300, 277, 
-	300, 40, 277, 277, 56, 301, 277, 282, 
-	283, 284, 277, 277, 277, 292, 277, 300, 
-	277, 293, 294, 299, 299, 43, 282, 283, 
-	284, 277, 277, 277, 297, 277, 277, 286, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 277, 277, 287, 277, 293, 
-	294, 295, 299, 43, 282, 283, 284, 277, 
-	277, 73, 297, 277, 277, 286, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 277, 287, 277, 290, 277, 355, 
-	277, 336, 336, 43, 282, 283, 284, 277, 
-	277, 277, 292, 277, 290, 277, 290, 277, 
-	277, 277, 277, 277, 277, 282, 283, 284, 
-	277, 277, 277, 292, 277, 290, 277, 290, 
-	277, 277, 277, 277, 356, 277, 282, 283, 
-	284, 277, 277, 277, 292, 277, 290, 277, 
-	290, 277, 355, 277, 277, 277, 277, 282, 
-	283, 284, 277, 277, 277, 292, 277, 290, 
-	277, 74, 42, 42, 43, 277, 277, 277, 
-	277, 277, 277, 74, 277, 290, 40, 277, 
-	277, 56, 291, 277, 282, 283, 284, 277, 
-	277, 277, 292, 277, 290, 277, 278, 279, 
-	289, 281, 43, 282, 283, 284, 277, 277, 
-	277, 285, 277, 277, 286, 277, 277, 277, 
-	277, 277, 277, 277, 277, 277, 277, 277, 
-	277, 277, 287, 277, 358, 184, 359, 359, 
-	81, 187, 188, 189, 357, 357, 357, 191, 
-	357, 357, 194, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	196, 357, 184, 359, 359, 81, 187, 188, 
-	189, 357, 357, 357, 191, 357, 357, 194, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 196, 357, 360, 
-	357, 357, 357, 95, 361, 357, 187, 188, 
-	189, 357, 357, 357, 362, 357, 360, 357, 
-	363, 364, 365, 366, 81, 187, 188, 189, 
-	357, 357, 112, 367, 357, 357, 194, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 196, 357, 368, 364, 
-	369, 369, 81, 187, 188, 189, 357, 357, 
-	357, 367, 357, 357, 194, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 196, 357, 364, 369, 369, 81, 
-	187, 188, 189, 357, 357, 357, 367, 357, 
-	357, 194, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 196, 
-	357, 370, 357, 357, 357, 95, 371, 357, 
-	187, 188, 189, 357, 357, 357, 362, 357, 
-	370, 357, 372, 373, 374, 375, 81, 187, 
-	188, 189, 357, 357, 110, 376, 357, 357, 
-	194, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 196, 357, 
-	377, 373, 378, 378, 81, 187, 188, 189, 
-	357, 357, 357, 376, 357, 357, 194, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 196, 357, 373, 378, 
-	378, 81, 187, 188, 189, 357, 357, 357, 
-	376, 357, 357, 194, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 196, 357, 379, 357, 357, 357, 95, 
-	380, 357, 187, 188, 189, 357, 357, 357, 
-	362, 357, 379, 357, 381, 382, 383, 384, 
-	81, 187, 188, 189, 357, 357, 108, 385, 
-	357, 357, 194, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	196, 357, 386, 382, 387, 387, 81, 187, 
-	188, 189, 357, 357, 357, 385, 357, 357, 
-	194, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 196, 357, 
-	382, 387, 387, 81, 187, 188, 189, 357, 
-	357, 357, 385, 357, 357, 194, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 196, 357, 388, 357, 357, 
-	357, 95, 389, 357, 187, 188, 189, 357, 
-	357, 357, 362, 357, 388, 357, 390, 391, 
-	392, 393, 81, 187, 188, 189, 357, 357, 
-	106, 394, 357, 357, 194, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 196, 357, 395, 391, 396, 396, 
-	81, 187, 188, 189, 357, 357, 357, 394, 
-	357, 357, 194, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	196, 357, 391, 396, 396, 81, 187, 188, 
-	189, 357, 357, 357, 394, 357, 357, 194, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 196, 357, 95, 
-	397, 357, 187, 188, 189, 357, 357, 357, 
-	362, 357, 187, 188, 189, 357, 357, 357, 
-	362, 357, 398, 357, 357, 399, 188, 189, 
-	357, 188, 189, 357, 400, 357, 188, 401, 
-	357, 188, 402, 357, 188, 357, 398, 357, 
-	357, 357, 188, 189, 357, 403, 357, 404, 
-	405, 357, 187, 188, 189, 357, 357, 79, 
-	357, 78, 357, 357, 357, 357, 187, 188, 
-	189, 357, 187, 188, 189, 357, 403, 357, 
-	357, 357, 357, 187, 188, 189, 357, 403, 
-	357, 404, 357, 357, 187, 188, 189, 357, 
-	357, 79, 357, 95, 357, 406, 406, 81, 
-	187, 188, 189, 357, 357, 357, 362, 357, 
-	407, 104, 408, 409, 85, 187, 188, 189, 
-	357, 357, 357, 362, 357, 104, 408, 409, 
-	85, 187, 188, 189, 357, 357, 357, 362, 
-	357, 408, 408, 85, 187, 188, 189, 357, 
-	357, 357, 362, 357, 410, 101, 411, 412, 
-	88, 187, 188, 189, 357, 357, 357, 362, 
-	357, 101, 411, 412, 88, 187, 188, 189, 
-	357, 357, 357, 362, 357, 411, 411, 88, 
-	187, 188, 189, 357, 357, 357, 362, 357, 
-	413, 98, 414, 415, 91, 187, 188, 189, 
-	357, 357, 357, 362, 357, 98, 414, 415, 
-	91, 187, 188, 189, 357, 357, 357, 362, 
-	357, 414, 414, 91, 187, 188, 189, 357, 
-	357, 357, 362, 357, 416, 95, 357, 417, 
-	357, 187, 188, 189, 357, 357, 357, 362, 
-	357, 95, 357, 417, 357, 187, 188, 189, 
-	357, 357, 357, 362, 357, 418, 357, 187, 
-	188, 189, 357, 357, 357, 362, 357, 95, 
-	357, 357, 357, 357, 187, 188, 189, 357, 
-	357, 357, 362, 357, 77, 78, 357, 357, 
-	95, 397, 357, 187, 188, 189, 357, 357, 
-	357, 362, 357, 77, 357, 391, 396, 396, 
-	81, 187, 188, 189, 357, 357, 357, 394, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	196, 357, 391, 396, 396, 81, 187, 188, 
-	189, 357, 357, 357, 394, 357, 390, 391, 
-	396, 396, 81, 187, 188, 189, 357, 357, 
-	357, 394, 357, 357, 194, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 196, 357, 390, 391, 392, 396, 
-	81, 187, 188, 189, 357, 357, 106, 394, 
-	357, 357, 194, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	196, 357, 388, 357, 419, 357, 406, 406, 
-	81, 187, 188, 189, 357, 357, 357, 362, 
-	357, 388, 357, 388, 357, 357, 357, 357, 
-	357, 357, 187, 188, 189, 357, 357, 357, 
-	362, 357, 388, 357, 388, 357, 357, 357, 
-	357, 420, 357, 187, 188, 189, 357, 357, 
-	357, 362, 357, 388, 357, 388, 357, 419, 
-	357, 357, 357, 357, 187, 188, 189, 357, 
-	357, 357, 362, 357, 388, 357, 388, 78, 
-	357, 357, 95, 389, 357, 187, 188, 189, 
-	357, 357, 357, 362, 357, 388, 357, 381, 
-	382, 387, 387, 81, 187, 188, 189, 357, 
-	357, 357, 385, 357, 357, 194, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 196, 357, 381, 382, 383, 
-	387, 81, 187, 188, 189, 357, 357, 108, 
-	385, 357, 357, 194, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 196, 357, 379, 357, 421, 357, 406, 
-	406, 81, 187, 188, 189, 357, 357, 357, 
-	362, 357, 379, 357, 379, 357, 357, 357, 
-	357, 357, 357, 187, 188, 189, 357, 357, 
-	357, 362, 357, 379, 357, 379, 357, 357, 
-	357, 357, 422, 357, 187, 188, 189, 357, 
-	357, 357, 362, 357, 379, 357, 379, 357, 
-	421, 357, 357, 357, 357, 187, 188, 189, 
-	357, 357, 357, 362, 357, 379, 357, 379, 
-	78, 357, 357, 95, 380, 357, 187, 188, 
-	189, 357, 357, 357, 362, 357, 379, 357, 
-	372, 373, 378, 378, 81, 187, 188, 189, 
-	357, 357, 357, 376, 357, 357, 194, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 196, 357, 372, 373, 
-	374, 378, 81, 187, 188, 189, 357, 357, 
-	110, 376, 357, 357, 194, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 196, 357, 370, 357, 423, 357, 
-	406, 406, 81, 187, 188, 189, 357, 357, 
-	357, 362, 357, 370, 357, 370, 357, 357, 
-	357, 357, 357, 357, 187, 188, 189, 357, 
-	357, 357, 362, 357, 370, 357, 370, 357, 
-	357, 357, 357, 424, 357, 187, 188, 189, 
-	357, 357, 357, 362, 357, 370, 357, 370, 
-	357, 423, 357, 357, 357, 357, 187, 188, 
-	189, 357, 357, 357, 362, 357, 370, 357, 
-	370, 78, 357, 357, 95, 371, 357, 187, 
-	188, 189, 357, 357, 357, 362, 357, 370, 
-	357, 363, 364, 369, 369, 81, 187, 188, 
-	189, 357, 357, 357, 367, 357, 357, 194, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 196, 357, 363, 
-	364, 365, 369, 81, 187, 188, 189, 357, 
-	357, 112, 367, 357, 357, 194, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 357, 196, 357, 360, 357, 425, 
-	357, 406, 406, 81, 187, 188, 189, 357, 
-	357, 357, 362, 357, 360, 357, 360, 357, 
-	357, 357, 357, 357, 357, 187, 188, 189, 
-	357, 357, 357, 362, 357, 360, 357, 360, 
-	357, 357, 357, 357, 426, 357, 187, 188, 
-	189, 357, 357, 357, 362, 357, 360, 357, 
-	360, 357, 425, 357, 357, 357, 357, 187, 
-	188, 189, 357, 357, 357, 362, 357, 360, 
-	357, 360, 78, 357, 357, 95, 361, 357, 
-	187, 188, 189, 357, 357, 357, 362, 357, 
-	360, 357, 113, 80, 80, 81, 427, 427, 
-	427, 427, 427, 152, 113, 427, 183, 184, 
-	359, 359, 81, 187, 188, 189, 357, 357, 
-	357, 191, 357, 357, 194, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	357, 357, 196, 357, 113, 80, 80, 81, 
-	427, 427, 427, 427, 427, 427, 113, 427, 
-	429, 430, 431, 432, 119, 433, 434, 435, 
-	428, 428, 151, 436, 428, 428, 437, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 438, 428, 439, 430, 
-	432, 432, 119, 433, 434, 435, 428, 428, 
-	428, 436, 428, 428, 437, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 438, 428, 430, 432, 432, 119, 
-	433, 434, 435, 428, 428, 428, 436, 428, 
-	428, 437, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 438, 
-	428, 440, 428, 428, 428, 132, 441, 428, 
-	433, 434, 435, 428, 428, 428, 442, 428, 
-	440, 428, 443, 444, 445, 446, 119, 433, 
-	434, 435, 428, 428, 149, 447, 428, 428, 
-	437, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 438, 428, 
-	448, 444, 449, 449, 119, 433, 434, 435, 
-	428, 428, 428, 447, 428, 428, 437, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 438, 428, 444, 449, 
-	449, 119, 433, 434, 435, 428, 428, 428, 
-	447, 428, 428, 437, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 438, 428, 450, 428, 428, 428, 132, 
-	451, 428, 433, 434, 435, 428, 428, 428, 
-	442, 428, 450, 428, 452, 453, 454, 455, 
-	119, 433, 434, 435, 428, 428, 147, 456, 
-	428, 428, 437, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	438, 428, 457, 453, 458, 458, 119, 433, 
-	434, 435, 428, 428, 428, 456, 428, 428, 
-	437, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 438, 428, 
-	453, 458, 458, 119, 433, 434, 435, 428, 
-	428, 428, 456, 428, 428, 437, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 438, 428, 459, 428, 428, 
-	428, 132, 460, 428, 433, 434, 435, 428, 
-	428, 428, 442, 428, 459, 428, 461, 462, 
-	463, 464, 119, 433, 434, 435, 428, 428, 
-	145, 465, 428, 428, 437, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 438, 428, 466, 462, 467, 467, 
-	119, 433, 434, 435, 428, 428, 428, 465, 
-	428, 428, 437, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	438, 428, 462, 467, 467, 119, 433, 434, 
-	435, 428, 428, 428, 465, 428, 428, 437, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 438, 428, 468, 
-	428, 428, 428, 132, 469, 428, 433, 434, 
-	435, 428, 428, 428, 442, 428, 468, 428, 
-	470, 471, 472, 473, 119, 433, 434, 435, 
-	428, 428, 143, 474, 428, 428, 437, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 438, 428, 475, 471, 
-	476, 476, 119, 433, 434, 435, 428, 428, 
-	428, 474, 428, 428, 437, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 438, 428, 471, 476, 476, 119, 
-	433, 434, 435, 428, 428, 428, 474, 428, 
-	428, 437, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 438, 
-	428, 132, 477, 428, 433, 434, 435, 428, 
-	428, 428, 442, 428, 433, 434, 435, 428, 
-	428, 428, 442, 428, 478, 428, 428, 479, 
-	434, 435, 428, 434, 435, 428, 480, 428, 
-	434, 481, 428, 434, 482, 428, 434, 428, 
-	478, 428, 428, 428, 434, 435, 428, 483, 
-	428, 484, 485, 428, 433, 434, 435, 428, 
-	428, 117, 428, 116, 428, 428, 428, 428, 
-	433, 434, 435, 428, 433, 434, 435, 428, 
-	483, 428, 428, 428, 428, 433, 434, 435, 
-	428, 483, 428, 484, 428, 428, 433, 434, 
-	435, 428, 428, 117, 428, 132, 428, 486, 
-	486, 119, 433, 434, 435, 428, 428, 428, 
-	442, 428, 487, 141, 488, 489, 122, 433, 
-	434, 435, 428, 428, 428, 442, 428, 141, 
-	488, 489, 122, 433, 434, 435, 428, 428, 
-	428, 442, 428, 488, 488, 122, 433, 434, 
-	435, 428, 428, 428, 442, 428, 490, 138, 
-	491, 492, 125, 433, 434, 435, 428, 428, 
-	428, 442, 428, 138, 491, 492, 125, 433, 
-	434, 435, 428, 428, 428, 442, 428, 491, 
-	491, 125, 433, 434, 435, 428, 428, 428, 
-	442, 428, 493, 135, 494, 495, 128, 433, 
-	434, 435, 428, 428, 428, 442, 428, 135, 
-	494, 495, 128, 433, 434, 435, 428, 428, 
-	428, 442, 428, 494, 494, 128, 433, 434, 
-	435, 428, 428, 428, 442, 428, 496, 132, 
-	428, 497, 428, 433, 434, 435, 428, 428, 
-	428, 442, 428, 132, 428, 497, 428, 433, 
-	434, 435, 428, 428, 428, 442, 428, 498, 
-	428, 433, 434, 435, 428, 428, 428, 442, 
-	428, 132, 428, 428, 428, 428, 433, 434, 
-	435, 428, 428, 428, 442, 428, 115, 116, 
-	428, 428, 132, 477, 428, 433, 434, 435, 
-	428, 428, 428, 442, 428, 115, 428, 471, 
-	476, 476, 119, 433, 434, 435, 428, 428, 
-	428, 474, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 438, 428, 471, 476, 476, 119, 
-	433, 434, 435, 428, 428, 428, 474, 428, 
-	470, 471, 476, 476, 119, 433, 434, 435, 
-	428, 428, 428, 474, 428, 428, 437, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 438, 428, 470, 471, 
-	472, 476, 119, 433, 434, 435, 428, 428, 
-	143, 474, 428, 428, 437, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 438, 428, 468, 428, 499, 428, 
-	486, 486, 119, 433, 434, 435, 428, 428, 
-	428, 442, 428, 468, 428, 468, 428, 428, 
-	428, 428, 428, 428, 433, 434, 435, 428, 
-	428, 428, 442, 428, 468, 428, 468, 428, 
-	428, 428, 428, 500, 428, 433, 434, 435, 
-	428, 428, 428, 442, 428, 468, 428, 468, 
-	428, 499, 428, 428, 428, 428, 433, 434, 
-	435, 428, 428, 428, 442, 428, 468, 428, 
-	468, 116, 428, 428, 132, 469, 428, 433, 
-	434, 435, 428, 428, 428, 442, 428, 468, 
-	428, 461, 462, 467, 467, 119, 433, 434, 
-	435, 428, 428, 428, 465, 428, 428, 437, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 438, 428, 461, 
-	462, 463, 467, 119, 433, 434, 435, 428, 
-	428, 145, 465, 428, 428, 437, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 438, 428, 459, 428, 501, 
-	428, 486, 486, 119, 433, 434, 435, 428, 
-	428, 428, 442, 428, 459, 428, 459, 428, 
-	428, 428, 428, 428, 428, 433, 434, 435, 
-	428, 428, 428, 442, 428, 459, 428, 459, 
-	428, 428, 428, 428, 502, 428, 433, 434, 
-	435, 428, 428, 428, 442, 428, 459, 428, 
-	459, 428, 501, 428, 428, 428, 428, 433, 
-	434, 435, 428, 428, 428, 442, 428, 459, 
-	428, 459, 116, 428, 428, 132, 460, 428, 
-	433, 434, 435, 428, 428, 428, 442, 428, 
-	459, 428, 452, 453, 458, 458, 119, 433, 
-	434, 435, 428, 428, 428, 456, 428, 428, 
-	437, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 438, 428, 
-	452, 453, 454, 458, 119, 433, 434, 435, 
-	428, 428, 147, 456, 428, 428, 437, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 438, 428, 450, 428, 
-	503, 428, 486, 486, 119, 433, 434, 435, 
-	428, 428, 428, 442, 428, 450, 428, 450, 
-	428, 428, 428, 428, 428, 428, 433, 434, 
-	435, 428, 428, 428, 442, 428, 450, 428, 
-	450, 428, 428, 428, 428, 504, 428, 433, 
-	434, 435, 428, 428, 428, 442, 428, 450, 
-	428, 450, 428, 503, 428, 428, 428, 428, 
-	433, 434, 435, 428, 428, 428, 442, 428, 
-	450, 428, 450, 116, 428, 428, 132, 451, 
-	428, 433, 434, 435, 428, 428, 428, 442, 
-	428, 450, 428, 443, 444, 449, 449, 119, 
-	433, 434, 435, 428, 428, 428, 447, 428, 
-	428, 437, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 438, 
-	428, 443, 444, 445, 449, 119, 433, 434, 
-	435, 428, 428, 149, 447, 428, 428, 437, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 438, 428, 440, 
-	428, 505, 428, 486, 486, 119, 433, 434, 
-	435, 428, 428, 428, 442, 428, 440, 428, 
-	440, 428, 428, 428, 428, 428, 428, 433, 
-	434, 435, 428, 428, 428, 442, 428, 440, 
-	428, 440, 428, 428, 428, 428, 506, 428, 
-	433, 434, 435, 428, 428, 428, 442, 428, 
-	440, 428, 440, 428, 505, 428, 428, 428, 
-	428, 433, 434, 435, 428, 428, 428, 442, 
-	428, 440, 428, 440, 116, 428, 428, 132, 
-	441, 428, 433, 434, 435, 428, 428, 428, 
-	442, 428, 440, 428, 429, 430, 432, 432, 
-	119, 433, 434, 435, 428, 428, 428, 436, 
-	428, 428, 437, 428, 428, 428, 428, 428, 
-	428, 428, 428, 428, 428, 428, 428, 428, 
-	438, 428, 181, 182, 183, 184, 507, 359, 
-	81, 187, 188, 189, 190, 190, 152, 191, 
-	357, 181, 194, 357, 357, 357, 357, 357, 
-	357, 357, 357, 357, 357, 357, 357, 357, 
-	196, 357, 198, 508, 200, 201, 5, 202, 
-	203, 204, 197, 197, 37, 205, 197, 197, 
-	206, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 207, 197, 
-	210, 182, 183, 184, 509, 510, 81, 511, 
-	512, 513, 197, 190, 152, 514, 197, 210, 
-	194, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 196, 197, 
-	113, 80, 80, 81, 202, 203, 204, 197, 
-	197, 152, 515, 197, 516, 2, 357, 357, 
-	357, 426, 357, 187, 188, 189, 357, 357, 
-	357, 362, 357, 516, 357, 517, 364, 518, 
-	519, 81, 511, 512, 513, 197, 197, 153, 
-	367, 197, 197, 194, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 196, 197, 520, 364, 369, 369, 81, 
-	511, 512, 513, 197, 197, 197, 367, 197, 
-	197, 194, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 196, 
-	197, 364, 369, 369, 81, 511, 512, 513, 
-	197, 197, 197, 367, 197, 197, 194, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 196, 197, 521, 197, 
-	197, 522, 512, 513, 197, 512, 513, 197, 
-	250, 197, 512, 523, 197, 512, 524, 197, 
-	512, 197, 521, 197, 197, 197, 512, 513, 
-	197, 517, 364, 369, 369, 81, 511, 512, 
-	513, 197, 197, 197, 367, 197, 197, 194, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 197, 197, 196, 197, 517, 
-	364, 518, 369, 81, 511, 512, 513, 197, 
-	197, 153, 367, 197, 197, 194, 197, 197, 
-	197, 197, 197, 197, 197, 197, 197, 197, 
-	197, 197, 197, 196, 197, 210, 197, 275, 
-	113, 525, 525, 155, 202, 203, 204, 197, 
-	197, 197, 515, 197, 210, 197, 526, 179, 
-	527, 528, 157, 511, 512, 513, 197, 197, 
-	197, 529, 197, 179, 527, 528, 157, 511, 
-	512, 513, 197, 197, 197, 529, 197, 527, 
-	527, 157, 511, 512, 513, 197, 197, 197, 
-	529, 197, 530, 176, 531, 532, 160, 511, 
-	512, 513, 197, 197, 197, 529, 197, 176, 
-	531, 532, 160, 511, 512, 513, 197, 197, 
-	197, 529, 197, 531, 531, 160, 511, 512, 
-	513, 197, 197, 197, 529, 197, 533, 173, 
-	534, 535, 163, 511, 512, 513, 197, 197, 
-	197, 529, 197, 173, 534, 535, 163, 511, 
-	512, 513, 197, 197, 197, 529, 197, 534, 
-	534, 163, 511, 512, 513, 197, 197, 197, 
-	529, 197, 536, 170, 197, 537, 197, 511, 
-	512, 513, 197, 197, 197, 529, 197, 170, 
-	197, 537, 197, 511, 512, 513, 197, 197, 
-	197, 529, 197, 511, 512, 513, 197, 197, 
-	197, 529, 197, 538, 197, 539, 540, 197, 
-	511, 512, 513, 197, 197, 167, 197, 166, 
-	197, 197, 197, 197, 511, 512, 513, 197, 
-	511, 512, 513, 197, 538, 197, 197, 197, 
-	197, 511, 512, 513, 197, 538, 197, 539, 
-	197, 197, 511, 512, 513, 197, 197, 167, 
-	197, 516, 166, 357, 357, 95, 361, 357, 
-	187, 188, 189, 357, 357, 357, 362, 357, 
-	516, 357, 542, 541, 541, 541, 541, 543, 
-	544, 545, 541, 543, 544, 545, 541, 546, 
-	541, 541, 547, 544, 545, 541, 544, 545, 
-	541, 548, 541, 544, 549, 541, 544, 550, 
-	541, 544, 541, 546, 541, 541, 541, 544, 
-	545, 541, 0
+	0, 2, 0, 1, 0, 0, 0, 0, 
+	4, 0, 5, 5, 6, 1, 0, 7, 
+	7, 6, 0, 6, 0, 8, 8, 9, 
+	1, 0, 10, 10, 9, 0, 9, 0, 
+	11, 11, 12, 1, 0, 13, 13, 12, 
+	0, 12, 0, 14, 14, 15, 1, 0, 
+	16, 16, 15, 0, 15, 0, 17, 0, 
+	0, 0, 1, 0, 18, 0, 19, 0, 
+	20, 14, 14, 15, 1, 0, 21, 0, 
+	22, 0, 23, 11, 11, 12, 1, 0, 
+	24, 0, 25, 0, 26, 8, 8, 9, 
+	1, 0, 27, 0, 28, 0, 29, 5, 
+	5, 6, 1, 0, 0, 0, 0, 0, 
+	29, 0, 29, 5, 5, 6, 1, 0, 
+	0, 0, 0, 30, 29, 0, 31, 5, 
+	5, 6, 1, 0, 0, 0, 0, 0, 
+	31, 0, 31, 5, 5, 6, 1, 0, 
+	0, 0, 0, 32, 31, 0, 33, 5, 
+	5, 6, 1, 0, 0, 0, 0, 0, 
+	33, 0, 33, 5, 5, 6, 1, 0, 
+	0, 0, 0, 34, 33, 0, 35, 5, 
+	5, 6, 1, 0, 0, 0, 0, 0, 
+	35, 0, 35, 5, 5, 6, 1, 0, 
+	0, 0, 0, 36, 35, 0, 37, 5, 
+	5, 6, 1, 0, 0, 0, 0, 0, 
+	37, 0, 37, 5, 5, 6, 1, 0, 
+	0, 0, 0, 38, 37, 0, 40, 39, 
+	41, 42, 39, 39, 39, 39, 39, 39, 
+	39, 39, 39, 39, 39, 39, 39, 41, 
+	39, 40, 39, 39, 39, 39, 43, 39, 
+	44, 44, 45, 40, 39, 46, 46, 45, 
+	39, 45, 39, 47, 47, 48, 40, 39, 
+	49, 49, 48, 39, 48, 39, 50, 50, 
+	51, 40, 39, 52, 52, 51, 39, 51, 
+	39, 53, 53, 54, 40, 39, 55, 55, 
+	54, 39, 54, 39, 56, 39, 39, 39, 
+	40, 39, 57, 39, 58, 39, 59, 53, 
+	53, 54, 40, 39, 60, 39, 61, 39, 
+	62, 50, 50, 51, 40, 39, 63, 39, 
+	64, 39, 65, 47, 47, 48, 40, 39, 
+	66, 39, 67, 39, 68, 44, 44, 45, 
+	40, 39, 39, 39, 39, 39, 68, 39, 
+	68, 44, 44, 45, 40, 39, 39, 39, 
+	39, 69, 68, 39, 70, 44, 44, 45, 
+	40, 39, 39, 39, 39, 39, 70, 39, 
+	70, 44, 44, 45, 40, 39, 39, 39, 
+	39, 71, 70, 39, 72, 44, 44, 45, 
+	40, 39, 39, 39, 39, 39, 72, 39, 
+	72, 44, 44, 45, 40, 39, 39, 39, 
+	39, 73, 72, 39, 74, 44, 44, 45, 
+	40, 39, 39, 39, 39, 39, 74, 39, 
+	74, 44, 44, 45, 40, 39, 39, 39, 
+	39, 75, 74, 39, 76, 44, 44, 45, 
+	40, 39, 39, 39, 39, 39, 76, 39, 
+	76, 44, 44, 45, 40, 39, 39, 39, 
+	39, 77, 76, 39, 79, 78, 80, 81, 
+	78, 78, 78, 78, 78, 78, 78, 78, 
+	78, 78, 78, 78, 78, 80, 78, 79, 
+	78, 78, 78, 78, 82, 78, 83, 83, 
+	84, 79, 78, 86, 86, 84, 85, 84, 
+	85, 87, 87, 88, 79, 78, 89, 89, 
+	88, 78, 88, 78, 90, 90, 91, 79, 
+	78, 92, 92, 91, 78, 91, 78, 93, 
+	93, 94, 79, 78, 95, 95, 94, 78, 
+	94, 78, 96, 78, 78, 78, 79, 78, 
+	97, 78, 98, 78, 99, 93, 93, 94, 
+	79, 78, 100, 78, 101, 78, 102, 90, 
+	90, 91, 79, 78, 103, 78, 104, 78, 
+	105, 87, 87, 88, 79, 78, 106, 78, 
+	107, 78, 108, 83, 83, 84, 79, 78, 
+	78, 78, 78, 78, 108, 78, 108, 83, 
+	83, 84, 79, 78, 78, 78, 78, 109, 
+	108, 78, 110, 83, 83, 84, 79, 78, 
+	78, 78, 78, 78, 110, 78, 110, 83, 
+	83, 84, 79, 78, 78, 78, 78, 111, 
+	110, 78, 112, 83, 83, 84, 79, 78, 
+	78, 78, 78, 78, 112, 78, 112, 83, 
+	83, 84, 79, 78, 78, 78, 78, 113, 
+	112, 78, 114, 83, 83, 84, 79, 78, 
+	78, 78, 78, 78, 114, 78, 114, 83, 
+	83, 84, 79, 78, 78, 78, 78, 115, 
+	114, 78, 116, 83, 83, 84, 79, 78, 
+	78, 78, 78, 78, 116, 78, 118, 117, 
+	119, 120, 117, 117, 117, 117, 117, 117, 
+	117, 117, 117, 117, 117, 117, 117, 119, 
+	117, 118, 117, 117, 117, 117, 121, 117, 
+	122, 122, 123, 118, 117, 124, 124, 123, 
+	117, 123, 117, 125, 125, 126, 118, 117, 
+	127, 127, 126, 117, 126, 117, 128, 128, 
+	129, 118, 117, 130, 130, 129, 117, 129, 
+	117, 131, 131, 132, 118, 117, 133, 133, 
+	132, 117, 132, 117, 134, 117, 117, 117, 
+	118, 117, 135, 117, 136, 117, 137, 131, 
+	131, 132, 118, 117, 138, 117, 139, 117, 
+	140, 128, 128, 129, 118, 117, 141, 117, 
+	142, 117, 143, 125, 125, 126, 118, 117, 
+	144, 117, 145, 117, 146, 122, 122, 123, 
+	118, 117, 117, 117, 117, 117, 146, 117, 
+	146, 122, 122, 123, 118, 117, 117, 117, 
+	117, 147, 146, 117, 148, 122, 122, 123, 
+	118, 117, 117, 117, 117, 117, 148, 117, 
+	148, 122, 122, 123, 118, 117, 117, 117, 
+	117, 149, 148, 117, 150, 122, 122, 123, 
+	118, 117, 117, 117, 117, 117, 150, 117, 
+	150, 122, 122, 123, 118, 117, 117, 117, 
+	117, 151, 150, 117, 152, 122, 122, 123, 
+	118, 117, 117, 117, 117, 117, 152, 117, 
+	152, 122, 122, 123, 118, 117, 117, 117, 
+	117, 153, 152, 117, 154, 122, 122, 123, 
+	118, 117, 117, 117, 117, 117, 154, 117, 
+	154, 122, 122, 123, 118, 117, 117, 117, 
+	117, 155, 154, 117, 116, 83, 83, 84, 
+	79, 78, 78, 78, 78, 156, 116, 78, 
+	86, 86, 84, 1, 0, 114, 83, 83, 
+	84, 157, 0, 0, 0, 0, 0, 114, 
+	0, 114, 83, 83, 84, 157, 0, 0, 
+	0, 0, 158, 114, 0, 159, 159, 160, 
+	1, 0, 7, 7, 160, 0, 161, 161, 
+	162, 157, 0, 163, 163, 162, 0, 162, 
+	0, 164, 164, 165, 157, 0, 166, 166, 
+	165, 0, 165, 0, 167, 167, 168, 157, 
+	0, 169, 169, 168, 0, 168, 0, 157, 
+	0, 170, 171, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	170, 0, 157, 0, 0, 0, 0, 172, 
+	0, 173, 0, 0, 0, 157, 0, 174, 
+	0, 175, 0, 176, 167, 167, 168, 157, 
+	0, 177, 0, 178, 0, 179, 164, 164, 
+	165, 157, 0, 180, 0, 181, 0, 182, 
+	161, 161, 162, 157, 0, 183, 0, 184, 
+	0, 186, 185, 188, 189, 190, 191, 192, 
+	193, 84, 79, 194, 195, 196, 196, 156, 
+	197, 198, 199, 200, 201, 187, 187, 187, 
+	187, 187, 187, 187, 187, 187, 187, 187, 
+	187, 202, 187, 204, 205, 206, 207, 6, 
+	1, 208, 209, 203, 203, 38, 210, 203, 
+	203, 211, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 212, 
+	203, 213, 205, 214, 214, 6, 1, 208, 
+	209, 203, 203, 203, 210, 203, 203, 211, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 212, 203, 205, 
+	214, 214, 6, 1, 208, 209, 203, 203, 
+	203, 210, 203, 203, 211, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 212, 203, 215, 203, 203, 203, 
+	19, 216, 203, 1, 208, 209, 203, 203, 
+	203, 217, 203, 215, 203, 218, 219, 220, 
+	221, 6, 1, 208, 209, 203, 203, 36, 
+	222, 203, 203, 211, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 212, 203, 223, 219, 224, 224, 6, 
+	1, 208, 209, 203, 203, 203, 222, 203, 
+	203, 211, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 212, 
+	203, 219, 224, 224, 6, 1, 208, 209, 
+	203, 203, 203, 222, 203, 203, 211, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 212, 203, 225, 203, 
+	203, 203, 19, 226, 203, 1, 208, 209, 
+	203, 203, 203, 217, 203, 225, 203, 227, 
+	228, 229, 230, 6, 1, 208, 209, 203, 
+	203, 34, 231, 203, 203, 211, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 212, 203, 232, 228, 233, 
+	233, 6, 1, 208, 209, 203, 203, 203, 
+	231, 203, 203, 211, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 212, 203, 228, 233, 233, 6, 1, 
+	208, 209, 203, 203, 203, 231, 203, 203, 
+	211, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 212, 203, 
+	234, 203, 203, 203, 19, 235, 203, 1, 
+	208, 209, 203, 203, 203, 217, 203, 234, 
+	203, 236, 237, 238, 239, 6, 1, 208, 
+	209, 203, 203, 32, 240, 203, 203, 211, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 212, 203, 241, 
+	237, 242, 242, 6, 1, 208, 209, 203, 
+	203, 203, 240, 203, 203, 211, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 212, 203, 237, 242, 242, 
+	6, 1, 208, 209, 203, 203, 203, 240, 
+	203, 203, 211, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	212, 203, 243, 203, 203, 203, 19, 244, 
+	203, 1, 208, 209, 203, 203, 203, 217, 
+	203, 243, 203, 245, 246, 247, 248, 6, 
+	1, 208, 209, 203, 203, 30, 249, 203, 
+	203, 211, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 212, 
+	203, 250, 246, 251, 251, 6, 1, 208, 
+	209, 203, 203, 203, 249, 203, 203, 211, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 212, 203, 246, 
+	251, 251, 6, 1, 208, 209, 203, 203, 
+	203, 249, 203, 203, 211, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 212, 203, 19, 252, 203, 1, 
+	208, 209, 203, 203, 203, 217, 203, 253, 
+	253, 203, 1, 208, 209, 203, 203, 203, 
+	217, 203, 254, 203, 203, 255, 208, 209, 
+	203, 208, 209, 203, 256, 203, 208, 257, 
+	203, 208, 258, 203, 208, 203, 254, 203, 
+	203, 203, 208, 209, 203, 259, 203, 260, 
+	261, 203, 1, 208, 209, 203, 203, 4, 
+	203, 3, 203, 253, 253, 203, 1, 208, 
+	209, 203, 253, 253, 203, 1, 208, 209, 
+	203, 259, 203, 253, 253, 203, 1, 208, 
+	209, 203, 259, 203, 260, 253, 203, 1, 
+	208, 209, 203, 203, 4, 203, 19, 203, 
+	262, 262, 6, 1, 208, 209, 203, 203, 
+	203, 217, 203, 263, 28, 264, 265, 9, 
+	1, 208, 209, 203, 203, 203, 217, 203, 
+	28, 264, 265, 9, 1, 208, 209, 203, 
+	203, 203, 217, 203, 264, 264, 9, 1, 
+	208, 209, 203, 203, 203, 217, 203, 266, 
+	25, 267, 268, 12, 1, 208, 209, 203, 
+	203, 203, 217, 203, 25, 267, 268, 12, 
+	1, 208, 209, 203, 203, 203, 217, 203, 
+	267, 267, 12, 1, 208, 209, 203, 203, 
+	203, 217, 203, 269, 22, 270, 271, 15, 
+	1, 208, 209, 203, 203, 203, 217, 203, 
+	22, 270, 271, 15, 1, 208, 209, 203, 
+	203, 203, 217, 203, 270, 270, 15, 1, 
+	208, 209, 203, 203, 203, 217, 203, 272, 
+	19, 253, 273, 203, 1, 208, 209, 203, 
+	203, 203, 217, 203, 19, 253, 273, 203, 
+	1, 208, 209, 203, 203, 203, 217, 203, 
+	253, 274, 203, 1, 208, 209, 203, 203, 
+	203, 217, 203, 19, 203, 253, 253, 203, 
+	1, 208, 209, 203, 203, 203, 217, 203, 
+	2, 3, 203, 203, 19, 252, 203, 1, 
+	208, 209, 203, 203, 203, 217, 203, 2, 
+	203, 246, 251, 251, 6, 1, 208, 209, 
+	203, 203, 203, 249, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 212, 203, 246, 251, 
+	251, 6, 1, 208, 209, 203, 203, 203, 
+	249, 203, 245, 246, 251, 251, 6, 1, 
+	208, 209, 203, 203, 203, 249, 203, 203, 
+	211, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 212, 203, 
+	245, 246, 247, 251, 6, 1, 208, 209, 
+	203, 203, 30, 249, 203, 203, 211, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 212, 203, 243, 203, 
+	275, 203, 262, 262, 6, 1, 208, 209, 
+	203, 203, 203, 217, 203, 243, 203, 243, 
+	203, 203, 203, 253, 253, 203, 1, 208, 
+	209, 203, 203, 203, 217, 203, 243, 203, 
+	243, 203, 203, 203, 253, 276, 203, 1, 
+	208, 209, 203, 203, 203, 217, 203, 243, 
+	203, 243, 203, 275, 203, 253, 253, 203, 
+	1, 208, 209, 203, 203, 203, 217, 203, 
+	243, 203, 243, 3, 203, 203, 19, 244, 
+	203, 1, 208, 209, 203, 203, 203, 217, 
+	203, 243, 203, 236, 237, 242, 242, 6, 
+	1, 208, 209, 203, 203, 203, 240, 203, 
+	203, 211, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 212, 
+	203, 236, 237, 238, 242, 6, 1, 208, 
+	209, 203, 203, 32, 240, 203, 203, 211, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 212, 203, 234, 
+	203, 277, 203, 262, 262, 6, 1, 208, 
+	209, 203, 203, 203, 217, 203, 234, 203, 
+	234, 203, 203, 203, 253, 253, 203, 1, 
+	208, 209, 203, 203, 203, 217, 203, 234, 
+	203, 234, 203, 203, 203, 253, 278, 203, 
+	1, 208, 209, 203, 203, 203, 217, 203, 
+	234, 203, 234, 203, 277, 203, 253, 253, 
+	203, 1, 208, 209, 203, 203, 203, 217, 
+	203, 234, 203, 234, 3, 203, 203, 19, 
+	235, 203, 1, 208, 209, 203, 203, 203, 
+	217, 203, 234, 203, 227, 228, 233, 233, 
+	6, 1, 208, 209, 203, 203, 203, 231, 
+	203, 203, 211, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	212, 203, 227, 228, 229, 233, 6, 1, 
+	208, 209, 203, 203, 34, 231, 203, 203, 
+	211, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 212, 203, 
+	225, 203, 279, 203, 262, 262, 6, 1, 
+	208, 209, 203, 203, 203, 217, 203, 225, 
+	203, 225, 203, 203, 203, 253, 253, 203, 
+	1, 208, 209, 203, 203, 203, 217, 203, 
+	225, 203, 225, 203, 203, 203, 253, 280, 
+	203, 1, 208, 209, 203, 203, 203, 217, 
+	203, 225, 203, 225, 203, 279, 203, 253, 
+	253, 203, 1, 208, 209, 203, 203, 203, 
+	217, 203, 225, 203, 225, 3, 203, 203, 
+	19, 226, 203, 1, 208, 209, 203, 203, 
+	203, 217, 203, 225, 203, 218, 219, 224, 
+	224, 6, 1, 208, 209, 203, 203, 203, 
+	222, 203, 203, 211, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 212, 203, 218, 219, 220, 224, 6, 
+	1, 208, 209, 203, 203, 36, 222, 203, 
+	203, 211, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 212, 
+	203, 215, 203, 281, 203, 262, 262, 6, 
+	1, 208, 209, 203, 203, 203, 217, 203, 
+	215, 203, 215, 203, 203, 203, 253, 253, 
+	203, 1, 208, 209, 203, 203, 203, 217, 
+	203, 215, 203, 215, 203, 203, 203, 253, 
+	282, 203, 1, 208, 209, 203, 203, 203, 
+	217, 203, 215, 203, 215, 203, 281, 203, 
+	253, 253, 203, 1, 208, 209, 203, 203, 
+	203, 217, 203, 215, 203, 215, 3, 203, 
+	203, 19, 216, 203, 1, 208, 209, 203, 
+	203, 203, 217, 203, 215, 203, 204, 205, 
+	214, 214, 6, 1, 208, 209, 203, 203, 
+	203, 210, 203, 203, 211, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 212, 203, 204, 205, 206, 214, 
+	6, 1, 208, 209, 203, 203, 38, 210, 
+	203, 203, 211, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	212, 203, 284, 285, 286, 287, 45, 40, 
+	288, 289, 283, 283, 77, 290, 283, 283, 
+	291, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 292, 283, 
+	293, 285, 294, 287, 45, 40, 288, 289, 
+	283, 283, 283, 290, 283, 283, 291, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 292, 283, 285, 294, 
+	287, 45, 40, 288, 289, 283, 283, 283, 
+	290, 283, 283, 291, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 292, 283, 295, 283, 283, 283, 58, 
+	296, 283, 40, 288, 289, 283, 283, 283, 
+	297, 283, 295, 283, 298, 299, 300, 301, 
+	45, 40, 288, 289, 283, 283, 75, 302, 
+	283, 283, 291, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	292, 283, 303, 299, 304, 304, 45, 40, 
+	288, 289, 283, 283, 283, 302, 283, 283, 
+	291, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 292, 283, 
+	299, 304, 304, 45, 40, 288, 289, 283, 
+	283, 283, 302, 283, 283, 291, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 292, 283, 305, 283, 283, 
+	283, 58, 306, 283, 40, 288, 289, 283, 
+	283, 283, 297, 283, 305, 283, 307, 308, 
+	309, 310, 45, 40, 288, 289, 283, 283, 
+	73, 311, 283, 283, 291, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 292, 283, 312, 308, 313, 313, 
+	45, 40, 288, 289, 283, 283, 283, 311, 
+	283, 283, 291, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	292, 283, 308, 313, 313, 45, 40, 288, 
+	289, 283, 283, 283, 311, 283, 283, 291, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 292, 283, 314, 
+	283, 283, 283, 58, 315, 283, 40, 288, 
+	289, 283, 283, 283, 297, 283, 314, 283, 
+	316, 317, 318, 319, 45, 40, 288, 289, 
+	283, 283, 71, 320, 283, 283, 291, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 292, 283, 321, 317, 
+	322, 322, 45, 40, 288, 289, 283, 283, 
+	283, 320, 283, 283, 291, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 292, 283, 317, 322, 322, 45, 
+	40, 288, 289, 283, 283, 283, 320, 283, 
+	283, 291, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 292, 
+	283, 323, 283, 283, 283, 58, 324, 283, 
+	40, 288, 289, 283, 283, 283, 297, 283, 
+	323, 283, 325, 326, 327, 328, 45, 40, 
+	288, 289, 283, 283, 69, 329, 283, 283, 
+	291, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 292, 283, 
+	330, 326, 331, 331, 45, 40, 288, 289, 
+	283, 283, 283, 329, 283, 283, 291, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 292, 283, 326, 331, 
+	331, 45, 40, 288, 289, 283, 283, 283, 
+	329, 283, 283, 291, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 292, 283, 58, 332, 283, 40, 288, 
+	289, 283, 283, 283, 297, 283, 333, 333, 
+	283, 40, 288, 289, 283, 283, 283, 297, 
+	283, 334, 283, 283, 335, 288, 289, 283, 
+	288, 289, 283, 336, 283, 288, 337, 283, 
+	288, 338, 283, 288, 283, 334, 283, 283, 
+	283, 288, 289, 283, 339, 283, 340, 341, 
+	283, 40, 288, 289, 283, 283, 43, 283, 
+	42, 283, 333, 333, 283, 40, 288, 289, 
+	283, 333, 333, 283, 40, 288, 289, 283, 
+	339, 283, 333, 333, 283, 40, 288, 289, 
+	283, 339, 283, 340, 333, 283, 40, 288, 
+	289, 283, 283, 43, 283, 58, 283, 342, 
+	342, 45, 40, 288, 289, 283, 283, 283, 
+	297, 283, 343, 67, 344, 345, 48, 40, 
+	288, 289, 283, 283, 283, 297, 283, 67, 
+	344, 345, 48, 40, 288, 289, 283, 283, 
+	283, 297, 283, 344, 344, 48, 40, 288, 
+	289, 283, 283, 283, 297, 283, 346, 64, 
+	347, 348, 51, 40, 288, 289, 283, 283, 
+	283, 297, 283, 64, 347, 348, 51, 40, 
+	288, 289, 283, 283, 283, 297, 283, 347, 
+	347, 51, 40, 288, 289, 283, 283, 283, 
+	297, 283, 349, 61, 350, 351, 54, 40, 
+	288, 289, 283, 283, 283, 297, 283, 61, 
+	350, 351, 54, 40, 288, 289, 283, 283, 
+	283, 297, 283, 350, 350, 54, 40, 288, 
+	289, 283, 283, 283, 297, 283, 352, 58, 
+	333, 353, 283, 40, 288, 289, 283, 283, 
+	283, 297, 283, 58, 333, 353, 283, 40, 
+	288, 289, 283, 283, 283, 297, 283, 333, 
+	354, 283, 40, 288, 289, 283, 283, 283, 
+	297, 283, 58, 283, 333, 333, 283, 40, 
+	288, 289, 283, 283, 283, 297, 283, 41, 
+	42, 283, 283, 58, 332, 283, 40, 288, 
+	289, 283, 283, 283, 297, 283, 41, 283, 
+	326, 331, 331, 45, 40, 288, 289, 283, 
+	283, 283, 329, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 292, 283, 326, 331, 331, 
+	45, 40, 288, 289, 283, 283, 283, 329, 
+	283, 325, 326, 331, 331, 45, 40, 288, 
+	289, 283, 283, 283, 329, 283, 283, 291, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 292, 283, 325, 
+	326, 327, 331, 45, 40, 288, 289, 283, 
+	283, 69, 329, 283, 283, 291, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 292, 283, 323, 283, 355, 
+	283, 342, 342, 45, 40, 288, 289, 283, 
+	283, 283, 297, 283, 323, 283, 323, 283, 
+	283, 283, 333, 333, 283, 40, 288, 289, 
+	283, 283, 283, 297, 283, 323, 283, 323, 
+	283, 283, 283, 333, 356, 283, 40, 288, 
+	289, 283, 283, 283, 297, 283, 323, 283, 
+	323, 283, 355, 283, 333, 333, 283, 40, 
+	288, 289, 283, 283, 283, 297, 283, 323, 
+	283, 323, 42, 283, 283, 58, 324, 283, 
+	40, 288, 289, 283, 283, 283, 297, 283, 
+	323, 283, 316, 317, 322, 322, 45, 40, 
+	288, 289, 283, 283, 283, 320, 283, 283, 
+	291, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 292, 283, 
+	316, 317, 318, 322, 45, 40, 288, 289, 
+	283, 283, 71, 320, 283, 283, 291, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 292, 283, 314, 283, 
+	357, 283, 342, 342, 45, 40, 288, 289, 
+	283, 283, 283, 297, 283, 314, 283, 314, 
+	283, 283, 283, 333, 333, 283, 40, 288, 
+	289, 283, 283, 283, 297, 283, 314, 283, 
+	314, 283, 283, 283, 333, 358, 283, 40, 
+	288, 289, 283, 283, 283, 297, 283, 314, 
+	283, 314, 283, 357, 283, 333, 333, 283, 
+	40, 288, 289, 283, 283, 283, 297, 283, 
+	314, 283, 314, 42, 283, 283, 58, 315, 
+	283, 40, 288, 289, 283, 283, 283, 297, 
+	283, 314, 283, 307, 308, 313, 313, 45, 
+	40, 288, 289, 283, 283, 283, 311, 283, 
+	283, 291, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 292, 
+	283, 307, 308, 309, 313, 45, 40, 288, 
+	289, 283, 283, 73, 311, 283, 283, 291, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 292, 283, 305, 
+	283, 359, 283, 342, 342, 45, 40, 288, 
+	289, 283, 283, 283, 297, 283, 305, 283, 
+	305, 283, 283, 283, 333, 333, 283, 40, 
+	288, 289, 283, 283, 283, 297, 283, 305, 
+	283, 305, 283, 283, 283, 333, 360, 283, 
+	40, 288, 289, 283, 283, 283, 297, 283, 
+	305, 283, 305, 283, 359, 283, 333, 333, 
+	283, 40, 288, 289, 283, 283, 283, 297, 
+	283, 305, 283, 305, 42, 283, 283, 58, 
+	306, 283, 40, 288, 289, 283, 283, 283, 
+	297, 283, 305, 283, 298, 299, 304, 304, 
+	45, 40, 288, 289, 283, 283, 283, 302, 
+	283, 283, 291, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	292, 283, 298, 299, 300, 304, 45, 40, 
+	288, 289, 283, 283, 75, 302, 283, 283, 
+	291, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 283, 292, 283, 
+	295, 283, 361, 283, 342, 342, 45, 40, 
+	288, 289, 283, 283, 283, 297, 283, 295, 
+	283, 295, 283, 283, 283, 333, 333, 283, 
+	40, 288, 289, 283, 283, 283, 297, 283, 
+	295, 283, 295, 283, 283, 283, 333, 362, 
+	283, 40, 288, 289, 283, 283, 283, 297, 
+	283, 295, 283, 295, 283, 361, 283, 333, 
+	333, 283, 40, 288, 289, 283, 283, 283, 
+	297, 283, 295, 283, 76, 44, 44, 45, 
+	40, 283, 283, 283, 283, 283, 76, 283, 
+	295, 42, 283, 283, 58, 296, 283, 40, 
+	288, 289, 283, 283, 283, 297, 283, 295, 
+	283, 284, 285, 294, 287, 45, 40, 288, 
+	289, 283, 283, 283, 290, 283, 283, 291, 
+	283, 283, 283, 283, 283, 283, 283, 283, 
+	283, 283, 283, 283, 283, 292, 283, 364, 
+	191, 365, 365, 84, 79, 194, 195, 363, 
+	363, 363, 197, 363, 363, 200, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 202, 363, 191, 365, 365, 
+	84, 79, 194, 195, 363, 363, 363, 197, 
+	363, 363, 200, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	202, 363, 366, 363, 363, 363, 98, 367, 
+	363, 79, 194, 195, 363, 363, 363, 368, 
+	363, 366, 363, 369, 370, 371, 372, 84, 
+	79, 194, 195, 363, 363, 115, 373, 363, 
+	363, 200, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 202, 
+	363, 374, 370, 375, 375, 84, 79, 194, 
+	195, 363, 363, 363, 373, 363, 363, 200, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 202, 363, 370, 
+	375, 375, 84, 79, 194, 195, 363, 363, 
+	363, 373, 363, 363, 200, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 202, 363, 376, 363, 363, 363, 
+	98, 377, 363, 79, 194, 195, 363, 363, 
+	363, 368, 363, 376, 363, 378, 379, 380, 
+	381, 84, 79, 194, 195, 363, 363, 113, 
+	382, 363, 363, 200, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 202, 363, 383, 379, 384, 384, 84, 
+	79, 194, 195, 363, 363, 363, 382, 363, 
+	363, 200, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 202, 
+	363, 379, 384, 384, 84, 79, 194, 195, 
+	363, 363, 363, 382, 363, 363, 200, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 202, 363, 385, 363, 
+	363, 363, 98, 386, 363, 79, 194, 195, 
+	363, 363, 363, 368, 363, 385, 363, 387, 
+	388, 389, 390, 84, 79, 194, 195, 363, 
+	363, 111, 391, 363, 363, 200, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 202, 363, 392, 388, 393, 
+	393, 84, 79, 194, 195, 363, 363, 363, 
+	391, 363, 363, 200, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 202, 363, 388, 393, 393, 84, 79, 
+	194, 195, 363, 363, 363, 391, 363, 363, 
+	200, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 202, 363, 
+	394, 363, 363, 363, 98, 395, 363, 79, 
+	194, 195, 363, 363, 363, 368, 363, 394, 
+	363, 396, 397, 398, 399, 84, 79, 194, 
+	195, 363, 363, 109, 400, 363, 363, 200, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 202, 363, 401, 
+	397, 402, 402, 84, 79, 194, 195, 363, 
+	363, 363, 400, 363, 363, 200, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 202, 363, 397, 402, 402, 
+	84, 79, 194, 195, 363, 363, 363, 400, 
+	363, 363, 200, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	202, 363, 98, 403, 363, 79, 194, 195, 
+	363, 363, 363, 368, 363, 404, 404, 363, 
+	79, 194, 195, 363, 363, 363, 368, 363, 
+	405, 363, 363, 406, 194, 195, 363, 194, 
+	195, 363, 407, 363, 194, 408, 363, 194, 
+	409, 363, 194, 363, 405, 363, 363, 363, 
+	194, 195, 363, 410, 363, 411, 412, 363, 
+	79, 194, 195, 363, 363, 82, 363, 81, 
+	363, 404, 404, 363, 79, 194, 195, 363, 
+	404, 404, 363, 79, 194, 195, 363, 410, 
+	363, 404, 404, 363, 79, 194, 195, 363, 
+	410, 363, 411, 404, 363, 79, 194, 195, 
+	363, 363, 82, 363, 98, 363, 413, 413, 
+	84, 79, 194, 195, 363, 363, 363, 368, 
+	363, 414, 107, 415, 416, 88, 79, 194, 
+	195, 363, 363, 363, 368, 363, 107, 415, 
+	416, 88, 79, 194, 195, 363, 363, 363, 
+	368, 363, 415, 415, 88, 79, 194, 195, 
+	363, 363, 363, 368, 363, 417, 104, 418, 
+	419, 91, 79, 194, 195, 363, 363, 363, 
+	368, 363, 104, 418, 419, 91, 79, 194, 
+	195, 363, 363, 363, 368, 363, 418, 418, 
+	91, 79, 194, 195, 363, 363, 363, 368, 
+	363, 420, 101, 421, 422, 94, 79, 194, 
+	195, 363, 363, 363, 368, 363, 101, 421, 
+	422, 94, 79, 194, 195, 363, 363, 363, 
+	368, 363, 421, 421, 94, 79, 194, 195, 
+	363, 363, 363, 368, 363, 423, 98, 404, 
+	424, 363, 79, 194, 195, 363, 363, 363, 
+	368, 363, 98, 404, 424, 363, 79, 194, 
+	195, 363, 363, 363, 368, 363, 404, 425, 
+	363, 79, 194, 195, 363, 363, 363, 368, 
+	363, 98, 363, 404, 404, 363, 79, 194, 
+	195, 363, 363, 363, 368, 363, 80, 81, 
+	363, 363, 98, 403, 363, 79, 194, 195, 
+	363, 363, 363, 368, 363, 80, 363, 397, 
+	402, 402, 84, 79, 194, 195, 363, 363, 
+	363, 400, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 202, 363, 397, 402, 402, 84, 
+	79, 194, 195, 363, 363, 363, 400, 363, 
+	396, 397, 402, 402, 84, 79, 194, 195, 
+	363, 363, 363, 400, 363, 363, 200, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 202, 363, 396, 397, 
+	398, 402, 84, 79, 194, 195, 363, 363, 
+	109, 400, 363, 363, 200, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 202, 363, 394, 363, 426, 363, 
+	413, 413, 84, 79, 194, 195, 363, 363, 
+	363, 368, 363, 394, 363, 394, 363, 363, 
+	363, 404, 404, 363, 79, 194, 195, 363, 
+	363, 363, 368, 363, 394, 363, 394, 363, 
+	363, 363, 404, 427, 363, 79, 194, 195, 
+	363, 363, 363, 368, 363, 394, 363, 394, 
+	363, 426, 363, 404, 404, 363, 79, 194, 
+	195, 363, 363, 363, 368, 363, 394, 363, 
+	394, 81, 363, 363, 98, 395, 363, 79, 
+	194, 195, 363, 363, 363, 368, 363, 394, 
+	363, 387, 388, 393, 393, 84, 79, 194, 
+	195, 363, 363, 363, 391, 363, 363, 200, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 202, 363, 387, 
+	388, 389, 393, 84, 79, 194, 195, 363, 
+	363, 111, 391, 363, 363, 200, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 202, 363, 385, 363, 428, 
+	363, 413, 413, 84, 79, 194, 195, 363, 
+	363, 363, 368, 363, 385, 363, 385, 363, 
+	363, 363, 404, 404, 363, 79, 194, 195, 
+	363, 363, 363, 368, 363, 385, 363, 385, 
+	363, 363, 363, 404, 429, 363, 79, 194, 
+	195, 363, 363, 363, 368, 363, 385, 363, 
+	385, 363, 428, 363, 404, 404, 363, 79, 
+	194, 195, 363, 363, 363, 368, 363, 385, 
+	363, 385, 81, 363, 363, 98, 386, 363, 
+	79, 194, 195, 363, 363, 363, 368, 363, 
+	385, 363, 378, 379, 384, 384, 84, 79, 
+	194, 195, 363, 363, 363, 382, 363, 363, 
+	200, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 202, 363, 
+	378, 379, 380, 384, 84, 79, 194, 195, 
+	363, 363, 113, 382, 363, 363, 200, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 202, 363, 376, 363, 
+	430, 363, 413, 413, 84, 79, 194, 195, 
+	363, 363, 363, 368, 363, 376, 363, 376, 
+	363, 363, 363, 404, 404, 363, 79, 194, 
+	195, 363, 363, 363, 368, 363, 376, 363, 
+	376, 363, 363, 363, 404, 431, 363, 79, 
+	194, 195, 363, 363, 363, 368, 363, 376, 
+	363, 376, 363, 430, 363, 404, 404, 363, 
+	79, 194, 195, 363, 363, 363, 368, 363, 
+	376, 363, 376, 81, 363, 363, 98, 377, 
+	363, 79, 194, 195, 363, 363, 363, 368, 
+	363, 376, 363, 369, 370, 375, 375, 84, 
+	79, 194, 195, 363, 363, 363, 373, 363, 
+	363, 200, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 202, 
+	363, 369, 370, 371, 375, 84, 79, 194, 
+	195, 363, 363, 115, 373, 363, 363, 200, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 202, 363, 366, 
+	363, 432, 363, 413, 413, 84, 79, 194, 
+	195, 363, 363, 363, 368, 363, 366, 363, 
+	366, 363, 363, 363, 404, 404, 363, 79, 
+	194, 195, 363, 363, 363, 368, 363, 366, 
+	363, 366, 363, 363, 363, 404, 433, 363, 
+	79, 194, 195, 363, 363, 363, 368, 363, 
+	366, 363, 366, 363, 432, 363, 404, 404, 
+	363, 79, 194, 195, 363, 363, 363, 368, 
+	363, 366, 363, 366, 81, 363, 363, 98, 
+	367, 363, 79, 194, 195, 363, 363, 363, 
+	368, 363, 366, 363, 116, 83, 83, 84, 
+	79, 434, 434, 434, 434, 156, 116, 434, 
+	190, 191, 365, 365, 84, 79, 194, 195, 
+	363, 363, 363, 197, 363, 363, 200, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 363, 363, 363, 202, 363, 116, 83, 
+	83, 84, 79, 434, 434, 434, 434, 434, 
+	116, 434, 436, 437, 438, 439, 123, 118, 
+	440, 441, 435, 435, 155, 442, 435, 435, 
+	443, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 444, 435, 
+	445, 437, 439, 439, 123, 118, 440, 441, 
+	435, 435, 435, 442, 435, 435, 443, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 444, 435, 437, 439, 
+	439, 123, 118, 440, 441, 435, 435, 435, 
+	442, 435, 435, 443, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 444, 435, 446, 435, 435, 435, 136, 
+	447, 435, 118, 440, 441, 435, 435, 435, 
+	448, 435, 446, 435, 449, 450, 451, 452, 
+	123, 118, 440, 441, 435, 435, 153, 453, 
+	435, 435, 443, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	444, 435, 454, 450, 455, 455, 123, 118, 
+	440, 441, 435, 435, 435, 453, 435, 435, 
+	443, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 444, 435, 
+	450, 455, 455, 123, 118, 440, 441, 435, 
+	435, 435, 453, 435, 435, 443, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 444, 435, 456, 435, 435, 
+	435, 136, 457, 435, 118, 440, 441, 435, 
+	435, 435, 448, 435, 456, 435, 458, 459, 
+	460, 461, 123, 118, 440, 441, 435, 435, 
+	151, 462, 435, 435, 443, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 444, 435, 463, 459, 464, 464, 
+	123, 118, 440, 441, 435, 435, 435, 462, 
+	435, 435, 443, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	444, 435, 459, 464, 464, 123, 118, 440, 
+	441, 435, 435, 435, 462, 435, 435, 443, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 444, 435, 465, 
+	435, 435, 435, 136, 466, 435, 118, 440, 
+	441, 435, 435, 435, 448, 435, 465, 435, 
+	467, 468, 469, 470, 123, 118, 440, 441, 
+	435, 435, 149, 471, 435, 435, 443, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 444, 435, 472, 468, 
+	473, 473, 123, 118, 440, 441, 435, 435, 
+	435, 471, 435, 435, 443, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 444, 435, 468, 473, 473, 123, 
+	118, 440, 441, 435, 435, 435, 471, 435, 
+	435, 443, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 444, 
+	435, 474, 435, 435, 435, 136, 475, 435, 
+	118, 440, 441, 435, 435, 435, 448, 435, 
+	474, 435, 476, 477, 478, 479, 123, 118, 
+	440, 441, 435, 435, 147, 480, 435, 435, 
+	443, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 444, 435, 
+	481, 477, 482, 482, 123, 118, 440, 441, 
+	435, 435, 435, 480, 435, 435, 443, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 444, 435, 477, 482, 
+	482, 123, 118, 440, 441, 435, 435, 435, 
+	480, 435, 435, 443, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 444, 435, 136, 483, 435, 118, 440, 
+	441, 435, 435, 435, 448, 435, 484, 484, 
+	435, 118, 440, 441, 435, 435, 435, 448, 
+	435, 485, 435, 435, 486, 440, 441, 435, 
+	440, 441, 435, 487, 435, 440, 488, 435, 
+	440, 489, 435, 440, 435, 485, 435, 435, 
+	435, 440, 441, 435, 490, 435, 491, 492, 
+	435, 118, 440, 441, 435, 435, 121, 435, 
+	120, 435, 484, 484, 435, 118, 440, 441, 
+	435, 484, 484, 435, 118, 440, 441, 435, 
+	490, 435, 484, 484, 435, 118, 440, 441, 
+	435, 490, 435, 491, 484, 435, 118, 440, 
+	441, 435, 435, 121, 435, 136, 435, 493, 
+	493, 123, 118, 440, 441, 435, 435, 435, 
+	448, 435, 494, 145, 495, 496, 126, 118, 
+	440, 441, 435, 435, 435, 448, 435, 145, 
+	495, 496, 126, 118, 440, 441, 435, 435, 
+	435, 448, 435, 495, 495, 126, 118, 440, 
+	441, 435, 435, 435, 448, 435, 497, 142, 
+	498, 499, 129, 118, 440, 441, 435, 435, 
+	435, 448, 435, 142, 498, 499, 129, 118, 
+	440, 441, 435, 435, 435, 448, 435, 498, 
+	498, 129, 118, 440, 441, 435, 435, 435, 
+	448, 435, 500, 139, 501, 502, 132, 118, 
+	440, 441, 435, 435, 435, 448, 435, 139, 
+	501, 502, 132, 118, 440, 441, 435, 435, 
+	435, 448, 435, 501, 501, 132, 118, 440, 
+	441, 435, 435, 435, 448, 435, 503, 136, 
+	484, 504, 435, 118, 440, 441, 435, 435, 
+	435, 448, 435, 136, 484, 504, 435, 118, 
+	440, 441, 435, 435, 435, 448, 435, 484, 
+	505, 435, 118, 440, 441, 435, 435, 435, 
+	448, 435, 136, 435, 484, 484, 435, 118, 
+	440, 441, 435, 435, 435, 448, 435, 119, 
+	120, 435, 435, 136, 483, 435, 118, 440, 
+	441, 435, 435, 435, 448, 435, 119, 435, 
+	477, 482, 482, 123, 118, 440, 441, 435, 
+	435, 435, 480, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 444, 435, 477, 482, 482, 
+	123, 118, 440, 441, 435, 435, 435, 480, 
+	435, 476, 477, 482, 482, 123, 118, 440, 
+	441, 435, 435, 435, 480, 435, 435, 443, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 444, 435, 476, 
+	477, 478, 482, 123, 118, 440, 441, 435, 
+	435, 147, 480, 435, 435, 443, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 444, 435, 474, 435, 506, 
+	435, 493, 493, 123, 118, 440, 441, 435, 
+	435, 435, 448, 435, 474, 435, 474, 435, 
+	435, 435, 484, 484, 435, 118, 440, 441, 
+	435, 435, 435, 448, 435, 474, 435, 474, 
+	435, 435, 435, 484, 507, 435, 118, 440, 
+	441, 435, 435, 435, 448, 435, 474, 435, 
+	474, 435, 506, 435, 484, 484, 435, 118, 
+	440, 441, 435, 435, 435, 448, 435, 474, 
+	435, 474, 120, 435, 435, 136, 475, 435, 
+	118, 440, 441, 435, 435, 435, 448, 435, 
+	474, 435, 467, 468, 473, 473, 123, 118, 
+	440, 441, 435, 435, 435, 471, 435, 435, 
+	443, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 444, 435, 
+	467, 468, 469, 473, 123, 118, 440, 441, 
+	435, 435, 149, 471, 435, 435, 443, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 444, 435, 465, 435, 
+	508, 435, 493, 493, 123, 118, 440, 441, 
+	435, 435, 435, 448, 435, 465, 435, 465, 
+	435, 435, 435, 484, 484, 435, 118, 440, 
+	441, 435, 435, 435, 448, 435, 465, 435, 
+	465, 435, 435, 435, 484, 509, 435, 118, 
+	440, 441, 435, 435, 435, 448, 435, 465, 
+	435, 465, 435, 508, 435, 484, 484, 435, 
+	118, 440, 441, 435, 435, 435, 448, 435, 
+	465, 435, 465, 120, 435, 435, 136, 466, 
+	435, 118, 440, 441, 435, 435, 435, 448, 
+	435, 465, 435, 458, 459, 464, 464, 123, 
+	118, 440, 441, 435, 435, 435, 462, 435, 
+	435, 443, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 444, 
+	435, 458, 459, 460, 464, 123, 118, 440, 
+	441, 435, 435, 151, 462, 435, 435, 443, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 444, 435, 456, 
+	435, 510, 435, 493, 493, 123, 118, 440, 
+	441, 435, 435, 435, 448, 435, 456, 435, 
+	456, 435, 435, 435, 484, 484, 435, 118, 
+	440, 441, 435, 435, 435, 448, 435, 456, 
+	435, 456, 435, 435, 435, 484, 511, 435, 
+	118, 440, 441, 435, 435, 435, 448, 435, 
+	456, 435, 456, 435, 510, 435, 484, 484, 
+	435, 118, 440, 441, 435, 435, 435, 448, 
+	435, 456, 435, 456, 120, 435, 435, 136, 
+	457, 435, 118, 440, 441, 435, 435, 435, 
+	448, 435, 456, 435, 449, 450, 455, 455, 
+	123, 118, 440, 441, 435, 435, 435, 453, 
+	435, 435, 443, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	444, 435, 449, 450, 451, 455, 123, 118, 
+	440, 441, 435, 435, 153, 453, 435, 435, 
+	443, 435, 435, 435, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 444, 435, 
+	446, 435, 512, 435, 493, 493, 123, 118, 
+	440, 441, 435, 435, 435, 448, 435, 446, 
+	435, 446, 435, 435, 435, 484, 484, 435, 
+	118, 440, 441, 435, 435, 435, 448, 435, 
+	446, 435, 446, 435, 435, 435, 484, 513, 
+	435, 118, 440, 441, 435, 435, 435, 448, 
+	435, 446, 435, 446, 435, 512, 435, 484, 
+	484, 435, 118, 440, 441, 435, 435, 435, 
+	448, 435, 446, 435, 446, 120, 435, 435, 
+	136, 447, 435, 118, 440, 441, 435, 435, 
+	435, 448, 435, 446, 435, 436, 437, 439, 
+	439, 123, 118, 440, 441, 435, 435, 435, 
+	442, 435, 435, 443, 435, 435, 435, 435, 
+	435, 435, 435, 435, 435, 435, 435, 435, 
+	435, 444, 435, 188, 189, 190, 191, 514, 
+	365, 84, 79, 194, 195, 196, 196, 156, 
+	197, 363, 188, 200, 363, 363, 363, 363, 
+	363, 363, 363, 363, 363, 363, 363, 363, 
+	363, 202, 363, 204, 515, 206, 207, 6, 
+	1, 208, 209, 203, 203, 38, 210, 203, 
+	203, 211, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 212, 
+	203, 215, 189, 190, 191, 516, 517, 84, 
+	157, 518, 519, 203, 196, 156, 520, 203, 
+	215, 200, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 202, 
+	203, 116, 521, 521, 84, 157, 208, 209, 
+	203, 203, 156, 522, 203, 523, 203, 203, 
+	524, 518, 519, 203, 518, 519, 203, 256, 
+	203, 518, 525, 203, 518, 526, 203, 518, 
+	203, 523, 203, 203, 203, 518, 519, 203, 
+	527, 3, 363, 363, 404, 433, 363, 79, 
+	194, 195, 363, 363, 363, 368, 363, 527, 
+	363, 528, 370, 529, 530, 84, 157, 518, 
+	519, 203, 203, 158, 373, 203, 203, 200, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 202, 203, 531, 
+	370, 532, 532, 84, 157, 518, 519, 203, 
+	203, 203, 373, 203, 203, 200, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 202, 203, 370, 532, 532, 
+	84, 157, 518, 519, 203, 203, 203, 373, 
+	203, 203, 200, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	202, 203, 528, 370, 532, 532, 84, 157, 
+	518, 519, 203, 203, 203, 373, 203, 203, 
+	200, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 203, 203, 202, 203, 
+	528, 370, 529, 532, 84, 157, 518, 519, 
+	203, 203, 158, 373, 203, 203, 200, 203, 
+	203, 203, 203, 203, 203, 203, 203, 203, 
+	203, 203, 203, 203, 202, 203, 215, 203, 
+	281, 116, 533, 533, 160, 157, 208, 209, 
+	203, 203, 203, 522, 203, 215, 203, 534, 
+	184, 535, 536, 162, 157, 518, 519, 203, 
+	203, 203, 537, 203, 184, 535, 536, 162, 
+	157, 518, 519, 203, 203, 203, 537, 203, 
+	535, 535, 162, 157, 518, 519, 203, 203, 
+	203, 537, 203, 538, 181, 539, 540, 165, 
+	157, 518, 519, 203, 203, 203, 537, 203, 
+	181, 539, 540, 165, 157, 518, 519, 203, 
+	203, 203, 537, 203, 539, 539, 165, 157, 
+	518, 519, 203, 203, 203, 537, 203, 541, 
+	178, 542, 543, 168, 157, 518, 519, 203, 
+	203, 203, 537, 203, 178, 542, 543, 168, 
+	157, 518, 519, 203, 203, 203, 537, 203, 
+	542, 542, 168, 157, 518, 519, 203, 203, 
+	203, 537, 203, 544, 175, 545, 546, 203, 
+	157, 518, 519, 203, 203, 203, 537, 203, 
+	175, 545, 546, 203, 157, 518, 519, 203, 
+	203, 203, 537, 203, 545, 545, 203, 157, 
+	518, 519, 203, 203, 203, 537, 203, 547, 
+	203, 548, 549, 203, 157, 518, 519, 203, 
+	203, 172, 203, 171, 203, 545, 545, 203, 
+	157, 518, 519, 203, 545, 545, 203, 157, 
+	518, 519, 203, 547, 203, 545, 545, 203, 
+	157, 518, 519, 203, 547, 203, 548, 545, 
+	203, 157, 518, 519, 203, 203, 172, 203, 
+	527, 171, 363, 363, 98, 367, 363, 79, 
+	194, 195, 363, 363, 363, 368, 363, 527, 
+	363, 551, 550, 552, 552, 550, 186, 553, 
+	554, 550, 552, 552, 550, 186, 553, 554, 
+	550, 555, 550, 550, 556, 553, 554, 550, 
+	553, 554, 550, 557, 550, 553, 558, 550, 
+	553, 559, 550, 553, 550, 555, 550, 550, 
+	550, 553, 554, 550, 0
 };
 
 static const short _indic_syllable_machine_trans_targs[] = {
-	170, 199, 201, 202, 3, 205, 4, 6, 
-	208, 7, 9, 211, 10, 12, 214, 13, 
-	15, 16, 191, 18, 19, 213, 21, 22, 
-	210, 24, 25, 207, 216, 221, 225, 228, 
-	232, 235, 239, 242, 246, 249, 170, 279, 
-	281, 282, 39, 285, 40, 42, 288, 43, 
-	45, 291, 46, 48, 294, 49, 51, 52, 
-	271, 54, 55, 293, 57, 58, 290, 60, 
-	61, 287, 296, 301, 305, 308, 312, 315, 
-	319, 322, 326, 330, 170, 358, 360, 361, 
-	75, 364, 170, 76, 78, 367, 79, 81, 
-	370, 82, 84, 373, 85, 87, 88, 350, 
-	90, 91, 372, 93, 94, 369, 96, 97, 
-	366, 375, 380, 384, 387, 391, 394, 398, 
-	401, 405, 170, 439, 441, 442, 110, 445, 
-	111, 113, 448, 114, 116, 451, 117, 119, 
-	454, 120, 122, 123, 431, 125, 126, 453, 
-	128, 129, 450, 131, 132, 447, 456, 461, 
-	465, 468, 472, 475, 479, 482, 486, 489, 
-	409, 505, 146, 508, 148, 511, 149, 151, 
-	514, 152, 154, 517, 155, 520, 522, 523, 
-	159, 160, 519, 162, 163, 516, 165, 166, 
-	513, 168, 169, 510, 170, 171, 251, 331, 
-	333, 408, 410, 351, 353, 354, 411, 407, 
-	490, 491, 378, 526, 379, 170, 172, 174, 
-	35, 250, 192, 194, 195, 248, 219, 220, 
-	173, 34, 175, 244, 0, 176, 178, 33, 
-	243, 241, 177, 32, 179, 237, 180, 182, 
-	31, 236, 234, 181, 30, 183, 230, 184, 
-	186, 29, 229, 227, 185, 28, 187, 223, 
-	188, 190, 27, 222, 218, 189, 26, 204, 
-	193, 198, 170, 196, 197, 200, 1, 203, 
-	2, 206, 5, 23, 209, 8, 20, 212, 
-	11, 17, 215, 14, 217, 224, 226, 231, 
-	233, 238, 240, 245, 247, 170, 252, 254, 
-	71, 328, 272, 274, 275, 329, 299, 300, 
-	253, 70, 255, 324, 36, 256, 258, 69, 
-	323, 321, 257, 68, 259, 317, 260, 262, 
-	67, 316, 314, 261, 66, 263, 310, 264, 
-	266, 65, 309, 307, 265, 64, 267, 303, 
-	268, 270, 63, 302, 298, 269, 62, 284, 
-	273, 278, 170, 276, 277, 280, 37, 283, 
-	38, 286, 41, 59, 289, 44, 56, 292, 
-	47, 53, 295, 50, 297, 304, 306, 311, 
-	313, 318, 320, 325, 327, 170, 332, 106, 
-	334, 403, 72, 335, 337, 105, 402, 400, 
-	336, 104, 338, 396, 339, 341, 103, 395, 
-	393, 340, 102, 342, 389, 343, 345, 101, 
-	388, 386, 344, 100, 346, 382, 347, 349, 
-	99, 381, 377, 348, 98, 363, 352, 357, 
-	170, 355, 356, 359, 73, 362, 74, 365, 
-	77, 95, 368, 80, 92, 371, 83, 89, 
-	374, 86, 376, 383, 385, 390, 392, 397, 
-	399, 404, 406, 170, 170, 412, 414, 142, 
-	141, 432, 434, 435, 488, 459, 460, 413, 
-	415, 484, 107, 416, 418, 140, 483, 481, 
-	417, 139, 419, 477, 420, 422, 138, 476, 
-	474, 421, 137, 423, 470, 424, 426, 136, 
-	469, 467, 425, 135, 427, 463, 428, 430, 
-	134, 462, 458, 429, 133, 444, 433, 438, 
-	170, 436, 437, 440, 108, 443, 109, 446, 
-	112, 130, 449, 115, 127, 452, 118, 124, 
-	455, 121, 457, 464, 466, 471, 473, 478, 
-	480, 485, 487, 143, 492, 493, 507, 498, 
-	500, 501, 525, 494, 495, 496, 144, 506, 
-	497, 499, 504, 502, 503, 145, 509, 147, 
-	167, 156, 512, 150, 164, 515, 153, 161, 
-	518, 158, 521, 157, 524, 170, 527, 528, 
-	530, 531, 529, 534, 170, 532, 533
+	178, 200, 207, 209, 210, 4, 213, 5, 
+	7, 216, 8, 10, 219, 11, 13, 222, 
+	14, 16, 17, 199, 19, 20, 221, 22, 
+	23, 218, 25, 26, 215, 224, 229, 233, 
+	236, 240, 243, 247, 250, 254, 257, 178, 
+	280, 287, 289, 290, 41, 293, 42, 44, 
+	296, 45, 47, 299, 48, 50, 302, 51, 
+	53, 54, 279, 56, 57, 301, 59, 60, 
+	298, 62, 63, 295, 304, 309, 313, 316, 
+	320, 323, 327, 330, 334, 338, 178, 359, 
+	366, 368, 369, 78, 372, 178, 79, 81, 
+	375, 82, 84, 378, 85, 87, 381, 88, 
+	90, 91, 358, 93, 94, 380, 96, 97, 
+	377, 99, 100, 374, 383, 388, 392, 395, 
+	399, 402, 406, 409, 413, 178, 440, 447, 
+	449, 450, 114, 453, 115, 117, 456, 118, 
+	120, 459, 121, 123, 462, 124, 126, 127, 
+	439, 129, 130, 461, 132, 133, 458, 135, 
+	136, 455, 464, 469, 473, 476, 480, 483, 
+	487, 490, 494, 497, 417, 502, 513, 152, 
+	516, 154, 519, 155, 157, 522, 158, 160, 
+	525, 161, 528, 530, 531, 166, 167, 527, 
+	169, 170, 524, 172, 173, 521, 175, 176, 
+	518, 178, 536, 178, 179, 259, 339, 341, 
+	416, 418, 361, 362, 419, 415, 498, 499, 
+	386, 534, 387, 178, 180, 182, 36, 258, 
+	202, 203, 256, 227, 228, 181, 35, 183, 
+	252, 1, 184, 186, 34, 251, 249, 185, 
+	33, 187, 245, 188, 190, 32, 244, 242, 
+	189, 31, 191, 238, 192, 194, 30, 237, 
+	235, 193, 29, 195, 231, 196, 198, 28, 
+	230, 226, 197, 27, 212, 0, 201, 206, 
+	178, 204, 205, 208, 2, 211, 3, 214, 
+	6, 24, 217, 9, 21, 220, 12, 18, 
+	223, 15, 225, 232, 234, 239, 241, 246, 
+	248, 253, 255, 178, 260, 262, 73, 336, 
+	282, 283, 337, 307, 308, 261, 72, 263, 
+	332, 38, 264, 266, 71, 331, 329, 265, 
+	70, 267, 325, 268, 270, 69, 324, 322, 
+	269, 68, 271, 318, 272, 274, 67, 317, 
+	315, 273, 66, 275, 311, 276, 278, 65, 
+	310, 306, 277, 64, 292, 37, 281, 286, 
+	178, 284, 285, 288, 39, 291, 40, 294, 
+	43, 61, 297, 46, 58, 300, 49, 55, 
+	303, 52, 305, 312, 314, 319, 321, 326, 
+	328, 333, 335, 178, 340, 109, 342, 411, 
+	75, 343, 345, 108, 410, 408, 344, 107, 
+	346, 404, 347, 349, 106, 403, 401, 348, 
+	105, 350, 397, 351, 353, 104, 396, 394, 
+	352, 103, 354, 390, 355, 357, 102, 389, 
+	385, 356, 101, 371, 74, 360, 365, 178, 
+	363, 364, 367, 76, 370, 77, 373, 80, 
+	98, 376, 83, 95, 379, 86, 92, 382, 
+	89, 384, 391, 393, 398, 400, 405, 407, 
+	412, 414, 178, 178, 420, 422, 146, 145, 
+	442, 443, 496, 467, 468, 421, 423, 492, 
+	111, 424, 426, 144, 491, 489, 425, 143, 
+	427, 485, 428, 430, 142, 484, 482, 429, 
+	141, 431, 478, 432, 434, 140, 477, 475, 
+	433, 139, 435, 471, 436, 438, 138, 470, 
+	466, 437, 137, 452, 110, 441, 446, 178, 
+	444, 445, 448, 112, 451, 113, 454, 116, 
+	134, 457, 119, 131, 460, 122, 128, 463, 
+	125, 465, 472, 474, 479, 481, 486, 488, 
+	493, 495, 147, 500, 501, 515, 504, 505, 
+	533, 148, 509, 503, 508, 506, 507, 510, 
+	511, 150, 514, 512, 149, 151, 517, 153, 
+	174, 163, 520, 156, 171, 523, 159, 168, 
+	526, 162, 165, 529, 164, 532, 178, 535, 
+	177, 538, 539, 537, 542, 178, 540, 541
 };
 
 static const char _indic_syllable_machine_trans_actions[] = {
-	1, 2, 0, 0, 0, 2, 0, 0, 
+	1, 0, 2, 2, 2, 0, 2, 0, 
+	0, 2, 0, 0, 2, 0, 0, 2, 
+	0, 0, 0, 2, 0, 0, 2, 0, 
+	0, 2, 0, 0, 2, 2, 2, 2, 
+	2, 2, 2, 2, 2, 2, 2, 3, 
+	0, 2, 2, 2, 0, 2, 0, 0, 
 	2, 0, 0, 2, 0, 0, 2, 0, 
 	0, 0, 2, 0, 0, 2, 0, 0, 
 	2, 0, 0, 2, 2, 2, 2, 2, 
-	2, 2, 2, 2, 2, 2, 3, 2, 
-	0, 0, 0, 2, 0, 0, 2, 0, 
+	2, 2, 2, 2, 2, 2, 4, 0, 
+	2, 2, 2, 0, 2, 5, 0, 0, 
+	2, 0, 0, 2, 0, 0, 2, 0, 
+	0, 0, 2, 0, 0, 2, 0, 0, 
+	2, 0, 0, 2, 2, 6, 2, 6, 
+	2, 6, 2, 6, 2, 7, 0, 2, 
+	2, 2, 0, 2, 0, 0, 2, 0, 
 	0, 2, 0, 0, 2, 0, 0, 0, 
 	2, 0, 0, 2, 0, 0, 2, 0, 
 	0, 2, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 2, 4, 2, 0, 0, 
-	0, 2, 5, 0, 0, 2, 0, 0, 
-	2, 0, 0, 2, 0, 0, 0, 2, 
+	2, 2, 2, 2, 6, 0, 8, 0, 
+	2, 0, 2, 0, 0, 2, 0, 0, 
+	2, 0, 2, 2, 2, 0, 0, 2, 
 	0, 0, 2, 0, 0, 2, 0, 0, 
-	2, 2, 6, 2, 6, 2, 6, 2, 
-	6, 2, 7, 2, 0, 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, 2, 2, 
-	2, 2, 2, 2, 2, 2, 2, 2, 
-	6, 8, 0, 2, 0, 2, 0, 0, 
-	2, 0, 0, 2, 0, 2, 0, 0, 
-	0, 0, 2, 0, 0, 2, 0, 0, 
-	2, 0, 0, 2, 11, 2, 2, 6, 
-	2, 12, 12, 0, 0, 0, 2, 2, 
-	6, 2, 6, 0, 6, 13, 2, 2, 
-	0, 2, 0, 0, 0, 2, 2, 2, 
-	2, 0, 2, 2, 0, 2, 2, 0, 
-	2, 2, 2, 0, 2, 2, 2, 2, 
-	0, 2, 2, 2, 0, 2, 2, 2, 
-	2, 0, 2, 2, 2, 0, 2, 2, 
-	2, 2, 0, 2, 2, 2, 0, 2, 
-	0, 0, 14, 0, 0, 0, 0, 2, 
-	0, 2, 0, 0, 2, 0, 0, 2, 
-	0, 0, 2, 0, 2, 2, 2, 2, 
-	2, 2, 2, 2, 2, 15, 2, 2, 
-	0, 2, 0, 0, 0, 2, 2, 2, 
-	2, 0, 2, 2, 0, 2, 2, 0, 
-	2, 2, 2, 0, 2, 2, 2, 2, 
-	0, 2, 2, 2, 0, 2, 2, 2, 
-	2, 0, 2, 2, 2, 0, 2, 2, 
-	2, 2, 0, 2, 2, 2, 0, 2, 
-	0, 0, 16, 0, 0, 0, 0, 2, 
-	0, 2, 0, 0, 2, 0, 0, 2, 
-	0, 0, 2, 0, 2, 2, 2, 2, 
-	2, 2, 2, 2, 2, 17, 6, 0, 
-	6, 6, 0, 6, 2, 0, 6, 2, 
-	6, 0, 6, 6, 6, 2, 0, 6, 
-	2, 6, 0, 6, 6, 6, 2, 0, 
-	6, 2, 6, 0, 6, 6, 6, 2, 
-	0, 6, 2, 6, 0, 6, 0, 0, 
-	18, 0, 0, 0, 0, 2, 0, 2, 
-	0, 0, 2, 0, 0, 2, 0, 0, 
-	2, 0, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 19, 20, 2, 2, 0, 
-	0, 0, 0, 0, 2, 2, 2, 2, 
-	2, 2, 0, 2, 2, 0, 2, 2, 
+	2, 9, 0, 12, 2, 2, 6, 2, 
+	13, 13, 0, 0, 2, 2, 6, 2, 
+	6, 2, 6, 14, 2, 2, 0, 2, 
+	0, 0, 2, 2, 2, 2, 0, 2, 
+	2, 0, 2, 2, 0, 2, 2, 2, 
+	0, 2, 2, 2, 2, 0, 2, 2, 
 	2, 0, 2, 2, 2, 2, 0, 2, 
 	2, 2, 0, 2, 2, 2, 2, 0, 
-	2, 2, 2, 0, 2, 2, 2, 2, 
-	0, 2, 2, 2, 0, 2, 0, 0, 
-	21, 0, 0, 0, 0, 2, 0, 2, 
+	2, 2, 2, 0, 2, 0, 0, 0, 
+	15, 0, 0, 2, 0, 2, 0, 2, 
 	0, 0, 2, 0, 0, 2, 0, 0, 
 	2, 0, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 0, 0, 8, 2, 0, 
-	0, 0, 2, 2, 8, 8, 0, 8, 
-	8, 0, 0, 0, 0, 0, 2, 0, 
+	2, 2, 2, 16, 2, 2, 0, 2, 
+	0, 0, 2, 2, 2, 2, 0, 2, 
+	2, 0, 2, 2, 0, 2, 2, 2, 
+	0, 2, 2, 2, 2, 0, 2, 2, 
+	2, 0, 2, 2, 2, 2, 0, 2, 
+	2, 2, 0, 2, 2, 2, 2, 0, 
+	2, 2, 2, 0, 2, 0, 0, 0, 
+	17, 0, 0, 2, 0, 2, 0, 2, 
 	0, 0, 2, 0, 0, 2, 0, 0, 
-	2, 0, 0, 0, 2, 22, 0, 0, 
-	0, 0, 0, 0, 23, 0, 0
+	2, 0, 2, 2, 2, 2, 2, 2, 
+	2, 2, 2, 18, 6, 0, 6, 6, 
+	0, 6, 2, 0, 6, 2, 6, 0, 
+	6, 6, 6, 2, 0, 6, 2, 6, 
+	0, 6, 6, 6, 2, 0, 6, 2, 
+	6, 0, 6, 6, 6, 2, 0, 6, 
+	2, 6, 0, 6, 0, 0, 0, 19, 
+	0, 0, 2, 0, 2, 0, 2, 0, 
+	0, 2, 0, 0, 2, 0, 0, 2, 
+	0, 2, 2, 2, 2, 2, 2, 2, 
+	2, 2, 20, 21, 2, 2, 0, 0, 
+	0, 0, 2, 2, 2, 2, 2, 2, 
+	0, 2, 2, 0, 2, 2, 2, 0, 
+	2, 2, 2, 2, 0, 2, 2, 2, 
+	0, 2, 2, 2, 2, 0, 2, 2, 
+	2, 0, 2, 2, 2, 2, 0, 2, 
+	2, 2, 0, 2, 0, 0, 0, 22, 
+	0, 0, 2, 0, 2, 0, 2, 0, 
+	0, 2, 0, 0, 2, 0, 0, 2, 
+	0, 2, 2, 2, 2, 2, 2, 2, 
+	2, 2, 0, 0, 8, 2, 0, 0, 
+	2, 0, 2, 0, 0, 0, 0, 8, 
+	8, 0, 8, 8, 0, 0, 2, 0, 
+	0, 0, 2, 0, 0, 2, 0, 0, 
+	2, 0, 0, 2, 0, 2, 23, 2, 
+	0, 0, 0, 0, 0, 24, 0, 0
 };
 
 static const char _indic_syllable_machine_to_state_actions[] = {
@@ -1331,75 +1354,6 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 9, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0
-};
-
-static const char _indic_syllable_machine_from_state_actions[] = {
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 10, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
@@ -1449,88 +1403,160 @@
 	0, 0, 0, 0, 0, 0, 0
 };
 
+static const char _indic_syllable_machine_from_state_actions[] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 11, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0
+};
+
 static const short _indic_syllable_machine_eof_trans[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 39, 39, 39, 39, 
-	39, 39, 39, 39, 39, 39, 39, 39, 
-	39, 39, 39, 39, 39, 39, 39, 39, 
-	39, 39, 39, 39, 39, 39, 39, 39, 
-	39, 39, 39, 39, 39, 39, 39, 39, 
-	77, 77, 77, 83, 83, 77, 77, 77, 
-	77, 77, 77, 77, 77, 77, 77, 77, 
-	77, 77, 77, 77, 77, 77, 77, 77, 
-	77, 77, 77, 77, 77, 77, 77, 77, 
-	83, 77, 77, 115, 115, 115, 115, 115, 
-	115, 115, 115, 115, 115, 115, 115, 115, 
-	115, 115, 115, 115, 115, 115, 115, 115, 
-	115, 115, 115, 115, 115, 115, 115, 115, 
-	115, 115, 115, 115, 115, 115, 115, 77, 
+	1, 1, 1, 1, 1, 40, 40, 40, 
+	40, 40, 40, 40, 40, 40, 40, 40, 
+	40, 40, 40, 40, 40, 40, 40, 40, 
+	40, 40, 40, 40, 40, 40, 40, 40, 
+	40, 40, 40, 40, 40, 40, 40, 40, 
+	40, 40, 79, 79, 79, 79, 86, 86, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 79, 79, 
+	79, 79, 79, 79, 79, 79, 118, 118, 
+	118, 118, 118, 118, 118, 118, 118, 118, 
+	118, 118, 118, 118, 118, 118, 118, 118, 
+	118, 118, 118, 118, 118, 118, 118, 118, 
+	118, 118, 118, 118, 118, 118, 118, 118, 
+	118, 118, 118, 79, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 0, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 278, 278, 278, 278, 278, 
-	278, 278, 278, 278, 278, 278, 278, 278, 
-	278, 278, 278, 278, 278, 278, 278, 278, 
-	278, 278, 278, 278, 278, 278, 278, 278, 
-	278, 278, 278, 278, 278, 278, 278, 278, 
-	278, 278, 278, 278, 278, 278, 278, 278, 
-	278, 278, 278, 278, 278, 278, 278, 278, 
-	278, 278, 278, 278, 278, 278, 278, 278, 
-	278, 278, 278, 278, 278, 278, 278, 278, 
-	278, 278, 278, 278, 278, 278, 278, 278, 
-	278, 278, 278, 358, 358, 358, 358, 358, 
-	358, 358, 358, 358, 358, 358, 358, 358, 
-	358, 358, 358, 358, 358, 358, 358, 358, 
-	358, 358, 358, 358, 358, 358, 358, 358, 
-	358, 358, 358, 358, 358, 358, 358, 358, 
-	358, 358, 358, 358, 358, 358, 358, 358, 
-	358, 358, 358, 358, 358, 358, 358, 358, 
-	358, 358, 358, 358, 358, 358, 358, 358, 
-	358, 358, 358, 358, 358, 358, 358, 358, 
-	358, 358, 358, 358, 358, 358, 358, 358, 
-	428, 358, 428, 429, 429, 429, 429, 429, 
-	429, 429, 429, 429, 429, 429, 429, 429, 
-	429, 429, 429, 429, 429, 429, 429, 429, 
-	429, 429, 429, 429, 429, 429, 429, 429, 
-	429, 429, 429, 429, 429, 429, 429, 429, 
-	429, 429, 429, 429, 429, 429, 429, 429, 
-	429, 429, 429, 429, 429, 429, 429, 429, 
-	429, 429, 429, 429, 429, 429, 429, 429, 
-	429, 429, 429, 429, 429, 429, 429, 429, 
-	429, 429, 429, 429, 429, 429, 429, 429, 
-	429, 429, 358, 198, 198, 198, 358, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 198, 198, 198, 
-	198, 198, 198, 198, 198, 358, 542, 542, 
-	542, 542, 542, 542, 542, 542, 542
+	1, 186, 0, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 284, 284, 284, 284, 284, 
+	284, 284, 284, 284, 284, 284, 284, 284, 
+	284, 284, 284, 284, 284, 284, 284, 284, 
+	284, 284, 284, 284, 284, 284, 284, 284, 
+	284, 284, 284, 284, 284, 284, 284, 284, 
+	284, 284, 284, 284, 284, 284, 284, 284, 
+	284, 284, 284, 284, 284, 284, 284, 284, 
+	284, 284, 284, 284, 284, 284, 284, 284, 
+	284, 284, 284, 284, 284, 284, 284, 284, 
+	284, 284, 284, 284, 284, 284, 284, 284, 
+	284, 284, 284, 364, 364, 364, 364, 364, 
+	364, 364, 364, 364, 364, 364, 364, 364, 
+	364, 364, 364, 364, 364, 364, 364, 364, 
+	364, 364, 364, 364, 364, 364, 364, 364, 
+	364, 364, 364, 364, 364, 364, 364, 364, 
+	364, 364, 364, 364, 364, 364, 364, 364, 
+	364, 364, 364, 364, 364, 364, 364, 364, 
+	364, 364, 364, 364, 364, 364, 364, 364, 
+	364, 364, 364, 364, 364, 364, 364, 364, 
+	364, 364, 364, 364, 364, 364, 364, 364, 
+	435, 364, 435, 436, 436, 436, 436, 436, 
+	436, 436, 436, 436, 436, 436, 436, 436, 
+	436, 436, 436, 436, 436, 436, 436, 436, 
+	436, 436, 436, 436, 436, 436, 436, 436, 
+	436, 436, 436, 436, 436, 436, 436, 436, 
+	436, 436, 436, 436, 436, 436, 436, 436, 
+	436, 436, 436, 436, 436, 436, 436, 436, 
+	436, 436, 436, 436, 436, 436, 436, 436, 
+	436, 436, 436, 436, 436, 436, 436, 436, 
+	436, 436, 436, 436, 436, 436, 436, 436, 
+	436, 436, 364, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 364, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 204, 204, 204, 
+	204, 204, 204, 204, 204, 364, 551, 551, 
+	551, 551, 551, 551, 551, 551, 551
 };
 
-static const int indic_syllable_machine_start = 170;
-static const int indic_syllable_machine_first_final = 170;
+static const int indic_syllable_machine_start = 178;
+static const int indic_syllable_machine_first_final = 178;
 static const int indic_syllable_machine_error = -1;
 
-static const int indic_syllable_machine_en_main = 170;
+static const int indic_syllable_machine_en_main = 178;
 
 
-#line 36 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 36 "hb-ot-shape-complex-indic-machine.rl"
 
 
 
-#line 97 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 97 "hb-ot-shape-complex-indic-machine.rl"
 
 
 #define found_syllable(syllable_type) \
@@ -1550,7 +1576,7 @@
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 1554 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1580 "hb-ot-shape-complex-indic-machine.hh"
 	{
 	cs = indic_syllable_machine_start;
 	ts = 0;
@@ -1558,7 +1584,7 @@
 	act = 0;
 	}
 
-#line 118 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 118 "hb-ot-shape-complex-indic-machine.rl"
 
 
   p = 0;
@@ -1567,7 +1593,7 @@
   unsigned int last = 0;
   unsigned int syllable_serial = 1;
   
-#line 1571 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1597 "hb-ot-shape-complex-indic-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -1577,11 +1603,11 @@
 		goto _test_eof;
 _resume:
 	switch ( _indic_syllable_machine_from_state_actions[cs] ) {
-	case 10:
+	case 11:
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 1585 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1611 "hb-ot-shape-complex-indic-machine.hh"
 	}
 
 	_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -1603,68 +1629,72 @@
 #line 1 "NONE"
 	{te = p+1;}
 	break;
-	case 14:
-#line 88 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 15:
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (consonant_syllable); }}
 	break;
-	case 16:
-#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 17:
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (vowel_syllable); }}
 	break;
-	case 21:
-#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 22:
+#line 90 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (standalone_cluster); }}
 	break;
-	case 23:
-#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 24:
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (symbol_cluster); }}
 	break;
-	case 18:
-#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 19:
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (broken_cluster); }}
 	break;
-	case 11:
-#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 12:
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (non_indic_cluster); }}
 	break;
-	case 13:
-#line 88 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 14:
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (consonant_syllable); }}
 	break;
-	case 15:
-#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 16:
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (vowel_syllable); }}
 	break;
-	case 20:
-#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 21:
+#line 90 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (standalone_cluster); }}
 	break;
-	case 22:
-#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 23:
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (symbol_cluster); }}
 	break;
-	case 17:
-#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 18:
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (broken_cluster); }}
 	break;
-	case 19:
-#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 20:
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (non_indic_cluster); }}
 	break;
 	case 1:
-#line 88 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
 	break;
 	case 3:
-#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
 	break;
 	case 7:
-#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 90 "hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
 	break;
+	case 9:
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
+	{{p = ((te))-1;}{ found_syllable (symbol_cluster); }}
+	break;
 	case 4:
-#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
 	break;
 	case 5:
@@ -1685,31 +1715,31 @@
 	case 8:
 #line 1 "NONE"
 	{te = p+1;}
-#line 88 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
 	{act = 1;}
 	break;
 	case 6:
 #line 1 "NONE"
 	{te = p+1;}
-#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
 	{act = 5;}
 	break;
-	case 12:
+	case 13:
 #line 1 "NONE"
 	{te = p+1;}
-#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
 	{act = 6;}
 	break;
-#line 1704 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1734 "hb-ot-shape-complex-indic-machine.hh"
 	}
 
 _again:
 	switch ( _indic_syllable_machine_to_state_actions[cs] ) {
-	case 9:
+	case 10:
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 1713 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1743 "hb-ot-shape-complex-indic-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -1725,7 +1755,7 @@
 
 	}
 
-#line 127 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 127 "hb-ot-shape-complex-indic-machine.rl"
 
 }
 
diff --git a/src/hb-ot-shape-complex-indic-private.hh b/src/hb-ot-shape-complex-indic-private.hh
index d8dfc65..326b364 100644
--- a/src/hb-ot-shape-complex-indic-private.hh
+++ b/src/hb-ot-shape-complex-indic-private.hh
@@ -109,27 +109,31 @@
 
   INDIC_SYLLABIC_CATEGORY_AVAGRAHA			= OT_Symbol,
   INDIC_SYLLABIC_CATEGORY_BINDU				= OT_SM,
-  INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER		= OT_PLACEHOLDER, /* TODO */
+  INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER		= OT_PLACEHOLDER, /* Don't care. */
   INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK		= OT_A,
   INDIC_SYLLABIC_CATEGORY_CONSONANT			= OT_C,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD		= OT_C,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL		= OT_CM,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER		= OT_C,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER		= OT_M, /* U+17CD only. */
   INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL		= OT_CM,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER		= OT_PLACEHOLDER,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA	= OT_Repha,
+  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_Repha, /* TODO */
   INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK		= OT_SM,
-  INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER		= OT_H, /* TODO */
+  INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER		= OT_Coeng,
   INDIC_SYLLABIC_CATEGORY_JOINER			= OT_ZWJ,
   INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER		= OT_X,
   INDIC_SYLLABIC_CATEGORY_NON_JOINER			= OT_ZWNJ,
   INDIC_SYLLABIC_CATEGORY_NUKTA				= OT_N,
   INDIC_SYLLABIC_CATEGORY_NUMBER			= OT_PLACEHOLDER,
-  INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER			= OT_PLACEHOLDER, /* TODO */
-  INDIC_SYLLABIC_CATEGORY_PURE_KILLER			= OT_H, /* TODO */
+  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_TONE_LETTER			= OT_X,
   INDIC_SYLLABIC_CATEGORY_TONE_MARK			= OT_N,
   INDIC_SYLLABIC_CATEGORY_VIRAMA			= OT_H,
@@ -161,20 +165,24 @@
   INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT		= POS_PRE_M
 };
 
-/* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation
- * because gcc fails to optimize the latter and fills the table in at runtime. */
 #define INDIC_COMBINE_CATEGORIES(S,M) \
-  (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || \
-			    ( \
-			     S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
-			     S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
-			     S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
-			     S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
-			     S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
-			     S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
-			     false)) + \
-   ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
-   ((M << 8) | S))
+  ( \
+    ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+    ( S | \
+     ( \
+      ( \
+       S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
+       S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
+       S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
+       S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
+       S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
+       S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
+       false \
+       ? M : INDIC_MATRA_CATEGORY_NOT_APPLICABLE \
+      ) << 8 \
+     ) \
+    ) \
+   )
 
 HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
 hb_indic_get_categories (hb_codepoint_t u);
diff --git a/src/hb-ot-shape-complex-indic-table.cc b/src/hb-ot-shape-complex-indic-table.cc
index 2e159a1..90abb55 100644
--- a/src/hb-ot-shape-complex-indic-table.cc
+++ b/src/hb-ot-shape-complex-indic-table.cc
@@ -6,63 +6,67 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-7.0.0.txt
- * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
- * # IndicMatraCategory-7.0.0.txt
- * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
- * # Blocks-7.0.0.txt
- * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
+ * # IndicSyllabicCategory-8.0.0.txt
+ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
+ * # IndicPositionalCategory-8.0.0.txt
+ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
+ * # Blocks-8.0.0.txt
+ * # Date: 2014-11-10, 23:04:00 GMT [KW]
  */
 
 #include "hb-ot-shape-complex-indic-private.hh"
 
 
 #define ISC_A	INDIC_SYLLABIC_CATEGORY_AVAGRAHA		/*  13 chars; Avagraha */
-#define ISC_Bi	INDIC_SYLLABIC_CATEGORY_BINDU			/*  59 chars; Bindu */
+#define ISC_Bi	INDIC_SYLLABIC_CATEGORY_BINDU			/*  60 chars; Bindu */
 #define ISC_BJN	INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER	/*  20 chars; Brahmi_Joining_Number */
-#define ISC_Ca	INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK	/*  30 chars; Cantillation_Mark */
-#define ISC_C	INDIC_SYLLABIC_CATEGORY_CONSONANT		/* 1744 chars; Consonant */
+#define ISC_Ca	INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK	/*  52 chars; Cantillation_Mark */
+#define ISC_C	INDIC_SYLLABIC_CATEGORY_CONSONANT		/* 1805 chars; Consonant */
 #define ISC_CD	INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD		/*   7 chars; Consonant_Dead */
-#define ISC_CF	INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL		/*  61 chars; Consonant_Final */
+#define ISC_CF	INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL		/*  62 chars; Consonant_Final */
 #define ISC_CHL	INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER	/*   5 chars; Consonant_Head_Letter */
-#define ISC_CM	INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL	/*  19 chars; Consonant_Medial */
-#define ISC_CP	INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER	/*  11 chars; Consonant_Placeholder */
+#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	/*  13 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	/*  61 chars; Consonant_Subjoined */
 #define ISC_CSR	INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA	/*   4 chars; Consonant_Succeeding_Repha */
+#define ISC_CWS	INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER	/*   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_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			/*  18 chars; Nukta */
-#define ISC_Nd	INDIC_SYLLABIC_CATEGORY_NUMBER			/* 408 chars; Number */
+#define ISC_N	INDIC_SYLLABIC_CATEGORY_NUKTA			/*  23 chars; Nukta */
+#define ISC_Nd	INDIC_SYLLABIC_CATEGORY_NUMBER			/* 420 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		/*  15 chars; Pure_Killer */
-#define ISC_RS	INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER	/*   3 chars; Register_Shifter */
+#define ISC_PK	INDIC_SYLLABIC_CATEGORY_PURE_KILLER		/*  16 chars; Pure_Killer */
+#define ISC_RS	INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER	/*   2 chars; Register_Shifter */
+#define ISC_SM	INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER	/*  20 chars; Syllable_Modifier */
 #define ISC_TL	INDIC_SYLLABIC_CATEGORY_TONE_LETTER		/*   7 chars; Tone_Letter */
-#define ISC_TM	INDIC_SYLLABIC_CATEGORY_TONE_MARK		/*  62 chars; Tone_Mark */
+#define ISC_TM	INDIC_SYLLABIC_CATEGORY_TONE_MARK		/*  42 chars; Tone_Mark */
 #define ISC_V	INDIC_SYLLABIC_CATEGORY_VIRAMA			/*  22 chars; Virama */
 #define ISC_Vs	INDIC_SYLLABIC_CATEGORY_VISARGA			/*  29 chars; Visarga */
 #define ISC_Vo	INDIC_SYLLABIC_CATEGORY_VOWEL			/*  30 chars; Vowel */
-#define ISC_M	INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT		/* 553 chars; Vowel_Dependent */
-#define ISC_VI	INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT	/* 395 chars; Vowel_Independent */
+#define ISC_M	INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT		/* 572 chars; Vowel_Dependent */
+#define ISC_VI	INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT	/* 404 chars; Vowel_Independent */
 
-#define IMC_B	INDIC_MATRA_CATEGORY_BOTTOM			/* 142 chars; Bottom */
+#define IMC_B	INDIC_MATRA_CATEGORY_BOTTOM			/* 256 chars; Bottom */
 #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_L	INDIC_MATRA_CATEGORY_LEFT			/*  55 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			/*   2 chars; Overstruck */
-#define IMC_R	INDIC_MATRA_CATEGORY_RIGHT			/* 163 chars; Right */
-#define IMC_T	INDIC_MATRA_CATEGORY_TOP			/* 169 chars; Top */
+#define IMC_O	INDIC_MATRA_CATEGORY_OVERSTRUCK			/*  10 chars; Overstruck */
+#define IMC_R	INDIC_MATRA_CATEGORY_RIGHT			/* 249 chars; Right */
+#define IMC_T	INDIC_MATRA_CATEGORY_TOP			/* 324 chars; Top */
 #define IMC_TB	INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM		/*  10 chars; Top_And_Bottom */
 #define IMC_TBR	INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT	/*   1 chars; Top_And_Bottom_And_Right */
 #define IMC_TL	INDIC_MATRA_CATEGORY_TOP_AND_LEFT		/*   6 chars; Top_And_Left */
 #define IMC_TLR	INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT	/*   4 chars; Top_And_Left_And_Right */
 #define IMC_TR	INDIC_MATRA_CATEGORY_TOP_AND_RIGHT		/*  13 chars; Top_And_Right */
-#define IMC_VOL	INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT		/*  15 chars; Visual_Order_Left */
+#define IMC_VOL	INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT		/*  19 chars; Visual_Order_Left */
 
 #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
 
@@ -79,29 +83,33 @@
   /* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 0038 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x00d0u 24
+#define indic_offset_0x00b0u 24
 
 
   /* Latin-1 Supplement */
 
+  /* 00B0 */  _(x,x),  _(x,x), _(SM,x), _(SM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 00B8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 00C0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 00C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 00D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CP,x),
 
-#define indic_offset_0x0900u 32
+#define indic_offset_0x0900u 64
 
 
   /* Devanagari */
 
-  /* 0900 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0900 */ _(Bi,T), _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0918 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0920 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0928 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0930 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0938 */  _(C,x),  _(C,x),  _(M,T),  _(M,R),  _(N,x),  _(A,x),  _(M,R),  _(M,L),
+  /* 0938 */  _(C,x),  _(C,x),  _(M,T),  _(M,R),  _(N,B),  _(A,x),  _(M,R),  _(M,L),
   /* 0940 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),
   /* 0948 */  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(V,B),  _(M,L),  _(M,R),
-  /* 0950 */  _(x,x), _(TM,x), _(TM,x),  _(x,x),  _(x,x),  _(M,T),  _(M,B),  _(M,B),
+  /* 0950 */  _(x,x), _(Ca,T), _(Ca,B),  _(x,T),  _(x,T),  _(M,T),  _(M,B),  _(M,B),
   /* 0958 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0960 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
@@ -110,14 +118,14 @@
 
   /* Bengali */
 
-  /* 0980 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0980 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x), _(VI,x),
   /* 0990 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0998 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 09A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 09A8 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 09B0 */  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),
-  /* 09B8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,x),  _(A,x),  _(M,R),  _(M,L),
+  /* 09B8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,L),
   /* 09C0 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(M,L),
   /* 09C8 */  _(M,L),  _(x,x),  _(x,x), _(M,LR), _(M,LR),  _(V,B), _(CD,x),  _(x,x),
   /* 09D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
@@ -129,33 +137,33 @@
 
   /* Gurmukhi */
 
-  /* 0A00 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0A00 */  _(x,x), _(Bi,T), _(Bi,T), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0A08 */ _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x),
   /* 0A10 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0A18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0A20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0A28 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0A30 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),
-  /* 0A38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,x),  _(x,x),  _(M,R),  _(M,L),
+  /* 0A38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(x,x),  _(M,R),  _(M,L),
   /* 0A40 */  _(M,R),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),
   /* 0A48 */  _(M,T),  _(x,x),  _(x,x),  _(M,T),  _(M,T),  _(V,B),  _(x,x),  _(x,x),
   /* 0A50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 0A58 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),
   /* 0A60 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0A70 */ _(Bi,x), _(GM,T), _(CP,x), _(CP,x),  _(x,x), _(CM,x),  _(x,x),  _(x,x),
+  /* 0A70 */ _(Bi,T), _(GM,T), _(CP,x), _(CP,x),  _(x,x), _(CM,B),  _(x,x),  _(x,x),
   /* 0A78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
   /* Gujarati */
 
-  /* 0A80 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0A80 */  _(x,x), _(Bi,T), _(Bi,T), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x),
   /* 0A90 */ _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0A98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0AA0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0AA8 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0AB0 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0AB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,x),  _(A,x),  _(M,R),  _(M,L),
+  /* 0AB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,L),
   /* 0AC0 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,T),  _(x,x),  _(M,T),
   /* 0AC8 */  _(M,T), _(M,TR),  _(x,x),  _(M,R),  _(M,R),  _(V,B),  _(x,x),  _(x,x),
   /* 0AD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -163,18 +171,18 @@
   /* 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),  _(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),
 
   /* Oriya */
 
-  /* 0B00 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0B00 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x), _(VI,x),
   /* 0B10 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0B18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0B20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0B28 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0B30 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0B38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,x),  _(A,x),  _(M,R),  _(M,T),
+  /* 0B38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,T),
   /* 0B40 */  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(M,L),
   /* 0B48 */ _(M,TL),  _(x,x),  _(x,x), _(M,LR),_(M,TLR),  _(V,B),  _(x,x),  _(x,x),
   /* 0B50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T), _(M,TR),
@@ -186,7 +194,7 @@
 
   /* Tamil */
 
-  /* 0B80 */  _(x,x),  _(x,x), _(Bi,x), _(ML,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0B80 */  _(x,x),  _(x,x), _(Bi,T), _(ML,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0B88 */ _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),
   /* 0B90 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(x,x),  _(x,x),
   /* 0B98 */  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),
@@ -194,7 +202,7 @@
   /* 0BA8 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),
   /* 0BB0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0BB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),  _(M,R),
-  /* 0BC0 */  _(M,T),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(M,L),  _(M,L),
+  /* 0BC0 */  _(M,T),  _(M,R),  _(M,R),  _(x,x),  _(x,x),  _(x,x),  _(M,L),  _(M,L),
   /* 0BC8 */  _(M,L),  _(x,x), _(M,LR), _(M,LR), _(M,LR),  _(V,T),  _(x,x),  _(x,x),
   /* 0BD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
   /* 0BD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -205,7 +213,7 @@
 
   /* Telugu */
 
-  /* 0C00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0C00 */ _(Bi,T), _(Bi,R), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
   /* 0C10 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0C18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -216,7 +224,7 @@
   /* 0C40 */  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(x,x),  _(M,T),  _(M,T),
   /* 0C48 */ _(M,TB),  _(x,x),  _(M,T),  _(M,T),  _(M,T),  _(V,T),  _(x,x),  _(x,x),
   /* 0C50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),  _(M,B),  _(x,x),
-  /* 0C58 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0C58 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 0C60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 0C70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -224,26 +232,26 @@
 
   /* Kannada */
 
-  /* 0C80 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0C80 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
   /* 0C90 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0C98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0CA0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0CA8 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0CB0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0CB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,x),  _(A,x),  _(M,R),  _(M,T),
+  /* 0CB8 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,R),  _(M,T),
   /* 0CC0 */ _(M,TR),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(x,x),  _(M,T), _(M,TR),
   /* 0CC8 */ _(M,TR),  _(x,x), _(M,TR), _(M,TR),  _(M,T),  _(V,T),  _(x,x),  _(x,x),
   /* 0CD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),  _(M,R),  _(x,x),
   /* 0CD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(x,x),
   /* 0CE0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 0CF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0CF0 */  _(x,x),_(CWS,x),_(CWS,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 0CF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
   /* Malayalam */
 
-  /* 0D00 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0D00 */  _(x,x), _(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),
@@ -254,7 +262,7 @@
   /* 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),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
-  /* 0D58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0D58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(VI,x),
   /* 0D60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 0D70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -262,7 +270,7 @@
 
   /* Sinhala */
 
-  /* 0D80 */  _(x,x),  _(x,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0D80 */  _(x,x),  _(x,x), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),
   /* 0D98 */  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -278,7 +286,7 @@
   /* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 0DF0 */  _(x,x),  _(x,x),  _(M,R),  _(M,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x1000u 1304
+#define indic_offset_0x1000u 1336
 
 
   /* Myanmar */
@@ -289,22 +297,22 @@
   /* 1018 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1020 */  _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 1028 */ _(VI,x), _(VI,x), _(VI,x),  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,B),
-  /* 1030 */  _(M,B),  _(M,L),  _(M,T),  _(M,T),  _(M,T),  _(M,T), _(Bi,x), _(TM,x),
-  /* 1038 */ _(Vs,x), _(IS,x), _(PK,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x),  _(C,x),
+  /* 1030 */  _(M,B),  _(M,L),  _(M,T),  _(M,T),  _(M,T),  _(M,T), _(Bi,T), _(TM,B),
+  /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R), _(CM,x), _(CM,B), _(CM,B),  _(C,x),
   /* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 1048 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CP,x),  _(x,x),
   /* 1050 */  _(C,x),  _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(M,R),  _(M,R),
-  /* 1058 */  _(M,B),  _(M,B),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CM,x), _(CM,x),
-  /* 1060 */ _(CM,x),  _(C,x),  _(M,R), _(TM,x), _(TM,x),  _(C,x),  _(C,x),  _(M,R),
-  /* 1068 */  _(M,R), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),  _(C,x),  _(C,x),
+  /* 1058 */  _(M,B),  _(M,B),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CM,B), _(CM,B),
+  /* 1060 */ _(CM,B),  _(C,x),  _(M,R), _(TM,R), _(TM,R),  _(C,x),  _(C,x),  _(M,R),
+  /* 1068 */  _(M,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R),  _(C,x),  _(C,x),
   /* 1070 */  _(C,x),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(C,x),  _(C,x),  _(C,x),
   /* 1078 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1080 */  _(C,x),  _(C,x), _(CM,x),  _(M,R),  _(M,L),  _(M,T),  _(M,T), _(TM,x),
-  /* 1088 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),  _(C,x), _(TM,x),
+  /* 1080 */  _(C,x),  _(C,x), _(CM,B),  _(M,R),  _(M,L),  _(M,T),  _(M,T), _(TM,R),
+  /* 1088 */ _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,B),  _(C,x), _(TM,R),
   /* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-  /* 1098 */ _(Nd,x), _(Nd,x), _(TM,x), _(TM,x),  _(M,R),  _(M,T),  _(x,x),  _(x,x),
+  /* 1098 */ _(Nd,x), _(Nd,x), _(TM,R), _(TM,R),  _(M,R),  _(M,T),  _(x,x),  _(x,x),
 
-#define indic_offset_0x1700u 1464
+#define indic_offset_0x1700u 1496
 
 
   /* Tagalog */
@@ -345,14 +353,14 @@
   /* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x),  _(M,R),  _(M,T),
   /* 17B8 */  _(M,T),  _(M,T),  _(M,T),  _(M,B),  _(M,B),  _(M,B), _(M,TL),_(M,TLR),
-  /* 17C0 */ _(M,LR),  _(M,L),  _(M,L),  _(M,L), _(M,LR), _(M,LR), _(Bi,x), _(Vs,x),
-  /* 17C8 */  _(M,R), _(RS,T), _(RS,T), _(RS,T),_(CSR,T),  _(M,T),  _(M,T),  _(M,T),
-  /* 17D0 */  _(M,T), _(PK,T), _(IS,x),  _(M,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 17D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(A,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 17C0 */ _(M,LR),  _(M,L),  _(M,L),  _(M,L), _(M,LR), _(M,LR), _(Bi,T), _(Vs,R),
+  /* 17C8 */  _(M,R), _(RS,T), _(RS,T), _(SM,T),_(CSR,T), _(CK,T), _(SM,T), _(SM,T),
+  /* 17D0 */ _(SM,T), _(PK,T), _(IS,x), _(SM,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 17D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(A,x),  _(x,T),  _(x,x),  _(x,x),
   /* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 17E8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x1900u 1704
+#define indic_offset_0x1900u 1736
 
 
   /* Limbu */
@@ -362,9 +370,9 @@
   /* 1910 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1918 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),
   /* 1920 */  _(M,T),  _(M,T),  _(M,B),  _(M,R),  _(M,R), _(M,TR), _(M,TR),  _(M,T),
-  /* 1928 */  _(M,T), _(CS,x), _(CS,x), _(CS,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1930 */ _(CF,x), _(CF,x), _(Bi,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
-  /* 1938 */ _(CF,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1928 */  _(M,T), _(CS,R), _(CS,R), _(CS,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1930 */ _(CF,R), _(CF,R), _(Bi,B), _(CF,R), _(CF,R), _(CF,R), _(CF,R), _(CF,R),
+  /* 1938 */ _(CF,R), _(CF,B),  _(M,T), _(SM,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1940 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 1948 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
 
@@ -385,10 +393,10 @@
   /* 1998 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 19A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 19A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 19B0 */  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,L),  _(M,L),  _(M,L),
-  /* 19B8 */  _(M,R),  _(M,R),  _(M,L),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),
+  /* 19B0 */  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),_(M,VOL),_(M,VOL),_(M,VOL),
+  /* 19B8 */  _(M,R),  _(M,R),_(M,VOL),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),
   /* 19C0 */  _(M,R), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
-  /* 19C8 */ _(TM,x), _(TM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 19C8 */ _(TM,R), _(TM,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 19D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 19D8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 19E0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -411,47 +419,47 @@
   /* 1A38 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1A40 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1A48 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 1A50 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x), _(CM,L), _(CM,x), _(CF,x),
-  /* 1A58 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),  _(x,x),
+  /* 1A50 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x), _(CM,L), _(CM,B), _(CF,R),
+  /* 1A58 */ _(CF,T), _(CF,T), _(CF,T), _(CF,B), _(CF,B), _(CF,B), _(CF,B),  _(x,x),
   /* 1A60 */ _(IS,x),  _(M,R),  _(M,T),  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,T),
   /* 1A68 */  _(M,T),  _(M,B),  _(M,B),  _(M,T),  _(M,B),  _(M,R),  _(M,L),  _(M,L),
-  /* 1A70 */  _(M,L),  _(M,L),  _(M,L),  _(M,T),  _(M,T), _(TM,x), _(TM,x), _(TM,x),
-  /* 1A78 */ _(TM,x), _(TM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1A70 */  _(M,L),  _(M,L),  _(M,L),  _(M,T),  _(M,T), _(TM,T), _(TM,T), _(TM,T),
+  /* 1A78 */ _(TM,T), _(TM,T), _(SM,T), _(SM,T), _(SM,T),  _(x,x),  _(x,x), _(SM,B),
   /* 1A80 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 1A88 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1A90 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 1A98 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x1b00u 2120
+#define indic_offset_0x1b00u 2152
 
 
   /* Balinese */
 
-  /* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 1B00 */ _(Bi,T), _(Bi,T), _(Bi,T),_(CSR,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x),
   /* 1B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 1B10 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B28 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1B30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(N,x),  _(M,R),  _(M,T),  _(M,T),
+  /* 1B30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(N,T),  _(M,R),  _(M,T),  _(M,T),
   /* 1B38 */  _(M,B),  _(M,B),  _(M,B), _(M,BR), _(M,TB),_(M,TBR),  _(M,L),  _(M,L),
   /* 1B40 */ _(M,LR), _(M,LR),  _(M,T), _(M,TR),  _(V,R),  _(C,x),  _(C,x),  _(C,x),
   /* 1B48 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1B50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 1B58 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1B60 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1B68 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1B70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1B68 */  _(x,x),  _(x,x),  _(x,x),  _(x,T),  _(x,B),  _(x,T),  _(x,T),  _(x,T),
+  /* 1B70 */  _(x,T),  _(x,T),  _(x,T),  _(x,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1B78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
   /* Sundanese */
 
-  /* 1B80 */ _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 1B80 */ _(Bi,T),_(CSR,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 1B88 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B90 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1BA0 */  _(C,x), _(CS,x), _(CS,x), _(CS,x),  _(M,T),  _(M,B),  _(M,L),  _(M,R),
-  /* 1BA8 */  _(M,T),  _(M,T), _(PK,R), _(IS,x), _(CS,x), _(CS,x),  _(C,x),  _(C,x),
+  /* 1BA0 */  _(C,x), _(CS,R), _(CS,B), _(CS,B),  _(M,T),  _(M,B),  _(M,L),  _(M,R),
+  /* 1BA8 */  _(M,T),  _(M,T), _(PK,R), _(IS,x), _(CS,B), _(CS,B),  _(C,x),  _(C,x),
   /* 1BB0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 1BB8 */ _(Nd,x), _(Nd,x),  _(A,x),  _(C,x),  _(C,x),  _(C,x), _(CF,x), _(CF,x),
 
@@ -461,9 +469,9 @@
   /* 1BC8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BD0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BD8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1BE0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x),  _(N,x),  _(M,R),
+  /* 1BE0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x),  _(N,T),  _(M,R),
   /* 1BE8 */  _(M,T),  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,T),  _(M,R),  _(M,T),
-  /* 1BF0 */ _(CF,x), _(CF,x), _(PK,R), _(PK,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1BF0 */ _(CF,T), _(CF,T), _(PK,R), _(PK,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1BF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
   /* Lepcha */
@@ -472,39 +480,49 @@
   /* 1C08 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1C10 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1C18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1C20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CS,x), _(CS,x),  _(M,R),  _(M,L),
-  /* 1C28 */  _(M,L), _(M,TL),  _(M,R),  _(M,R),  _(M,B), _(CF,x), _(CF,x), _(CF,x),
-  /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,L), _(Bi,L),  _(x,x),  _(N,x),
+  /* 1C20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CS,R), _(CS,R),  _(M,R),  _(M,L),
+  /* 1C28 */  _(M,L), _(M,TL),  _(M,R),  _(M,R),  _(M,B), _(CF,T), _(CF,T), _(CF,T),
+  /* 1C30 */ _(CF,T), _(CF,T), _(CF,T), _(CF,T), _(Bi,L), _(Bi,L), _(SM,T),  _(N,B),
   /* 1C38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1C40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 1C48 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
 
-#define indic_offset_0x1cd0u 2456
+#define indic_offset_0x1cd0u 2488
 
 
   /* Vedic Extensions */
 
-  /* 1CD0 */ _(TM,x), _(TM,x), _(TM,x),  _(x,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
-  /* 1CD8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
-  /* 1CE0 */ _(TM,x), _(TM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1CE8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1CF0 */  _(x,x),  _(x,x), _(Vs,x), _(Vs,x), _(TM,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CD0 */ _(Ca,T), _(Ca,T), _(Ca,T),  _(x,x), _(Ca,O), _(Ca,B), _(Ca,B), _(Ca,B),
+  /* 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),
+  /* 1CF8 */ _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x2008u 2496
+#define indic_offset_0x2008u 2536
 
 
   /* General Punctuation */
 
   /* 2008 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),_(ZWNJ,x),_(ZWJ,x),  _(x,x),  _(x,x),
-  /* 2010 */  _(x,x),  _(x,x), _(CP,x), _(CP,x), _(CP,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 2010 */ _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(CP,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0xa800u 2512
+#define indic_offset_0x2070u 2552
+
+
+  /* Superscripts and Subscripts */
+
+  /* 2070 */  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(SM,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 2078 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 2080 */  _(x,x),  _(x,x), _(SM,x), _(SM,x), _(SM,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0xa800u 2576
 
 
   /* Syloti Nagri */
 
   /* A800 */ _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x), _(PK,T),  _(C,x),
-  /* A808 */  _(C,x),  _(C,x),  _(C,x), _(Bi,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* A808 */  _(C,x),  _(C,x),  _(C,x), _(Bi,T),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A810 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A818 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A820 */  _(C,x),  _(C,x),  _(C,x),  _(M,R),  _(M,R),  _(M,B),  _(M,T),  _(M,R),
@@ -525,13 +543,13 @@
 
   /* Saurashtra */
 
-  /* A880 */ _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* A880 */ _(Bi,R), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* A888 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* A890 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A898 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A8A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A8A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* A8B0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CF,x),  _(M,R),  _(M,R),  _(M,R),
+  /* A8B0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CF,R),  _(M,R),  _(M,R),  _(M,R),
   /* A8B8 */  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),
   /* A8C0 */  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(V,B),  _(x,x),  _(x,x),  _(x,x),
   /* A8C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -540,9 +558,9 @@
 
   /* Devanagari Extended */
 
-  /* A8E0 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
-  /* A8E8 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
-  /* A8F0 */ _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 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),
   /* A8F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
   /* Kayah Li */
@@ -552,15 +570,15 @@
   /* A910 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A918 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A920 */  _(C,x),  _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
-  /* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,x), _(TM,x), _(TM,x),  _(x,x),  _(x,x),
+  /* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,B), _(TM,B), _(TM,B),  _(x,x),  _(x,x),
 
   /* Rejang */
 
   /* A930 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A938 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A940 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,B),
-  /* A948 */  _(M,B),  _(M,B),  _(M,T),  _(M,B),  _(M,B),  _(M,B),  _(M,B), _(CF,x),
-  /* A950 */ _(CF,x), _(CF,x), _(CF,x), _(PK,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* A948 */  _(M,B),  _(M,B),  _(M,T),  _(M,B),  _(M,B),  _(M,B),  _(M,B), _(CF,T),
+  /* A950 */ _(CF,T), _(CF,T), _(CF,R), _(PK,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A958 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A960 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A968 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -569,14 +587,14 @@
 
   /* Javanese */
 
-  /* A980 */ _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* A980 */ _(Bi,T), _(Bi,T),_(CSR,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* A988 */ _(VI,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),
   /* A990 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A998 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A9A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A9A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* A9B0 */  _(C,x),  _(C,x),  _(C,x),  _(N,x),  _(M,R),  _(M,R),  _(M,T),  _(M,T),
-  /* A9B8 */  _(M,B),  _(M,B),  _(M,L),  _(M,L),  _(M,T), _(CS,x), _(CM,x), _(CM,x),
+  /* A9B0 */  _(C,x),  _(C,x),  _(C,x),  _(N,T),  _(M,R),  _(M,R),  _(M,T),  _(M,T),
+  /* A9B8 */  _(M,B),  _(M,B),  _(M,L),  _(M,L),  _(M,T), _(CS,R), _(CM,R), _(CM,R),
   /* A9C0 */ _(V,BR),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A9C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A9D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
@@ -584,7 +602,7 @@
 
   /* Myanmar Extended-B */
 
-  /* A9E0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(C,x),
+  /* A9E0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,T),  _(x,x),  _(C,x),
   /* A9E8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* A9F8 */ _(Nd,x), _(Nd,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),
@@ -597,10 +615,10 @@
   /* AA18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AA20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AA28 */  _(C,x),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(M,B),  _(M,T),  _(M,L),
-  /* AA30 */  _(M,L),  _(M,T),  _(M,B), _(CM,x), _(CM,L), _(CM,x), _(CM,x),  _(x,x),
+  /* AA30 */  _(M,L),  _(M,T),  _(M,B), _(CM,R), _(CM,L), _(CM,B), _(CM,B),  _(x,x),
   /* AA38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
-  /* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),  _(x,x),  _(x,x),
+  /* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,T), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
+  /* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,T), _(CF,R),  _(x,x),  _(x,x),
   /* AA50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* AA58 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
@@ -609,7 +627,7 @@
   /* AA60 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AA68 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AA70 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* AA78 */  _(x,x),  _(x,x),  _(C,x), _(TM,x), _(TM,x), _(TM,x),  _(C,x),  _(C,x),
+  /* AA78 */  _(x,x),  _(x,x),  _(C,x), _(TM,R), _(TM,T), _(TM,R),  _(C,x),  _(C,x),
 
   /* Tai Viet */
 
@@ -620,8 +638,8 @@
   /* AAA0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AAA8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AAB0 */  _(M,T),  _(M,R),  _(M,T),  _(M,T),  _(M,B),_(M,VOL),_(M,VOL),  _(M,T),
-  /* AAB8 */  _(M,T),_(M,VOL),  _(M,R),_(M,VOL),_(M,VOL),  _(M,R),  _(M,T), _(TM,x),
-  /* AAC0 */ _(TL,x), _(TM,x), _(TL,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* AAB8 */  _(M,T),_(M,VOL),  _(M,R),_(M,VOL),_(M,VOL),  _(M,R),  _(M,T), _(TM,T),
+  /* AAC0 */ _(TL,x), _(TM,T), _(TL,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* AAC8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* AAD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* AAD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -630,9 +648,9 @@
 
   /* AAE0 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AAE8 */  _(C,x),  _(C,x),  _(C,x),  _(M,L),  _(M,B),  _(M,T),  _(M,L),  _(M,R),
-  /* AAF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Vs,x), _(IS,x),  _(x,x),
+  /* AAF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Vs,R), _(IS,x),  _(x,x),
 
-#define indic_offset_0xabc0u 3272
+#define indic_offset_0xabc0u 3336
 
 
   /* Meetei Mayek */
@@ -642,31 +660,31 @@
   /* ABD0 */  _(C,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* ABD8 */  _(C,x),  _(C,x),  _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
   /* ABE0 */ _(CF,x), _(CF,x), _(CF,x),  _(M,R),  _(M,R),  _(M,T),  _(M,R),  _(M,R),
-  /* ABE8 */  _(M,B),  _(M,R),  _(M,R),  _(x,x), _(TM,x), _(PK,B),  _(x,x),  _(x,x),
+  /* ABE8 */  _(M,B),  _(M,R),  _(M,R),  _(x,x), _(TM,R), _(PK,B),  _(x,x),  _(x,x),
   /* ABF0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* ABF8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x10a00u 3336
+#define indic_offset_0x10a00u 3400
 
 
   /* Kharoshthi */
 
   /* 10A00 */  _(C,x),  _(M,O),  _(M,B),  _(M,B),  _(x,x),  _(M,T),  _(M,O),  _(x,x),
-  /* 10A08 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,B),  _(x,x), _(Bi,x), _(Vs,x),
+  /* 10A08 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,B),  _(M,B), _(Bi,B), _(Vs,T),
   /* 10A10 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
   /* 10A18 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 10A20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 10A28 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 10A30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 10A38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(IS,x),
+  /* 10A38 */  _(N,T),  _(N,B),  _(N,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(IS,x),
   /* 10A40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
 
-#define indic_offset_0x11000u 3408
+#define indic_offset_0x11000u 3472
 
 
   /* Brahmi */
 
-  /* 11000 */ _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11000 */ _(Bi,R), _(Bi,T), _(Vs,R),_(CWS,x),_(CWS,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11008 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11010 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11018 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -685,21 +703,21 @@
 
   /* Kaithi */
 
-  /* 11080 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11080 */ _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11088 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11090 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11098 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 110A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 110A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 110B0 */  _(M,R),  _(M,L),  _(M,R),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,R),
-  /* 110B8 */  _(M,R),  _(V,B),  _(N,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 110B8 */  _(M,R),  _(V,B),  _(N,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x11100u 3600
+#define indic_offset_0x11100u 3664
 
 
   /* Chakma */
 
-  /* 11100 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),
+  /* 11100 */ _(Bi,T), _(Bi,T), _(Vs,T), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),
   /* 11108 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11110 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11118 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -716,12 +734,12 @@
   /* 11158 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11160 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11168 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 11170 */  _(C,x),  _(C,x),  _(C,x),  _(N,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11170 */  _(C,x),  _(C,x),  _(C,x),  _(N,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 11178 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
   /* Sharada */
 
-  /* 11180 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11180 */ _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11188 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11190 */ _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11198 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -729,8 +747,8 @@
   /* 111A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 111B0 */  _(C,x),  _(C,x),  _(C,x),  _(M,R),  _(M,L),  _(M,R),  _(M,B),  _(M,B),
   /* 111B8 */  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T), _(M,TR),
-  /* 111C0 */  _(V,R),  _(A,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 111C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 111C0 */  _(V,R),  _(A,x),_(CPrf,x),_(CPrf,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 111C8 */  _(x,x),  _(x,x),  _(N,x),  _(M,T),  _(M,B),  _(x,x),  _(x,x),  _(x,x),
   /* 111D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 111D8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
@@ -749,11 +767,20 @@
   /* 11218 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11220 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11228 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,R),  _(M,R),  _(M,R),  _(M,B),
-  /* 11230 */  _(M,T),  _(M,T), _(M,TR), _(M,TR), _(Bi,x),  _(V,R),  _(N,x), _(GM,T),
+  /* 11230 */  _(M,T),  _(M,T), _(M,TR), _(M,TR), _(Bi,T),  _(V,R),  _(N,T), _(GM,T),
 
-#define indic_offset_0x112b0u 3912
+#define indic_offset_0x11280u 3976
 
 
+  /* Multani */
+
+  /* 11280 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),
+  /* 11288 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),
+  /* 11290 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11298 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),
+  /* 112A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 112A8 */  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
   /* Khudawadi */
 
   /* 112B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -761,15 +788,15 @@
   /* 112C0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 112C8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 112D0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 112D8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(Bi,x),
+  /* 112D8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(Bi,T),
   /* 112E0 */  _(M,R),  _(M,L),  _(M,R),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),
-  /* 112E8 */  _(M,T),  _(N,x), _(PK,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 112E8 */  _(M,T),  _(N,B), _(PK,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 112F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 112F8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
   /* Grantha */
 
-  /* 11300 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11300 */ _(Bi,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11308 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x), _(VI,x),
   /* 11310 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11318 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -781,11 +808,11 @@
   /* 11348 */  _(M,L),  _(x,x),  _(x,x), _(M,LR), _(M,LR),  _(V,R),  _(x,x),  _(x,x),
   /* 11350 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
   /* 11358 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 11360 */ _(VI,x), _(VI,x),  _(M,R),  _(M,R),  _(x,x),  _(x,x), _(Ca,x), _(Ca,x),
-  /* 11368 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 11370 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11360 */ _(VI,x), _(VI,x),  _(M,R),  _(M,R),  _(x,x),  _(x,x), _(Ca,T), _(Ca,T),
+  /* 11368 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),  _(x,x),  _(x,x),  _(x,x),
+  /* 11370 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x11480u 4112
+#define indic_offset_0x11480u 4224
 
 
   /* Tirhuta */
@@ -797,13 +824,13 @@
   /* 114A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 114A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 114B0 */  _(M,R),  _(M,L),  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,B),
-  /* 114B8 */  _(M,B),  _(M,L),  _(M,T), _(M,TL), _(M,LR),  _(M,R), _(M,LR), _(Bi,x),
-  /* 114C0 */ _(Bi,x), _(Vs,x),  _(V,B),  _(N,x),  _(A,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 114B8 */  _(M,B),  _(M,L),  _(M,T), _(M,TL), _(M,LR),  _(M,R), _(M,LR), _(Bi,T),
+  /* 114C0 */ _(Bi,T), _(Vs,R),  _(V,B),  _(N,B),  _(A,x),  _(x,x),  _(x,x),  _(x,x),
   /* 114C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 114D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 114D8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x11580u 4208
+#define indic_offset_0x11580u 4320
 
 
   /* Siddham */
@@ -815,11 +842,15 @@
   /* 115A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 115A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,R),
   /* 115B0 */  _(M,L),  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(x,x),  _(x,x),
-  /* 115B8 */  _(M,L), _(M,TL), _(M,LR),_(M,TLR), _(Bi,x), _(Bi,x), _(Vs,x),  _(V,B),
-  /* 115C0 */  _(N,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-#define indic_offset_0x11600u 4280
-
+  /* 115B8 */  _(M,L), _(M,TL), _(M,LR),_(M,TLR), _(Bi,T), _(Bi,T), _(Vs,R),  _(V,B),
+  /* 115C0 */  _(N,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 115C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 115D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 115D8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x),
+  /* 115E0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 115E8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 115F0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 115F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
   /* Modi */
 
@@ -830,8 +861,8 @@
   /* 11620 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11628 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11630 */  _(M,R),  _(M,R),  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,B),
-  /* 11638 */  _(M,B),  _(M,T),  _(M,T),  _(M,R),  _(M,R), _(Bi,x), _(Vs,x),  _(V,B),
-  /* 11640 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11638 */  _(M,B),  _(M,T),  _(M,T),  _(M,R),  _(M,R), _(Bi,T), _(Vs,R),  _(V,B),
+  /* 11640 */  _(M,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 11648 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 11650 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 11658 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -847,13 +878,30 @@
   /* 11690 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11698 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 116A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 116A8 */  _(C,x),  _(C,x),  _(C,x), _(Bi,x), _(Vs,x),  _(M,T),  _(M,L),  _(M,R),
-  /* 116B0 */  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(V,T),  _(N,x),
+  /* 116A8 */  _(C,x),  _(C,x),  _(C,x), _(Bi,T), _(Vs,R),  _(M,T),  _(M,L),  _(M,R),
+  /* 116B0 */  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(V,R),  _(N,B),
   /* 116B8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 116C0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 116C8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 116D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 116D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 116E0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 116E8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 116F0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 116F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-}; /* Table items: 4488; occupancy: 73% */
+  /* Ahom */
+
+  /* 11700 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11708 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11710 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11718 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x), _(CM,B), _(CM,x), _(CM,T),
+  /* 11720 */  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,B),  _(M,B),  _(M,L),  _(M,T),
+  /* 11728 */  _(M,B),  _(M,T),  _(M,T), _(PK,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11730 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 11738 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+}; /* Table items: 4768; occupancy: 72% */
 
 INDIC_TABLE_ELEMENT_TYPE
 hb_indic_get_categories (hb_codepoint_t u)
@@ -862,7 +910,7 @@
   {
     case 0x0u:
       if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
-      if (hb_in_range (u, 0x00D0u, 0x00D7u)) return indic_table[u - 0x00D0u + indic_offset_0x00d0u];
+      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 (unlikely (u == 0x00A0u)) return _(CP,x);
       break;
@@ -872,11 +920,12 @@
       if (hb_in_range (u, 0x1700u, 0x17EFu)) return indic_table[u - 0x1700u + indic_offset_0x1700u];
       if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return indic_table[u - 0x1900u + indic_offset_0x1900u];
       if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return indic_table[u - 0x1B00u + indic_offset_0x1b00u];
-      if (hb_in_range (u, 0x1CD0u, 0x1CF7u)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+      if (hb_in_range (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 (unlikely (u == 0x25CCu)) return _(CP,x);
       break;
 
@@ -892,10 +941,9 @@
     case 0x11u:
       if (hb_in_range (u, 0x11000u, 0x110BFu)) return indic_table[u - 0x11000u + indic_offset_0x11000u];
       if (hb_in_range (u, 0x11100u, 0x11237u)) return indic_table[u - 0x11100u + indic_offset_0x11100u];
-      if (hb_in_range (u, 0x112B0u, 0x11377u)) return indic_table[u - 0x112B0u + indic_offset_0x112b0u];
+      if (hb_in_range (u, 0x11280u, 0x11377u)) return indic_table[u - 0x11280u + indic_offset_0x11280u];
       if (hb_in_range (u, 0x11480u, 0x114DFu)) return indic_table[u - 0x11480u + indic_offset_0x11480u];
-      if (hb_in_range (u, 0x11580u, 0x115C7u)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
-      if (hb_in_range (u, 0x11600u, 0x116CFu)) return indic_table[u - 0x11600u + indic_offset_0x11600u];
+      if (hb_in_range (u, 0x11580u, 0x1173Fu)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
       break;
 
     default:
@@ -914,11 +962,14 @@
 #undef ISC_CD
 #undef ISC_CF
 #undef ISC_CHL
+#undef ISC_CK
 #undef ISC_CM
 #undef ISC_CP
 #undef ISC_CPR
+#undef ISC_CPrf
 #undef ISC_CS
 #undef ISC_CSR
+#undef ISC_CWS
 #undef ISC_GM
 #undef ISC_IS
 #undef ISC_ZWJ
@@ -930,6 +981,7 @@
 #undef ISC_x
 #undef ISC_PK
 #undef ISC_RS
+#undef ISC_SM
 #undef ISC_TL
 #undef ISC_TM
 #undef ISC_V
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index 7723600..21256de 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 (info.indic_category()) & flags);
+  return !!(FLAG_SAFE (info.indic_category()) & flags);
 }
 
 static inline bool
@@ -176,24 +176,8 @@
    * Re-assign category
    */
 
-
-  /* The spec says U+0952 is OT_A.  However, testing shows that Uniscribe
-   * treats a whole bunch of characters similarly.
-   * TESTS: For example, for U+0951:
-   * U+092E,U+0947,U+0952
-   * U+092E,U+0952,U+0947
-   * U+092E,U+0947,U+0951
-   * U+092E,U+0951,U+0947
-   * U+092E,U+0951,U+0952
-   * U+092E,U+0952,U+0951
-   */
-  if (unlikely (hb_in_ranges (u, 0x0951u, 0x0952u,
-				 0x1CD0u, 0x1CD2u,
-				 0x1CD4u, 0x1CE1u) ||
-			    u == 0x1CF4u))
-    cat = OT_A;
   /* The following act more like the Bindus. */
-  else if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
+  if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
     cat = OT_SM;
   /* The following act like consonants. */
   else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
@@ -216,15 +200,12 @@
     cat = OT_Symbol;
     ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
   }
-  else if (unlikely (hb_in_range (u, 0x17CDu, 0x17D1u) ||
-		     u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
+  else if (unlikely (u == 0x17DDu)) /* https://github.com/roozbehp/unicode-data/issues/2 */
   {
-    /* These are like Top Matras. */
     cat = OT_M;
     pos = POS_ABOVE_C;
   }
   else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
-  else if (unlikely (u == 0x17D2u)) cat = OT_Coeng; /* Khmer coeng */
   else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
 				    cat = OT_PLACEHOLDER;
   else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
@@ -237,7 +218,7 @@
    * Re-assign position.
    */
 
-  if ((FLAG (cat) & CONSONANT_FLAGS))
+  if ((FLAG_SAFE (cat) & CONSONANT_FLAGS))
   {
     pos = POS_BASE_C;
     if (is_ra (u))
@@ -247,7 +228,7 @@
   {
     pos = matra_position (u, pos);
   }
-  else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
+  else if ((FLAG_SAFE (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
   {
     pos = POS_SMVD;
   }
@@ -557,8 +538,15 @@
   indic_plan->virama_glyph = (hb_codepoint_t) -1;
 
   /* Use zero-context would_substitute() matching for new-spec of the main
-   * Indic scripts, and scripts with one spec only, but not for old-specs. */
-  bool zero_context = !indic_plan->is_old_spec;
+   * Indic scripts, and scripts with one spec only, but not for old-specs.
+   * The new-spec for all dual-spec scripts says zero-context matching happens.
+   *
+   * However, testing with Malayalam shows that old and new spec both allow
+   * context.  Testing with Bengali new-spec however shows that it doesn't.
+   * So, the heuristic here is the way it is.  It should *only* be changed,
+   * as we discover more cases of what Windows does.  DON'T TOUCH OTHERWISE.
+   */
+  bool zero_context = !indic_plan->is_old_spec && plan->props.script != HB_SCRIPT_MALAYALAM;
   indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
   indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
   indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
@@ -756,7 +744,7 @@
     {
       default:
         assert (false);
-	/* fallthrough */
+	HB_FALLTHROUGH;
 
       case BASE_POS_LAST:
       {
@@ -963,7 +951,7 @@
     indic_position_t last_pos = POS_START;
     for (unsigned int i = start; i < end; i++)
     {
-      if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
+      if ((FLAG_SAFE (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 &&
@@ -1012,7 +1000,7 @@
       info[i].syllable() = i - start;
 
     /* Sit tight, rock 'n roll! */
-    hb_bubble_sort (info + start, end - start, compare_indic_order);
+    hb_stable_sort (info + start, end - start, compare_indic_order);
     /* Find base again */
     base = end;
     for (unsigned int i = start; i < end; i++)
@@ -1025,7 +1013,11 @@
      * around like crazy.  In old-spec mode, we move halants around, so in
      * that case merge all clusters after base.  Otherwise, check the sort
      * order and merge as needed.
-     * For pre-base stuff, we handle cluster issues in final reordering. */
+     * For pre-base stuff, we handle cluster issues in final reordering.
+     *
+     * We could use buffer->sort() for this, if there was no special
+     * reordering of pre-base stuff happening later...
+     */
     if (indic_plan->is_old_spec || end - base > 127)
       buffer->merge_clusters (base, end);
     else
@@ -1161,17 +1153,6 @@
     }
 }
 
-
-static void
-initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
-				   hb_face_t *face,
-				   hb_buffer_t *buffer,
-				   unsigned int start, unsigned int end)
-{
-  /* We made the vowels look like consonants.  So let's call the consonant logic! */
-  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
-}
-
 static void
 initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
 				       hb_face_t *face,
@@ -1194,50 +1175,27 @@
 }
 
 static void
-initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
-				   hb_face_t *face,
-				   hb_buffer_t *buffer,
-				   unsigned int start, unsigned int end)
-{
-  /* We already inserted dotted-circles, so just call the standalone_cluster. */
-  initial_reordering_standalone_cluster (plan, face, buffer, start, end);
-}
-
-static void
-initial_reordering_symbol_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
-				   hb_face_t *face HB_UNUSED,
-				   hb_buffer_t *buffer HB_UNUSED,
-				   unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
-{
-  /* Nothing to do right now.  If we ever switch to using the output
-   * buffer in the reordering process, we'd need to next_glyph() here. */
-}
-
-static void
-initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
-				      hb_face_t *face HB_UNUSED,
-				      hb_buffer_t *buffer HB_UNUSED,
-				      unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
-{
-  /* Nothing to do right now.  If we ever switch to using the output
-   * buffer in the reordering process, we'd need to next_glyph() here. */
-}
-
-
-static void
 initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
 			     hb_face_t *face,
 			     hb_buffer_t *buffer,
 			     unsigned int start, unsigned int end)
 {
   syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
-  switch (syllable_type) {
-  case consonant_syllable:	initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
-  case vowel_syllable:		initial_reordering_vowel_syllable     (plan, face, buffer, start, end); return;
-  case standalone_cluster:	initial_reordering_standalone_cluster (plan, face, buffer, start, end); return;
-  case symbol_cluster:		initial_reordering_symbol_cluster     (plan, face, buffer, start, end); return;
-  case broken_cluster:		initial_reordering_broken_cluster     (plan, face, buffer, start, end); return;
-  case non_indic_cluster:	initial_reordering_non_indic_cluster  (plan, face, buffer, start, end); return;
+  switch (syllable_type)
+  {
+    case vowel_syllable: /* We made the vowels look like consonants.  So let's call the consonant logic! */
+    case consonant_syllable:
+     initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+     break;
+
+    case broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */
+    case standalone_cluster:
+     initial_reordering_standalone_cluster (plan, face, buffer, start, end);
+     break;
+
+    case symbol_cluster:
+    case non_indic_cluster:
+      break;
   }
 }
 
@@ -1273,7 +1231,7 @@
 
   buffer->idx = 0;
   unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len)
+  while (buffer->idx < buffer->len && !buffer->in_error)
   {
     unsigned int syllable = buffer->cur().syllable();
     syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
@@ -1281,19 +1239,19 @@
     {
       last_syllable = syllable;
 
-      hb_glyph_info_t info = dottedcircle;
-      info.cluster = buffer->cur().cluster;
-      info.mask = buffer->cur().mask;
-      info.syllable() = buffer->cur().syllable();
+      hb_glyph_info_t ginfo = dottedcircle;
+      ginfo.cluster = buffer->cur().cluster;
+      ginfo.mask = buffer->cur().mask;
+      ginfo.syllable() = buffer->cur().syllable();
       /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
-      while (buffer->idx < buffer->len &&
+      while (buffer->idx < buffer->len && !buffer->in_error &&
 	     last_syllable == buffer->cur().syllable() &&
 	     buffer->cur().indic_category() == OT_Repha)
         buffer->next_glyph ();
 
-      buffer->output_info (info);
+      buffer->output_info (ginfo);
     }
     else
       buffer->next_glyph ();
@@ -1310,18 +1268,8 @@
   update_consonant_positions (plan, font, buffer);
   insert_dotted_circles (plan, font, buffer);
 
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  if (unlikely (!count)) return;
-  unsigned int last = 0;
-  unsigned int last_syllable = info[0].syllable();
-  for (unsigned int i = 1; i < count; i++)
-    if (last_syllable != info[i].syllable()) {
-      initial_reordering_syllable (plan, font->face, buffer, last, i);
-      last = i;
-      last_syllable = info[last].syllable();
-    }
-  initial_reordering_syllable (plan, font->face, buffer, last, count);
+  foreach_syllable (buffer, start, end)
+    initial_reordering_syllable (plan, font->face, buffer, start, end);
 }
 
 static void
@@ -1388,6 +1336,25 @@
 	    break;
 	  }
       }
+      /* For Malayalam, skip over unformed below- (but NOT post-) forms. */
+      if (buffer->props.script == HB_SCRIPT_MALAYALAM)
+      {
+	for (unsigned int i = base + 1; i < end; i++)
+	{
+	  while (i < end && is_joiner (info[i]))
+	    i++;
+	  if (i == end || !is_halant_or_coeng (info[i]))
+	    break;
+	  i++; /* Skip halant. */
+	  while (i < end && is_joiner (info[i]))
+	    i++;
+	  if (i < end && is_consonant (info[i]) && info[i].indic_position() == POS_BELOW_C)
+	  {
+	    base = i;
+	    info[base].indic_position() = POS_BASE_C;
+	  }
+	}
+      }
 
       if (start < base && info[base].indic_position() > POS_BASE_C)
         base--;
@@ -1448,12 +1415,17 @@
 	if (info[i - 1].indic_position () == POS_PRE_M)
 	{
 	  unsigned int old_pos = i - 1;
+	  if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
+	    base--;
+
 	  hb_glyph_info_t tmp = info[old_pos];
 	  memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0]));
 	  info[new_pos] = tmp;
-	  if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
-	    base--;
+
+	  /* Note: this merge_clusters() is intentionally *after* the reordering.
+	   * Indic matra reordering is special and tricky... */
 	  buffer->merge_clusters (new_pos, MIN (end, base + 1));
+
 	  new_pos--;
 	}
     } else {
@@ -1550,7 +1522,7 @@
     {
       new_reph_pos = base;
       while (new_reph_pos < end &&
-	     !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
+	     !( FLAG_SAFE (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;
@@ -1606,12 +1578,12 @@
 
     reph_move:
     {
-      buffer->merge_clusters (start, new_reph_pos + 1);
-
       /* Move */
+      buffer->merge_clusters (start, new_reph_pos + 1);
       hb_glyph_info_t reph = info[start];
       memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0]));
       info[new_reph_pos] = reph;
+
       if (start < base && base <= new_reph_pos)
 	base--;
     }
@@ -1666,8 +1638,8 @@
 	    if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
 	    {
 	      unsigned int old_pos = i;
-	      for (unsigned int i = base + 1; i < old_pos; i++)
-		if (info[i].indic_category() == OT_M)
+	      for (unsigned int j = base + 1; j < old_pos; j++)
+		if (info[j].indic_category() == OT_M)
 		{
 		  new_pos--;
 		  break;
@@ -1684,10 +1656,12 @@
 
 	  {
 	    unsigned int old_pos = i;
+
 	    buffer->merge_clusters (new_pos, old_pos + 1);
 	    hb_glyph_info_t tmp = info[old_pos];
 	    memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0]));
 	    info[new_pos] = tmp;
+
 	    if (new_pos <= base && base < old_pos)
 	      base++;
 	  }
@@ -1701,7 +1675,7 @@
   /* Apply 'init' to the Left Matra if it's a word start. */
   if (info[start].indic_position () == POS_PRE_M &&
       (!start ||
-       !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) &
+       !(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];
 
@@ -1737,16 +1711,8 @@
   unsigned int count = buffer->len;
   if (unlikely (!count)) return;
 
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int last = 0;
-  unsigned int last_syllable = info[0].syllable();
-  for (unsigned int i = 1; i < count; i++)
-    if (last_syllable != info[i].syllable()) {
-      final_reordering_syllable (plan, buffer, last, i);
-      last = i;
-      last_syllable = info[last].syllable();
-    }
-  final_reordering_syllable (plan, buffer, last, count);
+  foreach_syllable (buffer, start, end)
+    final_reordering_syllable (plan, buffer, start, end);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
@@ -1847,7 +1813,7 @@
     }
   }
 
-  return c->unicode->decompose (ab, a, b);
+  return (bool) c->unicode->decompose (ab, a, b);
 }
 
 static bool
@@ -1863,7 +1829,7 @@
   /* Composition-exclusion exceptions that we want to recompose. */
   if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; }
 
-  return c->unicode->compose (a, b, ab);
+  return (bool) c->unicode->compose (a, b, ab);
 }
 
 
@@ -1875,6 +1841,7 @@
   data_create_indic,
   data_destroy_indic,
   NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_indic,
   compose_indic,
diff --git a/src/hb-ot-shape-complex-myanmar-machine.hh b/src/hb-ot-shape-complex-myanmar-machine.hh
index bb80d7a..29fdf9a 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.hh
+++ b/src/hb-ot-shape-complex-myanmar-machine.hh
@@ -1,5 +1,5 @@
 
-#line 1 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 1 "hb-ot-shape-complex-myanmar-machine.rl"
 /*
  * Copyright © 2011,2012  Google, Inc.
  *
@@ -32,7 +32,7 @@
 #include "hb-private.hh"
 
 
-#line 36 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
 static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
 	1u, 31u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 
 	3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u, 
@@ -261,11 +261,11 @@
 static const int myanmar_syllable_machine_en_main = 0;
 
 
-#line 36 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 36 "hb-ot-shape-complex-myanmar-machine.rl"
 
 
 
-#line 93 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 93 "hb-ot-shape-complex-myanmar-machine.rl"
 
 
 #define found_syllable(syllable_type) \
@@ -285,7 +285,7 @@
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 289 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 289 "hb-ot-shape-complex-myanmar-machine.hh"
 	{
 	cs = myanmar_syllable_machine_start;
 	ts = 0;
@@ -293,7 +293,7 @@
 	act = 0;
 	}
 
-#line 114 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 114 "hb-ot-shape-complex-myanmar-machine.rl"
 
 
   p = 0;
@@ -302,7 +302,7 @@
   unsigned int last = 0;
   unsigned int syllable_serial = 1;
   
-#line 306 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 306 "hb-ot-shape-complex-myanmar-machine.hh"
 	{
 	int _slen;
 	int _trans;
@@ -316,7 +316,7 @@
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 320 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 	_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -335,38 +335,38 @@
 
 	switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
 	case 7:
-#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (consonant_syllable); }}
 	break;
 	case 5:
-#line 86 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
 	break;
 	case 10:
-#line 87 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 87 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (punctuation_cluster); }}
 	break;
 	case 4:
-#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (broken_cluster); }}
 	break;
 	case 3:
-#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
 	break;
 	case 6:
-#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (consonant_syllable); }}
 	break;
 	case 8:
-#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (broken_cluster); }}
 	break;
 	case 9:
-#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
 	{te = p;p--;{ found_syllable (non_myanmar_cluster); }}
 	break;
-#line 370 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 370 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 _again:
@@ -375,7 +375,7 @@
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 379 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
+#line 379 "hb-ot-shape-complex-myanmar-machine.hh"
 	}
 
 	if ( ++p != pe )
@@ -391,7 +391,7 @@
 
 	}
 
-#line 123 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 123 "hb-ot-shape-complex-myanmar-machine.rl"
 
 }
 
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index d016380..7b04344 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -154,7 +154,7 @@
 {
   /* If it ligated, all bets are off. */
   if (_hb_glyph_info_ligated (&info)) return false;
-  return !!(FLAG (info.myanmar_category()) & flags);
+  return !!(FLAG_SAFE (info.myanmar_category()) & flags);
 }
 
 static inline bool
@@ -199,6 +199,10 @@
       cat = (indic_category_t) OT_A;
       break;
 
+    case 0x1039u:
+      cat = (indic_category_t) OT_H;
+      break;
+
     case 0x103Au:
       cat = (indic_category_t) OT_As;
       break;
@@ -304,9 +308,7 @@
  * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm */
 
 static void
-initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
-				       hb_face_t *face,
-				       hb_buffer_t *buffer,
+initial_reordering_consonant_syllable (hb_buffer_t *buffer,
 				       unsigned int start, unsigned int end)
 {
   hb_glyph_info_t *info = buffer->info;
@@ -393,43 +395,11 @@
     }
   }
 
-  buffer->merge_clusters (start, end);
   /* Sit tight, rock 'n roll! */
-  hb_bubble_sort (info + start, end - start, compare_myanmar_order);
+  buffer->sort (start, end, compare_myanmar_order);
 }
 
 static void
-initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
-				   hb_face_t *face,
-				   hb_buffer_t *buffer,
-				   unsigned int start, unsigned int end)
-{
-  /* We already inserted dotted-circles, so just call the consonant_syllable. */
-  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
-}
-
-static void
-initial_reordering_punctuation_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
-					hb_face_t *face HB_UNUSED,
-					hb_buffer_t *buffer HB_UNUSED,
-					unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
-{
-  /* Nothing to do right now.  If we ever switch to using the output
-   * buffer in the reordering process, we'd need to next_glyph() here. */
-}
-
-static void
-initial_reordering_non_myanmar_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
-					hb_face_t *face HB_UNUSED,
-					hb_buffer_t *buffer HB_UNUSED,
-					unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
-{
-  /* Nothing to do right now.  If we ever switch to using the output
-   * buffer in the reordering process, we'd need to next_glyph() here. */
-}
-
-
-static void
 initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
 			     hb_face_t *face,
 			     hb_buffer_t *buffer,
@@ -437,10 +407,15 @@
 {
   syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   switch (syllable_type) {
-  case consonant_syllable:	initial_reordering_consonant_syllable  (plan, face, buffer, start, end); return;
-  case punctuation_cluster:	initial_reordering_punctuation_cluster (plan, face, buffer, start, end); return;
-  case broken_cluster:		initial_reordering_broken_cluster      (plan, face, buffer, start, end); return;
-  case non_myanmar_cluster:	initial_reordering_non_myanmar_cluster (plan, face, buffer, start, end); return;
+
+    case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
+    case consonant_syllable:
+      initial_reordering_consonant_syllable  (buffer, start, end);
+      break;
+
+    case punctuation_cluster:
+    case non_myanmar_cluster:
+      break;
   }
 }
 
@@ -476,7 +451,7 @@
 
   buffer->idx = 0;
   unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len)
+  while (buffer->idx < buffer->len && !buffer->in_error)
   {
     unsigned int syllable = buffer->cur().syllable();
     syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
@@ -484,12 +459,12 @@
     {
       last_syllable = syllable;
 
-      hb_glyph_info_t info = dottedcircle;
-      info.cluster = buffer->cur().cluster;
-      info.mask = buffer->cur().mask;
-      info.syllable() = buffer->cur().syllable();
+      hb_glyph_info_t ginfo = dottedcircle;
+      ginfo.cluster = buffer->cur().cluster;
+      ginfo.mask = buffer->cur().mask;
+      ginfo.syllable() = buffer->cur().syllable();
 
-      buffer->output_info (info);
+      buffer->output_info (ginfo);
     }
     else
       buffer->next_glyph ();
@@ -505,18 +480,8 @@
 {
   insert_dotted_circles (plan, font, buffer);
 
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  if (unlikely (!count)) return;
-  unsigned int last = 0;
-  unsigned int last_syllable = info[0].syllable();
-  for (unsigned int i = 1; i < count; i++)
-    if (last_syllable != info[i].syllable()) {
-      initial_reordering_syllable (plan, font->face, buffer, last, i);
-      last = i;
-      last_syllable = info[last].syllable();
-    }
-  initial_reordering_syllable (plan, font->face, buffer, last, count);
+  foreach_syllable (buffer, start, end)
+    initial_reordering_syllable (plan, font->face, buffer, start, end);
 }
 
 static void
@@ -546,6 +511,7 @@
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
@@ -562,6 +528,7 @@
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   NULL, /* decompose */
   NULL, /* compose */
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
index e268933..b3372bd 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex-private.hh
@@ -41,12 +41,8 @@
 
 enum hb_ot_shape_zero_width_marks_type_t {
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
-//  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY,
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
-
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
 };
 
 
@@ -59,9 +55,9 @@
   HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \
   HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
   HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
-  HB_COMPLEX_SHAPER_IMPLEMENT (sea) \
   HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
   HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (use) \
   /* ^--- Add new shapers here */
 
 
@@ -110,6 +106,15 @@
 			   hb_buffer_t              *buffer,
 			   hb_font_t                *font);
 
+  /* postprocess_glyphs()
+   * Called during shape().
+   * Shapers can use to modify glyphs after shaping ends.
+   * May be NULL.
+   */
+  void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan,
+			      hb_buffer_t              *buffer,
+			      hb_font_t                *font);
+
 
   hb_ot_shape_normalization_mode_t normalization_preference;
 
@@ -179,9 +184,12 @@
     case HB_SCRIPT_PSALTER_PAHLAVI:
 
       /* 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). */
-      if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
-	  planner->props.script == HB_SCRIPT_ARABIC)
+       * 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
+       * vertical text, just use the generic shaper instead. */
+      if ((planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
+	   planner->props.script == HB_SCRIPT_ARABIC) &&
+	  HB_DIRECTION_IS_HORIZONTAL(planner->props.direction))
 	return &_hb_ot_complex_shaper_arabic;
       else
 	return &_hb_ot_complex_shaper_default;
@@ -214,61 +222,9 @@
 
     /* ^--- Add new shapers here */
 
-
 #if 0
-    /* Note:
-     *
-     * These disabled scripts are listed in ucd/IndicSyllabicCategory.txt, but according
-     * to Martin Hosken and Jonathan Kew do not require complex shaping.
-     *
-     * TODO We should automate figuring out which scripts do not need complex shaping
-     *
-     * TODO We currently keep data for these scripts in our indic table.  Need to fix the
-     * generator to not do that.
-     */
-
-
-    /* Simple? */
-
-    /* Unicode-3.2 additions */
-    case HB_SCRIPT_BUHID:
-    case HB_SCRIPT_HANUNOO:
-
-    /* Unicode-5.1 additions */
-    case HB_SCRIPT_SAURASHTRA:
-
-    /* Unicode-6.0 additions */
-    case HB_SCRIPT_BATAK:
-    case HB_SCRIPT_BRAHMI:
-
-
-    /* Simple */
-
-    /* Unicode-1.1 additions */
-    /* These have their own shaper now. */
-    case HB_SCRIPT_LAO:
-    case HB_SCRIPT_THAI:
-
-    /* Unicode-3.2 additions */
-    case HB_SCRIPT_TAGALOG:
-    case HB_SCRIPT_TAGBANWA:
-
-    /* Unicode-4.0 additions */
-    case HB_SCRIPT_LIMBU:
-    case HB_SCRIPT_TAI_LE:
-
     /* Unicode-4.1 additions */
-    case HB_SCRIPT_KHAROSHTHI:
     case HB_SCRIPT_NEW_TAI_LUE:
-    case HB_SCRIPT_SYLOTI_NAGRI:
-
-    /* Unicode-5.1 additions */
-    case HB_SCRIPT_KAYAH_LI:
-
-    /* Unicode-5.2 additions */
-    case HB_SCRIPT_TAI_VIET:
-
-
 #endif
 
     /* Unicode-1.1 additions */
@@ -285,28 +241,11 @@
     /* Unicode-3.0 additions */
     case HB_SCRIPT_SINHALA:
 
-    /* Unicode-5.0 additions */
-    case HB_SCRIPT_BALINESE:
-
-    /* Unicode-5.1 additions */
-    case HB_SCRIPT_LEPCHA:
-    case HB_SCRIPT_REJANG:
-    case HB_SCRIPT_SUNDANESE:
-
     /* Unicode-5.2 additions */
     case HB_SCRIPT_JAVANESE:
-    case HB_SCRIPT_KAITHI:
-    case HB_SCRIPT_MEETEI_MAYEK:
-
-    /* Unicode-6.0 additions */
-
-    /* Unicode-6.1 additions */
-    case HB_SCRIPT_CHAKMA:
-    case HB_SCRIPT_SHARADA:
-    case HB_SCRIPT_TAKRI:
 
       /* If the designer designed the font for the 'DFLT' script,
-       * use the default shaper.  Otherwise, use the Indic shaper.
+       * 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'))
@@ -338,23 +277,82 @@
       else
 	return &_hb_ot_complex_shaper_default;
 
+
+    /* Unicode-2.0 additions */
+    //case HB_SCRIPT_TIBETAN:
+
+    /* Unicode-3.0 additions */
+    //case HB_SCRIPT_MONGOLIAN:
+    //case HB_SCRIPT_SINHALA:
+
+    /* Unicode-3.2 additions */
+    case HB_SCRIPT_BUHID:
+    case HB_SCRIPT_HANUNOO:
+    case HB_SCRIPT_TAGALOG:
+    case HB_SCRIPT_TAGBANWA:
+
+    /* Unicode-4.0 additions */
+    case HB_SCRIPT_LIMBU:
+    case HB_SCRIPT_TAI_LE:
+
     /* Unicode-4.1 additions */
     case HB_SCRIPT_BUGINESE:
+    case HB_SCRIPT_KHAROSHTHI:
+    case HB_SCRIPT_SYLOTI_NAGRI:
+    case HB_SCRIPT_TIFINAGH:
+
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_BALINESE:
+    //case HB_SCRIPT_NKO:
+    //case HB_SCRIPT_PHAGS_PA:
 
     /* Unicode-5.1 additions */
     case HB_SCRIPT_CHAM:
+    case HB_SCRIPT_KAYAH_LI:
+    case HB_SCRIPT_LEPCHA:
+    case HB_SCRIPT_REJANG:
+    case HB_SCRIPT_SAURASHTRA:
+    case HB_SCRIPT_SUNDANESE:
 
     /* Unicode-5.2 additions */
+    case HB_SCRIPT_EGYPTIAN_HIEROGLYPHS:
+    //case HB_SCRIPT_JAVANESE:
+    case HB_SCRIPT_KAITHI:
+    case HB_SCRIPT_MEETEI_MAYEK:
     case HB_SCRIPT_TAI_THAM:
+    case HB_SCRIPT_TAI_VIET:
+
+    /* Unicode-6.0 additions */
+    case HB_SCRIPT_BATAK:
+    case HB_SCRIPT_BRAHMI:
+    //case HB_SCRIPT_MANDAIC:
+
+    /* Unicode-6.1 additions */
+    case HB_SCRIPT_CHAKMA:
+    case HB_SCRIPT_SHARADA:
+    case HB_SCRIPT_TAKRI:
+
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_DUPLOYAN:
+    case HB_SCRIPT_GRANTHA:
+    case HB_SCRIPT_KHOJKI:
+    case HB_SCRIPT_KHUDAWADI:
+    case HB_SCRIPT_MAHAJANI:
+    //case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_MODI:
+    case HB_SCRIPT_PAHAWH_HMONG:
+    //case HB_SCRIPT_PSALTER_PAHLAVI:
+    case HB_SCRIPT_SIDDHAM:
+    case HB_SCRIPT_TIRHUTA:
 
       /* If the designer designed the font for the 'DFLT' script,
-       * use the default shaper.  Otherwise, use the Indic shaper.
+       * 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'))
 	return &_hb_ot_complex_shaper_default;
       else
-	return &_hb_ot_complex_shaper_sea;
+	return &_hb_ot_complex_shaper_use;
   }
 }
 
diff --git a/src/hb-ot-shape-complex-sea-machine.hh b/src/hb-ot-shape-complex-sea-machine.hh
deleted file mode 100644
index 86b7ae7..0000000
--- a/src/hb-ot-shape-complex-sea-machine.hh
+++ /dev/null
@@ -1,224 +0,0 @@
-
-#line 1 "../../src/hb-ot-shape-complex-sea-machine.rl"
-/*
- * Copyright © 2011,2012,2013  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_SHAPE_COMPLEX_SEA_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
-
-#include "hb-private.hh"
-
-
-#line 36 "hb-ot-shape-complex-sea-machine.hh.tmp"
-static const unsigned char _sea_syllable_machine_trans_keys[] = {
-	1u, 1u, 1u, 1u, 1u, 29u, 3u, 29u, 3u, 29u, 1u, 1u, 0
-};
-
-static const char _sea_syllable_machine_key_spans[] = {
-	1, 1, 29, 27, 27, 1
-};
-
-static const char _sea_syllable_machine_index_offsets[] = {
-	0, 2, 4, 34, 62, 90
-};
-
-static const char _sea_syllable_machine_indicies[] = {
-	1, 0, 3, 2, 1, 1, 3, 5, 
-	4, 4, 4, 4, 4, 3, 4, 1, 
-	4, 4, 4, 4, 3, 4, 4, 4, 
-	4, 3, 4, 4, 4, 3, 3, 3, 
-	3, 4, 1, 7, 6, 6, 6, 6, 
-	6, 1, 6, 6, 6, 6, 6, 6, 
-	1, 6, 6, 6, 6, 1, 6, 6, 
-	6, 1, 1, 1, 1, 6, 3, 9, 
-	8, 8, 8, 8, 8, 3, 8, 8, 
-	8, 8, 8, 8, 3, 8, 8, 8, 
-	8, 3, 8, 8, 8, 3, 3, 3, 
-	3, 8, 3, 10, 0
-};
-
-static const char _sea_syllable_machine_trans_targs[] = {
-	2, 3, 2, 4, 2, 5, 2, 0, 
-	2, 1, 2
-};
-
-static const char _sea_syllable_machine_trans_actions[] = {
-	1, 2, 3, 2, 6, 0, 7, 0, 
-	8, 0, 9
-};
-
-static const char _sea_syllable_machine_to_state_actions[] = {
-	0, 0, 4, 0, 0, 0
-};
-
-static const char _sea_syllable_machine_from_state_actions[] = {
-	0, 0, 5, 0, 0, 0
-};
-
-static const char _sea_syllable_machine_eof_trans[] = {
-	1, 3, 0, 7, 9, 11
-};
-
-static const int sea_syllable_machine_start = 2;
-static const int sea_syllable_machine_first_final = 2;
-static const int sea_syllable_machine_error = -1;
-
-static const int sea_syllable_machine_en_main = 2;
-
-
-#line 36 "../../src/hb-ot-shape-complex-sea-machine.rl"
-
-
-
-#line 67 "../../src/hb-ot-shape-complex-sea-machine.rl"
-
-
-#define found_syllable(syllable_type) \
-  HB_STMT_START { \
-    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
-    for (unsigned int i = last; i < p+1; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
-    last = p+1; \
-    syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
-  } HB_STMT_END
-
-static void
-find_syllables (hb_buffer_t *buffer)
-{
-  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
-  int cs;
-  hb_glyph_info_t *info = buffer->info;
-  
-#line 117 "hb-ot-shape-complex-sea-machine.hh.tmp"
-	{
-	cs = sea_syllable_machine_start;
-	ts = 0;
-	te = 0;
-	act = 0;
-	}
-
-#line 88 "../../src/hb-ot-shape-complex-sea-machine.rl"
-
-
-  p = 0;
-  pe = eof = buffer->len;
-
-  unsigned int last = 0;
-  unsigned int syllable_serial = 1;
-  
-#line 134 "hb-ot-shape-complex-sea-machine.hh.tmp"
-	{
-	int _slen;
-	int _trans;
-	const unsigned char *_keys;
-	const char *_inds;
-	if ( p == pe )
-		goto _test_eof;
-_resume:
-	switch ( _sea_syllable_machine_from_state_actions[cs] ) {
-	case 5:
-#line 1 "NONE"
-	{ts = p;}
-	break;
-#line 148 "hb-ot-shape-complex-sea-machine.hh.tmp"
-	}
-
-	_keys = _sea_syllable_machine_trans_keys + (cs<<1);
-	_inds = _sea_syllable_machine_indicies + _sea_syllable_machine_index_offsets[cs];
-
-	_slen = _sea_syllable_machine_key_spans[cs];
-	_trans = _inds[ _slen > 0 && _keys[0] <=( info[p].sea_category()) &&
-		( info[p].sea_category()) <= _keys[1] ?
-		( info[p].sea_category()) - _keys[0] : _slen ];
-
-_eof_trans:
-	cs = _sea_syllable_machine_trans_targs[_trans];
-
-	if ( _sea_syllable_machine_trans_actions[_trans] == 0 )
-		goto _again;
-
-	switch ( _sea_syllable_machine_trans_actions[_trans] ) {
-	case 2:
-#line 1 "NONE"
-	{te = p+1;}
-	break;
-	case 6:
-#line 63 "../../src/hb-ot-shape-complex-sea-machine.rl"
-	{te = p+1;{ found_syllable (non_sea_cluster); }}
-	break;
-	case 7:
-#line 61 "../../src/hb-ot-shape-complex-sea-machine.rl"
-	{te = p;p--;{ found_syllable (consonant_syllable); }}
-	break;
-	case 8:
-#line 62 "../../src/hb-ot-shape-complex-sea-machine.rl"
-	{te = p;p--;{ found_syllable (broken_cluster); }}
-	break;
-	case 9:
-#line 63 "../../src/hb-ot-shape-complex-sea-machine.rl"
-	{te = p;p--;{ found_syllable (non_sea_cluster); }}
-	break;
-	case 1:
-#line 61 "../../src/hb-ot-shape-complex-sea-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
-	break;
-	case 3:
-#line 62 "../../src/hb-ot-shape-complex-sea-machine.rl"
-	{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
-	break;
-#line 194 "hb-ot-shape-complex-sea-machine.hh.tmp"
-	}
-
-_again:
-	switch ( _sea_syllable_machine_to_state_actions[cs] ) {
-	case 4:
-#line 1 "NONE"
-	{ts = 0;}
-	break;
-#line 203 "hb-ot-shape-complex-sea-machine.hh.tmp"
-	}
-
-	if ( ++p != pe )
-		goto _resume;
-	_test_eof: {}
-	if ( p == eof )
-	{
-	if ( _sea_syllable_machine_eof_trans[cs] > 0 ) {
-		_trans = _sea_syllable_machine_eof_trans[cs] - 1;
-		goto _eof_trans;
-	}
-	}
-
-	}
-
-#line 97 "../../src/hb-ot-shape-complex-sea-machine.rl"
-
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-sea-machine.rl b/src/hb-ot-shape-complex-sea-machine.rl
deleted file mode 100644
index 46140fc..0000000
--- a/src/hb-ot-shape-complex-sea-machine.rl
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright © 2011,2012,2013  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_SHAPE_COMPLEX_SEA_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
-
-#include "hb-private.hh"
-
-%%{
-  machine sea_syllable_machine;
-  alphtype unsigned char;
-  write data;
-}%%
-
-%%{
-
-# Same order as enum sea_category_t.  Not sure how to avoid duplication.
-C    = 1;
-GB   = 12; # Generic Base
-H    = 4;  # Halant
-IV   = 2;  # Independent Vowel
-MR   = 22; # Medial Ra
-CM   = 17; # Consonant Medial
-VAbv = 26;
-VBlw = 27;
-VPre = 28;
-VPst = 29;
-T    = 3;  # Tone Marks
-A    = 10; # Anusvara
-
-syllable_tail = (VPre|VAbv|VBlw|VPst|H.C|CM|MR|T|A)*;
-
-consonant_syllable =	(C|IV|GB) syllable_tail;
-broken_cluster =	syllable_tail;
-other =			any;
-
-main := |*
-	consonant_syllable	=> { found_syllable (consonant_syllable); };
-	broken_cluster		=> { found_syllable (broken_cluster); };
-	other			=> { found_syllable (non_sea_cluster); };
-*|;
-
-
-}%%
-
-#define found_syllable(syllable_type) \
-  HB_STMT_START { \
-    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
-    for (unsigned int i = last; i < p+1; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
-    last = p+1; \
-    syllable_serial++; \
-    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
-  } HB_STMT_END
-
-static void
-find_syllables (hb_buffer_t *buffer)
-{
-  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
-  int cs;
-  hb_glyph_info_t *info = buffer->info;
-  %%{
-    write init;
-    getkey info[p].sea_category();
-  }%%
-
-  p = 0;
-  pe = eof = buffer->len;
-
-  unsigned int last = 0;
-  unsigned int syllable_serial = 1;
-  %%{
-    write exec;
-  }%%
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-sea.cc b/src/hb-ot-shape-complex-sea.cc
deleted file mode 100644
index f08b7cc..0000000
--- a/src/hb-ot-shape-complex-sea.cc
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright © 2011,2012,2013  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#include "hb-ot-shape-complex-indic-private.hh"
-
-/* buffer var allocations */
-#define sea_category() complex_var_u8_0() /* indic_category_t */
-#define sea_position() complex_var_u8_1() /* indic_position_t */
-
-
-/*
- * South-East Asian shaper.
- * Loosely based on the Myanmar spec / shaper.
- * There is no OpenType spec for this.
- */
-
-static const hb_tag_t
-basic_features[] =
-{
-  /*
-   * Basic features.
-   * These features are applied in order, one at a time, after initial_reordering.
-   */
-  HB_TAG('p','r','e','f'),
-  HB_TAG('a','b','v','f'),
-  HB_TAG('b','l','w','f'),
-  HB_TAG('p','s','t','f'),
-};
-static const hb_tag_t
-other_features[] =
-{
-  /*
-   * Other features.
-   * These features are applied all at once, after final_reordering.
-   */
-  HB_TAG('p','r','e','s'),
-  HB_TAG('a','b','v','s'),
-  HB_TAG('b','l','w','s'),
-  HB_TAG('p','s','t','s'),
-  /* Positioning features, though we don't care about the types. */
-  HB_TAG('d','i','s','t'),
-};
-
-static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
-		 hb_font_t *font,
-		 hb_buffer_t *buffer);
-static void
-initial_reordering (const hb_ot_shape_plan_t *plan,
-		    hb_font_t *font,
-		    hb_buffer_t *buffer);
-static void
-final_reordering (const hb_ot_shape_plan_t *plan,
-		  hb_font_t *font,
-		  hb_buffer_t *buffer);
-
-static void
-collect_features_sea (hb_ot_shape_planner_t *plan)
-{
-  hb_ot_map_builder_t *map = &plan->map;
-
-  /* Do this before any lookups have been applied. */
-  map->add_gsub_pause (setup_syllables);
-
-  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
-  /* The Indic specs do not require ccmp, but we apply it here since if
-   * there is a use of it, it's typically at the beginning. */
-  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
-
-  map->add_gsub_pause (initial_reordering);
-  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 (final_reordering);
-  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
-    map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
-}
-
-static void
-override_features_sea (hb_ot_shape_planner_t *plan)
-{
-  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
-}
-
-
-enum syllable_type_t {
-  consonant_syllable,
-  broken_cluster,
-  non_sea_cluster,
-};
-
-#include "hb-ot-shape-complex-sea-machine.hh"
-
-
-/* Note: This enum is duplicated in the -machine.rl source file.
- * Not sure how to avoid duplication. */
-enum sea_category_t {
-//  OT_C    = 1,
-  OT_GB   = 12, /* Generic Base XXX DOTTED CIRCLE only for now */
-//  OT_H    = 4,  /* Halant */
-  OT_IV   = 2,  /* Independent Vowel */
-  OT_MR   = 22, /* Medial Ra */
-//  OT_CM   = 17, /* Consonant Medial */
-  OT_VAbv = 26,
-  OT_VBlw = 27,
-  OT_VPre = 28,
-  OT_VPst = 29,
-  OT_T    = 3,  /* Tone Marks */
-//  OT_A    = 10, /* Anusvara */
-};
-
-static inline void
-set_sea_properties (hb_glyph_info_t &info)
-{
-  hb_codepoint_t u = info.codepoint;
-  unsigned int type = hb_indic_get_categories (u);
-  indic_category_t cat = (indic_category_t) (type & 0x7Fu);
-  indic_position_t pos = (indic_position_t) (type >> 8);
-
-  /* Medial Ra */
-  if (u == 0x1A55u || u == 0xAA34u)
-    cat = (indic_category_t) OT_MR;
-
-  if (cat == OT_M)
-  {
-    switch ((int) pos)
-    {
-      case POS_PRE_C:	cat = (indic_category_t) OT_VPre; break;
-      case POS_ABOVE_C:	cat = (indic_category_t) OT_VAbv; break;
-      case POS_BELOW_C:	cat = (indic_category_t) OT_VBlw; break;
-      case POS_POST_C:	cat = (indic_category_t) OT_VPst; break;
-    }
-  }
-
-  info.sea_category() = (sea_category_t) cat;
-  info.sea_position() = pos;
-}
-
-
-static void
-setup_masks_sea (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		 hb_buffer_t              *buffer,
-		 hb_font_t                *font HB_UNUSED)
-{
-  HB_BUFFER_ALLOCATE_VAR (buffer, sea_category);
-  HB_BUFFER_ALLOCATE_VAR (buffer, sea_position);
-
-  /* We cannot setup masks here.  We save information about characters
-   * and setup masks later on in a pause-callback. */
-
-  unsigned int count = buffer->len;
-  hb_glyph_info_t *info = buffer->info;
-  for (unsigned int i = 0; i < count; i++)
-    set_sea_properties (info[i]);
-}
-
-static void
-setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		 hb_font_t *font HB_UNUSED,
-		 hb_buffer_t *buffer)
-{
-  find_syllables (buffer);
-}
-
-static int
-compare_sea_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
-{
-  int a = pa->sea_position();
-  int b = pb->sea_position();
-
-  return a < b ? -1 : a == b ? 0 : +1;
-}
-
-
-static void
-initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
-				       hb_face_t *face,
-				       hb_buffer_t *buffer,
-				       unsigned int start, unsigned int end)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int base = start;
-
-  /* Reorder! */
-  unsigned int i = start;
-  for (; i < base; i++)
-    info[i].sea_position() = POS_PRE_C;
-  if (i < end)
-  {
-    info[i].sea_position() = POS_BASE_C;
-    i++;
-  }
-  for (; i < end; i++)
-  {
-    if (info[i].sea_category() == OT_MR) /* Pre-base reordering */
-    {
-      info[i].sea_position() = POS_PRE_C;
-      continue;
-    }
-    if (info[i].sea_category() == OT_VPre) /* Left matra */
-    {
-      info[i].sea_position() = POS_PRE_M;
-      continue;
-    }
-
-    info[i].sea_position() = POS_AFTER_MAIN;
-  }
-
-  buffer->merge_clusters (start, end);
-  /* Sit tight, rock 'n roll! */
-  hb_bubble_sort (info + start, end - start, compare_sea_order);
-}
-
-static void
-initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
-				   hb_face_t *face,
-				   hb_buffer_t *buffer,
-				   unsigned int start, unsigned int end)
-{
-  /* We already inserted dotted-circles, so just call the consonant_syllable. */
-  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
-}
-
-static void
-initial_reordering_non_sea_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
-				    hb_face_t *face HB_UNUSED,
-				    hb_buffer_t *buffer HB_UNUSED,
-				    unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
-{
-  /* Nothing to do right now.  If we ever switch to using the output
-   * buffer in the reordering process, we'd need to next_glyph() here. */
-}
-
-
-static void
-initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
-			     hb_face_t *face,
-			     hb_buffer_t *buffer,
-			     unsigned int start, unsigned int end)
-{
-  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
-  switch (syllable_type) {
-  case consonant_syllable:	initial_reordering_consonant_syllable  (plan, face, buffer, start, end); return;
-  case broken_cluster:		initial_reordering_broken_cluster      (plan, face, buffer, start, end); return;
-  case non_sea_cluster:		initial_reordering_non_sea_cluster     (plan, face, buffer, start, end); return;
-  }
-}
-
-static inline void
-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		       hb_font_t *font,
-		       hb_buffer_t *buffer)
-{
-  /* Note: This loop is extra overhead, but should not be measurable. */
-  bool has_broken_syllables = false;
-  unsigned int count = buffer->len;
-  hb_glyph_info_t *info = buffer->info;
-  for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_cluster)
-    {
-      has_broken_syllables = true;
-      break;
-    }
-  if (likely (!has_broken_syllables))
-    return;
-
-
-  hb_codepoint_t dottedcircle_glyph;
-  if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
-    return;
-
-  hb_glyph_info_t dottedcircle = {0};
-  dottedcircle.codepoint = 0x25CCu;
-  set_sea_properties (dottedcircle);
-  dottedcircle.codepoint = dottedcircle_glyph;
-
-  buffer->clear_output ();
-
-  buffer->idx = 0;
-  unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len)
-  {
-    unsigned int syllable = buffer->cur().syllable();
-    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
-    {
-      last_syllable = syllable;
-
-      hb_glyph_info_t info = dottedcircle;
-      info.cluster = buffer->cur().cluster;
-      info.mask = buffer->cur().mask;
-      info.syllable() = buffer->cur().syllable();
-
-      buffer->output_info (info);
-    }
-    else
-      buffer->next_glyph ();
-  }
-
-  buffer->swap_buffers ();
-}
-
-static void
-initial_reordering (const hb_ot_shape_plan_t *plan,
-		    hb_font_t *font,
-		    hb_buffer_t *buffer)
-{
-  insert_dotted_circles (plan, font, buffer);
-
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  if (unlikely (!count)) return;
-  unsigned int last = 0;
-  unsigned int last_syllable = info[0].syllable();
-  for (unsigned int i = 1; i < count; i++)
-    if (last_syllable != info[i].syllable()) {
-      initial_reordering_syllable (plan, font->face, buffer, last, i);
-      last = i;
-      last_syllable = info[last].syllable();
-    }
-  initial_reordering_syllable (plan, font->face, buffer, last, count);
-}
-
-static void
-final_reordering (const hb_ot_shape_plan_t *plan,
-		  hb_font_t *font HB_UNUSED,
-		  hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-
-  /* Zero syllables now... */
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-
-  HB_BUFFER_DEALLOCATE_VAR (buffer, sea_category);
-  HB_BUFFER_DEALLOCATE_VAR (buffer, sea_position);
-}
-
-
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_sea =
-{
-  "sea",
-  collect_features_sea,
-  override_features_sea,
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
-  NULL, /* decompose */
-  NULL, /* compose */
-  setup_masks_sea,
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
-  false, /* fallback_position */
-};
diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc
index feb7fc7..58392b6 100644
--- a/src/hb-ot-shape-complex-thai.cc
+++ b/src/hb-ot-shape-complex-thai.cc
@@ -139,7 +139,7 @@
   };
 
   switch (action) {
-    default: assert (false); /* Fallthrough */
+    default: assert (false); HB_FALLTHROUGH;
     case NOP: return u;
     case SD:  pua_mappings = SD_mappings; break;
     case SDL: pua_mappings = SDL_mappings; break;
@@ -315,7 +315,7 @@
 
   buffer->clear_output ();
   unsigned int count = buffer->len;
-  for (buffer->idx = 0; buffer->idx < count;)
+  for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
   {
     hb_codepoint_t u = buffer->cur().codepoint;
     if (likely (!IS_SARA_AM (u))) {
@@ -330,7 +330,7 @@
     if (unlikely (buffer->in_error))
       return;
 
-    /* Make Nikhahit be recognized as a mark when zeroing widths. */
+    /* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
     unsigned int end = buffer->out_len;
     _hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
 
@@ -353,7 +353,7 @@
     {
       /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
        * previous cluster. */
-      if (start)
+      if (start && buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
 	buffer->merge_out_clusters (start - 1, end);
     }
   }
@@ -372,10 +372,11 @@
   NULL, /* data_create */
   NULL, /* data_destroy */
   preprocess_text_thai,
+  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
   NULL, /* setup_masks */
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+  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 01465a4..a77b531 100644
--- a/src/hb-ot-shape-complex-tibetan.cc
+++ b/src/hb-ot-shape-complex-tibetan.cc
@@ -52,10 +52,11 @@
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
   NULL, /* setup_masks */
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
diff --git a/src/hb-ot-shape-complex-use-machine.hh b/src/hb-ot-shape-complex-use-machine.hh
new file mode 100644
index 0000000..ced9d97
--- /dev/null
+++ b/src/hb-ot-shape-complex-use-machine.hh
@@ -0,0 +1,548 @@
+
+#line 1 "hb-ot-shape-complex-use-machine.rl"
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
+#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
+
+#include "hb-private.hh"
+
+
+#line 38 "hb-ot-shape-complex-use-machine.hh"
+static const unsigned char _use_syllable_machine_trans_keys[] = {
+	0u, 0u, 4u, 4u, 1u, 1u, 0u, 39u, 21u, 21u, 8u, 39u, 8u, 39u, 1u, 1u, 
+	8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, 
+	8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 
+	8u, 39u, 8u, 39u, 8u, 39u, 1u, 1u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 
+	8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 
+	8u, 39u, 12u, 21u, 12u, 13u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 
+	8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 
+	8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 1u, 39u, 8u, 39u, 21u, 42u, 41u, 42u, 
+	42u, 42u, 0
+};
+
+static const char _use_syllable_machine_key_spans[] = {
+	0, 1, 1, 40, 1, 32, 32, 1, 
+	32, 32, 32, 19, 19, 19, 32, 32, 
+	32, 32, 32, 32, 32, 32, 32, 32, 
+	32, 32, 32, 1, 32, 32, 19, 19, 
+	19, 32, 32, 32, 32, 32, 32, 32, 
+	32, 10, 2, 32, 32, 32, 32, 19, 
+	19, 19, 32, 32, 32, 32, 32, 32, 
+	32, 32, 32, 32, 39, 32, 22, 2, 
+	1
+};
+
+static const short _use_syllable_machine_index_offsets[] = {
+	0, 0, 2, 4, 45, 47, 80, 113, 
+	115, 148, 181, 214, 234, 254, 274, 307, 
+	340, 373, 406, 439, 472, 505, 538, 571, 
+	604, 637, 670, 703, 705, 738, 771, 791, 
+	811, 831, 864, 897, 930, 963, 996, 1029, 
+	1062, 1095, 1106, 1109, 1142, 1175, 1208, 1241, 
+	1261, 1281, 1301, 1334, 1367, 1400, 1433, 1466, 
+	1499, 1532, 1565, 1598, 1631, 1671, 1704, 1727, 
+	1730
+};
+
+static const char _use_syllable_machine_indicies[] = {
+	1, 0, 3, 2, 4, 5, 6, 
+	4, 1, 5, 8, 8, 7, 8, 8, 
+	3, 9, 8, 8, 8, 4, 4, 10, 
+	11, 8, 8, 12, 13, 14, 15, 16, 
+	17, 18, 12, 19, 20, 21, 22, 23, 
+	24, 8, 25, 26, 27, 8, 29, 28, 
+	31, 30, 30, 32, 33, 30, 30, 30, 
+	30, 30, 30, 30, 30, 34, 35, 36, 
+	37, 38, 39, 40, 41, 35, 42, 34, 
+	43, 44, 45, 46, 30, 47, 48, 49, 
+	30, 31, 30, 30, 32, 33, 30, 30, 
+	30, 30, 30, 30, 30, 30, 50, 35, 
+	36, 37, 38, 39, 40, 41, 35, 42, 
+	43, 43, 44, 45, 46, 30, 47, 48, 
+	49, 30, 32, 51, 31, 30, 30, 32, 
+	33, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 35, 36, 37, 38, 39, 40, 
+	41, 35, 42, 43, 43, 44, 45, 46, 
+	30, 47, 48, 49, 30, 31, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 35, 36, 37, 38, 39, 
+	30, 30, 30, 30, 30, 30, 44, 45, 
+	46, 30, 47, 48, 49, 30, 31, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 36, 37, 38, 
+	39, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 47, 48, 49, 30, 31, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 37, 
+	38, 39, 30, 31, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 38, 39, 30, 31, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 39, 30, 31, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 37, 38, 39, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	47, 48, 49, 30, 31, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 37, 38, 39, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 48, 49, 30, 31, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 37, 38, 39, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 49, 30, 31, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 36, 37, 38, 
+	39, 30, 30, 30, 30, 30, 30, 44, 
+	45, 46, 30, 47, 48, 49, 30, 31, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 36, 37, 
+	38, 39, 30, 30, 30, 30, 30, 30, 
+	30, 45, 46, 30, 47, 48, 49, 30, 
+	31, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 36, 
+	37, 38, 39, 30, 30, 30, 30, 30, 
+	30, 30, 30, 46, 30, 47, 48, 49, 
+	30, 31, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 35, 
+	36, 37, 38, 39, 30, 41, 35, 30, 
+	30, 30, 44, 45, 46, 30, 47, 48, 
+	49, 30, 31, 30, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	35, 36, 37, 38, 39, 30, 30, 35, 
+	30, 30, 30, 44, 45, 46, 30, 47, 
+	48, 49, 30, 31, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 30, 30, 
+	30, 35, 36, 37, 38, 39, 40, 41, 
+	35, 30, 30, 30, 44, 45, 46, 30, 
+	47, 48, 49, 30, 31, 30, 30, 32, 
+	33, 30, 30, 30, 30, 30, 30, 30, 
+	30, 30, 35, 36, 37, 38, 39, 40, 
+	41, 35, 42, 30, 43, 44, 45, 46, 
+	30, 47, 48, 49, 30, 31, 30, 30, 
+	32, 33, 30, 30, 30, 30, 30, 30, 
+	30, 30, 30, 35, 36, 37, 38, 39, 
+	40, 41, 35, 42, 34, 43, 44, 45, 
+	46, 30, 47, 48, 49, 30, 53, 52, 
+	52, 54, 55, 52, 52, 52, 52, 52, 
+	52, 52, 52, 56, 52, 57, 58, 59, 
+	60, 61, 62, 57, 63, 56, 64, 52, 
+	52, 52, 52, 65, 66, 67, 52, 53, 
+	52, 52, 54, 55, 52, 52, 52, 52, 
+	52, 52, 52, 52, 68, 52, 57, 58, 
+	59, 60, 61, 62, 57, 63, 64, 64, 
+	52, 52, 52, 52, 65, 66, 67, 52, 
+	54, 51, 53, 52, 52, 54, 55, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 57, 58, 59, 60, 61, 62, 57, 
+	63, 64, 64, 52, 52, 52, 52, 65, 
+	66, 67, 52, 53, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 52, 57, 58, 59, 60, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	65, 66, 67, 52, 53, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 58, 59, 60, 52, 
+	53, 52, 52, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 59, 60, 52, 53, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 60, 52, 
+	53, 52, 52, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	58, 59, 60, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 65, 66, 67, 
+	52, 53, 52, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 58, 59, 60, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 66, 
+	67, 52, 53, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 52, 58, 59, 60, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 67, 52, 53, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 52, 57, 58, 59, 60, 52, 62, 
+	57, 52, 52, 52, 52, 52, 52, 52, 
+	65, 66, 67, 52, 53, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 52, 52, 57, 58, 59, 60, 52, 
+	52, 57, 52, 52, 52, 52, 52, 52, 
+	52, 65, 66, 67, 52, 53, 52, 52, 
+	52, 52, 52, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 57, 58, 59, 60, 
+	61, 62, 57, 52, 52, 52, 52, 52, 
+	52, 52, 65, 66, 67, 52, 53, 52, 
+	52, 54, 55, 52, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 57, 58, 59, 
+	60, 61, 62, 57, 63, 52, 64, 52, 
+	52, 52, 52, 65, 66, 67, 52, 53, 
+	52, 52, 54, 55, 52, 52, 52, 52, 
+	52, 52, 52, 52, 52, 52, 57, 58, 
+	59, 60, 61, 62, 57, 63, 56, 64, 
+	52, 52, 52, 52, 65, 66, 67, 52, 
+	70, 71, 69, 69, 69, 69, 69, 69, 
+	69, 72, 69, 70, 71, 69, 7, 73, 
+	73, 3, 9, 73, 73, 73, 73, 73, 
+	73, 73, 73, 74, 12, 13, 14, 15, 
+	16, 17, 18, 12, 19, 21, 21, 22, 
+	23, 24, 73, 25, 26, 27, 73, 7, 
+	73, 73, 3, 9, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 12, 13, 14, 
+	15, 16, 17, 18, 12, 19, 21, 21, 
+	22, 23, 24, 73, 25, 26, 27, 73, 
+	7, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 12, 13, 
+	14, 15, 16, 73, 73, 73, 73, 73, 
+	73, 22, 23, 24, 73, 25, 26, 27, 
+	73, 7, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	13, 14, 15, 16, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 25, 26, 
+	27, 73, 7, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 14, 15, 16, 73, 7, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 15, 
+	16, 73, 7, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 16, 73, 7, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 14, 15, 
+	16, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 25, 26, 27, 73, 7, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 14, 
+	15, 16, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 26, 27, 73, 
+	7, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	14, 15, 16, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 27, 
+	73, 7, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	13, 14, 15, 16, 73, 73, 73, 73, 
+	73, 73, 22, 23, 24, 73, 25, 26, 
+	27, 73, 7, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 13, 14, 15, 16, 73, 73, 73, 
+	73, 73, 73, 73, 23, 24, 73, 25, 
+	26, 27, 73, 7, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 13, 14, 15, 16, 73, 73, 
+	73, 73, 73, 73, 73, 73, 24, 73, 
+	25, 26, 27, 73, 7, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 12, 13, 14, 15, 16, 73, 
+	18, 12, 73, 73, 73, 22, 23, 24, 
+	73, 25, 26, 27, 73, 7, 73, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 12, 13, 14, 15, 16, 
+	73, 73, 12, 73, 73, 73, 22, 23, 
+	24, 73, 25, 26, 27, 73, 7, 73, 
+	73, 73, 73, 73, 73, 73, 73, 73, 
+	73, 73, 73, 73, 12, 13, 14, 15, 
+	16, 17, 18, 12, 73, 73, 73, 22, 
+	23, 24, 73, 25, 26, 27, 73, 7, 
+	73, 73, 3, 9, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 12, 13, 14, 
+	15, 16, 17, 18, 12, 19, 73, 21, 
+	22, 23, 24, 73, 25, 26, 27, 73, 
+	5, 6, 73, 73, 5, 73, 73, 7, 
+	73, 73, 3, 9, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 12, 13, 14, 
+	15, 16, 17, 18, 12, 19, 20, 21, 
+	22, 23, 24, 73, 25, 26, 27, 73, 
+	7, 73, 73, 3, 9, 73, 73, 73, 
+	73, 73, 73, 73, 73, 73, 12, 13, 
+	14, 15, 16, 17, 18, 12, 19, 20, 
+	21, 22, 23, 24, 73, 25, 26, 27, 
+	73, 76, 75, 75, 75, 75, 75, 75, 
+	75, 75, 75, 75, 75, 75, 75, 75, 
+	75, 75, 75, 75, 75, 76, 77, 75, 
+	76, 77, 75, 77, 75, 0
+};
+
+static const char _use_syllable_machine_trans_targs[] = {
+	3, 41, 3, 43, 4, 5, 25, 3, 
+	0, 2, 60, 62, 45, 46, 47, 48, 
+	49, 56, 57, 58, 61, 59, 53, 54, 
+	55, 50, 51, 52, 3, 3, 3, 3, 
+	6, 7, 24, 9, 10, 11, 12, 13, 
+	20, 21, 22, 23, 17, 18, 19, 14, 
+	15, 16, 8, 3, 3, 3, 26, 27, 
+	40, 29, 30, 31, 32, 36, 37, 38, 
+	39, 33, 34, 35, 28, 3, 3, 1, 
+	42, 3, 44, 3, 63, 64
+};
+
+static const char _use_syllable_machine_trans_actions[] = {
+	1, 2, 3, 4, 0, 0, 0, 7, 
+	0, 0, 4, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 4, 4, 0, 0, 
+	0, 0, 0, 0, 8, 9, 10, 11, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 12, 13, 14, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 15, 16, 0, 
+	2, 17, 4, 18, 0, 0
+};
+
+static const char _use_syllable_machine_to_state_actions[] = {
+	0, 0, 0, 5, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0
+};
+
+static const char _use_syllable_machine_from_state_actions[] = {
+	0, 0, 0, 6, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0
+};
+
+static const short _use_syllable_machine_eof_trans[] = {
+	0, 1, 3, 0, 29, 31, 31, 52, 
+	31, 31, 31, 31, 31, 31, 31, 31, 
+	31, 31, 31, 31, 31, 31, 31, 31, 
+	31, 53, 53, 52, 53, 53, 53, 53, 
+	53, 53, 53, 53, 53, 53, 53, 53, 
+	53, 70, 70, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 74, 74, 
+	74, 74, 74, 74, 74, 74, 76, 76, 
+	76
+};
+
+static const int use_syllable_machine_start = 3;
+static const int use_syllable_machine_first_final = 3;
+static const int use_syllable_machine_error = 0;
+
+static const int use_syllable_machine_en_main = 3;
+
+
+#line 38 "hb-ot-shape-complex-use-machine.rl"
+
+
+
+#line 145 "hb-ot-shape-complex-use-machine.rl"
+
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+    for (unsigned int i = last; i < p+1; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    last = p+1; \
+    syllable_serial++; \
+    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+  } HB_STMT_END
+
+static void
+find_syllables (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+  
+#line 388 "hb-ot-shape-complex-use-machine.hh"
+	{
+	cs = use_syllable_machine_start;
+	ts = 0;
+	te = 0;
+	act = 0;
+	}
+
+#line 166 "hb-ot-shape-complex-use-machine.rl"
+
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int last = 0;
+  unsigned int syllable_serial = 1;
+  
+#line 405 "hb-ot-shape-complex-use-machine.hh"
+	{
+	int _slen;
+	int _trans;
+	const unsigned char *_keys;
+	const char *_inds;
+	if ( p == pe )
+		goto _test_eof;
+	if ( cs == 0 )
+		goto _out;
+_resume:
+	switch ( _use_syllable_machine_from_state_actions[cs] ) {
+	case 6:
+#line 1 "NONE"
+	{ts = p;}
+	break;
+#line 421 "hb-ot-shape-complex-use-machine.hh"
+	}
+
+	_keys = _use_syllable_machine_trans_keys + (cs<<1);
+	_inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs];
+
+	_slen = _use_syllable_machine_key_spans[cs];
+	_trans = _inds[ _slen > 0 && _keys[0] <=( info[p].use_category()) &&
+		( info[p].use_category()) <= _keys[1] ?
+		( info[p].use_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+	cs = _use_syllable_machine_trans_targs[_trans];
+
+	if ( _use_syllable_machine_trans_actions[_trans] == 0 )
+		goto _again;
+
+	switch ( _use_syllable_machine_trans_actions[_trans] ) {
+	case 2:
+#line 1 "NONE"
+	{te = p+1;}
+	break;
+	case 9:
+#line 134 "hb-ot-shape-complex-use-machine.rl"
+	{te = p+1;{ found_syllable (independent_cluster); }}
+	break;
+	case 11:
+#line 136 "hb-ot-shape-complex-use-machine.rl"
+	{te = p+1;{ found_syllable (consonant_cluster); }}
+	break;
+	case 14:
+#line 137 "hb-ot-shape-complex-use-machine.rl"
+	{te = p+1;{ found_syllable (vowel_cluster); }}
+	break;
+	case 16:
+#line 138 "hb-ot-shape-complex-use-machine.rl"
+	{te = p+1;{ found_syllable (number_joiner_terminated_cluster); }}
+	break;
+	case 7:
+#line 141 "hb-ot-shape-complex-use-machine.rl"
+	{te = p+1;{ found_syllable (broken_cluster); }}
+	break;
+	case 8:
+#line 134 "hb-ot-shape-complex-use-machine.rl"
+	{te = p;p--;{ found_syllable (independent_cluster); }}
+	break;
+	case 12:
+#line 135 "hb-ot-shape-complex-use-machine.rl"
+	{te = p;p--;{ found_syllable (virama_terminated_cluster); }}
+	break;
+	case 10:
+#line 136 "hb-ot-shape-complex-use-machine.rl"
+	{te = p;p--;{ found_syllable (consonant_cluster); }}
+	break;
+	case 13:
+#line 137 "hb-ot-shape-complex-use-machine.rl"
+	{te = p;p--;{ found_syllable (vowel_cluster); }}
+	break;
+	case 15:
+#line 139 "hb-ot-shape-complex-use-machine.rl"
+	{te = p;p--;{ found_syllable (numeral_cluster); }}
+	break;
+	case 18:
+#line 140 "hb-ot-shape-complex-use-machine.rl"
+	{te = p;p--;{ found_syllable (symbol_cluster); }}
+	break;
+	case 17:
+#line 141 "hb-ot-shape-complex-use-machine.rl"
+	{te = p;p--;{ found_syllable (broken_cluster); }}
+	break;
+	case 1:
+#line 139 "hb-ot-shape-complex-use-machine.rl"
+	{{p = ((te))-1;}{ found_syllable (numeral_cluster); }}
+	break;
+	case 3:
+#line 1 "NONE"
+	{	switch( act ) {
+	case 0:
+	{{cs = 0; goto _again;}}
+	break;
+	case 8:
+	{{p = ((te))-1;} found_syllable (broken_cluster); }
+	break;
+	}
+	}
+	break;
+	case 4:
+#line 1 "NONE"
+	{te = p+1;}
+#line 141 "hb-ot-shape-complex-use-machine.rl"
+	{act = 8;}
+	break;
+#line 513 "hb-ot-shape-complex-use-machine.hh"
+	}
+
+_again:
+	switch ( _use_syllable_machine_to_state_actions[cs] ) {
+	case 5:
+#line 1 "NONE"
+	{ts = 0;}
+#line 1 "NONE"
+	{act = 0;}
+	break;
+#line 524 "hb-ot-shape-complex-use-machine.hh"
+	}
+
+	if ( cs == 0 )
+		goto _out;
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	if ( p == eof )
+	{
+	if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
+		_trans = _use_syllable_machine_eof_trans[cs] - 1;
+		goto _eof_trans;
+	}
+	}
+
+	_out: {}
+	}
+
+#line 175 "hb-ot-shape-complex-use-machine.rl"
+
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-use-machine.rl b/src/hb-ot-shape-complex-use-machine.rl
new file mode 100644
index 0000000..b8242ba
--- /dev/null
+++ b/src/hb-ot-shape-complex-use-machine.rl
@@ -0,0 +1,180 @@
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
+#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
+
+#include "hb-private.hh"
+
+%%{
+  machine use_syllable_machine;
+  alphtype unsigned char;
+  write data;
+}%%
+
+%%{
+
+# Same order as enum use_category_t.  Not sure how to avoid duplication.
+
+O	= 0; # OTHER
+
+B	= 1; # BASE
+IV	= 2; # BASE_VOWEL
+IND	= 3; # BASE_IND
+N	= 4; # BASE_NUM
+GB	= 5; # BASE_OTHER
+CGJ	= 6; # CGJ
+#F	= 7; # CONS_FINAL
+FM	= 8; # CONS_FINAL_MOD
+#M	= 9; # CONS_MED
+#CM	= 10; # CONS_MOD
+SUB	= 11; # CONS_SUB
+H	= 12; # HALANT
+
+HN	= 13; # HALANT_NUM
+ZWNJ	= 14; # Zero width non-joiner
+ZWJ	= 15; # Zero width joiner
+WJ	= 16; # Word joiner
+Rsv	= 17; # Reserved characters
+R	= 18; # REPHA
+S	= 19; # SYM
+#SM	= 20; # SYM_MOD
+VS	= 21; # VARIATION_SELECTOR
+#V	= 36; # VOWEL
+#VM	= 40; # VOWEL_MOD
+
+FAbv	= 24; # CONS_FINAL_ABOVE
+FBlw	= 25; # CONS_FINAL_BELOW
+FPst	= 26; # CONS_FINAL_POST
+MAbv	= 27; # CONS_MED_ABOVE
+MBlw	= 28; # CONS_MED_BELOW
+MPst	= 29; # CONS_MED_POST
+MPre	= 30; # CONS_MED_PRE
+CMAbv	= 31; # CONS_MOD_ABOVE
+CMBlw	= 32; # CONS_MOD_BELOW
+VAbv	= 33; # VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST
+VBlw	= 34; # VOWEL_BELOW / VOWEL_BELOW_POST
+VPst	= 35; # VOWEL_POST	UIPC = Right
+VPre	= 22; # VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST
+VMAbv	= 37; # VOWEL_MOD_ABOVE
+VMBlw	= 38; # VOWEL_MOD_BELOW
+VMPst	= 39; # VOWEL_MOD_POST
+VMPre	= 23; # VOWEL_MOD_PRE
+SMAbv	= 41; # SYM_MOD_ABOVE
+SMBlw	= 42; # SYM_MOD_BELOW
+
+
+consonant_modifiers = CMAbv* CMBlw* ((H B | SUB) VS? CMAbv? CMBlw*)*;
+medial_consonants = MPre? MAbv? 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 | IV) VS?
+	consonant_modifiers
+	H
+;
+consonant_cluster =
+	R? (B | GB) VS?
+	consonant_modifiers
+	medial_consonants
+	dependent_vowels
+	vowel_modifiers
+	final_consonants
+;
+vowel_cluster =
+	R? (IV) VS?
+	consonant_modifiers
+	medial_consonants
+	vowel_modifiers
+	final_consonants
+;
+
+broken_cluster =
+	R?
+	consonant_modifiers
+	medial_consonants
+	dependent_vowels
+	vowel_modifiers
+	final_consonants
+;
+
+number_joiner_terminated_cluster = N VS? (HN N VS?)* H;
+numeral_cluster = N VS? (HN N VS?)*;
+symbol_cluster = S VS? SMAbv* SMBlw*;
+independent_cluster = (IND | O | Rsv | WJ) VS?;
+
+main := |*
+	independent_cluster			=> { found_syllable (independent_cluster); };
+	virama_terminated_cluster		=> { found_syllable (virama_terminated_cluster); };
+	consonant_cluster			=> { found_syllable (consonant_cluster); };
+	vowel_cluster				=> { found_syllable (vowel_cluster); };
+	number_joiner_terminated_cluster	=> { found_syllable (number_joiner_terminated_cluster); };
+	numeral_cluster				=> { found_syllable (numeral_cluster); };
+	symbol_cluster				=> { found_syllable (symbol_cluster); };
+	broken_cluster				=> { found_syllable (broken_cluster); };
+*|;
+
+
+}%%
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+    for (unsigned int i = last; i < p+1; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    last = p+1; \
+    syllable_serial++; \
+    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+  } HB_STMT_END
+
+static void
+find_syllables (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+  %%{
+    write init;
+    getkey info[p].use_category();
+  }%%
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int last = 0;
+  unsigned int syllable_serial = 1;
+  %%{
+    write exec;
+  }%%
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-use-private.hh b/src/hb-ot-shape-complex-use-private.hh
new file mode 100644
index 0000000..a143736
--- /dev/null
+++ b/src/hb-ot-shape-complex-use-private.hh
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH
+#define HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+#define USE_TABLE_ELEMENT_TYPE uint8_t
+
+/* Cateories used in the Universal Shaping Engine spec:
+ * https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm
+ */
+/* Note: This enum is duplicated in the -machine.rl source file.
+ * Not sure how to avoid duplication. */
+enum use_category_t {
+  USE_O		= 0,	/* OTHER */
+
+  USE_B		= 1,	/* BASE */
+  USE_IV	= 2,	/* BASE_VOWEL */
+  USE_IND	= 3,	/* BASE_IND */
+  USE_N		= 4,	/* BASE_NUM */
+  USE_GB	= 5,	/* BASE_OTHER */
+  USE_CGJ	= 6,	/* CGJ */
+//  USE_F		= 7,	/* CONS_FINAL */
+  USE_FM	= 8,	/* CONS_FINAL_MOD */
+//  USE_M		= 9,	/* CONS_MED */
+//  USE_CM	= 10,	/* CONS_MOD */
+  USE_SUB	= 11,	/* CONS_SUB */
+  USE_H		= 12,	/* HALANT */
+
+  USE_HN	= 13,	/* HALANT_NUM */
+  USE_ZWNJ	= 14,	/* Zero width non-joiner */
+  USE_ZWJ	= 15,	/* Zero width joiner */
+  USE_WJ	= 16,	/* Word joiner */
+  USE_Rsv	= 17,	/* Reserved characters */
+  USE_R		= 18,	/* REPHA */
+  USE_S		= 19,	/* SYM */
+//  USE_SM	= 20,	/* SYM_MOD */
+  USE_VS	= 21,	/* VARIATION_SELECTOR */
+//  USE_V	= 36,	/* VOWEL */
+//  USE_VM	= 40,	/* VOWEL_MOD */
+
+  USE_FAbv	= 24,	/* CONS_FINAL_ABOVE */
+  USE_FBlw	= 25,	/* CONS_FINAL_BELOW */
+  USE_FPst	= 26,	/* CONS_FINAL_POST */
+  USE_MAbv	= 27,	/* CONS_MED_ABOVE */
+  USE_MBlw	= 28,	/* CONS_MED_BELOW */
+  USE_MPst	= 29,	/* CONS_MED_POST */
+  USE_MPre	= 30,	/* CONS_MED_PRE */
+  USE_CMAbv	= 31,	/* CONS_MOD_ABOVE */
+  USE_CMBlw	= 32,	/* CONS_MOD_BELOW */
+  USE_VAbv	= 33,	/* VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST */
+  USE_VBlw	= 34,	/* VOWEL_BELOW / VOWEL_BELOW_POST */
+  USE_VPst	= 35,	/* VOWEL_POST	UIPC = Right */
+  USE_VPre	= 22,	/* VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST */
+  USE_VMAbv	= 37,	/* VOWEL_MOD_ABOVE */
+  USE_VMBlw	= 38,	/* VOWEL_MOD_BELOW */
+  USE_VMPst	= 39,	/* VOWEL_MOD_POST */
+  USE_VMPre	= 23,	/* VOWEL_MOD_PRE */
+  USE_SMAbv	= 41,	/* SYM_MOD_ABOVE */
+  USE_SMBlw	= 42	/* SYM_MOD_BELOW */
+};
+
+HB_INTERNAL USE_TABLE_ELEMENT_TYPE
+hb_use_get_categories (hb_codepoint_t u);
+
+#endif /* HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH */
diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc
new file mode 100644
index 0000000..6cd1c5d
--- /dev/null
+++ b/src/hb-ot-shape-complex-use-table.cc
@@ -0,0 +1,696 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
+ *
+ * on files with these headers:
+ *
+ * # IndicSyllabicCategory-8.0.0.txt
+ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
+ * # IndicPositionalCategory-8.0.0.txt
+ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
+ * # Blocks-8.0.0.txt
+ * # Date: 2014-11-10, 23:04:00 GMT [KW]
+ * UnicodeData.txt does not have a header.
+ */
+
+#include "hb-ot-shape-complex-use-private.hh"
+
+#define B	USE_B	/* BASE */
+#define CGJ	USE_CGJ	/* CGJ */
+#define FM	USE_FM	/* CONS_FINAL_MOD */
+#define GB	USE_GB	/* BASE_OTHER */
+#define H	USE_H	/* HALANT */
+#define HN	USE_HN	/* HALANT_NUM */
+#define IND	USE_IND	/* BASE_IND */
+#define IV	USE_IV	/* BASE_VOWEL */
+#define N	USE_N	/* BASE_NUM */
+#define O	USE_O	/* OTHER */
+#define R	USE_R	/* REPHA */
+#define Rsv	USE_Rsv	/* Reserved */
+#define S	USE_S	/* SYM */
+#define SUB	USE_SUB	/* CONS_SUB */
+#define VS	USE_VS	/* VARIATION_SELECTOR */
+#define WJ	USE_WJ	/* Word_Joiner */
+#define ZWJ	USE_ZWJ	/* ZWJ */
+#define ZWNJ	USE_ZWNJ	/* ZWNJ */
+#define CMBlw	USE_CMBlw
+#define CMAbv	USE_CMAbv
+#define FBlw	USE_FBlw
+#define FPst	USE_FPst
+#define FAbv	USE_FAbv
+#define MPre	USE_MPre
+#define MBlw	USE_MBlw
+#define MPst	USE_MPst
+#define MAbv	USE_MAbv
+#define SMBlw	USE_SMBlw
+#define SMAbv	USE_SMAbv
+#define VPre	USE_VPre
+#define VBlw	USE_VBlw
+#define VPst	USE_VPst
+#define VAbv	USE_VAbv
+#define VMPre	USE_VMPre
+#define VMBlw	USE_VMBlw
+#define VMPst	USE_VMPst
+#define VMAbv	USE_VMAbv
+
+static const USE_TABLE_ELEMENT_TYPE use_table[] = {
+
+
+#define use_offset_0x0028u 0
+
+
+  /* Basic Latin */
+                                                                         O,     O,     O,     O,     O,    GB,     O,     O,
+  /* 0030 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0x00a0u 24
+
+
+  /* Latin-1 Supplement */
+
+  /* 00A0 */    GB,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 00B0 */     O,     O,    FM,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 00C0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 00D0 */     O,     O,     O,     O,     O,     O,     O,    GB,
+
+#define use_offset_0x0900u 80
+
+
+  /* Devanagari */
+
+  /* 0900 */ VMAbv, VMAbv, VMAbv, VMPst,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,
+  /* 0910 */    IV,    IV,    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0920 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0930 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VPst, CMBlw,     B,  VPst,  VPre,
+  /* 0940 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,  VPst,  VPst,  VPst,  VPst,     H,  VPre,  VPst,
+  /* 0950 */     O, VMAbv, VMBlw,     O,     O,  VAbv,  VBlw,  VBlw,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0960 */    IV,    IV,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0970 */     O,     O,    IV,    IV,    IV,    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,
+
+  /* Bengali */
+
+  /* 0980 */     O, VMAbv, VMPst, VMPst,     O,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     O,     O,    IV,
+  /* 0990 */    IV,     O,     O,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 09A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 09B0 */     B,     O,     B,     O,     O,     O,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VPre,
+  /* 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 */    IV,    IV,  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,
+
+  /* Gurmukhi */
+
+  /* 0A00 */     O, VMAbv, VMAbv, VMPst,     O,    IV,    IV,    IV,    IV,    IV,    IV,     O,     O,     O,     O,    IV,
+  /* 0A10 */    IV,     O,     O,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0A30 */     B,     O,     B,     B,     O,     B,     B,     O,     B,     B,     O,     O, CMBlw,     O,  VPst,  VPre,
+  /* 0A40 */  VPst,  VBlw,  VBlw,     O,     O,     O,     O,  VAbv,  VAbv,     O,     O,  VAbv,  VAbv,     H,     O,     O,
+  /* 0A50 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     O,     B,     O,
+  /* 0A60 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0A70 */ VMAbv, CMAbv,    GB,    GB,     O,  MBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Gujarati */
+
+  /* 0A80 */     O, VMAbv, VMAbv, VMPst,     O,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     O,    IV,
+  /* 0A90 */    IV,    IV,     O,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0AA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0AB0 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VPre,
+  /* 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 */    IV,    IV,  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,
+
+  /* Oriya */
+
+  /* 0B00 */     O, VMAbv, VMPst, VMPst,     O,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     O,     O,    IV,
+  /* 0B10 */    IV,     O,     O,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0B20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0B30 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VAbv,
+  /* 0B40 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VPre,  VPre,     O,     O,  VPre,  VPre,     H,     O,     O,
+  /* 0B50 */     O,     O,     O,     O,     O,     O,  VAbv,  VAbv,     O,     O,     O,     O,     B,     B,     O,     B,
+  /* 0B60 */    IV,    IV,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0B70 */     O,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Tamil */
+
+  /* 0B80 */     O,     O, VMAbv,   IND,     O,    IV,    IV,    IV,    IV,    IV,    IV,     O,     O,     O,    IV,    IV,
+  /* 0B90 */    IV,     O,    IV,    IV,    IV,     B,     O,     O,     O,     B,     B,     O,     B,     O,     B,     B,
+  /* 0BA0 */     O,     O,     O,     B,     B,     O,     O,     O,     B,     B,     B,     O,     O,     O,     B,     B,
+  /* 0BB0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,  VPst,  VPst,
+  /* 0BC0 */  VAbv,  VPst,  VPst,     O,     O,     O,  VPre,  VPre,  VPre,     O,  VPre,  VPre,  VPre,     H,     O,     O,
+  /* 0BD0 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 0BE0 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0BF0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Telugu */
+
+  /* 0C00 */ VMAbv, VMPst, VMPst, VMPst,     O,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     O,    IV,    IV,
+  /* 0C10 */    IV,     O,    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0C20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0C30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,  VAbv,  VAbv,
+  /* 0C40 */  VAbv,  VPst,  VPst,  VPst,  VPst,     O,  VAbv,  VAbv,  VAbv,     O,  VAbv,  VAbv,  VAbv,     H,     O,     O,
+  /* 0C50 */     O,     O,     O,     O,     O,  VAbv,  VBlw,     O,     B,     B,     B,     O,     O,     O,     O,     O,
+  /* 0C60 */    IV,    IV,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0C70 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Kannada */
+
+  /* 0C80 */     O, VMAbv, VMPst, VMPst,     O,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     O,    IV,    IV,
+  /* 0C90 */    IV,     O,    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0CA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 0CB0 */     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VAbv,
+  /* 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 */    IV,    IV,  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,
+
+  /* Malayalam */
+
+  /* 0D00 */     O, VMAbv, VMPst, VMPst,     O,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     O,    IV,    IV,
+  /* 0D10 */    IV,     O,    IV,    IV,    IV,     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,
+  /* 0D40 */  VPst,  VPst,  VPst,  VBlw,  VBlw,     O,  VPre,  VPre,  VPre,     O,  VPre,  VPre,  VPre,     H,     R,     O,
+  /* 0D50 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     O,     O,     O,    IV,
+  /* 0D60 */    IV,    IV,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0D70 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,   IND,   IND,   IND,   IND,   IND,   IND,
+
+  /* Sinhala */
+
+  /* 0D80 */     O,     O, VMPst, VMPst,     O,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,
+  /* 0D90 */    IV,    IV,    IV,    IV,    IV,    IV,    IV,     O,     O,     O,     B,     B,     B,     B,     B,     B,
+  /* 0DA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0DB0 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     O,     O,
+  /* 0DC0 */     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     H,     O,     O,     O,     O,  VPst,
+  /* 0DD0 */  VPst,  VPst,  VAbv,  VAbv,  VBlw,     O,  VBlw,     O,  VPst,  VPre,  VPre,  VPre,  VPre,  VPre,  VPre,  VPst,
+  /* 0DE0 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0DF0 */     O,     O,  VPst,  VPst,     O,     O,     O,     O,
+
+#define use_offset_0x1000u 1352
+
+
+  /* Myanmar */
+
+  /* 1000 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1010 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1020 */     B,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,  VPst,  VPst,  VAbv,  VAbv,  VBlw,
+  /* 1030 */  VBlw,  VPre,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMBlw, VMPst,     H,  VAbv,  MPst,  MPre,  MBlw,  MBlw,     B,
+  /* 1040 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,    GB,     O,
+  /* 1050 */     B,     B,    IV,    IV,    IV,    IV,  VPst,  VPst,  VBlw,  VBlw,     B,     B,     B,     B,  MBlw,  MBlw,
+  /* 1060 */  MBlw,     B,  VPst, VMPst, VMPst,     B,     B,  VPst,  VPst, VMPst, VMPst, VMPst, VMPst, VMPst,     B,     B,
+  /* 1070 */     B,  VAbv,  VAbv,  VAbv,  VAbv,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1080 */     B,     B,  MBlw,  VPst,  VPre,  VAbv,  VAbv, VMPst, VMPst, VMPst, VMPst, VMPst, VMPst, VMBlw,     B, VMPst,
+  /* 1090 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMPst, VMPst,  VPst,  VAbv,     O,     O,
+
+#define use_offset_0x1700u 1512
+
+
+  /* Tagalog */
+
+  /* 1700 */    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 1710 */     B,     B,  VAbv,  VBlw,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Hanunoo */
+
+  /* 1720 */    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1730 */     B,     B,  VAbv,  VBlw,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Buhid */
+
+  /* 1740 */    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1750 */     B,     B,  VAbv,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Tagbanwa */
+
+  /* 1760 */    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 1770 */     B,     O,  VAbv,  VBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Khmer */
+
+  /* 1780 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1790 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 17A0 */     B,     B,     B,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,
+  /* 17B0 */    IV,    IV,    IV,    IV,     O,     O,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VPre,  VPre,
+  /* 17C0 */  VPre,  VPre,  VPre,  VPre,  VPre,  VPre, VMAbv, VMPst,  VPst, VMAbv, VMAbv,    FM,  FAbv, CMAbv,    FM,    FM,
+  /* 17D0 */    FM,  VAbv,     H,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     B,  VAbv,     O,     O,
+  /* 17E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0x1900u 1752
+
+
+  /* Limbu */
+
+  /* 1900 */    GB,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,
+  /* 1920 */  VAbv,  VAbv,  VBlw,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,   SUB,   SUB,   SUB,     O,     O,     O,     O,
+  /* 1930 */  FPst,  FPst, VMBlw,  FPst,  FPst,  FPst,  FPst,  FPst,  FPst,  FBlw,  VAbv,    FM,     O,     O,     O,     O,
+  /* 1940 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+
+  /* Tai Le */
+
+  /* 1950 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1960 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,
+  /* 1970 */     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* New Tai Lue */
+
+  /* 1980 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1990 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 19A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
+  /* 19B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 19C0 */     B,     B,     B,     B,     B,     B,     B,     B, VMPst, VMPst,     O,     O,     O,     O,     O,     O,
+  /* 19D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 19E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 19F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Buginese */
+
+  /* 1A00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1A10 */     B,     B,     B,     B,     B,     B,     B,  VAbv,  VBlw,  VPre,  VPst,  VAbv,     O,     O,     O,     O,
+
+  /* Tai Tham */
+
+  /* 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,    IV,    IV,    IV,
+  /* 1A50 */    IV,    IV,    IV,     B,     B,  MPre,  MBlw,  FPst,  FAbv,  FAbv,  FAbv,  FBlw,  FBlw,  FBlw,  FBlw,     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,
+  /* 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,
+
+#define use_offset_0x1b00u 2168
+
+
+  /* Balinese */
+
+  /* 1B00 */ VMAbv, VMAbv, VMAbv,  FAbv, VMPst,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,
+  /* 1B10 */    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1B20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1B30 */     B,     B,     B,     B, CMAbv,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPre,  VPre,
+  /* 1B40 */  VPre,  VPre,  VAbv,  VAbv,     H,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
+  /* 1B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 1B60 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
+  /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Sundanese */
+
+  /* 1B80 */ VMAbv,  FAbv, VMPst,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,
+  /* 1B90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1BA0 */     B,   SUB,   SUB,   SUB,  VAbv,  VBlw,  VPre,  VPst,  VAbv,  VAbv,  VPst,     H,   SUB,   SUB,     B,     B,
+  /* 1BB0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+
+  /* Batak */
+
+  /* 1BC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1BD0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1BE0 */     B,     B,     B,     B,    IV,    IV, CMAbv,  VPst,  VAbv,  VAbv,  VPst,  VPst,  VPst,  VAbv,  VPst,  VAbv,
+  /* 1BF0 */  FAbv,  FAbv,  VPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Lepcha */
+
+  /* 1C00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1C10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 1C20 */     B,     B,     B,     B,   SUB,   SUB,  VPst,  VPre,  VPre,  VPre,  VPst,  VPst,  VBlw,  FAbv,  FAbv,  FAbv,
+  /* 1C30 */  FAbv,  FAbv,  FAbv,  FAbv, VMPre, VMPre,    FM, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 1C40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,     B,     B,
+
+#define use_offset_0x1cd0u 2504
+
+
+  /* Vedic Extensions */
+
+  /* 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,
+
+#define use_offset_0x2008u 2552
+
+
+  /* General Punctuation */
+                                                                         O,     O,     O,     O,  ZWNJ,   ZWJ,     O,     O,
+  /* 2010 */    GB,    GB,    GB,    GB,    GB,     O,     O,     O,
+
+#define use_offset_0x2060u 2568
+
+  /* 2060 */    WJ,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Superscripts and Subscripts */
+
+  /* 2070 */     O,     O,     O,     O,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 2080 */     O,     O,    FM,    FM,    FM,     O,     O,     O,
+
+#define use_offset_0xa800u 2608
+
+
+  /* Syloti Nagri */
+
+  /* A800 */    IV,    IV,     O,    IV,    IV,    IV,  VAbv,     B,     B,     B,     B, VMAbv,     B,     B,     B,     B,
+  /* A810 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A820 */     B,     B,     B,  VPst,  VPst,  VBlw,  VAbv,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A830 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Phags-pa */
+
+  /* A840 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A850 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A860 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A870 */     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Saurashtra */
+
+  /* A880 */ VMPst, VMPst,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,
+  /* A890 */    IV,    IV,     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,
+  /* A8C0 */  VPst,  VPst,  VPst,  VPst,     H,     O,     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,
+
+  /* Kayah Li */
+
+  /* A900 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A920 */     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv, VMBlw, VMBlw, VMBlw,     O,     O,
+
+  /* Rejang */
+
+  /* A930 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A940 */     B,     B,     B,     B,     B,     B,     B,  VBlw,  VBlw,  VBlw,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,  FAbv,
+  /* A950 */  FAbv,  FAbv,  FPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A960 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A970 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Javanese */
+
+  /* A980 */ VMAbv, VMAbv,  FAbv, VMPst,    IV,    IV,    IV,    IV,    IV,     B,     B,     B,    IV,    IV,    IV,     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,
+  /* 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,
+
+  /* Myanmar Extended-B */
+
+  /* A9E0 */     B,     B,     B,     B,     B,  VAbv,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* A9F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,
+
+  /* Cham */
+
+  /* AA00 */    IV,    IV,    IV,    IV,    IV,    IV,     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,
+  /* 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,
+
+  /* Myanmar Extended-A */
+
+  /* AA60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AA70 */     O,     B,     B,     B,     O,     O,     O,     O,     O,     O,     B, VMPst, VMAbv, VMPst,     B,     B,
+
+  /* Tai Viet */
+
+  /* AA80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AA90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AAA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* AAB0 */  VAbv,     B,  VAbv,  VAbv,  VBlw,     B,     B,  VAbv,  VAbv,     B,     B,     B,     B,     B,  VAbv, VMAbv,
+  /* AAC0 */     B, VMAbv,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* AAD0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Meetei Mayek Extensions */
+
+  /* AAE0 */    IV,    IV,     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 3368
+
+
+  /* Meetei Mayek */
+
+  /* ABC0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,    IV,    IV,
+  /* ABD0 */     B,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 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 3432
+
+
+  /* Variation Selectors */
+
+  /* FE00 */    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,    VS,
+
+#define use_offset_0x10a00u 3448
+
+
+  /* Kharoshthi */
+
+  /* 10A00 */     B,  VBlw,  VBlw,  VBlw,     O,  VAbv,  VBlw,     O,     O,     O,     O,     O,  VBlw,  VBlw, VMBlw, VMAbv,
+  /* 10A10 */     B,     B,     B,     B,     O,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,
+  /* 10A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 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 3520
+
+
+  /* Brahmi */
+
+  /* 11000 */ VMPst, VMAbv, VMPst,     R,     R,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,
+  /* 11010 */    IV,    IV,    IV,     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,
+  /* 11040 */  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,     H,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11050 */     O,     O,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,     N,
+  /* 11060 */     N,     N,     N,     N,     N,     N,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11070 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Kaithi */
+
+  /* 11080 */ VMAbv, VMAbv, VMPst,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     B,     B,     B,
+  /* 11090 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 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 3712
+
+
+  /* Chakma */
+
+  /* 11100 */ VMAbv, VMAbv, VMAbv,    IV,    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11110 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11120 */     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VAbv,  VAbv,  VAbv,
+  /* 11130 */  VAbv,  VBlw,  VBlw,     H,  VAbv,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11140 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Mahajani */
+
+  /* 11150 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11160 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11170 */     B,     B,     B, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Sharada */
+
+  /* 11180 */ VMAbv, VMAbv, VMPst,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,
+  /* 11190 */    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 111A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 111B0 */     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,
+  /* 111C0 */     H,     B,     R,     R,     O,     O,     O,     O,     O,     O, CMBlw,  VAbv,  VBlw,     O,     O,     O,
+  /* 111D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+  /* Sinhala Archaic Numbers */
+
+  /* 111E0 */     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 111F0 */     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Khojki */
+
+  /* 11200 */    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11210 */     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 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,
+
+#define use_offset_0x11280u 4024
+
+
+  /* Multani */
+
+  /* 11280 */    IV,    IV,    IV,    IV,     B,     B,     B,     O,     B,     O,     B,     B,     B,     B,     O,     B,
+  /* 11290 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,
+  /* 112A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Khudawadi */
+
+  /* 112B0 */    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,
+  /* 112C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 112D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv,
+  /* 112E0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv, CMBlw,  VBlw,     O,     O,     O,     O,     O,
+  /* 112F0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+  /* Grantha */
+
+  /* 11300 */ VMAbv, VMAbv, VMPst, VMPst,     O,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     O,     O,    IV,
+  /* 11310 */    IV,     O,     O,    IV,    IV,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11320 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
+  /* 11330 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O,     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,
+  /* 11360 */    IV,    IV,  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_0x11480u 4272
+
+
+  /* Tirhuta */
+
+  /* 11480 */     O,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     B,
+  /* 11490 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 114A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 114B0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VPre,  VAbv,  VPre,  VPre,  VPst,  VPre, VMAbv,
+  /* 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 4368
+
+
+  /* Siddham */
+
+  /* 11580 */    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     B,     B,
+  /* 11590 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 115A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,
+  /* 115B0 */  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VPre,  VPre,  VPre,  VPre, VMAbv, VMAbv, VMPst,     H,
+  /* 115C0 */ CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 115D0 */     O,     O,     O,     O,     O,     O,     O,     O,    IV,    IV,    IV,    IV,  VBlw,  VBlw,     O,     O,
+  /* 115E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 115F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Modi */
+
+  /* 11600 */    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     B,     B,
+  /* 11610 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11620 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11630 */  VPst,  VPst,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPst,  VPst, VMAbv, VMPst,     H,
+  /* 11640 */  VAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11650 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 11660 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11670 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Takri */
+
+  /* 11680 */    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,    IV,     B,     B,     B,     B,     B,     B,
+  /* 11690 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 116A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv, VMPst,  VAbv,  VPre,  VPst,
+  /* 116B0 */  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,     H, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 116C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 116D0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 116E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 116F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
+  /* Ahom */
+
+  /* 11700 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11710 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,  MBlw,  MPre,  MAbv,
+  /* 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,
+
+}; /* Table items: 4816; occupancy: 72% */
+
+USE_TABLE_ELEMENT_TYPE
+hb_use_get_categories (hb_codepoint_t u)
+{
+  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 (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];
+      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 (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];
+      break;
+
+    case 0xFu:
+      if (hb_in_range (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];
+      break;
+
+    case 0x11u:
+      if (hb_in_range (u, 0x11000u, 0x110BFu)) return use_table[u - 0x11000u + use_offset_0x11000u];
+      if (hb_in_range (u, 0x11100u, 0x11237u)) 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, 0x11480u, 0x114DFu)) return use_table[u - 0x11480u + use_offset_0x11480u];
+      if (hb_in_range (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u];
+      if (unlikely (u == 0x1107Fu)) return HN;
+      break;
+
+    default:
+      break;
+  }
+  return USE_O;
+}
+
+#undef B
+#undef CGJ
+#undef FM
+#undef GB
+#undef H
+#undef HN
+#undef IND
+#undef IV
+#undef N
+#undef O
+#undef R
+#undef Rsv
+#undef S
+#undef SUB
+#undef VS
+#undef WJ
+#undef ZWJ
+#undef ZWNJ
+#undef CMBlw
+#undef CMAbv
+#undef FBlw
+#undef FPst
+#undef FAbv
+#undef MPre
+#undef MBlw
+#undef MPst
+#undef MAbv
+#undef SMBlw
+#undef SMAbv
+#undef VPre
+#undef VBlw
+#undef VPst
+#undef VAbv
+#undef VMPre
+#undef VMBlw
+#undef VMPst
+#undef VMAbv
+
+/* == End of generated table == */
diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc
new file mode 100644
index 0000000..6fbfe2b
--- /dev/null
+++ b/src/hb-ot-shape-complex-use.cc
@@ -0,0 +1,588 @@
+/*
+ * Copyright © 2015  Mozilla Foundation.
+ * Copyright © 2015  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.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-use-private.hh"
+#include "hb-ot-shape-complex-arabic-private.hh"
+
+/* buffer var allocations */
+#define use_category() complex_var_u8_0()
+
+
+/*
+ * Universal Shaping Engine.
+ * https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm
+ */
+
+static const hb_tag_t
+basic_features[] =
+{
+  /*
+   * Basic features.
+   * These features are applied all at once, before reordering.
+   */
+  HB_TAG('r','k','r','f'),
+  HB_TAG('a','b','v','f'),
+  HB_TAG('b','l','w','f'),
+  HB_TAG('h','a','l','f'),
+  HB_TAG('p','s','t','f'),
+  HB_TAG('v','a','t','u'),
+  HB_TAG('c','j','c','t'),
+};
+static const hb_tag_t
+arabic_features[] =
+{
+  HB_TAG('i','s','o','l'),
+  HB_TAG('i','n','i','t'),
+  HB_TAG('m','e','d','i'),
+  HB_TAG('f','i','n','a'),
+  /* The spec doesn't specify these but we apply anyway, since our Arabic shaper
+   * does.  These are only used in Syriac spec. */
+  HB_TAG('m','e','d','2'),
+  HB_TAG('f','i','n','2'),
+  HB_TAG('f','i','n','3'),
+};
+/* Same order as arabic_features.  Don't need Syriac stuff.*/
+enum joining_form_t {
+  ISOL,
+  INIT,
+  MEDI,
+  FINA,
+  _NONE
+};
+static const hb_tag_t
+other_features[] =
+{
+  /*
+   * Other features.
+   * These features are applied all at once, after reordering.
+   */
+  HB_TAG('a','b','v','s'),
+  HB_TAG('b','l','w','s'),
+  HB_TAG('h','a','l','n'),
+  HB_TAG('p','r','e','s'),
+  HB_TAG('p','s','t','s'),
+  /* Positioning features, though we don't care about the types. */
+  HB_TAG('d','i','s','t'),
+  HB_TAG('a','b','v','m'),
+  HB_TAG('b','l','w','m'),
+};
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+		 hb_font_t *font,
+		 hb_buffer_t *buffer);
+static void
+clear_substitution_flags (const hb_ot_shape_plan_t *plan,
+			  hb_font_t *font,
+			  hb_buffer_t *buffer);
+static void
+record_rphf (const hb_ot_shape_plan_t *plan,
+	     hb_font_t *font,
+	     hb_buffer_t *buffer);
+static void
+record_pref (const hb_ot_shape_plan_t *plan,
+	     hb_font_t *font,
+	     hb_buffer_t *buffer);
+static void
+reorder (const hb_ot_shape_plan_t *plan,
+	 hb_font_t *font,
+	 hb_buffer_t *buffer);
+
+static void
+collect_features_use (hb_ot_shape_planner_t *plan)
+{
+  hb_ot_map_builder_t *map = &plan->map;
+
+  /* Do this before any lookups have been applied. */
+  map->add_gsub_pause (setup_syllables);
+
+  /* "Default glyph pre-processing group" */
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+  map->add_global_bool_feature (HB_TAG('n','u','k','t'));
+  map->add_global_bool_feature (HB_TAG('a','k','h','n'));
+
+  /* "Reordering group" */
+  map->add_gsub_pause (clear_substitution_flags);
+  map->add_feature (HB_TAG('r','p','h','f'), 1, F_MANUAL_ZWJ);
+  map->add_gsub_pause (record_rphf);
+  map->add_gsub_pause (clear_substitution_flags);
+  map->add_feature (HB_TAG('p','r','e','f'), 1, F_GLOBAL | F_MANUAL_ZWJ);
+  map->add_gsub_pause (record_pref);
+
+  /* "Orthographic unit shaping group" */
+  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 (reorder);
+
+  /* "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);
+
+  /* "Standard typographic presentation" and "Positional feature application" */
+  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
+    map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+}
+
+struct use_shape_plan_t
+{
+  ASSERT_POD ();
+
+  hb_mask_t rphf_mask;
+
+  arabic_shape_plan_t *arabic_plan;
+};
+
+static bool
+has_arabic_joining (hb_script_t script)
+{
+  /* List of scripts that have data in arabic-table. */
+  switch ((int) script)
+  {
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_ARABIC:
+
+    /* Unicode-3.0 additions */
+    case HB_SCRIPT_MONGOLIAN:
+    case HB_SCRIPT_SYRIAC:
+
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_NKO:
+    case HB_SCRIPT_PHAGS_PA:
+
+    /* Unicode-6.0 additions */
+    case HB_SCRIPT_MANDAIC:
+
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_PSALTER_PAHLAVI:
+
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+static void *
+data_create_use (const hb_ot_shape_plan_t *plan)
+{
+  use_shape_plan_t *use_plan = (use_shape_plan_t *) calloc (1, sizeof (use_shape_plan_t));
+  if (unlikely (!use_plan))
+    return NULL;
+
+  use_plan->rphf_mask = plan->map.get_1_mask (HB_TAG('r','p','h','f'));
+
+  if (has_arabic_joining (plan->props.script))
+  {
+    use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan);
+    if (unlikely (!use_plan->arabic_plan))
+    {
+      free (use_plan);
+      return NULL;
+    }
+  }
+
+  return use_plan;
+}
+
+static void
+data_destroy_use (void *data)
+{
+  use_shape_plan_t *use_plan = (use_shape_plan_t *) data;
+
+  if (use_plan->arabic_plan)
+    data_destroy_arabic (use_plan->arabic_plan);
+
+  free (data);
+}
+
+enum syllable_type_t {
+  independent_cluster,
+  virama_terminated_cluster,
+  consonant_cluster,
+  vowel_cluster,
+  number_joiner_terminated_cluster,
+  numeral_cluster,
+  symbol_cluster,
+  broken_cluster,
+};
+
+#include "hb-ot-shape-complex-use-machine.hh"
+
+
+static void
+setup_masks_use (const hb_ot_shape_plan_t *plan,
+		 hb_buffer_t              *buffer,
+		 hb_font_t                *font HB_UNUSED)
+{
+  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+
+  /* Do this before allocating use_category(). */
+  if (use_plan->arabic_plan)
+  {
+    setup_masks_arabic_plan (use_plan->arabic_plan, buffer, plan->props.script);
+  }
+
+  HB_BUFFER_ALLOCATE_VAR (buffer, use_category);
+
+  /* We cannot setup masks here.  We save information about characters
+   * and setup masks later on in a pause-callback. */
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].use_category() = hb_use_get_categories (info[i].codepoint);
+}
+
+static void
+setup_rphf_mask (const hb_ot_shape_plan_t *plan,
+		 hb_buffer_t *buffer)
+{
+  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+
+  hb_mask_t mask = use_plan->rphf_mask;
+  if (!mask) return;
+
+  hb_glyph_info_t *info = buffer->info;
+
+  foreach_syllable (buffer, start, end)
+  {
+    unsigned int limit = info[start].use_category() == USE_R ? 1 : MIN (3u, end - start);
+    for (unsigned int i = start; i < start + limit; i++)
+      info[i].mask |= mask;
+  }
+}
+
+static void
+setup_topographical_masks (const hb_ot_shape_plan_t *plan,
+			   hb_buffer_t *buffer)
+{
+  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+  if (use_plan->arabic_plan)
+    return;
+
+  ASSERT_STATIC (INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4);
+  hb_mask_t masks[4], all_masks = 0;
+  for (unsigned int i = 0; i < 4; i++)
+  {
+    masks[i] = plan->map.get_1_mask (arabic_features[i]);
+    if (masks[i] == plan->map.get_global_mask ())
+      masks[i] = 0;
+    all_masks |= masks[i];
+  }
+  if (!all_masks)
+    return;
+  hb_mask_t other_masks = ~all_masks;
+
+  unsigned int last_start = 0;
+  joining_form_t last_form = _NONE;
+  hb_glyph_info_t *info = buffer->info;
+  foreach_syllable (buffer, start, end)
+  {
+    syllable_type_t syllable_type = (syllable_type_t) (info[start].syllable() & 0x0F);
+    switch (syllable_type)
+    {
+      case independent_cluster:
+      case symbol_cluster:
+	/* These don't join.  Nothing to do. */
+	last_form = _NONE;
+	break;
+
+      case virama_terminated_cluster:
+      case consonant_cluster:
+      case vowel_cluster:
+      case number_joiner_terminated_cluster:
+      case numeral_cluster:
+      case broken_cluster:
+
+	bool join = last_form == FINA || last_form == ISOL;
+
+	if (join)
+	{
+	  /* Fixup previous syllable's form. */
+	  last_form = last_form == FINA ? MEDI : INIT;
+	  for (unsigned int i = last_start; i < start; i++)
+	    info[i].mask = (info[i].mask & other_masks) | masks[last_form];
+	}
+
+	/* Form for this syllable. */
+	last_form = join ? FINA : ISOL;
+	for (unsigned int i = start; i < end; i++)
+	  info[i].mask = (info[i].mask & other_masks) | masks[last_form];
+
+	break;
+    }
+
+    last_start = start;
+  }
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+		 hb_font_t *font HB_UNUSED,
+		 hb_buffer_t *buffer)
+{
+  find_syllables (buffer);
+  setup_rphf_mask (plan, buffer);
+  setup_topographical_masks (plan, buffer);
+}
+
+static void
+clear_substitution_flags (const hb_ot_shape_plan_t *plan,
+			  hb_font_t *font HB_UNUSED,
+			  hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    _hb_glyph_info_clear_substituted (&info[i]);
+}
+
+static void
+record_rphf (const hb_ot_shape_plan_t *plan,
+	     hb_font_t *font,
+	     hb_buffer_t *buffer)
+{
+  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+
+  hb_mask_t mask = use_plan->rphf_mask;
+  if (!mask) return;
+  hb_glyph_info_t *info = buffer->info;
+
+  foreach_syllable (buffer, start, end)
+  {
+    /* Mark a substituted repha as USE_R. */
+    for (unsigned int i = start; i < end && (info[i].mask & mask); i++)
+      if (_hb_glyph_info_substituted (&info[i]))
+      {
+	info[i].use_category() = USE_R;
+	break;
+      }
+  }
+}
+
+static void
+record_pref (const hb_ot_shape_plan_t *plan,
+	     hb_font_t *font,
+	     hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+
+  foreach_syllable (buffer, start, end)
+  {
+    /* Mark a substituted pref as VPre, as they behave the same way. */
+    for (unsigned int i = start; i < end; i++)
+      if (_hb_glyph_info_substituted (&info[i]))
+      {
+	info[i].use_category() = USE_VPre;
+	break;
+      }
+  }
+}
+
+static inline bool
+is_halant (const hb_glyph_info_t &info)
+{
+  return info.use_category() == USE_H && !_hb_glyph_info_ligated (&info);
+}
+
+static void
+reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
+{
+  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) &
+		  (FLAG (virama_terminated_cluster) |
+		   FLAG (consonant_cluster) |
+		   FLAG (vowel_cluster) |
+		   FLAG (broken_cluster) |
+		   0))))
+    return;
+
+  hb_glyph_info_t *info = buffer->info;
+
+#define BASE_FLAGS (FLAG (USE_B) | FLAG (USE_GB) | FLAG (USE_IV))
+
+  /* Move things forward. */
+  if (info[start].use_category() == USE_R && end - start > 1)
+  {
+    /* Got a repha.  Reorder it to after first base, before first halant. */
+    for (unsigned int i = start + 1; i < end; i++)
+      if ((FLAG_UNSAFE (info[i].use_category()) & (BASE_FLAGS)) || is_halant (info[i]))
+      {
+	/* If we hit a halant, move before it; otherwise it's a base: move to it's
+	 * place, and shift things in between backward. */
+
+	if (is_halant (info[i]))
+	  i--;
+
+	buffer->merge_clusters (start, i + 1);
+	hb_glyph_info_t t = info[start];
+	memmove (&info[start], &info[start + 1], (i - start) * sizeof (info[0]));
+	info[i] = t;
+
+	break;
+      }
+  }
+
+  /* Move things back. */
+  unsigned int j = end;
+  for (unsigned int i = start; i < end; i++)
+  {
+    uint32_t flag = FLAG_UNSAFE (info[i].use_category());
+    if ((flag & (BASE_FLAGS)) || is_halant (info[i]))
+    {
+      /* If we hit a halant, move after it; otherwise it's a base: move to it's
+       * place, and shift things in between backward. */
+      if (is_halant (info[i]))
+	j = i + 1;
+      else
+	j = i;
+    }
+    else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) &&
+	     /* Only move the first component of a MultipleSubst. */
+	     0 == _hb_glyph_info_get_lig_comp (&info[i]) &&
+	     j < i)
+    {
+      buffer->merge_clusters (j, i + 1);
+      hb_glyph_info_t t = info[i];
+      memmove (&info[j + 1], &info[j], (i - j) * sizeof (info[0]));
+      info[j] = t;
+    }
+  }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+		       hb_font_t *font,
+		       hb_buffer_t *buffer)
+{
+  /* Note: This loop is extra overhead, but should not be measurable. */
+  bool has_broken_syllables = false;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    {
+      has_broken_syllables = true;
+      break;
+    }
+  if (likely (!has_broken_syllables))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  if (!font->get_glyph (0x25CCu, 0, &dottedcircle.codepoint))
+    return;
+  dottedcircle.use_category() = hb_use_get_categories (0x25CC);
+
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  unsigned int last_syllable = 0;
+  while (buffer->idx < buffer->len && !buffer->in_error)
+  {
+    unsigned int syllable = buffer->cur().syllable();
+    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    {
+      last_syllable = syllable;
+
+      hb_glyph_info_t ginfo = dottedcircle;
+      ginfo.cluster = buffer->cur().cluster;
+      ginfo.mask = buffer->cur().mask;
+      ginfo.syllable() = buffer->cur().syllable();
+      /* TODO Set glyph_props? */
+
+      /* Insert dottedcircle after possible Repha. */
+      while (buffer->idx < buffer->len && !buffer->in_error &&
+	     last_syllable == buffer->cur().syllable() &&
+	     buffer->cur().use_category() == USE_R)
+        buffer->next_glyph ();
+
+      buffer->output_info (ginfo);
+    }
+    else
+      buffer->next_glyph ();
+  }
+
+  buffer->swap_buffers ();
+}
+
+static void
+reorder (const hb_ot_shape_plan_t *plan,
+	 hb_font_t *font,
+	 hb_buffer_t *buffer)
+{
+  insert_dotted_circles (plan, font, buffer);
+
+  hb_glyph_info_t *info = buffer->info;
+
+  foreach_syllable (buffer, start, end)
+    reorder_syllable (buffer, start, end);
+
+  /* Zero syllables now... */
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].syllable() = 0;
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
+}
+
+static bool
+compose_use (const hb_ot_shape_normalize_context_t *c,
+	     hb_codepoint_t  a,
+	     hb_codepoint_t  b,
+	     hb_codepoint_t *ab)
+{
+  /* Avoid recomposing split matras. */
+  if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
+    return false;
+
+  return (bool)c->unicode->compose (a, b, ab);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
+{
+  "use",
+  collect_features_use,
+  NULL, /* override_features */
+  data_create_use,
+  data_destroy_use,
+  NULL, /* preprocess_text */
+  NULL, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+  NULL, /* decompose */
+  compose_use,
+  setup_masks_use,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+  false, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-fallback-private.hh b/src/hb-ot-shape-fallback-private.hh
index ec65351..e134224 100644
--- a/src/hb-ot-shape-fallback-private.hh
+++ b/src/hb-ot-shape-fallback-private.hh
@@ -45,5 +45,9 @@
 					     hb_font_t *font,
 					     hb_buffer_t  *buffer);
 
+HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
+					       hb_font_t *font,
+					       hb_buffer_t  *buffer);
+
 
 #endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index 80d7da8..c9cf737 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -224,7 +224,7 @@
 	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
         break;
       }
-      /* Fall through */
+      HB_FALLTHROUGH;
 
     default:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
@@ -259,6 +259,7 @@
     case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
       /* Add gap, fall-through. */
       base_extents.height -= y_gap;
+      HB_FALLTHROUGH;
 
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
@@ -279,6 +280,7 @@
       /* Add gap, fall-through. */
       base_extents.y_bearing += y_gap;
       base_extents.height -= y_gap;
+      HB_FALLTHROUGH;
 
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
@@ -418,13 +420,12 @@
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
   unsigned int start = 0;
-  unsigned int last_cluster = buffer->info[0].cluster;
   unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
-    if (buffer->info[i].cluster != last_cluster) {
+    if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
       position_cluster (plan, font, buffer, start, i);
       start = i;
-      last_cluster = buffer->info[i].cluster;
     }
   position_cluster (plan, font, buffer, start, count);
 }
@@ -441,13 +442,15 @@
   OT::hb_apply_context_t c (1, font, buffer);
   c.set_lookup_mask (plan->kern_mask);
   c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
+  OT::hb_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
+  skippy_iter.init (&c);
 
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   hb_glyph_position_t *pos = buffer->pos;
   for (unsigned int idx = 0; idx < count;)
   {
-    OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1);
+    skippy_iter.reset (idx, 1);
     if (!skippy_iter.next ())
     {
       idx++;
@@ -481,3 +484,70 @@
     idx = skippy_iter.idx;
   }
 }
+
+
+/* Adjusts width of various spaces. */
+void
+_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
+			      hb_font_t *font,
+			      hb_buffer_t  *buffer)
+{
+  if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+    return;
+
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
+    {
+      hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]);
+      hb_codepoint_t glyph;
+      typedef hb_unicode_funcs_t t;
+      switch (space_type)
+      {
+	case t::NOT_SPACE: /* Shouldn't happen. */
+	case t::SPACE:
+	  break;
+
+	case t::SPACE_EM:
+	case t::SPACE_EM_2:
+	case t::SPACE_EM_3:
+	case t::SPACE_EM_4:
+	case t::SPACE_EM_5:
+	case t::SPACE_EM_6:
+	case t::SPACE_EM_16:
+	  pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
+	  break;
+
+	case t::SPACE_4_EM_18:
+	  pos[i].x_advance = font->x_scale * 4 / 18;
+	  break;
+
+	case t::SPACE_FIGURE:
+	  for (char u = '0'; u <= '9'; u++)
+	    if (font->get_glyph (u, 0, &glyph))
+	    {
+	      pos[i].x_advance = font->get_glyph_h_advance (glyph);
+	      break;
+	    }
+	  break;
+
+	case t::SPACE_PUNCTUATION:
+	  if (font->get_glyph ('.', 0, &glyph))
+	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
+	  else if (font->get_glyph (',', 0, &glyph))
+	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
+	  break;
+
+	case t::SPACE_NARROW:
+	  /* Half-space?
+	   * Unicode doc http://www.unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM.
+	   * However, in my testing, many fonts have their regular space being about that
+	   * size.  To me, a percentage of the space width makes more sense.  Half is as
+	   * good as any. */
+	  pos[i].x_advance /= 2;
+	  break;
+      }
+    }
+}
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 4287253..3f00b8e 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -62,24 +62,12 @@
  *     with previous base, use that.  This needs the itemizer to have this
  *     knowledge too.  We need to provide assistance to the itemizer.
  *
- *   - When a font does not support a character but supports its decomposition,
- *     well, use the decomposition (preferring the canonical decomposition, but
- *     falling back to the compatibility decomposition if necessary).  The
- *     compatibility decomposition is really nice to have, for characters like
- *     ellipsis, or various-sized space characters.
+ *   - When a font does not support a character but supports its canonical
+ *     decomposition, well, use the decomposition.
  *
  *   - The complex shapers can customize the compose and decompose functions to
  *     offload some of their requirements to the normalizer.  For example, the
  *     Indic shaper may want to disallow recomposing of two matras.
- *
- *   - We try compatibility decomposition if decomposing through canonical
- *     decomposition alone failed to find a sequence that the font supports.
- *     We don't try compatibility decomposition recursively during the canonical
- *     decomposition phase.  This has minimal impact.  There are only a handful
- *     of Greek letter that have canonical decompositions that include characters
- *     with compatibility decomposition.  Those can be found using this command:
- *
- *     egrep  "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt
  */
 
 static bool
@@ -88,7 +76,7 @@
 		   hb_codepoint_t *a,
 		   hb_codepoint_t *b)
 {
-  return c->unicode->decompose (ab, a, b);
+  return (bool) c->unicode->decompose (ab, a, b);
 }
 
 static bool
@@ -97,7 +85,7 @@
 		 hb_codepoint_t  b,
 		 hb_codepoint_t *ab)
 {
-  return c->unicode->compose (a, b, ab);
+  return (bool) c->unicode->compose (a, b, ab);
 }
 
 static inline void
@@ -110,8 +98,8 @@
 output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
 {
   buffer->cur().glyph_index() = glyph;
-  buffer->output_glyph (unichar);
-  _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
+  buffer->output_glyph (unichar); /* This is very confusing indeed. */
+  _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
 }
 
 static inline void
@@ -139,7 +127,7 @@
       (b && !font->get_glyph (b, 0, &b_glyph)))
     return 0;
 
-  bool has_a = font->get_glyph (a, 0, &a_glyph);
+  bool has_a = (bool) font->get_glyph (a, 0, &a_glyph);
   if (shortest && has_a) {
     /* Output a and b */
     output_char (buffer, a, a_glyph);
@@ -171,45 +159,57 @@
   return 0;
 }
 
-/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
-static inline unsigned int
-decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u)
-{
-  unsigned int len, i;
-  hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
-  hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN];
-
-  len = c->buffer->unicode->decompose_compatibility (u, decomposed);
-  if (!len)
-    return 0;
-
-  for (i = 0; i < len; i++)
-    if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i]))
-      return 0;
-
-  for (i = 0; i < len; i++)
-    output_char (c->buffer, decomposed[i], glyphs[i]);
-
-  return len;
-}
-
 static inline void
 decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
 {
   hb_buffer_t * const buffer = c->buffer;
+  hb_codepoint_t u = buffer->cur().codepoint;
   hb_codepoint_t glyph;
 
-  /* Kind of a cute waterfall here... */
-  if (shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
+  if (shortest && c->font->get_glyph (u, 0, &glyph))
+  {
     next_char (buffer, glyph);
-  else if (decompose (c, shortest, buffer->cur().codepoint))
+    return;
+  }
+
+  if (decompose (c, shortest, u))
+  {
     skip_char (buffer);
-  else if (!shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
+    return;
+  }
+
+  if (!shortest && c->font->get_glyph (u, 0, &glyph))
+  {
     next_char (buffer, glyph);
-  else if (decompose_compatibility (c, buffer->cur().codepoint))
-    skip_char (buffer);
-  else
-    next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
+    return;
+  }
+
+  if (_hb_glyph_info_is_unicode_space (&buffer->cur()))
+  {
+    hb_codepoint_t space_glyph;
+    hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u);
+    if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_glyph (0x0020u, 0, &space_glyph))
+    {
+      _hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type);
+      next_char (buffer, space_glyph);
+      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK;
+      return;
+    }
+  }
+
+  if (u == 0x2011u)
+  {
+    /* U+2011 is the only sensible character that is a no-break version of another character
+     * and not a space.  The space ones are handled already.  Handle this lone one. */
+    hb_codepoint_t other_glyph;
+    if (c->font->get_glyph (0x2010u, 0, &other_glyph))
+    {
+      next_char (buffer, other_glyph);
+      return;
+    }
+  }
+
+  next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
 }
 
 static inline void
@@ -218,7 +218,7 @@
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
   hb_buffer_t * const buffer = c->buffer;
   hb_font_t * const font = c->font;
-  for (; buffer->idx < end - 1;) {
+  for (; buffer->idx < end - 1 && !buffer->in_error;) {
     if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
       /* The next two lines are some ugly lines... But work. */
       if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
@@ -254,13 +254,13 @@
 decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
 {
   hb_buffer_t * const buffer = c->buffer;
-  for (unsigned int i = buffer->idx; i < end; i++)
+  for (unsigned int i = buffer->idx; i < end && !buffer->in_error; i++)
     if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
       handle_variation_selector_cluster (c, end, short_circuit);
       return;
     }
 
-  while (buffer->idx < end)
+  while (buffer->idx < end && !buffer->in_error)
     decompose_current_character (c, short_circuit);
 }
 
@@ -289,6 +289,8 @@
 			hb_buffer_t *buffer,
 			hb_font_t *font)
 {
+  if (unlikely (!buffer->len)) return;
+
   _hb_buffer_assert_unicode_vars (buffer);
 
   hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
@@ -318,11 +320,11 @@
 
   buffer->clear_output ();
   count = buffer->len;
-  for (buffer->idx = 0; buffer->idx < count;)
+  for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
   {
     unsigned int end;
     for (end = buffer->idx + 1; end < count; end++)
-      if (buffer->cur().cluster != buffer->info[end].cluster)
+      if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
         break;
 
     decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
@@ -343,15 +345,13 @@
       if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
         break;
 
-    /* We are going to do a bubble-sort.  Only do this if the
-     * sequence is short.  Doing it on long sequences can result
-     * in an O(n^2) DoS. */
+    /* We are going to do a O(n^2).  Only do this if the sequence is short. */
     if (end - i > 10) {
       i = end;
       continue;
     }
 
-    hb_bubble_sort (buffer->info + i, end - i, compare_combining_class);
+    buffer->sort (i, end, compare_combining_class);
 
     i = end;
   }
@@ -370,7 +370,7 @@
   count = buffer->len;
   unsigned int starter = 0;
   buffer->next_glyph ();
-  while (buffer->idx < count)
+  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.
@@ -399,7 +399,7 @@
       /* 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->unicode);
+      _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
 
       continue;
     }
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index a0b503a..42b921c 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -59,10 +59,6 @@
   HB_TAG('r','c','l','t'),
 };
 
-static hb_tag_t vertical_features[] = {
-  HB_TAG('v','e','r','t'),
-};
-
 
 
 static void
@@ -105,10 +101,13 @@
 			(horizontal_features[i] == HB_TAG('k','e','r','n') ?
 			 F_HAS_FALLBACK : F_NONE));
   else
-    for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++)
-      map->add_feature (vertical_features[i], 1, F_GLOBAL |
-			(vertical_features[i] == HB_TAG('v','k','r','n') ?
-			 F_HAS_FALLBACK : F_NONE));
+  {
+    /* 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 */
+    map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
+  }
 
   if (planner->shaper->override_features)
     planner->shaper->override_features (planner);
@@ -146,7 +145,7 @@
 struct hb_ot_shaper_font_data_t {};
 
 hb_ot_shaper_font_data_t *
-_hb_ot_shaper_font_data_create (hb_font_t *font)
+_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
 {
   return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
@@ -229,7 +228,7 @@
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    _hb_glyph_info_set_unicode_props (&info[i], buffer->unicode);
+    _hb_glyph_info_set_unicode_props (&info[i], buffer);
 }
 
 static void
@@ -246,7 +245,7 @@
 
   hb_glyph_info_t dottedcircle = {0};
   dottedcircle.codepoint = 0x25CCu;
-  _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
+  _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
 
   buffer->clear_output ();
 
@@ -255,7 +254,7 @@
   info.cluster = buffer->cur().cluster;
   info.mask = buffer->cur().mask;
   buffer->output_info (info);
-  while (buffer->idx < buffer->len)
+  while (buffer->idx < buffer->len && !buffer->in_error)
     buffer->next_glyph ();
 
   buffer->swap_buffers ();
@@ -264,11 +263,24 @@
 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)
+    return;
+
+  /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
+  unsigned int base = 0;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
-    if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
-      buffer->merge_clusters (i - 1, i + 1);
+  {
+    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);
+      base = i;
+    }
+  }
+  buffer->merge_clusters (base, count);
 }
 
 static void
@@ -283,7 +295,28 @@
   if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
       (HB_DIRECTION_IS_VERTICAL   (direction) && direction != HB_DIRECTION_TTB))
   {
-    hb_buffer_reverse_clusters (buffer);
+    /* Same loop as hb_form_clusters().
+     * Since form_clusters() merged clusters already, we don't merge. */
+    unsigned int base = 0;
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    for (unsigned int i = 1; i < count; i++)
+    {
+      if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
+      {
+	if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+	  buffer->merge_clusters (base, i);
+	buffer->reverse_range (base, i);
+
+	base = i;
+      }
+    }
+    if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
+      buffer->merge_clusters (base, count);
+    buffer->reverse_range (base, count);
+
+    buffer->reverse ();
+
     buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
   }
 }
@@ -305,7 +338,7 @@
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++) {
     hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
-    if (likely (codepoint == info[i].codepoint))
+    if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
       info[i].mask |= rtlm_mask;
     else
       info[i].codepoint = codepoint;
@@ -315,7 +348,8 @@
 static inline void
 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
 {
-  if (!c->plan->has_frac)
+  if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
+      !c->plan->has_frac)
     return;
 
   hb_buffer_t *buffer = c->buffer;
@@ -380,6 +414,103 @@
   }
 }
 
+static void
+hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
+{
+  hb_buffer_t *buffer = c->buffer;
+
+  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
+      (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
+    return;
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+  unsigned int i = 0;
+  for (i = 0; i < count; i++)
+    if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
+      pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
+}
+
+static void
+hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
+{
+  hb_buffer_t *buffer = c->buffer;
+
+  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
+      (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
+    return;
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+  unsigned int i = 0;
+  for (i = 0; i < count; i++)
+  {
+    if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
+      break;
+  }
+
+  /* No default-ignorables found; return. */
+  if (i == count)
+    return;
+
+  hb_codepoint_t space;
+  if (c->font->get_glyph (' ', 0, &space))
+  {
+    /* Replace default-ignorables with a zero-advance space glyph. */
+    for (/*continue*/; i < count; i++)
+    {
+      if (_hb_glyph_info_is_default_ignorable (&info[i]))
+	info[i].codepoint = space;
+    }
+  }
+  else
+  {
+    /* Merge clusters and delete default-ignorables.
+     * NOTE! We can't use out-buffer as we have positioning data. */
+    unsigned int j = i;
+    for (; i < count; i++)
+    {
+      if (_hb_glyph_info_is_default_ignorable (&info[i]))
+      {
+	/* Merge clusters.
+	 * Same logic as buffer->delete_glyph(), but for in-place removal. */
+
+	unsigned int cluster = info[i].cluster;
+	if (i + 1 < count && cluster == info[i + 1].cluster)
+	  continue; /* Cluster survives; do nothing. */
+
+	if (j)
+	{
+	  /* Merge cluster backward. */
+	  if (cluster < info[j - 1].cluster)
+	  {
+	    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;
+	  }
+	  continue;
+	}
+
+	if (i + 1 < count)
+	  buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
+
+	continue;
+      }
+
+      if (j != i)
+      {
+	info[j] = info[i];
+	pos[j] = pos[i];
+      }
+      j++;
+    }
+    buffer->len = j;
+  }
+}
+
+
 static inline void
 hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
 {
@@ -388,6 +519,8 @@
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
     info[i].codepoint = info[i].glyph_index();
+
+  buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
 }
 
 static inline void
@@ -397,7 +530,7 @@
   hb_glyph_info_t *info = c->buffer->info;
   for (unsigned int i = 0; i < count; i++)
   {
-    hb_ot_layout_glyph_class_mask_t klass;
+    hb_ot_layout_glyph_props_flags_t klass;
 
     /* Never mark default-ignorables as marks.
      * They won't get in the way of lookups anyway,
@@ -421,9 +554,6 @@
 {
   hb_buffer_t *buffer = c->buffer;
 
-  if (c->plan->shaper->preprocess_text)
-    c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
-
   hb_ot_shape_initialize_masks (c);
 
   hb_ot_mirror_chars (c);
@@ -448,7 +578,6 @@
 {
   hb_buffer_t *buffer = c->buffer;
 
-  _hb_buffer_allocate_gsubgpos_vars (buffer);
   hb_ot_layout_substitute_start (c->font, buffer);
 
   if (!hb_ot_layout_has_glyph_classes (c->face))
@@ -456,8 +585,6 @@
 
   c->plan->substitute (c->font, buffer);
 
-  hb_ot_layout_substitute_finish (c->font, buffer);
-
   return;
 }
 
@@ -465,6 +592,9 @@
 hb_ot_substitute (hb_ot_shape_context_t *c)
 {
   hb_ot_substitute_default (c);
+
+  _hb_buffer_allocate_gsubgpos_vars (c->buffer);
+
   hb_ot_substitute_complex (c);
 }
 
@@ -485,20 +615,6 @@
 }
 
 static inline void
-zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
-{
-  unsigned int count = buffer->len;
-  hb_glyph_info_t *info = buffer->info;
-  for (unsigned int i = 0; i < count; i++)
-    if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
-    {
-      if (adjust_offsets)
-        adjust_mark_offsets (&buffer->pos[i]);
-      zero_mark_width (&buffer->pos[i]);
-    }
-}
-
-static inline void
 zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
 {
   unsigned int count = buffer->len;
@@ -519,26 +635,41 @@
   unsigned int count = c->buffer->len;
   hb_glyph_info_t *info = c->buffer->info;
   hb_glyph_position_t *pos = c->buffer->pos;
-  for (unsigned int i = 0; i < count; i++)
-  {
-    c->font->get_glyph_advance_for_direction (info[i].codepoint,
-					      direction,
-					      &pos[i].x_advance,
-					      &pos[i].y_advance);
-    c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
-						  direction,
-						  &pos[i].x_offset,
-						  &pos[i].y_offset);
 
+  if (HB_DIRECTION_IS_HORIZONTAL (direction))
+  {
+    for (unsigned int i = 0; i < count; i++)
+      pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
+    /* 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);
   }
+  else
+  {
+    for (unsigned int i = 0; i < count; i++)
+    {
+      pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
+      c->font->subtract_glyph_v_origin (info[i].codepoint,
+					&pos[i].x_offset,
+					&pos[i].y_offset);
+    }
+  }
+  if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
+    _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
 }
 
 static inline bool
 hb_ot_position_complex (hb_ot_shape_context_t *c)
 {
+  hb_ot_layout_position_start (c->font, c->buffer);
+
   bool ret = false;
   unsigned int count = c->buffer->len;
-  bool has_positioning = hb_ot_layout_has_positioning (c->face);
+  bool has_positioning = (bool) hb_ot_layout_has_positioning (c->face);
+
   /* If the font has no GPOS, AND, no fallback positioning will
    * happen, AND, direction is forward, then when zeroing mark
    * widths, we shift the mark with it, such that the mark
@@ -557,15 +688,8 @@
       zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
       break;
 
-    /* Not currently used for any shaper:
-    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
-      zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
-      break;
-    */
-
     default:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
-    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
       break;
   }
@@ -575,58 +699,56 @@
     hb_glyph_info_t *info = c->buffer->info;
     hb_glyph_position_t *pos = c->buffer->pos;
 
-    /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
+    /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
 
-    for (unsigned int i = 0; i < count; i++) {
-      c->font->add_glyph_origin_for_direction (info[i].codepoint,
-					       HB_DIRECTION_LTR,
-					       &pos[i].x_offset,
-					       &pos[i].y_offset);
-    }
+    /* 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);
 
-    for (unsigned int i = 0; i < count; i++) {
-      c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
-						    HB_DIRECTION_LTR,
-						    &pos[i].x_offset,
-						    &pos[i].y_offset);
-    }
+    /* 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);
 
     ret = true;
   }
 
   switch (c->plan->shaper->zero_width_marks)
   {
-    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
-      zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
-      break;
-
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
       zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
       break;
 
     default:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
-    //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
       break;
   }
 
+  /* Finishing off GPOS has to follow a certain order. */
+  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);
+
   return ret;
 }
 
 static inline void
 hb_ot_position (hb_ot_shape_context_t *c)
 {
-  hb_ot_layout_position_start (c->font, c->buffer);
+  c->buffer->clear_positions ();
 
   hb_ot_position_default (c);
 
   hb_bool_t fallback = !hb_ot_position_complex (c);
 
-  hb_ot_layout_position_finish (c->font, c->buffer);
-
   if (fallback && c->plan->shaper->fallback_position)
     _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
 
@@ -642,59 +764,18 @@
 }
 
 
-/* Post-process */
-
-static void
-hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
-{
-  if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
-    return;
-
-  hb_codepoint_t space;
-  enum {
-    SPACE_DONT_KNOW,
-    SPACE_AVAILABLE,
-    SPACE_UNAVAILABLE
-  } space_status = SPACE_DONT_KNOW;
-
-  unsigned int count = c->buffer->len;
-  hb_glyph_info_t *info = c->buffer->info;
-  hb_glyph_position_t *pos = c->buffer->pos;
-  unsigned int j = 0;
-  for (unsigned int i = 0; i < count; i++)
-  {
-    if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
-		  _hb_glyph_info_is_default_ignorable (&info[i])))
-    {
-      if (space_status == SPACE_DONT_KNOW)
-	space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
-
-      if (space_status == SPACE_AVAILABLE)
-      {
-	info[i].codepoint = space;
-	pos[i].x_advance = 0;
-	pos[i].y_advance = 0;
-      }
-      else
-	continue; /* Delete it. */
-    }
-    if (j != i)
-    {
-      info[j] = info[i];
-      pos[j] = pos[i];
-    }
-    j++;
-  }
-  c->buffer->len = j;
-}
-
-
 /* Pull it all together! */
 
 static void
 hb_ot_shape_internal (hb_ot_shape_context_t *c)
 {
   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)))
+  {
+    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
+			      (unsigned) HB_BUFFER_MAX_LEN_MIN);
+  }
 
   /* Save the original direction, we use it later. */
   c->target_direction = c->buffer->props.direction;
@@ -709,15 +790,22 @@
 
   hb_ensure_native_direction (c->buffer);
 
+  if (c->plan->shaper->preprocess_text)
+    c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
+
   hb_ot_substitute (c);
   hb_ot_position (c);
 
   hb_ot_hide_default_ignorables (c);
 
+  if (c->plan->shaper->postprocess_glyphs)
+    c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
+
   _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->deallocate_var_all ();
 }
 
@@ -736,6 +824,11 @@
 }
 
 
+/**
+ * hb_ot_shape_plan_collect_lookups:
+ *
+ * Since: 0.9.7
+ **/
 void
 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
 				  hb_tag_t         table_tag,
@@ -766,6 +859,11 @@
 }
 
 
+/**
+ * hb_ot_shape_glyphs_closure:
+ *
+ * Since: 0.9.2
+ **/
 void
 hb_ot_shape_glyphs_closure (hb_font_t          *font,
 			    hb_buffer_t        *buffer,
diff --git a/src/hb-ot-shape.h b/src/hb-ot-shape.h
index 1402f54..7b1bcc0 100644
--- a/src/hb-ot-shape.h
+++ b/src/hb-ot-shape.h
@@ -36,14 +36,14 @@
 HB_BEGIN_DECLS
 
 /* TODO port to shape-plan / set. */
-void
+HB_EXTERN void
 hb_ot_shape_glyphs_closure (hb_font_t          *font,
 			    hb_buffer_t        *buffer,
 			    const hb_feature_t *features,
 			    unsigned int        num_features,
 			    hb_set_t           *glyphs);
 
-void
+HB_EXTERN void
 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
 				  hb_tag_t         table_tag,
 				  hb_set_t        *lookup_indexes /* OUT */);
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index 878dd79..9a6a120 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -175,6 +175,11 @@
  *
  * Some items still missing.  Those are commented out at the end.
  * Keep sorted for bsearch.
+ *
+ * Updated as of 2015-05-06: OT1.7 on MS website has some newer
+ * items that we don't have here, eg. Zazaki.  This is the new
+ * items in OpenType 1.7 (red items), most of which we have:
+ * http://www.microsoft.com/typography/otspec170/languagetags.htm
  */
 
 static const LangTag ot_languages[] = {
@@ -217,9 +222,9 @@
   {"bci",	HB_TAG('B','A','U',' ')},	/* Baoulé */
   {"bcl",	HB_TAG('B','I','K',' ')},	/* Central Bikol */
   {"bcq",	HB_TAG('B','C','H',' ')},	/* Bench */
-  {"be",	HB_TAG('B','E','L',' ')},  	/* Belarusian */
+  {"be",	HB_TAG('B','E','L',' ')},	/* Belarusian */
   {"bem",	HB_TAG('B','E','M',' ')},	/* Bemba (Zambia) */
-  {"ber",	HB_TAG('B','E','R',' ')},  	/* Berber [family] */
+  {"ber",	HB_TAG('B','E','R',' ')},	/* Berber [family] */
   {"bfq",	HB_TAG('B','A','D',' ')},	/* Badaga */
   {"bft",	HB_TAG('B','L','T',' ')},	/* Balti */
   {"bfy",	HB_TAG('B','A','G',' ')},	/* Baghelkhandi */
@@ -346,11 +351,10 @@
   {"gv",	HB_TAG('M','N','X',' ')},	/* Manx */
   {"ha",	HB_TAG('H','A','U',' ')},	/* Hausa */
   {"har",	HB_TAG('H','R','I',' ')},	/* Harari */
-  {"haw",	HB_TAG('H','A','W',' ')},  	/* Hawaiian */
-  {"hay",	HB_TAG('H','A','Y',' ')},  	/* Haya */
-  {"haz",	HB_TAG('H','A','Z',' ')},  	/* Hazaragi */
+  {"haw",	HB_TAG('H','A','W',' ')},	/* Hawaiian */
+  {"hay",	HB_TAG('H','A','Y',' ')},	/* Haya */
+  {"haz",	HB_TAG('H','A','Z',' ')},	/* Hazaragi */
   {"he",	HB_TAG('I','W','R',' ')},	/* Hebrew */
-  {"hz",	HB_TAG('H','E','R',' ')},	/* Herero */
   {"hi",	HB_TAG('H','I','N',' ')},	/* Hindi */
   {"hil",	HB_TAG('H','I','L',' ')},	/* Hiligaynon */
   {"hnd",	HB_TAG('H','N','D',' ')},	/* [Southern] Hindko */
@@ -542,6 +546,7 @@
   {"nr",	HB_TAG('N','D','B',' ')},	/* [South] Ndebele */
   {"nsk",	HB_TAG('N','A','S',' ')},	/* Naskapi */
   {"nso",	HB_TAG('S','O','T',' ')},	/* [Northern] Sotho */
+  {"nv",	HB_TAG('N','A','V',' ')},	/* Navajo */
   {"ny",	HB_TAG('C','H','I',' ')},	/* Chewa/Chichwa/Nyanja */
   {"nym",	HB_TAG('N','Y','M',' ')},	/* Nyamwezi */
   {"nyn",	HB_TAG('N','K','L',' ')},	/* Nyankole */
@@ -595,8 +600,8 @@
   {"sah",	HB_TAG('Y','A','K',' ')},	/* Yakut */
   {"sas",	HB_TAG('S','A','S',' ')},	/* Sasak */
   {"sat",	HB_TAG('S','A','T',' ')},	/* Santali */
-  {"sck",	HB_TAG('S','A','D',' ')},	/* Sadri */
   {"sc",	HB_TAG('S','R','D',' ')},	/* Sardinian [macrolanguage] */
+  {"sck",	HB_TAG('S','A','D',' ')},	/* Sadri */
   {"scn",	HB_TAG('S','C','N',' ')},	/* Sicilian */
   {"sco",	HB_TAG('S','C','O',' ')},	/* Scots */
   {"scs",	HB_TAG('S','L','A',' ')},	/* [North] Slavey */
@@ -684,8 +689,8 @@
   {"uzs",	HB_TAG('U','Z','B',' ')},	/* Southern Uzbek */
   {"ve",	HB_TAG('V','E','N',' ')},	/* Venda */
   {"vec",	HB_TAG('V','E','C',' ')},	/* Venetian */
-  {"vls",	HB_TAG('F','L','E',' ')},	/* Vlaams */
   {"vi",	HB_TAG('V','I','T',' ')},	/* Vietnamese */
+  {"vls",	HB_TAG('F','L','E',' ')},	/* Vlaams */
   {"vmw",	HB_TAG('M','A','K',' ')},	/* Makhuwa */
   {"vo",	HB_TAG('V','O','L',' ')},	/* Volapük */
   {"vro",	HB_TAG('V','R','O',' ')},	/* Võro */
@@ -694,9 +699,9 @@
   {"wbm",	HB_TAG('W','A',' ',' ')},	/* Wa */
   {"wbr",	HB_TAG('W','A','G',' ')},	/* Wagdi */
   {"wle",	HB_TAG('S','I','G',' ')},	/* Wolane */
+  {"wo",	HB_TAG('W','L','F',' ')},	/* Wolof */
   {"wry",	HB_TAG('M','A','W',' ')},	/* Merwari */
   {"wtm",	HB_TAG('W','T','M',' ')},	/* Mewati */
-  {"wo",	HB_TAG('W','L','F',' ')},	/* Wolof */
   {"xal",	HB_TAG('K','L','M',' ')},	/* Kalmyk */
   {"xh",	HB_TAG('X','H','S',' ')},	/* Xhosa */
   {"xog",	HB_TAG('X','O','G',' ')},	/* Soga */
@@ -727,7 +732,6 @@
 /*{"fuf?",	HB_TAG('F','T','A',' ')},*/	/* Futa */
 /*{"ar-Syrc?",	HB_TAG('G','A','R',' ')},*/	/* Garshuni */
 /*{"cfm/rnl?",	HB_TAG('H','A','L',' ')},*/	/* Halam */
-/*{"fonipa",	HB_TAG('I','P','P','H')},*/	/* Phonetic transcription—IPA conventions */
 /*{"ga-Latg?/Latg?",	HB_TAG('I','R','T',' ')},*/	/* Irish Traditional */
 /*{"krc",	HB_TAG('K','A','R',' ')},*/	/* Karachay */
 /*{"alw?/ktb?",	HB_TAG('K','E','B',' ')},*/	/* Kebena */
@@ -826,6 +830,14 @@
     }
   }
 
+  /*
+   * The International Phonetic Alphabet is a variant tag in BCP-47,
+   * which can be applied to any language.
+   */
+  if (strstr (lang_str, "-fonipa")) {
+    return HB_TAG('I','P','P','H');  /* Phonetic transcription—IPA conventions */
+  }
+
   /* Find a language matching in the first component */
   {
     const LangTag *lang_tag;
@@ -864,6 +876,15 @@
   return HB_OT_TAG_DEFAULT_LANGUAGE;
 }
 
+/**
+ * hb_ot_tag_to_language:
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 0.9.2
+ **/
 hb_language_t
 hb_ot_tag_to_language (hb_tag_t tag)
 {
@@ -886,6 +907,12 @@
     }
   }
 
+  /* struct LangTag has only room for 3-letter language tags. */
+  switch (tag) {
+  case HB_TAG('I','P','P','H'):  /* Phonetic transcription—IPA conventions */
+    return hb_language_from_string ("und-fonipa", -1);
+  }
+
   /* Else return a custom language in the form of "x-hbotABCD" */
   {
     unsigned char buf[11] = "x-hbot";
@@ -900,4 +927,27 @@
   }
 }
 
+#ifdef MAIN
+static inline void
+test_langs_sorted (void)
+{
+  for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++)
+  {
+    int c = lang_compare_first_component (ot_languages[i-1].language, ot_languages[i].language);
+    if (c >= 0)
+    {
+      fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
+	       i, ot_languages[i-1].language, c, ot_languages[i].language);
+      abort();
+    }
+  }
+}
 
+int
+main (void)
+{
+  test_langs_sorted ();
+  return 0;
+}
+
+#endif
diff --git a/src/hb-ot-tag.h b/src/hb-ot-tag.h
index 1bf12ab..54fb747 100644
--- a/src/hb-ot-tag.h
+++ b/src/hb-ot-tag.h
@@ -39,18 +39,18 @@
 #define HB_OT_TAG_DEFAULT_SCRIPT	HB_TAG ('D', 'F', 'L', 'T')
 #define HB_OT_TAG_DEFAULT_LANGUAGE	HB_TAG ('d', 'f', 'l', 't')
 
-void
+HB_EXTERN void
 hb_ot_tags_from_script (hb_script_t  script,
 			hb_tag_t    *script_tag_1,
 			hb_tag_t    *script_tag_2);
 
-hb_script_t
+HB_EXTERN hb_script_t
 hb_ot_tag_to_script (hb_tag_t tag);
 
-hb_tag_t
+HB_EXTERN hb_tag_t
 hb_ot_tag_from_language (hb_language_t language);
 
-hb_language_t
+HB_EXTERN hb_language_t
 hb_ot_tag_to_language (hb_tag_t tag);
 
 
diff --git a/src/hb-private.hh b/src/hb-private.hh
index c92cdec..7afb258 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -54,6 +54,23 @@
 #include <stdarg.h>
 
 
+/* Compile-time custom allocator support. */
+
+#if defined(hb_malloc_impl) \
+ && defined(hb_calloc_impl) \
+ && defined(hb_realloc_impl) \
+ && defined(hb_free_impl)
+extern "C" void* hb_malloc_impl(size_t size);
+extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
+extern "C" void* hb_realloc_impl(void *ptr, size_t size);
+extern "C" void  hb_free_impl(void *ptr);
+#define malloc hb_malloc_impl
+#define calloc hb_calloc_impl
+#define realloc hb_realloc_impl
+#define free hb_free_impl
+#endif
+
+
 /* Compiler attributes */
 
 
@@ -94,22 +111,6 @@
 # endif
 #endif
 
-#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
-#define snprintf _snprintf
-/* Windows CE only has _strdup, while rest of Windows has both. */
-#define strdup _strdup
-#endif
-
-#ifdef _MSC_VER
-#undef inline
-#define inline __inline
-#endif
-
-#ifdef __STRICT_ANSI__
-#undef inline
-#define inline __inline__
-#endif
-
 #if __GNUC__ >= 3
 #define HB_FUNC __PRETTY_FUNCTION__
 #elif defined(_MSC_VER)
@@ -118,6 +119,36 @@
 #define HB_FUNC __func__
 #endif
 
+/*
+ * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
+ * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
+ * cases that fall through without a break or return statement. HB_FALLTHROUGH
+ * is only needed on cases that have code:
+ *
+ * switch (foo) {
+ *   case 1: // These cases have no code. No fallthrough annotations are needed.
+ *   case 2:
+ *   case 3:
+ *     foo = 4; // This case has code, so a fallthrough annotation is needed:
+ *     HB_FALLTHROUGH;
+ *   default:
+ *     return foo;
+ * }
+ */
+#if defined(__clang__) && __cplusplus >= 201103L
+   /* clang's fallthrough annotations are only available starting in C++11. */
+#  define HB_FALLTHROUGH [[clang::fallthrough]]
+#elif defined(_MSC_VER)
+   /*
+    * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
+    * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
+    */
+#  include <sal.h>
+#  define HB_FALLTHROUGH __fallthrough
+#else
+#  define HB_FALLTHROUGH /* FALLTHROUGH */
+#endif
+
 #if defined(_WIN32) || defined(__CYGWIN__)
    /* We need Windows Vista for both Uniscribe backend and for
     * MemoryBarrier.  We don't support compiling on Windows XP,
@@ -134,14 +165,24 @@
 #  ifndef STRICT
 #    define STRICT 1
 #  endif
-#endif
 
-#ifdef _WIN32_WCE
-/* Some things not defined on Windows CE. */
-#define MemoryBarrier()
-#define getenv(Name) NULL
-#define setlocale(Category, Locale) "C"
+#  if defined(_WIN32_WCE)
+     /* Some things not defined on Windows CE. */
+#    define strdup _strdup
+#    define getenv(Name) NULL
+#    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
+#  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
 
 #if HAVE_ATEXIT
@@ -202,8 +243,9 @@
 #define _ASSERT_STATIC0(_line, _cond)	_ASSERT_STATIC1 (_line, (_cond))
 #define ASSERT_STATIC(_cond)		_ASSERT_STATIC0 (__LINE__, (_cond))
 
-#define ASSERT_STATIC_EXPR(_cond)((void) sizeof (char[(_cond) ? 1 : -1]))
-#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
+template <unsigned int cond> class hb_assert_constant_t {};
+
+#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)
@@ -256,8 +298,8 @@
 
 /* Void! */
 struct _hb_void_t {};
-typedef const _hb_void_t &hb_void_t;
-#define HB_VOID (* (const _hb_void_t *) NULL)
+typedef const _hb_void_t *hb_void_t;
+#define HB_VOID ((const _hb_void_t *) NULL)
 
 /* Return the number of 1 bits in mask. */
 static inline HB_CONST_FUNC unsigned int
@@ -583,6 +625,30 @@
 #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,
@@ -628,27 +694,13 @@
   } else
     fprintf (stderr, "   " VRBAR LBAR);
 
-  if (func)
-  {
-    unsigned int func_len = strlen (func);
-#ifndef HB_DEBUG_VERBOSE
-    /* 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;
-#endif
-    fprintf (stderr, "%.*s: ", func_len, func);
-  }
+  _hb_print_func (func);
 
   if (message)
+  {
+    fprintf (stderr, ": ");
     vfprintf (stderr, message, ap);
+  }
 
   fprintf (stderr, "\n");
 }
@@ -738,7 +790,7 @@
 static inline void _hb_warn_no_return (bool returned)
 {
   if (unlikely (!returned)) {
-    fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN.  This is a bug, please report.\n");
+    fprintf (stderr, "OUCH, returned with no call to return_trace().  This is a bug, please report.\n");
   }
 }
 template <>
@@ -773,7 +825,7 @@
   inline ret_t ret (ret_t v, unsigned int line = 0)
   {
     if (unlikely (returned)) {
-      fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
+      fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
       return v;
     }
 
@@ -804,7 +856,7 @@
   inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
 };
 
-#define TRACE_RETURN(RET) trace.ret (RET, __LINE__)
+#define return_trace(RET) return trace.ret (RET, __LINE__)
 
 /* Misc */
 
@@ -820,7 +872,7 @@
   /* The sizeof() is here to force template instantiation.
    * I'm sure there are better ways to do this but can't think of
    * one right now.  Declaring a variable won't work as HB_UNUSED
-   * is unsable on some platforms and unused types are less likely
+   * 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);
 
@@ -842,51 +894,68 @@
 }
 
 
+/* Enable bitwise ops on enums marked as flags_t */
+/* To my surprise, looks like the function resolver is happy to silently cast
+ * 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
+ */
+#ifdef _MSC_VER
+# pragma warning(disable:4200)
+# pragma warning(disable:4800)
+#endif
+#define HB_MARK_AS_FLAG_T(T) \
+	extern "C++" { \
+	  static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
+	  static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
+	  static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
+	  static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
+	  static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
+	  static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
+	  static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
+	}
+
+
 /* Useful for set-operations on small enums.
  * For example, for testing "x ∈ {x1, x2, x3}" use:
- * (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ * (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
  */
-#define FLAG(x) (1<<(x))
+#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_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
 
 
 template <typename T, typename T2> static inline void
-hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
 {
-  if (unlikely (!len))
-    return;
-
-  unsigned int k = len - 1;
-  do {
-    unsigned int new_k = 0;
-
-    for (unsigned int j = 0; j < k; j++)
-      if (compar (&array[j], &array[j+1]) > 0)
-      {
-        {
-	  T t;
-	  t = array[j];
-	  array[j] = array[j + 1];
-	  array[j + 1] = t;
-	}
-        if (array2)
-        {
-	  T2 t;
-	  t = array2[j];
-	  array2[j] = array2[j + 1];
-	  array2[j + 1] = t;
-	}
-
-	new_k = j;
-      }
-    k = new_k;
-  } while (k);
+  for (unsigned int i = 1; i < len; i++)
+  {
+    unsigned int j = i;
+    while (j && compar (&array[j - 1], &array[i]) > 0)
+      j--;
+    if (i == j)
+      continue;
+    /* Move item i to occupy place for item j, shift what's in between. */
+    {
+      T t = array[i];
+      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
+      array[j] = t;
+    }
+    if (array2)
+    {
+      T2 t = array2[i];
+      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
+      array2[j] = t;
+    }
+  }
 }
 
 template <typename T> static inline void
-hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
 {
-  hb_bubble_sort (array, len, compar, (int *) NULL);
+  hb_stable_sort (array, len, compar, (int *) NULL);
 }
 
 static inline hb_bool_t
@@ -936,5 +1005,7 @@
   return _hb_options.opts;
 }
 
+/* Size signifying variable-sized array */
+#define VAR 1
 
 #endif /* HB_PRIVATE_HH */
diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh
index 59e8f45..3c302b1 100644
--- a/src/hb-set-private.hh
+++ b/src/hb-set-private.hh
@@ -36,7 +36,15 @@
  * "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.  As a result, our filters have much higher.
+ * 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>
@@ -145,6 +153,8 @@
 
 struct hb_set_t
 {
+  friend struct hb_frozen_set_t;
+
   hb_object_header_t header;
   ASSERT_POD ();
   bool in_error;
@@ -326,7 +336,7 @@
   static  const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
 
   elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
-  elt_t elt (hb_codepoint_t g) const { 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 */
@@ -335,6 +345,58 @@
   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)
+  {
+    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))
+    {
+      start = count = 0;
+      return;
+    }
+    memcpy (elts, &min_elt, elts_size);
+  }
+
+  inline void fini (void)
+  {
+    if (elts)
+      free (elts);
+  }
+
+  inline bool has (hb_codepoint_t g) const
+  {
+    /* hb_codepoint_t is unsigned. */
+    g -= start;
+    if (unlikely (g > count)) return false;
+    return !!(elt (g) & mask (g));
+  }
+
+  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;
+};
 
 
 #endif /* HB_SET_PRIVATE_HH */
diff --git a/src/hb-set.cc b/src/hb-set.cc
index 59a0af4..cb7fcdb 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -35,7 +35,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_set_t *
 hb_set_create (void)
@@ -55,7 +55,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_set_t *
 hb_set_get_empty (void)
@@ -76,7 +76,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_set_t *
 hb_set_reference (hb_set_t *set)
@@ -88,7 +88,7 @@
  * hb_set_destroy: (skip)
  * @set: a set.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_set_destroy (hb_set_t *set)
@@ -110,7 +110,7 @@
  *
  * Return value:
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_set_set_user_data (hb_set_t           *set,
@@ -129,7 +129,7 @@
  *
  * Return value: (transfer none):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void *
 hb_set_get_user_data (hb_set_t           *set,
@@ -147,7 +147,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_set_allocation_successful (const hb_set_t  *set HB_UNUSED)
@@ -161,7 +161,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_set_clear (hb_set_t *set)
@@ -177,7 +177,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_bool_t
 hb_set_is_empty (const hb_set_t *set)
@@ -194,7 +194,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_set_has (const hb_set_t *set,
@@ -210,7 +210,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_set_add (hb_set_t       *set,
@@ -227,7 +227,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 void
 hb_set_add_range (hb_set_t       *set,
@@ -244,7 +244,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_set_del (hb_set_t       *set,
@@ -261,7 +261,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 void
 hb_set_del_range (hb_set_t       *set,
@@ -280,7 +280,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_bool_t
 hb_set_is_equal (const hb_set_t *set,
@@ -296,7 +296,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_set_set (hb_set_t       *set,
@@ -312,7 +312,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_set_union (hb_set_t       *set,
@@ -328,7 +328,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_set_intersect (hb_set_t       *set,
@@ -344,7 +344,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_set_subtract (hb_set_t       *set,
@@ -360,7 +360,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_set_symmetric_difference (hb_set_t       *set,
@@ -375,7 +375,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.10
  **/
 void
 hb_set_invert (hb_set_t *set)
@@ -391,7 +391,7 @@
  *
  * Return value: set population.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 unsigned int
 hb_set_get_population (const hb_set_t *set)
@@ -407,7 +407,7 @@
  *
  * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_codepoint_t
 hb_set_get_min (const hb_set_t *set)
@@ -423,7 +423,7 @@
  *
  * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_codepoint_t
 hb_set_get_max (const hb_set_t *set)
@@ -440,7 +440,7 @@
  *
  * Return value: whether there was a next value.
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_set_next (const hb_set_t *set,
@@ -460,7 +460,7 @@
  *
  * Return value: whether there was a next range.
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_bool_t
 hb_set_next_range (const hb_set_t *set,
diff --git a/src/hb-set.h b/src/hb-set.h
index bafdae9..2164c1a 100644
--- a/src/hb-set.h
+++ b/src/hb-set.h
@@ -36,114 +36,117 @@
 HB_BEGIN_DECLS
 
 
+/*
+ * Since: 0.9.21
+ */
 #define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
 
 typedef struct hb_set_t hb_set_t;
 
 
-hb_set_t *
+HB_EXTERN hb_set_t *
 hb_set_create (void);
 
-hb_set_t *
+HB_EXTERN hb_set_t *
 hb_set_get_empty (void);
 
-hb_set_t *
+HB_EXTERN hb_set_t *
 hb_set_reference (hb_set_t *set);
 
-void
+HB_EXTERN void
 hb_set_destroy (hb_set_t *set);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_set_set_user_data (hb_set_t           *set,
 		      hb_user_data_key_t *key,
 		      void *              data,
 		      hb_destroy_func_t   destroy,
 		      hb_bool_t           replace);
 
-void *
+HB_EXTERN void *
 hb_set_get_user_data (hb_set_t           *set,
 		      hb_user_data_key_t *key);
 
 
 /* Returns false if allocation has failed before */
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_set_allocation_successful (const hb_set_t *set);
 
-void
+HB_EXTERN void
 hb_set_clear (hb_set_t *set);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_set_is_empty (const hb_set_t *set);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_set_has (const hb_set_t *set,
 	    hb_codepoint_t  codepoint);
 
 /* Right now limited to 16-bit integers.  Eventually will do full codepoint range, sans -1
  * which we will use as a sentinel. */
-void
+HB_EXTERN void
 hb_set_add (hb_set_t       *set,
 	    hb_codepoint_t  codepoint);
 
-void
+HB_EXTERN void
 hb_set_add_range (hb_set_t       *set,
 		  hb_codepoint_t  first,
 		  hb_codepoint_t  last);
 
-void
+HB_EXTERN void
 hb_set_del (hb_set_t       *set,
 	    hb_codepoint_t  codepoint);
 
-void
+HB_EXTERN void
 hb_set_del_range (hb_set_t       *set,
 		  hb_codepoint_t  first,
 		  hb_codepoint_t  last);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_set_is_equal (const hb_set_t *set,
 		 const hb_set_t *other);
 
-void
+HB_EXTERN void
 hb_set_set (hb_set_t       *set,
 	    const hb_set_t *other);
 
-void
+HB_EXTERN void
 hb_set_union (hb_set_t       *set,
 	      const hb_set_t *other);
 
-void
+HB_EXTERN void
 hb_set_intersect (hb_set_t       *set,
 		  const hb_set_t *other);
 
-void
+HB_EXTERN void
 hb_set_subtract (hb_set_t       *set,
 		 const hb_set_t *other);
 
-void
+HB_EXTERN void
 hb_set_symmetric_difference (hb_set_t       *set,
 			     const hb_set_t *other);
 
-void
+HB_EXTERN void
 hb_set_invert (hb_set_t *set);
 
-unsigned int
+HB_EXTERN unsigned int
 hb_set_get_population (const hb_set_t *set);
 
 /* Returns -1 if set empty. */
-hb_codepoint_t
+HB_EXTERN hb_codepoint_t
 hb_set_get_min (const hb_set_t *set);
 
 /* Returns -1 if set empty. */
-hb_codepoint_t
+HB_EXTERN hb_codepoint_t
 hb_set_get_max (const hb_set_t *set);
 
 /* Pass -1 in to get started. */
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_set_next (const hb_set_t *set,
 	     hb_codepoint_t *codepoint);
 
 /* Pass -1 for first and last to get started. */
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_set_next_range (const hb_set_t *set,
 		   hb_codepoint_t *first,
 		   hb_codepoint_t *last);
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 2166173..56e2ea5 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -106,7 +106,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_shape_plan_t *
 hb_shape_plan_create (hb_face_t                     *face,
@@ -126,9 +126,9 @@
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
-  if (unlikely (!props || hb_object_is_inert (face)))
+  if (unlikely (!props))
     return hb_shape_plan_get_empty ();
-  if (num_user_features && !(features = (hb_feature_t *) malloc (num_user_features * sizeof (hb_feature_t))))
+  if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
     return hb_shape_plan_get_empty ();
   if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
     free (features);
@@ -158,7 +158,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_shape_plan_t *
 hb_shape_plan_get_empty (void)
@@ -194,7 +194,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_shape_plan_t *
 hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
@@ -208,7 +208,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 void
 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
@@ -236,7 +236,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_bool_t
 hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
@@ -257,7 +257,7 @@
  *
  * Return value: (transfer none):
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 void *
 hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
@@ -279,7 +279,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_bool_t
 hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
@@ -293,9 +293,13 @@
 		  num_features,
 		  shape_plan->shaper_func);
 
-  if (unlikely (hb_object_is_inert (shape_plan) ||
-		hb_object_is_inert (font) ||
-		hb_object_is_inert (buffer)))
+  if (unlikely (!buffer->len))
+    return true;
+
+  assert (!hb_object_is_inert (buffer));
+  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
+
+  if (unlikely (hb_object_is_inert (shape_plan)))
     return false;
 
   assert (shape_plan->face_unsafe == font->face);
@@ -396,7 +400,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 hb_shape_plan_t *
 hb_shape_plan_create_cached (hb_face_t                     *face,
@@ -453,6 +457,10 @@
 
   hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
 
+  /* Don't add to the cache if face is inert. */
+  if (unlikely (hb_object_is_inert (face)))
+    return shape_plan;
+
   /* Don't add the plan to the cache if there were user features with non-global ranges */
 
   if (hb_non_global_user_features_present (user_features, num_user_features))
@@ -483,7 +491,7 @@
  *
  * Return value: (transfer none):
  *
- * Since: 1.0
+ * Since: 0.9.7
  **/
 const char *
 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
index 8f54552..aa5e0c7 100644
--- a/src/hb-shape-plan.h
+++ b/src/hb-shape-plan.h
@@ -38,49 +38,49 @@
 
 typedef struct hb_shape_plan_t hb_shape_plan_t;
 
-hb_shape_plan_t *
+HB_EXTERN hb_shape_plan_t *
 hb_shape_plan_create (hb_face_t                     *face,
 		      const hb_segment_properties_t *props,
 		      const hb_feature_t            *user_features,
 		      unsigned int                   num_user_features,
 		      const char * const            *shaper_list);
 
-hb_shape_plan_t *
+HB_EXTERN hb_shape_plan_t *
 hb_shape_plan_create_cached (hb_face_t                     *face,
 			     const hb_segment_properties_t *props,
 			     const hb_feature_t            *user_features,
 			     unsigned int                   num_user_features,
 			     const char * const            *shaper_list);
 
-hb_shape_plan_t *
+HB_EXTERN hb_shape_plan_t *
 hb_shape_plan_get_empty (void);
 
-hb_shape_plan_t *
+HB_EXTERN hb_shape_plan_t *
 hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
 
-void
+HB_EXTERN void
 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
 			     hb_user_data_key_t *key,
 			     void *              data,
 			     hb_destroy_func_t   destroy,
 			     hb_bool_t           replace);
 
-void *
+HB_EXTERN void *
 hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
 			     hb_user_data_key_t *key);
 
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
 		       hb_font_t          *font,
 		       hb_buffer_t        *buffer,
 		       const hb_feature_t *features,
 		       unsigned int        num_features);
 
-const char *
+HB_EXTERN const char *
 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan);
 
 
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 9a59c08..352d42c 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -33,6 +33,17 @@
 #include "hb-buffer-private.hh"
 #include "hb-font-private.hh"
 
+/**
+ * SECTION:hb-shape
+ * @title: Shaping
+ * @short_description: Conversion of text strings into positioned glyphs
+ * @include: hb.h
+ *
+ * Shaping is the central operation of HarfBuzz. Shaping operates on buffers,
+ * which are sequences of Unicode characters that use the same font and have
+ * the same text direction, script and language. After shaping the buffer
+ * contains the output glyphs and their positions.
+ **/
 
 static bool
 parse_space (const char **pp, const char *end)
@@ -198,15 +209,18 @@
 
 /**
  * hb_feature_from_string:
- * @str: (array length=len):
- * @len: 
- * @feature: (out) (optional):
+ * @str: (array length=len) (element-type uint8_t): a string to parse
+ * @len: length of @str, or -1 if string is %NULL terminated
+ * @feature: (out): the #hb_feature_t to initialize with the parsed values
  *
- * 
+ * Parses a string into a #hb_feature_t.
  *
- * Return value: 
+ * TODO: document the syntax here.
  *
- * Since: 1.0
+ * Return value:
+ * %true if @str is successfully parsed, %false otherwise.
+ *
+ * Since: 0.9.5
  **/
 hb_bool_t
 hb_feature_from_string (const char *str, int len,
@@ -231,13 +245,15 @@
 
 /**
  * hb_feature_to_string:
- * @feature: 
- * @buf: (array length=size):
- * @size: 
+ * @feature: an #hb_feature_t to convert
+ * @buf: (array length=size) (out): output string
+ * @size: the allocated size of @buf
  *
- * 
+ * Converts a #hb_feature_t into a %NULL-terminated string in the format
+ * understood by hb_feature_from_string(). The client in responsible for
+ * allocating big enough size for @buf, 128 bytes is more than enough.
  *
- * Since: 1.0
+ * Since: 0.9.5
  **/
 void
 hb_feature_to_string (hb_feature_t *feature,
@@ -290,11 +306,12 @@
 /**
  * hb_shape_list_shapers:
  *
- * 
+ * Retrieves the list of shapers supported by HarfBuzz.
  *
- * Return value: (transfer none):
+ * Return value: (transfer none) (array zero-terminated=1): an array of
+ *    constant strings
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 const char **
 hb_shape_list_shapers (void)
@@ -333,17 +350,21 @@
 
 /**
  * hb_shape_full:
- * @font: a font.
- * @buffer: a buffer.
- * @features: (array length=num_features):
- * @num_features: 
- * @shaper_list: (array zero-terminated=1):
+ * @font: an #hb_font_t to use for shaping
+ * @buffer: an #hb_buffer_t to shape
+ * @features: (array length=num_features) (allow-none): an array of user
+ *    specified #hb_feature_t or %NULL
+ * @num_features: the length of @features array
+ * @shaper_list: (array zero-terminated=1) (allow-none): a %NULL-terminated
+ *    array of shapers to use or %NULL
  *
- * 
+ * See hb_shape() for details. If @shaper_list is not %NULL, the specified
+ * shapers will be used in the given order, otherwise the default shapers list
+ * will be used.
  *
- * Return value: 
+ * Return value: %FALSE if all shapers failed, %TRUE otherwise
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_shape_full (hb_font_t          *font,
@@ -352,11 +373,6 @@
 	       unsigned int        num_features,
 	       const char * const *shaper_list)
 {
-  if (unlikely (!buffer->len))
-    return true;
-
-  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
-
   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
   hb_shape_plan_destroy (shape_plan);
@@ -368,14 +384,19 @@
 
 /**
  * hb_shape:
- * @font: a font.
- * @buffer: a buffer.
- * @features: (array length=num_features):
- * @num_features: 
+ * @font: an #hb_font_t to use for shaping
+ * @buffer: an #hb_buffer_t to shape
+ * @features: (array length=num_features) (allow-none): an array of user
+ *    specified #hb_feature_t or %NULL
+ * @num_features: the length of @features array
  *
- * 
+ * Shapes @buffer using @font turning its Unicode characters content to
+ * positioned glyphs. If @features is not %NULL, it will be used to control the
+ * features applied during shaping.
  *
- * Since: 1.0
+ * Return value: %FALSE if all shapers failed, %TRUE otherwise
+ *
+ * Since: 0.9.2
  **/
 void
 hb_shape (hb_font_t           *font,
diff --git a/src/hb-shape.h b/src/hb-shape.h
index 10a35cb..53bb845 100644
--- a/src/hb-shape.h
+++ b/src/hb-shape.h
@@ -47,32 +47,29 @@
   unsigned int  end;
 } hb_feature_t;
 
-/* len=-1 means str is NUL-terminated */
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_feature_from_string (const char *str, int len,
 			hb_feature_t *feature);
 
-/* Something like 128 bytes is more than enough.
- * nul-terminates. */
-void
+HB_EXTERN void
 hb_feature_to_string (hb_feature_t *feature,
 		      char *buf, unsigned int size);
 
 
-void
+HB_EXTERN void
 hb_shape (hb_font_t           *font,
 	  hb_buffer_t         *buffer,
 	  const hb_feature_t  *features,
 	  unsigned int         num_features);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_shape_full (hb_font_t          *font,
 	       hb_buffer_t        *buffer,
 	       const hb_feature_t *features,
 	       unsigned int        num_features,
 	       const char * const *shaper_list);
 
-const char **
+HB_EXTERN const char **
 hb_shape_list_shapers (void);
 
 
diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh
index 6c537d4..b0835d3 100644
--- a/src/hb-shaper-list.hh
+++ b/src/hb-shaper-list.hh
@@ -46,6 +46,9 @@
 #ifdef HAVE_UNISCRIBE
 HB_SHAPER_IMPLEMENT (uniscribe)
 #endif
+#ifdef HAVE_DIRECTWRITE
+HB_SHAPER_IMPLEMENT (directwrite)
+#endif
 #ifdef HAVE_CORETEXT
 HB_SHAPER_IMPLEMENT (coretext)
 #endif
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
index 29c4493..d1d1146 100644
--- a/src/hb-shaper-private.hh
+++ b/src/hb-shaper-private.hh
@@ -79,10 +79,9 @@
 	HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data)
 
 #define HB_SHAPER_DATA_DESTROY(shaper, object) \
-	if (object->shaper_data.shaper && \
-	    object->shaper_data.shaper != HB_SHAPER_DATA_INVALID && \
-	    object->shaper_data.shaper != HB_SHAPER_DATA_SUCCEEDED) \
-	  HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA (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 \
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
index 580b95c..b25566d 100644
--- a/src/hb-shaper.cc
+++ b/src/hb-shaper.cc
@@ -64,7 +64,7 @@
     }
 
     /* Not found; allocate one. */
-    shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers));
+    shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
     if (unlikely (!shapers)) {
       (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
       return (const hb_shaper_pair_t *) all_shapers;
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
index 5b53821..b4a5833 100644
--- a/src/hb-ucdn.cc
+++ b/src/hb-ucdn.cc
@@ -148,6 +148,12 @@
     HB_SCRIPT_SIDDHAM,
     HB_SCRIPT_TIRHUTA,
     HB_SCRIPT_WARANG_CITI,
+    HB_SCRIPT_AHOM,
+    HB_SCRIPT_ANATOLIAN_HIEROGLYPHS,
+    HB_SCRIPT_HATRAN,
+    HB_SCRIPT_MULTANI,
+    HB_SCRIPT_OLD_HUNGARIAN,
+    HB_SCRIPT_SIGNWRITING,
 };
 
 static hb_unicode_combining_class_t
diff --git a/src/hb-ucdn/Makefile.am b/src/hb-ucdn/Makefile.am
index 0670b5c..73b5502 100644
--- a/src/hb-ucdn/Makefile.am
+++ b/src/hb-ucdn/Makefile.am
@@ -2,11 +2,9 @@
 
 noinst_LTLIBRARIES = libhb-ucdn.la
 
+include Makefile.sources
 
-libhb_ucdn_la_SOURCES = \
-	ucdn.h \
-	ucdn.c \
-	unicodedata_db.h
+libhb_ucdn_la_SOURCES = $(LIBHB_UCDN_sources)
 libhb_ucdn_la_CPPFLAGS = \
 	-I$(top_srcdir) \
 	-I$(top_srcdir)/src \
diff --git a/src/hb-ucdn/Makefile.sources b/src/hb-ucdn/Makefile.sources
new file mode 100644
index 0000000..d5f87b2
--- /dev/null
+++ b/src/hb-ucdn/Makefile.sources
@@ -0,0 +1,4 @@
+LIBHB_UCDN_sources = \
+	ucdn.h \
+	ucdn.c \
+	unicodedata_db.h
diff --git a/src/hb-ucdn/ucdn.h b/src/hb-ucdn/ucdn.h
index ec8085b..8354ae5 100644
--- a/src/hb-ucdn/ucdn.h
+++ b/src/hb-ucdn/ucdn.h
@@ -191,6 +191,12 @@
 #define UCDN_SCRIPT_SIDDHAM 123
 #define UCDN_SCRIPT_TIRHUTA 124
 #define UCDN_SCRIPT_WARANG_CITI 125
+#define UCDN_SCRIPT_AHOM 126
+#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127
+#define UCDN_SCRIPT_HATRAN 128
+#define UCDN_SCRIPT_MULTANI 129
+#define UCDN_SCRIPT_OLD_HUNGARIAN 130
+#define UCDN_SCRIPT_SIGNWRITING 131
 
 #define UCDN_GENERAL_CATEGORY_CC 0
 #define UCDN_GENERAL_CATEGORY_CF 1
diff --git a/src/hb-ucdn/unicodedata_db.h b/src/hb-ucdn/unicodedata_db.h
index a78d2e6..f458be1 100644
--- a/src/hb-ucdn/unicodedata_db.h
+++ b/src/hb-ucdn/unicodedata_db.h
@@ -1,6 +1,6 @@
 /* this file was generated by makeunicodedata.py 3.2 */
 
-#define UNIDATA_VERSION "7.0.0"
+#define UNIDATA_VERSION "8.0.0"
 /* a list of unique database records */
 static const UCDRecord ucd_records[] = {
     {2, 0, 18, 0, 5, 0, 102},
@@ -141,7 +141,7 @@
     {12, 34, 13, 0, 5, 0, 40},
     {12, 220, 13, 0, 5, 0, 40},
     {12, 220, 13, 0, 5, 0, 6},
-    {13, 0, 11, 0, 5, 0, 0},
+    {13, 0, 11, 0, 5, 0, 6},
     {21, 0, 11, 0, 5, 0, 6},
     {12, 35, 13, 0, 5, 0, 40},
     {6, 0, 4, 0, 5, 0, 6},
@@ -300,7 +300,8 @@
     {21, 0, 0, 0, 5, 0, 25},
     {15, 0, 0, 0, 5, 0, 25},
     {26, 0, 18, 0, 5, 0, 25},
-    {7, 0, 0, 0, 5, 0, 26},
+    {9, 0, 0, 0, 5, 0, 26},
+    {5, 0, 0, 0, 5, 0, 26},
     {17, 0, 18, 0, 5, 0, 27},
     {7, 0, 0, 0, 5, 0, 27},
     {21, 0, 0, 0, 5, 0, 27},
@@ -349,7 +350,6 @@
     {13, 0, 0, 0, 5, 0, 45},
     {7, 0, 0, 0, 5, 0, 46},
     {7, 0, 0, 0, 5, 0, 55},
-    {10, 0, 0, 0, 5, 0, 55},
     {13, 0, 0, 0, 5, 0, 55},
     {15, 0, 0, 0, 5, 0, 55},
     {26, 0, 18, 0, 5, 0, 55},
@@ -500,7 +500,6 @@
     {15, 0, 18, 0, 2, 0, 0},
     {26, 0, 0, 0, 2, 0, 33},
     {7, 0, 0, 0, 2, 0, 35},
-    {2, 0, 18, 0, 2, 0, 35},
     {2, 0, 18, 0, 2, 0, 102},
     {7, 0, 0, 0, 2, 0, 36},
     {6, 0, 0, 0, 2, 0, 36},
@@ -568,10 +567,8 @@
     {6, 0, 0, 0, 5, 0, 85},
     {12, 9, 13, 0, 5, 0, 85},
     {13, 0, 0, 0, 5, 0, 85},
-    {2, 0, 18, 0, 2, 0, 24},
     {4, 0, 0, 0, 5, 0, 102},
     {3, 0, 0, 0, 4, 0, 102},
-    {2, 0, 18, 0, 4, 0, 102},
     {12, 26, 13, 0, 5, 0, 5},
     {25, 0, 9, 0, 5, 0, 5},
     {24, 0, 4, 0, 5, 0, 6},
@@ -644,6 +641,8 @@
     {15, 0, 3, 0, 5, 0, 120},
     {7, 0, 3, 0, 5, 0, 116},
     {15, 0, 3, 0, 5, 0, 116},
+    {7, 0, 3, 0, 5, 0, 128},
+    {15, 0, 3, 0, 5, 0, 128},
     {7, 0, 3, 0, 5, 0, 63},
     {15, 0, 3, 0, 5, 0, 63},
     {21, 0, 18, 0, 5, 0, 63},
@@ -651,6 +650,7 @@
     {21, 0, 3, 0, 5, 0, 75},
     {7, 0, 3, 0, 5, 0, 97},
     {7, 0, 3, 0, 5, 0, 96},
+    {15, 0, 3, 0, 5, 0, 96},
     {7, 0, 3, 0, 5, 0, 60},
     {12, 0, 13, 0, 5, 0, 60},
     {12, 220, 13, 0, 5, 0, 60},
@@ -680,6 +680,9 @@
     {21, 0, 3, 0, 5, 0, 122},
     {15, 0, 3, 0, 5, 0, 122},
     {7, 0, 3, 0, 5, 0, 90},
+    {9, 0, 3, 0, 5, 0, 130},
+    {5, 0, 3, 0, 5, 0, 130},
+    {15, 0, 3, 0, 5, 0, 130},
     {15, 0, 11, 0, 5, 0, 6},
     {10, 0, 0, 0, 5, 0, 93},
     {12, 0, 13, 0, 5, 0, 93},
@@ -712,6 +715,7 @@
     {7, 0, 0, 0, 5, 0, 99},
     {10, 9, 0, 0, 5, 0, 99},
     {21, 0, 0, 0, 5, 0, 99},
+    {12, 7, 13, 0, 5, 0, 99},
     {13, 0, 0, 0, 5, 0, 99},
     {15, 0, 0, 0, 5, 0, 18},
     {7, 0, 0, 0, 5, 0, 108},
@@ -720,6 +724,8 @@
     {10, 9, 0, 0, 5, 0, 108},
     {12, 7, 13, 0, 5, 0, 108},
     {21, 0, 0, 0, 5, 0, 108},
+    {7, 0, 0, 0, 5, 0, 129},
+    {21, 0, 0, 0, 5, 0, 129},
     {7, 0, 0, 0, 5, 0, 109},
     {12, 0, 13, 0, 5, 0, 109},
     {10, 0, 0, 0, 5, 0, 109},
@@ -757,6 +763,14 @@
     {10, 9, 0, 0, 5, 0, 101},
     {12, 7, 13, 0, 5, 0, 101},
     {13, 0, 0, 0, 5, 0, 101},
+    {7, 0, 0, 0, 5, 0, 126},
+    {12, 0, 13, 0, 5, 0, 126},
+    {10, 0, 0, 0, 5, 0, 126},
+    {12, 9, 13, 0, 5, 0, 126},
+    {13, 0, 0, 0, 5, 0, 126},
+    {15, 0, 0, 0, 5, 0, 126},
+    {21, 0, 0, 0, 5, 0, 126},
+    {26, 0, 0, 0, 5, 0, 126},
     {9, 0, 0, 0, 5, 0, 125},
     {5, 0, 0, 0, 5, 0, 125},
     {13, 0, 0, 0, 5, 0, 125},
@@ -767,6 +781,7 @@
     {14, 0, 0, 0, 5, 0, 62},
     {21, 0, 0, 0, 5, 0, 62},
     {7, 0, 0, 0, 5, 0, 80},
+    {7, 0, 0, 0, 5, 0, 127},
     {7, 0, 0, 0, 5, 0, 115},
     {13, 0, 0, 0, 5, 0, 115},
     {21, 0, 0, 0, 5, 0, 115},
@@ -794,6 +809,9 @@
     {12, 230, 13, 0, 5, 0, 2},
     {25, 0, 0, 0, 5, 0, 0},
     {13, 0, 8, 0, 5, 0, 0},
+    {26, 0, 0, 0, 5, 0, 131},
+    {12, 0, 13, 0, 5, 0, 131},
+    {21, 0, 0, 0, 5, 0, 131},
     {7, 0, 3, 0, 5, 0, 113},
     {15, 0, 3, 0, 5, 0, 113},
     {12, 220, 13, 0, 5, 0, 113},
@@ -1561,6 +1579,12 @@
 #define UCDN_SCRIPT_SIDDHAM 123
 #define UCDN_SCRIPT_TIRHUTA 124
 #define UCDN_SCRIPT_WARANG_CITI 125
+#define UCDN_SCRIPT_AHOM 126
+#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127
+#define UCDN_SCRIPT_HATRAN 128
+#define UCDN_SCRIPT_MULTANI 129
+#define UCDN_SCRIPT_OLD_HUNGARIAN 130
+#define UCDN_SCRIPT_SIGNWRITING 131
 
 #define UCDN_GENERAL_CATEGORY_CC 0
 #define UCDN_GENERAL_CATEGORY_CF 1
@@ -1623,252 +1647,251 @@
 static const unsigned char index0[] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
     21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 
-    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 54, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 55, 56, 57, 57, 57, 58, 
-    59, 60, 61, 62, 63, 64, 65, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 
-    67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 
-    67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 68, 69, 70, 70, 
-    71, 69, 70, 70, 72, 73, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 76, 77, 78, 79, 80, 81, 
-    82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 70, 96, 70, 97, 
-    98, 99, 100, 101, 102, 103, 70, 104, 70, 105, 70, 70, 70, 70, 70, 106, 
-    106, 106, 107, 108, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 109, 109, 
-    109, 109, 110, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 111, 111, 112, 113, 70, 70, 70, 114, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 115, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 116, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 117, 118, 
-    119, 120, 121, 122, 123, 124, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 125, 70, 70, 70, 70, 70, 126, 70, 127, 128, 129, 130, 
-    131, 132, 133, 134, 135, 70, 70, 70, 70, 70, 70, 70, 52, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
-    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 136, 
-    52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 137, 138, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 76, 76, 140, 139, 139, 139, 139, 141, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 
-    139, 139, 139, 141, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 142, 143, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
-    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 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, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 144, 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, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
-    74, 74, 144, 
+    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 53, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 54, 55, 56, 56, 56, 57, 
+    58, 59, 60, 61, 62, 63, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 
+    65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 
+    65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 67, 67, 67, 
+    67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 52, 69, 70, 71, 72, 73, 
+    74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 88, 90, 
+    91, 92, 93, 94, 95, 96, 97, 98, 88, 99, 88, 88, 88, 88, 88, 100, 100, 
+    100, 101, 102, 103, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 104, 104, 
+    104, 104, 105, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 106, 106, 107, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 108, 108, 109, 110, 88, 88, 88, 111, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 112, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 113, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 114, 
+    115, 116, 117, 118, 119, 120, 121, 122, 122, 123, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 124, 88, 88, 88, 88, 88, 125, 88, 126, 127, 
+    128, 129, 130, 131, 132, 133, 134, 135, 88, 88, 88, 88, 88, 88, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 136, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 137, 138, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 
+    52, 52, 52, 52, 52, 52, 139, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 52, 52, 141, 140, 140, 140, 140, 142, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 
+    142, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 143, 144, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 
+    88, 88, 88, 88, 88, 88, 88, 88, 88, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 145, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 145, 
 };
 
 static const unsigned short index1[] = {
@@ -1894,319 +1917,323 @@
     180, 181, 182, 175, 183, 184, 185, 186, 186, 187, 188, 189, 190, 191, 
     192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 201, 202, 203, 204, 
     205, 206, 207, 208, 209, 210, 211, 120, 212, 213, 214, 215, 215, 216, 
-    217, 218, 219, 220, 221, 120, 222, 223, 224, 120, 225, 226, 227, 228, 
-    228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 120, 239, 240, 
-    241, 242, 243, 240, 244, 245, 246, 247, 248, 120, 249, 250, 251, 252, 
-    253, 254, 255, 256, 256, 255, 256, 257, 258, 259, 260, 261, 262, 263, 
-    120, 264, 265, 266, 267, 268, 268, 267, 269, 270, 271, 272, 273, 274, 
-    275, 276, 277, 120, 278, 279, 280, 281, 281, 281, 281, 282, 283, 284, 
-    285, 120, 286, 287, 288, 289, 290, 291, 292, 293, 291, 291, 294, 295, 
-    292, 296, 297, 298, 299, 300, 301, 120, 302, 303, 303, 303, 303, 303, 
-    304, 305, 306, 307, 308, 309, 120, 120, 120, 120, 310, 311, 312, 313, 
-    314, 315, 316, 317, 318, 319, 320, 321, 120, 120, 120, 120, 322, 323, 
-    324, 325, 326, 327, 328, 329, 330, 331, 330, 330, 330, 332, 333, 334, 
-    335, 336, 337, 338, 337, 337, 337, 339, 340, 341, 342, 343, 120, 120, 
-    120, 120, 344, 344, 344, 344, 344, 345, 346, 347, 348, 349, 350, 351, 
-    352, 353, 354, 344, 355, 356, 348, 357, 358, 358, 358, 358, 359, 360, 
-    361, 361, 361, 361, 361, 362, 363, 363, 363, 363, 363, 363, 363, 363, 
-    363, 363, 363, 363, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 
-    364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 365, 365, 365, 365, 
-    365, 365, 365, 365, 365, 366, 367, 366, 365, 365, 365, 365, 365, 366, 
-    365, 365, 365, 365, 366, 367, 366, 365, 367, 365, 365, 365, 365, 365, 
-    365, 365, 366, 365, 365, 365, 365, 365, 365, 365, 365, 368, 369, 370, 
-    371, 372, 365, 365, 373, 374, 375, 375, 375, 375, 375, 375, 375, 375, 
-    375, 375, 376, 120, 377, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
-    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
-    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
-    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
-    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
-    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 379, 378, 378, 
-    380, 381, 381, 382, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384, 
-    385, 386, 387, 388, 389, 120, 390, 390, 391, 120, 392, 392, 393, 120, 
-    394, 395, 396, 120, 397, 397, 397, 397, 397, 397, 398, 399, 400, 401, 
-    402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 412, 412, 412, 
-    413, 412, 412, 412, 412, 412, 412, 120, 412, 412, 412, 412, 412, 414, 
-    378, 378, 378, 378, 378, 378, 378, 378, 415, 120, 416, 416, 416, 417, 
-    418, 419, 420, 421, 422, 423, 424, 424, 424, 425, 426, 120, 427, 427, 
-    427, 427, 427, 428, 429, 429, 430, 431, 432, 433, 434, 434, 434, 434, 
-    435, 435, 436, 437, 438, 438, 438, 438, 438, 438, 439, 440, 441, 442, 
-    443, 444, 445, 446, 445, 446, 447, 448, 449, 450, 120, 120, 120, 120, 
-    120, 120, 120, 120, 451, 452, 452, 452, 452, 452, 453, 454, 455, 456, 
-    457, 458, 459, 460, 461, 462, 463, 464, 464, 464, 465, 466, 467, 468, 
-    469, 469, 469, 469, 470, 471, 472, 473, 474, 474, 474, 474, 475, 476, 
-    477, 478, 479, 480, 481, 482, 483, 483, 483, 484, 120, 120, 120, 120, 
-    120, 120, 120, 120, 485, 120, 486, 487, 488, 489, 490, 491, 54, 54, 54, 
-    54, 492, 493, 56, 56, 56, 56, 56, 494, 495, 496, 54, 497, 54, 54, 54, 
-    498, 56, 56, 56, 499, 500, 501, 502, 503, 503, 503, 504, 505, 27, 27, 27, 
-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 506, 507, 27, 
-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 508, 509, 510, 511, 508, 509, 
-    508, 509, 510, 511, 508, 512, 508, 509, 508, 510, 508, 513, 508, 513, 
-    508, 513, 514, 515, 516, 517, 518, 519, 508, 520, 521, 522, 523, 524, 
-    525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 
-    539, 540, 56, 541, 542, 543, 542, 544, 120, 120, 545, 546, 547, 548, 549, 
-    120, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 
-    563, 562, 564, 565, 566, 567, 568, 569, 570, 571, 572, 571, 573, 574, 
-    571, 575, 571, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 
-    587, 588, 589, 590, 591, 586, 586, 592, 593, 594, 595, 596, 586, 586, 
-    597, 577, 598, 599, 586, 586, 600, 586, 586, 571, 601, 602, 571, 603, 
-    604, 605, 606, 606, 606, 606, 606, 606, 606, 606, 607, 571, 571, 608, 
-    609, 577, 577, 610, 571, 571, 571, 571, 576, 611, 571, 571, 612, 571, 
-    571, 571, 571, 613, 120, 120, 120, 571, 612, 120, 120, 614, 614, 614, 
-    614, 614, 615, 615, 616, 617, 617, 617, 617, 617, 617, 617, 617, 617, 
-    618, 614, 614, 619, 619, 619, 619, 619, 619, 619, 619, 619, 620, 619, 
-    619, 619, 619, 620, 571, 619, 619, 621, 571, 622, 572, 623, 624, 625, 
-    626, 572, 571, 621, 575, 571, 577, 627, 628, 624, 629, 571, 571, 571, 
-    571, 630, 571, 571, 571, 631, 632, 571, 571, 571, 571, 571, 633, 571, 
-    634, 571, 633, 635, 636, 619, 619, 637, 619, 619, 619, 571, 571, 571, 
-    571, 571, 571, 571, 638, 571, 571, 575, 571, 571, 639, 640, 614, 641, 
-    641, 642, 571, 571, 571, 571, 571, 643, 644, 645, 646, 647, 648, 577, 
-    577, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 
-    649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 
-    649, 649, 649, 649, 649, 577, 577, 577, 577, 577, 577, 577, 577, 577, 
-    577, 577, 577, 577, 577, 577, 577, 650, 651, 651, 652, 586, 586, 577, 
-    653, 600, 654, 655, 656, 657, 658, 659, 660, 577, 661, 586, 662, 663, 
-    664, 665, 646, 577, 577, 589, 653, 665, 666, 667, 668, 586, 586, 586, 
-    586, 669, 670, 586, 586, 586, 586, 671, 672, 673, 646, 674, 675, 571, 
-    571, 571, 571, 571, 571, 577, 577, 676, 677, 678, 572, 571, 571, 679, 
-    571, 571, 571, 680, 571, 571, 571, 571, 681, 571, 682, 683, 120, 120, 
-    120, 120, 120, 684, 684, 684, 684, 684, 685, 686, 686, 686, 686, 686, 
-    687, 688, 689, 690, 691, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 
-    692, 693, 694, 695, 696, 696, 696, 696, 697, 698, 699, 699, 699, 699, 
-    699, 699, 699, 700, 701, 702, 365, 365, 367, 120, 367, 367, 367, 367, 
-    367, 367, 367, 367, 703, 703, 703, 703, 704, 705, 706, 707, 708, 709, 
-    532, 710, 711, 120, 120, 120, 120, 120, 120, 120, 712, 712, 712, 713, 
-    712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 714, 120, 712, 712, 
-    712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 
-    712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 715, 120, 120, 120, 
-    716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 727, 727, 
-    727, 727, 727, 727, 727, 727, 728, 729, 730, 731, 731, 731, 731, 731, 
-    731, 731, 731, 731, 731, 732, 733, 734, 734, 734, 734, 735, 736, 363, 
-    363, 363, 363, 363, 363, 363, 363, 363, 363, 737, 738, 739, 734, 734, 
-    734, 740, 716, 716, 716, 716, 717, 120, 731, 731, 741, 741, 741, 742, 
-    743, 744, 739, 739, 739, 745, 746, 747, 741, 741, 741, 748, 743, 744, 
-    739, 739, 739, 739, 749, 747, 739, 750, 751, 751, 751, 751, 751, 752, 
-    751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 739, 739, 739, 
-    753, 754, 739, 739, 739, 739, 739, 739, 739, 739, 739, 739, 739, 755, 
-    739, 739, 739, 753, 756, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 757, 757, 757, 758, 759, 571, 571, 571, 571, 571, 571, 
-    571, 571, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 760, 
-    759, 759, 759, 759, 759, 759, 761, 761, 762, 761, 761, 761, 761, 761, 
+    217, 218, 219, 220, 221, 120, 222, 223, 224, 225, 226, 227, 228, 229, 
+    229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 120, 240, 241, 
+    242, 243, 244, 241, 245, 246, 247, 248, 249, 120, 250, 251, 252, 253, 
+    254, 255, 256, 257, 257, 256, 257, 258, 259, 260, 261, 262, 263, 264, 
+    120, 265, 266, 267, 268, 269, 269, 268, 270, 271, 272, 273, 274, 275, 
+    276, 277, 278, 120, 279, 280, 281, 282, 282, 282, 282, 283, 284, 285, 
+    286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 293, 293, 296, 297, 
+    294, 298, 299, 300, 301, 302, 303, 120, 304, 305, 305, 305, 305, 305, 
+    306, 307, 308, 309, 310, 311, 120, 120, 120, 120, 312, 313, 314, 315, 
+    316, 317, 318, 319, 320, 321, 322, 323, 120, 120, 120, 120, 324, 325, 
+    326, 327, 328, 329, 330, 331, 332, 333, 332, 332, 332, 334, 335, 336, 
+    337, 338, 339, 340, 339, 339, 339, 341, 342, 343, 344, 345, 120, 120, 
+    120, 120, 346, 346, 346, 346, 346, 347, 348, 349, 350, 351, 352, 353, 
+    354, 355, 356, 346, 357, 358, 350, 359, 360, 360, 360, 360, 361, 362, 
+    363, 363, 363, 363, 363, 364, 365, 365, 365, 365, 365, 365, 365, 365, 
+    365, 365, 365, 365, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 
+    366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 367, 367, 367, 367, 
+    367, 367, 367, 367, 367, 368, 369, 368, 367, 367, 367, 367, 367, 368, 
+    367, 367, 367, 367, 368, 369, 368, 367, 369, 367, 367, 367, 367, 367, 
+    367, 367, 368, 367, 367, 367, 367, 367, 367, 367, 367, 370, 371, 372, 
+    373, 374, 367, 367, 375, 376, 377, 377, 377, 377, 377, 377, 377, 377, 
+    377, 377, 378, 379, 380, 381, 381, 381, 381, 381, 381, 381, 381, 381, 
+    381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 
+    381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 
+    381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 
+    381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 
+    381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 382, 381, 381, 
+    383, 384, 384, 385, 386, 386, 386, 386, 386, 386, 386, 386, 386, 387, 
+    388, 389, 390, 391, 392, 120, 393, 393, 394, 120, 395, 395, 396, 120, 
+    397, 398, 399, 120, 400, 400, 400, 400, 400, 400, 401, 402, 403, 404, 
+    405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 415, 415, 415, 
+    416, 415, 415, 415, 415, 415, 415, 120, 415, 415, 415, 415, 415, 417, 
+    381, 381, 381, 381, 381, 381, 381, 381, 418, 120, 419, 419, 419, 420, 
+    421, 422, 423, 424, 425, 426, 427, 427, 427, 428, 429, 120, 430, 430, 
+    430, 430, 430, 431, 430, 430, 430, 432, 433, 434, 435, 435, 435, 435, 
+    436, 436, 437, 438, 439, 439, 439, 439, 439, 439, 440, 441, 442, 443, 
+    444, 445, 446, 447, 446, 447, 448, 449, 450, 451, 120, 120, 120, 120, 
+    120, 120, 120, 120, 452, 453, 453, 453, 453, 453, 454, 455, 456, 457, 
+    458, 459, 460, 461, 462, 463, 464, 465, 465, 465, 466, 467, 468, 469, 
+    470, 470, 470, 470, 471, 472, 473, 474, 475, 475, 475, 475, 476, 477, 
+    478, 479, 480, 481, 482, 483, 484, 484, 484, 485, 120, 120, 120, 120, 
+    120, 120, 120, 120, 486, 120, 487, 488, 489, 490, 491, 492, 54, 54, 54, 
+    54, 493, 494, 56, 56, 56, 56, 56, 495, 496, 497, 54, 498, 54, 54, 54, 
+    499, 56, 56, 56, 500, 501, 502, 503, 504, 504, 504, 505, 506, 27, 27, 27, 
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 507, 508, 27, 
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 509, 510, 511, 512, 509, 510, 
+    509, 510, 511, 512, 509, 513, 509, 510, 509, 511, 509, 514, 509, 514, 
+    509, 514, 515, 516, 517, 518, 519, 520, 509, 521, 522, 523, 524, 525, 
+    526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 
+    540, 541, 56, 542, 543, 544, 543, 545, 120, 120, 546, 547, 548, 549, 550, 
+    120, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 
+    564, 563, 565, 566, 567, 568, 569, 570, 571, 572, 573, 572, 574, 575, 
+    572, 576, 572, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 
+    588, 589, 590, 591, 592, 587, 587, 593, 594, 595, 596, 597, 587, 587, 
+    598, 578, 599, 600, 587, 587, 601, 587, 587, 572, 602, 603, 572, 604, 
+    605, 606, 607, 607, 607, 607, 607, 607, 607, 607, 608, 572, 572, 609, 
+    610, 578, 578, 611, 572, 572, 572, 572, 577, 612, 572, 572, 613, 572, 
+    572, 572, 572, 614, 120, 120, 120, 572, 613, 120, 120, 615, 615, 615, 
+    615, 615, 616, 616, 617, 618, 618, 618, 618, 618, 618, 618, 618, 618, 
+    619, 615, 615, 620, 620, 620, 620, 620, 620, 620, 620, 620, 621, 620, 
+    620, 620, 620, 621, 572, 620, 620, 622, 572, 623, 573, 624, 625, 626, 
+    627, 573, 572, 622, 576, 572, 578, 628, 629, 625, 630, 572, 572, 572, 
+    572, 631, 572, 572, 572, 632, 633, 572, 572, 572, 572, 572, 634, 572, 
+    635, 572, 634, 636, 637, 620, 620, 638, 620, 620, 620, 572, 572, 572, 
+    572, 572, 572, 572, 639, 572, 572, 576, 572, 572, 640, 641, 615, 642, 
+    642, 643, 572, 572, 572, 572, 572, 644, 645, 646, 647, 648, 649, 578, 
+    578, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 
+    650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 
+    650, 650, 650, 650, 650, 578, 578, 578, 578, 578, 578, 578, 578, 578, 
+    578, 578, 578, 578, 578, 578, 578, 651, 652, 652, 653, 587, 587, 578, 
+    654, 601, 655, 656, 657, 658, 659, 660, 661, 578, 662, 587, 663, 664, 
+    665, 666, 647, 578, 578, 590, 654, 666, 667, 668, 669, 587, 587, 587, 
+    587, 670, 671, 587, 587, 587, 587, 672, 673, 674, 647, 675, 676, 572, 
+    572, 572, 572, 572, 572, 578, 578, 677, 678, 679, 573, 572, 572, 680, 
+    572, 572, 572, 681, 572, 572, 572, 572, 682, 572, 683, 684, 120, 120, 
+    685, 120, 120, 686, 686, 686, 686, 686, 687, 688, 688, 688, 688, 688, 
+    689, 690, 691, 692, 693, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 
+    694, 695, 696, 697, 698, 698, 698, 698, 699, 700, 701, 701, 701, 701, 
+    701, 701, 701, 702, 703, 704, 367, 367, 369, 120, 369, 369, 369, 369, 
+    369, 369, 369, 369, 705, 705, 705, 705, 706, 707, 708, 709, 710, 711, 
+    533, 712, 713, 120, 120, 120, 120, 120, 120, 120, 714, 714, 714, 715, 
+    714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 716, 120, 714, 714, 
+    714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 
+    714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 717, 120, 120, 120, 
+    718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 729, 729, 
+    729, 729, 729, 729, 729, 729, 730, 731, 732, 733, 733, 733, 733, 733, 
+    733, 733, 733, 733, 733, 734, 735, 736, 736, 736, 736, 737, 738, 365, 
+    365, 365, 365, 365, 365, 365, 365, 365, 365, 739, 740, 741, 736, 736, 
+    736, 742, 718, 718, 718, 718, 719, 120, 733, 733, 743, 743, 743, 744, 
+    745, 746, 741, 741, 741, 747, 748, 749, 743, 743, 743, 750, 745, 746, 
+    741, 741, 741, 741, 751, 749, 741, 752, 753, 753, 753, 753, 753, 754, 
+    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 741, 741, 741, 
+    755, 756, 741, 741, 741, 741, 741, 741, 741, 741, 741, 741, 741, 757, 
+    741, 741, 741, 755, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 759, 760, 572, 572, 572, 572, 572, 572, 572, 572, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 759, 760, 760, 760, 
+    760, 760, 761, 761, 762, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
     761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
     761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
     761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
     761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
-    761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
-    761, 761, 761, 763, 764, 764, 764, 764, 764, 764, 765, 120, 766, 766, 
-    766, 766, 766, 767, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 
+    761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 763, 
+    764, 764, 764, 764, 764, 764, 765, 120, 766, 766, 766, 766, 766, 767, 
     768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 
-    768, 768, 768, 768, 768, 768, 768, 768, 768, 769, 768, 768, 770, 771, 
-    120, 120, 101, 101, 101, 101, 101, 772, 773, 774, 101, 101, 101, 775, 
-    776, 776, 776, 776, 776, 776, 776, 776, 777, 778, 779, 120, 64, 64, 780, 
-    781, 782, 27, 783, 27, 27, 27, 27, 27, 27, 27, 784, 785, 27, 786, 787, 
-    27, 27, 788, 789, 120, 120, 120, 120, 120, 120, 120, 790, 791, 792, 793, 
-    794, 794, 795, 796, 797, 798, 799, 799, 799, 799, 799, 799, 800, 120, 
-    801, 802, 802, 802, 802, 802, 803, 804, 805, 806, 807, 808, 809, 809, 
-    810, 811, 812, 813, 814, 814, 815, 816, 817, 817, 818, 819, 820, 821, 
-    363, 363, 363, 822, 823, 824, 824, 824, 824, 824, 825, 826, 827, 828, 
-    829, 830, 831, 344, 348, 832, 833, 833, 833, 833, 833, 834, 835, 120, 
-    836, 837, 838, 839, 344, 344, 840, 841, 842, 842, 842, 842, 842, 842, 
-    843, 844, 845, 120, 120, 846, 847, 848, 849, 120, 850, 850, 850, 120, 
-    367, 367, 54, 54, 54, 54, 54, 851, 852, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 847, 847, 847, 847, 853, 854, 855, 856, 857, 
-    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
-    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
-    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
-    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
-    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
-    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 859, 
-    120, 364, 364, 860, 861, 364, 364, 364, 364, 364, 862, 863, 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, 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, 864, 863, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 864, 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, 864, 865, 
-    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
-    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
-    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
-    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
-    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
-    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
-    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 867, 868, 868, 868, 
-    868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 
-    868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 
-    868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 
-    869, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 
-    870, 759, 759, 759, 759, 871, 120, 872, 873, 121, 874, 875, 876, 877, 
-    121, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 878, 
-    879, 880, 120, 881, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
+    768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 
+    768, 768, 768, 768, 768, 769, 768, 768, 770, 771, 120, 120, 101, 101, 
+    101, 101, 101, 772, 773, 774, 101, 101, 101, 775, 776, 776, 776, 776, 
+    776, 776, 776, 776, 777, 778, 779, 120, 64, 64, 780, 781, 782, 27, 783, 
+    27, 27, 27, 27, 27, 27, 27, 784, 785, 27, 786, 787, 27, 27, 788, 789, 
+    120, 120, 120, 120, 120, 120, 120, 790, 791, 792, 793, 794, 794, 795, 
+    796, 797, 798, 799, 799, 799, 799, 799, 799, 800, 120, 801, 802, 802, 
+    802, 802, 802, 803, 804, 805, 806, 807, 808, 809, 809, 810, 811, 812, 
+    813, 814, 814, 815, 816, 817, 817, 818, 819, 820, 821, 365, 365, 365, 
+    822, 823, 824, 824, 824, 824, 824, 825, 826, 827, 828, 829, 830, 831, 
+    346, 350, 832, 833, 833, 833, 833, 833, 834, 835, 120, 836, 837, 838, 
+    839, 346, 346, 840, 841, 842, 842, 842, 842, 842, 842, 843, 844, 845, 
+    120, 120, 846, 847, 848, 849, 120, 850, 850, 850, 120, 369, 369, 54, 54, 
+    54, 54, 54, 851, 852, 120, 853, 853, 853, 853, 853, 853, 853, 853, 853, 
+    853, 847, 847, 847, 847, 854, 855, 856, 857, 365, 365, 365, 365, 365, 
+    365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 
+    365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 
+    365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 
+    365, 365, 365, 365, 365, 858, 120, 366, 366, 859, 860, 366, 366, 366, 
+    366, 366, 861, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 
+    862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 
+    862, 862, 862, 862, 862, 862, 862, 863, 863, 863, 863, 863, 863, 863, 
+    863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 
+    863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 759, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 864, 760, 760, 760, 
+    760, 865, 120, 866, 867, 121, 868, 869, 870, 871, 121, 128, 128, 128, 
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 872, 873, 874, 120, 875, 
     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, 882, 120, 120, 128, 128, 128, 128, 128, 
-    128, 128, 128, 883, 128, 128, 128, 128, 128, 128, 120, 120, 120, 120, 
-    120, 128, 884, 885, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 
-    895, 896, 897, 898, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
-    128, 128, 128, 128, 128, 128, 899, 900, 901, 902, 903, 904, 905, 905, 
-    906, 907, 908, 908, 909, 910, 911, 912, 911, 911, 911, 911, 913, 914, 
-    914, 914, 915, 916, 916, 916, 917, 918, 919, 120, 920, 921, 922, 921, 
-    921, 923, 921, 921, 924, 921, 925, 921, 925, 120, 120, 120, 120, 921, 
-    921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 
-    926, 927, 928, 928, 928, 928, 928, 929, 606, 930, 930, 930, 930, 930, 
-    930, 931, 932, 933, 934, 571, 935, 936, 120, 120, 120, 120, 120, 606, 
-    606, 606, 606, 606, 937, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 938, 938, 938, 939, 940, 940, 940, 
-    940, 940, 940, 941, 120, 942, 943, 943, 944, 945, 945, 945, 945, 946, 
-    120, 947, 947, 948, 949, 950, 950, 950, 950, 951, 952, 953, 953, 953, 
-    954, 955, 955, 955, 955, 956, 955, 957, 120, 120, 120, 120, 120, 958, 
-    958, 958, 958, 958, 959, 959, 959, 959, 959, 960, 960, 960, 960, 960, 
-    960, 961, 961, 961, 962, 963, 964, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 965, 965, 965, 965, 965, 120, 966, 966, 966, 966, 966, 
-    966, 967, 968, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 969, 969, 969, 969, 969, 969, 969, 
-    969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 
-    969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 
-    969, 969, 969, 970, 120, 969, 969, 971, 120, 969, 120, 120, 120, 120, 
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
+    128, 128, 876, 120, 120, 128, 128, 128, 128, 128, 128, 128, 128, 877, 
+    128, 128, 128, 128, 128, 128, 120, 120, 120, 120, 120, 128, 878, 879, 
+    879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
+    128, 128, 893, 894, 895, 896, 897, 898, 899, 899, 900, 901, 902, 902, 
+    903, 904, 905, 906, 905, 905, 905, 905, 907, 908, 908, 908, 909, 910, 
+    910, 910, 911, 912, 913, 120, 914, 915, 916, 915, 915, 917, 915, 915, 
+    918, 915, 919, 915, 919, 120, 120, 120, 120, 915, 915, 915, 915, 915, 
+    915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 920, 921, 922, 922, 
+    922, 922, 922, 923, 607, 924, 924, 924, 924, 924, 924, 925, 926, 927, 
+    928, 572, 929, 930, 120, 120, 120, 120, 120, 607, 607, 607, 607, 607, 
+    931, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 932, 932, 932, 933, 934, 934, 934, 934, 934, 934, 935, 
+    120, 936, 937, 937, 938, 939, 939, 939, 939, 940, 120, 941, 941, 942, 
+    943, 944, 944, 944, 944, 945, 946, 947, 947, 947, 948, 949, 949, 949, 
+    949, 950, 949, 951, 120, 120, 120, 120, 120, 952, 952, 952, 952, 952, 
+    953, 953, 953, 953, 953, 954, 954, 954, 954, 954, 954, 955, 955, 955, 
+    956, 957, 958, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 959, 
+    959, 959, 959, 959, 120, 960, 960, 960, 960, 960, 960, 961, 962, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 972, 973, 974, 974, 974, 974, 975, 976, 977, 977, 978, 979, 980, 
-    980, 981, 982, 983, 983, 983, 984, 985, 986, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 987, 987, 988, 989, 990, 990, 990, 991, 120, 
-    120, 120, 120, 120, 120, 120, 120, 992, 992, 992, 992, 993, 993, 993, 
-    994, 120, 120, 120, 120, 120, 120, 120, 120, 995, 996, 997, 998, 999, 
-    999, 1000, 1001, 1002, 120, 1003, 1004, 1005, 1005, 1005, 1006, 1007, 
-    1007, 1007, 1008, 120, 120, 120, 120, 1009, 1010, 1009, 1009, 1011, 1012, 
-    1013, 120, 1014, 1014, 1014, 1014, 1014, 1014, 1015, 1016, 1017, 1017, 
-    1018, 1019, 1020, 1020, 1021, 1022, 1023, 1023, 1024, 1025, 120, 1026, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1027, 1027, 1027, 1027, 
-    1027, 1027, 1027, 1027, 1027, 1028, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 
+    963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 
+    963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 964, 
+    120, 963, 963, 965, 120, 963, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 966, 967, 968, 
+    968, 968, 968, 969, 970, 971, 971, 972, 973, 974, 974, 975, 976, 977, 
+    977, 977, 978, 979, 980, 120, 120, 120, 120, 120, 120, 981, 981, 982, 
+    983, 984, 984, 985, 986, 987, 987, 987, 988, 120, 120, 120, 120, 120, 
+    120, 120, 120, 989, 989, 989, 989, 990, 990, 990, 991, 992, 992, 993, 
+    992, 992, 992, 992, 992, 994, 995, 996, 997, 998, 998, 999, 1000, 1001, 
+    120, 1002, 1003, 1004, 1004, 1004, 1005, 1006, 1006, 1006, 1007, 120, 
+    120, 120, 120, 1008, 1009, 1008, 1008, 1010, 1011, 1012, 120, 1013, 1013, 
+    1013, 1013, 1013, 1013, 1014, 1015, 1016, 1016, 1017, 1018, 1019, 1019, 
+    1020, 1021, 1022, 1022, 1023, 1024, 120, 1025, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 
+    1026, 1027, 120, 120, 120, 120, 120, 120, 1028, 1028, 1028, 1028, 1028, 
+    1028, 1029, 120, 1030, 1030, 1030, 1030, 1030, 1030, 1031, 1032, 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, 1029, 
-    1029, 1029, 1030, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 1031, 1032, 1032, 1032, 1032, 1032, 1032, 1033, 
-    1034, 1035, 1036, 1037, 1038, 1039, 120, 1040, 1041, 1042, 1042, 1042, 
-    1042, 1042, 1043, 1044, 1045, 120, 1046, 1046, 1046, 1047, 1048, 1049, 
-    1050, 1051, 1051, 1051, 1052, 1053, 1054, 1055, 1056, 120, 1057, 1057, 
-    1057, 1057, 1058, 120, 1059, 1060, 1060, 1060, 1060, 1060, 1061, 1062, 
-    1063, 1064, 1065, 1066, 1067, 1068, 1069, 120, 1070, 1070, 1071, 1070, 
-    1070, 1072, 1073, 1074, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 1075, 1075, 1075, 1075, 1075, 1076, 1077, 1078, 1079, 
-    1080, 1081, 1082, 1083, 1084, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 
-    1091, 1092, 1093, 1093, 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, 1094, 1094, 1094, 1094, 
-    1094, 1094, 1095, 1096, 1097, 120, 1098, 1099, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 1100, 1100, 1100, 1100, 1100, 1101, 1102, 1103, 1104, 1105, 120, 
-    120, 120, 120, 120, 120, 1106, 1106, 1106, 1106, 1106, 1106, 1107, 1108, 
-    1109, 120, 1110, 1111, 120, 120, 120, 120, 1112, 1112, 1112, 1112, 1112, 
-    1113, 1114, 120, 1115, 1116, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 1033, 1033, 1033, 1034, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 1035, 1036, 1036, 1036, 1036, 1036, 
+    1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 120, 1044, 1045, 1046, 
+    1046, 1046, 1046, 1046, 1047, 1048, 1049, 120, 1050, 1050, 1050, 1051, 
+    1052, 1053, 1054, 1055, 1055, 1055, 1056, 1057, 1058, 1059, 1060, 120, 
+    1061, 1061, 1061, 1061, 1062, 120, 1063, 1064, 1064, 1064, 1064, 1064, 
+    1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 120, 1074, 1074, 
+    1075, 1074, 1074, 1076, 1077, 1078, 120, 120, 120, 120, 120, 120, 120, 
+    120, 1079, 1080, 1081, 1082, 1081, 1083, 1084, 1084, 1084, 1084, 1084, 
+    1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1093, 1094, 1095, 
+    1096, 1097, 1098, 1099, 1100, 1101, 1102, 1102, 120, 120, 120, 120, 120, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 1117, 1117, 1117, 1117, 1118, 1118, 1118, 1118, 1119, 
-    1120, 1121, 1122, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1123, 
-    1123, 1123, 1123, 1123, 1123, 1123, 1124, 1125, 1125, 1125, 1125, 1125, 
-    1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 
-    1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 
-    1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 
-    1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1126, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1127, 1127, 1127, 
-    1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1128, 1129, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 
-    1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 
-    1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 
-    1130, 1130, 1130, 1130, 1131, 120, 120, 120, 120, 120, 120, 120, 120, 
+    1103, 1103, 1103, 1103, 1103, 1103, 1104, 1105, 1106, 120, 1107, 1108, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 
+    120, 120, 120, 120, 120, 120, 1109, 1109, 1109, 1109, 1109, 1110, 1111, 
+    1112, 1113, 1114, 1114, 1115, 120, 120, 120, 120, 1116, 1116, 1116, 1116, 
+    1116, 1116, 1117, 1118, 1119, 120, 1120, 1121, 120, 120, 120, 120, 1122, 
+    1122, 1122, 1122, 1122, 1123, 1124, 120, 1125, 1126, 120, 120, 120, 120, 
+    120, 120, 1127, 1127, 1127, 1128, 1129, 1130, 1131, 1132, 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, 1133, 
+    1133, 1133, 1133, 1134, 1134, 1134, 1134, 1135, 1136, 1137, 1138, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 1139, 1139, 1139, 1139, 
+    1139, 1139, 1139, 1140, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 
+    1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 
+    1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 
+    1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 
+    1141, 1141, 1141, 1141, 1141, 1141, 1141, 1142, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 1143, 1143, 1143, 1143, 1143, 1143, 
+    1143, 1143, 1143, 1143, 1143, 1143, 1143, 1144, 1145, 120, 1141, 1141, 
+    1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 
+    1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1141, 1146, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 1147, 1147, 1147, 1147, 1147, 
+    1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 
+    1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 
+    1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1148, 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, 1149, 1149, 1149, 1149, 1149, 
+    1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 
+    1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 
+    1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1150, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 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, 1132, 1133, 1133, 1133, 1134, 1135, 1136, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 1137, 1137, 1137, 1138, 1139, 120, 
-    1140, 1140, 1140, 1140, 1140, 1140, 1141, 1142, 1143, 120, 1144, 1145, 
-    1146, 1140, 1140, 1147, 1140, 1140, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 1148, 1148, 1148, 1148, 1148, 1148, 
-    1148, 1148, 1149, 120, 1150, 1151, 1151, 1151, 1151, 1152, 120, 1153, 
-    1154, 1155, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    1156, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    776, 776, 776, 776, 776, 776, 1151, 1152, 1152, 1152, 1153, 1154, 1155, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1156, 1156, 
+    1156, 1157, 1158, 120, 1159, 1159, 1159, 1159, 1159, 1159, 1160, 1161, 
+    1162, 120, 1163, 1164, 1165, 1159, 1159, 1166, 1159, 1159, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1167, 1167, 1167, 
+    1167, 1167, 1167, 1167, 1167, 1168, 120, 1169, 1170, 1170, 1170, 1170, 
+    1171, 120, 1172, 1173, 1174, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 1175, 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, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 
-    1157, 1157, 1157, 1157, 1158, 1157, 1159, 1157, 1160, 1157, 1161, 1162, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 606, 606, 606, 
-    606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 
-    606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 1163, 
-    120, 606, 606, 606, 606, 1164, 1165, 606, 606, 606, 606, 606, 606, 1166, 
-    1167, 1168, 1169, 1170, 1171, 606, 606, 606, 1172, 606, 606, 606, 606, 
-    606, 1163, 120, 120, 120, 120, 933, 933, 933, 933, 933, 933, 933, 933, 
-    1173, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 571, 571, 571, 571, 
-    571, 571, 571, 571, 571, 571, 613, 120, 928, 928, 1174, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 1176, 1176, 1176, 1176, 1176, 1176, 
+    1176, 1176, 1176, 1176, 1176, 1176, 1176, 1177, 1176, 1178, 1176, 1179, 
+    1176, 1180, 1181, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 
+    607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 
+    607, 607, 1182, 120, 607, 607, 607, 607, 1183, 1184, 607, 607, 607, 607, 
+    607, 607, 1185, 1186, 1187, 1188, 1189, 1190, 607, 607, 607, 1191, 607, 
+    607, 607, 607, 607, 607, 607, 1192, 120, 120, 927, 927, 927, 927, 927, 
+    927, 927, 927, 1193, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 572, 
+    572, 572, 572, 572, 572, 572, 572, 572, 572, 614, 120, 922, 922, 1194, 
     120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    1175, 1175, 1175, 1176, 1177, 1177, 1178, 1175, 1175, 1179, 1180, 1177, 
-    1177, 1175, 1175, 1175, 1176, 1177, 1177, 1181, 1182, 1183, 1179, 1184, 
-    1185, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1186, 1187, 1188, 1189, 
-    1177, 1177, 1177, 1190, 1191, 1192, 1193, 1177, 1177, 1178, 1175, 1175, 
-    1179, 1177, 1177, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1178, 1175, 
-    1175, 1179, 1177, 1177, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1178, 
-    1175, 1175, 1179, 1177, 1177, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 
-    1194, 1175, 1175, 1175, 1195, 1177, 1177, 1196, 1197, 1175, 1175, 1198, 
-    1177, 1177, 1199, 1178, 1175, 1175, 1200, 1177, 1177, 1201, 1202, 1175, 
-    1175, 1203, 1177, 1177, 1177, 1204, 1175, 1175, 1175, 1195, 1177, 1177, 
-    1196, 1205, 1206, 1206, 1206, 1206, 1206, 1206, 1207, 1207, 1207, 1207, 
-    1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 
-    1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1208, 1209, 1210, 120, 
-    120, 120, 120, 120, 1211, 128, 128, 128, 1212, 1213, 1214, 1215, 1216, 
-    1217, 1212, 1218, 1212, 1214, 1214, 1219, 128, 1220, 128, 1221, 1222, 
-    1220, 128, 1221, 120, 120, 120, 120, 120, 120, 1223, 120, 571, 571, 571, 
-    571, 571, 935, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
-    571, 935, 120, 571, 613, 1224, 571, 1224, 571, 1224, 571, 571, 571, 680, 
-    120, 615, 1225, 617, 617, 617, 1226, 617, 617, 617, 617, 617, 617, 617, 
-    1227, 617, 617, 617, 617, 617, 1228, 120, 120, 120, 120, 120, 120, 120, 
-    120, 1229, 606, 606, 606, 1230, 120, 739, 739, 739, 739, 739, 1231, 739, 
-    1232, 1233, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 120, 120, 120, 571, 571, 571, 571, 571, 
-    1234, 571, 571, 571, 571, 571, 571, 571, 571, 571, 680, 571, 571, 571, 
-    571, 571, 571, 571, 571, 571, 613, 1235, 571, 571, 571, 571, 120, 571, 
-    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
-    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
-    571, 571, 613, 571, 571, 571, 571, 571, 571, 571, 571, 571, 612, 571, 
-    571, 571, 571, 571, 1236, 571, 571, 571, 571, 1237, 571, 571, 571, 571, 
-    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
-    571, 1238, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
-    571, 571, 571, 571, 571, 120, 120, 571, 1234, 935, 120, 571, 571, 571, 
-    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 935, 120, 571, 
-    571, 571, 571, 571, 571, 571, 571, 571, 571, 1234, 120, 120, 120, 120, 
-    120, 571, 935, 571, 571, 571, 571, 571, 571, 571, 120, 571, 683, 571, 
-    571, 571, 571, 571, 120, 571, 571, 571, 680, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 1239, 759, 759, 759, 759, 759, 757, 757, 757, 757, 757, 
-    757, 760, 759, 756, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
-    757, 757, 758, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
-    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
-    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
-    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
-    759, 759, 759, 759, 759, 759, 759, 868, 868, 868, 869, 759, 759, 759, 
-    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
-    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
-    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
-    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
-    1240, 1241, 120, 120, 120, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 
-    1242, 1242, 1242, 1242, 1242, 120, 120, 120, 120, 120, 120, 120, 120, 
-    120, 120, 120, 120, 120, 120, 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, 120, 120, 866, 866, 
-    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
-    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
-    866, 1243, 
+    120, 120, 120, 1195, 1195, 1195, 1196, 1197, 1197, 1198, 1195, 1195, 
+    1199, 1200, 1197, 1197, 1195, 1195, 1195, 1196, 1197, 1197, 1201, 1202, 
+    1203, 1199, 1204, 1205, 1197, 1195, 1195, 1195, 1196, 1197, 1197, 1206, 
+    1207, 1208, 1209, 1197, 1197, 1197, 1210, 1211, 1212, 1213, 1197, 1197, 
+    1198, 1195, 1195, 1199, 1197, 1197, 1197, 1195, 1195, 1195, 1196, 1197, 
+    1197, 1198, 1195, 1195, 1199, 1197, 1197, 1197, 1195, 1195, 1195, 1196, 
+    1197, 1197, 1198, 1195, 1195, 1199, 1197, 1197, 1197, 1195, 1195, 1195, 
+    1196, 1197, 1197, 1214, 1195, 1195, 1195, 1215, 1197, 1197, 1216, 1217, 
+    1195, 1195, 1218, 1197, 1197, 1219, 1198, 1195, 1195, 1220, 1197, 1197, 
+    1221, 1222, 1195, 1195, 1223, 1197, 1197, 1197, 1224, 1195, 1195, 1195, 
+    1215, 1197, 1197, 1216, 1225, 1226, 1226, 1226, 1226, 1226, 1226, 1227, 
+    1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 
+    1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 
+    1227, 1227, 1227, 1227, 1227, 1227, 1227, 1228, 1228, 1228, 1228, 1228, 
+    1228, 1229, 1230, 1228, 1228, 1228, 1228, 1228, 1231, 1232, 1227, 1233, 
+    1234, 120, 1235, 1236, 1228, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 
+    1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 
+    1237, 1238, 1239, 1240, 120, 120, 120, 120, 120, 1241, 128, 128, 128, 
+    1242, 1243, 1244, 1245, 1246, 1247, 1242, 1248, 1242, 1244, 1244, 1249, 
+    128, 1250, 128, 1251, 1252, 1250, 128, 1251, 120, 120, 120, 120, 120, 
+    120, 1253, 120, 572, 572, 572, 572, 572, 929, 572, 572, 572, 572, 572, 
+    572, 572, 572, 572, 572, 572, 572, 929, 120, 572, 614, 1254, 572, 1254, 
+    572, 1254, 572, 572, 572, 681, 120, 616, 1255, 618, 618, 618, 1256, 618, 
+    618, 618, 618, 618, 618, 618, 1257, 618, 618, 618, 618, 618, 1258, 120, 
+    120, 120, 120, 120, 120, 120, 120, 1259, 607, 607, 607, 1260, 120, 741, 
+    741, 741, 741, 741, 1261, 741, 1262, 1263, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 
+    572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 
+    572, 572, 572, 572, 1264, 572, 572, 572, 572, 572, 572, 572, 572, 572, 
+    572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 
+    572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 
+    572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 1265, 572, 572, 572, 
+    572, 1266, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 
+    572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 
+    572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 1267, 120, 572, 
+    1268, 929, 120, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 572, 
+    572, 572, 572, 929, 120, 572, 572, 572, 572, 572, 572, 572, 572, 572, 
+    572, 1268, 120, 120, 120, 120, 120, 572, 929, 572, 572, 572, 572, 572, 
+    572, 572, 120, 572, 684, 572, 572, 572, 572, 572, 120, 572, 572, 572, 
+    681, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 572, 
+    1267, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1268, 
+    120, 120, 120, 120, 120, 120, 120, 1267, 120, 120, 120, 120, 120, 120, 
+    120, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 1269, 
+    760, 760, 760, 760, 760, 758, 758, 758, 758, 758, 758, 1270, 760, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 759, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 
+    758, 758, 758, 758, 758, 864, 760, 760, 760, 760, 760, 760, 760, 760, 
+    760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 
+    760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 
+    760, 760, 760, 760, 760, 760, 760, 758, 758, 758, 759, 760, 760, 760, 
+    760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 
+    760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 
+    760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 
+    760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 
+    1271, 1272, 120, 120, 120, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 
+    1273, 1273, 1273, 1273, 1273, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 879, 879, 879, 879, 879, 879, 
+    879, 879, 879, 879, 879, 879, 879, 879, 879, 879, 879, 879, 879, 879, 
+    879, 879, 879, 879, 879, 879, 879, 879, 879, 879, 120, 120, 863, 863, 
+    863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 
+    863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 
+    863, 1274, 
 };
 
 static const unsigned short index2[] = {
@@ -2289,109 +2316,110 @@
     161, 160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 160, 160, 160, 
     161, 160, 160, 160, 160, 160, 64, 64, 162, 162, 162, 162, 162, 162, 162, 
     162, 162, 162, 162, 162, 162, 162, 162, 64, 163, 163, 163, 163, 163, 163, 
-    163, 163, 163, 164, 164, 164, 64, 64, 165, 64, 126, 126, 126, 64, 64, 64, 
-    64, 64, 64, 64, 64, 64, 120, 120, 137, 120, 120, 137, 120, 120, 120, 137, 
-    137, 137, 166, 167, 168, 120, 120, 120, 137, 120, 120, 137, 137, 120, 
-    120, 120, 120, 120, 169, 169, 169, 170, 171, 171, 171, 171, 171, 171, 
-    171, 171, 171, 171, 171, 171, 171, 171, 169, 170, 172, 171, 170, 170, 
-    170, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 173, 
-    170, 170, 171, 78, 136, 174, 174, 169, 169, 169, 171, 171, 169, 169, 84, 
-    84, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 177, 171, 171, 
-    171, 171, 171, 171, 178, 179, 180, 180, 64, 178, 178, 178, 178, 178, 178, 
-    178, 178, 64, 64, 178, 178, 64, 64, 178, 178, 178, 178, 178, 178, 178, 
-    178, 178, 178, 178, 178, 178, 178, 64, 178, 178, 178, 178, 178, 178, 178, 
-    64, 178, 64, 64, 64, 178, 178, 178, 178, 64, 64, 181, 178, 180, 180, 180, 
-    179, 179, 179, 179, 64, 64, 180, 180, 64, 64, 180, 180, 182, 178, 64, 64, 
-    64, 64, 64, 64, 64, 64, 180, 64, 64, 64, 64, 178, 178, 64, 178, 178, 178, 
-    179, 179, 64, 64, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 178, 
-    178, 184, 184, 185, 185, 185, 185, 185, 185, 186, 184, 64, 64, 64, 64, 
-    64, 187, 187, 188, 64, 189, 189, 189, 189, 189, 189, 64, 64, 64, 64, 189, 
-    189, 64, 64, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 
-    189, 189, 64, 189, 189, 189, 189, 189, 189, 189, 64, 189, 189, 64, 189, 
-    189, 64, 189, 189, 64, 64, 190, 64, 188, 188, 188, 187, 187, 64, 64, 64, 
-    64, 187, 187, 64, 64, 187, 187, 191, 64, 64, 64, 187, 64, 64, 64, 64, 64, 
-    64, 64, 189, 189, 189, 189, 64, 189, 64, 64, 64, 64, 64, 64, 64, 192, 
-    192, 192, 192, 192, 192, 192, 192, 192, 192, 187, 187, 189, 189, 189, 
-    187, 64, 64, 64, 193, 193, 194, 64, 195, 195, 195, 195, 195, 195, 195, 
-    195, 195, 64, 195, 195, 195, 64, 195, 195, 195, 195, 195, 195, 195, 195, 
-    195, 195, 195, 195, 195, 195, 64, 195, 195, 195, 195, 195, 195, 195, 64, 
-    195, 195, 64, 195, 195, 195, 195, 195, 64, 64, 196, 195, 194, 194, 194, 
-    193, 193, 193, 193, 193, 64, 193, 193, 194, 64, 194, 194, 197, 64, 64, 
-    195, 64, 64, 64, 64, 64, 64, 64, 195, 195, 193, 193, 64, 64, 198, 198, 
-    198, 198, 198, 198, 198, 198, 198, 198, 199, 200, 64, 64, 64, 64, 64, 64, 
-    64, 201, 202, 202, 64, 203, 203, 203, 203, 203, 203, 203, 203, 64, 64, 
-    203, 203, 64, 64, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 
-    203, 203, 203, 64, 203, 203, 203, 203, 203, 203, 203, 64, 203, 203, 64, 
-    203, 203, 203, 203, 203, 64, 64, 204, 203, 202, 201, 202, 201, 201, 201, 
-    201, 64, 64, 202, 202, 64, 64, 202, 202, 205, 64, 64, 64, 64, 64, 64, 64, 
-    64, 201, 202, 64, 64, 64, 64, 203, 203, 64, 203, 203, 203, 201, 201, 64, 
-    64, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 207, 203, 208, 208, 
-    208, 208, 208, 208, 64, 64, 209, 210, 64, 210, 210, 210, 210, 210, 210, 
-    64, 64, 64, 210, 210, 210, 64, 210, 210, 210, 210, 64, 64, 64, 210, 210, 
-    64, 210, 64, 210, 210, 64, 64, 64, 210, 210, 64, 64, 64, 210, 210, 210, 
-    210, 210, 210, 210, 210, 210, 210, 64, 64, 64, 64, 211, 211, 209, 211, 
-    211, 64, 64, 64, 211, 211, 211, 64, 211, 211, 211, 212, 64, 64, 210, 64, 
-    64, 64, 64, 64, 64, 211, 64, 64, 64, 64, 64, 64, 213, 213, 213, 213, 213, 
-    213, 213, 213, 213, 213, 214, 214, 214, 215, 215, 215, 215, 215, 215, 
-    216, 215, 64, 64, 64, 64, 64, 217, 218, 218, 218, 64, 219, 219, 219, 219, 
-    219, 219, 219, 219, 64, 219, 219, 219, 64, 219, 219, 219, 219, 219, 219, 
-    219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 64, 64, 64, 219, 217, 
-    217, 217, 218, 218, 218, 218, 64, 217, 217, 217, 64, 217, 217, 217, 220, 
-    64, 64, 64, 64, 64, 64, 64, 221, 222, 64, 219, 219, 64, 64, 64, 64, 64, 
-    64, 219, 219, 217, 217, 64, 64, 223, 223, 223, 223, 223, 223, 223, 223, 
-    223, 223, 224, 224, 224, 224, 224, 224, 224, 225, 64, 226, 227, 227, 64, 
-    228, 228, 228, 228, 228, 228, 228, 228, 64, 228, 228, 228, 64, 228, 228, 
-    228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 
-    228, 228, 64, 228, 228, 228, 228, 228, 64, 64, 229, 228, 227, 230, 227, 
-    227, 227, 227, 227, 64, 230, 227, 227, 64, 227, 227, 226, 231, 64, 64, 
-    64, 64, 64, 64, 64, 227, 227, 64, 64, 64, 64, 64, 64, 64, 228, 64, 228, 
-    228, 226, 226, 64, 64, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 
-    64, 228, 228, 64, 64, 64, 64, 64, 64, 233, 234, 234, 64, 235, 235, 235, 
-    235, 235, 235, 235, 235, 64, 235, 235, 235, 64, 235, 235, 235, 235, 235, 
-    235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 64, 64, 235, 
-    234, 234, 234, 233, 233, 233, 233, 64, 234, 234, 234, 64, 234, 234, 234, 
-    236, 235, 64, 64, 64, 64, 64, 64, 64, 64, 234, 235, 235, 233, 233, 64, 
-    64, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 238, 238, 238, 238, 
-    238, 238, 64, 64, 64, 239, 235, 235, 235, 235, 235, 235, 64, 64, 240, 
-    240, 64, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 
-    241, 241, 241, 241, 241, 64, 64, 64, 241, 241, 241, 241, 241, 241, 241, 
-    241, 64, 241, 241, 241, 241, 241, 241, 241, 241, 241, 64, 241, 64, 64, 
-    64, 64, 242, 64, 64, 64, 64, 240, 240, 240, 243, 243, 243, 64, 243, 64, 
-    240, 240, 240, 240, 240, 240, 240, 240, 64, 64, 64, 64, 64, 64, 244, 244, 
-    244, 244, 244, 244, 244, 244, 244, 244, 64, 64, 240, 240, 245, 64, 64, 
-    64, 64, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 
-    246, 246, 246, 247, 246, 246, 247, 247, 247, 247, 248, 248, 249, 64, 64, 
-    64, 64, 250, 246, 246, 246, 246, 246, 246, 251, 247, 252, 252, 252, 252, 
-    247, 247, 247, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 
-    253, 253, 64, 64, 64, 64, 64, 255, 255, 64, 255, 64, 64, 255, 255, 64, 
-    255, 64, 64, 255, 64, 64, 64, 64, 64, 64, 255, 255, 255, 255, 64, 255, 
-    255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 64, 255, 64, 255, 64, 
-    64, 255, 255, 64, 255, 255, 255, 255, 256, 255, 255, 256, 256, 256, 256, 
-    257, 257, 64, 256, 256, 255, 64, 64, 255, 255, 255, 255, 255, 64, 258, 
-    64, 259, 259, 259, 259, 256, 256, 64, 64, 260, 260, 260, 260, 260, 260, 
-    260, 260, 260, 260, 64, 64, 255, 255, 255, 255, 261, 262, 262, 262, 263, 
+    163, 163, 163, 164, 164, 164, 64, 64, 165, 64, 126, 126, 126, 126, 126, 
+    64, 64, 64, 64, 64, 64, 137, 120, 120, 137, 120, 120, 137, 120, 120, 120, 
+    137, 137, 137, 166, 167, 168, 120, 120, 120, 137, 120, 120, 137, 137, 
+    120, 120, 120, 120, 120, 169, 169, 169, 170, 171, 171, 171, 171, 171, 
+    171, 171, 171, 171, 171, 171, 171, 171, 171, 169, 170, 172, 171, 170, 
+    170, 170, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 
+    173, 170, 170, 171, 78, 136, 174, 174, 169, 169, 169, 171, 171, 169, 169, 
+    84, 84, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 177, 171, 
+    171, 171, 171, 171, 171, 178, 179, 180, 180, 64, 178, 178, 178, 178, 178, 
+    178, 178, 178, 64, 64, 178, 178, 64, 64, 178, 178, 178, 178, 178, 178, 
+    178, 178, 178, 178, 178, 178, 178, 178, 64, 178, 178, 178, 178, 178, 178, 
+    178, 64, 178, 64, 64, 64, 178, 178, 178, 178, 64, 64, 181, 178, 180, 180, 
+    180, 179, 179, 179, 179, 64, 64, 180, 180, 64, 64, 180, 180, 182, 178, 
+    64, 64, 64, 64, 64, 64, 64, 64, 180, 64, 64, 64, 64, 178, 178, 64, 178, 
+    178, 178, 179, 179, 64, 64, 183, 183, 183, 183, 183, 183, 183, 183, 183, 
+    183, 178, 178, 184, 184, 185, 185, 185, 185, 185, 185, 186, 184, 64, 64, 
+    64, 64, 64, 187, 187, 188, 64, 189, 189, 189, 189, 189, 189, 64, 64, 64, 
+    64, 189, 189, 64, 64, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 
+    189, 189, 189, 189, 64, 189, 189, 189, 189, 189, 189, 189, 64, 189, 189, 
+    64, 189, 189, 64, 189, 189, 64, 64, 190, 64, 188, 188, 188, 187, 187, 64, 
+    64, 64, 64, 187, 187, 64, 64, 187, 187, 191, 64, 64, 64, 187, 64, 64, 64, 
+    64, 64, 64, 64, 189, 189, 189, 189, 64, 189, 64, 64, 64, 64, 64, 64, 64, 
+    192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 187, 187, 189, 189, 
+    189, 187, 64, 64, 64, 193, 193, 194, 64, 195, 195, 195, 195, 195, 195, 
+    195, 195, 195, 64, 195, 195, 195, 64, 195, 195, 195, 195, 195, 195, 195, 
+    195, 195, 195, 195, 195, 195, 195, 64, 195, 195, 195, 195, 195, 195, 195, 
+    64, 195, 195, 64, 195, 195, 195, 195, 195, 64, 64, 196, 195, 194, 194, 
+    194, 193, 193, 193, 193, 193, 64, 193, 193, 194, 64, 194, 194, 197, 64, 
+    64, 195, 64, 64, 64, 64, 64, 64, 64, 195, 195, 193, 193, 64, 64, 198, 
+    198, 198, 198, 198, 198, 198, 198, 198, 198, 199, 200, 64, 64, 64, 64, 
+    64, 64, 64, 195, 64, 64, 64, 64, 64, 64, 64, 201, 202, 202, 64, 203, 203, 
+    203, 203, 203, 203, 203, 203, 64, 64, 203, 203, 64, 64, 203, 203, 203, 
+    203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 64, 203, 203, 203, 
+    203, 203, 203, 203, 64, 203, 203, 64, 203, 203, 203, 203, 203, 64, 64, 
+    204, 203, 202, 201, 202, 201, 201, 201, 201, 64, 64, 202, 202, 64, 64, 
+    202, 202, 205, 64, 64, 64, 64, 64, 64, 64, 64, 201, 202, 64, 64, 64, 64, 
+    203, 203, 64, 203, 203, 203, 201, 201, 64, 64, 206, 206, 206, 206, 206, 
+    206, 206, 206, 206, 206, 207, 203, 208, 208, 208, 208, 208, 208, 64, 64, 
+    209, 210, 64, 210, 210, 210, 210, 210, 210, 64, 64, 64, 210, 210, 210, 
+    64, 210, 210, 210, 210, 64, 64, 64, 210, 210, 64, 210, 64, 210, 210, 64, 
+    64, 64, 210, 210, 64, 64, 64, 210, 210, 210, 210, 210, 210, 210, 210, 
+    210, 210, 64, 64, 64, 64, 211, 211, 209, 211, 211, 64, 64, 64, 211, 211, 
+    211, 64, 211, 211, 211, 212, 64, 64, 210, 64, 64, 64, 64, 64, 64, 211, 
+    64, 64, 64, 64, 64, 64, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 
+    214, 214, 214, 215, 215, 215, 215, 215, 215, 216, 215, 64, 64, 64, 64, 
+    64, 217, 218, 218, 218, 64, 219, 219, 219, 219, 219, 219, 219, 219, 64, 
+    219, 219, 219, 64, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 
+    219, 219, 219, 219, 219, 64, 64, 64, 219, 217, 217, 217, 218, 218, 218, 
+    218, 64, 217, 217, 217, 64, 217, 217, 217, 220, 64, 64, 64, 64, 64, 64, 
+    64, 221, 222, 64, 219, 219, 219, 64, 64, 64, 64, 64, 219, 219, 217, 217, 
+    64, 64, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 
+    224, 224, 224, 224, 225, 64, 226, 227, 227, 64, 228, 228, 228, 228, 228, 
+    228, 228, 228, 64, 228, 228, 228, 64, 228, 228, 228, 228, 228, 228, 228, 
+    228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 64, 228, 228, 228, 
+    228, 228, 64, 64, 229, 228, 227, 230, 227, 227, 227, 227, 227, 64, 230, 
+    227, 227, 64, 227, 227, 226, 231, 64, 64, 64, 64, 64, 64, 64, 227, 227, 
+    64, 64, 64, 64, 64, 64, 64, 228, 64, 228, 228, 226, 226, 64, 64, 232, 
+    232, 232, 232, 232, 232, 232, 232, 232, 232, 64, 228, 228, 64, 64, 64, 
+    64, 64, 64, 233, 234, 234, 64, 235, 235, 235, 235, 235, 235, 235, 235, 
+    64, 235, 235, 235, 64, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 
+    235, 235, 235, 235, 235, 235, 235, 64, 64, 235, 234, 234, 234, 233, 233, 
+    233, 233, 64, 234, 234, 234, 64, 234, 234, 234, 236, 235, 64, 64, 64, 64, 
+    64, 64, 64, 64, 234, 64, 64, 64, 64, 64, 64, 64, 235, 235, 235, 233, 233, 
+    64, 64, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 238, 238, 238, 
+    238, 238, 238, 64, 64, 64, 239, 235, 235, 235, 235, 235, 235, 64, 64, 
+    240, 240, 64, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 
+    241, 241, 241, 241, 241, 241, 64, 64, 64, 241, 241, 241, 241, 241, 241, 
+    241, 241, 64, 241, 241, 241, 241, 241, 241, 241, 241, 241, 64, 241, 64, 
+    64, 64, 64, 242, 64, 64, 64, 64, 240, 240, 240, 243, 243, 243, 64, 243, 
+    64, 240, 240, 240, 240, 240, 240, 240, 240, 64, 64, 64, 64, 64, 64, 244, 
+    244, 244, 244, 244, 244, 244, 244, 244, 244, 64, 64, 240, 240, 245, 64, 
+    64, 64, 64, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 
+    246, 246, 246, 246, 247, 246, 246, 247, 247, 247, 247, 248, 248, 249, 64, 
+    64, 64, 64, 250, 246, 246, 246, 246, 246, 246, 251, 247, 252, 252, 252, 
+    252, 247, 247, 247, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 
+    254, 253, 253, 64, 64, 64, 64, 64, 255, 255, 64, 255, 64, 64, 255, 255, 
+    64, 255, 64, 64, 255, 64, 64, 64, 64, 64, 64, 255, 255, 255, 255, 64, 
+    255, 255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 64, 255, 64, 255, 
+    64, 64, 255, 255, 64, 255, 255, 255, 255, 256, 255, 255, 256, 256, 256, 
+    256, 257, 257, 64, 256, 256, 255, 64, 64, 255, 255, 255, 255, 255, 64, 
+    258, 64, 259, 259, 259, 259, 256, 256, 64, 64, 260, 260, 260, 260, 260, 
+    260, 260, 260, 260, 260, 64, 64, 255, 255, 255, 255, 261, 262, 262, 262, 
     263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 
-    262, 263, 262, 262, 262, 264, 264, 262, 262, 262, 262, 262, 262, 265, 
-    265, 265, 265, 265, 265, 265, 265, 265, 265, 266, 266, 266, 266, 266, 
-    266, 266, 266, 266, 266, 262, 264, 262, 264, 262, 267, 268, 269, 268, 
-    269, 270, 270, 261, 261, 261, 261, 261, 261, 261, 261, 64, 261, 261, 261, 
-    261, 261, 261, 261, 261, 261, 261, 261, 261, 64, 64, 64, 64, 271, 272, 
-    273, 274, 273, 273, 273, 273, 273, 272, 272, 272, 272, 273, 270, 272, 
-    273, 275, 275, 276, 263, 275, 275, 261, 261, 261, 261, 261, 273, 273, 
-    273, 273, 273, 273, 273, 273, 273, 273, 273, 64, 273, 273, 273, 273, 273, 
-    273, 273, 273, 273, 273, 273, 273, 64, 262, 262, 262, 262, 262, 262, 262, 
-    262, 264, 262, 262, 262, 262, 262, 262, 64, 262, 262, 263, 263, 263, 263, 
-    263, 277, 277, 277, 277, 263, 263, 64, 64, 64, 64, 64, 278, 278, 278, 
-    278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 280, 280, 280, 280, 
-    279, 280, 280, 280, 280, 280, 281, 279, 282, 282, 279, 279, 280, 280, 
-    278, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 284, 284, 
-    284, 284, 284, 278, 278, 278, 278, 278, 278, 279, 279, 280, 280, 278, 
-    278, 278, 278, 280, 280, 280, 278, 279, 279, 279, 278, 278, 279, 279, 
-    279, 279, 279, 279, 279, 278, 278, 278, 280, 280, 280, 280, 278, 278, 
-    278, 278, 278, 280, 279, 279, 280, 280, 279, 279, 279, 279, 279, 279, 
-    285, 278, 279, 283, 283, 279, 279, 279, 280, 286, 286, 287, 287, 287, 
-    287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 64, 287, 64, 64, 
-    64, 64, 64, 287, 64, 64, 288, 288, 288, 288, 288, 288, 288, 288, 288, 
+    263, 262, 263, 262, 262, 262, 264, 264, 262, 262, 262, 262, 262, 262, 
+    265, 265, 265, 265, 265, 265, 265, 265, 265, 265, 266, 266, 266, 266, 
+    266, 266, 266, 266, 266, 266, 262, 264, 262, 264, 262, 267, 268, 269, 
+    268, 269, 270, 270, 261, 261, 261, 261, 261, 261, 261, 261, 64, 261, 261, 
+    261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 64, 64, 64, 64, 271, 
+    272, 273, 274, 273, 273, 273, 273, 273, 272, 272, 272, 272, 273, 270, 
+    272, 273, 275, 275, 276, 263, 275, 275, 261, 261, 261, 261, 261, 273, 
+    273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 64, 273, 273, 273, 273, 
+    273, 273, 273, 273, 273, 273, 273, 273, 64, 262, 262, 262, 262, 262, 262, 
+    262, 262, 264, 262, 262, 262, 262, 262, 262, 64, 262, 262, 263, 263, 263, 
+    263, 263, 277, 277, 277, 277, 263, 263, 64, 64, 64, 64, 64, 278, 278, 
+    278, 278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 280, 280, 280, 
+    280, 279, 280, 280, 280, 280, 280, 281, 279, 282, 282, 279, 279, 280, 
+    280, 278, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 284, 
+    284, 284, 284, 284, 278, 278, 278, 278, 278, 278, 279, 279, 280, 280, 
+    278, 278, 278, 278, 280, 280, 280, 278, 279, 279, 279, 278, 278, 279, 
+    279, 279, 279, 279, 279, 279, 278, 278, 278, 280, 280, 280, 280, 278, 
+    278, 278, 278, 278, 280, 279, 279, 280, 280, 279, 279, 279, 279, 279, 
+    279, 285, 278, 279, 283, 283, 279, 279, 279, 280, 286, 286, 287, 287, 
+    287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 64, 287, 64, 
+    64, 64, 64, 64, 287, 64, 64, 288, 288, 288, 288, 288, 288, 288, 288, 288, 
     288, 288, 84, 289, 288, 288, 288, 290, 290, 290, 290, 290, 290, 290, 290, 
     291, 291, 291, 291, 291, 291, 291, 291, 292, 292, 292, 292, 292, 292, 
     292, 292, 292, 64, 292, 292, 292, 292, 64, 64, 292, 292, 292, 292, 292, 
@@ -2399,166 +2427,166 @@
     294, 294, 294, 294, 294, 295, 295, 295, 295, 295, 295, 295, 295, 295, 
     295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 64, 64, 64, 296, 
     296, 296, 296, 296, 296, 296, 296, 296, 296, 64, 64, 64, 64, 64, 64, 297, 
-    297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 64, 64, 64, 
-    298, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 
-    299, 299, 299, 299, 299, 299, 299, 300, 300, 299, 301, 302, 302, 302, 
-    302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 
-    302, 303, 304, 64, 64, 64, 305, 305, 305, 305, 305, 305, 305, 305, 305, 
-    305, 305, 84, 84, 84, 306, 306, 306, 305, 305, 305, 305, 305, 305, 305, 
-    305, 64, 64, 64, 64, 64, 64, 64, 307, 307, 307, 307, 307, 307, 307, 307, 
-    307, 307, 307, 307, 307, 64, 307, 307, 307, 307, 308, 308, 309, 64, 64, 
-    64, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 311, 311, 312, 84, 
-    84, 64, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 314, 314, 64, 
-    64, 64, 64, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 
-    315, 64, 315, 315, 315, 64, 316, 316, 64, 64, 64, 64, 317, 317, 317, 317, 
-    317, 317, 317, 317, 317, 317, 317, 317, 318, 318, 319, 318, 318, 318, 
-    318, 318, 318, 318, 319, 319, 319, 319, 319, 319, 319, 319, 318, 319, 
-    319, 318, 318, 318, 318, 318, 318, 318, 318, 318, 320, 318, 321, 321, 
-    321, 322, 321, 321, 321, 323, 317, 324, 64, 64, 325, 325, 325, 325, 325, 
-    325, 325, 325, 325, 325, 64, 64, 64, 64, 64, 64, 326, 326, 326, 326, 326, 
-    326, 326, 326, 326, 326, 64, 64, 64, 64, 64, 64, 327, 327, 66, 66, 327, 
-    66, 328, 327, 327, 327, 327, 329, 329, 329, 330, 64, 331, 331, 331, 331, 
-    331, 331, 331, 331, 331, 331, 64, 64, 64, 64, 64, 64, 332, 332, 332, 332, 
-    332, 332, 332, 332, 332, 332, 332, 333, 332, 332, 332, 332, 332, 334, 
-    332, 64, 64, 64, 64, 64, 299, 299, 299, 299, 299, 299, 64, 64, 335, 335, 
-    335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 64, 336, 
-    336, 336, 337, 337, 337, 337, 336, 336, 337, 337, 337, 64, 64, 64, 64, 
-    337, 337, 336, 337, 337, 337, 337, 337, 337, 338, 339, 340, 64, 64, 64, 
-    64, 341, 64, 64, 64, 342, 342, 343, 343, 343, 343, 343, 343, 343, 343, 
-    343, 343, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 
-    344, 344, 64, 64, 344, 344, 344, 344, 344, 64, 64, 64, 345, 345, 345, 
-    345, 345, 345, 345, 345, 345, 345, 345, 345, 64, 64, 64, 64, 346, 346, 
-    346, 346, 346, 346, 346, 346, 346, 345, 345, 345, 345, 345, 345, 345, 
-    346, 346, 64, 64, 64, 64, 64, 64, 347, 347, 347, 347, 347, 347, 347, 347, 
-    347, 347, 348, 64, 64, 64, 349, 349, 350, 350, 350, 350, 350, 350, 350, 
-    350, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 
-    351, 351, 352, 353, 354, 354, 355, 64, 64, 356, 356, 357, 357, 357, 357, 
-    357, 357, 357, 357, 357, 357, 357, 357, 357, 358, 359, 358, 359, 359, 
-    359, 359, 359, 359, 359, 64, 360, 358, 359, 358, 358, 359, 359, 359, 359, 
-    359, 359, 359, 359, 358, 358, 358, 358, 358, 358, 359, 359, 361, 361, 
-    361, 361, 361, 361, 361, 361, 64, 64, 362, 363, 363, 363, 363, 363, 363, 
-    363, 363, 363, 363, 64, 64, 64, 64, 64, 64, 364, 364, 364, 364, 364, 364, 
-    364, 365, 364, 364, 364, 364, 364, 364, 64, 64, 78, 78, 78, 78, 78, 136, 
-    136, 136, 136, 136, 136, 78, 78, 136, 366, 64, 367, 367, 367, 367, 368, 
-    369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 
-    369, 370, 368, 367, 367, 367, 367, 367, 368, 367, 368, 368, 368, 368, 
-    368, 367, 368, 371, 369, 369, 369, 369, 369, 369, 369, 64, 64, 64, 64, 
-    372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 373, 373, 373, 373, 
-    373, 373, 373, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 375, 
-    376, 375, 375, 375, 375, 375, 375, 375, 374, 374, 374, 374, 374, 374, 
-    374, 374, 374, 64, 64, 64, 377, 377, 378, 379, 379, 379, 379, 379, 379, 
-    379, 379, 379, 379, 379, 379, 379, 379, 378, 377, 377, 377, 377, 378, 
-    378, 377, 377, 380, 381, 377, 377, 379, 379, 382, 382, 382, 382, 382, 
-    382, 382, 382, 382, 382, 379, 379, 379, 379, 379, 379, 383, 383, 383, 
-    383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384, 385, 386, 
-    386, 385, 385, 385, 386, 385, 386, 386, 386, 387, 387, 64, 64, 64, 64, 
-    64, 64, 64, 64, 388, 388, 388, 388, 389, 389, 389, 389, 389, 389, 389, 
-    389, 389, 389, 389, 389, 390, 390, 390, 390, 390, 390, 390, 390, 391, 
-    391, 391, 391, 391, 391, 391, 391, 390, 390, 391, 392, 64, 64, 64, 393, 
-    393, 393, 393, 393, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 64, 
-    64, 64, 389, 389, 389, 395, 395, 395, 395, 395, 395, 395, 395, 395, 395, 
-    396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 
-    397, 397, 397, 397, 397, 397, 398, 398, 399, 399, 399, 399, 399, 399, 
-    399, 399, 78, 78, 78, 84, 400, 136, 136, 136, 136, 136, 78, 78, 136, 136, 
-    136, 136, 78, 401, 400, 400, 400, 400, 400, 400, 400, 402, 402, 402, 402, 
-    136, 402, 402, 402, 402, 401, 401, 78, 402, 402, 64, 78, 78, 64, 64, 64, 
-    64, 64, 64, 41, 41, 41, 41, 41, 41, 62, 62, 62, 62, 62, 75, 44, 44, 44, 
-    44, 44, 44, 44, 44, 44, 65, 65, 65, 65, 65, 44, 44, 44, 44, 65, 65, 65, 
-    65, 65, 41, 41, 41, 41, 41, 403, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 
-    44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 65, 78, 78, 136, 78, 78, 
-    78, 78, 78, 78, 78, 136, 78, 78, 404, 405, 136, 406, 78, 78, 78, 78, 78, 
-    78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 64, 64, 
-    64, 64, 64, 64, 407, 136, 78, 136, 37, 41, 37, 41, 37, 41, 41, 41, 41, 
-    41, 41, 41, 41, 41, 37, 41, 62, 62, 62, 62, 62, 62, 62, 62, 61, 61, 61, 
-    61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 64, 64, 61, 61, 61, 61, 61, 
-    61, 64, 64, 64, 61, 64, 61, 64, 61, 64, 61, 408, 408, 408, 408, 408, 408, 
-    408, 408, 62, 62, 62, 62, 62, 64, 62, 62, 61, 61, 61, 61, 408, 63, 62, 
-    63, 63, 63, 62, 62, 62, 64, 62, 62, 61, 61, 61, 61, 408, 63, 63, 63, 62, 
-    62, 62, 62, 64, 64, 62, 62, 61, 61, 61, 61, 64, 63, 63, 63, 61, 61, 61, 
-    61, 61, 63, 63, 63, 64, 64, 62, 62, 62, 64, 62, 62, 61, 61, 61, 61, 408, 
-    63, 63, 64, 409, 409, 409, 409, 409, 409, 409, 409, 409, 409, 409, 410, 
-    411, 411, 412, 413, 414, 415, 415, 414, 414, 414, 22, 66, 416, 417, 418, 
-    419, 416, 417, 418, 419, 22, 22, 22, 66, 22, 22, 22, 22, 420, 421, 422, 
-    423, 424, 425, 426, 21, 427, 428, 427, 427, 428, 22, 66, 66, 66, 28, 35, 
-    22, 66, 66, 22, 429, 429, 66, 66, 66, 430, 431, 432, 66, 66, 66, 66, 66, 
-    66, 66, 66, 66, 66, 66, 433, 66, 429, 66, 66, 66, 66, 66, 66, 66, 66, 66, 
-    66, 409, 410, 410, 410, 410, 410, 64, 434, 435, 436, 437, 410, 410, 410, 
-    410, 410, 410, 438, 44, 64, 64, 33, 438, 438, 438, 438, 438, 439, 439, 
-    433, 431, 432, 440, 438, 33, 33, 33, 33, 438, 438, 438, 438, 438, 439, 
-    439, 433, 431, 432, 64, 44, 44, 44, 44, 44, 64, 64, 64, 250, 250, 250, 
-    250, 250, 250, 250, 250, 250, 441, 250, 250, 23, 250, 250, 250, 250, 250, 
-    250, 250, 250, 250, 64, 64, 78, 78, 400, 400, 78, 78, 78, 78, 400, 400, 
-    400, 78, 78, 366, 366, 366, 366, 78, 366, 366, 366, 400, 400, 78, 136, 
-    78, 400, 400, 136, 136, 136, 136, 78, 64, 64, 64, 64, 64, 64, 64, 26, 26, 
-    442, 30, 26, 30, 26, 442, 26, 30, 34, 442, 442, 442, 34, 34, 442, 442, 
-    442, 443, 26, 442, 30, 26, 433, 442, 442, 442, 442, 442, 26, 26, 26, 30, 
-    30, 26, 442, 26, 67, 26, 442, 26, 37, 38, 442, 442, 444, 34, 442, 442, 
-    37, 442, 34, 402, 402, 402, 402, 34, 26, 26, 34, 34, 442, 442, 445, 433, 
-    433, 433, 433, 442, 34, 34, 34, 34, 26, 433, 26, 26, 41, 277, 446, 446, 
-    446, 36, 36, 446, 446, 446, 446, 446, 446, 36, 36, 36, 36, 446, 447, 447, 
-    447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 448, 448, 448, 448, 
-    447, 447, 448, 448, 448, 448, 448, 448, 448, 448, 448, 37, 41, 448, 448, 
-    448, 448, 36, 64, 64, 64, 64, 64, 64, 39, 39, 39, 39, 39, 30, 30, 30, 30, 
-    30, 433, 433, 26, 26, 26, 26, 433, 26, 26, 433, 26, 26, 433, 26, 26, 26, 
-    26, 26, 26, 26, 433, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 26, 26, 
-    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 433, 433, 26, 26, 39, 26, 39, 26, 
-    26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, 26, 26, 433, 433, 433, 
-    433, 433, 433, 433, 433, 433, 433, 433, 433, 39, 445, 449, 449, 445, 433, 
-    433, 39, 449, 445, 445, 449, 445, 445, 433, 39, 433, 449, 439, 450, 433, 
-    449, 445, 433, 433, 433, 449, 445, 445, 449, 39, 449, 449, 445, 445, 39, 
-    445, 39, 445, 39, 39, 39, 39, 449, 449, 445, 449, 445, 445, 445, 445, 
-    445, 39, 39, 39, 39, 433, 445, 433, 445, 449, 449, 445, 445, 445, 445, 
-    445, 445, 445, 445, 445, 445, 449, 445, 445, 445, 449, 433, 433, 433, 
-    433, 433, 449, 445, 445, 445, 433, 433, 433, 433, 433, 433, 433, 433, 
-    433, 445, 449, 39, 445, 433, 449, 449, 449, 449, 445, 445, 449, 449, 433, 
-    433, 449, 449, 445, 445, 449, 449, 445, 445, 449, 449, 445, 445, 445, 
-    445, 445, 433, 433, 445, 445, 445, 445, 433, 433, 39, 433, 433, 445, 39, 
-    433, 433, 433, 433, 433, 433, 433, 433, 445, 445, 433, 39, 445, 445, 445, 
-    433, 433, 433, 433, 433, 445, 449, 433, 445, 445, 445, 445, 445, 433, 
+    297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 64, 64, 
+    298, 298, 298, 298, 298, 298, 64, 64, 299, 300, 300, 300, 300, 300, 300, 
+    300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 
+    301, 301, 300, 302, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 
+    303, 303, 303, 303, 303, 303, 303, 303, 304, 305, 64, 64, 64, 306, 306, 
+    306, 306, 306, 306, 306, 306, 306, 306, 306, 84, 84, 84, 307, 307, 307, 
+    306, 306, 306, 306, 306, 306, 306, 306, 64, 64, 64, 64, 64, 64, 64, 308, 
+    308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 64, 308, 308, 
+    308, 308, 309, 309, 310, 64, 64, 64, 311, 311, 311, 311, 311, 311, 311, 
+    311, 311, 311, 312, 312, 313, 84, 84, 64, 314, 314, 314, 314, 314, 314, 
+    314, 314, 314, 314, 315, 315, 64, 64, 64, 64, 316, 316, 316, 316, 316, 
+    316, 316, 316, 316, 316, 316, 316, 316, 64, 316, 316, 316, 64, 317, 317, 
+    64, 64, 64, 64, 318, 318, 318, 318, 318, 318, 318, 318, 318, 318, 318, 
+    318, 319, 319, 320, 319, 319, 319, 319, 319, 319, 319, 320, 320, 320, 
+    320, 320, 320, 320, 320, 319, 320, 320, 319, 319, 319, 319, 319, 319, 
+    319, 319, 319, 321, 319, 322, 322, 322, 323, 322, 322, 322, 324, 318, 
+    325, 64, 64, 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, 64, 64, 
+    64, 64, 64, 64, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 64, 64, 
+    64, 64, 64, 64, 328, 328, 66, 66, 328, 66, 329, 328, 328, 328, 328, 330, 
+    330, 330, 331, 64, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 64, 
+    64, 64, 64, 64, 64, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 
+    333, 334, 333, 333, 333, 333, 333, 335, 333, 64, 64, 64, 64, 64, 300, 
+    300, 300, 300, 300, 300, 64, 64, 336, 336, 336, 336, 336, 336, 336, 336, 
+    336, 336, 336, 336, 336, 336, 336, 64, 337, 337, 337, 338, 338, 338, 338, 
+    337, 337, 338, 338, 338, 64, 64, 64, 64, 338, 338, 337, 338, 338, 338, 
+    338, 338, 338, 339, 340, 341, 64, 64, 64, 64, 342, 64, 64, 64, 343, 343, 
+    344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 345, 345, 345, 345, 
+    345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 64, 64, 345, 345, 345, 
+    345, 345, 64, 64, 64, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 
+    346, 346, 64, 64, 64, 64, 346, 346, 64, 64, 64, 64, 64, 64, 347, 347, 
+    347, 347, 347, 347, 347, 347, 347, 347, 348, 64, 64, 64, 349, 349, 350, 
+    350, 350, 350, 350, 350, 350, 350, 351, 351, 351, 351, 351, 351, 351, 
+    351, 351, 351, 351, 351, 351, 351, 351, 352, 353, 354, 354, 355, 64, 64, 
+    356, 356, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 
+    357, 358, 359, 358, 359, 359, 359, 359, 359, 359, 359, 64, 360, 358, 359, 
+    358, 358, 359, 359, 359, 359, 359, 359, 359, 359, 358, 358, 358, 358, 
+    358, 358, 359, 359, 361, 361, 361, 361, 361, 361, 361, 361, 64, 64, 362, 
+    363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 64, 64, 64, 64, 64, 64, 
+    364, 364, 364, 364, 364, 364, 364, 365, 364, 364, 364, 364, 364, 364, 64, 
+    64, 78, 78, 78, 78, 78, 136, 136, 136, 136, 136, 136, 78, 78, 136, 366, 
+    64, 367, 367, 367, 367, 368, 369, 369, 369, 369, 369, 369, 369, 369, 369, 
+    369, 369, 369, 369, 369, 369, 370, 368, 367, 367, 367, 367, 367, 368, 
+    367, 368, 368, 368, 368, 368, 367, 368, 371, 369, 369, 369, 369, 369, 
+    369, 369, 64, 64, 64, 64, 372, 372, 372, 372, 372, 372, 372, 372, 372, 
+    372, 373, 373, 373, 373, 373, 373, 373, 374, 374, 374, 374, 374, 374, 
+    374, 374, 374, 374, 375, 376, 375, 375, 375, 375, 375, 375, 375, 374, 
+    374, 374, 374, 374, 374, 374, 374, 374, 64, 64, 64, 377, 377, 378, 379, 
+    379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 378, 
+    377, 377, 377, 377, 378, 378, 377, 377, 380, 381, 377, 377, 379, 379, 
+    382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 379, 379, 379, 379, 
+    379, 379, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 
+    383, 383, 384, 385, 386, 386, 385, 385, 385, 386, 385, 386, 386, 386, 
+    387, 387, 64, 64, 64, 64, 64, 64, 64, 64, 388, 388, 388, 388, 389, 389, 
+    389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 390, 390, 390, 390, 
+    390, 390, 390, 390, 391, 391, 391, 391, 391, 391, 391, 391, 390, 390, 
+    391, 392, 64, 64, 64, 393, 393, 393, 393, 393, 394, 394, 394, 394, 394, 
+    394, 394, 394, 394, 394, 64, 64, 64, 389, 389, 389, 395, 395, 395, 395, 
+    395, 395, 395, 395, 395, 395, 396, 396, 396, 396, 396, 396, 396, 396, 
+    396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397, 398, 398, 
+    399, 399, 399, 399, 399, 399, 399, 399, 78, 78, 78, 84, 400, 136, 136, 
+    136, 136, 136, 78, 78, 136, 136, 136, 136, 78, 401, 400, 400, 400, 400, 
+    400, 400, 400, 402, 402, 402, 402, 136, 402, 402, 402, 402, 401, 401, 78, 
+    402, 402, 64, 78, 78, 64, 64, 64, 64, 64, 64, 41, 41, 41, 41, 41, 41, 62, 
+    62, 62, 62, 62, 75, 44, 44, 44, 44, 44, 44, 44, 44, 44, 65, 65, 65, 65, 
+    65, 44, 44, 44, 44, 65, 65, 65, 65, 65, 41, 41, 41, 41, 41, 403, 41, 41, 
+    41, 41, 41, 41, 41, 41, 41, 41, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 
+    44, 44, 65, 78, 78, 136, 78, 78, 78, 78, 78, 78, 78, 136, 78, 78, 404, 
+    405, 136, 406, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 
+    78, 78, 78, 78, 78, 78, 78, 64, 64, 64, 64, 64, 64, 407, 136, 78, 136, 
+    37, 41, 37, 41, 37, 41, 41, 41, 41, 41, 41, 41, 41, 41, 37, 41, 62, 62, 
+    62, 62, 62, 62, 62, 62, 61, 61, 61, 61, 61, 61, 61, 61, 62, 62, 62, 62, 
+    62, 62, 64, 64, 61, 61, 61, 61, 61, 61, 64, 64, 64, 61, 64, 61, 64, 61, 
+    64, 61, 408, 408, 408, 408, 408, 408, 408, 408, 62, 62, 62, 62, 62, 64, 
+    62, 62, 61, 61, 61, 61, 408, 63, 62, 63, 63, 63, 62, 62, 62, 64, 62, 62, 
+    61, 61, 61, 61, 408, 63, 63, 63, 62, 62, 62, 62, 64, 64, 62, 62, 61, 61, 
+    61, 61, 64, 63, 63, 63, 61, 61, 61, 61, 61, 63, 63, 63, 64, 64, 62, 62, 
+    62, 64, 62, 62, 61, 61, 61, 61, 408, 63, 63, 64, 409, 409, 409, 409, 409, 
+    409, 409, 409, 409, 409, 409, 410, 411, 411, 412, 413, 414, 415, 415, 
+    414, 414, 414, 22, 66, 416, 417, 418, 419, 416, 417, 418, 419, 22, 22, 
+    22, 66, 22, 22, 22, 22, 420, 421, 422, 423, 424, 425, 426, 21, 427, 428, 
+    427, 427, 428, 22, 66, 66, 66, 28, 35, 22, 66, 66, 22, 429, 429, 66, 66, 
+    66, 430, 431, 432, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 433, 66, 
+    429, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 409, 410, 410, 410, 410, 
+    410, 64, 434, 435, 436, 437, 410, 410, 410, 410, 410, 410, 438, 44, 64, 
+    64, 33, 438, 438, 438, 438, 438, 439, 439, 433, 431, 432, 440, 438, 33, 
+    33, 33, 33, 438, 438, 438, 438, 438, 439, 439, 433, 431, 432, 64, 44, 44, 
+    44, 44, 44, 64, 64, 64, 250, 250, 250, 250, 250, 250, 250, 250, 250, 441, 
+    250, 250, 23, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 64, 78, 
+    78, 400, 400, 78, 78, 78, 78, 400, 400, 400, 78, 78, 366, 366, 366, 366, 
+    78, 366, 366, 366, 400, 400, 78, 136, 78, 400, 400, 136, 136, 136, 136, 
+    78, 64, 64, 64, 64, 64, 64, 64, 26, 26, 442, 30, 26, 30, 26, 442, 26, 30, 
+    34, 442, 442, 442, 34, 34, 442, 442, 442, 443, 26, 442, 30, 26, 433, 442, 
+    442, 442, 442, 442, 26, 26, 26, 30, 30, 26, 442, 26, 67, 26, 442, 26, 37, 
+    38, 442, 442, 444, 34, 442, 442, 37, 442, 34, 402, 402, 402, 402, 34, 26, 
+    26, 34, 34, 442, 442, 445, 433, 433, 433, 433, 442, 34, 34, 34, 34, 26, 
+    433, 26, 26, 41, 277, 446, 446, 446, 36, 36, 446, 446, 446, 446, 446, 
+    446, 36, 36, 36, 36, 446, 447, 447, 447, 447, 447, 447, 447, 447, 447, 
+    447, 447, 447, 448, 448, 448, 448, 447, 447, 448, 448, 448, 448, 448, 
+    448, 448, 448, 448, 37, 41, 448, 448, 448, 448, 36, 26, 26, 64, 64, 64, 
+    64, 39, 39, 39, 39, 39, 30, 30, 30, 30, 30, 433, 433, 26, 26, 26, 26, 
+    433, 26, 26, 433, 26, 26, 433, 26, 26, 26, 26, 26, 26, 26, 433, 26, 26, 
+    26, 26, 26, 26, 26, 26, 26, 30, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 
+    26, 26, 26, 433, 433, 26, 26, 39, 26, 39, 26, 26, 26, 26, 26, 26, 26, 26, 
+    26, 26, 30, 26, 26, 26, 26, 433, 433, 433, 433, 433, 433, 433, 433, 433, 
+    433, 433, 433, 39, 445, 449, 449, 445, 433, 433, 39, 449, 445, 445, 449, 
+    445, 445, 433, 39, 433, 449, 439, 450, 433, 449, 445, 433, 433, 433, 449, 
+    445, 445, 449, 39, 449, 449, 445, 445, 39, 445, 39, 445, 39, 39, 39, 39, 
+    449, 449, 445, 449, 445, 445, 445, 445, 445, 39, 39, 39, 39, 433, 445, 
+    433, 445, 449, 449, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 
+    449, 445, 445, 445, 449, 433, 433, 433, 433, 433, 449, 445, 445, 445, 
+    433, 433, 433, 433, 433, 433, 433, 433, 433, 445, 449, 39, 445, 433, 449, 
+    449, 449, 449, 445, 445, 449, 449, 433, 433, 449, 449, 445, 445, 449, 
+    449, 445, 445, 449, 449, 445, 445, 445, 445, 445, 433, 433, 445, 445, 
+    445, 445, 433, 433, 39, 433, 433, 445, 39, 433, 433, 433, 433, 433, 433, 
+    433, 433, 445, 445, 433, 39, 445, 445, 445, 433, 433, 433, 433, 433, 445, 
+    449, 433, 445, 445, 445, 445, 445, 433, 433, 445, 445, 433, 433, 433, 
+    433, 445, 445, 445, 445, 445, 445, 445, 445, 433, 433, 431, 432, 431, 
+    432, 26, 26, 26, 26, 26, 26, 30, 26, 26, 26, 26, 26, 445, 445, 26, 26, 
+    26, 26, 26, 26, 26, 451, 452, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 
+    277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 433, 
+    26, 26, 26, 26, 26, 26, 26, 26, 277, 26, 26, 26, 26, 26, 433, 433, 433, 
+    433, 433, 433, 433, 433, 433, 26, 26, 26, 26, 433, 433, 26, 26, 26, 26, 
+    26, 26, 26, 26, 26, 64, 64, 64, 64, 64, 26, 26, 26, 26, 26, 26, 26, 64, 
+    36, 36, 36, 36, 36, 36, 36, 36, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 
+    33, 33, 453, 453, 453, 453, 453, 453, 453, 453, 453, 453, 453, 453, 453, 
+    453, 446, 36, 36, 36, 36, 36, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 
+    30, 26, 26, 26, 26, 26, 26, 30, 30, 30, 30, 26, 26, 30, 30, 26, 30, 30, 
+    30, 30, 30, 26, 26, 30, 30, 26, 26, 30, 39, 26, 26, 26, 26, 30, 30, 26, 
+    26, 30, 39, 26, 26, 26, 26, 30, 30, 30, 26, 26, 30, 26, 26, 30, 30, 26, 
+    26, 26, 26, 26, 30, 30, 26, 26, 30, 26, 26, 26, 26, 30, 30, 26, 26, 26, 
+    26, 30, 26, 30, 26, 30, 26, 30, 26, 26, 26, 26, 26, 30, 30, 26, 30, 30, 
+    30, 26, 30, 30, 30, 30, 26, 30, 30, 26, 39, 26, 26, 26, 26, 26, 26, 30, 
+    30, 26, 26, 26, 26, 277, 26, 26, 26, 26, 26, 26, 26, 30, 30, 30, 30, 30, 
+    30, 30, 30, 30, 30, 26, 30, 30, 30, 26, 30, 26, 26, 26, 26, 26, 26, 26, 
+    26, 26, 30, 26, 26, 431, 432, 431, 432, 431, 432, 431, 432, 431, 432, 
+    431, 432, 431, 432, 36, 36, 446, 446, 446, 446, 446, 446, 446, 446, 446, 
+    446, 446, 446, 26, 26, 26, 26, 445, 433, 433, 445, 445, 431, 432, 433, 
+    445, 445, 433, 445, 445, 445, 433, 433, 433, 433, 433, 445, 445, 445, 
+    445, 433, 433, 433, 433, 433, 445, 445, 445, 433, 433, 433, 445, 445, 
+    445, 445, 9, 10, 9, 10, 9, 10, 9, 10, 431, 432, 454, 454, 454, 454, 454, 
+    454, 454, 454, 433, 433, 433, 431, 432, 9, 10, 431, 432, 431, 432, 431, 
+    432, 431, 432, 431, 432, 433, 433, 445, 445, 445, 445, 445, 445, 433, 
+    433, 433, 433, 433, 433, 433, 433, 445, 433, 433, 433, 433, 445, 445, 
+    445, 445, 445, 433, 445, 445, 433, 433, 431, 432, 431, 432, 445, 433, 
+    433, 433, 433, 445, 433, 445, 445, 445, 433, 433, 445, 445, 433, 433, 
+    433, 433, 433, 433, 433, 433, 433, 433, 445, 445, 445, 445, 445, 445, 
+    433, 433, 431, 432, 433, 433, 433, 433, 445, 445, 445, 445, 445, 445, 
+    445, 445, 445, 445, 445, 433, 445, 445, 445, 445, 433, 433, 445, 433, 
+    445, 433, 433, 445, 433, 445, 445, 445, 445, 433, 433, 433, 433, 433, 
+    445, 445, 433, 433, 433, 433, 445, 445, 445, 445, 433, 445, 445, 433, 
     433, 445, 445, 433, 433, 433, 433, 445, 445, 445, 445, 445, 445, 445, 
-    445, 433, 433, 431, 432, 431, 432, 26, 26, 26, 26, 26, 26, 30, 26, 26, 
-    26, 26, 26, 445, 445, 26, 26, 26, 26, 26, 26, 26, 451, 452, 26, 26, 26, 
-    26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, 
-    277, 277, 277, 277, 277, 26, 433, 26, 26, 26, 26, 26, 26, 26, 26, 277, 
-    26, 26, 26, 26, 26, 433, 433, 433, 433, 433, 433, 433, 433, 433, 26, 26, 
-    26, 26, 433, 433, 26, 26, 26, 26, 26, 26, 26, 26, 26, 64, 64, 64, 64, 64, 
-    26, 26, 26, 26, 26, 26, 26, 64, 36, 36, 36, 36, 36, 36, 36, 36, 33, 33, 
-    33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 453, 453, 453, 453, 453, 453, 
-    453, 453, 453, 453, 453, 453, 453, 453, 446, 36, 36, 36, 36, 36, 30, 30, 
-    30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 26, 26, 26, 26, 26, 30, 30, 
-    30, 30, 26, 26, 30, 30, 26, 30, 30, 30, 30, 30, 26, 26, 30, 30, 26, 26, 
-    30, 39, 26, 26, 26, 26, 30, 30, 26, 26, 30, 39, 26, 26, 26, 26, 30, 30, 
-    30, 26, 26, 30, 26, 26, 30, 30, 26, 26, 26, 26, 26, 30, 30, 26, 26, 30, 
-    26, 26, 26, 26, 30, 30, 26, 26, 26, 26, 30, 26, 30, 26, 30, 26, 30, 26, 
-    26, 26, 26, 26, 30, 30, 26, 30, 30, 30, 26, 30, 30, 30, 30, 26, 30, 30, 
-    26, 39, 26, 26, 26, 26, 26, 26, 30, 30, 26, 26, 26, 26, 277, 26, 26, 26, 
-    26, 26, 26, 26, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 30, 30, 30, 
-    26, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, 431, 432, 431, 
-    432, 431, 432, 431, 432, 431, 432, 431, 432, 431, 432, 36, 36, 446, 446, 
-    446, 446, 446, 446, 446, 446, 446, 446, 446, 446, 26, 26, 26, 26, 445, 
-    433, 433, 445, 445, 431, 432, 433, 445, 445, 433, 445, 445, 445, 433, 
-    433, 433, 433, 433, 445, 445, 445, 445, 433, 433, 433, 433, 433, 445, 
-    445, 445, 433, 433, 433, 445, 445, 445, 445, 9, 10, 9, 10, 9, 10, 9, 10, 
-    431, 432, 454, 454, 454, 454, 454, 454, 454, 454, 433, 433, 433, 431, 
-    432, 9, 10, 431, 432, 431, 432, 431, 432, 431, 432, 431, 432, 433, 433, 
-    445, 445, 445, 445, 445, 445, 433, 433, 433, 433, 433, 433, 433, 433, 
-    445, 433, 433, 433, 433, 445, 445, 445, 445, 445, 433, 445, 445, 433, 
-    433, 431, 432, 431, 432, 445, 433, 433, 433, 433, 445, 433, 445, 445, 
-    445, 433, 433, 445, 445, 433, 433, 433, 433, 433, 433, 433, 433, 433, 
-    433, 445, 445, 445, 445, 445, 445, 433, 433, 431, 432, 433, 433, 433, 
-    433, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 433, 445, 
-    445, 445, 445, 433, 433, 445, 433, 445, 433, 433, 445, 433, 445, 445, 
-    445, 445, 433, 433, 433, 433, 433, 445, 445, 433, 433, 433, 433, 445, 
-    445, 445, 445, 433, 445, 445, 433, 433, 445, 445, 433, 433, 433, 433, 
-    445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 433, 433, 445, 
-    445, 445, 445, 445, 445, 445, 445, 433, 445, 445, 445, 445, 445, 445, 
-    445, 445, 433, 433, 433, 433, 433, 445, 433, 445, 433, 433, 433, 445, 
-    445, 445, 445, 445, 433, 433, 433, 433, 445, 433, 433, 433, 445, 445, 
-    445, 445, 445, 433, 445, 433, 433, 433, 433, 433, 433, 433, 26, 26, 433, 
-    433, 433, 433, 433, 433, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 30, 26, 
-    26, 26, 26, 64, 64, 26, 26, 26, 26, 26, 26, 26, 26, 64, 64, 26, 26, 64, 
-    64, 64, 26, 26, 26, 26, 64, 26, 26, 26, 26, 26, 26, 26, 26, 64, 64, 64, 
-    64, 64, 64, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 
+    445, 445, 445, 445, 433, 433, 445, 445, 445, 445, 445, 445, 445, 445, 
+    433, 445, 445, 445, 445, 445, 445, 445, 445, 433, 433, 433, 433, 433, 
+    445, 433, 445, 433, 433, 433, 445, 445, 445, 445, 445, 433, 433, 433, 
+    433, 445, 433, 433, 433, 445, 445, 445, 445, 445, 433, 445, 433, 433, 
+    433, 433, 433, 433, 433, 26, 26, 433, 433, 433, 433, 433, 433, 26, 26, 
+    26, 26, 26, 26, 26, 26, 30, 30, 30, 26, 26, 26, 26, 64, 64, 26, 26, 26, 
+    26, 26, 26, 26, 26, 64, 64, 26, 26, 64, 64, 64, 26, 26, 26, 26, 64, 26, 
+    26, 26, 26, 26, 26, 26, 26, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 26, 
+    26, 26, 26, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 
     455, 455, 455, 64, 456, 456, 456, 456, 456, 456, 456, 456, 456, 456, 456, 
     456, 456, 456, 456, 64, 37, 41, 37, 37, 37, 41, 41, 37, 41, 37, 41, 37, 
     41, 37, 37, 37, 37, 41, 37, 41, 41, 37, 41, 41, 41, 41, 41, 41, 44, 44, 
@@ -2596,263 +2624,280 @@
     467, 467, 467, 467, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 
     495, 495, 495, 495, 495, 64, 489, 489, 489, 489, 489, 489, 489, 467, 467, 
     467, 467, 489, 489, 489, 489, 489, 489, 489, 489, 489, 489, 489, 467, 
-    467, 496, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497, 
-    497, 497, 497, 497, 497, 497, 497, 497, 496, 498, 498, 498, 498, 498, 
-    498, 498, 498, 498, 498, 497, 497, 497, 497, 496, 498, 498, 498, 499, 
-    499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 500, 499, 
-    499, 499, 499, 499, 499, 499, 64, 64, 64, 501, 501, 501, 501, 501, 501, 
-    501, 501, 501, 501, 501, 501, 501, 501, 501, 64, 502, 502, 502, 502, 502, 
-    502, 502, 502, 503, 503, 503, 503, 503, 503, 504, 504, 505, 505, 505, 
-    505, 505, 505, 505, 505, 505, 505, 505, 505, 506, 507, 507, 507, 508, 
-    508, 508, 508, 508, 508, 508, 508, 508, 508, 505, 505, 64, 64, 64, 64, 
-    72, 75, 72, 75, 72, 75, 509, 77, 79, 79, 79, 510, 77, 77, 77, 77, 77, 77, 
-    77, 77, 77, 77, 510, 511, 72, 75, 72, 75, 403, 403, 64, 77, 512, 512, 
-    512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 513, 513, 
-    513, 513, 513, 513, 513, 513, 513, 513, 514, 514, 515, 515, 515, 515, 
-    515, 515, 47, 47, 47, 47, 47, 47, 47, 45, 45, 45, 45, 45, 45, 45, 45, 45, 
-    47, 47, 37, 41, 37, 41, 37, 41, 41, 41, 37, 41, 37, 41, 37, 41, 44, 41, 
-    41, 41, 41, 41, 41, 41, 41, 37, 41, 37, 41, 37, 37, 41, 45, 516, 516, 37, 
-    41, 37, 41, 64, 37, 41, 37, 41, 41, 41, 37, 41, 37, 41, 37, 37, 37, 37, 
-    64, 64, 37, 37, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 42, 
-    44, 44, 41, 42, 42, 42, 42, 42, 517, 517, 518, 517, 517, 517, 519, 517, 
-    517, 517, 517, 518, 517, 517, 517, 517, 517, 517, 517, 517, 517, 517, 
-    517, 517, 517, 517, 517, 520, 520, 518, 518, 520, 521, 521, 521, 521, 64, 
-    64, 64, 64, 522, 522, 522, 522, 522, 522, 277, 277, 250, 444, 64, 64, 64, 
-    64, 64, 64, 523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 
-    524, 524, 524, 524, 525, 525, 526, 526, 526, 526, 526, 526, 526, 526, 
-    526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 525, 525, 525, 525, 
-    525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 527, 64, 64, 
-    64, 64, 64, 64, 64, 64, 64, 528, 528, 529, 529, 529, 529, 529, 529, 529, 
-    529, 529, 529, 64, 64, 64, 64, 64, 64, 174, 174, 174, 174, 174, 174, 174, 
-    174, 174, 174, 171, 171, 171, 171, 171, 171, 176, 176, 176, 171, 64, 64, 
-    64, 64, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 531, 531, 531, 
-    531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 
-    531, 531, 531, 532, 532, 532, 532, 532, 533, 533, 533, 84, 534, 535, 535, 
-    535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 536, 
-    536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 537, 538, 64, 64, 64, 
-    64, 64, 64, 64, 64, 64, 64, 64, 539, 290, 290, 290, 290, 290, 64, 64, 64, 
-    540, 540, 540, 541, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 
-    542, 542, 542, 542, 542, 543, 541, 541, 540, 540, 540, 540, 541, 541, 
-    540, 541, 541, 541, 544, 545, 545, 545, 545, 545, 545, 545, 545, 545, 
-    545, 545, 545, 545, 64, 46, 546, 546, 546, 546, 546, 546, 546, 546, 546, 
-    546, 64, 64, 64, 64, 545, 545, 278, 278, 278, 278, 278, 280, 547, 278, 
-    283, 283, 278, 278, 278, 278, 278, 64, 548, 548, 548, 548, 548, 548, 548, 
-    548, 548, 549, 549, 549, 549, 549, 549, 550, 550, 549, 549, 550, 550, 
-    549, 549, 64, 548, 548, 548, 549, 548, 548, 548, 548, 548, 548, 548, 548, 
-    549, 550, 64, 64, 551, 551, 551, 551, 551, 551, 551, 551, 551, 551, 64, 
-    64, 552, 552, 552, 552, 547, 278, 278, 278, 278, 278, 278, 286, 286, 286, 
-    278, 279, 280, 279, 278, 278, 553, 553, 553, 553, 553, 553, 553, 553, 
-    554, 553, 554, 554, 555, 553, 553, 554, 554, 553, 553, 553, 553, 553, 
-    554, 554, 553, 554, 553, 64, 64, 64, 64, 64, 64, 64, 64, 553, 553, 556, 
-    557, 557, 558, 558, 558, 558, 558, 558, 558, 558, 558, 558, 558, 559, 
-    560, 560, 559, 559, 561, 561, 558, 562, 562, 559, 563, 64, 64, 292, 292, 
-    292, 292, 292, 292, 64, 41, 41, 41, 516, 44, 44, 44, 44, 64, 64, 64, 64, 
-    41, 62, 64, 64, 558, 558, 558, 559, 559, 560, 559, 559, 560, 559, 559, 
-    561, 559, 563, 64, 64, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 
-    64, 64, 64, 64, 64, 64, 290, 565, 565, 565, 565, 565, 565, 565, 565, 565, 
-    565, 565, 565, 565, 565, 565, 565, 565, 565, 290, 64, 64, 64, 64, 291, 
-    291, 291, 291, 291, 291, 291, 64, 64, 64, 64, 291, 291, 291, 291, 291, 
-    291, 291, 291, 291, 64, 64, 64, 64, 566, 64, 64, 64, 64, 64, 64, 64, 64, 
-    64, 64, 64, 64, 64, 64, 566, 567, 568, 568, 568, 568, 568, 568, 568, 568, 
-    568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 
-    567, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 
-    496, 498, 498, 496, 496, 498, 498, 498, 498, 498, 498, 41, 41, 41, 41, 
-    41, 41, 41, 64, 64, 64, 64, 83, 83, 83, 83, 83, 64, 64, 64, 64, 64, 110, 
-    569, 110, 110, 570, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 
-    110, 110, 110, 64, 110, 110, 110, 110, 110, 64, 110, 64, 110, 110, 64, 
-    110, 110, 64, 110, 110, 126, 126, 571, 571, 571, 571, 571, 571, 571, 571, 
-    571, 571, 571, 571, 571, 571, 571, 571, 64, 64, 64, 64, 64, 64, 64, 64, 
-    64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 572, 418, 64, 
-    64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 116, 119, 64, 64, 
-    58, 58, 58, 58, 58, 58, 58, 58, 469, 469, 469, 469, 469, 469, 469, 474, 
-    475, 469, 64, 64, 64, 64, 64, 64, 78, 78, 78, 78, 78, 78, 78, 136, 136, 
-    136, 136, 136, 136, 136, 64, 64, 469, 473, 473, 573, 573, 474, 475, 474, 
-    475, 474, 475, 474, 475, 474, 475, 474, 475, 474, 475, 474, 475, 469, 
-    469, 474, 475, 469, 469, 469, 469, 573, 573, 573, 574, 469, 574, 64, 469, 
-    574, 469, 469, 473, 451, 452, 451, 452, 451, 452, 575, 469, 469, 576, 
-    577, 578, 578, 579, 64, 469, 580, 575, 469, 64, 64, 64, 64, 126, 126, 
-    126, 126, 126, 64, 126, 126, 126, 126, 126, 126, 126, 64, 64, 410, 64, 
-    581, 581, 582, 583, 582, 581, 581, 584, 585, 581, 586, 587, 588, 587, 
-    587, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 587, 581, 590, 
-    591, 590, 581, 581, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 
-    592, 592, 592, 592, 592, 592, 592, 592, 584, 581, 585, 593, 594, 593, 
-    595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 
-    595, 595, 595, 595, 584, 591, 585, 591, 584, 585, 596, 597, 598, 596, 
-    596, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 600, 599, 599, 
-    599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 600, 600, 601, 
-    601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 64, 
-    64, 64, 601, 601, 601, 601, 601, 601, 64, 64, 601, 601, 601, 64, 64, 64, 
-    583, 583, 591, 593, 602, 583, 583, 64, 603, 604, 604, 604, 604, 603, 603, 
-    64, 64, 605, 605, 605, 26, 30, 64, 64, 606, 606, 606, 606, 606, 606, 606, 
-    606, 606, 606, 606, 606, 64, 606, 606, 606, 606, 606, 606, 606, 606, 606, 
-    606, 64, 606, 606, 606, 64, 606, 606, 64, 606, 606, 606, 606, 606, 606, 
-    606, 64, 64, 606, 606, 606, 64, 64, 64, 64, 64, 84, 66, 84, 64, 64, 64, 
-    64, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 64, 
-    64, 64, 277, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 
-    607, 608, 608, 608, 608, 609, 609, 609, 609, 609, 609, 609, 609, 609, 
-    609, 609, 609, 609, 609, 609, 609, 609, 608, 608, 609, 64, 64, 64, 26, 
-    26, 26, 26, 64, 64, 64, 64, 609, 64, 64, 64, 64, 64, 64, 64, 277, 277, 
-    277, 277, 277, 136, 64, 64, 610, 610, 610, 610, 610, 610, 610, 610, 610, 
-    610, 610, 610, 610, 64, 64, 64, 611, 611, 611, 611, 611, 611, 611, 611, 
-    611, 64, 64, 64, 64, 64, 64, 64, 136, 438, 438, 438, 438, 438, 438, 438, 
+    467, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 
+    496, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497, 498, 498, 498, 
+    498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 499, 498, 498, 498, 
+    498, 498, 498, 498, 64, 64, 64, 500, 500, 500, 500, 500, 500, 500, 500, 
+    500, 500, 500, 500, 500, 500, 500, 64, 501, 501, 501, 501, 501, 501, 501, 
+    501, 502, 502, 502, 502, 502, 502, 503, 503, 504, 504, 504, 504, 504, 
+    504, 504, 504, 504, 504, 504, 504, 505, 506, 506, 506, 507, 507, 507, 
+    507, 507, 507, 507, 507, 507, 507, 504, 504, 64, 64, 64, 64, 72, 75, 72, 
+    75, 72, 75, 508, 77, 79, 79, 79, 509, 77, 77, 77, 77, 77, 77, 77, 77, 77, 
+    77, 509, 510, 72, 75, 72, 75, 403, 403, 77, 77, 511, 511, 511, 511, 511, 
+    511, 511, 511, 511, 511, 511, 511, 511, 511, 512, 512, 512, 512, 512, 
+    512, 512, 512, 512, 512, 513, 513, 514, 514, 514, 514, 514, 514, 47, 47, 
+    47, 47, 47, 47, 47, 45, 45, 45, 45, 45, 45, 45, 45, 45, 47, 47, 37, 41, 
+    37, 41, 37, 41, 41, 41, 37, 41, 37, 41, 37, 41, 44, 41, 41, 41, 41, 41, 
+    41, 41, 41, 37, 41, 37, 41, 37, 37, 41, 45, 515, 515, 37, 41, 37, 41, 42, 
+    37, 41, 37, 41, 41, 41, 37, 41, 37, 41, 37, 37, 37, 37, 64, 64, 37, 37, 
+    37, 37, 37, 41, 37, 41, 64, 64, 64, 64, 64, 64, 64, 42, 44, 44, 41, 42, 
+    42, 42, 42, 42, 516, 516, 517, 516, 516, 516, 518, 516, 516, 516, 516, 
+    517, 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, 
+    516, 516, 519, 519, 517, 517, 519, 520, 520, 520, 520, 64, 64, 64, 64, 
+    521, 521, 521, 521, 521, 521, 277, 277, 250, 444, 64, 64, 64, 64, 64, 64, 
+    522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 523, 523, 
+    523, 523, 524, 524, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 
+    525, 525, 525, 525, 525, 525, 525, 525, 524, 524, 524, 524, 524, 524, 
+    524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 526, 64, 64, 64, 64, 
+    64, 64, 64, 64, 64, 527, 527, 528, 528, 528, 528, 528, 528, 528, 528, 
+    528, 528, 64, 64, 64, 64, 64, 64, 174, 174, 174, 174, 174, 174, 174, 174, 
+    174, 174, 171, 171, 171, 171, 171, 171, 176, 176, 176, 171, 176, 171, 64, 
+    64, 529, 529, 529, 529, 529, 529, 529, 529, 529, 529, 530, 530, 530, 530, 
+    530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 
+    530, 530, 531, 531, 531, 531, 531, 532, 532, 532, 84, 533, 534, 534, 534, 
+    534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 535, 535, 
+    535, 535, 535, 535, 535, 535, 535, 535, 535, 536, 537, 64, 64, 64, 64, 
+    64, 64, 64, 64, 64, 64, 64, 538, 290, 290, 290, 290, 290, 64, 64, 64, 
+    539, 539, 539, 540, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 
+    541, 541, 541, 541, 541, 542, 540, 540, 539, 539, 539, 539, 540, 540, 
+    539, 540, 540, 540, 543, 544, 544, 544, 544, 544, 544, 544, 544, 544, 
+    544, 544, 544, 544, 64, 46, 545, 545, 545, 545, 545, 545, 545, 545, 545, 
+    545, 64, 64, 64, 64, 544, 544, 278, 278, 278, 278, 278, 280, 546, 278, 
+    283, 283, 278, 278, 278, 278, 278, 64, 547, 547, 547, 547, 547, 547, 547, 
+    547, 547, 548, 548, 548, 548, 548, 548, 549, 549, 548, 548, 549, 549, 
+    548, 548, 64, 547, 547, 547, 548, 547, 547, 547, 547, 547, 547, 547, 547, 
+    548, 549, 64, 64, 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, 64, 
+    64, 551, 551, 551, 551, 546, 278, 278, 278, 278, 278, 278, 286, 286, 286, 
+    278, 279, 280, 279, 278, 278, 552, 552, 552, 552, 552, 552, 552, 552, 
+    553, 552, 553, 553, 554, 552, 552, 553, 553, 552, 552, 552, 552, 552, 
+    553, 553, 552, 553, 552, 64, 64, 64, 64, 64, 64, 64, 64, 552, 552, 555, 
+    556, 556, 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, 558, 
+    559, 559, 558, 558, 560, 560, 557, 561, 561, 558, 562, 64, 64, 292, 292, 
+    292, 292, 292, 292, 64, 41, 41, 41, 515, 44, 44, 44, 44, 41, 41, 41, 41, 
+    41, 62, 64, 64, 298, 298, 298, 298, 298, 298, 298, 298, 557, 557, 557, 
+    558, 558, 559, 558, 558, 559, 558, 558, 560, 558, 562, 64, 64, 563, 563, 
+    563, 563, 563, 563, 563, 563, 563, 563, 64, 64, 64, 64, 64, 64, 290, 290, 
+    290, 290, 64, 64, 64, 64, 291, 291, 291, 291, 291, 291, 291, 64, 64, 64, 
+    64, 291, 291, 291, 291, 291, 291, 291, 291, 291, 64, 64, 64, 64, 564, 
+    564, 564, 564, 564, 564, 564, 564, 565, 565, 565, 565, 565, 565, 565, 
+    565, 496, 496, 497, 497, 497, 497, 497, 497, 41, 41, 41, 41, 41, 41, 41, 
+    64, 64, 64, 64, 83, 83, 83, 83, 83, 64, 64, 64, 64, 64, 110, 566, 110, 
+    110, 567, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 
+    110, 64, 110, 110, 110, 110, 110, 64, 110, 64, 110, 110, 64, 110, 110, 
+    64, 110, 110, 126, 126, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 
+    568, 568, 568, 568, 568, 568, 64, 64, 64, 64, 64, 64, 64, 64, 64, 126, 
+    126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 569, 418, 64, 64, 126, 
+    126, 126, 126, 126, 126, 126, 126, 126, 126, 116, 119, 64, 64, 58, 58, 
+    58, 58, 58, 58, 58, 58, 469, 469, 469, 469, 469, 469, 469, 474, 475, 469, 
+    64, 64, 64, 64, 64, 64, 78, 78, 78, 78, 78, 78, 78, 136, 136, 136, 136, 
+    136, 136, 136, 77, 77, 469, 473, 473, 570, 570, 474, 475, 474, 475, 474, 
+    475, 474, 475, 474, 475, 474, 475, 474, 475, 474, 475, 469, 469, 474, 
+    475, 469, 469, 469, 469, 570, 570, 570, 571, 469, 571, 64, 469, 571, 469, 
+    469, 473, 451, 452, 451, 452, 451, 452, 572, 469, 469, 573, 574, 575, 
+    575, 576, 64, 469, 577, 572, 469, 64, 64, 64, 64, 126, 126, 126, 126, 
+    126, 64, 126, 126, 126, 126, 126, 126, 126, 64, 64, 410, 64, 578, 578, 
+    579, 580, 579, 578, 578, 581, 582, 578, 583, 584, 585, 584, 584, 586, 
+    586, 586, 586, 586, 586, 586, 586, 586, 586, 584, 578, 587, 588, 587, 
+    578, 578, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 
+    589, 589, 589, 589, 589, 589, 581, 578, 582, 590, 591, 590, 592, 592, 
+    592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 
+    592, 592, 581, 588, 582, 588, 581, 582, 593, 594, 595, 593, 593, 596, 
+    596, 596, 596, 596, 596, 596, 596, 596, 596, 597, 596, 596, 596, 596, 
+    596, 596, 596, 596, 596, 596, 596, 596, 596, 597, 597, 598, 598, 598, 
+    598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 64, 64, 64, 
+    598, 598, 598, 598, 598, 598, 64, 64, 598, 598, 598, 64, 64, 64, 580, 
+    580, 588, 590, 599, 580, 580, 64, 600, 601, 601, 601, 601, 600, 600, 64, 
+    64, 602, 602, 602, 26, 30, 64, 64, 603, 603, 603, 603, 603, 603, 603, 
+    603, 603, 603, 603, 603, 64, 603, 603, 603, 603, 603, 603, 603, 603, 603, 
+    603, 64, 603, 603, 603, 64, 603, 603, 64, 603, 603, 603, 603, 603, 603, 
+    603, 64, 64, 603, 603, 603, 64, 64, 64, 64, 64, 84, 66, 84, 64, 64, 64, 
+    64, 521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 521, 64, 
+    64, 64, 277, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 
+    604, 605, 605, 605, 605, 606, 606, 606, 606, 606, 606, 606, 606, 606, 
+    606, 606, 606, 606, 606, 606, 606, 606, 605, 605, 606, 64, 64, 64, 26, 
+    26, 26, 26, 64, 64, 64, 64, 606, 64, 64, 64, 64, 64, 64, 64, 277, 277, 
+    277, 277, 277, 136, 64, 64, 607, 607, 607, 607, 607, 607, 607, 607, 607, 
+    607, 607, 607, 607, 64, 64, 64, 608, 608, 608, 608, 608, 608, 608, 608, 
+    608, 64, 64, 64, 64, 64, 64, 64, 136, 438, 438, 438, 438, 438, 438, 438, 
     438, 438, 438, 438, 438, 438, 438, 438, 438, 438, 438, 438, 64, 64, 64, 
-    64, 612, 612, 612, 612, 612, 612, 612, 612, 613, 613, 613, 613, 64, 64, 
-    64, 64, 614, 614, 614, 614, 614, 614, 614, 614, 614, 615, 614, 614, 614, 
-    614, 614, 614, 614, 614, 615, 64, 64, 64, 64, 64, 616, 616, 616, 616, 
-    616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 617, 617, 617, 
-    617, 64, 64, 64, 64, 64, 618, 618, 618, 618, 618, 618, 618, 618, 618, 
-    618, 618, 618, 618, 618, 64, 619, 620, 620, 620, 620, 620, 620, 620, 620, 
-    620, 620, 620, 620, 64, 64, 64, 64, 621, 622, 622, 622, 622, 622, 64, 64, 
-    623, 623, 623, 623, 623, 623, 623, 623, 624, 624, 624, 624, 624, 624, 
-    624, 624, 625, 625, 625, 625, 625, 625, 625, 625, 626, 626, 626, 626, 
-    626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 64, 64, 627, 627, 627, 
-    627, 627, 627, 627, 627, 627, 627, 64, 64, 64, 64, 64, 64, 628, 628, 628, 
-    628, 628, 628, 628, 628, 629, 629, 629, 629, 629, 629, 629, 629, 629, 
-    629, 629, 629, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 630, 631, 631, 
-    631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 64, 631, 
-    631, 631, 631, 631, 631, 64, 64, 632, 632, 632, 632, 632, 632, 64, 64, 
-    632, 64, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 
-    632, 632, 632, 632, 632, 632, 632, 64, 632, 632, 64, 64, 64, 632, 64, 64, 
-    632, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 
-    633, 64, 634, 635, 635, 635, 635, 635, 635, 635, 635, 636, 636, 636, 636, 
-    636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 637, 638, 
-    638, 638, 638, 638, 638, 638, 639, 639, 639, 639, 639, 639, 639, 639, 
-    639, 639, 639, 639, 639, 639, 639, 64, 64, 64, 64, 64, 64, 64, 64, 640, 
-    640, 640, 640, 640, 640, 640, 640, 640, 641, 641, 641, 641, 641, 641, 
-    641, 641, 641, 641, 641, 641, 641, 641, 642, 642, 642, 642, 642, 642, 64, 
-    64, 64, 643, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 64, 64, 
-    64, 64, 64, 645, 646, 646, 646, 646, 646, 646, 646, 646, 647, 647, 647, 
-    647, 647, 647, 647, 647, 64, 64, 64, 64, 64, 64, 647, 647, 648, 649, 649, 
-    649, 64, 649, 649, 64, 64, 64, 64, 64, 649, 650, 649, 651, 648, 648, 648, 
-    648, 64, 648, 648, 648, 64, 648, 648, 648, 648, 648, 648, 648, 648, 648, 
-    648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 64, 64, 64, 64, 651, 
-    652, 650, 64, 64, 64, 64, 653, 654, 654, 654, 654, 654, 654, 654, 654, 
-    655, 655, 655, 655, 655, 655, 655, 655, 655, 64, 64, 64, 64, 64, 64, 64, 
-    656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 657, 
-    657, 658, 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, 
-    659, 660, 660, 660, 661, 661, 661, 661, 661, 661, 661, 661, 662, 661, 
-    661, 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, 663, 664, 64, 64, 
-    64, 64, 665, 665, 665, 665, 665, 666, 666, 666, 666, 666, 666, 666, 64, 
-    667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 64, 
-    64, 64, 668, 668, 668, 668, 668, 668, 668, 669, 669, 669, 669, 669, 669, 
-    669, 669, 669, 669, 669, 669, 669, 669, 64, 64, 670, 670, 670, 670, 670, 
-    670, 670, 670, 671, 671, 671, 671, 671, 671, 671, 671, 671, 671, 671, 64, 
-    64, 64, 64, 64, 672, 672, 672, 672, 672, 672, 672, 672, 673, 673, 673, 
-    673, 673, 673, 673, 673, 673, 673, 64, 64, 64, 64, 64, 64, 64, 674, 674, 
-    674, 674, 64, 64, 64, 64, 675, 675, 675, 675, 675, 675, 675, 676, 676, 
-    676, 676, 676, 676, 676, 676, 676, 64, 64, 64, 64, 64, 64, 64, 677, 677, 
-    677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 64, 678, 
-    679, 678, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680, 
-    680, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 
-    679, 681, 682, 682, 682, 682, 682, 682, 682, 64, 64, 64, 64, 683, 683, 
-    683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 
-    683, 683, 683, 683, 684, 684, 684, 684, 684, 684, 684, 684, 684, 684, 64, 
-    64, 64, 64, 64, 64, 64, 681, 685, 685, 686, 687, 687, 687, 687, 687, 687, 
-    687, 687, 687, 687, 687, 687, 687, 686, 686, 686, 685, 685, 685, 685, 
-    686, 686, 688, 689, 690, 690, 691, 690, 690, 690, 690, 64, 64, 64, 64, 
-    64, 64, 692, 692, 692, 692, 692, 692, 692, 692, 692, 64, 64, 64, 64, 64, 
-    64, 64, 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, 64, 64, 64, 64, 
-    64, 64, 694, 694, 694, 695, 695, 695, 695, 695, 695, 695, 695, 695, 695, 
-    695, 695, 695, 695, 695, 695, 695, 695, 695, 695, 696, 696, 696, 696, 
-    696, 697, 696, 696, 696, 696, 696, 696, 698, 698, 64, 699, 699, 699, 699, 
-    699, 699, 699, 699, 699, 699, 700, 700, 700, 700, 64, 64, 64, 64, 701, 
-    701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 702, 703, 703, 701, 64, 
-    704, 704, 705, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 
-    706, 706, 706, 706, 706, 705, 705, 705, 704, 704, 704, 704, 704, 704, 
-    704, 704, 704, 705, 707, 706, 706, 706, 706, 708, 708, 708, 708, 64, 64, 
-    64, 64, 708, 64, 64, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 
-    706, 64, 64, 64, 64, 64, 64, 710, 710, 710, 710, 710, 710, 710, 710, 710, 
-    710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 64, 64, 64, 711, 
-    711, 711, 711, 711, 711, 711, 711, 711, 711, 64, 711, 711, 711, 711, 711, 
-    711, 711, 711, 711, 712, 712, 712, 713, 713, 713, 712, 712, 713, 714, 
-    715, 713, 716, 716, 716, 716, 716, 716, 64, 64, 717, 717, 717, 717, 717, 
-    717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 718, 719, 719, 719, 
-    718, 718, 718, 718, 718, 718, 720, 721, 64, 64, 64, 64, 64, 722, 722, 
-    722, 722, 722, 722, 722, 722, 722, 722, 64, 64, 64, 64, 64, 64, 64, 723, 
-    724, 724, 64, 725, 725, 725, 725, 725, 725, 725, 725, 64, 64, 725, 725, 
-    64, 64, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 
-    725, 64, 725, 725, 725, 725, 725, 725, 725, 64, 725, 725, 64, 725, 725, 
-    725, 725, 725, 64, 64, 726, 725, 724, 724, 723, 724, 724, 724, 724, 64, 
-    64, 724, 724, 64, 64, 724, 724, 727, 64, 64, 64, 64, 64, 64, 64, 64, 64, 
-    724, 64, 64, 64, 64, 64, 725, 725, 725, 725, 725, 724, 724, 64, 64, 728, 
-    728, 728, 728, 728, 728, 728, 64, 64, 64, 729, 729, 729, 729, 729, 729, 
-    729, 729, 730, 730, 730, 731, 731, 731, 731, 731, 731, 730, 731, 730, 
-    730, 730, 730, 731, 731, 730, 732, 733, 729, 729, 734, 729, 735, 735, 
-    735, 735, 735, 735, 735, 735, 735, 735, 64, 64, 64, 64, 64, 64, 736, 736, 
-    736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 737, 
-    737, 737, 738, 738, 738, 738, 64, 64, 737, 737, 737, 737, 738, 738, 737, 
-    739, 740, 741, 741, 741, 741, 741, 741, 741, 741, 741, 64, 64, 64, 64, 
-    64, 64, 742, 742, 742, 742, 742, 742, 742, 742, 743, 743, 743, 744, 744, 
-    744, 744, 744, 744, 744, 744, 743, 743, 744, 743, 745, 744, 746, 746, 
-    746, 742, 64, 64, 64, 747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 
-    64, 64, 64, 64, 64, 64, 748, 748, 748, 748, 748, 748, 748, 748, 748, 748, 
-    748, 749, 750, 749, 750, 750, 749, 749, 749, 749, 749, 749, 751, 752, 
-    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 64, 64, 64, 64, 64, 64, 
-    754, 754, 754, 754, 754, 754, 754, 754, 755, 755, 755, 755, 755, 755, 
-    755, 755, 756, 756, 756, 756, 756, 756, 756, 756, 756, 756, 757, 757, 
-    757, 757, 757, 757, 757, 757, 757, 64, 64, 64, 64, 64, 64, 64, 64, 64, 
-    64, 64, 64, 758, 759, 759, 759, 759, 759, 759, 759, 759, 759, 64, 64, 64, 
-    64, 64, 64, 64, 760, 760, 760, 760, 760, 760, 760, 760, 760, 64, 64, 64, 
-    64, 64, 64, 64, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
-    761, 761, 761, 761, 64, 762, 762, 762, 762, 762, 64, 64, 64, 763, 763, 
-    763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 64, 512, 
-    64, 64, 64, 64, 64, 64, 64, 764, 764, 764, 764, 764, 764, 764, 764, 764, 
-    764, 764, 764, 764, 764, 764, 64, 765, 765, 765, 765, 765, 765, 765, 765, 
-    765, 765, 64, 64, 64, 64, 766, 766, 767, 767, 767, 767, 767, 767, 767, 
-    767, 767, 767, 767, 767, 767, 767, 64, 64, 768, 768, 768, 768, 768, 769, 
-    64, 64, 770, 770, 770, 770, 770, 770, 770, 770, 771, 771, 771, 771, 771, 
-    771, 771, 772, 772, 772, 772, 772, 773, 773, 773, 773, 774, 774, 774, 
-    774, 772, 773, 64, 64, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 
-    64, 776, 776, 776, 776, 776, 776, 776, 64, 770, 770, 770, 770, 770, 64, 
-    64, 64, 64, 64, 770, 770, 770, 777, 777, 777, 777, 777, 777, 777, 777, 
-    777, 777, 777, 777, 777, 64, 64, 64, 777, 778, 778, 778, 778, 778, 778, 
-    778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 
-    778, 778, 64, 64, 64, 64, 64, 64, 64, 64, 779, 779, 779, 779, 780, 780, 
-    780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 486, 482, 64, 64, 
-    64, 64, 64, 64, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 
-    64, 64, 64, 64, 64, 781, 781, 781, 781, 781, 64, 64, 64, 781, 64, 64, 64, 
-    64, 64, 64, 64, 781, 781, 64, 64, 782, 783, 784, 785, 410, 410, 410, 410, 
-    64, 64, 64, 64, 277, 277, 277, 277, 277, 277, 64, 64, 277, 277, 277, 277, 
-    277, 277, 277, 64, 64, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 
-    277, 277, 786, 786, 400, 400, 400, 277, 277, 277, 787, 786, 786, 786, 
-    786, 786, 410, 410, 410, 410, 410, 410, 410, 410, 136, 136, 136, 136, 
-    136, 136, 136, 136, 277, 277, 78, 78, 78, 78, 78, 136, 136, 277, 277, 
-    277, 277, 277, 277, 78, 78, 78, 78, 277, 277, 609, 609, 788, 788, 788, 
-    609, 64, 64, 522, 522, 64, 64, 64, 64, 64, 64, 442, 442, 442, 442, 442, 
-    442, 442, 442, 442, 442, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 
-    34, 34, 34, 34, 34, 34, 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, 
-    34, 34, 34, 34, 34, 34, 34, 64, 34, 34, 34, 34, 34, 34, 442, 64, 442, 
-    442, 64, 64, 442, 64, 64, 442, 442, 64, 64, 442, 442, 442, 442, 64, 442, 
-    442, 34, 34, 64, 34, 64, 34, 34, 34, 34, 34, 34, 34, 64, 34, 34, 34, 34, 
-    34, 34, 34, 442, 442, 64, 442, 442, 442, 442, 64, 64, 442, 442, 442, 442, 
-    442, 442, 442, 442, 64, 442, 442, 442, 442, 442, 442, 442, 64, 34, 34, 
-    442, 442, 64, 442, 442, 442, 442, 64, 442, 442, 442, 442, 442, 64, 442, 
-    64, 64, 64, 442, 442, 442, 442, 442, 442, 442, 64, 34, 34, 34, 34, 34, 
-    34, 34, 34, 34, 34, 34, 34, 64, 64, 442, 789, 34, 34, 34, 34, 34, 34, 34, 
-    34, 34, 445, 34, 34, 34, 34, 34, 34, 442, 442, 442, 442, 442, 442, 442, 
-    442, 442, 789, 34, 34, 34, 34, 34, 34, 34, 34, 34, 445, 34, 34, 442, 442, 
-    442, 442, 442, 789, 34, 34, 34, 34, 34, 34, 34, 34, 34, 445, 34, 34, 34, 
-    34, 34, 34, 442, 442, 442, 442, 442, 442, 442, 442, 442, 789, 34, 445, 
-    34, 34, 34, 34, 34, 34, 34, 34, 442, 34, 64, 64, 790, 790, 790, 790, 790, 
-    790, 790, 790, 790, 790, 791, 791, 791, 791, 791, 791, 791, 791, 791, 
-    791, 791, 791, 791, 64, 64, 792, 792, 792, 792, 792, 792, 792, 792, 792, 
-    793, 793, 793, 793, 793, 793, 793, 64, 126, 126, 126, 126, 64, 126, 126, 
-    126, 64, 126, 126, 64, 126, 64, 64, 126, 64, 126, 126, 126, 126, 126, 
-    126, 126, 126, 126, 126, 64, 126, 126, 126, 126, 64, 126, 64, 126, 64, 
-    64, 64, 64, 64, 64, 126, 64, 64, 64, 64, 126, 64, 126, 64, 126, 64, 126, 
-    126, 126, 64, 126, 64, 126, 64, 126, 64, 126, 64, 126, 126, 126, 126, 64, 
-    126, 64, 126, 126, 64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 64, 
-    64, 64, 64, 64, 126, 126, 126, 64, 126, 126, 126, 113, 113, 64, 64, 64, 
-    64, 64, 64, 64, 26, 26, 26, 26, 26, 26, 26, 33, 33, 33, 446, 446, 64, 64, 
-    64, 453, 453, 453, 453, 453, 453, 277, 64, 453, 453, 26, 26, 64, 64, 64, 
-    64, 453, 453, 453, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 277, 277, 
-    794, 489, 489, 64, 64, 64, 64, 64, 489, 489, 489, 64, 64, 64, 64, 64, 
-    489, 64, 64, 64, 64, 64, 64, 64, 489, 489, 64, 64, 64, 64, 64, 64, 26, 
-    26, 26, 26, 26, 64, 64, 64, 64, 64, 64, 64, 26, 26, 26, 26, 26, 26, 64, 
-    26, 26, 26, 26, 26, 26, 26, 26, 26, 64, 26, 26, 26, 26, 26, 26, 64, 64, 
-    26, 26, 26, 497, 497, 497, 497, 497, 497, 496, 498, 498, 498, 498, 498, 
-    498, 498, 64, 64, 64, 410, 64, 64, 64, 64, 64, 64, 410, 410, 410, 410, 
-    410, 410, 410, 410, 568, 568, 568, 568, 568, 567, 64, 64, 
+    64, 609, 609, 609, 609, 609, 609, 609, 609, 610, 610, 610, 610, 64, 64, 
+    64, 64, 611, 611, 611, 611, 611, 611, 611, 611, 611, 612, 611, 611, 611, 
+    611, 611, 611, 611, 611, 612, 64, 64, 64, 64, 64, 613, 613, 613, 613, 
+    613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 614, 614, 614, 614, 
+    614, 64, 64, 64, 64, 64, 615, 615, 615, 615, 615, 615, 615, 615, 615, 
+    615, 615, 615, 615, 615, 64, 616, 617, 617, 617, 617, 617, 617, 617, 617, 
+    617, 617, 617, 617, 64, 64, 64, 64, 618, 619, 619, 619, 619, 619, 64, 64, 
+    620, 620, 620, 620, 620, 620, 620, 620, 621, 621, 621, 621, 621, 621, 
+    621, 621, 622, 622, 622, 622, 622, 622, 622, 622, 623, 623, 623, 623, 
+    623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 64, 64, 624, 624, 624, 
+    624, 624, 624, 624, 624, 624, 624, 64, 64, 64, 64, 64, 64, 625, 625, 625, 
+    625, 625, 625, 625, 625, 626, 626, 626, 626, 626, 626, 626, 626, 626, 
+    626, 626, 626, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 627, 628, 628, 
+    628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 64, 628, 
+    628, 628, 628, 628, 628, 64, 64, 629, 629, 629, 629, 629, 629, 64, 64, 
+    629, 64, 629, 629, 629, 629, 629, 629, 629, 629, 629, 629, 629, 629, 629, 
+    629, 629, 629, 629, 629, 629, 629, 64, 629, 629, 64, 64, 64, 629, 64, 64, 
+    629, 630, 630, 630, 630, 630, 630, 630, 630, 630, 630, 630, 630, 630, 
+    630, 64, 631, 632, 632, 632, 632, 632, 632, 632, 632, 633, 633, 633, 633, 
+    633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 634, 634, 635, 
+    635, 635, 635, 635, 635, 635, 636, 636, 636, 636, 636, 636, 636, 636, 
+    636, 636, 636, 636, 636, 636, 636, 64, 64, 64, 64, 64, 64, 64, 64, 637, 
+    637, 637, 637, 637, 637, 637, 637, 637, 638, 638, 638, 638, 638, 638, 
+    638, 638, 638, 638, 638, 64, 638, 638, 64, 64, 64, 64, 64, 639, 639, 639, 
+    639, 639, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 
+    640, 640, 641, 641, 641, 641, 641, 641, 64, 64, 64, 642, 643, 643, 643, 
+    643, 643, 643, 643, 643, 643, 643, 64, 64, 64, 64, 64, 644, 645, 645, 
+    645, 645, 645, 645, 645, 645, 646, 646, 646, 646, 646, 646, 646, 646, 64, 
+    64, 64, 64, 647, 647, 646, 646, 647, 647, 647, 647, 647, 647, 647, 647, 
+    64, 64, 647, 647, 647, 647, 647, 647, 648, 649, 649, 649, 64, 649, 649, 
+    64, 64, 64, 64, 64, 649, 650, 649, 651, 648, 648, 648, 648, 64, 648, 648, 
+    648, 64, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 
+    648, 648, 648, 648, 648, 648, 64, 64, 64, 64, 651, 652, 650, 64, 64, 64, 
+    64, 653, 654, 654, 654, 654, 654, 654, 654, 654, 655, 655, 655, 655, 655, 
+    655, 655, 655, 655, 64, 64, 64, 64, 64, 64, 64, 656, 656, 656, 656, 656, 
+    656, 656, 656, 656, 656, 656, 656, 656, 657, 657, 658, 659, 659, 659, 
+    659, 659, 659, 659, 659, 659, 659, 659, 659, 659, 660, 660, 660, 661, 
+    661, 661, 661, 661, 661, 661, 661, 662, 661, 661, 661, 661, 661, 661, 
+    661, 661, 661, 661, 661, 661, 663, 664, 64, 64, 64, 64, 665, 665, 665, 
+    665, 665, 666, 666, 666, 666, 666, 666, 666, 64, 667, 667, 667, 667, 667, 
+    667, 667, 667, 667, 667, 667, 667, 667, 667, 64, 64, 64, 668, 668, 668, 
+    668, 668, 668, 668, 669, 669, 669, 669, 669, 669, 669, 669, 669, 669, 
+    669, 669, 669, 669, 64, 64, 670, 670, 670, 670, 670, 670, 670, 670, 671, 
+    671, 671, 671, 671, 671, 671, 671, 671, 671, 671, 64, 64, 64, 64, 64, 
+    672, 672, 672, 672, 672, 672, 672, 672, 673, 673, 673, 673, 673, 673, 
+    673, 673, 673, 673, 64, 64, 64, 64, 64, 64, 64, 674, 674, 674, 674, 64, 
+    64, 64, 64, 675, 675, 675, 675, 675, 675, 675, 676, 676, 676, 676, 676, 
+    676, 676, 676, 676, 64, 64, 64, 64, 64, 64, 64, 677, 677, 677, 677, 677, 
+    677, 677, 677, 677, 677, 677, 64, 64, 64, 64, 64, 678, 678, 678, 678, 
+    678, 678, 678, 678, 678, 678, 678, 64, 64, 64, 64, 64, 64, 64, 679, 679, 
+    679, 679, 679, 679, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680, 
+    680, 680, 680, 680, 680, 64, 681, 682, 681, 683, 683, 683, 683, 683, 683, 
+    683, 683, 683, 683, 683, 683, 683, 682, 682, 682, 682, 682, 682, 682, 
+    682, 682, 682, 682, 682, 682, 682, 684, 685, 685, 685, 685, 685, 685, 
+    685, 64, 64, 64, 64, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 
+    686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 687, 687, 687, 687, 
+    687, 687, 687, 687, 687, 687, 64, 64, 64, 64, 64, 64, 64, 684, 688, 688, 
+    689, 690, 690, 690, 690, 690, 690, 690, 690, 690, 690, 690, 690, 690, 
+    689, 689, 689, 688, 688, 688, 688, 689, 689, 691, 692, 693, 693, 694, 
+    693, 693, 693, 693, 64, 64, 64, 64, 64, 64, 695, 695, 695, 695, 695, 695, 
+    695, 695, 695, 64, 64, 64, 64, 64, 64, 64, 696, 696, 696, 696, 696, 696, 
+    696, 696, 696, 696, 64, 64, 64, 64, 64, 64, 697, 697, 697, 698, 698, 698, 
+    698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 
+    698, 698, 698, 699, 699, 699, 699, 699, 700, 699, 699, 699, 699, 699, 
+    699, 701, 701, 64, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 703, 
+    703, 703, 703, 64, 64, 64, 64, 704, 704, 704, 704, 704, 704, 704, 704, 
+    704, 704, 704, 705, 706, 706, 704, 64, 707, 707, 708, 709, 709, 709, 709, 
+    709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 708, 708, 
+    708, 707, 707, 707, 707, 707, 707, 707, 707, 707, 708, 710, 709, 709, 
+    709, 709, 711, 711, 711, 711, 711, 712, 707, 707, 711, 64, 64, 713, 713, 
+    713, 713, 713, 713, 713, 713, 713, 713, 709, 711, 709, 711, 711, 711, 64, 
+    714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, 
+    714, 714, 714, 714, 714, 714, 64, 64, 64, 715, 715, 715, 715, 715, 715, 
+    715, 715, 715, 715, 64, 715, 715, 715, 715, 715, 715, 715, 715, 715, 716, 
+    716, 716, 717, 717, 717, 716, 716, 717, 718, 719, 717, 720, 720, 720, 
+    720, 720, 720, 64, 64, 721, 721, 721, 721, 721, 721, 721, 64, 721, 64, 
+    721, 721, 721, 721, 64, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 
+    721, 721, 721, 721, 721, 64, 721, 721, 722, 64, 64, 64, 64, 64, 64, 723, 
+    723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 
+    724, 725, 725, 725, 724, 724, 724, 724, 724, 724, 726, 727, 64, 64, 64, 
+    64, 64, 728, 728, 728, 728, 728, 728, 728, 728, 728, 728, 64, 64, 64, 64, 
+    64, 64, 729, 729, 730, 730, 64, 731, 731, 731, 731, 731, 731, 731, 731, 
+    64, 64, 731, 731, 64, 64, 731, 731, 731, 731, 731, 731, 731, 731, 731, 
+    731, 731, 731, 731, 731, 64, 731, 731, 731, 731, 731, 731, 731, 64, 731, 
+    731, 64, 731, 731, 731, 731, 731, 64, 64, 732, 731, 730, 730, 729, 730, 
+    730, 730, 730, 64, 64, 730, 730, 64, 64, 730, 730, 733, 64, 64, 731, 64, 
+    64, 64, 64, 64, 64, 730, 64, 64, 64, 64, 64, 731, 731, 731, 731, 731, 
+    730, 730, 64, 64, 734, 734, 734, 734, 734, 734, 734, 64, 64, 64, 735, 
+    735, 735, 735, 735, 735, 735, 735, 736, 736, 736, 737, 737, 737, 737, 
+    737, 737, 736, 737, 736, 736, 736, 736, 737, 737, 736, 738, 739, 735, 
+    735, 740, 735, 741, 741, 741, 741, 741, 741, 741, 741, 741, 741, 64, 64, 
+    64, 64, 64, 64, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 
+    742, 742, 742, 742, 743, 743, 743, 744, 744, 744, 744, 64, 64, 743, 743, 
+    743, 743, 744, 744, 743, 745, 746, 747, 747, 747, 747, 747, 747, 747, 
+    747, 747, 747, 747, 747, 747, 747, 747, 742, 742, 742, 742, 744, 744, 64, 
+    64, 748, 748, 748, 748, 748, 748, 748, 748, 749, 749, 749, 750, 750, 750, 
+    750, 750, 750, 750, 750, 749, 749, 750, 749, 751, 750, 752, 752, 752, 
+    748, 64, 64, 64, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 64, 
+    64, 64, 64, 64, 64, 754, 754, 754, 754, 754, 754, 754, 754, 754, 754, 
+    754, 755, 756, 755, 756, 756, 755, 755, 755, 755, 755, 755, 757, 758, 
+    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 64, 64, 64, 64, 64, 64, 
+    760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 64, 64, 64, 761, 761, 
+    761, 762, 762, 761, 761, 761, 761, 762, 761, 761, 761, 761, 763, 64, 64, 
+    64, 64, 764, 764, 764, 764, 764, 764, 764, 764, 764, 764, 765, 765, 766, 
+    766, 766, 767, 768, 768, 768, 768, 768, 768, 768, 768, 769, 769, 769, 
+    769, 769, 769, 769, 769, 770, 770, 770, 770, 770, 770, 770, 770, 770, 
+    770, 771, 771, 771, 771, 771, 771, 771, 771, 771, 64, 64, 64, 64, 64, 64, 
+    64, 64, 64, 64, 64, 64, 772, 773, 773, 773, 773, 773, 773, 773, 773, 773, 
+    64, 64, 64, 64, 64, 64, 64, 774, 774, 774, 774, 774, 774, 774, 774, 774, 
+    774, 64, 64, 64, 64, 64, 64, 775, 775, 775, 775, 775, 775, 775, 775, 775, 
+    775, 775, 775, 775, 775, 775, 64, 776, 776, 776, 776, 776, 64, 64, 64, 
+    774, 774, 774, 774, 64, 64, 64, 64, 777, 777, 777, 777, 777, 777, 777, 
+    777, 777, 777, 777, 777, 777, 777, 777, 64, 778, 778, 778, 778, 778, 778, 
+    778, 778, 778, 778, 778, 778, 778, 778, 778, 64, 511, 64, 64, 64, 64, 64, 
+    64, 64, 779, 779, 779, 779, 779, 779, 779, 779, 779, 779, 779, 779, 779, 
+    779, 779, 64, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 64, 64, 
+    64, 64, 781, 781, 782, 782, 782, 782, 782, 782, 782, 782, 782, 782, 782, 
+    782, 782, 782, 64, 64, 783, 783, 783, 783, 783, 784, 64, 64, 785, 785, 
+    785, 785, 785, 785, 785, 785, 786, 786, 786, 786, 786, 786, 786, 787, 
+    787, 787, 787, 787, 788, 788, 788, 788, 789, 789, 789, 789, 787, 788, 64, 
+    64, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 64, 791, 791, 791, 
+    791, 791, 791, 791, 64, 785, 785, 785, 785, 785, 64, 64, 64, 64, 64, 785, 
+    785, 785, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 
+    792, 64, 64, 64, 792, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 
+    793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 64, 64, 64, 
+    64, 64, 64, 64, 64, 794, 794, 794, 794, 795, 795, 795, 795, 795, 795, 
+    795, 795, 795, 795, 795, 795, 795, 486, 482, 64, 64, 64, 64, 64, 64, 796, 
+    796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 64, 64, 64, 64, 64, 
+    796, 796, 796, 796, 796, 64, 64, 64, 796, 64, 64, 64, 64, 64, 64, 64, 
+    796, 796, 64, 64, 797, 798, 799, 800, 410, 410, 410, 410, 64, 64, 64, 64, 
+    277, 277, 277, 277, 277, 277, 64, 64, 277, 277, 277, 277, 277, 277, 277, 
+    64, 64, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 801, 
+    801, 400, 400, 400, 277, 277, 277, 802, 801, 801, 801, 801, 801, 410, 
+    410, 410, 410, 410, 410, 410, 410, 136, 136, 136, 136, 136, 136, 136, 
+    136, 277, 277, 78, 78, 78, 78, 78, 136, 136, 277, 277, 277, 277, 277, 
+    277, 78, 78, 78, 78, 277, 277, 277, 64, 64, 64, 64, 64, 64, 64, 606, 606, 
+    803, 803, 803, 606, 64, 64, 521, 521, 64, 64, 64, 64, 64, 64, 442, 442, 
+    442, 442, 442, 442, 442, 442, 442, 442, 34, 34, 34, 34, 34, 34, 34, 34, 
+    34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 442, 442, 442, 442, 442, 442, 
+    442, 442, 442, 442, 34, 34, 34, 34, 34, 34, 34, 64, 34, 34, 34, 34, 34, 
+    34, 442, 64, 442, 442, 64, 64, 442, 64, 64, 442, 442, 64, 64, 442, 442, 
+    442, 442, 64, 442, 442, 34, 34, 64, 34, 64, 34, 34, 34, 34, 34, 34, 34, 
+    64, 34, 34, 34, 34, 34, 34, 34, 442, 442, 64, 442, 442, 442, 442, 64, 64, 
+    442, 442, 442, 442, 442, 442, 442, 442, 64, 442, 442, 442, 442, 442, 442, 
+    442, 64, 34, 34, 442, 442, 64, 442, 442, 442, 442, 64, 442, 442, 442, 
+    442, 442, 64, 442, 64, 64, 64, 442, 442, 442, 442, 442, 442, 442, 64, 34, 
+    34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 64, 64, 442, 804, 34, 34, 34, 
+    34, 34, 34, 34, 34, 34, 445, 34, 34, 34, 34, 34, 34, 442, 442, 442, 442, 
+    442, 442, 442, 442, 442, 804, 34, 34, 34, 34, 34, 34, 34, 34, 34, 445, 
+    34, 34, 442, 442, 442, 442, 442, 804, 34, 34, 34, 34, 34, 34, 34, 34, 34, 
+    445, 34, 34, 34, 34, 34, 34, 442, 442, 442, 442, 442, 442, 442, 442, 442, 
+    804, 34, 445, 34, 34, 34, 34, 34, 34, 34, 34, 442, 34, 64, 64, 805, 805, 
+    805, 805, 805, 805, 805, 805, 805, 805, 806, 806, 806, 806, 806, 806, 
+    806, 806, 807, 807, 807, 807, 807, 807, 807, 807, 807, 807, 807, 807, 
+    807, 807, 807, 806, 806, 806, 806, 807, 807, 807, 807, 807, 807, 807, 
+    807, 807, 807, 806, 806, 806, 806, 806, 806, 806, 806, 807, 806, 806, 
+    806, 806, 806, 806, 807, 806, 806, 808, 808, 808, 808, 808, 64, 64, 64, 
+    64, 64, 64, 64, 807, 807, 807, 807, 807, 64, 807, 807, 807, 807, 807, 
+    807, 807, 809, 809, 809, 809, 809, 809, 809, 809, 809, 809, 809, 809, 
+    809, 64, 64, 810, 810, 810, 810, 810, 810, 810, 810, 810, 811, 811, 811, 
+    811, 811, 811, 811, 64, 126, 126, 126, 126, 64, 126, 126, 126, 64, 126, 
+    126, 64, 126, 64, 64, 126, 64, 126, 126, 126, 126, 126, 126, 126, 126, 
+    126, 126, 64, 126, 126, 126, 126, 64, 126, 64, 126, 64, 64, 64, 64, 64, 
+    64, 126, 64, 64, 64, 64, 126, 64, 126, 64, 126, 64, 126, 126, 126, 64, 
+    126, 64, 126, 64, 126, 64, 126, 64, 126, 126, 126, 126, 64, 126, 64, 126, 
+    126, 64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 64, 64, 64, 64, 64, 
+    126, 126, 126, 64, 126, 126, 126, 113, 113, 64, 64, 64, 64, 64, 64, 64, 
+    26, 26, 26, 26, 26, 26, 26, 33, 33, 33, 446, 446, 64, 64, 64, 453, 453, 
+    453, 453, 453, 453, 277, 64, 453, 453, 26, 26, 64, 64, 64, 64, 453, 453, 
+    453, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 277, 277, 812, 489, 489, 
+    64, 64, 64, 64, 64, 489, 489, 489, 64, 64, 64, 64, 64, 489, 64, 64, 64, 
+    64, 64, 64, 64, 489, 489, 64, 64, 64, 64, 64, 64, 26, 26, 26, 47, 47, 47, 
+    47, 47, 26, 26, 64, 26, 26, 26, 26, 26, 26, 26, 26, 26, 64, 26, 26, 26, 
+    26, 64, 64, 64, 64, 64, 64, 64, 26, 26, 26, 26, 26, 64, 64, 64, 496, 496, 
+    496, 496, 496, 496, 496, 497, 496, 496, 496, 496, 496, 497, 497, 497, 
+    497, 497, 497, 497, 497, 497, 64, 64, 64, 410, 64, 64, 64, 64, 64, 64, 
+    410, 410, 410, 410, 410, 410, 410, 410, 565, 565, 565, 565, 565, 565, 64, 
+    64, 
 };
 
 /* decomposition data */
diff --git a/src/hb-unicode-private.hh b/src/hb-unicode-private.hh
index a2c59da..44fbe58 100644
--- a/src/hb-unicode-private.hh
+++ b/src/hb-unicode-private.hh
@@ -199,6 +199,50 @@
     }
   }
 
+  /* Space estimates based on:
+   * http://www.unicode.org/charts/PDF/U2000.pdf
+   * https://www.microsoft.com/typography/developers/fdsspec/spaces.aspx
+   */
+  enum space_t {
+    NOT_SPACE = 0,
+    SPACE_EM   = 1,
+    SPACE_EM_2 = 2,
+    SPACE_EM_3 = 3,
+    SPACE_EM_4 = 4,
+    SPACE_EM_5 = 5,
+    SPACE_EM_6 = 6,
+    SPACE_EM_16 = 16,
+    SPACE_4_EM_18,	/* 4/18th of an EM! */
+    SPACE,
+    SPACE_FIGURE,
+    SPACE_PUNCTUATION,
+    SPACE_NARROW,
+  };
+  static inline space_t
+  space_fallback_type (hb_codepoint_t u)
+  {
+    switch (u)
+    {
+      /* All GC=Zs chars that can use a fallback. */
+      default:	    return NOT_SPACE;	/* Shouldn't happen. */
+      case 0x0020u: return SPACE;	/* U+0020 SPACE */
+      case 0x00A0u: return SPACE;	/* U+00A0 NO-BREAK SPACE */
+      case 0x2000u: return SPACE_EM_2;	/* U+2000 EN QUAD */
+      case 0x2001u: return SPACE_EM;	/* U+2001 EM QUAD */
+      case 0x2002u: return SPACE_EM_2;	/* U+2002 EN SPACE */
+      case 0x2003u: return SPACE_EM;	/* U+2003 EM SPACE */
+      case 0x2004u: return SPACE_EM_3;	/* U+2004 THREE-PER-EM SPACE */
+      case 0x2005u: return SPACE_EM_4;	/* U+2005 FOUR-PER-EM SPACE */
+      case 0x2006u: return SPACE_EM_6;	/* U+2006 SIX-PER-EM SPACE */
+      case 0x2007u: return SPACE_FIGURE;	/* U+2007 FIGURE SPACE */
+      case 0x2008u: return SPACE_PUNCTUATION;	/* U+2008 PUNCTUATION SPACE */
+      case 0x2009u: return SPACE_EM_5;		/* U+2009 THIN SPACE */
+      case 0x200Au: return SPACE_EM_16;		/* U+200A HAIR SPACE */
+      case 0x202Fu: return SPACE_NARROW;	/* U+202F NARROW NO-BREAK SPACE */
+      case 0x205Fu: return SPACE_4_EM_18;	/* U+205F MEDIUM MATHEMATICAL SPACE */
+      case 0x3000u: return SPACE_EM;		/* U+3000 IDEOGRAPHIC SPACE */
+    }
+  }
 
   struct {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
@@ -308,10 +352,15 @@
 /* Misc */
 
 #define HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat) \
-	(FLAG (gen_cat) & \
+	(FLAG_SAFE (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 (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL)))
 
 #endif /* HB_UNICODE_PRIVATE_HH */
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index fc19006..487d10b 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -146,13 +146,8 @@
 }
 
 #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
-#ifdef _MSC_VER
-#pragma message("Could not find any Unicode functions implementation, you have to provide your own")
-#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
-#else
-#warning "Could not find any Unicode functions implementation, you have to provide your own"
-#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
-#endif
+#error "Could not find any Unicode functions implementation, you have to provide your own"
+#error "Consider building hb-ucdn.c.  If you absolutely want to build without any, check the code."
 #endif
 
 /**
@@ -163,7 +158,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
@@ -209,7 +204,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_empty (void)
@@ -225,7 +220,7 @@
  *
  * Return value: (transfer full):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
@@ -239,7 +234,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
@@ -268,7 +263,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
@@ -289,7 +284,7 @@
  *
  * Return value: (transfer none):
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void *
 hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
@@ -305,7 +300,7 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 void
 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
@@ -324,7 +319,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
@@ -340,7 +335,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
@@ -400,7 +395,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
@@ -422,7 +417,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 hb_bool_t
 hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
@@ -443,7 +438,7 @@
  *
  * Return value: 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
 unsigned int
 hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index 1c4e097..6a15cb0 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -174,23 +174,23 @@
 /*
  * just give me the best implementation you've got there.
  */
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
 hb_unicode_funcs_get_default (void);
 
 
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
 hb_unicode_funcs_create (hb_unicode_funcs_t *parent);
 
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
 hb_unicode_funcs_get_empty (void);
 
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
 hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs);
 
-void
+HB_EXTERN void
 hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
 			        hb_user_data_key_t *key,
 			        void *              data,
@@ -198,18 +198,18 @@
 				hb_bool_t           replace);
 
 
-void *
+HB_EXTERN void *
 hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
 			        hb_user_data_key_t *key);
 
 
-void
+HB_EXTERN void
 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs);
 
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
 hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
 
 
@@ -283,9 +283,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
 					   hb_unicode_combining_class_func_t func,
 					   void *user_data, hb_destroy_func_t destroy);
@@ -299,9 +299,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
 					   hb_unicode_eastasian_width_func_t func,
 					   void *user_data, hb_destroy_func_t destroy);
@@ -315,9 +315,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
 					    hb_unicode_general_category_func_t func,
 					    void *user_data, hb_destroy_func_t destroy);
@@ -331,9 +331,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
 				     hb_unicode_mirroring_func_t func,
 				     void *user_data, hb_destroy_func_t destroy);
@@ -347,9 +347,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
 				  hb_unicode_script_func_t func,
 				  void *user_data, hb_destroy_func_t destroy);
@@ -363,9 +363,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
 				   hb_unicode_compose_func_t func,
 				   void *user_data, hb_destroy_func_t destroy);
@@ -379,9 +379,9 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
 				     hb_unicode_decompose_func_t func,
 				     void *user_data, hb_destroy_func_t destroy);
@@ -395,47 +395,88 @@
  *
  * 
  *
- * Since: 1.0
+ * Since: 0.9.2
  **/
-void
+HB_EXTERN void
 hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
 						   hb_unicode_decompose_compatibility_func_t func,
 						   void *user_data, hb_destroy_func_t destroy);
 
 /* accessors */
 
-hb_unicode_combining_class_t
+/**
+ * hb_unicode_combining_class:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_unicode_combining_class_t
 hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
 			    hb_codepoint_t unicode);
 
-unsigned int
+/**
+ * hb_unicode_eastasian_width:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN unsigned int
 hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
 			    hb_codepoint_t unicode);
 
-hb_unicode_general_category_t
+/**
+ * hb_unicode_general_category:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_unicode_general_category_t
 hb_unicode_general_category (hb_unicode_funcs_t *ufuncs,
 			     hb_codepoint_t unicode);
 
-hb_codepoint_t
+/**
+ * hb_unicode_mirroring:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_codepoint_t
 hb_unicode_mirroring (hb_unicode_funcs_t *ufuncs,
 		      hb_codepoint_t unicode);
 
-hb_script_t
+/**
+ * hb_unicode_script:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_script_t
 hb_unicode_script (hb_unicode_funcs_t *ufuncs,
 		   hb_codepoint_t unicode);
 
-hb_bool_t
+/**
+ * hb_unicode_compose:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_bool_t
 hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
 		    hb_codepoint_t      a,
 		    hb_codepoint_t      b,
 		    hb_codepoint_t     *ab);
-hb_bool_t
+
+/**
+ * hb_unicode_decompose:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN hb_bool_t
 hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
 		      hb_codepoint_t      ab,
 		      hb_codepoint_t     *a,
 		      hb_codepoint_t     *b);
 
-unsigned int
+/**
+ * hb_unicode_decompose_compatibility:
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN unsigned int
 hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
 				    hb_codepoint_t      u,
 				    hb_codepoint_t     *decomposed);
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index e7bcad2..7fda678 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -486,14 +486,16 @@
   LOGFONTW log_font;
   HFONT hfont;
   SCRIPT_CACHE script_cache;
+  double x_mult, y_mult; /* From LOGFONT space to HB space. */
 };
 
 static bool
 populate_log_font (LOGFONTW  *lf,
-		   hb_font_t *font)
+		   hb_font_t *font,
+		   unsigned int font_size)
 {
   memset (lf, 0, sizeof (*lf));
-  lf->lfHeight = -font->y_scale;
+  lf->lfHeight = -font_size;
   lf->lfCharSet = DEFAULT_CHARSET;
 
   hb_face_t *face = font->face;
@@ -513,9 +515,19 @@
   if (unlikely (!data))
     return NULL;
 
+  int font_size = font->face->get_upem (); /* Default... */
+  /* No idea if the following is even a good idea. */
+  if (font->y_ppem)
+    font_size = font->y_ppem;
+
+  if (font_size < 0)
+    font_size = -font_size;
+  data->x_mult = (double) font->x_scale / font_size;
+  data->y_mult = (double) font->y_scale / font_size;
+
   data->hdc = GetDC (NULL);
 
-  if (unlikely (!populate_log_font (&data->log_font, font))) {
+  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;
@@ -907,7 +919,7 @@
 
     if (unlikely (items[i].a.fNoGlyphIndex))
       FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
-    if (unlikely (hr == E_OUTOFMEMORY))
+    if (unlikely (hr == E_OUTOFMEMORY || hr == E_NOT_SUFFICIENT_BUFFER))
     {
       if (unlikely (!buffer->ensure (buffer->allocated * 2)))
 	FAIL ("Buffer resize failed");
@@ -994,21 +1006,22 @@
 
     /* The rest is crap.  Let's store position info there for now. */
     info->mask = advances[i];
-    info->var1.u32 = offsets[i].du;
-    info->var2.u32 = offsets[i].dv;
+    info->var1.i32 = offsets[i].du;
+    info->var2.i32 = offsets[i].dv;
   }
 
   /* Set glyph positions */
   buffer->clear_positions ();
+  double x_mult = font_data->x_mult, y_mult = font_data->y_mult;
   for (unsigned int i = 0; i < glyphs_len; i++)
   {
     hb_glyph_info_t *info = &buffer->info[i];
     hb_glyph_position_t *pos = &buffer->pos[i];
 
     /* TODO vertical */
-    pos->x_advance = info->mask;
-    pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
-    pos->y_offset = info->var2.u32;
+    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;
   }
 
   if (backward)
diff --git a/src/hb-uniscribe.h b/src/hb-uniscribe.h
index 001ab38..4e4ef99 100644
--- a/src/hb-uniscribe.h
+++ b/src/hb-uniscribe.h
@@ -34,10 +34,10 @@
 HB_BEGIN_DECLS
 
 
-LOGFONTW *
+HB_EXTERN LOGFONTW *
 hb_uniscribe_font_get_logfontw (hb_font_t *font);
 
-HFONT
+HB_EXTERN HFONT
 hb_uniscribe_font_get_hfont (hb_font_t *font);
 
 
diff --git a/src/hb-utf-private.hh b/src/hb-utf-private.hh
index 0b798a0..74cf5d6 100644
--- a/src/hb-utf-private.hh
+++ b/src/hb-utf-private.hh
@@ -29,14 +29,11 @@
 
 #include "hb-private.hh"
 
-template <typename T, bool validate=true> struct hb_utf_t;
 
-
-/* UTF-8 */
-
-template <>
-struct hb_utf_t<uint8_t, true>
+struct hb_utf8_t
 {
+  typedef uint8_t codepoint_t;
+
   static inline const uint8_t *
   next (const uint8_t *text,
 	const uint8_t *end,
@@ -131,11 +128,10 @@
 };
 
 
-/* UTF-16 */
-
-template <>
-struct hb_utf_t<uint16_t, true>
+struct hb_utf16_t
 {
+  typedef uint16_t codepoint_t;
+
   static inline const uint16_t *
   next (const uint16_t *text,
 	const uint16_t *end,
@@ -150,11 +146,11 @@
       return text;
     }
 
-    if (likely (hb_in_range (c, 0xD800u, 0xDBFFu)))
+    if (likely (c <= 0xDBFFu && text < end))
     {
       /* High-surrogate in c */
-      hb_codepoint_t l;
-      if (text < end && ((l = *text), likely (hb_in_range (l, 0xDC00u, 0xDFFFu))))
+      hb_codepoint_t l = *text;
+      if (likely (hb_in_range (l, 0xDC00u, 0xDFFFu)))
       {
 	/* Low-surrogate in l */
 	*unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
@@ -174,8 +170,7 @@
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
-    const uint16_t *end = text--;
-    hb_codepoint_t c = *text;
+    hb_codepoint_t c = *--text;
 
     if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
     {
@@ -183,14 +178,22 @@
       return text;
     }
 
-    if (likely (start < text && hb_in_range (c, 0xDC00u, 0xDFFFu)))
-      text--;
+    if (likely (c >= 0xDC00u && start < text))
+    {
+      /* Low-surrogate in c */
+      hb_codepoint_t h = text[-1];
+      if (likely (hb_in_range (h, 0xD800u, 0xDBFFu)))
+      {
+        /* High-surrogate in h */
+        *unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);
+        text--;
+        return text;
+      }
+    }
 
-    if (likely (next (text, end, unicode, replacement) == end))
-      return text;
-
+    /* Lonely / out-of-order surrogate. */
     *unicode = replacement;
-    return end - 1;
+    return text;
   }
 
 
@@ -204,25 +207,20 @@
 };
 
 
-/* UTF-32 */
-
-template <bool validate>
-struct hb_utf_t<uint32_t, validate>
+template <bool validate=true>
+struct hb_utf32_t
 {
+  typedef uint32_t codepoint_t;
+
   static inline const uint32_t *
   next (const uint32_t *text,
 	const uint32_t *end HB_UNUSED,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
-    hb_codepoint_t c = *text++;
-    if (validate && unlikely (c > 0x10FFFFu || hb_in_range (c, 0xD800u, 0xDFFFu)))
-      goto error;
-    *unicode = c;
-    return text;
-
-  error:
-    *unicode = replacement;
+    hb_codepoint_t c = *unicode = *text++;
+    if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
+      *unicode = replacement;
     return text;
   }
 
@@ -232,8 +230,10 @@
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
-    next (text - 1, text, unicode, replacement);
-    return text - 1;
+    hb_codepoint_t c = *unicode = *--text;
+    if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
+      *unicode = replacement;
+    return text;
   }
 
   static inline unsigned int
@@ -246,4 +246,37 @@
 };
 
 
+struct hb_latin1_t
+{
+  typedef uint8_t codepoint_t;
+
+  static inline const uint8_t *
+  next (const uint8_t *text,
+	const uint8_t *end HB_UNUSED,
+	hb_codepoint_t *unicode,
+	hb_codepoint_t replacement HB_UNUSED)
+  {
+    *unicode = *text++;
+    return text;
+  }
+
+  static inline const uint8_t *
+  prev (const uint8_t *text,
+	const uint8_t *start HB_UNUSED,
+	hb_codepoint_t *unicode,
+	hb_codepoint_t replacement)
+  {
+    *unicode = *--text;
+    return text;
+  }
+
+  static inline unsigned int
+  strlen (const uint8_t *text)
+  {
+    unsigned int l = 0;
+    while (*text++) l++;
+    return l;
+  }
+};
+
 #endif /* HB_UTF_PRIVATE_HH */
diff --git a/src/hb-version.h b/src/hb-version.h
index 3561490..3456e7d 100644
--- a/src/hb-version.h
+++ b/src/hb-version.h
@@ -36,26 +36,26 @@
 HB_BEGIN_DECLS
 
 
-#define HB_VERSION_MAJOR 0
-#define HB_VERSION_MINOR 9
-#define HB_VERSION_MICRO 30
+#define HB_VERSION_MAJOR 1
+#define HB_VERSION_MINOR 2
+#define HB_VERSION_MICRO 1
 
-#define HB_VERSION_STRING "0.9.30"
+#define HB_VERSION_STRING "1.2.1"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
 	 HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
 
 
-void
+HB_EXTERN void
 hb_version (unsigned int *major,
 	    unsigned int *minor,
 	    unsigned int *micro);
 
-const char *
+HB_EXTERN const char *
 hb_version_string (void);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_version_atleast (unsigned int major,
 		    unsigned int minor,
 		    unsigned int micro);
diff --git a/src/hb-version.h.in b/src/hb-version.h.in
index 2517160..0ffd889 100644
--- a/src/hb-version.h.in
+++ b/src/hb-version.h.in
@@ -47,15 +47,15 @@
 	 HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
 
 
-void
+HB_EXTERN void
 hb_version (unsigned int *major,
 	    unsigned int *minor,
 	    unsigned int *micro);
 
-const char *
+HB_EXTERN const char *
 hb_version_string (void);
 
-hb_bool_t
+HB_EXTERN hb_bool_t
 hb_version_atleast (unsigned int major,
 		    unsigned int minor,
 		    unsigned int micro);
diff --git a/src/hb-warning.cc b/src/hb-warning.cc
index e0f88e2..8f322bc 100644
--- a/src/hb-warning.cc
+++ b/src/hb-warning.cc
@@ -29,27 +29,11 @@
 
 
 #if defined(HB_ATOMIC_INT_NIL)
-#ifdef _MSC_VER
-#pragma message("Could not find any system to define atomic_int macros, library may NOT be thread-safe")
-#else
-#warning "Could not find any system to define atomic_int macros, library may NOT be thread-safe"
-#endif
+#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe"
+#error "Check hb-atomic-private.hh for possible resolutions."
 #endif
 
 #if defined(HB_MUTEX_IMPL_NIL)
-#ifdef _MSC_VER
-#pragma message("Could not find any system to define mutex macros, library may NOT be thread-safe")
-#else
-#warning "Could not find any system to define mutex macros, library may NOT be thread-safe"
+#error "Could not find any system to define mutex macros, library WILL NOT be thread-safe"
+#error "Check hb-mutex-private.hh for possible resolutions."
 #endif
-#endif
-
-#if defined(HB_ATOMIC_INT_NIL) || defined(HB_MUTEX_IMPL_NIL)
-#ifdef _MSC_VER
-#pragma message("To suppress these warnings, define HB_NO_MT")
-#else
-#warning "To suppress these warnings, define HB_NO_MT"
-#endif
-#endif
-
-
diff --git a/src/hb.h b/src/hb.h
index c5a938a..7402034 100644
--- a/src/hb.h
+++ b/src/hb.h
@@ -28,6 +28,10 @@
 #define HB_H
 #define HB_H_IN
 
+#ifndef HB_EXTERN
+#define HB_EXTERN extern
+#endif
+
 #include "hb-blob.h"
 #include "hb-buffer.h"
 #include "hb-common.h"
diff --git a/src/sample.py b/src/sample.py
index f8d2216..19a4fdc 100755
--- a/src/sample.py
+++ b/src/sample.py
@@ -33,6 +33,12 @@
 hb.ot_font_set_funcs (font)
 
 buf = hb.buffer_create ()
+class Debugger(object):
+	def message (self, buf, font, msg, data, _x_what_is_this):
+		print(msg)
+		return True
+debugger = Debugger()
+hb.buffer_set_message_func (buf, debugger.message, 1, 0)
 hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
 hb.buffer_guess_segment_properties (buf)
 
diff --git a/src/test.cc b/src/test.cc
index a8fe046..0c90f8f 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -120,7 +120,7 @@
 	    info->cluster,
 	    info->codepoint,
 	    pos->x_offset,
-	    pos->x_offset,
+	    pos->y_offset,
 	    pos->x_advance,
 	    pos->y_advance);
 
diff --git a/test/Makefile.am b/test/Makefile.am
index 16a3cd2..ec77822 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,5 +1,9 @@
 # Process this file with automake to produce Makefile.in
 
-SUBDIRS = api shaping
+SUBDIRS = api shaping fuzzing
+
+# Convenience targets:
+lib:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
 
 -include $(top_srcdir)/git.mk
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index 4ff14fa..d7d40af 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -6,6 +6,10 @@
 DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 
+# Convenience targets:
+lib:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
 if HAVE_GLIB
 AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS)
 LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS)
@@ -34,7 +38,7 @@
 endif
 if HAVE_ICU
 test_unicode_CPPFLAGS += $(ICU_CFLAGS)
-test_unicode_LDADD += $(top_builddir)/src/libharfbuzz-icu.la
+test_unicode_LDADD += $(top_builddir)/src/libharfbuzz-icu.la $(ICU_LIBS)
 endif
 
 
diff --git a/test/api/test-font.c b/test/api/test-font.c
index 6b6a503..34f6c74 100644
--- a/test/api/test-font.c
+++ b/test/api/test-font.c
@@ -36,8 +36,8 @@
 test_face_empty (void)
 {
   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));
+  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));
 
   g_assert (hb_face_reference_table (hb_face_get_empty (), HB_TAG ('h','e','a','d')) == hb_blob_get_empty ());
 
@@ -115,6 +115,7 @@
   hb_codepoint_t glyph;
   hb_position_t x, y;
   hb_glyph_extents_t extents;
+  unsigned int upem = hb_face_get_upem (hb_font_get_face (font));
 
   x = y = 13;
   g_assert (!hb_font_get_glyph_contour_point (font, 17, 2, &x, &y));
@@ -122,7 +123,7 @@
   g_assert_cmpint (y, ==, 0);
 
   x = hb_font_get_glyph_h_advance (font, 17);
-  g_assert_cmpint (x, ==, 0);
+  g_assert_cmpint (x, ==, upem);
 
   extents.x_bearing = extents.y_bearing = 13;
   extents.width = extents.height = 15;
@@ -290,9 +291,22 @@
   x = hb_font_get_glyph_h_advance (font1, 2);
   g_assert_cmpint (x, ==, 0);
 
+  /* creating sub-font doesn't make the parent font immutable;
+   * making a font immutable however makes it's lineage immutable.
+   */
+  font2 = hb_font_create_sub_font (font1);
+  font3 = hb_font_create_sub_font (font2);
+  g_assert (!hb_font_is_immutable (font1));
+  g_assert (!hb_font_is_immutable (font2));
+  g_assert (!hb_font_is_immutable (font3));
+  hb_font_make_immutable (font3);
+  g_assert (hb_font_is_immutable (font1));
+  g_assert (hb_font_is_immutable (font2));
+  g_assert (hb_font_is_immutable (font3));
+  hb_font_destroy (font2);
+  hb_font_destroy (font3);
 
   font2 = hb_font_create_sub_font (font1);
-  g_assert (hb_font_is_immutable (font1));
   hb_font_destroy (font1);
 
   /* setup font2 to override some funcs */
@@ -316,12 +330,8 @@
   x = hb_font_get_glyph_h_advance (font2, 2);
   g_assert_cmpint (x, ==, 0);
 
-
-  font3 = hb_font_create_sub_font (font2);
-  g_assert (hb_font_is_immutable (font2));
-  hb_font_destroy (font2);
-
   /* setup font3 to override scale */
+  font3 = hb_font_create_sub_font (font2);
   hb_font_set_scale (font3, 20, 30);
 
   x = y = 1;
@@ -348,9 +358,9 @@
 test_font_empty (void)
 {
   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));
+  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));
   g_assert (hb_font_is_immutable (hb_font_get_empty ()));
 
   g_assert (hb_font_get_face (hb_font_get_empty ()) == hb_face_get_empty ());
@@ -366,6 +376,7 @@
   hb_font_t *subfont;
   int x_scale, y_scale;
   unsigned int x_ppem, y_ppem;
+  unsigned int upem;
 
   blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
   face = hb_face_create (blob, 0);
@@ -375,22 +386,35 @@
 
 
   g_assert (hb_font_get_face (font) == face);
-  g_assert (hb_font_get_parent (font) == NULL);
+  g_assert (hb_font_get_parent (font) == hb_font_get_empty ());
+  subfont = hb_font_create_sub_font (font);
+  g_assert (hb_font_get_parent (subfont) == font);
+  hb_font_set_parent(subfont, NULL);
+  g_assert (hb_font_get_parent (subfont) == hb_font_get_empty());
+  hb_font_set_parent(subfont, font);
+  g_assert (hb_font_get_parent (subfont) == font);
+  hb_font_set_parent(subfont, NULL);
+  hb_font_make_immutable (subfont);
+  g_assert (hb_font_get_parent (subfont) == hb_font_get_empty());
+  hb_font_set_parent(subfont, font);
+  g_assert (hb_font_get_parent (subfont) == hb_font_get_empty());
+  hb_font_destroy (subfont);
 
 
   /* Check scale */
 
+  upem = hb_face_get_upem (hb_font_get_face (font));
   hb_font_get_scale (font, NULL, NULL);
   x_scale = y_scale = 13;
   hb_font_get_scale (font, &x_scale, NULL);
-  g_assert_cmpint (x_scale, ==, 0);
+  g_assert_cmpint (x_scale, ==, upem);
   x_scale = y_scale = 13;
   hb_font_get_scale (font, NULL, &y_scale);
-  g_assert_cmpint (y_scale, ==, 0);
+  g_assert_cmpint (y_scale, ==, upem);
   x_scale = y_scale = 13;
   hb_font_get_scale (font, &x_scale, &y_scale);
-  g_assert_cmpint (x_scale, ==, 0);
-  g_assert_cmpint (y_scale, ==, 0);
+  g_assert_cmpint (x_scale, ==, upem);
+  g_assert_cmpint (y_scale, ==, upem);
 
   hb_font_set_scale (font, 17, 19);
 
diff --git a/test/api/test-object.c b/test/api/test-object.c
index 3afe6ae..02b9760 100644
--- a/test/api/test-object.c
+++ b/test/api/test-object.c
@@ -36,7 +36,7 @@
   return hb_blob_create (data, sizeof (data), HB_MEMORY_MODE_READONLY, NULL, NULL);
 }
 static void *
-create_blob_inert (void)
+create_blob_from_inert (void)
 {
   return hb_blob_create (NULL, 0, HB_MEMORY_MODE_DUPLICATE, NULL, NULL);
 }
@@ -47,7 +47,7 @@
   return hb_buffer_create ();
 }
 static void *
-create_buffer_inert (void)
+create_buffer_from_inert (void)
 {
   return NULL;
 }
@@ -58,7 +58,7 @@
   return hb_set_create ();
 }
 static void *
-create_set_inert (void)
+create_set_from_inert (void)
 {
   return NULL;
 }
@@ -72,7 +72,7 @@
   return face;
 }
 static void *
-create_face_inert (void)
+create_face_from_inert (void)
 {
   return hb_face_create (hb_blob_get_empty (), 0);
 }
@@ -86,7 +86,7 @@
   return font;
 }
 static void *
-create_font_inert (void)
+create_font_from_inert (void)
 {
   return hb_font_create (hb_face_get_empty ());
 }
@@ -97,7 +97,7 @@
   return hb_font_funcs_create ();
 }
 static void *
-create_font_funcs_inert (void)
+create_font_funcs_from_inert (void)
 {
   return NULL;
 }
@@ -108,9 +108,9 @@
   return hb_unicode_funcs_create (NULL);
 }
 static void *
-create_unicode_funcs_inert (void)
+create_unicode_funcs_from_inert (void)
 {
-  return hb_unicode_funcs_get_default ();
+  return hb_unicode_funcs_create (hb_unicode_funcs_get_empty ());
 }
 
 
@@ -125,7 +125,7 @@
 
 typedef struct {
   create_func_t          create;
-  create_func_t          create_inert;
+  create_func_t          create_from_inert;
   create_func_t          get_empty;
   reference_func_t       reference;
   destroy_func_t         destroy;
@@ -139,7 +139,7 @@
 #define OBJECT_WITHOUT_IMMUTABILITY(name) \
   { \
     (create_func_t)         create_##name, \
-    (create_func_t)         create_##name##_inert, \
+    (create_func_t)         create_##name##_from_inert, \
     (create_func_t)         hb_##name##_get_empty, \
     (reference_func_t)      hb_##name##_reference, \
     (destroy_func_t)        hb_##name##_destroy, \
@@ -152,7 +152,7 @@
 #define OBJECT_WITH_IMMUTABILITY(name) \
   { \
     (create_func_t)         create_##name, \
-    (create_func_t)         create_##name##_inert, \
+    (create_func_t)         create_##name##_from_inert, \
     (create_func_t)         hb_##name##_get_empty, \
     (reference_func_t)      hb_##name##_reference, \
     (destroy_func_t)        hb_##name##_destroy, \
@@ -340,8 +340,8 @@
     {
       data_t data[2] = {{MAGIC0, FALSE}, {MAGIC1, FALSE}};
 
-      g_test_message ("->create_inert()");
-      obj = o->create_inert ();
+      g_test_message ("->create_from_inert()");
+      obj = o->create_from_inert ();
       if (!obj)
 	continue;
       if (obj == o->get_empty ())
@@ -351,18 +351,14 @@
       o->destroy (obj);
 
       if (o->is_immutable)
-	g_assert (o->is_immutable (obj));
+	g_assert (!o->is_immutable (obj));
 
-      g_assert (!o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
-      g_assert (!o->get_user_data (obj, &key[0]));
+      g_assert (o->set_user_data (obj, &key[0], &data[0], free_up0, TRUE));
+      g_assert (o->get_user_data (obj, &key[0]));
 
       o->destroy (obj);
-      o->destroy (obj);
-      o->destroy (obj);
-      o->destroy (obj);
-      o->destroy (obj);
 
-      g_assert (!data[0].freed);
+      g_assert (data[0].freed);
     }
   }
 }
diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c
index b667c7d..29e0aa2 100644
--- a/test/api/test-ot-tag.c
+++ b/test/api/test-ot-tag.c
@@ -222,6 +222,13 @@
   test_tag_from_language ("XYZ", "xyz"); /* Unknown ISO 639-3 */
   test_tag_from_language ("XYZ", "xyz-qw"); /* Unknown ISO 639-3 */
 
+  /* International Phonetic Alphabet */
+  test_tag_from_language ("IPPH", "en-fonipa");
+  test_tag_from_language ("IPPH", "rm-CH-fonipa-sursilv-x-foobar");
+  test_tag_from_language ("IPPH", "und-fonipa");
+  test_tag_from_language ("IPPH", "zh-fonipa");
+  test_tag_to_language ("IPPH", "und-fonipa");
+
   /* Test that x-hbot overrides the base language */
   test_tag_from_language ("ABC", "fa-x-hbotabc-zxc");
   test_tag_from_language ("ABC", "fa-ir-x-hbotabc-zxc");
diff --git a/test/api/test-shape.c b/test/api/test-shape.c
index ccf6eed..eb24407 100644
--- a/test/api/test-shape.c
+++ b/test/api/test-shape.c
@@ -139,6 +139,48 @@
 }
 
 static void
+test_shape_clusters (void)
+{
+  hb_face_t *face;
+  hb_font_t *font;
+  hb_buffer_t *buffer;
+  unsigned int len;
+  hb_glyph_info_t *glyphs;
+
+  face = hb_face_create (NULL, 0);
+  font = hb_font_create (face);
+  hb_face_destroy (face);
+
+  buffer =  hb_buffer_create ();
+  hb_buffer_set_direction (buffer, HB_DIRECTION_LTR);
+  {
+    /* https://code.google.com/p/chromium/issues/detail?id=497578 */
+    hb_codepoint_t test[] = {0xFFF1, 0xF0B6};
+    hb_buffer_add_utf32 (buffer, test, 2, 0, 2);
+  }
+
+  hb_shape (font, buffer, NULL, 0);
+
+  len = hb_buffer_get_length (buffer);
+  glyphs = hb_buffer_get_glyph_infos (buffer, NULL);
+
+  {
+    const hb_codepoint_t output_glyphs[] = {0};
+    const hb_position_t output_clusters[] = {0};
+    unsigned int i;
+    g_assert_cmpint (len, ==, 1);
+    for (i = 0; i < len; i++) {
+      g_assert_cmphex (glyphs[i].codepoint, ==, output_glyphs[i]);
+      g_assert_cmphex (glyphs[i].cluster,   ==, output_clusters[i]);
+    }
+  }
+
+  hb_buffer_destroy (buffer);
+  hb_font_destroy (font);
+}
+
+
+static void
 test_shape_list (void)
 {
   const char **shapers = hb_shape_list_shapers ();
@@ -157,6 +199,7 @@
   hb_test_init (&argc, &argv);
 
   hb_test_add (test_shape);
+  hb_test_add (test_shape_clusters);
   /* TODO test fallback shaper */
   /* TODO test shaper_full */
   hb_test_add (test_shape_list);
diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am
new file mode 100644
index 0000000..7b0eb94
--- /dev/null
+++ b/test/fuzzing/Makefile.am
@@ -0,0 +1,52 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+
+# Convenience targets:
+lib:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src fuzzing
+
+$(top_builddir)/src/libharfbuzz-fuzzing.la: lib
+
+EXTRA_DIST += \
+	README \
+	$(NULL)
+
+check_PROGRAMS = \
+	hb-fuzzer \
+	$(NULL)
+
+AM_CPPFLAGS = \
+	-DHB_DISABLE_DEPRECATED \
+	-I$(top_srcdir)/src/ \
+	-I$(top_builddir)/src/ \
+	$(NULL)
+LDADD = \
+	$(top_builddir)/src/libharfbuzz-fuzzing.la \
+	$(NULL)
+
+hb_fuzzer_SOURCES = \
+	hb-fuzzer.cc \
+	$(NULL)
+hb_fuzzer_LDADD = \
+	$(LDADD) \
+	$(NULL)
+hb_fuzzer_CPPFLAGS = \
+	$(AM_CPPFLAGS) \
+	-DMAIN \
+	$(NULL)
+hb_fuzzer_DEPENDENCIES = \
+	lib \
+	$(NULL)
+
+check:
+	cat $(srcdir)/../shaping/tests/fuzzed.tests | \
+	cut -d: -f1 | while read x; do \
+		./hb-fuzzer $(srcdir)/../shaping/$$x; \
+	done
+
+-include $(top_srcdir)/git.mk
diff --git a/test/fuzzing/README b/test/fuzzing/README
new file mode 100644
index 0000000..c858f5d
--- /dev/null
+++ b/test/fuzzing/README
@@ -0,0 +1,21 @@
+In order to build the fuzzer one needs to build HarfBuzz and
+harfbuzz/test/fuzzing/hb-fuzzer.cc with:
+  - Using the most recent Clang
+  - With -fsanitize=address (or =undefined, or a combination)
+  - With -fsanitize-coverage=edge[,8bit-counters,trace-cmp]
+  - With various defines that limit worst case exponential behavior.
+    See FUZZING_CPPFLAGS in harfbuzz/src/Makefile.am for the list.
+  - link against libFuzzer
+
+To run the fuzzer one needs to first obtain a test corpus as a directory
+containing interesting fonts.  A good starting point is inside
+harfbuzz/test/shaping/fonts/fonts/.
+Then, run the fuzzer like this:
+   ./hb-fuzzer -max_len=2048 CORPUS_DIR
+Where max_len specifies the maximal length of font files to handle.
+The smaller the faster.
+
+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
diff --git a/test/fuzzing/hb-fuzzer.cc b/test/fuzzing/hb-fuzzer.cc
new file mode 100644
index 0000000..b319a71
--- /dev/null
+++ b/test/fuzzing/hb-fuzzer.cc
@@ -0,0 +1,61 @@
+#include <stddef.h>
+#include <hb.h>
+#include <hb-ot.h>
+#include <string.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+
+  hb_blob_t *blob = hb_blob_create((const char *)data, size,
+                                   HB_MEMORY_MODE_READONLY, NULL, NULL);
+  hb_face_t *face = hb_face_create(blob, 0);
+  hb_font_t *font = hb_font_create(face);
+  hb_ot_font_set_funcs(font);
+  hb_font_set_scale(font, 12, 12);
+
+  {
+    const char text[] = "ABCDEXYZ123@_%&)*$!";
+    hb_buffer_t *buffer = hb_buffer_create();
+    hb_buffer_add_utf8(buffer, text, -1, 0, -1);
+    hb_buffer_guess_segment_properties(buffer);
+    hb_shape(font, buffer, NULL, 0);
+    hb_buffer_destroy(buffer);
+  }
+
+  uint32_t text32[16];
+  if (size > sizeof(text32)) {
+    memcpy(text32, data + size - sizeof(text32), sizeof(text32));
+    hb_buffer_t *buffer = hb_buffer_create();
+    hb_buffer_add_utf32(buffer, text32, sizeof(text32)/sizeof(text32[0]), 0, -1);
+    hb_buffer_guess_segment_properties(buffer);
+    hb_shape(font, buffer, NULL, 0);
+    hb_buffer_destroy(buffer);
+  }
+
+
+  hb_font_destroy(font);
+  hb_face_destroy(face);
+  hb_blob_destroy(blob);
+  return 0;
+}
+
+#ifdef MAIN
+#include <iostream>
+#include <iterator>
+#include <fstream>
+#include <assert.h>
+
+std::string FileToString(const std::string &Path) {
+  /* TODO This silently passes if file does not exist.  Fix it! */
+  std::ifstream T(Path.c_str());
+  return std::string((std::istreambuf_iterator<char>(T)),
+                     std::istreambuf_iterator<char>());
+}
+
+int main(int argc, char **argv) {
+  for (int i = 1; i < argc; i++) {
+    std::string s = FileToString(argv[i]);
+    std::cout << argv[i] << std::endl;
+    LLVMFuzzerTestOneInput((const unsigned char*)s.data(), s.size());
+  }
+}
+#endif
diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am
index 70bcdd5..e70dff7 100644
--- a/test/shaping/Makefile.am
+++ b/test/shaping/Makefile.am
@@ -6,10 +6,15 @@
 DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 
+# Convenience targets:
+lib:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
 manifests:
 	@$(srcdir)/hb-manifest-update "$(srcdir)/texts" "$(srcdir)/fonts" "$(srcdir)/tests"
 
 EXTRA_DIST += \
+	README.md \
 	hb-diff \
 	hb-diff-colorize \
 	hb-diff-filter-failures \
@@ -38,12 +43,22 @@
 TESTS = \
 	tests/arabic-fallback-shaping.tests \
 	tests/arabic-feature-order.tests \
+	tests/cluster.tests \
 	tests/context-matching.tests \
+	tests/cursive-positioning.tests \
+	tests/default-ignorables.tests \
+	tests/fuzzed.tests \
 	tests/hangul-jamo.tests \
+	tests/hyphens.tests \
 	tests/indic-joiner-candrabindu.tests \
 	tests/indic-old-spec.tests \
 	tests/indic-pref-blocking.tests \
+	tests/ligature-id.tests \
 	tests/mongolian-variation-selector.tests \
+	tests/spaces.tests \
+	tests/simple.tests \
+	tests/use.tests \
+	tests/vertical.tests \
 	tests/zero-width-marks.tests \
 	$(NULL)
 
diff --git a/test/shaping/README.md b/test/shaping/README.md
new file mode 100644
index 0000000..bf09909
--- /dev/null
+++ b/test/shaping/README.md
@@ -0,0 +1,40 @@
+Adding tests
+============
+
+You can test shaping of a unicode sequence against a font like this:
+```sh
+$ ./hb-unicode-encode 41 42 43 627 | ../../util/hb-shape font.ttf
+```
+assuming an in-tree build.  The 41 42 43 627 here is a sequence of
+Unicode codepoints: U+0041,0042,0043,0627.  When you are happy with
+the shape results, you can use the `record-test.sh` script to add
+this to the test suite.  `record-test.sh` requires `pyftsubset` to
+be installed.  You can get `pyftsubset` by installing
+FontTools from <https://github.com/behdad/fonttools>.
+
+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
+```
+what this does is:
+  * Subset the font for the sequence of Unicode characters requested,
+  * Compare the `hb-shape` output of the original font versus the subset
+    font for the input sequence,
+  * If the outputs differ, perhaps it is because the font does not have
+    glyph names; it then compares the output of `hb-view` for both fonts.
+  * If the outputs differ, recording fails.  Otherwise, it will move the
+    subset font file into `fonts/sha1sum` and name it after its hash,
+    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
+```
+
+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.
+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!
+
+*Note!*  Please only add tests using Open Source fonts, preferably under
+OFL or similar license.
diff --git a/test/shaping/fonts/sha1sum/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf b/test/shaping/fonts/sha1sum/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf
new file mode 100644
index 0000000..2036031
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/051d92f8bc6ff724511b296c27623f824de256e9.ttf b/test/shaping/fonts/sha1sum/051d92f8bc6ff724511b296c27623f824de256e9.ttf
new file mode 100644
index 0000000..419f8f3
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/051d92f8bc6ff724511b296c27623f824de256e9.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/191826b9643e3f124d865d617ae609db6a2ce203.ttf b/test/shaping/fonts/sha1sum/191826b9643e3f124d865d617ae609db6a2ce203.ttf
new file mode 100644
index 0000000..dbc6e26
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/191826b9643e3f124d865d617ae609db6a2ce203.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf b/test/shaping/fonts/sha1sum/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf
new file mode 100644
index 0000000..c71e85a
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf b/test/shaping/fonts/sha1sum/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf
new file mode 100644
index 0000000..26d19ad
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf b/test/shaping/fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf
new file mode 100644
index 0000000..213e7ce
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf b/test/shaping/fonts/sha1sum/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf
new file mode 100644
index 0000000..7210658
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/205edd09bd3d141cc9580f650109556cc28b22cb.ttf b/test/shaping/fonts/sha1sum/205edd09bd3d141cc9580f650109556cc28b22cb.ttf
new file mode 100644
index 0000000..4e0ce0a
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/205edd09bd3d141cc9580f650109556cc28b22cb.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf b/test/shaping/fonts/sha1sum/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf
new file mode 100644
index 0000000..0d677a8
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/3511ff5c1647150595846ac414c595cccac34f18.ttf b/test/shaping/fonts/sha1sum/3511ff5c1647150595846ac414c595cccac34f18.ttf
new file mode 100644
index 0000000..789abf7
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/3511ff5c1647150595846ac414c595cccac34f18.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf b/test/shaping/fonts/sha1sum/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf
new file mode 100644
index 0000000..b284c98
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf b/test/shaping/fonts/sha1sum/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf
new file mode 100644
index 0000000..a5c0156
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/43ef465752be9af900745f72fe29cb853a1401a5.ttf b/test/shaping/fonts/sha1sum/43ef465752be9af900745f72fe29cb853a1401a5.ttf
new file mode 100644
index 0000000..649c156
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/43ef465752be9af900745f72fe29cb853a1401a5.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf b/test/shaping/fonts/sha1sum/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf
new file mode 100644
index 0000000..6ef470c
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf b/test/shaping/fonts/sha1sum/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf
new file mode 100644
index 0000000..ea1326d
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf b/test/shaping/fonts/sha1sum/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf
new file mode 100644
index 0000000..4795238
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf b/test/shaping/fonts/sha1sum/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf
new file mode 100644
index 0000000..9b4d23f
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/641bd9db850193064d17575053ae2bf8ec149ddc.ttf b/test/shaping/fonts/sha1sum/641bd9db850193064d17575053ae2bf8ec149ddc.ttf
new file mode 100644
index 0000000..66cefd4
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/641bd9db850193064d17575053ae2bf8ec149ddc.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/6466d38c62e73a39202435a4f73bf5d6acbb73c0.ttf b/test/shaping/fonts/sha1sum/6466d38c62e73a39202435a4f73bf5d6acbb73c0.ttf
new file mode 100644
index 0000000..33c4229
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/6466d38c62e73a39202435a4f73bf5d6acbb73c0.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf b/test/shaping/fonts/sha1sum/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf
new file mode 100644
index 0000000..eb5c50c
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf b/test/shaping/fonts/sha1sum/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf
new file mode 100644
index 0000000..a5787a8
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf b/test/shaping/fonts/sha1sum/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf
new file mode 100644
index 0000000..6bb13bd
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf b/test/shaping/fonts/sha1sum/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf
new file mode 100644
index 0000000..8eed14d
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/MANIFEST b/test/shaping/fonts/sha1sum/MANIFEST
deleted file mode 100644
index 924732d..0000000
--- a/test/shaping/fonts/sha1sum/MANIFEST
+++ /dev/null
@@ -1,19 +0,0 @@
-226bc2deab3846f1a682085f70c67d0421014144.ttf
-270b89df543a7e48e206a2d830c0e10e5265c630.ttf
-37033cc5cf37bb223d7355153016b6ccece93b28.ttf
-4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf
-5028afb650b1bb718ed2131e872fbcce57828fff.ttf
-57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf
-757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf
-7e14e7883ed152baa158b80e207b66114c823a8b.ttf
-813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf
-8454d22037f892e76614e1645d066689a0200e61.ttf
-8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf
-a919b33197965846f21074b24e30250d67277bce.ttf
-bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf
-bb9473d2403488714043bcfb946c9f78b86ad627.ttf
-d629e7fedc0b350222d7987345fe61613fa3929a.ttf
-df768b9c257e0c9c35786c47cae15c46571d56be.ttf
-e207635780b42f898d58654b65098763e340f5c7.ttf
-ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf
-f499fbc23865022234775c43503bba2e63978fe1.ttf
diff --git a/test/shaping/fonts/sha1sum/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf b/test/shaping/fonts/sha1sum/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf
new file mode 100644
index 0000000..8bbddb1
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf b/test/shaping/fonts/sha1sum/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf
new file mode 100644
index 0000000..500276d
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf b/test/shaping/fonts/sha1sum/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf
new file mode 100644
index 0000000..3b7c470
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf b/test/shaping/fonts/sha1sum/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf
new file mode 100644
index 0000000..99cda16
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf b/test/shaping/fonts/sha1sum/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf
new file mode 100644
index 0000000..a48d2a6
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.ttf b/test/shaping/fonts/sha1sum/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.ttf
new file mode 100644
index 0000000..039f5e8
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/f518eb6f6b5eec2946c9fbbbde44e45d46f5e2ac.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/fab39d60d758cb586db5a504f218442cd1395725.ttf b/test/shaping/fonts/sha1sum/fab39d60d758cb586db5a504f218442cd1395725.ttf
new file mode 100644
index 0000000..451ed04
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/fab39d60d758cb586db5a504f218442cd1395725.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf b/test/shaping/fonts/sha1sum/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf
new file mode 100644
index 0000000..d49432d
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/fbb6c84c9e1fe0c39e152fbe845e51fd81f6748e.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf b/test/shaping/fonts/sha1sum/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf
new file mode 100644
index 0000000..c4e0253
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf
Binary files differ
diff --git a/test/shaping/fonts/sha1sum/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf b/test/shaping/fonts/sha1sum/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf
new file mode 100644
index 0000000..224dbc6
--- /dev/null
+++ b/test/shaping/fonts/sha1sum/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf
Binary files differ
diff --git a/test/shaping/hb-diff b/test/shaping/hb-diff
index 6a13fa2..3705de7 100755
--- a/test/shaping/hb-diff
+++ b/test/shaping/hb-diff
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 import sys, os
diff --git a/test/shaping/hb-diff-colorize b/test/shaping/hb-diff-colorize
index 4e045d2..1fdae8a 100755
--- a/test/shaping/hb-diff-colorize
+++ b/test/shaping/hb-diff-colorize
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 
diff --git a/test/shaping/hb-diff-filter-failures b/test/shaping/hb-diff-filter-failures
index 4fe218a..34b76de 100755
--- a/test/shaping/hb-diff-filter-failures
+++ b/test/shaping/hb-diff-filter-failures
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 
diff --git a/test/shaping/hb-diff-ngrams b/test/shaping/hb-diff-ngrams
index a496447..c02f541 100755
--- a/test/shaping/hb-diff-ngrams
+++ b/test/shaping/hb-diff-ngrams
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 
diff --git a/test/shaping/hb-diff-stat b/test/shaping/hb-diff-stat
index 81626e1..12ee8f0 100755
--- a/test/shaping/hb-diff-stat
+++ b/test/shaping/hb-diff-stat
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 
diff --git a/test/shaping/hb-manifest-read b/test/shaping/hb-manifest-read
index f486bcc..b1b36ba 100755
--- a/test/shaping/hb-manifest-read
+++ b/test/shaping/hb-manifest-read
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 
diff --git a/test/shaping/hb-manifest-update b/test/shaping/hb-manifest-update
index b963f22..eeb84b8 100755
--- a/test/shaping/hb-manifest-update
+++ b/test/shaping/hb-manifest-update
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 
diff --git a/test/shaping/hb-unicode-decode b/test/shaping/hb-unicode-decode
index 5b00eae..9ac5ed6 100755
--- a/test/shaping/hb-unicode-decode
+++ b/test/shaping/hb-unicode-decode
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 
diff --git a/test/shaping/hb-unicode-encode b/test/shaping/hb-unicode-encode
index 11bf365..5889807 100755
--- a/test/shaping/hb-unicode-encode
+++ b/test/shaping/hb-unicode-encode
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 
diff --git a/test/shaping/hb-unicode-prettyname b/test/shaping/hb-unicode-prettyname
index ecc26cc..1d004c0 100755
--- a/test/shaping/hb-unicode-prettyname
+++ b/test/shaping/hb-unicode-prettyname
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 from hb_test_tools import *
 
diff --git a/test/shaping/hb_test_tools.py b/test/shaping/hb_test_tools.py
index a370e5e..747699b 100644
--- a/test/shaping/hb_test_tools.py
+++ b/test/shaping/hb_test_tools.py
@@ -1,11 +1,15 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
+from __future__ import print_function
 import sys, os, re, difflib, unicodedata, errno, cgi
 from itertools import *
 
 diff_symbols = "-+=*&^%$#@!~/"
 diff_colors = ['red', 'green', 'blue']
 
+if sys.version_info[0] >= 3:
+	unichr = chr
+
 class ColorFormatter:
 
 	class Null:
@@ -142,7 +146,7 @@
 						sys.stdout.writelines ([symbols[i], l])
 		except IOError as e:
 			if e.errno != errno.EPIPE:
-				print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)
+				print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr)
 				sys.exit (1)
 
 
@@ -215,7 +219,7 @@
 			else:
 				failed += 1
 		total = passed + failed
-		print "%d out of %d tests passed.  %d failed (%g%%)" % (passed, total, failed, 100. * failed / total)
+		print ("%d out of %d tests passed.  %d failed (%g%%)" % (passed, total, failed, 100. * failed / total))
 
 	@staticmethod
 	def print_ngrams (f, ns=(1,2,3)):
@@ -240,7 +244,7 @@
 		del importantgrams
 
 		for ngram, stats in allgrams.iteritems ():
-			print "zscore: %9f failed: %6d passed: %6d ngram: <%s>" % (stats.zscore (allstats), stats.failed.count, stats.passed.count, ','.join ("U+%04X" % u for u in ngram))
+			print ("zscore: %9f failed: %6d passed: %6d ngram: <%s>" % (stats.zscore (allstats), stats.failed.count, stats.passed.count, ','.join ("U+%04X" % u for u in ngram)))
 
 
 
@@ -310,7 +314,7 @@
 	def filter_printer_function (filter_callback):
 		def printer (f):
 			for line in filter_callback (f):
-				print line
+				print (line)
 		return printer
 
 	@staticmethod
@@ -344,7 +348,7 @@
 	def process_multiple_files (callback, mnemonic = "FILE"):
 
 		if "--help" in sys.argv:
-			print "Usage: %s %s..." % (sys.argv[0], mnemonic)
+			print ("Usage: %s %s..." % (sys.argv[0], mnemonic))
 			sys.exit (1)
 
 		try:
@@ -353,14 +357,14 @@
 				callback (FileHelpers.open_file_or_stdin (s))
 		except IOError as e:
 			if e.errno != errno.EPIPE:
-				print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)
+				print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr)
 				sys.exit (1)
 
 	@staticmethod
 	def process_multiple_args (callback, mnemonic):
 
 		if len (sys.argv) == 1 or "--help" in sys.argv:
-			print "Usage: %s %s..." % (sys.argv[0], mnemonic)
+			print ("Usage: %s %s..." % (sys.argv[0], mnemonic))
 			sys.exit (1)
 
 		try:
@@ -368,7 +372,7 @@
 				callback (s)
 		except IOError as e:
 			if e.errno != errno.EPIPE:
-				print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)
+				print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr)
 				sys.exit (1)
 
 	@staticmethod
@@ -377,8 +381,8 @@
 					      concat_separator = False):
 
 		if "--help" in sys.argv:
-			print "Usage:\n  %s %s...\nor:\n  %s\n\nWhen called with no arguments, input is read from standard input." \
-			      % (sys.argv[0], mnemonic, sys.argv[0])
+			print ("Usage:\n  %s %s...\nor:\n  %s\n\nWhen called with no arguments, input is read from standard input." \
+			      % (sys.argv[0], mnemonic, sys.argv[0]))
 			sys.exit (1)
 
 		try:
@@ -389,15 +393,15 @@
 						break
 					if line[-1] == '\n':
 						line = line[:-1]
-					print callback (line)
+					print (callback (line))
 			else:
 				args = sys.argv[1:]
 				if concat_separator != False:
 					args = [concat_separator.join (args)]
-				print separator.join (callback (x) for x in (args))
+				print (separator.join (callback (x) for x in (args)))
 		except IOError as e:
 			if e.errno != errno.EPIPE:
-				print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)
+				print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr)
 				sys.exit (1)
 
 
@@ -410,12 +414,14 @@
 	@staticmethod
 	def parse (s):
 		s = re.sub (r"0[xX]", " ", s)
-		s = re.sub (r"[<+>,;&#\\xXuU\n	]", " ", s)
+		s = re.sub (r"[<+>{},;&#\\xXuUnNiI\n	]", " ", s)
 		return [int (x, 16) for x in s.split ()]
 
 	@staticmethod
 	def encode (s):
-		return u''.join (unichr (x) for x in Unicode.parse (s)).encode ('utf-8')
+		s = u''.join (unichr (x) for x in Unicode.parse (s))
+		if sys.version_info[0] == 2: s = s.encode ('utf-8')
+		return s
 
 	shorthands = {
 		"ZERO WIDTH NON-JOINER": "ZWNJ",
@@ -471,7 +477,7 @@
 
 		if not os.path.exists (s):
 			if strict:
-				print >> sys.stderr, "%s: %s does not exist" % (sys.argv[0], s)
+				print ("%s: %s does not exist" % (sys.argv[0], s), file=sys.stderr)
 				sys.exit (1)
 			return
 
@@ -487,7 +493,7 @@
 						yield p
 			except IOError:
 				if strict:
-					print >> sys.stderr, "%s: %s does not exist" % (sys.argv[0], os.path.join (s, "MANIFEST"))
+					print ("%s: %s does not exist" % (sys.argv[0], os.path.join (s, "MANIFEST")), file=sys.stderr)
 					sys.exit (1)
 				return
 		else:
@@ -506,12 +512,12 @@
 			dirnames.sort ()
 			filenames.sort ()
 			ms = os.path.join (dirpath, "MANIFEST")
-			print "  GEN    %s" % ms
+			print ("  GEN    %s" % ms)
 			m = open (ms, "w")
 			for f in filenames:
-				print >> m, f
+				print (f, file=m)
 			for f in dirnames:
-				print >> m, f
+				print (f, file=m)
 			for f in dirnames:
 				Manifest.update_recursive (os.path.join (dirpath, f))
 
diff --git a/test/shaping/record-test.sh b/test/shaping/record-test.sh
index a69157f..b2a74f7 100755
--- a/test/shaping/record-test.sh
+++ b/test/shaping/record-test.sh
@@ -5,15 +5,47 @@
 hb_shape=$1
 shift
 fontfile=$1
+if test "x${fontfile:0:1}" == 'x-'; then
+	echo "Specify font file before other options." >&2
+	exit 1
+fi
 shift
-hb_shape="$hb_shape $@"
-unicodes=`./hb-unicode-decode`
-text=`./hb-unicode-encode "$unicodes"`
-glyphs=`echo "$text" | $hb_shape "$fontfile"`
+if ! echo "$hb_shape" | grep -q 'hb-shape'; then
+	echo "Specify hb-shape (not hb-view, etc)." >&2
+	exit 1
+fi
+options=
+have_text=false
+for arg in "$@"; do
+	if test "x${arg:0:1}" == 'x-'; then
+		if echo "$arg" | grep -q ' '; then
+			echo "Space in argument is not supported: '$arg'." >&2
+			exit 1
+		fi
+		options="$options${options:+ }$arg"
+		continue
+	fi
+	if $have_text; then
+		echo "Too many arguments found...  Use '=' notation for options: '$arg'" >&2
+		exit 1;
+	fi
+	text="$arg"
+	have_text=true
+done
+if ! $have_text; then
+	text=`cat`
+fi
+unicodes=`echo "$text" | ./hb-unicode-decode`
+glyphs=`echo "$text" | $hb_shape $options "$fontfile"`
+if test $? != 0; then
+	echo "hb-shape failed." >&2
+	exit 2
+fi
 
 cp "$fontfile" "$dir/font.ttf"
 pyftsubset \
 	--glyph-names \
+	--no-hinting \
 	"$dir/font.ttf" \
 	--text="$text"
 if ! test -s "$dir/font.ttf.subset"; then
@@ -22,14 +54,14 @@
 fi
 
 # Verify that subset font produces same glyphs!
-glyphs_subset=`echo "$text" | $hb_shape "$dir/font.ttf.subset"`
+glyphs_subset=`echo "$text" | $hb_shape $options "$dir/font.ttf.subset"`
 
 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 "$dir/font.ttf" --output-format=png --output-file="$dir/orig.png"
-	echo "$text" | $hb_view "$dir/font.ttf.subset" --output-format=png --output-file="$dir/subset.png"
+	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"
 	if ! cmp "$dir/orig.png" "$dir/subset.png"; then
 		echo "Images differ.  Please inspect $dir/*.png." >&2
 		echo "$glyphs"
@@ -46,7 +78,18 @@
 subset="fonts/sha1sum/$sha1sum.ttf"
 mv "$dir/font.ttf.subset" "$subset"
 
-echo "$subset:$unicodes:$glyphs"
+# There ought to be an easier way to do this, but it escapes me...
+unicodes_file=`mktemp`
+glyphs_file=`mktemp`
+echo "$unicodes" > "$unicodes_file"
+echo "$glyphs" > "$glyphs_file"
+# Open the "file"s
+exec 3<"$unicodes_file"
+exec 4<"$glyphs_file"
+while read uline <&3 && read gline <&4; do
+	echo "$subset:$options:$uline:$gline"
+done
+
 
 rm -f "$dir/font.ttf"
 rmdir "$dir"
diff --git a/test/shaping/run-tests.sh b/test/shaping/run-tests.sh
index a2cdf32..668bb8c 100755
--- a/test/shaping/run-tests.sh
+++ b/test/shaping/run-tests.sh
@@ -8,16 +8,31 @@
 
 fails=0
 
+reference=false
+if test "x$1" = x--reference; then
+	reference=true
+	shift
+fi
+
 if test $# = 0; then
 	set /dev/stdin
 fi
 
 IFS=:
 for f in "$@"; do
-	echo "Running tests in $f"
-	while read fontfile unicodes glyphs_expected; do
-		echo "Testing $fontfile:$unicodes"
-		glyphs=`$srcdir/hb-unicode-encode "$unicodes" | $hb_shape "$srcdir/$fontfile"`
+	$reference || echo "Running tests in $f"
+	while read fontfile options unicodes glyphs_expected; do
+		$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
@@ -27,8 +42,8 @@
 done
 
 if test $fails != 0; then
-	echo "$fails tests failed."
+	$reference || echo "$fails tests failed."
 	exit 1
 else
-	echo "All tests passed."
+	$reference || echo "All tests passed."
 fi
diff --git a/test/shaping/tests/MANIFEST b/test/shaping/tests/MANIFEST
deleted file mode 100644
index 849ebc5..0000000
--- a/test/shaping/tests/MANIFEST
+++ /dev/null
@@ -1,9 +0,0 @@
-arabic-fallback-shaping.tests
-arabic-feature-order.tests
-context-matching.tests
-hangul-jamo.tests
-indic-joiner-candrabindu.tests
-indic-old-spec.tests
-indic-pref-blocking.tests
-mongolian-variation-selector.tests
-zero-width-marks.tests
diff --git a/test/shaping/tests/arabic-fallback-shaping.tests b/test/shaping/tests/arabic-fallback-shaping.tests
index e3eaf3f..6f1cb8b 100644
--- a/test/shaping/tests/arabic-fallback-shaping.tests
+++ b/test/shaping/tests/arabic-fallback-shaping.tests
@@ -1 +1 @@
-fonts/sha1sum/df768b9c257e0c9c35786c47cae15c46571d56be.ttf:U+0633,U+064F,U+0644,U+064E,U+0651,U+0627,U+0651,U+0650,U+0645,U+062A,U+06CC:[uni06CC.fina=10+1655|uni062A.medi=9+868|uni0645.init=8+1098|uni0650=2@221,0+0|uni0651=2@260,736+0|uni064E=2@935,1259+0|uni0651=2@974,736+0|uni06440627.fina=2+1470|uni064F=0@558,-10+0|uni0633.init=0+1585]
+fonts/sha1sum/df768b9c257e0c9c35786c47cae15c46571d56be.ttf::U+0633,U+064F,U+0644,U+064E,U+0651,U+0627,U+0651,U+0650,U+0645,U+062A,U+06CC:[uni06CC.fina=10+1655|uni062A.medi=9+868|uni0645.init=8+1098|uni0650=2@221,0+0|uni0651=2@260,736+0|uni064E=2@935,1259+0|uni0651=2@974,736+0|uni06440627.fina=2+1470|uni064F=0@558,-10+0|uni0633.init=0+1585]
diff --git a/test/shaping/tests/arabic-feature-order.tests b/test/shaping/tests/arabic-feature-order.tests
index 3e3cf6a..e60ab1a 100644
--- a/test/shaping/tests/arabic-feature-order.tests
+++ b/test/shaping/tests/arabic-feature-order.tests
@@ -1,3 +1,3 @@
-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/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]
diff --git a/test/shaping/tests/cluster.tests b/test/shaping/tests/cluster.tests
new file mode 100644
index 0000000..24f04dd
--- /dev/null
+++ b/test/shaping/tests/cluster.tests
@@ -0,0 +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/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/context-matching.tests b/test/shaping/tests/context-matching.tests
index 4c7d25f..e20616e 100644
--- a/test/shaping/tests/context-matching.tests
+++ b/test/shaping/tests/context-matching.tests
@@ -1,3 +1,3 @@
-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+1212|uni1A25=3+1912|uni1A58=3+0|uni1A63=3+1212]
-fonts/sha1sum/d629e7fedc0b350222d7987345fe61613fa3929a.ttf:U+0915,U+093F,U+0915,U+093F:[ivowelsign03deva=0+530|kadeva=0+1561|ivowelsign03deva=2+530|kadeva=2+1561]
-fonts/sha1sum/f499fbc23865022234775c43503bba2e63978fe1.ttf:U+09B0,U+09CD,U+09A5,U+09CD,U+09AF,U+09C0:[gid1=0+1320|gid13=0+523|gid18=0+545]
+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/d629e7fedc0b350222d7987345fe61613fa3929a.ttf::U+0915,U+093F,U+0915,U+093F:[ivowelsign03deva=0+530|kadeva=0+1561|ivowelsign03deva=2+530|kadeva=2+1561]
+fonts/sha1sum/f499fbc23865022234775c43503bba2e63978fe1.ttf::U+09B0,U+09CD,U+09A5,U+09CD,U+09AF,U+09C0:[gid1=0+1320|gid13=0+523|gid18=0+545]
diff --git a/test/shaping/tests/cursive-positioning.tests b/test/shaping/tests/cursive-positioning.tests
new file mode 100644
index 0000000..503554f
--- /dev/null
+++ b/test/shaping/tests/cursive-positioning.tests
@@ -0,0 +1,3 @@
+fonts/sha1sum/c4e48b0886ef460f532fb49f00047ec92c432ec0.ttf::U+0643,U+0645,U+0645,U+062B,U+0644:[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+452|gid9=1@0,977+452|gid10=0@20,1577+207]
+fonts/sha1sum/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf::U+0643,U+0645,U+0645,U+062B,U+0644:[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+500|gid9=1@0,577+452|gid10=0@20,1177+207]
+fonts/sha1sum/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf::U+0B1F,U+0B4D,U+0B1A,U+0B4D,U+0B1A:[ttaorya=0+1307|casubscriptorya=0@-242,104+-231|casubscriptnarroworya=0@20,104+507]
diff --git a/test/shaping/tests/default-ignorables.tests b/test/shaping/tests/default-ignorables.tests
new file mode 100644
index 0000000..2d3ce97
--- /dev/null
+++ b/test/shaping/tests/default-ignorables.tests
@@ -0,0 +1 @@
+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]
diff --git a/test/shaping/tests/fuzzed.tests b/test/shaping/tests/fuzzed.tests
new file mode 100644
index 0000000..7a5d395
--- /dev/null
+++ b/test/shaping/tests/fuzzed.tests
@@ -0,0 +1,11 @@
+fonts/sha1sum/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/641bd9db850193064d17575053ae2bf8ec149ddc.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
+fonts/sha1sum/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf:--font-funcs=ot:U+0041:[gid0=0+4352]
+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/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]
diff --git a/test/shaping/tests/hangul-jamo.tests b/test/shaping/tests/hangul-jamo.tests
index 667a1cc..fe9973f 100644
--- a/test/shaping/tests/hangul-jamo.tests
+++ b/test/shaping/tests/hangul-jamo.tests
@@ -1,2 +1,2 @@
-fonts/sha1sum/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf:U+115F,U+11A2:[gid3=0+920|gid4=0+0]
-fonts/sha1sum/7e14e7883ed152baa158b80e207b66114c823a8b.ttf:U+11A2:[gid1=0+920]
+fonts/sha1sum/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf::U+115F,U+11A2:[gid3=0+920|gid4=0+0]
+fonts/sha1sum/7e14e7883ed152baa158b80e207b66114c823a8b.ttf::U+11A2:[gid1=0+920]
diff --git a/test/shaping/tests/hyphens.tests b/test/shaping/tests/hyphens.tests
new file mode 100644
index 0000000..d2cb186
--- /dev/null
+++ b/test/shaping/tests/hyphens.tests
@@ -0,0 +1,2 @@
+fonts/sha1sum/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf::U+2010:[gid1=0+739]
+fonts/sha1sum/1c04a16f32a39c26c851b7fc014d2e8d298ba2b8.ttf::U+2011:[gid1=0+739]
diff --git a/test/shaping/tests/indic-joiner-candrabindu.tests b/test/shaping/tests/indic-joiner-candrabindu.tests
index 351e927..80ad8ce 100644
--- a/test/shaping/tests/indic-joiner-candrabindu.tests
+++ b/test/shaping/tests/indic-joiner-candrabindu.tests
@@ -1,2 +1,2 @@
-fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf:U+0B13,U+200D,U+0B01:[omorya=0+1450]
-fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf:U+0B13,U+200C,U+0B01:[oorya=0+1309|space=1+0|candrabinduorya=1+0]
+fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200D,U+0B01:[omorya=0+1450]
+fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200C,U+0B01:[oorya=0+1309|space=0+0|candrabinduorya=0+0]
diff --git a/test/shaping/tests/indic-old-spec.tests b/test/shaping/tests/indic-old-spec.tests
index 96e8cdd..5410a6a 100644
--- a/test/shaping/tests/indic-old-spec.tests
+++ b/test/shaping/tests/indic-old-spec.tests
@@ -1,2 +1,2 @@
-fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf:U+0C9A,U+0CCD,U+0C9A,U+0CCD:[U0C9A_U0CCD.haln=0+1066|U0C9A_0CCD.blwf=0+0]
-fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf:U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D:[glyph201=0+1183|U0D4D=0+0]
+fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf::U+0C9A,U+0CCD,U+0C9A,U+0CCD:[U0C9A_U0CCD.haln=0+1066|U0C9A_0CCD.blwf=0+0]
+fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf::U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D:[glyph201=0+1183|U0D4D=0+0]
diff --git a/test/shaping/tests/indic-pref-blocking.tests b/test/shaping/tests/indic-pref-blocking.tests
index 260980a..204b92a 100644
--- a/test/shaping/tests/indic-pref-blocking.tests
+++ b/test/shaping/tests/indic-pref-blocking.tests
@@ -1,2 +1,2 @@
-fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf:U+0D2F,U+0D4D,U+0D30,U+0D46:[evowelsignmlym=0+1465|rapostmlym=0+499|yamlym=0+2120]
-fonts/sha1sum/e207635780b42f898d58654b65098763e340f5c7.ttf:U+0D2F,U+0D4D,U+0D30,U+0D46:[yamlym=0+2120|viramamlym=0+0|evowelsignmlym=0+1465|ramlym=0+1507]
+fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf::U+0D2F,U+0D4D,U+0D30,U+0D46:[evowelsignmlym=0+1465|rapostmlym=0+499|yamlym=0+2120]
+fonts/sha1sum/e207635780b42f898d58654b65098763e340f5c7.ttf::U+0D2F,U+0D4D,U+0D30,U+0D46:[yamlym=0+2120|viramamlym=0+0|evowelsignmlym=0+1465|ramlym=0+1507]
diff --git a/test/shaping/tests/ligature-id.tests b/test/shaping/tests/ligature-id.tests
new file mode 100644
index 0000000..a1ce2bb
--- /dev/null
+++ b/test/shaping/tests/ligature-id.tests
@@ -0,0 +1,35 @@
+fonts/sha1sum/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf::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|space=3+213|u0995_u09B0_u09CD.blwf.vatu=4+643|u0995_u09CD.half_u09B2.pres=7+602]
+fonts/sha1sum/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf::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|space=6+213|u0995_u09B0_u09CD.blwf.vatu=7+643|u0995_u09CD.half_u09B2.pres=10+602]
+fonts/sha1sum/1c2fb74c1b2aa173262734c1f616148f1648cfd6.ttf::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|space=9+213|u0995_u09B0_u09CD.blwf.vatu=10+643|u0995_u09CD.half_u09B2.pres=13+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+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|space=12+213|u0995_u09B0_u09CD.blwf.vatu=13+643|u0995_u09CD.half_u09B2.pres=16+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+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|space=15+213|u0995_u09B0_u09CD.blwf.vatu=16+643|u0995_u09CD.half_u09B2.pres=19+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+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|space=18+213|u0995_u09B0_u09CD.blwf.vatu=19+643|u0995_u09CD.half_u09B2.pres=22+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+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|space=21+213|u0995_u09B0_u09CD.blwf.vatu=22+643|u0995_u09CD.half_u09B2.pres=25+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+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|space=24+213|u0995_u09B0_u09CD.blwf.vatu=25+643|u0995_u09CD.half_u09B2.pres=28+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+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|space=27+213|u0995_u09B0_u09CD.blwf.vatu=28+643|u0995_u09CD.half_u09B2.pres=31+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+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|space=30+213|u0995_u09B0_u09CD.blwf.vatu=31+643|u0995_u09CD.half_u09B2.pres=34+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+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|space=33+213|u0995_u09B0_u09CD.blwf.vatu=34+643|u0995_u09CD.half_u09B2.pres=37+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+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|space=36+213|u0995_u09B0_u09CD.blwf.vatu=37+643|u0995_u09CD.half_u09B2.pres=40+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+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|space=39+213|u0995_u09B0_u09CD.blwf.vatu=40+643|u0995_u09CD.half_u09B2.pres=43+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+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|space=42+213|u0995_u09B0_u09CD.blwf.vatu=43+643|u0995_u09CD.half_u09B2.pres=46+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+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|space=45+213|u0995_u09B0_u09CD.blwf.vatu=46+643|u0995_u09CD.half_u09B2.pres=49+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+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|space=48+213|u0995_u09B0_u09CD.blwf.vatu=49+643|u0995_u09CD.half_u09B2.pres=52+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+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|space=51+213|u0995_u09B0_u09CD.blwf.vatu=52+643|u0995_u09CD.half_u09B2.pres=55+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+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|space=54+213|u0995_u09B0_u09CD.blwf.vatu=55+643|u0995_u09CD.half_u09B2.pres=58+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+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|space=57+213|u0995_u09B0_u09CD.blwf.vatu=58+643|u0995_u09CD.half_u09B2.pres=61+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+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|space=60+213|u0995_u09B0_u09CD.blwf.vatu=61+643|u0995_u09CD.half_u09B2.pres=64+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+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|space=63+213|u0995_u09B0_u09CD.blwf.vatu=64+643|u0995_u09CD.half_u09B2.pres=67+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+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|space=66+213|u0995_u09B0_u09CD.blwf.vatu=67+643|u0995_u09CD.half_u09B2.pres=70+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+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|space=69+213|u0995_u09B0_u09CD.blwf.vatu=70+643|u0995_u09CD.half_u09B2.pres=73+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+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|space=72+213|u0995_u09B0_u09CD.blwf.vatu=73+643|u0995_u09CD.half_u09B2.pres=76+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+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|space=75+213|u0995_u09B0_u09CD.blwf.vatu=76+643|u0995_u09CD.half_u09B2.pres=79+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+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|space=78+213|u0995_u09B0_u09CD.blwf.vatu=79+643|u0995_u09CD.half_u09B2.pres=82+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+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|space=81+213|u0995_u09B0_u09CD.blwf.vatu=82+643|u0995_u09CD.half_u09B2.pres=85+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+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|space=84+213|u0995_u09B0_u09CD.blwf.vatu=85+643|u0995_u09CD.half_u09B2.pres=88+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+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|space=87+213|u0995_u09B0_u09CD.blwf.vatu=88+643|u0995_u09CD.half_u09B2.pres=91+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+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|space=90+213|u0995_u09B0_u09CD.blwf.vatu=91+643|u0995_u09CD.half_u09B2.pres=94+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+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|space=93+213|u0995_u09B0_u09CD.blwf.vatu=94+643|u0995_u09CD.half_u09B2.pres=97+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+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|space=96+213|u0995_u09B0_u09CD.blwf.vatu=97+643|u0995_u09CD.half_u09B2.pres=100+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+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]
diff --git a/test/shaping/tests/mongolian-variation-selector.tests b/test/shaping/tests/mongolian-variation-selector.tests
index 6b7e94a..c24c9ba 100644
--- a/test/shaping/tests/mongolian-variation-selector.tests
+++ b/test/shaping/tests/mongolian-variation-selector.tests
@@ -1,3 +1,3 @@
-fonts/sha1sum/37033cc5cf37bb223d7355153016b6ccece93b28.ttf:U+1826,U+180B,U+1826:[uni1826.E85E_ue.init1=0+599|uni1826.E856_ue.fina=2+750]
-fonts/sha1sum/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf:U+1820,U+180B:[uni1820.E821_a.isol1=0+1199]
-fonts/sha1sum/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf:U+183A,U+1823,U+182E,U+182B,U+1822,U+1826,U+180B,U+1832,U+180B,U+1827,U+1837,U+0020,U+182D,U+182D,U+180B,U+0020,U+182D,U+180C,U+0020,U+182D,U+180D,U+200D,U+0020,U+182D,U+200D,U+182D,U+180B,U+200D,U+0020,U+182D,U+180C,U+200D,U+0020,U+182D,U+180D,U+200D,U+0020,U+200D,U+182D,U+200D,U+200D,U+182D,U+180B,U+200D,U+0020,U+200D,U+182D,U+180C,U+200D,U+0020,U+200D,U+182D,U+180D,U+200D,U+0020,U+200D,U+182D,U+200D,U+182D,U+180B,U+0020,U+200D,U+182D,U+180C,U+0020,U+1820,U+200C,U+182D,U+1820,U+1837,U+0020,U+1830,U+1824,U+1837,U+200D,U+200D,U+182D,U+1820,U+200D,U+0020,U+200D,U+182D,U+1824,U+182F,U+1822,U+0020,U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828:[uni183A1823.E971_ko.init=0+950|uni182E.E904_m.medi=2+400|uni182B1822.E8A6_pi.medi=3+1150|uni1826.E854_ue.medi1=5+1100|uni1832.E916_t.medi1=7+1000|uni1827.E85C_ee.medi=9+750|uni1837.E931_r.fina=10+750|space=11+500|uni182D.E8E2_g.init=12+1000|uni182D.E8E8_g.fina1=13+1250|space=15+500|uni182D.EA1B_g.isol2=16+1000|space=18+500|uni182D.EA1E_g.init3=19+650|space=21+0|space=22+500|uni182D.E8E2_g.init=23+1000|space=24+0|uni182D.E8E5_g.medi1=25+800|space=27+0|space=28+500|uni182D.EA1D_g.init2=29+950|space=31+0|space=32+500|uni182D.EA1E_g.init3=33+650|space=35+0|space=36+500|space=37+0|uni182D.E8E4_g.medi=38+800|space=39+0|space=40+0|uni182D.E8E5_g.medi1=41+800|space=43+0|space=44+500|space=45+0|uni182D.E8E6_g.medi2=46+650|space=48+0|space=49+500|space=50+0|uni182D.E8E6_g.medi2=51+650|space=53+0|space=54+500|space=55+0|uni182D.E8E4_g.medi=56+800|space=57+0|uni182D.E8E8_g.fina1=58+1250|space=60+500|space=61+0|uni182D.E8E9_g.fina2=62+1050|space=64+500|uni1820.E820_a.isol=65+1550|space=66+0|uni182D.E8E2_g.init=67+1000|uni1820.E823_a.medi=68+400|uni1837.E931_r.fina=69+750|space=70+500|uni1830.E90B_s.init=71+850|uni1824.E844_u.medi=72+600|uni1837.E930_r.medi=73+600|space=74+0|space=75+0|uni182D.E8E5_g.medi1=76+800|uni1820.E823_a.medi=77+400|space=78+0|space=79+500|space=80+0|uni182D.E8E5_g.medi1=81+800|uni1824.E844_u.medi=82+600|uni182F.E908_l.medi=83+400|uni1822.E837_i.fina=84+600|space=85+500|uni182A1820.E875_ba.init=86+1000|uni1822.E836_i.medi2=88+1000|uni182D.E8E8_g.fina1=89+1250|space=90+0|uni1820.E827_a.fina2=91+600|uni202F.nobreak=92+500|uni1836.E92B_y.init1=93+500|uni1822.E834_i.medi=94+500|uni1828.E866_n.fina=95+850]
+fonts/sha1sum/37033cc5cf37bb223d7355153016b6ccece93b28.ttf::U+1826,U+180B,U+1826:[uni1826.E85E_ue.init1=0+599|uni1826.E856_ue.fina=2+750]
+fonts/sha1sum/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf::U+1820,U+180B:[uni1820.E821_a.isol1=0+1199]
+fonts/sha1sum/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf::U+183A,U+1823,U+182E,U+182B,U+1822,U+1826,U+180B,U+1832,U+180B,U+1827,U+1837,U+0020,U+182D,U+182D,U+180B,U+0020,U+182D,U+180C,U+0020,U+182D,U+180D,U+200D,U+0020,U+182D,U+200D,U+182D,U+180B,U+200D,U+0020,U+182D,U+180C,U+200D,U+0020,U+182D,U+180D,U+200D,U+0020,U+200D,U+182D,U+200D,U+200D,U+182D,U+180B,U+200D,U+0020,U+200D,U+182D,U+180C,U+200D,U+0020,U+200D,U+182D,U+180D,U+200D,U+0020,U+200D,U+182D,U+200D,U+182D,U+180B,U+0020,U+200D,U+182D,U+180C,U+0020,U+1820,U+200C,U+182D,U+1820,U+1837,U+0020,U+1830,U+1824,U+1837,U+200D,U+200D,U+182D,U+1820,U+200D,U+0020,U+200D,U+182D,U+1824,U+182F,U+1822,U+0020,U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828:[uni183A1823.E971_ko.init=0+950|uni182E.E904_m.medi=2+400|uni182B1822.E8A6_pi.medi=3+1150|uni1826.E854_ue.medi1=5+1100|uni1832.E916_t.medi1=7+1000|uni1827.E85C_ee.medi=9+750|uni1837.E931_r.fina=10+750|space=11+500|uni182D.E8E2_g.init=12+1000|uni182D.E8E8_g.fina1=13+1250|space=15+500|uni182D.EA1B_g.isol2=16+1000|space=18+500|uni182D.EA1E_g.init3=19+650|space=19+0|space=22+500|uni182D.E8E2_g.init=23+1000|space=23+0|uni182D.E8E5_g.medi1=25+800|space=25+0|space=28+500|uni182D.EA1D_g.init2=29+950|space=29+0|space=32+500|uni182D.EA1E_g.init3=33+650|space=33+0|space=36+500|space=36+0|uni182D.E8E4_g.medi=38+800|space=38+0|space=38+0|uni182D.E8E5_g.medi1=41+800|space=41+0|space=44+500|space=44+0|uni182D.E8E6_g.medi2=46+650|space=46+0|space=49+500|space=49+0|uni182D.E8E6_g.medi2=51+650|space=51+0|space=54+500|space=54+0|uni182D.E8E4_g.medi=56+800|space=56+0|uni182D.E8E8_g.fina1=58+1250|space=60+500|space=60+0|uni182D.E8E9_g.fina2=62+1050|space=64+500|uni1820.E820_a.isol=65+1550|space=65+0|uni182D.E8E2_g.init=67+1000|uni1820.E823_a.medi=68+400|uni1837.E931_r.fina=69+750|space=70+500|uni1830.E90B_s.init=71+850|uni1824.E844_u.medi=72+600|uni1837.E930_r.medi=73+600|space=73+0|space=73+0|uni182D.E8E5_g.medi1=76+800|uni1820.E823_a.medi=77+400|space=77+0|space=79+500|space=79+0|uni182D.E8E5_g.medi1=81+800|uni1824.E844_u.medi=82+600|uni182F.E908_l.medi=83+400|uni1822.E837_i.fina=84+600|space=85+500|uni182A1820.E875_ba.init=86+1000|uni1822.E836_i.medi2=88+1000|uni182D.E8E8_g.fina1=89+1250|space=90+0|uni1820.E827_a.fina2=91+600|uni202F.nobreak=92+500|uni1836.E92B_y.init1=93+500|uni1822.E834_i.medi=94+500|uni1828.E866_n.fina=95+850]
diff --git a/test/shaping/tests/simple.tests b/test/shaping/tests/simple.tests
new file mode 100644
index 0000000..bebe008
--- /dev/null
+++ b/test/shaping/tests/simple.tests
@@ -0,0 +1,2 @@
+fonts/sha1sum/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf:--shaper=ot:U+0056,U+0041,U+0042,U+0045,U+0061,U+0062,U+0063,U+0064:[V=0+1142|A=1+1295|B=2+1295|E=3+1123|a=4+1126|b=5+1164|c=6+1072|d=7+1164]
+fonts/sha1sum/49c9f7485c1392fa09a1b801bc2ffea79275f22e.ttf:--shaper=fallback:U+0056,U+0041,U+0042,U+0045,U+0061,U+0062,U+0063,U+0064:[V=0+1295|A=1+1295|B=2+1295|E=3+1123|a=4+1126|b=5+1164|c=6+1072|d=7+1164]
diff --git a/test/shaping/tests/spaces.tests b/test/shaping/tests/spaces.tests
new file mode 100644
index 0000000..cb386de
--- /dev/null
+++ b/test/shaping/tests/spaces.tests
@@ -0,0 +1,17 @@
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+0020:[gid1=0+560]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+00A0:[gid1=0+560]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+1680:[gid0=0+692]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2000:[gid1=0+1024]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2001:[gid1=0+2048]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2002:[gid1=0+1024]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2003:[gid1=0+2048]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2004:[gid1=0+683]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2005:[gid1=0+512]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2006:[gid1=0+341]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2007:[gid1=0+560]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2008:[gid1=0+560]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2009:[gid1=0+410]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+200A:[gid1=0+128]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+202F:[gid1=0+280]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+205F:[gid1=0+455]
+fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+3000:[gid1=0+2048]
diff --git a/test/shaping/tests/use.tests b/test/shaping/tests/use.tests
new file mode 100644
index 0000000..e35259c
--- /dev/null
+++ b/test/shaping/tests/use.tests
@@ -0,0 +1,3 @@
+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]
diff --git a/test/shaping/tests/vertical.tests b/test/shaping/tests/vertical.tests
new file mode 100644
index 0000000..8276890
--- /dev/null
+++ b/test/shaping/tests/vertical.tests
@@ -0,0 +1 @@
+fonts/sha1sum/191826b9643e3f124d865d617ae609db6a2ce203.ttf:--direction=t:U+300C:[uni300C.vert=0@-512,-578+0,-1024]
diff --git a/test/shaping/tests/zero-width-marks.tests b/test/shaping/tests/zero-width-marks.tests
index be7ec96..c08f26b 100644
--- a/test/shaping/tests/zero-width-marks.tests
+++ b/test/shaping/tests/zero-width-marks.tests
@@ -1,2 +1,11 @@
-fonts/sha1sum/bb9473d2403488714043bcfb946c9f78b86ad627.ttf:U+1030:[circledash=0+636|u1030.med=0@-162,0+0]
-fonts/sha1sum/8454d22037f892e76614e1645d066689a0200e61.ttf:U+05E0,U+05B8,U+0591,U+05DA,U+05B0:[uni05DA05B0=3+991|uni2009=0+200|uni0591=0@75,0+0|uni05B8=0@495,0+0|uni05E0=0+683]
+fonts/sha1sum/bb9473d2403488714043bcfb946c9f78b86ad627.ttf::U+1030:[circledash=0+636|u1030.med=0@-162,0+0]
+fonts/sha1sum/8454d22037f892e76614e1645d066689a0200e61.ttf::U+05E0,U+05B8,U+0591,U+05DA,U+05B0:[uni05DA05B0=3+991|uni2009=0+200|uni0591=0@75,0+0|uni05B8=0@495,0+0|uni05E0=0+683]
+fonts/sha1sum/45855bc8d46332b39c4ab9e2ee1a26b1f896da6b.ttf::U+0E01,U+0E34,U+0E01:[gid1=0+1264|gid2=0@20,0+0|gid1=2+1264]
+fonts/sha1sum/7a37dc4d5bf018456aea291cee06daf004c0221c.ttf::U+0E01,U+0E34,U+0E01:[gid1=0+1264|gid2=0@20,0+1000|gid1=2+1264]
+fonts/sha1sum/8099955657a54e9ee38a6ba1d6f950ce58e3cc25.ttf::U+0E01,U+0E34,U+0E01:[gid1=0+1264|gid2=0+0|gid1=2+1264]
+fonts/sha1sum/bb0c53752e85c3d28973ebc913287b8987d3dfe8.ttf::U+0E01,U+0E34,U+0E01:[gid1=0+1264|gid2=0+0|gid1=2+1264]
+fonts/sha1sum/ffa0f5d2d9025486d8469d8b1fdd983e7632499b.ttf::U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A:[gid1=0+1200|gid6=0@-1029,340+0|gid3=2+1083|gid6=2@-992,0+0|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6@-693,0+0|gid5=8+528|gid6=8@-693,0+0|gid2=10+528|gid2=11+528]
+fonts/sha1sum/cc5f3d2d717fb6bd4dfae1c16d48a2cb8e12233b.ttf::U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A:[gid1=0+1200|gid6=0@-1029,340+1200|gid3=2+1083|gid6=2@-992,0+1200|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6@-693,0+1200|gid5=8+528|gid6=8@-693,0+1200|gid2=10+528|gid2=11+528]
+fonts/sha1sum/fcdcffbdf1c4c97c05308d7600e4c283eb47dbca.ttf::U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A:[gid1=0+1200|gid6=0+0|gid3=2+1083|gid6=2+0|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6+0|gid5=8+528|gid6=8+0|gid2=10+528|gid2=11+528]
+fonts/sha1sum/56cfd0e18d07f41c38e9598545a6d369127fc6f9.ttf::U+0058,U+0303,U+0078,U+0303,U+006A,U+006A,U+006A,U+0303,U+006A,U+0303,U+006A,U+006A:[gid1=0+1200|gid6=0@-1029,340+0|gid3=2+1083|gid6=2@-992,0+0|gid2=4+528|gid2=5+528|gid5=6+528|gid6=6@-693,0+0|gid5=8+528|gid6=8@-693,0+0|gid2=10+528|gid2=11+528]
+fonts/sha1sum/a98e908e2ed21b22228ea59ebcc0f05034c86f2e.ttf::U+0041,U+0042,U+0041:[A=0+1368|B=1+0|A=2+1368]
diff --git a/test/shaping/texts/MANIFEST b/test/shaping/texts/MANIFEST
deleted file mode 100644
index 26a3e67..0000000
--- a/test/shaping/texts/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-in-tree
diff --git a/test/shaping/texts/in-tree/MANIFEST b/test/shaping/texts/in-tree/MANIFEST
deleted file mode 100644
index f7a7a96..0000000
--- a/test/shaping/texts/in-tree/MANIFEST
+++ /dev/null
@@ -1,9 +0,0 @@
-shaper-arabic
-shaper-default
-shaper-hangul
-shaper-hebrew
-shaper-indic
-shaper-myanmar
-shaper-sea
-shaper-thai
-shaper-tibetan
diff --git a/test/shaping/texts/in-tree/shaper-arabic/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/MANIFEST
deleted file mode 100644
index eb8f9ec..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/MANIFEST
+++ /dev/null
@@ -1,6 +0,0 @@
-script-arabic
-script-mandaic
-script-mongolian
-script-nko
-script-phags-pa
-script-syriac
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/MANIFEST
deleted file mode 100644
index 62e050d..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-language-persian
-language-urdu
-misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-persian/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-persian/MANIFEST
deleted file mode 100644
index a6ac235..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-persian/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-mehran.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/MANIFEST
deleted file mode 100644
index 0c0a6f3..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-crulp
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/MANIFEST
deleted file mode 100644
index 5786e7b..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-ligatures
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/MANIFEST
deleted file mode 100644
index c945d0e..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/MANIFEST
+++ /dev/null
@@ -1,7 +0,0 @@
-2grams.txt
-3grams.txt
-4grams.txt
-5grams.txt
-6grams.txt
-7grams.txt
-8grams.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/MANIFEST
deleted file mode 100644
index 0ac75c3..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-diacritics
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/MANIFEST
deleted file mode 100644
index c71d035..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/MANIFEST
+++ /dev/null
@@ -1,7 +0,0 @@
-lam-alef.txt
-language-arabic.txt
-language-persian.txt
-language-urdu.txt
-ligature-components.txt
-ligature-diacritics.txt
-mark-skipping.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/misc/MANIFEST
deleted file mode 100644
index e69de29..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/misc/MANIFEST
+++ /dev/null
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/MANIFEST
deleted file mode 100644
index 3c76c94..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/MANIFEST
+++ /dev/null
@@ -1,4 +0,0 @@
-misc.txt
-non-joining.txt
-poem.txt
-variation-selectors.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-nko/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-nko/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-nko/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-nko/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-nko/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-nko/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-syriac/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-syriac/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-syriac/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/MANIFEST
deleted file mode 100644
index ae45bdf..0000000
--- a/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-alaph.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/abbreviation-mark.txt b/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/abbreviation-mark.txt
new file mode 100644
index 0000000..a450678
--- /dev/null
+++ b/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/abbreviation-mark.txt
@@ -0,0 +1,11 @@
+ܐܒ 
+ܐ܏ 
+ܐ܏ܒ 
+ܐ܏ܒܓ 
+ܐ܏ܒܓܕ 
+ܐ܏ܒܓܕܐ 
+ܐ܏ܒܓܕܐܐܐܐܐܐܐܐܐ 
+ܐ܏ܒܓܕܐ܏ܐܐܐ܏ܐ܏ܐܐܐܐ 
+ܐ܏ܒܓܕܓܓܓܓܓܓ 
+ܐ܏ܒܓ 
+܏ܫܘabcܒ.
diff --git a/test/shaping/texts/in-tree/shaper-default/MANIFEST b/test/shaping/texts/in-tree/shaper-default/MANIFEST
deleted file mode 100644
index d08deb7..0000000
--- a/test/shaping/texts/in-tree/shaper-default/MANIFEST
+++ /dev/null
@@ -1,5 +0,0 @@
-script-ethiopic
-script-han
-script-hiragana
-script-linear-b
-script-tifinagh
diff --git a/test/shaping/texts/in-tree/shaper-default/script-ethiopic/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-ethiopic/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-ethiopic/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-ethiopic/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-ethiopic/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-ethiopic/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-default/script-han/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-han/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-han/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-han/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-han/misc/MANIFEST
deleted file mode 100644
index 003c956..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-han/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-cjk-compat.txt
diff --git a/test/shaping/texts/in-tree/shaper-default/script-hiragana/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-hiragana/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-hiragana/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/MANIFEST
deleted file mode 100644
index 4d2d52c..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-kazuraki-liga-lines.txt
-kazuraki-liga.txt
diff --git a/test/shaping/texts/in-tree/shaper-default/script-linear-b/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-linear-b/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-linear-b/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-linear-b/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-linear-b/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-linear-b/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-default/script-tifinagh/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-tifinagh/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-tifinagh/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-tifinagh/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-tifinagh/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-default/script-tifinagh/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-hangul/script-hangul/MANIFEST b/test/shaping/texts/in-tree/shaper-hangul/script-hangul/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-hangul/script-hangul/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-hangul/script-hangul/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-hangul/script-hangul/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-hangul/script-hangul/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/MANIFEST b/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/misc/MANIFEST
deleted file mode 100644
index 06ca481..0000000
--- a/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-diacritics.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/MANIFEST
deleted file mode 100644
index 3f2011f..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-indic
-south-east-asian
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/MANIFEST
deleted file mode 100644
index 5e62ebf..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/MANIFEST
+++ /dev/null
@@ -1,11 +0,0 @@
-script-assamese
-script-bengali
-script-devanagari
-script-gujarati
-script-gurmukhi
-script-kannada
-script-malayalam
-script-oriya
-script-sinhala
-script-tamil
-script-telugu
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/misc/MANIFEST
deleted file mode 100644
index e69de29..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/misc/MANIFEST
+++ /dev/null
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/MANIFEST
deleted file mode 100644
index 0658824..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-codepoint
-gpos
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 1490dfe..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,7 +0,0 @@
-IndicFontFeatureCodepoint-AdditionalVowels.txt
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-Reserved.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/MANIFEST
deleted file mode 100644
index d7ae70e..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-IndicFontFeatureGPOS-AboveBase.txt
-IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/MANIFEST
deleted file mode 100644
index 3c2a4fb..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc.txt
-reph.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/MANIFEST
deleted file mode 100644
index 0658824..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-codepoint
-gpos
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 1490dfe..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,7 +0,0 @@
-IndicFontFeatureCodepoint-AdditionalVowels.txt
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-Reserved.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/MANIFEST
deleted file mode 100644
index d7ae70e..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-IndicFontFeatureGPOS-AboveBase.txt
-IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/MANIFEST
deleted file mode 100644
index c384b38..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/MANIFEST
+++ /dev/null
@@ -1,6 +0,0 @@
-dottedcircle.txt
-eyelash.txt
-joiners.txt
-misc.txt
-spec-deviations.txt
-tricky-reordering.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/MANIFEST
deleted file mode 100644
index 0658824..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-codepoint
-gpos
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 21eb56c..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,9 +0,0 @@
-IndicFontFeatureCodepoint-AdditionalConsonants.txt
-IndicFontFeatureCodepoint-AdditionalVowels.txt
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-GenericPunctuation.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/MANIFEST
deleted file mode 100644
index d7ae70e..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-IndicFontFeatureGPOS-AboveBase.txt
-IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/misc/MANIFEST
deleted file mode 100644
index e69de29..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/misc/MANIFEST
+++ /dev/null
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/MANIFEST
deleted file mode 100644
index 0658824..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-codepoint
-gpos
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 1490dfe..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,7 +0,0 @@
-IndicFontFeatureCodepoint-AdditionalVowels.txt
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-Reserved.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/MANIFEST
deleted file mode 100644
index d7ae70e..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-IndicFontFeatureGPOS-AboveBase.txt
-IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/MANIFEST
deleted file mode 100644
index 0658824..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-codepoint
-gpos
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/MANIFEST
deleted file mode 100644
index c213616..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,7 +0,0 @@
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-GurmukhiSpecific.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-Reserved.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/MANIFEST
deleted file mode 100644
index d7ae70e..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-IndicFontFeatureGPOS-AboveBase.txt
-IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/MANIFEST
deleted file mode 100644
index f53f999..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc.txt
-right-matras.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/MANIFEST
deleted file mode 100644
index 0658824..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-codepoint
-gpos
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 8fac7bc..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,8 +0,0 @@
-IndicFontFeatureCodepoint-AdditionalConsonants.txt
-IndicFontFeatureCodepoint-AdditionalVowels.txt
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-Reserved.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gpos/MANIFEST
deleted file mode 100644
index 49d0284..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gpos/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/MANIFEST
deleted file mode 100644
index 48800d4..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-cibu.txt
-dot-reph.txt
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/MANIFEST
deleted file mode 100644
index b389359..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-codepoint
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 1490dfe..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,7 +0,0 @@
-IndicFontFeatureCodepoint-AdditionalVowels.txt
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-Reserved.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/MANIFEST
deleted file mode 100644
index 66a2468..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-bindu.txt
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/MANIFEST
deleted file mode 100644
index b389359..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-codepoint
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 17fe498..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,9 +0,0 @@
-IndicFontFeatureCodepoint-AdditionalConsonants.txt
-IndicFontFeatureCodepoint-AdditionalVowels.txt
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-OriyaSpecific.txt
-IndicFontFeatureCodepoint-Reserved.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/MANIFEST
deleted file mode 100644
index a00d7ae..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/MANIFEST
+++ /dev/null
@@ -1,4 +0,0 @@
-extensive.txt
-misc.txt
-reph.txt
-split-matras.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/MANIFEST
deleted file mode 100644
index 0658824..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-codepoint
-gpos
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 48e393c..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,5 +0,0 @@
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-Punctuation.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gpos/MANIFEST
deleted file mode 100644
index f4d0fc3..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gpos/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGPOS.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/MANIFEST
deleted file mode 100644
index 6aa964b..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1,7 +0,0 @@
-IndicFontFeatureGSUB-Conjunct.txt
-IndicFontFeatureGSUB-Rakaaraansaya.txt
-IndicFontFeatureGSUB-Repaya.txt
-IndicFontFeatureGSUB-Special-Cases.txt
-IndicFontFeatureGSUB-TouchingLetters.txt
-IndicFontFeatureGSUB-Yansaya.txt
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/MANIFEST
deleted file mode 100644
index 0658824..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-codepoint
-gpos
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 3e28731..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,10 +0,0 @@
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-CurrencySymbols.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-Numerics.txt
-IndicFontFeatureCodepoint-Reserved.txt
-IndicFontFeatureCodepoint-Symbols.txt
-IndicFontFeatureCodepoint-TamilSymbol.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/MANIFEST
deleted file mode 100644
index d7ae70e..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-IndicFontFeatureGPOS-AboveBase.txt
-IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/MANIFEST
deleted file mode 100644
index ecb8d96..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc
-utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/MANIFEST
deleted file mode 100644
index 0658824..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-codepoint
-gpos
-gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/MANIFEST
deleted file mode 100644
index 1490dfe..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/MANIFEST
+++ /dev/null
@@ -1,7 +0,0 @@
-IndicFontFeatureCodepoint-AdditionalVowels.txt
-IndicFontFeatureCodepoint-Consonants.txt
-IndicFontFeatureCodepoint-DependentVowels.txt
-IndicFontFeatureCodepoint-Digits.txt
-IndicFontFeatureCodepoint-IndependentVowels.txt
-IndicFontFeatureCodepoint-Reserved.txt
-IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gpos/MANIFEST
deleted file mode 100644
index 49d0284..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gpos/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gsub/MANIFEST
deleted file mode 100644
index 4b47068..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gsub/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/south-east-asian/MANIFEST
deleted file mode 100644
index 9627b9e..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-script-khmer
diff --git a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/MANIFEST
deleted file mode 100644
index fde3fa1..0000000
--- a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-misc.txt
-other-marks-invalid.txt
-other-marks.txt
diff --git a/test/shaping/texts/in-tree/shaper-myanmar/MANIFEST b/test/shaping/texts/in-tree/shaper-myanmar/MANIFEST
deleted file mode 100644
index 895bcea..0000000
--- a/test/shaping/texts/in-tree/shaper-myanmar/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-script-myanmar
diff --git a/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/MANIFEST b/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/MANIFEST
deleted file mode 100644
index b5a09c0..0000000
--- a/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-misc.txt
-otspec.txt
-utn11.txt
diff --git a/test/shaping/texts/in-tree/shaper-sea/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/MANIFEST
deleted file mode 100644
index ba95488..0000000
--- a/test/shaping/texts/in-tree/shaper-sea/MANIFEST
+++ /dev/null
@@ -1,3 +0,0 @@
-script-cham
-script-new-tai-lue
-script-tai-tham
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-cham/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-cham/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-sea/script-cham/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-cham/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-cham/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-sea/script-cham/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/misc.txt b/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/misc.txt
deleted file mode 100644
index 11224a1..0000000
--- a/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/misc.txt
+++ /dev/null
@@ -1 +0,0 @@
-ᦀᦷᧃᧈ
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/MANIFEST
deleted file mode 100644
index cfc4f65..0000000
--- a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-misc.txt
-torture.txt
diff --git a/test/shaping/texts/in-tree/shaper-thai/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/MANIFEST
deleted file mode 100644
index 32b5476..0000000
--- a/test/shaping/texts/in-tree/shaper-thai/MANIFEST
+++ /dev/null
@@ -1,2 +0,0 @@
-script-lao
-script-thai
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-lao/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/script-lao/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-thai/script-lao/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-lao/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/script-lao/misc/MANIFEST
deleted file mode 100644
index ffd16f1..0000000
--- a/test/shaping/texts/in-tree/shaper-thai/script-lao/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-sara-am.txt
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-thai/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/script-thai/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-thai/script-thai/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/MANIFEST
deleted file mode 100644
index 6b5ca6f..0000000
--- a/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/MANIFEST
+++ /dev/null
@@ -1,4 +0,0 @@
-misc.txt
-phinthu.txt
-pua-shaping.txt
-sara-am.txt
diff --git a/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/MANIFEST b/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/MANIFEST
deleted file mode 100644
index b8752e7..0000000
--- a/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc
diff --git a/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/misc/MANIFEST
deleted file mode 100644
index 29cfb2f..0000000
--- a/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/misc/MANIFEST
+++ /dev/null
@@ -1 +0,0 @@
-misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-use/script-batak/misc.txt b/test/shaping/texts/in-tree/shaper-use/script-batak/misc.txt
new file mode 100644
index 0000000..c8ae04b
--- /dev/null
+++ b/test/shaping/texts/in-tree/shaper-use/script-batak/misc.txt
@@ -0,0 +1,9 @@
+ᯂᯩ
+ᯄ᯦ᯩ
+ᯇᯪᯰ
+ᯓᯩᯰ
+ᯄᯮ
+ᯃᯮ
+ᯎᯮ
+ᯞᯮ
+ᯖᯪᯇ᯲
diff --git a/test/shaping/texts/in-tree/shaper-use/script-buginese/misc.txt b/test/shaping/texts/in-tree/shaper-use/script-buginese/misc.txt
new file mode 100644
index 0000000..fe1b76d
--- /dev/null
+++ b/test/shaping/texts/in-tree/shaper-use/script-buginese/misc.txt
@@ -0,0 +1,70 @@
+ᨒᨚᨈᨑ
+ᨔᨑ
+ᨅᨔ ᨈᨚ ᨅᨙᨀ
+ᨕᨒᨚ ᨆᨒᨗᨕᨘ ᨅᨛᨈᨘᨕᨊ
+ᨕᨗᨉᨚ ᨔᨘᨑᨛ
+ᨕᨗᨊ ᨔᨘᨑᨛ
+ᨕᨊ ᨔᨘᨑᨛ
+
+ᨊᨀᨚ	ᨕᨛᨃ	ᨈᨕᨘᨄᨔᨒ᨞	ᨕᨍ	ᨆᨘᨄᨈᨒᨒᨚᨓᨗ	ᨄᨌᨒᨆᨘ	ᨑᨗᨈᨚᨄᨔᨒᨕᨙ᨞
+ᨄᨔᨗᨈᨘᨍᨘᨓᨗᨆᨘᨈᨚᨓᨗᨔ	ᨕᨔᨒᨊ	ᨄᨌᨒᨆᨘ᨞	ᨕᨄ	ᨕᨗᨀᨚᨊᨈᨘ	ᨊᨁᨗᨒᨗ	ᨉᨙᨓᨈᨕᨙ᨞
+ᨊᨀᨚ	ᨅᨕᨗᨌᨘᨆᨘᨄᨗ	ᨕᨔᨒᨊ	ᨈᨕᨘᨓᨙ᨞	ᨆᨘᨄᨙᨑᨍᨕᨗᨔ	ᨄᨉᨈᨚᨓᨗ᨞
+ᨊᨀᨚ	ᨄᨔᨒᨕᨗ	ᨈᨕᨘᨓᨙ᨞	ᨕᨍ	ᨈᨗᨆᨘᨌᨒᨕᨗ	ᨑᨗᨔᨗᨈᨗᨊᨍᨊᨕᨙᨈᨚᨔ	ᨕᨔᨒᨊ᨞
+
+ᨕᨛᨛᨃ	ᨕᨛᨃ	ᨄ ᨙᨑ᨞	ᨕᨛᨃ	 ᨙᨔᨕᨘᨓ	ᨓᨛᨈᨘ᨞
+ᨕᨛᨃ	 ᨙᨔᨕᨘᨓ	ᨕᨑᨘ	ᨆᨀᨘᨋᨕᨗ	ᨑᨗ	ᨒᨘᨓᨘ᨞	ᨆᨔᨒ	ᨕᨘᨒᨗ᨞
+
+ᨄᨘᨑᨊᨗᨀᨚ	ᨆᨙᨋ?
+ᨉᨙᨄ
+
+ᨆᨙᨒᨚ ᨀ ᨌᨛᨙᨆ
+ᨔᨙᨉᨗ	
+ᨉᨘᨓ	
+ᨈᨛᨒᨘ	
+ᨕᨛᨄ	
+ᨒᨗᨆ	
+ᨕᨛᨊᨛ	
+ᨄᨗᨈᨘ	
+ᨕᨑᨘᨓ	
+ᨕᨙᨔᨑ	
+ᨔᨄᨘᨒᨚ	
+ᨉᨘᨓᨄᨘᨒᨚ	
+ᨈᨛᨒᨘᨄᨘᨒᨚ	
+ᨄᨈᨄᨘᨒᨚ	
+ᨒᨗᨆᨄᨘᨒᨚ	
+ᨕᨛᨊᨛᨄᨘᨒᨚᨊ	
+ᨄᨗᨈᨘᨄᨘᨒᨚ	
+ᨕᨑᨘᨓᨄᨘᨒᨚᨊ	
+ᨕᨙᨔᨑᨄᨘᨒᨚᨊ	
+ᨔᨗᨑᨈᨘ	
+ᨔᨗᨔᨛᨅᨘ	
+ᨔᨗᨒᨔ	
+ᨔᨗᨀᨚᨈᨗ	
+
+ᨅᨔ ᨕᨘᨁᨗ
+
+ᨅᨔ ᨆᨀᨔᨑ
+ᨅᨒ	
+ᨅᨚᨒᨚ	
+ᨅᨅ	
+ᨌᨗᨄᨘᨑᨘ	
+ᨉᨚᨕᨙ	
+ᨕᨗᨐᨚ	
+ᨒᨚᨄᨚ	
+ᨔᨒᨚ	
+ᨈ ᨅᨙᨙ	
+ᨈᨙᨊ	
+ᨀᨑᨕᨙ	
+ᨕᨄ ᨀᨑᨙᨅ?	
+ᨒᨀᨙᨀᨚ ᨆᨕᨙ?	
+ᨅᨒ	
+ᨅᨚᨈᨚ	
+ᨑᨈᨔ	
+ᨅᨈᨒ	
+ᨅᨗᨒ	
+ᨁᨙᨒᨙ ᨁᨙᨒᨙ	
+ᨀᨚᨀᨚ	
+ᨍᨑ	
+ᨅᨙᨅᨙ	
+ᨆᨚᨈᨙᨑᨙ	
+ᨂᨑᨙ	
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-cham/misc/misc.txt b/test/shaping/texts/in-tree/shaper-use/script-cham/misc.txt
similarity index 100%
rename from test/shaping/texts/in-tree/shaper-sea/script-cham/misc/misc.txt
rename to test/shaping/texts/in-tree/shaper-use/script-cham/misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-use/script-kaithi/misc.txt b/test/shaping/texts/in-tree/shaper-use/script-kaithi/misc.txt
new file mode 100644
index 0000000..5503298
--- /dev/null
+++ b/test/shaping/texts/in-tree/shaper-use/script-kaithi/misc.txt
@@ -0,0 +1,6 @@
+𑂍   𑂎 𑂍𑂹𑂎 𑂍𑂹𑂎𑂱 𑂍𑂹𑂍𑂹𑂎𑂱 𑂍𑂹𑂎𑂹𑂎𑂱 𑂍𑂱 𑂍𑂹𑂍𑂹𑂎𑂱 𑂍𑂹𑂎𑂹𑂎𑂱𑂁 𑂍𑂹𑂎𑂹𑂎𑂱𑂀 𑂎𑂱𑂁
+𑂩𑂍 𑂩𑂹𑂍 𑂩𑂹𑂞 𑂩𑂹𑂍𑂹𑂍 𑂩𑂹𑂍
+𑂩𑂹𑂍𑂵 𑂩𑂹𑂍𑂵
+𑂩𑂍 𑂩𑂹𑂍 𑂩𑂹𑂞 𑂩𑂹𑂍𑂹𑂍 𑂩𑂹𑂍
+𑂩𑂹𑂍𑂵 𑂩𑂹𑂍𑂵
+𑂩𑂍 𑂩𑂹𑂍𑂱  𑂩𑂹𑂍𑂹𑂍𑂱  𑂩𑂹𑂍𑂹𑂍𑂵  𑂩𑂹𑂔𑂹𑂍𑂹𑂍𑂱 𑂩𑂹𑂞
diff --git a/test/shaping/texts/in-tree/shaper-use/script-kharoshti/misc.txt b/test/shaping/texts/in-tree/shaper-use/script-kharoshti/misc.txt
new file mode 100644
index 0000000..5a563c1
--- /dev/null
+++ b/test/shaping/texts/in-tree/shaper-use/script-kharoshti/misc.txt
@@ -0,0 +1,36 @@
+𐨤𐨪𐨌𐨪𐨿𐨗𐨸𐨅𐨌𐨏
+𐨀𐨁
+𐨐𐨁
+𐨠𐨁
+𐨀𐨂
+𐨱𐨂
+𐨨𐨂
+𐨀𐨃
+𐨨𐨃
+𐨀𐨅
+𐨐𐨅
+𐨠𐨅
+𐨡𐨅
+𐨀𐨆
+𐨤𐨆
+𐨨𐨌
+𐨯𐨍
+𐨀𐨎
+𐨐𐨏
+𐨗𐨸
+𐨒𐨹
+𐨨𐨺
+𐨢𐨁𐨐𐨿
+𐨐𐨿𐨮
+𐨨𐨿𐨪
+𐨬𐨿𐨱
+𐨯𐨿𐨟
+𐨯𐨿𐨩
+𐨪𐨿𐨟
+𐨟𐨿𐨪
+𐨫𐨿𐨤
+𐨤𐨿𐨫
+𐨐𐨿𐨫
+𐨟𐨿𐨬
+𐨐𐨿𐨟
+𐨑𐨿𐨐𐨿𐨮
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/misc.txt b/test/shaping/texts/in-tree/shaper-use/script-tai-tham/misc.txt
similarity index 100%
rename from test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/misc.txt
rename to test/shaping/texts/in-tree/shaper-use/script-tai-tham/misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/torture.txt b/test/shaping/texts/in-tree/shaper-use/script-tai-tham/torture.txt
similarity index 100%
rename from test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/torture.txt
rename to test/shaping/texts/in-tree/shaper-use/script-tai-tham/torture.txt
diff --git a/util/Makefile.am b/util/Makefile.am
index 266681c..2543a60 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -1,11 +1,16 @@
 # Process this file with automake to produce Makefile.in
 
-NULL =
 EXTRA_DIST =
 CLEANFILES =
 DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 
+include Makefile.sources
+
+# Convenience targets:
+lib:
+	@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
 bin_PROGRAMS =
 
 AM_CPPFLAGS = \
@@ -27,21 +32,7 @@
 
 if HAVE_FREETYPE
 if HAVE_CAIRO_FT
-hb_view_SOURCES = \
-	hb-view.cc \
-	options.cc \
-	options.hh \
-	main-font-text.hh \
-	shape-consumer.hh \
-	ansi-print.cc \
-	ansi-print.hh \
-	helper-cairo.cc \
-	helper-cairo.hh \
-	helper-cairo-ansi.cc \
-	helper-cairo-ansi.hh \
-	view-cairo.cc \
-	view-cairo.hh \
-	$(NULL)
+hb_view_SOURCES = $(HB_VIEW_sources)
 hb_view_LDADD = \
 	$(LDADD) \
 	$(CAIRO_LIBS) \
@@ -51,25 +42,29 @@
 endif # HAVE_CAIRO_FT
 endif # HAVE_FREETYPE
 
-hb_shape_SOURCES = \
-	hb-shape.cc \
-	options.cc \
-	options.hh \
-	main-font-text.hh \
-	shape-consumer.hh \
-	$(NULL)
+hb_shape_SOURCES = $(HB_SHAPE_sources)
 bin_PROGRAMS += hb-shape
 
 if HAVE_OT
-hb_ot_shape_closure_SOURCES = \
-	hb-ot-shape-closure.cc \
-	options.cc \
-	options.hh \
-	main-font-text.hh \
-	$(NULL)
+hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources)
 bin_PROGRAMS += hb-ot-shape-closure
 endif # HAVE_OT
 
 endif # HAVE_GLIB
 
+#if HAVE_OT
+#if HAVE_FONTCONFIG
+#hb_fc_list_SOURCES = \
+#	hb-fc.cc \
+#	hb-fc.h \
+#	hb-fc-list.c \
+#	$(NULL)
+#hb_fc_list_LDADD = \
+#	$(LDADD) \
+#	$(FONTCONFIG_LIBS) \
+#	$(NULL)
+#bin_PROGRAMS += hb-fc-list
+#endif # HAVE_FONTCONFIG
+#endif # HAVE_OT
+
 -include $(top_srcdir)/git.mk
diff --git a/util/Makefile.sources b/util/Makefile.sources
new file mode 100644
index 0000000..368fdb0
--- /dev/null
+++ b/util/Makefile.sources
@@ -0,0 +1,32 @@
+NULL =
+
+HB_VIEW_sources = \
+	hb-view.cc \
+	options.cc \
+	options.hh \
+	main-font-text.hh \
+	shape-consumer.hh \
+	ansi-print.cc \
+	ansi-print.hh \
+	helper-cairo.cc \
+	helper-cairo.hh \
+	helper-cairo-ansi.cc \
+	helper-cairo-ansi.hh \
+	view-cairo.cc \
+	view-cairo.hh \
+	$(NULL)
+
+HB_SHAPE_sources = \
+	hb-shape.cc \
+	options.cc \
+	options.hh \
+	main-font-text.hh \
+	shape-consumer.hh \
+	$(NULL)
+
+HB_OT_SHAPE_CLOSURE_sources = \
+	hb-ot-shape-closure.cc \
+	options.cc \
+	options.hh \
+	main-font-text.hh \
+	$(NULL)
diff --git a/util/ansi-print.cc b/util/ansi-print.cc
index 0fc3719..e0ce7b3 100644
--- a/util/ansi-print.cc
+++ b/util/ansi-print.cc
@@ -41,7 +41,7 @@
 #include <unistd.h> /* for isatty() */
 #endif
 
-#ifdef _MSC_VER
+#if defined (_MSC_VER) && (_MSC_VER < 1800)
 static inline long int
 lround (double x)
 {
@@ -52,6 +52,8 @@
 }
 #endif
 
+#define ESC_E (char)27
+
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 
 #define CELL_W 8
@@ -222,11 +224,12 @@
 };
 
 const char *
-block_best (const biimage_t &bi, unsigned int *score, bool *inverse)
+block_best (const biimage_t &bi, bool *inverse)
 {
   assert (bi.width  <= CELL_W);
   assert (bi.height <= CELL_H);
 
+  unsigned int score = (unsigned int) -1;
   unsigned int row_sum[CELL_H] = {0};
   unsigned int col_sum[CELL_W] = {0};
   unsigned int row_sum_i[CELL_H] = {0};
@@ -262,14 +265,14 @@
   const char *best_c = " ";
 
   /* Maybe empty is better! */
-  if (total < *score) {
-    *score = total;
+  if (total < score) {
+    score = total;
     *inverse = false;
     best_c = " ";
   }
   /* Maybe full is better! */
-  if (total_i < *score) {
-    *score = total_i;
+  if (total_i < score) {
+    score = total_i;
     *inverse = true;
     best_c = " ";
   }
@@ -295,11 +298,11 @@
 	best_inv = true;
       }
     }
-    if (best_s < *score) {
+    if (best_s < score) {
       static const char *lower[7] = {"▁", "▂", "▃", "▄", "▅", "▆", "▇"};
-      unsigned int which = lround (((best_i + 1) * 8) / bi.height);
+      unsigned int which = lround ((double) ((best_i + 1) * 8) / bi.height);
       if (1 <= which && which <= 7) {
-	*score = best_s;
+	score = best_s;
 	*inverse = best_inv;
 	best_c = lower[7 - which];
       }
@@ -327,11 +330,11 @@
 	best_inv = false;
       }
     }
-    if (best_s < *score) {
+    if (best_s < score) {
       static const char *left [7] = {"▏", "▎", "▍", "▌", "▋", "▊", "▉"};
-      unsigned int which = lround (((best_i + 1) * 8) / bi.width);
+      unsigned int which = lround ((double) ((best_i + 1) * 8) / bi.width);
       if (1 <= which && which <= 7) {
-	*score = best_s;
+	score = best_s;
 	*inverse = best_inv;
 	best_c = left[which - 1];
       }
@@ -349,7 +352,7 @@
 	  qs += quad_i[i][j];
 	} else
 	  qs += quad[i][j];
-    if (qs < *score) {
+    if (qs < score) {
       const char *c = NULL;
       bool inv = false;
       switch (q) {
@@ -365,7 +368,7 @@
 	case 14: c = "▟"; inv = true;  break;
       }
       if (c) {
-	*score = qs;
+	score = qs;
 	*inverse = inv;
 	best_c = c;
       }
@@ -394,24 +397,23 @@
       bi.set (cell);
       if (bi.unicolor) {
         if (last_bg != bi.bg) {
-	  printf ("\e[%dm", 40 + bi.bg);
+	  printf ("%c[%dm", ESC_E, 40 + bi.bg);
 	  last_bg = bi.bg;
 	}
 	printf (" ");
       } else {
         /* Figure out the closest character to the biimage */
-        unsigned int score = (unsigned int) -1;
 	bool inverse = false;
-        const char *c = block_best (bi, &score, &inverse);
+        const char *c = block_best (bi, &inverse);
 	if (inverse) {
 	  if (last_bg != bi.fg || last_fg != bi.bg) {
-	    printf ("\e[%d;%dm", 30 + bi.bg, 40 + bi.fg);
+	    printf ("%c[%d;%dm", ESC_E, 30 + bi.bg, 40 + bi.fg);
 	    last_bg = bi.fg;
 	    last_fg = bi.bg;
 	  }
 	} else {
 	  if (last_bg != bi.bg || last_fg != bi.fg) {
-	    printf ("\e[%d;%dm", 40 + bi.bg, 30 + bi.fg);
+	    printf ("%c[%d;%dm", ESC_E, 40 + bi.bg, 30 + bi.fg);
 	    last_bg = bi.bg;
 	    last_fg = bi.fg;
 	  }
@@ -419,7 +421,7 @@
 	printf ("%s", c);
       }
     }
-    printf ("\e[0m\n"); /* Reset */
+    printf ("%c[0m\n", ESC_E); /* Reset */
     last_bg = last_fg = -1;
   }
 }
diff --git a/util/hb-fc-list.c b/util/hb-fc-list.c
new file mode 100644
index 0000000..573d11e
--- /dev/null
+++ b/util/hb-fc-list.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright © 2002 Keith Packard
+ * Copyright © 2014  Google, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the author(s) not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The authors make no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#define HAVE_GETOPT_LONG 1 /* XXX */
+
+#include "hb-fc.h"
+
+#include <fontconfig/fontconfig.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#ifdef linux
+#define HAVE_GETOPT_LONG 1
+#endif
+#define HAVE_GETOPT 1
+#endif
+
+#ifndef HAVE_GETOPT
+#define HAVE_GETOPT 0
+#endif
+#ifndef HAVE_GETOPT_LONG
+#define HAVE_GETOPT_LONG 0
+#endif
+
+#if HAVE_GETOPT_LONG
+#undef  _GNU_SOURCE
+#define _GNU_SOURCE
+#include <getopt.h>
+const struct option longopts[] = {
+    {"verbose", 0, 0, 'v'},
+    {"format", 1, 0, 'f'},
+    {"quiet", 0, 0, 'q'},
+    {"version", 0, 0, 'V'},
+    {"help", 0, 0, 'h'},
+    {NULL,0,0,0},
+};
+#else
+#if HAVE_GETOPT
+extern char *optarg;
+extern int optind, opterr, optopt;
+#endif
+#endif
+
+static void
+usage (char *program, int error)
+{
+    FILE *file = error ? stderr : stdout;
+#if HAVE_GETOPT_LONG
+    fprintf (file, "usage: %s [-vqVh] [-f FORMAT] [--verbose] [--format=FORMAT] [--quiet] [--version] [--help] text [pattern] {element ...} \n",
+	     program);
+#else
+    fprintf (file, "usage: %s [-vqVh] [-f FORMAT] text [pattern] {element ...} \n",
+	     program);
+#endif
+    fprintf (file, "List fonts matching [pattern] that can render [text]\n");
+    fprintf (file, "\n");
+#if HAVE_GETOPT_LONG
+    fprintf (file, "  -v, --verbose        display entire font pattern verbosely\n");
+    fprintf (file, "  -f, --format=FORMAT  use the given output format\n");
+    fprintf (file, "  -q, --quiet          suppress all normal output, exit 1 if no fonts matched\n");
+    fprintf (file, "  -V, --version        display font config version and exit\n");
+    fprintf (file, "  -h, --help           display this help and exit\n");
+#else
+    fprintf (file, "  -v         (verbose) display entire font pattern verbosely\n");
+    fprintf (file, "  -f FORMAT  (format)  use the given output format\n");
+    fprintf (file, "  -q,        (quiet)   suppress all normal output, exit 1 if no fonts matched\n");
+    fprintf (file, "  -V         (version) display HarfBuzz version and exit\n");
+    fprintf (file, "  -h         (help)    display this help and exit\n");
+#endif
+    exit (error);
+}
+
+int
+main (int argc, char **argv)
+{
+    int			verbose = 0;
+    int			quiet = 0;
+    const FcChar8	*format = NULL;
+    int			nfont = 0;
+    int			i;
+    FcObjectSet		*os = 0;
+    FcFontSet		*fs;
+    FcPattern		*pat;
+    const char		*text;
+#if HAVE_GETOPT_LONG || HAVE_GETOPT
+    int			c;
+
+#if HAVE_GETOPT_LONG
+    while ((c = getopt_long (argc, argv, "vf:qVh", longopts, NULL)) != -1)
+#else
+    while ((c = getopt (argc, argv, "vf:qVh")) != -1)
+#endif
+    {
+	switch (c) {
+	case 'v':
+	    verbose = 1;
+	    break;
+	case 'f':
+	    format = (FcChar8 *) strdup (optarg);
+	    break;
+	case 'q':
+	    quiet = 1;
+	    break;
+	case 'V':
+	    fprintf (stderr, "fontconfig version %d.%d.%d\n",
+		     FC_MAJOR, FC_MINOR, FC_REVISION);
+	    exit (0);
+	case 'h':
+	    usage (argv[0], 0);
+	default:
+	    usage (argv[0], 1);
+	}
+    }
+    i = optind;
+#else
+    i = 1;
+#endif
+
+    if (!argv[i])
+	usage (argv[0], 1);
+
+    text = argv[i];
+    i++;
+
+    if (argv[i])
+    {
+	pat = FcNameParse ((FcChar8 *) argv[i]);
+	if (!pat)
+	{
+	    fputs ("Unable to parse the pattern\n", stderr);
+	    return 1;
+	}
+	while (argv[++i])
+	{
+	    if (!os)
+		os = FcObjectSetCreate ();
+	    FcObjectSetAdd (os, argv[i]);
+	}
+    }
+    else
+	pat = FcPatternCreate ();
+    if (quiet && !os)
+	os = FcObjectSetCreate ();
+    if (!verbose && !format && !os)
+	os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_FILE, (char *) 0);
+    FcObjectSetAdd (os, FC_CHARSET);
+    if (!format)
+        format = (const FcChar8 *) "%{=fclist}\n";
+    fs = FcFontList (0, pat, os);
+    if (os)
+	FcObjectSetDestroy (os);
+    if (pat)
+	FcPatternDestroy (pat);
+
+    if (!quiet && fs)
+    {
+	int	j;
+
+	for (j = 0; j < fs->nfont; j++)
+	{
+	    hb_font_t *font = hb_fc_font_create (fs->fonts[j]);
+	    hb_bool_t can_render = hb_fc_can_render (font, text);
+	    hb_font_destroy (font);
+
+	    if (!can_render)
+		continue;
+
+	    FcPatternDel (fs->fonts[j], FC_CHARSET);
+
+	    if (verbose)
+	    {
+		FcPatternPrint (fs->fonts[j]);
+	    }
+	    else
+	    {
+	        FcChar8 *s;
+
+		s = FcPatternFormat (fs->fonts[j], format);
+		if (s)
+		{
+		    printf ("%s", s);
+		    FcStrFree (s);
+		}
+	    }
+	}
+    }
+
+    if (fs) {
+	nfont = fs->nfont;
+	FcFontSetDestroy (fs);
+    }
+
+    FcFini ();
+
+    return quiet ? (nfont == 0 ? 1 : 0) : 0;
+}
diff --git a/util/hb-fc.cc b/util/hb-fc.cc
new file mode 100644
index 0000000..e99b1ae
--- /dev/null
+++ b/util/hb-fc.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2014  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "hb-fc.h"
+
+static hb_bool_t
+hb_fc_get_glyph (hb_font_t *font /*HB_UNUSED*/,
+		 void *font_data,
+		 hb_codepoint_t unicode,
+		 hb_codepoint_t variation_selector,
+		 hb_codepoint_t *glyph,
+		 void *user_data /*HB_UNUSED*/)
+
+{
+  FcCharSet *cs = (FcCharSet *) font_data;
+
+  if (variation_selector)
+  {
+    /* Fontconfig doesn't cache cmap-14 info.  However:
+     * 1. If the font maps the variation_selector, assume it's
+     *    supported,
+     * 2. If the font doesn't map it, still say it's supported,
+     *    but return 0.  This way, the caller will see the zero
+     *    and reject.  If we return unsupported here, then the
+     *    variation selector will be hidden and ignored.
+     */
+    if (FcCharSetHasChar (cs, unicode) &&
+	FcCharSetHasChar (cs, variation_selector))
+    {
+      unsigned int var_num = 0;
+      if (variation_selector - 0xFE00u < 16)
+        var_num = variation_selector - 0xFE00 + 1;
+      else if (variation_selector - 0xE0100u < (256 - 16))
+        var_num = variation_selector - 0xE0100 + 17;
+      *glyph = (var_num << 21) | unicode;
+    }
+    else
+    {
+      *glyph = 0;
+    }
+    return true;
+  }
+
+  *glyph = FcCharSetHasChar (cs, unicode) ? unicode : 0;
+  return *glyph != 0;
+}
+
+static hb_font_funcs_t *
+_hb_fc_get_font_funcs (void)
+{
+  static const hb_font_funcs_t *fc_ffuncs;
+
+  const hb_font_funcs_t *ffuncs;
+
+  if (!(ffuncs = fc_ffuncs))
+  {
+    hb_font_funcs_t *newfuncs = hb_font_funcs_create ();
+
+    hb_font_funcs_set_glyph_func (newfuncs, hb_fc_get_glyph, NULL, NULL);
+
+    /* XXX MT-unsafe */
+    if (fc_ffuncs)
+      hb_font_funcs_destroy (newfuncs);
+    else
+      fc_ffuncs = ffuncs = newfuncs;
+  }
+
+  return const_cast<hb_font_funcs_t *> (fc_ffuncs);
+}
+
+
+hb_font_t *
+hb_fc_font_create (FcPattern *fcfont)
+{
+  static hb_face_t *face;
+  hb_font_t *font;
+
+  FcCharSet *cs;
+  if (FcResultMatch != FcPatternGetCharSet (fcfont, FC_CHARSET, 0, &cs))
+    return hb_font_get_empty ();
+
+  if (!face) /* XXX MT-unsafe */
+    face = hb_face_create (hb_blob_get_empty (), 0);
+
+  font = hb_font_create (face);
+
+  hb_font_set_funcs (font,
+		     _hb_fc_get_font_funcs (),
+		     FcCharSetCopy (cs),
+		     (hb_destroy_func_t) FcCharSetDestroy);
+
+  return font;
+}
+
+hb_bool_t
+hb_fc_can_render (hb_font_t *font, const char *text)
+{
+  static const char *ot[] = {"ot", NULL};
+
+  hb_buffer_t *buffer = hb_buffer_create ();
+  hb_buffer_add_utf8 (buffer, text, -1, 0, -1);
+
+  /* XXX Do we need this?  I think Arabic and Hangul shapers are the
+   * only one that make any use of this.  The Hangul case is not really
+   * needed, and for Arabic we'll miss a very narrow set of fonts.
+   * Might be better to force generic shaper perhaps. */
+  hb_buffer_guess_segment_properties (buffer);
+
+  if (!hb_shape_full (font, buffer, NULL, 0, ot))
+    abort (); /* hb-ot shaper not enabled? */
+
+  unsigned int len;
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &len);
+  for (unsigned int i = 0; i < len; i++)
+   {
+    if (!info[i].codepoint)
+     {
+      return false;
+     }
+   }
+
+  return true;
+}
diff --git a/util/hb-fc.h b/util/hb-fc.h
new file mode 100644
index 0000000..bb2f78a
--- /dev/null
+++ b/util/hb-fc.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2014  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_FC_H
+#define HB_FC_H
+
+#include "hb.h"
+
+#include <fontconfig/fontconfig.h>
+
+HB_BEGIN_DECLS
+
+
+hb_font_t *
+hb_fc_font_create (FcPattern *font);
+
+hb_bool_t
+hb_fc_can_render (hb_font_t *font, const char *text);
+
+
+HB_END_DECLS
+
+#endif /* HB_FC_H */
diff --git a/util/hb-shape.cc b/util/hb-shape.cc
index f38f387..3bd2184 100644
--- a/util/hb-shape.cc
+++ b/util/hb-shape.cc
@@ -70,6 +70,8 @@
       flags |= HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS;
     if (!format.show_positions)
       flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
+    if (format.show_extents)
+      flags |= HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS;
     format_flags = (hb_buffer_serialize_flags_t) flags;
   }
   void new_line (void)
diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc
index d576c3f..8f30eea 100644
--- a/util/helper-cairo.cc
+++ b/util/helper-cairo.cc
@@ -75,7 +75,9 @@
   hb_font_t *font = hb_font_reference (font_opts->get_font ());
 
   cairo_font_face_t *cairo_face;
-  FT_Face ft_face = hb_ft_font_get_face (font);
+  /* 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... */
+  FT_Face ft_face = NULL;//hb_ft_font_get_face (font);
   if (!ft_face)
   {
     if (!ft_library)
@@ -128,6 +130,22 @@
   return scaled_font;
 }
 
+bool
+helper_cairo_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
+{
+  bool ret = false;
+#ifdef FT_HAS_COLOR
+  FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+  if (ft_face)
+  {
+    if (FT_HAS_COLOR (ft_face))
+      ret = true;
+    cairo_ft_scaled_font_unlock_face (scaled_font);
+  }
+#endif
+  return ret;
+}
+
 
 struct finalize_closure_t {
   void (*callback)(finalize_closure_t *);
@@ -295,7 +313,8 @@
 cairo_t *
 helper_cairo_create_context (double w, double h,
 			     view_options_t *view_opts,
-			     output_options_t *out_opts)
+			     output_options_t *out_opts,
+			     cairo_content_t content)
 {
   cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
 				   void *closure,
@@ -324,42 +343,47 @@
   }
   if (0)
     ;
-    else if (0 == strcasecmp (extension, "ansi"))
+    else if (0 == g_ascii_strcasecmp (extension, "ansi"))
       constructor2 = _cairo_ansi_surface_create_for_stream;
   #ifdef CAIRO_HAS_PNG_FUNCTIONS
-    else if (0 == strcasecmp (extension, "png"))
+    else if (0 == g_ascii_strcasecmp (extension, "png"))
       constructor2 = _cairo_png_surface_create_for_stream;
   #endif
   #ifdef CAIRO_HAS_SVG_SURFACE
-    else if (0 == strcasecmp (extension, "svg"))
+    else if (0 == g_ascii_strcasecmp (extension, "svg"))
       constructor = cairo_svg_surface_create_for_stream;
   #endif
   #ifdef CAIRO_HAS_PDF_SURFACE
-    else if (0 == strcasecmp (extension, "pdf"))
+    else if (0 == g_ascii_strcasecmp (extension, "pdf"))
       constructor = cairo_pdf_surface_create_for_stream;
   #endif
   #ifdef CAIRO_HAS_PS_SURFACE
-    else if (0 == strcasecmp (extension, "ps"))
+    else if (0 == g_ascii_strcasecmp (extension, "ps"))
       constructor = cairo_ps_surface_create_for_stream;
    #ifdef HAS_EPS
-    else if (0 == strcasecmp (extension, "eps"))
+    else if (0 == g_ascii_strcasecmp (extension, "eps"))
       constructor = _cairo_eps_surface_create_for_stream;
    #endif
   #endif
 
 
   unsigned int fr, fg, fb, fa, br, bg, bb, ba;
+  const char *color;
   br = bg = bb = 0; ba = 255;
-  sscanf (view_opts->back + (*view_opts->back=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba);
+  color = view_opts->back ? view_opts->back : DEFAULT_BACK;
+  sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba);
   fr = fg = fb = 0; fa = 255;
-  sscanf (view_opts->fore + (*view_opts->fore=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa);
+  color = view_opts->fore ? view_opts->fore : DEFAULT_FORE;
+  sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa);
 
-  cairo_content_t content;
-  if (!view_opts->annotate && ba == 255 && br == bg && bg == bb && fr == fg && fg == fb)
-    content = CAIRO_CONTENT_ALPHA;
-  else if (ba == 255)
-    content = CAIRO_CONTENT_COLOR;
-  else
+  if (content == CAIRO_CONTENT_ALPHA)
+  {
+    if (view_opts->annotate ||
+	br != bg || bg != bb ||
+	fr != fg || fg != fb)
+      content = CAIRO_CONTENT_COLOR;
+  }
+  if (ba != 255)
     content = CAIRO_CONTENT_COLOR_ALPHA;
 
   cairo_surface_t *surface;
@@ -456,16 +480,16 @@
   for (i = 0; i < (int) l->num_glyphs; i++)
   {
     l->glyphs[i].index = hb_glyph[i].codepoint;
-    l->glyphs[i].x = scalbn ( hb_position->x_offset + x, scale_bits);
-    l->glyphs[i].y = scalbn (-hb_position->y_offset + y, scale_bits);
+    l->glyphs[i].x = scalbn ((double)  hb_position->x_offset + x, scale_bits);
+    l->glyphs[i].y = scalbn ((double) -hb_position->y_offset + y, scale_bits);
     x +=  hb_position->x_advance;
     y += -hb_position->y_advance;
 
     hb_position++;
   }
   l->glyphs[i].index = -1;
-  l->glyphs[i].x = scalbn (x, scale_bits);
-  l->glyphs[i].y = scalbn (y, scale_bits);
+  l->glyphs[i].x = scalbn ((double) x, scale_bits);
+  l->glyphs[i].y = scalbn ((double) y, scale_bits);
 
   if (l->num_clusters) {
     memset ((void *) l->clusters, 0, l->num_clusters * sizeof (l->clusters[0]));
diff --git a/util/helper-cairo.hh b/util/helper-cairo.hh
index ed55a45..27b6eb3 100644
--- a/util/helper-cairo.hh
+++ b/util/helper-cairo.hh
@@ -35,12 +35,16 @@
 cairo_scaled_font_t *
 helper_cairo_create_scaled_font (const font_options_t *font_opts);
 
+bool
+helper_cairo_scaled_font_has_color (cairo_scaled_font_t *scaled_font);
+
 extern const char *helper_cairo_supported_formats[];
 
 cairo_t *
 helper_cairo_create_context (double w, double h,
 			     view_options_t *view_opts,
-			     output_options_t *out_opts);
+			     output_options_t *out_opts,
+			     cairo_content_t content);
 
 void
 helper_cairo_destroy_context (cairo_t *cr);
diff --git a/util/main-font-text.hh b/util/main-font-text.hh
index 628cdf9..059dde4 100644
--- a/util/main-font-text.hh
+++ b/util/main-font-text.hh
@@ -31,6 +31,38 @@
 
 /* main() body for utilities taking font and processing text.*/
 
+static char *
+locale_to_utf8 (char *s)
+{
+  char *t;
+  GError *error = NULL;
+
+  t = g_locale_to_utf8 (s, -1, NULL, NULL, &error);
+  if (!t)
+  {
+     fail (true, "Failed converting text to UTF-8");
+  }
+
+  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);
+  printf ("HB: buffer [%s]\n", buf);
+  return true;
+}
+
 template <typename consumer_t, int default_font_size, int subpixel_bits>
 struct main_font_text_t
 {
@@ -46,18 +78,20 @@
     options.parse (&argc, &argv);
 
     argc--, argv++;
-    if (argc && !font_opts.font_file) font_opts.font_file = argv[0], argc--, argv++;
-    if (argc && !input.text && !input.text_file) input.text = argv[0], argc--, argv++;
+    if (argc && !font_opts.font_file) font_opts.font_file = locale_to_utf8 (argv[0]), argc--, argv++;
+    if (argc && !input.text && !input.text_file) input.text = locale_to_utf8 (argv[0]), argc--, argv++;
     if (argc)
       fail (true, "Too many arguments on the command line");
     if (!font_opts.font_file)
       options.usage ();
     if (!input.text && !input.text_file)
-      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);
     unsigned int text_len;
     const char *text;
     while ((text = input.get_line (&text_len)))
diff --git a/util/options.cc b/util/options.cc
index 7387a56..bc699c1 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -30,7 +30,7 @@
 #include <hb-ft.h>
 #endif
 #ifdef HAVE_OT
-#include <hb-ot-font.h>
+#include <hb-ot.h>
 #endif
 
 struct supported_font_funcs_t {
@@ -174,7 +174,7 @@
 {
   view_options_t *view_opts = (view_options_t *) data;
   view_options_t::margin_t &m = view_opts->margin;
-  switch (sscanf (arg, "%lf %lf %lf %lf", &m.t, &m.r, &m.b, &m.l)) {
+  switch (sscanf (arg, "%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf", &m.t, &m.r, &m.b, &m.l)) {
     case 1: m.r = m.t;
     case 2: m.b = m.t;
     case 3: m.l = m.r;
@@ -291,6 +291,7 @@
     {"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},
+    {"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},
     {"num-iterations",	0, 0, G_OPTION_ARG_INT,		&this->num_iterations,		"Run shaper N times (default: 1)",	"N"},
     {NULL}
@@ -361,7 +362,7 @@
     font_opts->font_size_y = font_opts->font_size_x = FONT_SIZE_UPEM;
     return true;
   }
-  switch (sscanf (arg, "%lf %lf", &font_opts->font_size_x, &font_opts->font_size_y)) {
+  switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->font_size_x, &font_opts->font_size_y)) {
     case 1: font_opts->font_size_y = font_opts->font_size_x;
     case 2: return true;
     default:
@@ -440,7 +441,7 @@
   const char *text;
 
   if (NULL == supported_formats)
-    text = "Set output format";
+    text = "Set output serialization format";
   else
   {
     char *items = g_strjoinv ("/", const_cast<char **> (supported_formats));
@@ -457,8 +458,8 @@
   };
   parser->add_group (entries,
 		     "output",
-		     "Output options:",
-		     "Options controlling the output",
+		     "Output destination & format options:",
+		     "Options controlling the destination and form of the output",
 		     this);
 }
 
@@ -489,7 +490,7 @@
       GString *gs = g_string_new (NULL);
       char buf[BUFSIZ];
 #if defined(_WIN32) || defined(__CYGWIN__)
-      setmode (fileno (stdin), _O_BINARY);
+      setmode (fileno (stdin), O_BINARY);
 #endif
       while (!feof (stdin)) {
 	size_t ret = fread (buf, 1, sizeof (buf), stdin);
@@ -537,6 +538,9 @@
       }
     }
 
+    if (debug)
+      mm = HB_MEMORY_MODE_DUPLICATE;
+
     blob = hb_blob_create (font_data, len, mm, user_data, destroy);
   }
 
@@ -565,7 +569,7 @@
   else
   {
     for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
-      if (0 == strcasecmp (font_funcs, supported_font_funcs[i].name))
+      if (0 == g_ascii_strcasecmp (font_funcs, supported_font_funcs[i].name))
       {
 	set_font_funcs = supported_font_funcs[i].func;
 	break;
@@ -597,25 +601,26 @@
 text_options_t::get_line (unsigned int *len)
 {
   if (text) {
-    if (text_len == (unsigned int) -1)
-      text_len = strlen (text);
+    if (!line) line = text;
+    if (line_len == (unsigned int) -1)
+      line_len = strlen (line);
 
-    if (!text_len) {
+    if (!line_len) {
       *len = 0;
       return NULL;
     }
 
-    const char *ret = text;
-    const char *p = (const char *) memchr (text, '\n', text_len);
+    const char *ret = line;
+    const char *p = (const char *) memchr (line, '\n', line_len);
     unsigned int ret_len;
     if (!p) {
-      ret_len = text_len;
-      text += ret_len;
-      text_len = 0;
+      ret_len = line_len;
+      line += ret_len;
+      line_len = 0;
     } else {
       ret_len = p - ret;
-      text += ret_len + 1;
-      text_len -= ret_len + 1;
+      line += ret_len + 1;
+      line_len -= ret_len + 1;
     }
 
     *len = ret_len;
@@ -667,7 +672,7 @@
     fp = fopen (output_file, "wb");
   else {
 #if defined(_WIN32) || defined(__CYGWIN__)
-    setmode (fileno (stdout), _O_BINARY);
+    setmode (fileno (stdout), O_BINARY);
 #endif
     fp = stdout;
   }
@@ -694,19 +699,27 @@
 {
   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},
-    {"no-positions",	0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,	&this->show_positions,		"Do not show glyph positions",		NULL},
-    {"no-clusters",	0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,	&this->show_clusters,		"Do not show cluster mapping",		NULL},
-    {"show-text",	0, 0,			  G_OPTION_ARG_NONE,	&this->show_text,		"Show input text",			NULL},
-    {"show-unicode",	0, 0,			  G_OPTION_ARG_NONE,	&this->show_unicode,		"Show input Unicode codepoints",	NULL},
-    {"show-line-num",	0, 0,			  G_OPTION_ARG_NONE,	&this->show_line_num,		"Show line numbers",			NULL},
-    {"verbose",		0, G_OPTION_FLAG_NO_ARG,  G_OPTION_ARG_CALLBACK,(gpointer) &parse_verbose,	"Show everything",			NULL},
+    {"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},
+    {"no-glyph-names",	0, G_OPTION_FLAG_REVERSE,
+			      G_OPTION_ARG_NONE,	&this->show_glyph_names,	"Output glyph indices instead of names",				NULL},
+    {"no-positions",	0, G_OPTION_FLAG_REVERSE,
+			      G_OPTION_ARG_NONE,	&this->show_positions,		"Do not output glyph positions",					NULL},
+    {"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}
   };
   parser->add_group (entries,
-		     "format",
-		     "Format options:",
-		     "Options controlling the formatting of buffer contents",
+		     "output-syntax",
+		     "Output syntax:\n"
+         "    text: [<glyph name or index>=<glyph cluster index within input>@<horizontal displacement>,<vertical displacement>+<horizontal advance>,<vertical advance>|...]\n"
+         "    json: [{\"g\": <glyph name or index>, \"ax\": <horizontal advance>, \"ay\": <vertical advance>, \"dx\": <horizontal displacement>, \"dy\": <vertical displacement>, \"cl\": <glyph cluster index within input>}, ...]\n"
+         "\nOutput syntax options:",
+		     "Options controlling the syntax of the output",
 		     this);
 }
 
diff --git a/util/options.hh b/util/options.hh
index 8b9b10e..919e4f8 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -150,19 +150,24 @@
 {
   view_options_t (option_parser_t *parser) {
     annotate = false;
-    fore = DEFAULT_FORE;
-    back = DEFAULT_BACK;
+    fore = NULL;
+    back = NULL;
     line_space = 0;
     margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN;
 
     add_options (parser);
   }
+  ~view_options_t (void)
+  {
+    g_free (fore);
+    g_free (back);
+  }
 
   void add_options (option_parser_t *parser);
 
   hb_bool_t annotate;
-  const char *fore;
-  const char *back;
+  char *fore;
+  char *back;
   double line_space;
   struct margin_t {
     double t, r, b, l;
@@ -180,6 +185,7 @@
     num_features = 0;
     shapers = NULL;
     utf8_clusters = false;
+    cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
     normalize_glyphs = false;
     num_iterations = 1;
 
@@ -187,6 +193,9 @@
   }
   ~shape_options_t (void)
   {
+    g_free (direction);
+    g_free (language);
+    g_free (script);
     free (features);
     g_strfreev (shapers);
   }
@@ -202,6 +211,7 @@
 			 (bot ? HB_BUFFER_FLAG_BOT : 0) |
 			 (eot ? HB_BUFFER_FLAG_EOT : 0) |
 			 (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0)));
+    hb_buffer_set_cluster_level (buffer, cluster_level);
     hb_buffer_guess_segment_properties (buffer);
   }
 
@@ -252,9 +262,9 @@
   }
 
   /* Buffer properties */
-  const char *direction;
-  const char *language;
-  const char *script;
+  char *direction;
+  char *language;
+  char *script;
 
   /* Buffer flags */
   hb_bool_t bot;
@@ -265,6 +275,7 @@
   unsigned int num_features;
   char **shapers;
   hb_bool_t utf8_clusters;
+  hb_buffer_cluster_level_t cluster_level;
   hb_bool_t normalize_glyphs;
   unsigned int num_iterations;
 };
@@ -287,6 +298,8 @@
     add_options (parser);
   }
   ~font_options_t (void) {
+    g_free (font_file);
+    g_free (font_funcs);
     hb_font_destroy (font);
   }
 
@@ -294,13 +307,13 @@
 
   hb_font_t *get_font (void) const;
 
-  const char *font_file;
+  char *font_file;
   int face_index;
   int default_font_size;
   unsigned int subpixel_bits;
   mutable double font_size_x;
   mutable double font_size_y;
-  const char *font_funcs;
+  char *font_funcs;
 
   private:
   mutable hb_font_t *font;
@@ -318,11 +331,16 @@
 
     fp = NULL;
     gs = NULL;
-    text_len = (unsigned int) -1;
+    line = NULL;
+    line_len = (unsigned int) -1;
 
     add_options (parser);
   }
   ~text_options_t (void) {
+    g_free (text_before);
+    g_free (text_after);
+    g_free (text);
+    g_free (text_file);
     if (gs)
       g_string_free (gs, true);
     if (fp)
@@ -336,21 +354,21 @@
       g_set_error (error,
 		   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
 		   "Only one of text and text-file can be set");
-
   };
 
   const char *get_line (unsigned int *len);
 
-  const char *text_before;
-  const char *text_after;
+  char *text_before;
+  char *text_after;
 
-  const char *text;
-  const char *text_file;
+  char *text;
+  char *text_file;
 
   private:
   FILE *fp;
   GString *gs;
-  unsigned int text_len;
+  char *line;
+  unsigned int line_len;
 };
 
 struct output_options_t : option_group_t
@@ -367,6 +385,8 @@
     add_options (parser);
   }
   ~output_options_t (void) {
+    g_free (output_file);
+    g_free (output_format);
     if (fp)
       fclose (fp);
   }
@@ -381,7 +401,10 @@
     if (output_file && !output_format) {
       output_format = strrchr (output_file, '.');
       if (output_format)
+      {
 	  output_format++; /* skip the dot */
+	  output_format = strdup (output_format);
+      }
     }
 
     if (output_file && 0 == strcmp (output_file, "-"))
@@ -390,8 +413,8 @@
 
   FILE *get_file_handle (void);
 
-  const char *output_file;
-  const char *output_format;
+  char *output_file;
+  char *output_format;
   const char **supported_formats;
   bool explicit_output_format;
 
@@ -407,6 +430,7 @@
     show_text = false;
     show_unicode = false;
     show_line_num = false;
+    show_extents = false;
 
     add_options (parser);
   }
@@ -447,7 +471,25 @@
   hb_bool_t show_text;
   hb_bool_t show_unicode;
   hb_bool_t show_line_num;
+  hb_bool_t show_extents;
 };
 
+/* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */
+#if defined (_MSC_VER) && (_MSC_VER < 1800)
+
+#ifndef FLT_RADIX
+#define FLT_RADIX 2
+#endif
+
+__inline long double scalbn (long double x, int exp)
+{
+  return x * (pow ((long double) FLT_RADIX, exp));
+}
+
+__inline float scalbnf (float x, int exp)
+{
+  return x * (pow ((float) FLT_RADIX, exp));
+}
+#endif
 
 #endif
diff --git a/util/view-cairo.cc b/util/view-cairo.cc
index 160250e..f4f2bc5 100644
--- a/util/view-cairo.cc
+++ b/util/view-cairo.cc
@@ -26,71 +26,76 @@
 
 #include "view-cairo.hh"
 
+#include <assert.h>
+
+
 void
-view_cairo_t::get_surface_size (cairo_scaled_font_t *scaled_font,
-				double *w, double *h)
+view_cairo_t::render (const font_options_t *font_opts)
 {
-  cairo_font_extents_t font_extents;
-
-  cairo_scaled_font_extents (scaled_font, &font_extents);
-
   bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
-  (vertical ? *w : *h) = (int) lines->len * (font_extents.height + view_options.line_space) - view_options.line_space;
-  (vertical ? *h : *w) = 0;
+  int vert  = vertical ? 1 : 0;
+  int horiz = vertical ? 0 : 1;
+
+  int x_sign = font_opts->font_size_x < 0 ? -1 : +1;
+  int y_sign = font_opts->font_size_y < 0 ? -1 : +1;
+
+  hb_font_t *font = font_opts->get_font();
+  hb_font_extents_t extents;
+  hb_font_get_extents_for_direction (font, direction, &extents);
+
+  double ascent = y_sign * scalbn ((double) extents.ascender, scale_bits);
+  double descent = y_sign * -scalbn ((double) extents.descender, scale_bits);
+  double font_height = y_sign * scalbn ((double) extents.ascender - extents.descender + extents.line_gap, scale_bits);
+  double leading = font_height + view_options.line_space;
+
+  /* Calculate surface size. */
+  double w, h;
+  (vertical ? w : h) = (int) lines->len * leading - view_options.line_space;
+  (vertical ? h : w) = 0;
   for (unsigned int i = 0; i < lines->len; i++) {
     helper_cairo_line_t &line = g_array_index (lines, helper_cairo_line_t, i);
     double x_advance, y_advance;
     line.get_advance (&x_advance, &y_advance);
     if (vertical)
-      *h =  MAX (*h, y_advance);
+      h =  MAX (h, y_sign * y_advance);
     else
-      *w =  MAX (*w, x_advance);
+      w =  MAX (w, x_sign * x_advance);
   }
 
-  *w += view_options.margin.l + view_options.margin.r;
-  *h += view_options.margin.t + view_options.margin.b;
-}
-
-void
-view_cairo_t::render (const font_options_t *font_opts)
-{
   cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts);
-  double w, h;
-  get_surface_size (scaled_font, &w, &h);
-  cairo_t *cr = helper_cairo_create_context (w, h, &view_options, &output_options);
+
+  /* See if font needs color. */
+  cairo_content_t content = CAIRO_CONTENT_ALPHA;
+  if (helper_cairo_scaled_font_has_color (scaled_font))
+    content = CAIRO_CONTENT_COLOR;
+
+  /* Create surface. */
+  cairo_t *cr = helper_cairo_create_context (w + view_options.margin.l + view_options.margin.r,
+					     h + view_options.margin.t + view_options.margin.b,
+					     &view_options, &output_options, content);
   cairo_set_scaled_font (cr, scaled_font);
-  cairo_scaled_font_destroy (scaled_font);
 
-  draw (cr);
-
-  helper_cairo_destroy_context (cr);
-}
-
-void
-view_cairo_t::draw (cairo_t *cr)
-{
-  cairo_save (cr);
-
-  bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
-  int v = vertical ? 1 : 0;
-  int h = vertical ? 0 : 1;
-  cairo_font_extents_t font_extents;
-  cairo_font_extents (cr, &font_extents);
+  /* Setup coordinate system. */
   cairo_translate (cr, view_options.margin.l, view_options.margin.t);
-  double descent;
   if (vertical)
-    descent = font_extents.height * (lines->len + .5);
+    cairo_translate (cr,
+		     w /* We stack lines right to left */
+		     -font_height * .5 /* "ascent" for vertical */,
+		     y_sign < 0 ? h : 0);
   else
-    descent = font_extents.height - font_extents.ascent;
-  cairo_translate (cr, v * descent, h * -descent);
+   {
+    cairo_translate (cr,
+		     x_sign < 0 ? w : 0,
+		     y_sign < 0 ? descent : ascent);
+   }
+
+  /* Draw. */
+  cairo_translate (cr, +vert * leading, -horiz * leading);
   for (unsigned int i = 0; i < lines->len; i++)
   {
     helper_cairo_line_t &l = g_array_index (lines, helper_cairo_line_t, i);
 
-    if (i)
-      cairo_translate (cr, v * -view_options.line_space, h * view_options.line_space);
-
-    cairo_translate (cr, v * -font_extents.height, h * font_extents.height);
+    cairo_translate (cr, -vert * leading, +horiz * leading);
 
     if (view_options.annotate) {
       cairo_save (cr);
@@ -122,5 +127,7 @@
       cairo_show_glyphs (cr, l.glyphs, l.num_glyphs);
   }
 
-  cairo_restore (cr);
+  /* Clean up. */
+  helper_cairo_destroy_context (cr);
+  cairo_scaled_font_destroy (scaled_font);
 }
diff --git a/util/view-cairo.hh b/util/view-cairo.hh
index cb52373..f55d4bb 100644
--- a/util/view-cairo.hh
+++ b/util/view-cairo.hh
@@ -95,8 +95,6 @@
   view_options_t view_options;
 
   void render (const font_options_t *font_opts);
-  void get_surface_size (cairo_scaled_font_t *scaled_font, double *w, double *h);
-  void draw (cairo_t *cr);
 
   hb_direction_t direction; // Remove this, make segment_properties accessible
   GArray *lines;
diff --git a/win32/Makefile.am b/win32/Makefile.am
new file mode 100644
index 0000000..63ba468
--- /dev/null
+++ b/win32/Makefile.am
@@ -0,0 +1,16 @@
+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
new file mode 100644
index 0000000..fdde7a7
--- /dev/null
+++ b/win32/Makefile.vc
@@ -0,0 +1,52 @@
+# 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
new file mode 100644
index 0000000..e2ead01
--- /dev/null
+++ b/win32/README.txt
@@ -0,0 +1,79 @@
+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, as well as the Uniscribe platform shaper, 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 HarfBuzz-ICU, which is now the recommended layout engine

+     for ICU (International Components for Unicode), which deprecated ICU LE.

+     Requires the ICU libraries.

+

+DIRECTWRITE: Enable (experimental) 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
new file mode 100644
index 0000000..03b3833
--- /dev/null
+++ b/win32/build-rules-msvc.mak
@@ -0,0 +1,140 @@
+# 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 @<<
+$<
+<<
+
+{..\src\}.cc{$(CFG)\$(PLAT)\harfbuzz-icu\}.obj::
+	$(CXX) $(CFLAGS) $(HB_LIB_CFLAGS) $(HB_ICU_CFLAGS) /Fo$(CFG)\$(PLAT)\harfbuzz-icu\ /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-icu.lib: $(HARFBUZZ_ICU_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 [email protected] mt /manifest [email protected] /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 [email protected] mt /manifest [email protected] /outputresource:$@;2
+
+$(HARFBUZZ_ICU_DLL_FILENAME).dll: $(CFG)\$(PLAT)\harfbuzz.lib $(harfbuzz_icu_OBJS) $(CFG)\$(PLAT)\harfbuzz-icu
+	link /DLL $(LDFLAGS) $(CFG)\$(PLAT)\harfbuzz.lib $(HB_ICU_DEP_LIBS) /implib:$(CFG)\$(PLAT)\harfbuzz-icu.lib -out:$@ @<<
+$(harfbuzz_icu_OBJS)
+<<
+	@-if exist [email protected] mt /manifest [email protected] /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 [email protected] mt /manifest [email protected] /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 [email protected] mt /manifest [email protected] /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 [email protected] mt /manifest [email protected] /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 [email protected] mt /manifest [email protected] /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 [email protected] mt /manifest [email protected] /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
+	@-if exist $(CFG)\$(PLAT)\harfbuzz-icu del /f /q $(CFG)\$(PLAT)\harfbuzz-icu\*.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
new file mode 100644
index 0000000..e0c6468
--- /dev/null
+++ b/win32/config-msvc.mak
@@ -0,0 +1,198 @@
+# 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
+FREETYPE_LIB = freetype.lib
+
+# Cairo is needed for building hb-view
+CAIRO_LIB = cairo.lib
+
+# Graphite2 is needed for building SIL Graphite2 support
+GRAPHITE2_LIB = graphite2.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_UNISCRIBE_sources)	\
+
+HB_HEADERS =	\
+	$(HB_BASE_headers)		\
+	$(HB_NODIST_headers)	\
+	$(HB_OT_headers)		\
+	$(HB_UNISCRIBE_headers)
+
+# Minimal set of (system) libraries needed for the HarfBuzz DLL
+HB_DEP_LIBS = usp10.lib gdi32.lib rpcrt4.lib user32.lib
+
+# 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_ICU_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-icu-0
+HARFBUZZ_GOBJECT_DLL_FILENAME = $(CFG)\$(PLAT)\libharfbuzz-gobject-0
+!else
+HARFBUZZ_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-vs$(VSVER)
+HARFBUZZ_ICU_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-icu-vs$(VSVER)
+HARFBUZZ_GOBJECT_DLL_FILENAME = $(CFG)\$(PLAT)\harfbuzz-gobject-vs$(VSVER)
+!endif
+
+# Enable HarfBuzz-ICU, if desired
+!if "$(ICU)" == "1"
+HB_ICU_CFLAGS =
+HB_LIBS =	\
+	$(HB_LIBS)	\
+	$(CFG)\$(PLAT)\harfbuzz-icu.lib
+
+# We don't want to re-define int8_t Visual Studio 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_ICU_CFLAGS = /DU_HAVE_INT8_T
+!endif
+
+!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"
+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
+
+!else
+# If there is no GLib support, use the built-in UCDN
+# 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_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 "$(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
new file mode 100644
index 0000000..73ad205
--- /dev/null
+++ b/win32/config.h.win32.in
@@ -0,0 +1,158 @@
+/* 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 */
+#define HAVE_UNISCRIBE 1
+
+/* 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
new file mode 100644
index 0000000..9b5574b
--- /dev/null
+++ b/win32/create-lists-msvc.mak
@@ -0,0 +1,151 @@
+# 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 HarfBuzz-ICU
+!if "$(ICU)" == "1"
+
+!if [call create-lists.bat header hb_objs.mak harfbuzz_icu_OBJS]
+!endif
+
+!if [for %c in ($(HB_ICU_sources)) do @if "%~xc" == ".cc" @call create-lists.bat file hb_objs.mak ^$(CFG)\^$(PLAT)\harfbuzz-icu\%~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
new file mode 100644
index 0000000..ef60d5c
--- /dev/null
+++ b/win32/create-lists.bat
@@ -0,0 +1,42 @@
+@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
new file mode 100644
index 0000000..a94ab84
--- /dev/null
+++ b/win32/detectenv-msvc.mak
@@ -0,0 +1,136 @@
+# 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"
+CFLAGS_ADD = $(CFLAGS_ADD) /d2Zi+
+!endif
+!else
+CFLAGS_ADD = /MDd /Od
+!endif
+
+!if "$(PLAT)" == "x64"
+LDFLAGS_ARCH = /machine:x64
+!else
+LDFLAGS_ARCH = /machine:x86
+!endif
+
+!if "$(VALID_CFGSET)" == "TRUE"
+CFLAGS = $(CFLAGS_ADD) /W3 /Zi /I.. /I..\src /I. /I$(PREFIX)\include
+
+LDFLAGS_BASE = $(LDFLAGS_ARCH) /libpath:$(PREFIX)\lib /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
new file mode 100644
index 0000000..48bd9f0
--- /dev/null
+++ b/win32/generate-msvc.mak
@@ -0,0 +1,26 @@
+# 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 [email protected] $@
+
+# 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 [email protected]
+	@-del [email protected]
+!endif
+
+# Create the build directories
+$(CFG)\$(PLAT)\harfbuzz $(CFG)\$(PLAT)\harfbuzz-icu $(CFG)\$(PLAT)\harfbuzz-gobject $(CFG)\$(PLAT)\util:
+	@-mkdir $@
diff --git a/win32/hb-introspection-msvc.mak b/win32/hb-introspection-msvc.mak
new file mode 100644
index 0000000..67a0c5e
--- /dev/null
+++ b/win32/hb-introspection-msvc.mak
@@ -0,0 +1,42 @@
+
+!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
new file mode 100644
index 0000000..bc85dc9
--- /dev/null
+++ b/win32/info-msvc.mak
@@ -0,0 +1,137 @@
+# NMake Makefile portion for displaying config info
+
+INC_FEATURES = Uniscribe 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
+!else
+UNICODE_IMPL = ucdn
+!endif
+
+!if "$(FREETYPE)" == "1"
+INC_FEATURES = $(INC_FEATURES) FreeType
+!endif
+
+!if "$(GRAPHITE2)" == "1"
+INC_FEATURES = $(INC_FEATURES) Graphite2
+!endif
+
+!if "$(DIRECTWRITE)" == "1"
+INC_FEATURES = $(INC_FEATURES) DirectWrite
+!endif
+
+!if "$(ICU)" == "1"
+BUILT_LIBRARIES = $(BUILT_LIBRARIES) HarfBuzz-ICU
+!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, fallback and Uniscribe support
+	@echo with a bundled Unicode implementation (UCDN).
+	@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 the HarfBuzz-ICU layout library, 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 interpretor (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 interpretor (that was used to build the gobject-introsoection 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
new file mode 100644
index 0000000..fa239ea
--- /dev/null
+++ b/win32/install.mak
@@ -0,0 +1,29 @@
+# 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_ICU_DLL_FILENAME).dll copy /b $(HARFBUZZ_ICU_DLL_FILENAME).dll $(PREFIX)\bin
+	@if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll copy /b $(HARFBUZZ_ICU_DLL_FILENAME).pdb $(PREFIX)\bin
+	@if exist $(HARFBUZZ_ICU_DLL_FILENAME).dll copy /b $(CFG)\$(PLAT)\harfbuzz-icu.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_ICU_DLL_FILENAME).dll for %h in ($(HB_ICU_headers)) do @copy ..\src\%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
new file mode 100644
index 0000000..d32f7cf
--- /dev/null
+++ b/win32/introspection-msvc.mak
@@ -0,0 +1,73 @@
+# 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