8247872: Upgrade HarfBuzz to the latest 2.7.2

Reviewed-by: serb
diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
index 7fbd104..3203378 100644
--- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk
+++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
@@ -435,7 +435,6 @@
 ifeq ($(USE_EXTERNAL_HARFBUZZ), true)
   LIBHARFBUZZ_LIBS := $(HARFBUZZ_LIBS)
 else
-  HARFBUZZ_CFLAGS := -DHAVE_OT -DHAVE_FALLBACK -DHAVE_UCDN -DHAVE_ROUND
 
   # This is better than adding EXPORT_ALL_SYMBOLS
   ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), )
@@ -493,7 +492,7 @@
         maybe-uninitialized class-memaccess, \
       DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \
         tautological-constant-out-of-range-compare int-to-pointer-cast \
-        undef missing-field-initializers, \
+        undef missing-field-initializers range-loop-analysis, \
       DISABLED_WARNINGS_microsoft := 4267 4244 4090 4146 4334 4819 4101 4068 4805 4138, \
       LDFLAGS := $(LDFLAGS_JDKLIB) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
diff --git a/src/java.desktop/share/legal/harfbuzz.md b/src/java.desktop/share/legal/harfbuzz.md
index 16698bc..465bcf5 100644
--- a/src/java.desktop/share/legal/harfbuzz.md
+++ b/src/java.desktop/share/legal/harfbuzz.md
@@ -1,16 +1,18 @@
-## Harfbuzz v2.3.1
+## Harfbuzz v2.7.2
 
 ### Harfbuzz License
 
-http://cgit.freedesktop.org/harfbuzz/tree/COPYING
+https://github.com/harfbuzz/harfbuzz/blob/master/COPYING
 
 <pre>
 
-HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
+HarfBuzz is licensed under the so-called "Old MIT" license.  Details follow.
 For parts of HarfBuzz that are licensed under different licenses see individual
 files names COPYING in subdirectories where applicable.
 
-Copyright © 2010,2011,2012  Google, Inc.
+Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020  Google, Inc.
+Copyright © 2018,2019,2020  Ebrahim Byagowi
+Copyright © 2019,2020  Facebook, Inc. 
 Copyright © 2012  Mozilla Foundation
 Copyright © 2011  Codethink Limited
 Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-fdsc-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-fdsc-table.hh
deleted file mode 100644
index 4ee7353..0000000
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-fdsc-table.hh
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright © 2018  Ebrahim Byagowi
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
-#ifndef HB_AAT_FDSC_TABLE_HH
-#define HB_AAT_FDSC_TABLE_HH
-
-#include "hb-aat-layout-common.hh"
-#include "hb-open-type.hh"
-
-/*
- * fdsc -- Font descriptors
- * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fdsc.html
- */
-#define HB_AAT_TAG_fdsc HB_TAG('f','d','s','c')
-
-
-namespace AAT {
-
-
-struct FontDescriptor
-{
-  bool has_data () const { return tag; }
-
-  int cmp (hb_tag_t a) const { return tag.cmp (a); }
-
-  float get_value () const { return u.value.to_float (); }
-
-  enum non_alphabetic_value_t {
-    Alphabetic          = 0,
-    Dingbats            = 1,
-    PiCharacters        = 2,
-    Fleurons            = 3,
-    DecorativeBorders   = 4,
-    InternationalSymbols= 5,
-    MathSymbols         = 6
-  };
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
-  }
-
-  protected:
-  Tag           tag;            /* The 4-byte table tag name. */
-  union {
-  Fixed         value;          /* The value for the descriptor tag. */
-  HBUINT32      nalfType;       /* If the tag is `nalf`, see non_alphabetic_value_t */
-  } u;
-  public:
-  DEFINE_SIZE_STATIC (8);
-};
-
-struct fdsc
-{
-  static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
-
-  enum {
-    Weight       = HB_TAG ('w','g','h','t'),
-                                /* Percent weight relative to regular weight.
-                                 * (defaul value: 1.0) */
-    Width        = HB_TAG ('w','d','t','h'),
-                                /* Percent width relative to regular width.
-                                 * (default value: 1.0) */
-    Slant        = HB_TAG ('s','l','n','t'),
-                                /* Angle of slant in degrees, where positive
-                                 * is clockwise from straight up.
-                                 * (default value: 0.0) */
-    OpticalSize  = HB_TAG ('o','p','s','z'),
-                                /* Point size the font was designed for.
-                                 * (default value: 12.0) */
-    NonAlphabetic= HB_TAG ('n','a','l','f')
-                                /* These values are treated as integers,
-                                 * not fixed32s. 0 means alphabetic, and greater
-                                 * integers mean the font is non-alphabetic (e.g. symbols).
-                                 * (default value: 0) */
-  };
-
-  const FontDescriptor &get_descriptor (hb_tag_t style) const
-  { return descriptors.lsearch (style); }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-                  descriptors.sanitize (c));
-  }
-
-  protected:
-  Fixed         version;        /* Version number of the font descriptors
-                                 * table (0x00010000 for the current version). */
-  LArrayOf<FontDescriptor>
-                descriptors;    /* List of tagged-coordinate pairs style descriptors
-                                 * that will be included to characterize this font.
-                                 * Each descriptor consists of a <tag, value> pair.
-                                 * These pairs are located in the gxFontDescriptor
-                                 * array that follows. */
-  public:
-  DEFINE_SIZE_ARRAY (8, descriptors);
-};
-
-} /* namespace AAT */
-
-
-#endif /* HB_AAT_FDSC_TABLE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-ankr-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-ankr-table.hh
index f8495f3..90dd949 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-ankr-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-ankr-table.hh
@@ -66,7 +66,7 @@
   {
     const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
     if (!offset)
-      return Null(Anchor);
+      return Null (Anchor);
     const GlyphAnchors &anchors = &(this+anchorData) + *offset;
     return anchors[i];
   }
@@ -76,13 +76,14 @@
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
                           version == 0 &&
+                          c->check_range (this, anchorData) &&
                           lookupTable.sanitize (c, this, &(this+anchorData))));
   }
 
   protected:
   HBUINT16      version;        /* Version number (set to zero) */
   HBUINT16      flags;          /* Flags (currently unused; set to zero) */
-  LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors> > >
+  LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
                 lookupTable;    /* Offset to the table's lookup table */
   LNNOffsetTo<HBUINT8>
                 anchorData;     /* Offset to the glyph data table */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh
index 746da3a..7dcf1c3 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh
@@ -82,7 +82,7 @@
   }
 
   protected:
-  GlyphID       stdGlyph;       /* The specific glyph index number in this
+  HBGlyphID     stdGlyph;       /* The specific glyph index number in this
                                  * font that is used to set the baseline values.
                                  * This is the standard glyph.
                                  * This glyph must contain a set of control points
@@ -101,11 +101,11 @@
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && lookupTable.sanitize (c));
+    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c)));
   }
 
   protected:
-  GlyphID       stdGlyph;       /* ditto */
+  HBGlyphID     stdGlyph;       /* ditto */
   HBUINT16      ctlPoints[32];  /* ditto */
   Lookup<HBUINT16>
                 lookupTable;    /* Lookup table that maps glyphs to their
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh
index 7c8e3ce..e1dcd6f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh
@@ -93,8 +93,8 @@
     return_trace (c->check_struct (this) && value.sanitize (c, base));
   }
 
-  GlyphID       last;           /* Last GlyphID in this segment */
-  GlyphID       first;          /* First GlyphID in this segment */
+  HBGlyphID     last;           /* Last GlyphID in this segment */
+  HBGlyphID     first;          /* First GlyphID in this segment */
   T             value;          /* The lookup value (only one) */
   public:
   DEFINE_SIZE_STATIC (4 + T::static_size);
@@ -125,7 +125,7 @@
 
   protected:
   HBUINT16      format;         /* Format identifier--format = 2 */
-  VarSizedBinSearchArrayOf<LookupSegmentSingle<T> >
+  VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
                 segments;       /* The actual segments. These must already be sorted,
                                  * according to the first word in each one (the last
                                  * glyph in each segment). */
@@ -153,18 +153,18 @@
                   first <= last &&
                   valuesZ.sanitize (c, base, last - first + 1));
   }
-  template <typename T2>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T2 user_data) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
                   first <= last &&
-                  valuesZ.sanitize (c, base, last - first + 1, user_data));
+                  valuesZ.sanitize (c, base, last - first + 1, hb_forward<Ts> (ds)...));
   }
 
-  GlyphID       last;           /* Last GlyphID in this segment */
-  GlyphID       first;          /* First GlyphID in this segment */
-  NNOffsetTo<UnsizedArrayOf<T> >
+  HBGlyphID     last;           /* Last GlyphID in this segment */
+  HBGlyphID     first;          /* First GlyphID in this segment */
+  NNOffsetTo<UnsizedArrayOf<T>>
                 valuesZ;        /* A 16-bit offset from the start of
                                  * the table to the data. */
   public:
@@ -196,7 +196,7 @@
 
   protected:
   HBUINT16      format;         /* Format identifier--format = 4 */
-  VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
+  VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
                 segments;       /* The actual segments. These must already be sorted,
                                  * according to the first word in each one (the last
                                  * glyph in each segment). */
@@ -222,7 +222,7 @@
     return_trace (c->check_struct (this) && value.sanitize (c, base));
   }
 
-  GlyphID       glyph;          /* Last GlyphID */
+  HBGlyphID     glyph;          /* Last GlyphID */
   T             value;          /* The lookup value (only one) */
   public:
   DEFINE_SIZE_STATIC (2 + T::static_size);
@@ -253,7 +253,7 @@
 
   protected:
   HBUINT16      format;         /* Format identifier--format = 6 */
-  VarSizedBinSearchArrayOf<LookupSingle<T> >
+  VarSizedBinSearchArrayOf<LookupSingle<T>>
                 entries;        /* The actual entries, sorted by glyph index. */
   public:
   DEFINE_SIZE_ARRAY (8, entries);
@@ -284,7 +284,7 @@
 
   protected:
   HBUINT16      format;         /* Format identifier--format = 8 */
-  GlyphID       firstGlyph;     /* First glyph index included in the trimmed array. */
+  HBGlyphID     firstGlyph;     /* First glyph index included in the trimmed array. */
   HBUINT16      glyphCount;     /* Total number of glyphs (equivalent to the last
                                  * glyph minus the value of firstGlyph plus 1). */
   UnsizedArrayOf<T>
@@ -303,7 +303,7 @@
   const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
   {
     if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
-      return Null(T);
+      return Null (T);
 
     const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
 
@@ -326,7 +326,7 @@
   protected:
   HBUINT16      format;         /* Format identifier--format = 8 */
   HBUINT16      valueSize;      /* Byte size of each value. */
-  GlyphID       firstGlyph;     /* First glyph index included in the trimmed array. */
+  HBGlyphID     firstGlyph;     /* First glyph index included in the trimmed array. */
   HBUINT16      glyphCount;     /* Total number of glyphs (equivalent to the last
                                  * glyph minus the value of firstGlyph plus 1). */
   UnsizedArrayOf<HBUINT8>
@@ -358,7 +358,7 @@
       case 10: return u.format10.get_value_or_null (glyph_id);
       default:
       const T *v = get_value (glyph_id, num_glyphs);
-      return v ? *v : Null(T);
+      return v ? *v : Null (T);
     }
   }
 
@@ -418,15 +418,11 @@
 } /* Close namespace. */
 /* Ugly hand-coded null objects for template Lookup<> :(. */
 extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
-template <>
-/*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > ()
-{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup); }
-template <>
-/*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > ()
-{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup); }
-template <>
-/*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > ()
-{ return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup); }
+template <typename T>
+struct Null<AAT::Lookup<T>> {
+  static AAT::Lookup<T> const & get_null ()
+  { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
+};
 namespace AAT {
 
 enum { DELETED_GLYPH = 0xFFFF };
@@ -514,7 +510,7 @@
   const Entry<Extra> &get_entry (int state, unsigned int klass) const
   {
     if (unlikely (klass >= nClasses))
-      klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS;
+      klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
 
     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
     const Entry<Extra> *entries = (this+entryTable).arrayZ;
@@ -580,7 +576,7 @@
           if (unlikely (stop > states))
             return_trace (false);
           for (const HBUSHORT *p = states; stop < p; p--)
-            num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1);
+            num_entries = hb_max (num_entries, *(p - 1) + 1);
           state_neg = min_state;
         }
       }
@@ -601,7 +597,7 @@
           if (unlikely (stop < states))
             return_trace (false);
           for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
-            num_entries = MAX<unsigned int> (num_entries, *p + 1);
+            num_entries = hb_max (num_entries, *p + 1);
           state_pos = max_state + 1;
         }
       }
@@ -615,8 +611,8 @@
         for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
         {
           int newState = new_state (p->newState);
-          min_state = MIN (min_state, newState);
-          max_state = MAX (max_state, newState);
+          min_state = hb_min (min_state, newState);
+          max_state = hb_max (max_state, newState);
         }
         entry = num_entries;
       }
@@ -635,7 +631,7 @@
                 classTable;     /* Offset to the class table. */
   NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
                 stateArrayTable;/* Offset to the state array. */
-  NNOffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT>
+  NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
                 entryTable;     /* Offset to the entry array. */
 
   public:
@@ -662,7 +658,7 @@
     return_trace (c->check_struct (this) && classArray.sanitize (c));
   }
   protected:
-  GlyphID               firstGlyph;     /* First glyph index included in the trimmed array. */
+  HBGlyphID             firstGlyph;     /* First glyph index included in the trimmed array. */
   ArrayOf<HBUCHAR>      classArray;     /* The class codes (indexed by glyph index minus
                                          * firstGlyph). */
   public:
@@ -682,7 +678,7 @@
                                      const void *base,
                                      const T *array)
   {
-    return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
+    return (offset - ((const char *) array - (const char *) base)) / T::static_size;
   }
   template <typename T>
   static unsigned int byteOffsetToIndex (unsigned int offset,
@@ -824,12 +820,11 @@
 
   /* Unused. For debug tracing only. */
   unsigned int lookup_index;
-  unsigned int debug_depth;
 
   HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
                                       hb_font_t *font_,
                                       hb_buffer_t *buffer_,
-                                      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)));
+                                      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
 
   HB_INTERNAL ~hb_aat_apply_context_t ();
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh
index 910a94f..06c48d2 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh
@@ -47,17 +47,16 @@
   hb_aat_layout_feature_selector_t get_selector () const
   { return (hb_aat_layout_feature_selector_t) (unsigned) setting; }
 
-  void get_info (hb_aat_layout_feature_selector_info_t *s,
-                        hb_aat_layout_feature_selector_t default_selector) const
+  hb_aat_layout_feature_selector_info_t get_info (hb_aat_layout_feature_selector_t default_selector) const
   {
-    s->name_id = nameIndex;
-
-    s->enable = (hb_aat_layout_feature_selector_t) (unsigned int) setting;
-    s->disable = default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID ?
-                 (hb_aat_layout_feature_selector_t) (s->enable + 1) :
-                 default_selector;
-
-    s->reserved = 0;
+    return {
+      nameIndex,
+      (hb_aat_layout_feature_selector_t) (unsigned int) setting,
+      default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID
+        ? (hb_aat_layout_feature_selector_t) (setting + 1)
+        : default_selector,
+      0
+    };
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -117,9 +116,10 @@
 
     if (selectors_count)
     {
-      hb_array_t<const SettingName> arr = settings_table.sub_array (start_offset, selectors_count);
-      for (unsigned int i = 0; i < arr.length; i++)
-        settings_table[start_offset + i].get_info (&selectors[i], default_selector);
+      + settings_table.sub_array (start_offset, selectors_count)
+      | hb_map ([=] (const SettingName& setting) { return setting.get_info (default_selector); })
+      | hb_sink (hb_array (selectors, *selectors_count))
+      ;
     }
     return settings_table.length;
   }
@@ -129,6 +129,11 @@
 
   hb_ot_name_id_t get_feature_name_id () const { return nameIndex; }
 
+  bool is_exclusive () const { return featureFlags & Exclusive; }
+
+  /* A FeatureName with no settings is meaningless */
+  bool has_data () const { return nSettings; }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -139,7 +144,7 @@
   protected:
   HBUINT16      feature;        /* Feature type. */
   HBUINT16      nSettings;      /* The number of records in the setting name array. */
-  LOffsetTo<UnsizedArrayOf<SettingName>, false>
+  LNNOffsetTo<UnsizedArrayOf<SettingName>>
                 settingTableZ;  /* Offset in bytes from the beginning of this table to
                                  * this feature's setting name array. The actual type of
                                  * record this offset refers to will depend on the
@@ -162,21 +167,21 @@
                                   unsigned int                 *count,
                                   hb_aat_layout_feature_type_t *features) const
   {
-    unsigned int feature_count = featureNameCount;
-    if (count && *count)
+    if (count)
     {
-      unsigned int len = MIN (feature_count - start_offset, *count);
-      for (unsigned int i = 0; i < len; i++)
-        features[i] = namesZ[i + start_offset].get_feature_type ();
-      *count = len;
+      + namesZ.as_array (featureNameCount).sub_array (start_offset, count)
+      | hb_map (&FeatureName::get_feature_type)
+      | hb_sink (hb_array (features, *count))
+      ;
     }
     return featureNameCount;
   }
 
+  bool exposes_feature (hb_aat_layout_feature_type_t feature_type) const
+  { return get_feature (feature_type).has_data (); }
+
   const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const
-  {
-    return namesZ.bsearch (featureNameCount, feature_type);
-  }
+  { return namesZ.bsearch (featureNameCount, feature_type); }
 
   hb_ot_name_id_t get_feature_name_id (hb_aat_layout_feature_type_t feature) const
   { return get_feature (feature).get_feature_name_id (); }
@@ -209,7 +214,7 @@
   SortedUnsizedArrayOf<FeatureName>
                 namesZ;         /* The feature name array. */
   public:
-  DEFINE_SIZE_STATIC (24);
+  DEFINE_SIZE_ARRAY (12, namesZ);
 };
 
 } /* namespace AAT */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh
index c3817ea..7ebd6a5 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh
@@ -70,9 +70,9 @@
 
   ActionSubrecordHeader
                 header;
-  Fixed         lowerLimit;     /* If the distance factor is less than this value,
+  HBFixed       lowerLimit;     /* If the distance factor is less than this value,
                                  * then the ligature is decomposed. */
-  Fixed         upperLimit;     /* If the distance factor is greater than this value,
+  HBFixed       upperLimit;     /* If the distance factor is greater than this value,
                                  * then the ligature is decomposed. */
   HBUINT16      order;          /* Numerical order in which this ligature will
                                  * be decomposed; you may want infrequent ligatures
@@ -100,7 +100,7 @@
   protected:
   ActionSubrecordHeader
                 header;
-  GlyphID       addGlyph;       /* Glyph that should be added if the distance factor
+  HBGlyphID     addGlyph;       /* Glyph that should be added if the distance factor
                                  * is growing. */
 
   public:
@@ -118,14 +118,14 @@
   protected:
   ActionSubrecordHeader
                 header;
-  Fixed         substThreshold; /* Distance growth factor (in ems) at which
+  HBFixed       substThreshold; /* Distance growth factor (in ems) at which
                                  * this glyph is replaced and the growth factor
                                  * recalculated. */
-  GlyphID       addGlyph;       /* Glyph to be added as kashida. If this value is
+  HBGlyphID     addGlyph;       /* Glyph to be added as kashida. If this value is
                                  * 0xFFFF, no extra glyph will be added. Note that
                                  * generally when a glyph is added, justification
                                  * will need to be redone. */
-  GlyphID       substGlyph;     /* Glyph to be substituted for this glyph if the
+  HBGlyphID     substGlyph;     /* Glyph to be substituted for this glyph if the
                                  * growth factor equals or exceeds the value of
                                  * substThreshold. */
   public:
@@ -146,13 +146,13 @@
   HBUINT32      variationAxis;  /* The 4-byte tag identifying the ductile axis.
                                  * This would normally be 0x64756374 ('duct'),
                                  * but you may use any axis the font contains. */
-  Fixed         minimumLimit;   /* The lowest value for the ductility axis tha
+  HBFixed       minimumLimit;   /* The lowest value for the ductility axis tha
                                  * still yields an acceptable appearance. Normally
                                  * this will be 1.0. */
-  Fixed         noStretchValue; /* This is the default value that corresponds to
+  HBFixed       noStretchValue; /* This is the default value that corresponds to
                                  * no change in appearance. Normally, this will
                                  * be 1.0. */
-  Fixed         maximumLimit;   /* The highest value for the ductility axis that
+  HBFixed       maximumLimit;   /* The highest value for the ductility axis that
                                  * still yields an acceptable appearance. */
   public:
   DEFINE_SIZE_STATIC (22);
@@ -170,7 +170,7 @@
   ActionSubrecordHeader
                 header;
   HBUINT16      flags;          /* Currently unused; set to 0. */
-  GlyphID       glyph;          /* Glyph that should be added if the distance factor
+  HBGlyphID     glyph;          /* Glyph that should be added if the distance factor
                                  * is growing. */
   public:
   DEFINE_SIZE_STATIC (10);
@@ -271,14 +271,14 @@
   };
 
   protected:
-  Fixed         beforeGrowLimit;/* The ratio by which the advance width of the
+  HBFixed       beforeGrowLimit;/* The ratio by which the advance width of the
                                  * glyph is permitted to grow on the left or top side. */
-  Fixed         beforeShrinkLimit;
+  HBFixed       beforeShrinkLimit;
                                 /* The ratio by which the advance width of the
                                  * glyph is permitted to shrink on the left or top side. */
-  Fixed         afterGrowLimit; /* The ratio by which the advance width of the glyph
+  HBFixed       afterGrowLimit; /* The ratio by which the advance width of the glyph
                                  * is permitted to shrink on the left or top side. */
-  Fixed         afterShrinkLimit;
+  HBFixed       afterShrinkLimit;
                                 /* The ratio by which the advance width of the glyph
                                  * is at most permitted to shrink on the right or
                                  * bottom side. */
@@ -371,7 +371,7 @@
                                  * of postcompensation subtable (set to zero if none).
                                  *
                                  * The postcompensation subtable, if present in the font. */
-  Lookup<OffsetTo<WidthDeltaCluster> >
+  Lookup<OffsetTo<WidthDeltaCluster>>
                 lookupTable;    /* Lookup table associating glyphs with width delta
                                  * clusters. See the description of Width Delta Clusters
                                  * table for details on how to interpret the lookup values. */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh
index b551948..76e1da0 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh
@@ -82,8 +82,8 @@
   }
 
   protected:
-  GlyphID       left;
-  GlyphID       right;
+  HBGlyphID     left;
+  HBGlyphID     right;
   FWORD         value;
   public:
   DEFINE_SIZE_STATIC (6);
@@ -229,9 +229,7 @@
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
                         const Entry<EntryData> &entry)
-    {
-      return Format1EntryT::performAction (entry);
-    }
+    { return Format1EntryT::performAction (entry); }
     void transition (StateTableDriver<Types, EntryData> *driver,
                      const Entry<EntryData> &entry)
     {
@@ -251,7 +249,7 @@
 
       if (Format1EntryT::performAction (entry) && depth)
       {
-        unsigned int tuple_count = MAX (1u, table->header.tuple_count ());
+        unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
 
         unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
         kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
@@ -281,35 +279,28 @@
 
           hb_glyph_position_t &o = buffer->pos[idx];
 
-          /* Testing shows that CoreText only applies kern (cross-stream or not)
-           * if none has been applied by previous subtables.  That is, it does
-           * NOT seem to accumulate as otherwise implied by specs. */
-
-          /* The following flag is undocumented in the spec, but described
-           * in the 'kern' table example. */
-          if (v == -0x8000)
-          {
-            o.attach_type() = ATTACH_TYPE_NONE;
-            o.attach_chain() = 0;
-            o.x_offset = o.y_offset = 0;
-          }
-          else if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+          if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
           {
             if (crossStream)
             {
-              if (buffer->pos[idx].attach_type() && !buffer->pos[idx].y_offset)
+              /* The following flag is undocumented in the spec, but described
+               * in the 'kern' table example. */
+              if (v == -0x8000)
               {
-                o.y_offset = c->font->em_scale_y (v);
+                o.attach_type() = ATTACH_TYPE_NONE;
+                o.attach_chain() = 0;
+                o.y_offset = 0;
+              }
+              else if (o.attach_type())
+              {
+                o.y_offset += c->font->em_scale_y (v);
                 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
               }
             }
             else if (buffer->info[idx].mask & kern_mask)
             {
-              if (!buffer->pos[idx].x_offset)
-              {
-                buffer->pos[idx].x_advance += c->font->em_scale_x (v);
-                buffer->pos[idx].x_offset += c->font->em_scale_x (v);
-              }
+              o.x_advance += c->font->em_scale_x (v);
+              o.x_offset += c->font->em_scale_x (v);
             }
           }
           else
@@ -317,19 +308,22 @@
             if (crossStream)
             {
               /* CoreText doesn't do crossStream kerning in vertical.  We do. */
-              if (buffer->pos[idx].attach_type() && !buffer->pos[idx].x_offset)
+              if (v == -0x8000)
               {
-                o.x_offset = c->font->em_scale_x (v);
+                o.attach_type() = ATTACH_TYPE_NONE;
+                o.attach_chain() = 0;
+                o.x_offset = 0;
+              }
+              else if (o.attach_type())
+              {
+                o.x_offset += c->font->em_scale_x (v);
                 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
               }
             }
             else if (buffer->info[idx].mask & kern_mask)
             {
-              if (!buffer->pos[idx].y_offset)
-              {
-                buffer->pos[idx].y_advance += c->font->em_scale_y (v);
-                buffer->pos[idx].y_offset += c->font->em_scale_y (v);
-              }
+              o.y_advance += c->font->em_scale_y (v);
+              o.y_offset += c->font->em_scale_y (v);
             }
           }
         }
@@ -392,7 +386,7 @@
 
     const UnsizedArrayOf<FWORD> &arrayZ = this+array;
     unsigned int kern_idx = l + r;
-    kern_idx = Types::offsetToIndex (kern_idx, this, &arrayZ);
+    kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
     const FWORD *v = &arrayZ[kern_idx];
     if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
 
@@ -488,7 +482,7 @@
     };
 
     driver_context_t (const KerxSubTableFormat4 *table,
-                             hb_aat_apply_context_t *c_) :
+                      hb_aat_apply_context_t *c_) :
         c (c_),
         action_type ((table->flags & ActionType) >> 30),
         ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
@@ -497,9 +491,7 @@
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
                         const Entry<EntryData> &entry)
-    {
-      return entry.data.ankrActionIndex != 0xFFFF;
-    }
+    { return entry.data.ankrActionIndex != 0xFFFF; }
     void transition (StateTableDriver<Types, EntryData> *driver,
                      const Entry<EntryData> &entry)
     {
@@ -512,11 +504,13 @@
         {
           case 0: /* Control Point Actions.*/
           {
-            /* indexed into glyph outline. */
-            const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+            /* Indexed into glyph outline. */
+            /* Each action (record in ankrData) contains two 16-bit fields, so we must
+               double the ankrActionIndex to get the correct offset here. */
+            const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
             if (!c->sanitizer.check_array (data, 2)) return;
-            HB_UNUSED unsigned int markControlPoint = *data++;
-            HB_UNUSED unsigned int currControlPoint = *data++;
+            unsigned int markControlPoint = *data++;
+            unsigned int currControlPoint = *data++;
             hb_position_t markX = 0;
             hb_position_t markY = 0;
             hb_position_t currX = 0;
@@ -538,8 +532,10 @@
 
           case 1: /* Anchor Point Actions. */
           {
-           /* Indexed into 'ankr' table. */
-            const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+            /* Indexed into 'ankr' table. */
+            /* Each action (record in ankrData) contains two 16-bit fields, so we must
+               double the ankrActionIndex to get the correct offset here. */
+            const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
             if (!c->sanitizer.check_array (data, 2)) return;
             unsigned int markAnchorPoint = *data++;
             unsigned int currAnchorPoint = *data++;
@@ -557,7 +553,9 @@
 
           case 2: /* Control Point Coordinate Actions. */
           {
-            const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex];
+            /* Each action contains four 16-bit fields, so we multiply the ankrActionIndex
+               by 4 to get the correct offset for the given action. */
+            const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
             if (!c->sanitizer.check_array (data, 4)) return;
             int markX = *data++;
             int markY = *data++;
@@ -628,7 +626,7 @@
   bool is_long () const { return flags & ValuesAreLong; }
 
   int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
-                          hb_aat_apply_context_t *c) const
+                   hb_aat_apply_context_t *c) const
   {
     unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
     if (is_long ())
@@ -712,18 +710,18 @@
   {
     struct Long
     {
-      LNNOffsetTo<Lookup<HBUINT32> >            rowIndexTable;
-      LNNOffsetTo<Lookup<HBUINT32> >            columnIndexTable;
-      LNNOffsetTo<UnsizedArrayOf<FWORD32> >     array;
+      LNNOffsetTo<Lookup<HBUINT32>>             rowIndexTable;
+      LNNOffsetTo<Lookup<HBUINT32>>             columnIndexTable;
+      LNNOffsetTo<UnsizedArrayOf<FWORD32>>      array;
     } l;
     struct Short
     {
-      LNNOffsetTo<Lookup<HBUINT16> >            rowIndexTable;
-      LNNOffsetTo<Lookup<HBUINT16> >            columnIndexTable;
-      LNNOffsetTo<UnsizedArrayOf<FWORD> >       array;
+      LNNOffsetTo<Lookup<HBUINT16>>             rowIndexTable;
+      LNNOffsetTo<Lookup<HBUINT16>>             columnIndexTable;
+      LNNOffsetTo<UnsizedArrayOf<FWORD>>        array;
     } s;
   } u;
-  LNNOffsetTo<UnsizedArrayOf<FWORD> >   vector;
+  LNNOffsetTo<UnsizedArrayOf<FWORD>>    vector;
   public:
   DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
 };
@@ -733,8 +731,8 @@
 {
   typedef ExtendedTypes Types;
 
-  unsigned int tuple_count () const { return tupleCount; }
-  bool is_horizontal () const       { return !(coverage & Vertical); }
+  unsigned   tuple_count () const { return tupleCount; }
+  bool     is_horizontal () const { return !(coverage & Vertical); }
 
   enum Coverage
   {
@@ -771,17 +769,17 @@
   unsigned int get_size () const { return u.header.length; }
   unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case 0:     return_trace (c->dispatch (u.format0));
-    case 1:     return_trace (c->dispatch (u.format1));
-    case 2:     return_trace (c->dispatch (u.format2));
-    case 4:     return_trace (c->dispatch (u.format4));
-    case 6:     return_trace (c->dispatch (u.format6));
+    case 0:     return_trace (c->dispatch (u.format0, hb_forward<Ts> (ds)...));
+    case 1:     return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2:     return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    case 4:     return_trace (c->dispatch (u.format4, hb_forward<Ts> (ds)...));
+    case 6:     return_trace (c->dispatch (u.format6, hb_forward<Ts> (ds)...));
     default:    return_trace (c->default_return_value ());
     }
   }
@@ -891,7 +889,7 @@
       reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
                 HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
-      if (!c->buffer->message (c->font, "start %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index))
+      if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index))
         goto skip;
 
       if (!seenCrossStream &&
@@ -923,7 +921,7 @@
       if (reverse)
         c->buffer->reverse ();
 
-      (void) c->buffer->message (c->font, "end %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index);
+      (void) c->buffer->message (c->font, "end subtable %d", c->lookup_index);
 
     skip:
       st = &StructAfter<SubTable> (*st);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-lcar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-lcar-table.hh
deleted file mode 100644
index 58f1ee0..0000000
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-lcar-table.hh
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright © 2018  Ebrahim Byagowi
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-#ifndef HB_AAT_LAYOUT_LCAR_TABLE_HH
-#define HB_AAT_LAYOUT_LCAR_TABLE_HH
-
-#include "hb-open-type.hh"
-#include "hb-aat-layout-common.hh"
-
-/*
- * lcar -- Ligature caret
- * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6lcar.html
- */
-#define HB_AAT_TAG_lcar HB_TAG('l','c','a','r')
-
-
-namespace AAT {
-
-typedef ArrayOf<HBINT16> LigCaretClassEntry;
-
-struct lcar
-{
-  static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
-
-  unsigned int get_lig_carets (hb_font_t      *font,
-                               hb_direction_t  direction,
-                               hb_codepoint_t  glyph,
-                               unsigned int    start_offset,
-                               unsigned int   *caret_count /* IN/OUT */,
-                               hb_position_t  *caret_array /* OUT */) const
-  {
-    const OffsetTo<LigCaretClassEntry>* entry_offset = lookup.get_value (glyph,
-                                                                         font->face->get_num_glyphs ());
-    const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry);
-    if (caret_count)
-    {
-      hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
-      unsigned int count = arr.length;
-      for (unsigned int i = 0; i < count; ++i)
-        switch (format)
-        {
-        case 0: caret_array[i] = font->em_scale_dir (arr[i], direction); break;
-        case 1:
-          hb_position_t x, y;
-          font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y);
-          caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
-          break;
-        }
-    }
-    return array.len;
-  }
-
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) &&
-                          version.major == 1 &&
-                          lookup.sanitize (c, this)));
-  }
-
-  protected:
-  FixedVersion<>version;        /* Version number of the ligature caret table */
-  HBUINT16      format;         /* Format of the ligature caret table. */
-  Lookup<OffsetTo<LigCaretClassEntry> >
-                lookup;         /* data Lookup table associating glyphs */
-
-  public:
-  DEFINE_SIZE_MIN (8);
-};
-
-} /* namespace AAT */
-
-#endif /* HB_AAT_LAYOUT_LCAR_TABLE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh
index f52d2ab..a0d1378 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh
@@ -88,7 +88,7 @@
         start = buffer->idx;
 
       if (flags & MarkLast)
-        end = MIN (buffer->idx + 1, buffer->len);
+        end = hb_min (buffer->idx + 1, buffer->len);
 
       if ((flags & Verb) && start < end)
       {
@@ -117,14 +117,14 @@
         };
 
         unsigned int m = map[flags & Verb];
-        unsigned int l = MIN<unsigned int> (2, m >> 4);
-        unsigned int r = MIN<unsigned int> (2, m & 0x0F);
+        unsigned int l = hb_min (2u, m >> 4);
+        unsigned int r = hb_min (2u, m & 0x0F);
         bool reverse_l = 3 == (m >> 4);
         bool reverse_r = 3 == (m & 0x0F);
 
         if (end - start >= l + r)
         {
-          buffer->merge_clusters (start, MIN (buffer->idx + 1, buffer->len));
+          buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
           buffer->merge_clusters (start, end);
 
           hb_glyph_info_t *info = buffer->info;
@@ -240,46 +240,46 @@
       if (buffer->idx == buffer->len && !mark_set)
         return;
 
-      const GlyphID *replacement;
+      const HBGlyphID *replacement;
 
       replacement = nullptr;
       if (Types::extended)
       {
         if (entry.data.markIndex != 0xFFFF)
         {
-          const Lookup<GlyphID> &lookup = subs[entry.data.markIndex];
+          const Lookup<HBGlyphID> &lookup = subs[entry.data.markIndex];
           replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
         }
       }
       else
       {
         unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
-        const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
+        const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
         replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
         if (!replacement->sanitize (&c->sanitizer) || !*replacement)
           replacement = nullptr;
       }
       if (replacement)
       {
-        buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
+        buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
         buffer->info[mark].codepoint = *replacement;
         ret = true;
       }
 
       replacement = nullptr;
-      unsigned int idx = MIN (buffer->idx, buffer->len - 1);
+      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
       if (Types::extended)
       {
         if (entry.data.currentIndex != 0xFFFF)
         {
-          const Lookup<GlyphID> &lookup = subs[entry.data.currentIndex];
+          const Lookup<HBGlyphID> &lookup = subs[entry.data.currentIndex];
           replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
         }
       }
       else
       {
         unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
-        const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
+        const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
         replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
         if (!replacement->sanitize (&c->sanitizer) || !*replacement)
           replacement = nullptr;
@@ -304,7 +304,7 @@
     bool mark_set;
     unsigned int mark;
     const ContextualSubtable *table;
-    const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false> &subs;
+    const UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false> &subs;
   };
 
   bool apply (hb_aat_apply_context_t *c) const
@@ -337,9 +337,9 @@
       const EntryData &data = entries[i].data;
 
       if (data.markIndex != 0xFFFF)
-        num_lookups = MAX<unsigned int> (num_lookups, 1 + data.markIndex);
+        num_lookups = hb_max (num_lookups, 1 + data.markIndex);
       if (data.currentIndex != 0xFFFF)
-        num_lookups = MAX<unsigned int> (num_lookups, 1 + data.currentIndex);
+        num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
     }
 
     return_trace (substitutionTables.sanitize (c, this, num_lookups));
@@ -348,7 +348,7 @@
   protected:
   StateTable<Types, EntryData>
                 machine;
-  NNOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT>
+  NNOffsetTo<UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false>, HBUINT>
                 substitutionTables;
   public:
   DEFINE_SIZE_STATIC (20);
@@ -520,7 +520,7 @@
           if (action & (LigActionStore | LigActionLast))
           {
             ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
-            const GlyphID &ligatureData = ligature[ligature_idx];
+            const HBGlyphID &ligatureData = ligature[ligature_idx];
             if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
             hb_codepoint_t lig = ligatureData;
 
@@ -554,7 +554,7 @@
     const LigatureSubtable *table;
     const UnsizedArrayOf<HBUINT32> &ligAction;
     const UnsizedArrayOf<HBUINT16> &component;
-    const UnsizedArrayOf<GlyphID> &ligature;
+    const UnsizedArrayOf<HBGlyphID> &ligature;
     unsigned int match_length;
     unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
   };
@@ -586,7 +586,7 @@
                 ligAction;      /* Offset to the ligature action table. */
   NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
                 component;      /* Offset to the component table. */
-  NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT>
+  NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
                 ligature;       /* Offset to the actual ligature lists. */
   public:
   DEFINE_SIZE_STATIC (28);
@@ -606,7 +606,7 @@
     unsigned int count = c->buffer->len;
     for (unsigned int i = 0; i < count; i++)
     {
-      const GlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
+      const HBGlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
       if (replacement)
       {
         info[i].codepoint = *replacement;
@@ -624,7 +624,7 @@
   }
 
   protected:
-  Lookup<GlyphID>       substitute;
+  Lookup<HBGlyphID>     substitute;
   public:
   DEFINE_SIZE_MIN (2);
 };
@@ -725,8 +725,9 @@
       if (entry.data.markedInsertIndex != 0xFFFF)
       {
         unsigned int count = (flags & MarkedInsertCount);
+        if (unlikely ((buffer->max_ops -= count) <= 0)) return;
         unsigned int start = entry.data.markedInsertIndex;
-        const GlyphID *glyphs = &insertionAction[start];
+        const HBGlyphID *glyphs = &insertionAction[start];
         if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
         bool before = flags & MarkedInsertBefore;
@@ -744,7 +745,7 @@
 
         buffer->move_to (end + count);
 
-        buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
+        buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
       }
 
       if (flags & SetMark)
@@ -753,8 +754,9 @@
       if (entry.data.currentInsertIndex != 0xFFFF)
       {
         unsigned int count = (flags & CurrentInsertCount) >> 5;
+        if (unlikely ((buffer->max_ops -= count) <= 0)) return;
         unsigned int start = entry.data.currentInsertIndex;
-        const GlyphID *glyphs = &insertionAction[start];
+        const HBGlyphID *glyphs = &insertionAction[start];
         if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
         bool before = flags & CurrentInsertBefore;
@@ -793,7 +795,7 @@
     private:
     hb_aat_apply_context_t *c;
     unsigned int mark;
-    const UnsizedArrayOf<GlyphID> &insertionAction;
+    const UnsizedArrayOf<HBGlyphID> &insertionAction;
   };
 
   bool apply (hb_aat_apply_context_t *c) const
@@ -819,7 +821,7 @@
   protected:
   StateTable<Types, EntryData>
                 machine;
-  NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT>
+  NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
                 insertionAction;        /* Byte offset from stateHeader to the start of
                                          * the insertion glyph table. */
   public:
@@ -883,17 +885,17 @@
     Insertion           = 5
   };
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case Rearrangement:         return_trace (c->dispatch (u.rearrangement));
-    case Contextual:            return_trace (c->dispatch (u.contextual));
-    case Ligature:              return_trace (c->dispatch (u.ligature));
-    case Noncontextual:         return_trace (c->dispatch (u.noncontextual));
-    case Insertion:             return_trace (c->dispatch (u.insertion));
+    case Rearrangement:         return_trace (c->dispatch (u.rearrangement, hb_forward<Ts> (ds)...));
+    case Contextual:            return_trace (c->dispatch (u.contextual, hb_forward<Ts> (ds)...));
+    case Ligature:              return_trace (c->dispatch (u.ligature, hb_forward<Ts> (ds)...));
+    case Noncontextual:         return_trace (c->dispatch (u.noncontextual, hb_forward<Ts> (ds)...));
+    case Insertion:             return_trace (c->dispatch (u.insertion, hb_forward<Ts> (ds)...));
     default:                    return_trace (c->default_return_value ());
     }
   }
@@ -948,8 +950,10 @@
         hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
         hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
       retry:
-        const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type);
-        if (info && info->setting == setting)
+        // Check whether this type/setting pair was requested in the map, and if so, apply its flags.
+        // (The search here only looks at the type and setting fields of feature_info_t.)
+        hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
+        if (map->features.bsearch (info))
         {
           flags &= feature.disableFlags;
           flags |= feature.enableFlags;
@@ -967,9 +971,9 @@
   }
 
   void apply (hb_aat_apply_context_t *c,
-                     hb_mask_t flags) const
+              hb_mask_t flags) const
   {
-    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
+    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
     unsigned int count = subtableCount;
     for (unsigned int i = 0; i < count; i++)
     {
@@ -1015,7 +1019,7 @@
                 bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
                 HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
-      if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
+      if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index))
         goto skip;
 
       if (reverse)
@@ -1026,12 +1030,12 @@
       if (reverse)
         c->buffer->reverse ();
 
-      (void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
+      (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index);
 
       if (unlikely (!c->buffer->successful)) return;
 
     skip:
-      subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
+      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
       c->set_lookup_index (c->lookup_index + 1);
     }
   }
@@ -1049,13 +1053,13 @@
     if (!c->check_array (featureZ.arrayZ, featureCount))
       return_trace (false);
 
-    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
+    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
     unsigned int count = subtableCount;
     for (unsigned int i = 0; i < count; i++)
     {
       if (!subtable->sanitize (c))
         return_trace (false);
-      subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
+      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
     }
 
     return_trace (true);
@@ -1080,10 +1084,10 @@
  * The 'mort'/'morx' Table
  */
 
-template <typename Types>
+template <typename Types, hb_tag_t TAG>
 struct mortmorx
 {
-  static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
+  static constexpr hb_tag_t tableTag = TAG;
 
   bool has_data () const { return version != 0; }
 
@@ -1095,7 +1099,7 @@
     for (unsigned int i = 0; i < count; i++)
     {
       map->chain_flags.push (chain->compile_flags (mapper));
-      chain = &StructAfter<Chain<Types> > (*chain);
+      chain = &StructAfter<Chain<Types>> (*chain);
     }
   }
 
@@ -1109,7 +1113,7 @@
     {
       chain->apply (c, c->plan->aat_map.chain_flags[i]);
       if (unlikely (!c->buffer->successful)) return;
-      chain = &StructAfter<Chain<Types> > (*chain);
+      chain = &StructAfter<Chain<Types>> (*chain);
     }
   }
 
@@ -1125,7 +1129,7 @@
     {
       if (!chain->sanitize (c, version))
         return_trace (false);
-      chain = &StructAfter<Chain<Types> > (*chain);
+      chain = &StructAfter<Chain<Types>> (*chain);
     }
 
     return_trace (true);
@@ -1143,14 +1147,8 @@
   DEFINE_SIZE_MIN (8);
 };
 
-struct morx : mortmorx<ExtendedTypes>
-{
-  static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
-};
-struct mort : mortmorx<ObsoleteTypes>
-{
-  static constexpr hb_tag_t tableTag = HB_AAT_TAG_mort;
-};
+struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {};
+struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {};
 
 
 } /* namespace AAT */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh
new file mode 100644
index 0000000..bfd476c
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_AAT_LAYOUT_OPBD_TABLE_HH
+#define HB_AAT_LAYOUT_OPBD_TABLE_HH
+
+#include "hb-aat-layout-common.hh"
+#include "hb-open-type.hh"
+
+/*
+ * opbd -- Optical Bounds
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6opbd.html
+ */
+#define HB_AAT_TAG_opbd HB_TAG('o','p','b','d')
+
+
+namespace AAT {
+
+struct OpticalBounds
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  FWORD         leftSide;
+  FWORD         topSide;
+  FWORD         rightSide;
+  FWORD         bottomSide;
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct opbdFormat0
+{
+  bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
+                   hb_glyph_extents_t *extents, const void *base) const
+  {
+    const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
+    if (!bounds_offset) return false;
+    const OpticalBounds &bounds = base+*bounds_offset;
+
+    if (extents)
+      *extents = {
+        font->em_scale_x (bounds.leftSide),
+        font->em_scale_y (bounds.topSide),
+        font->em_scale_x (bounds.rightSide),
+        font->em_scale_y (bounds.bottomSide)
+      };
+    return true;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
+  }
+
+  protected:
+  Lookup<OffsetTo<OpticalBounds>>
+                lookupTable;    /* Lookup table associating glyphs with the four
+                                 * int16 values for the left-side, top-side,
+                                 * right-side, and bottom-side optical bounds. */
+  public:
+  DEFINE_SIZE_MIN (2);
+};
+
+struct opbdFormat1
+{
+  bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
+                   hb_glyph_extents_t *extents, const void *base) const
+  {
+    const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
+    if (!bounds_offset) return false;
+    const OpticalBounds &bounds = base+*bounds_offset;
+
+    hb_position_t left = 0, top = 0, right = 0, bottom = 0, ignore;
+    if (font->get_glyph_contour_point (glyph_id, bounds.leftSide, &left, &ignore) ||
+        font->get_glyph_contour_point (glyph_id, bounds.topSide, &ignore, &top) ||
+        font->get_glyph_contour_point (glyph_id, bounds.rightSide, &right, &ignore) ||
+        font->get_glyph_contour_point (glyph_id, bounds.bottomSide, &ignore, &bottom))
+    {
+      if (extents)
+        *extents = {left, top, right, bottom};
+      return true;
+    }
+    return false;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
+  }
+
+  protected:
+  Lookup<OffsetTo<OpticalBounds>>
+                lookupTable;    /* Lookup table associating glyphs with the four
+                                 * int16 values for the left-side, top-side,
+                                 * right-side, and bottom-side optical bounds. */
+  public:
+  DEFINE_SIZE_MIN (2);
+};
+
+struct opbd
+{
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_opbd;
+
+  bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
+                   hb_glyph_extents_t *extents) const
+  {
+    switch (format)
+    {
+    case 0: return u.format0.get_bounds (font, glyph_id, extents, this);
+    case 1: return u.format1.get_bounds (font, glyph_id, extents, this);
+    default:return false;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this) || version.major != 1))
+      return_trace (false);
+
+    switch (format)
+    {
+    case 0: return_trace (u.format0.sanitize (c, this));
+    case 1: return_trace (u.format1.sanitize (c, this));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  FixedVersion<>version;        /* Version number of the optical bounds
+                                 * table (0x00010000 for the current version). */
+  HBUINT16      format;         /* Format of the optical bounds table.
+                                 * Format 0 indicates distance and Format 1 indicates
+                                 * control point. */
+  union {
+  opbdFormat0   format0;
+  opbdFormat1   format1;
+  } u;
+  public:
+  DEFINE_SIZE_MIN (8);
+};
+
+} /* namespace AAT */
+
+
+#endif /* HB_AAT_LAYOUT_OPBD_TABLE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh
index 469cae5..1643e14 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh
@@ -62,11 +62,11 @@
   }
 
   protected:
-  Fixed         track;          /* Track value for this record. */
+  HBFixed       track;          /* Track value for this record. */
   NameID        trackNameID;    /* The 'name' table index for this track.
                                  * (a short word or phrase like "loose"
                                  * or "very tight") */
-  NNOffsetTo<UnsizedArrayOf<FWORD> >
+  NNOffsetTo<UnsizedArrayOf<FWORD>>
                 valuesZ;        /* Offset from start of tracking table to
                                  * per-size tracking values for this track. */
 
@@ -82,7 +82,7 @@
                         const void *base) const
   {
     unsigned int sizes = nSizes;
-    hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
+    hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
 
     float s0 = size_table[idx].to_float ();
     float s1 = size_table[idx + 1].to_float ();
@@ -93,13 +93,6 @@
 
   int get_tracking (const void *base, float ptem) const
   {
-    /* CoreText points are CSS pixels (96 per inch),
-     * NOT typographic points (72 per inch).
-     *
-     * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
-     */
-    float csspx = ptem * 96.f / 72.f;
-
     /*
      * Choose track.
      */
@@ -127,14 +120,14 @@
     if (!sizes) return 0.;
     if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
 
-    hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
+    hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
     unsigned int size_index;
     for (size_index = 0; size_index < sizes - 1; size_index++)
-      if (size_table[size_index].to_float () >= csspx)
+      if (size_table[size_index].to_float () >= ptem)
         break;
 
-    return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
-                                  *trackTableEntry, base));
+    return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
+                                   *trackTableEntry, base));
   }
 
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -148,7 +141,7 @@
   protected:
   HBUINT16      nTracks;        /* Number of separate tracks included in this table. */
   HBUINT16      nSizes;         /* Number of point sizes included in this table. */
-  LOffsetTo<UnsizedArrayOf<Fixed>, false>
+  LNNOffsetTo<UnsizedArrayOf<HBFixed>>
                 sizeTable;      /* Offset from start of the tracking table to
                                  * Array[nSizes] of size values.. */
   UnsizedArrayOf<TrackTableEntry>
@@ -217,7 +210,7 @@
 
   protected:
   FixedVersion<>version;        /* Version of the tracking table
-                                         * (0x00010000u for version 1.0). */
+                                 * (0x00010000u for version 1.0). */
   HBUINT16      format;         /* Format of the tracking table (set to 0). */
   OffsetTo<TrackData>
                 horizData;      /* Offset from start of tracking table to TrackData
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc
index a49729d..38a5c57 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc
@@ -25,11 +25,9 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-open-type.hh"
+#include "hb.hh"
 
-#include "hb-ot-face.hh"
 #include "hb-aat-layout.hh"
-#include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-aat-layout-ankr-table.hh"
 #include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-aat-layout-feat-table.hh"
@@ -40,6 +38,41 @@
 #include "hb-aat-ltag-table.hh"
 
 
+/*
+ * hb_aat_apply_context_t
+ */
+
+/* Note: This context is used for kerning, even without AAT, hence the condition. */
+#if !defined(HB_NO_AAT) || !defined(HB_NO_OT_KERN)
+
+AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
+                                                     hb_font_t *font_,
+                                                     hb_buffer_t *buffer_,
+                                                     hb_blob_t *blob) :
+                                                       plan (plan_),
+                                                       font (font_),
+                                                       face (font->face),
+                                                       buffer (buffer_),
+                                                       sanitizer (),
+                                                       ankr_table (&Null (AAT::ankr)),
+                                                       lookup_index (0)
+{
+  sanitizer.init (blob);
+  sanitizer.set_num_glyphs (face->get_num_glyphs ());
+  sanitizer.start_processing ();
+  sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
+}
+
+AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
+{ sanitizer.end_processing (); }
+
+void
+AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
+{ ankr_table = ankr_table_; }
+
+#endif
+
+
 /**
  * SECTION:hb-aat-layout
  * @title: hb-aat-layout
@@ -50,6 +83,8 @@
  **/
 
 
+#if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
+
 /* Table data courtesy of Apple.  Converted from mnemonics to integers
  * when moving to this file. */
 static const hb_aat_feature_mapping_t feature_mappings[] =
@@ -135,44 +170,12 @@
 const hb_aat_feature_mapping_t *
 hb_aat_layout_find_feature_mapping (hb_tag_t tag)
 {
-  return (const hb_aat_feature_mapping_t *) bsearch (&tag,
-                                                     feature_mappings,
-                                                     ARRAY_LENGTH (feature_mappings),
-                                                     sizeof (feature_mappings[0]),
-                                                     hb_aat_feature_mapping_t::cmp);
+  return hb_sorted_array (feature_mappings).bsearch (tag);
 }
+#endif
 
 
-/*
- * hb_aat_apply_context_t
- */
-
-AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
-                                                     hb_font_t *font_,
-                                                     hb_buffer_t *buffer_,
-                                                     hb_blob_t *blob) :
-                                                       plan (plan_),
-                                                       font (font_),
-                                                       face (font->face),
-                                                       buffer (buffer_),
-                                                       sanitizer (),
-                                                       ankr_table (&Null(AAT::ankr)),
-                                                       lookup_index (0),
-                                                       debug_depth (0)
-{
-  sanitizer.init (blob);
-  sanitizer.set_num_glyphs (face->get_num_glyphs ());
-  sanitizer.start_processing ();
-  sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
-}
-
-AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
-{ sanitizer.end_processing (); }
-
-void
-AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
-{ ankr_table = ankr_table_; }
-
+#ifndef HB_NO_AAT
 
 /*
  * mort/morx/kerx/trak
@@ -311,14 +314,6 @@
   trak.apply (&c);
 }
 
-
-hb_language_t
-_hb_aat_language_get (hb_face_t *face,
-                      unsigned int i)
-{
-  return face->table.ltag->get_language (i);
-}
-
 /**
  * hb_aat_layout_get_feature_types:
  * @face: a face object
@@ -382,3 +377,6 @@
 {
   return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.h b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.h
index 42540f2..977599e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.h
@@ -85,7 +85,7 @@
   HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE                  = 39,
   HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE             = 103,
 
-  _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
+  _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_aat_layout_feature_type_t;
 
 /**
@@ -424,7 +424,7 @@
   HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN              = 2,
   HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN           = 3,
 
-  _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
+  _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_aat_layout_feature_selector_t;
 
 HB_EXTERN unsigned int
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh
index 80b6a1d..1a95507 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh
@@ -30,7 +30,7 @@
 #include "hb.hh"
 
 #include "hb-ot-shape.hh"
-
+#include "hb-aat-ltag-table.hh"
 
 struct hb_aat_feature_mapping_t
 {
@@ -39,14 +39,8 @@
   hb_aat_layout_feature_selector_t selectorToEnable;
   hb_aat_layout_feature_selector_t selectorToDisable;
 
-  static int cmp (const void *key_, const void *entry_)
-  {
-    hb_tag_t key = * (unsigned int *) key_;
-    const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_;
-    return key < entry->otFeatureTag ? -1 :
-           key > entry->otFeatureTag ? 1 :
-           0;
-  }
+  int cmp (hb_tag_t key) const
+  { return key < otFeatureTag ? -1 : key > otFeatureTag ? 1 : 0; }
 };
 
 HB_INTERNAL const hb_aat_feature_mapping_t *
@@ -77,9 +71,5 @@
                      hb_font_t *font,
                      hb_buffer_t *buffer);
 
-HB_INTERNAL hb_language_t
-_hb_aat_language_get (hb_face_t *face,
-                      unsigned int i);
-
 
 #endif /* HB_AAT_LAYOUT_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-ltag-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-ltag-table.hh
index 23649f8..f42ca23 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-ltag-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-ltag-table.hh
@@ -50,7 +50,7 @@
   }
 
   protected:
-  NNOffsetTo<UnsizedArrayOf<HBUINT8> >
+  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
                 tag;            /* Offset from the start of the table to
                                  * the beginning of the string */
   HBUINT16      length;         /* String length (in bytes) */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc
index c3d078d..ad3eff7 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc
@@ -26,28 +26,55 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_AAT_SHAPE
+
 #include "hb-aat-map.hh"
 
 #include "hb-aat-layout.hh"
+#include "hb-aat-layout-feat-table.hh"
 
 
-void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
-                                        unsigned int value)
+void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
 {
+  if (!face->table.feat->has_data ()) return;
+
   if (tag == HB_TAG ('a','a','l','t'))
   {
+    if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
+      return;
     feature_info_t *info = features.push();
     info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
     info->setting = (hb_aat_layout_feature_selector_t) value;
+    info->seq = features.length;
+    info->is_exclusive = true;
     return;
   }
 
   const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
   if (!mapping) return;
 
+  const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType);
+  if (!feature->has_data ())
+  {
+    /* Special case: Chain::compile_flags will fall back to the deprecated version of
+     * small-caps if necessary, so we need to check for that possibility.
+     * https://github.com/harfbuzz/harfbuzz/issues/2307 */
+    if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
+        mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
+    {
+      feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
+      if (!feature->has_data ()) return;
+    }
+    else return;
+  }
+
   feature_info_t *info = features.push();
   info->type = mapping->aatFeatureType;
   info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
+  info->seq = features.length;
+  info->is_exclusive = feature->is_exclusive ();
 }
 
 void
@@ -59,10 +86,17 @@
     features.qsort ();
     unsigned int j = 0;
     for (unsigned int i = 1; i < features.length; i++)
-      if (features[i].type != features[j].type)
+      if (features[i].type != features[j].type ||
+          /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
+           * respectively, so we mask out the low-order bit when checking for "duplicates"
+           * (selectors referring to the same feature setting) here. */
+          (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1))))
         features[++j] = features[i];
     features.shrink (j + 1);
   }
 
   hb_aat_layout_compile_map (this, &m);
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh
index 594d48e..ce30daa 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh
@@ -64,19 +64,24 @@
   {
     hb_aat_layout_feature_type_t  type;
     hb_aat_layout_feature_selector_t  setting;
+    bool is_exclusive;
     unsigned  seq; /* For stable sorting only. */
 
-    static int cmp (const void *pa, const void *pb)
+    HB_INTERNAL static int cmp (const void *pa, const void *pb)
     {
       const feature_info_t *a = (const feature_info_t *) pa;
       const feature_info_t *b = (const feature_info_t *) pb;
-      return (a->type != b->type) ? (a->type < b->type ? -1 : 1) :
-             (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
+      if (a->type != b->type) return (a->type < b->type ? -1 : 1);
+      if (!a->is_exclusive &&
+          (a->setting & ~1) != (b->setting & ~1)) return (a->setting < b->setting ? -1 : 1);
+            return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
     }
 
-    int cmp (hb_aat_layout_feature_type_t ty) const
+    /* compares type & setting only, not is_exclusive flag or seq number */
+    int cmp (const feature_info_t& f) const
     {
-      return (type != ty) ? (type < ty ? -1 : 1) : 0;
+      return (f.type != type) ? (f.type < type ? -1 : 1) :
+             (f.setting != setting) ? (f.setting < setting ? -1 : 1) : 0;
     }
   };
 
@@ -84,7 +89,7 @@
   hb_face_t *face;
 
   public:
-  hb_vector_t<feature_info_t> features;
+  hb_sorted_vector_t<feature_info_t> features;
 };
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
new file mode 100644
index 0000000..e21cb54
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
@@ -0,0 +1,1127 @@
+/*
+ * Copyright © 2017  Google, Inc.
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_ALGS_HH
+#define HB_ALGS_HH
+
+#include "hb.hh"
+#include "hb-meta.hh"
+#include "hb-null.hh"
+#include "hb-number.hh"
+
+
+/* Encodes three unsigned integers in one 64-bit number.  If the inputs have more than 21 bits,
+ * values will be truncated / overlap, and might not decode exactly. */
+#define HB_CODEPOINT_ENCODE3(x,y,z) (((uint64_t) (x) << 42) | ((uint64_t) (y) << 21) | (uint64_t) (z))
+#define HB_CODEPOINT_DECODE3_1(v) ((hb_codepoint_t) ((v) >> 42))
+#define HB_CODEPOINT_DECODE3_2(v) ((hb_codepoint_t) ((v) >> 21) & 0x1FFFFFu)
+#define HB_CODEPOINT_DECODE3_3(v) ((hb_codepoint_t) (v) & 0x1FFFFFu)
+
+/* Custom encoding used by hb-ucd. */
+#define HB_CODEPOINT_ENCODE3_11_7_14(x,y,z) (((uint32_t) ((x) & 0x07FFu) << 21) | (((uint32_t) (y) & 0x007Fu) << 14) | (uint32_t) ((z) & 0x3FFFu))
+#define HB_CODEPOINT_DECODE3_11_7_14_1(v) ((hb_codepoint_t) ((v) >> 21))
+#define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300)
+#define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu)
+
+struct
+{
+  /* Note.  This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
+  template <typename T> constexpr auto
+  operator () (T&& v) const HB_AUTO_RETURN ( hb_forward<T> (v) )
+}
+HB_FUNCOBJ (hb_identity);
+struct
+{
+  /* Like identity(), but only retains lvalue-references.  Rvalues are returned as rvalues. */
+  template <typename T> constexpr T&
+  operator () (T& v) const { return v; }
+
+  template <typename T> constexpr hb_remove_reference<T>
+  operator () (T&& v) const { return v; }
+}
+HB_FUNCOBJ (hb_lidentity);
+struct
+{
+  /* Like identity(), but always returns rvalue. */
+  template <typename T> constexpr hb_remove_reference<T>
+  operator () (T&& v) const { return v; }
+}
+HB_FUNCOBJ (hb_ridentity);
+
+struct
+{
+  template <typename T> constexpr bool
+  operator () (T&& v) const { return bool (hb_forward<T> (v)); }
+}
+HB_FUNCOBJ (hb_bool);
+
+struct
+{
+  private:
+
+  template <typename T> constexpr auto
+  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
+
+  template <typename T,
+            hb_enable_if (hb_is_integral (T))> constexpr auto
+  impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN
+  (
+    /* Knuth's multiplicative method: */
+    (uint32_t) v * 2654435761u
+  )
+
+  public:
+
+  template <typename T> constexpr auto
+  operator () (const T& v) const HB_RETURN (uint32_t, impl (v, hb_prioritize))
+}
+HB_FUNCOBJ (hb_hash);
+
+
+struct
+{
+  private:
+
+  /* Pointer-to-member-function. */
+  template <typename Appl, typename T, typename ...Ts> auto
+  impl (Appl&& a, hb_priority<2>, T &&v, Ts&&... ds) const HB_AUTO_RETURN
+  ((hb_deref (hb_forward<T> (v)).*hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
+
+  /* Pointer-to-member. */
+  template <typename Appl, typename T> auto
+  impl (Appl&& a, hb_priority<1>, T &&v) const HB_AUTO_RETURN
+  ((hb_deref (hb_forward<T> (v))).*hb_forward<Appl> (a))
+
+  /* Operator(). */
+  template <typename Appl, typename ...Ts> auto
+  impl (Appl&& a, hb_priority<0>, Ts&&... ds) const HB_AUTO_RETURN
+  (hb_deref (hb_forward<Appl> (a)) (hb_forward<Ts> (ds)...))
+
+  public:
+
+  template <typename Appl, typename ...Ts> auto
+  operator () (Appl&& a, Ts&&... ds) const HB_AUTO_RETURN
+  (
+    impl (hb_forward<Appl> (a),
+          hb_prioritize,
+          hb_forward<Ts> (ds)...)
+  )
+}
+HB_FUNCOBJ (hb_invoke);
+
+template <unsigned Pos, typename Appl, typename V>
+struct hb_partial_t
+{
+  hb_partial_t (Appl a, V v) : a (a), v (v) {}
+
+  static_assert (Pos > 0, "");
+
+  template <typename ...Ts,
+            unsigned P = Pos,
+            hb_enable_if (P == 1)> auto
+  operator () (Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
+                                                   hb_declval (V),
+                                                   hb_declval (Ts)...))
+  {
+    return hb_invoke (hb_forward<Appl> (a),
+                      hb_forward<V> (v),
+                      hb_forward<Ts> (ds)...);
+  }
+  template <typename T0, typename ...Ts,
+            unsigned P = Pos,
+            hb_enable_if (P == 2)> auto
+  operator () (T0&& d0, Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
+                                                            hb_declval (T0),
+                                                            hb_declval (V),
+                                                            hb_declval (Ts)...))
+  {
+    return hb_invoke (hb_forward<Appl> (a),
+                      hb_forward<T0> (d0),
+                      hb_forward<V> (v),
+                      hb_forward<Ts> (ds)...);
+  }
+
+  private:
+  hb_reference_wrapper<Appl> a;
+  V v;
+};
+template <unsigned Pos=1, typename Appl, typename V>
+auto hb_partial (Appl&& a, V&& v) HB_AUTO_RETURN
+(( hb_partial_t<Pos, Appl, V> (a, v) ))
+
+/* The following, HB_PARTIALIZE, macro uses a particular corner-case
+ * of C++11 that is not particularly well-supported by all compilers.
+ * What's happening is that it's using "this" in a trailing return-type
+ * via decltype().  Broken compilers deduce the type of "this" pointer
+ * in that context differently from what it resolves to in the body
+ * of the function.
+ *
+ * One probable cause of this is that at the time of trailing return
+ * type declaration, "this" points to an incomplete type, whereas in
+ * the function body the type is complete.  That doesn't justify the
+ * error in any way, but is probably what's happening.
+ *
+ * In the case of MSVC, we get around this by using C++14 "decltype(auto)"
+ * which deduces the type from the actual return statement.  For gcc 4.8
+ * we use "+this" instead of "this" which produces an rvalue that seems
+ * to be deduced as the same type with this particular compiler, and seem
+ * to be fine as default code path as well.
+ */
+#ifdef _MSC_VER
+/* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \
+#define HB_PARTIALIZE(Pos) \
+  template <typename _T> \
+  decltype(auto) operator () (_T&& _v) const \
+  { return hb_partial<Pos> (this, hb_forward<_T> (_v)); } \
+  static_assert (true, "")
+#else
+/* https://github.com/harfbuzz/harfbuzz/issues/1724 */
+#define HB_PARTIALIZE(Pos) \
+  template <typename _T> \
+  auto operator () (_T&& _v) const HB_AUTO_RETURN \
+  (hb_partial<Pos> (+this, hb_forward<_T> (_v))) \
+  static_assert (true, "")
+#endif
+
+
+struct
+{
+  private:
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
+  (hb_deref (hb_forward<Pred> (p)).has (hb_forward<Val> (v)))
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
+  (
+    hb_invoke (hb_forward<Pred> (p),
+               hb_forward<Val> (v))
+  )
+
+  public:
+
+  template <typename Pred, typename Val> auto
+  operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
+    impl (hb_forward<Pred> (p),
+          hb_forward<Val> (v),
+          hb_prioritize)
+  )
+}
+HB_FUNCOBJ (hb_has);
+
+struct
+{
+  private:
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
+  (
+    hb_has (hb_forward<Pred> (p),
+            hb_forward<Val> (v))
+  )
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
+  (
+    hb_forward<Pred> (p) == hb_forward<Val> (v)
+  )
+
+  public:
+
+  template <typename Pred, typename Val> auto
+  operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
+    impl (hb_forward<Pred> (p),
+          hb_forward<Val> (v),
+          hb_prioritize)
+  )
+}
+HB_FUNCOBJ (hb_match);
+
+struct
+{
+  private:
+
+  template <typename Proj, typename Val> auto
+  impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN
+  (hb_deref (hb_forward<Proj> (f)).get (hb_forward<Val> (v)))
+
+  template <typename Proj, typename Val> auto
+  impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
+  (
+    hb_invoke (hb_forward<Proj> (f),
+               hb_forward<Val> (v))
+  )
+
+  template <typename Proj, typename Val> auto
+  impl (Proj&& f, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
+  (
+    hb_forward<Proj> (f)[hb_forward<Val> (v)]
+  )
+
+  public:
+
+  template <typename Proj, typename Val> auto
+  operator () (Proj&& f, Val &&v) const HB_AUTO_RETURN
+  (
+    impl (hb_forward<Proj> (f),
+          hb_forward<Val> (v),
+          hb_prioritize)
+  )
+}
+HB_FUNCOBJ (hb_get);
+
+
+template <typename T1, typename T2>
+struct hb_pair_t
+{
+  typedef T1 first_t;
+  typedef T2 second_t;
+  typedef hb_pair_t<T1, T2> pair_t;
+
+  hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
+
+  template <typename Q1, typename Q2,
+            hb_enable_if (hb_is_convertible (T1, Q1) &&
+                          hb_is_convertible (T2, T2))>
+  operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); }
+
+  hb_pair_t<T1, T2> reverse () const
+  { return hb_pair_t<T1, T2> (second, first); }
+
+  bool operator == (const pair_t& o) const { return first == o.first && second == o.second; }
+  bool operator != (const pair_t& o) const { return !(*this == o); }
+  bool operator < (const pair_t& o) const { return first < o.first || (first == o.first && second < o.second); }
+  bool operator >= (const pair_t& o) const { return !(*this < o); }
+  bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); }
+  bool operator <= (const pair_t& o) const { return !(*this > o); }
+
+  T1 first;
+  T2 second;
+};
+#define hb_pair_t(T1,T2) hb_pair_t<T1, T2>
+template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
+hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
+
+struct
+{
+  template <typename Pair> constexpr typename Pair::first_t
+  operator () (const Pair& pair) const { return pair.first; }
+}
+HB_FUNCOBJ (hb_first);
+
+struct
+{
+  template <typename Pair> constexpr typename Pair::second_t
+  operator () (const Pair& pair) const { return pair.second; }
+}
+HB_FUNCOBJ (hb_second);
+
+/* Note.  In min/max impl, we can use hb_type_identity<T> for second argument.
+ * However, that would silently convert between different-signedness integers.
+ * Instead we accept two different types, such that compiler can err if
+ * comparing integers of different signedness. */
+struct
+{
+  template <typename T, typename T2> constexpr auto
+  operator () (T&& a, T2&& b) const HB_AUTO_RETURN
+  (hb_forward<T> (a) <= hb_forward<T2> (b) ? hb_forward<T> (a) : hb_forward<T2> (b))
+}
+HB_FUNCOBJ (hb_min);
+struct
+{
+  template <typename T, typename T2> constexpr auto
+  operator () (T&& a, T2&& b) const HB_AUTO_RETURN
+  (hb_forward<T> (a) >= hb_forward<T2> (b) ? hb_forward<T> (a) : hb_forward<T2> (b))
+}
+HB_FUNCOBJ (hb_max);
+struct
+{
+  template <typename T, typename T2, typename T3> constexpr auto
+  operator () (T&& x, T2&& min, T3&& max) const HB_AUTO_RETURN
+  (hb_min (hb_max (hb_forward<T> (x), hb_forward<T2> (min)), hb_forward<T3> (max)))
+}
+HB_FUNCOBJ (hb_clamp);
+
+
+/*
+ * Bithacks.
+ */
+
+/* Return the number of 1 bits in v. */
+template <typename T>
+static inline HB_CONST_FUNC unsigned int
+hb_popcount (T v)
+{
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+  if (sizeof (T) <= sizeof (unsigned int))
+    return __builtin_popcount (v);
+
+  if (sizeof (T) <= sizeof (unsigned long))
+    return __builtin_popcountl (v);
+
+  if (sizeof (T) <= sizeof (unsigned long long))
+    return __builtin_popcountll (v);
+#endif
+
+  if (sizeof (T) <= 4)
+  {
+    /* "HACKMEM 169" */
+    uint32_t y;
+    y = (v >> 1) &033333333333;
+    y = v - y - ((y >>1) & 033333333333);
+    return (((y + (y >> 3)) & 030707070707) % 077);
+  }
+
+  if (sizeof (T) == 8)
+  {
+    unsigned int shift = 32;
+    return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
+  }
+
+  if (sizeof (T) == 16)
+  {
+    unsigned int shift = 64;
+    return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
+  }
+
+  assert (0);
+  return 0; /* Shut up stupid compiler. */
+}
+
+/* Returns the number of bits needed to store number */
+template <typename T>
+static inline HB_CONST_FUNC unsigned int
+hb_bit_storage (T v)
+{
+  if (unlikely (!v)) return 0;
+
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+  if (sizeof (T) <= sizeof (unsigned int))
+    return sizeof (unsigned int) * 8 - __builtin_clz (v);
+
+  if (sizeof (T) <= sizeof (unsigned long))
+    return sizeof (unsigned long) * 8 - __builtin_clzl (v);
+
+  if (sizeof (T) <= sizeof (unsigned long long))
+    return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
+#endif
+
+#if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
+  if (sizeof (T) <= sizeof (unsigned int))
+  {
+    unsigned long where;
+    _BitScanReverse (&where, v);
+    return 1 + where;
+  }
+# if defined(_WIN64)
+  if (sizeof (T) <= 8)
+  {
+    unsigned long where;
+    _BitScanReverse64 (&where, v);
+    return 1 + where;
+  }
+# endif
+#endif
+
+  if (sizeof (T) <= 4)
+  {
+    /* "bithacks" */
+    const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
+    const unsigned int S[] = {1, 2, 4, 8, 16};
+    unsigned int r = 0;
+    for (int i = 4; i >= 0; i--)
+      if (v & b[i])
+      {
+        v >>= S[i];
+        r |= S[i];
+      }
+    return r + 1;
+  }
+  if (sizeof (T) <= 8)
+  {
+    /* "bithacks" */
+    const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
+    const unsigned int S[] = {1, 2, 4, 8, 16, 32};
+    unsigned int r = 0;
+    for (int i = 5; i >= 0; i--)
+      if (v & b[i])
+      {
+        v >>= S[i];
+        r |= S[i];
+      }
+    return r + 1;
+  }
+  if (sizeof (T) == 16)
+  {
+    unsigned int shift = 64;
+    return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
+                          hb_bit_storage<uint64_t> ((uint64_t) v);
+  }
+
+  assert (0);
+  return 0; /* Shut up stupid compiler. */
+}
+
+/* Returns the number of zero bits in the least significant side of v */
+template <typename T>
+static inline HB_CONST_FUNC unsigned int
+hb_ctz (T v)
+{
+  if (unlikely (!v)) return 8 * sizeof (T);
+
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+  if (sizeof (T) <= sizeof (unsigned int))
+    return __builtin_ctz (v);
+
+  if (sizeof (T) <= sizeof (unsigned long))
+    return __builtin_ctzl (v);
+
+  if (sizeof (T) <= sizeof (unsigned long long))
+    return __builtin_ctzll (v);
+#endif
+
+#if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
+  if (sizeof (T) <= sizeof (unsigned int))
+  {
+    unsigned long where;
+    _BitScanForward (&where, v);
+    return where;
+  }
+# if defined(_WIN64)
+  if (sizeof (T) <= 8)
+  {
+    unsigned long where;
+    _BitScanForward64 (&where, v);
+    return where;
+  }
+# endif
+#endif
+
+  if (sizeof (T) <= 4)
+  {
+    /* "bithacks" */
+    unsigned int c = 32;
+    v &= - (int32_t) v;
+    if (v) c--;
+    if (v & 0x0000FFFF) c -= 16;
+    if (v & 0x00FF00FF) c -= 8;
+    if (v & 0x0F0F0F0F) c -= 4;
+    if (v & 0x33333333) c -= 2;
+    if (v & 0x55555555) c -= 1;
+    return c;
+  }
+  if (sizeof (T) <= 8)
+  {
+    /* "bithacks" */
+    unsigned int c = 64;
+    v &= - (int64_t) (v);
+    if (v) c--;
+    if (v & 0x00000000FFFFFFFFULL) c -= 32;
+    if (v & 0x0000FFFF0000FFFFULL) c -= 16;
+    if (v & 0x00FF00FF00FF00FFULL) c -= 8;
+    if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
+    if (v & 0x3333333333333333ULL) c -= 2;
+    if (v & 0x5555555555555555ULL) c -= 1;
+    return c;
+  }
+  if (sizeof (T) == 16)
+  {
+    unsigned int shift = 64;
+    return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
+                          hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
+  }
+
+  assert (0);
+  return 0; /* Shut up stupid compiler. */
+}
+
+
+/*
+ * Tiny stuff.
+ */
+
+/* ASCII tag/character handling */
+static inline bool ISALPHA (unsigned char c)
+{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
+static inline bool ISALNUM (unsigned char c)
+{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
+static inline bool ISSPACE (unsigned char c)
+{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
+static inline unsigned char TOUPPER (unsigned char c)
+{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
+static inline unsigned char TOLOWER (unsigned char c)
+{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
+static inline bool ISHEX (unsigned char c)
+{ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); }
+static inline unsigned char TOHEX (uint8_t c)
+{ return (c & 0xF) <= 9 ? (c & 0xF) + '0' : (c & 0xF) + 'a' - 10; }
+static inline uint8_t FROMHEX (unsigned char c)
+{ return (c >= '0' && c <= '9') ? c - '0' : TOLOWER (c) - 'a' + 10; }
+
+static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
+{ return (a + (b - 1)) / b; }
+
+
+#undef  ARRAY_LENGTH
+template <typename Type, unsigned int n>
+static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
+/* A const version, but does not detect erratically being called on pointers. */
+#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
+
+
+static inline int
+hb_memcmp (const void *a, const void *b, unsigned int len)
+{
+  /* It's illegal to pass NULL to memcmp(), even if len is zero.
+   * So, wrap it.
+   * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
+  if (unlikely (!len)) return 0;
+  return memcmp (a, b, len);
+}
+
+static inline void *
+hb_memset (void *s, int c, unsigned int n)
+{
+  /* It's illegal to pass NULL to memset(), even if n is zero. */
+  if (unlikely (!n)) return 0;
+  return memset (s, c, n);
+}
+
+static inline unsigned int
+hb_ceil_to_4 (unsigned int v)
+{
+  return ((v - 1) | 3) + 1;
+}
+
+template <typename T> static inline bool
+hb_in_range (T u, T lo, T hi)
+{
+  static_assert (!hb_is_signed<T>::value, "");
+
+  /* The casts below are important as if T is smaller than int,
+   * the subtract results will become a signed int! */
+  return (T)(u - lo) <= (T)(hi - lo);
+}
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
+{
+  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
+}
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
+{
+  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
+}
+
+
+/*
+ * Overflow checking.
+ */
+
+/* Consider __builtin_mul_overflow use here also */
+static inline bool
+hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
+{
+  return (size > 0) && (count >= ((unsigned int) -1) / size);
+}
+
+
+/*
+ * Sort and search.
+ */
+
+template <typename K, typename V, typename ...Ts>
+static int
+_hb_cmp_method (const void *pkey, const void *pval, Ts... ds)
+{
+  const K& key = * (const K*) pkey;
+  const V& val = * (const V*) pval;
+
+  return val.cmp (key, ds...);
+}
+
+template <typename V, typename K, typename ...Ts>
+static inline bool
+hb_bsearch_impl (unsigned *pos, /* Out */
+                 const K& key,
+                 V* base, size_t nmemb, size_t stride,
+                 int (*compar)(const void *_key, const void *_item, Ts... _ds),
+                 Ts... ds)
+{
+  /* This is our *only* bsearch implementation. */
+
+  int min = 0, max = (int) nmemb - 1;
+  while (min <= max)
+  {
+    int mid = ((unsigned int) min + (unsigned int) max) / 2;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+    V* p = (V*) (((const char *) base) + (mid * stride));
+#pragma GCC diagnostic pop
+    int c = compar ((const void *) hb_addressof (key), (const void *) p, ds...);
+    if (c < 0)
+      max = mid - 1;
+    else if (c > 0)
+      min = mid + 1;
+    else
+    {
+      *pos = mid;
+      return true;
+    }
+  }
+  *pos = min;
+  return false;
+}
+
+template <typename V, typename K>
+static inline V*
+hb_bsearch (const K& key, V* base,
+            size_t nmemb, size_t stride = sizeof (V),
+            int (*compar)(const void *_key, const void *_item) = _hb_cmp_method<K, V>)
+{
+  unsigned pos;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar) ?
+         (V*) (((const char *) base) + (pos * stride)) : nullptr;
+#pragma GCC diagnostic pop
+}
+template <typename V, typename K, typename ...Ts>
+static inline V*
+hb_bsearch (const K& key, V* base,
+            size_t nmemb, size_t stride,
+            int (*compar)(const void *_key, const void *_item, Ts... _ds),
+            Ts... ds)
+{
+  unsigned pos;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar, ds...) ?
+         (V*) (((const char *) base) + (pos * stride)) : nullptr;
+#pragma GCC diagnostic pop
+}
+
+
+/* From https://github.com/noporpoise/sort_r
+   Feb 5, 2019 (c8c65c1e)
+   Modified to support optional argument using templates */
+
+/* Isaac Turner 29 April 2014 Public Domain */
+
+/*
+hb_qsort function to be exported.
+Parameters:
+  base is the array to be sorted
+  nel is the number of elements in the array
+  width is the size in bytes of each element of the array
+  compar is the comparison function
+  arg (optional) is a pointer to be passed to the comparison function
+
+void hb_qsort(void *base, size_t nel, size_t width,
+              int (*compar)(const void *_a, const void *_b, [void *_arg]),
+              [void *arg]);
+*/
+
+#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
+
+/* swap a and b */
+/* a and b must not be equal! */
+static inline void sort_r_swap(char *__restrict a, char *__restrict b,
+                               size_t w)
+{
+  char tmp, *end = a+w;
+  for(; a < end; a++, b++) { SORT_R_SWAP(*a, *b, tmp); }
+}
+
+/* swap a, b iff a>b */
+/* a and b must not be equal! */
+/* __restrict is same as restrict but better support on old machines */
+template <typename ...Ts>
+static inline int sort_r_cmpswap(char *__restrict a,
+                                 char *__restrict b, size_t w,
+                                 int (*compar)(const void *_a,
+                                               const void *_b,
+                                               Ts... _ds),
+                                 Ts... ds)
+{
+  if(compar(a, b, ds...) > 0) {
+    sort_r_swap(a, b, w);
+    return 1;
+  }
+  return 0;
+}
+
+/*
+Swap consecutive blocks of bytes of size na and nb starting at memory addr ptr,
+with the smallest swap so that the blocks are in the opposite order. Blocks may
+be internally re-ordered e.g.
+  12345ab  ->   ab34512
+  123abc   ->   abc123
+  12abcde  ->   deabc12
+*/
+static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb)
+{
+  if(na > 0 && nb > 0) {
+    if(na > nb) { sort_r_swap(ptr, ptr+na, nb); }
+    else { sort_r_swap(ptr, ptr+nb, na); }
+  }
+}
+
+/* Implement recursive quicksort ourselves */
+/* Note: quicksort is not stable, equivalent values may be swapped */
+template <typename ...Ts>
+static inline void sort_r_simple(void *base, size_t nel, size_t w,
+                                 int (*compar)(const void *_a,
+                                               const void *_b,
+                                               Ts... _ds),
+                                 Ts... ds)
+{
+  char *b = (char *)base, *end = b + nel*w;
+
+  /* for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
+  printf("\n"); */
+
+  if(nel < 10) {
+    /* Insertion sort for arbitrarily small inputs */
+    char *pi, *pj;
+    for(pi = b+w; pi < end; pi += w) {
+      for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,ds...); pj -= w) {}
+    }
+  }
+  else
+  {
+    /* nel > 9; Quicksort */
+
+    int cmp;
+    char *pl, *ple, *pr, *pre, *pivot;
+    char *last = b+w*(nel-1), *tmp;
+
+    /*
+    Use median of second, middle and second-last items as pivot.
+    First and last may have been swapped with pivot and therefore be extreme
+    */
+    char *l[3];
+    l[0] = b + w;
+    l[1] = b+w*(nel/2);
+    l[2] = last - w;
+
+    /* printf("pivots: %i, %i, %i\n", *(int*)l[0], *(int*)l[1], *(int*)l[2]); */
+
+    if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
+    if(compar(l[1],l[2],ds...) > 0) {
+      SORT_R_SWAP(l[1], l[2], tmp);
+      if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
+    }
+
+    /* swap mid value (l[1]), and last element to put pivot as last element */
+    if(l[1] != last) { sort_r_swap(l[1], last, w); }
+
+    /*
+    pl is the next item on the left to be compared to the pivot
+    pr is the last item on the right that was compared to the pivot
+    ple is the left position to put the next item that equals the pivot
+    ple is the last right position where we put an item that equals the pivot
+                                           v- end (beyond the array)
+      EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE.
+      ^- b  ^- ple  ^- pl   ^- pr  ^- pre ^- last (where the pivot is)
+    Pivot comparison key:
+      E = equal, L = less than, u = unknown, G = greater than, E = equal
+    */
+    pivot = last;
+    ple = pl = b;
+    pre = pr = last;
+
+    /*
+    Strategy:
+    Loop into the list from the left and right at the same time to find:
+    - an item on the left that is greater than the pivot
+    - an item on the right that is less than the pivot
+    Once found, they are swapped and the loop continues.
+    Meanwhile items that are equal to the pivot are moved to the edges of the
+    array.
+    */
+    while(pl < pr) {
+      /* Move left hand items which are equal to the pivot to the far left.
+         break when we find an item that is greater than the pivot */
+      for(; pl < pr; pl += w) {
+        cmp = compar(pl, pivot, ds...);
+        if(cmp > 0) { break; }
+        else if(cmp == 0) {
+          if(ple < pl) { sort_r_swap(ple, pl, w); }
+          ple += w;
+        }
+      }
+      /* break if last batch of left hand items were equal to pivot */
+      if(pl >= pr) { break; }
+      /* Move right hand items which are equal to the pivot to the far right.
+         break when we find an item that is less than the pivot */
+      for(; pl < pr; ) {
+        pr -= w; /* Move right pointer onto an unprocessed item */
+        cmp = compar(pr, pivot, ds...);
+        if(cmp == 0) {
+          pre -= w;
+          if(pr < pre) { sort_r_swap(pr, pre, w); }
+        }
+        else if(cmp < 0) {
+          if(pl < pr) { sort_r_swap(pl, pr, w); }
+          pl += w;
+          break;
+        }
+      }
+    }
+
+    pl = pr; /* pr may have gone below pl */
+
+    /*
+    Now we need to go from: EEELLLGGGGEEEE
+                        to: LLLEEEEEEEGGGG
+    Pivot comparison key:
+      E = equal, L = less than, u = unknown, G = greater than, E = equal
+    */
+    sort_r_swap_blocks(b, ple-b, pl-ple);
+    sort_r_swap_blocks(pr, pre-pr, end-pre);
+
+    /*for(size_t i=0; i<nel; i++) {printf("%4i", *(int*)(b + i*sizeof(int)));}
+    printf("\n");*/
+
+    sort_r_simple(b, (pl-ple)/w, w, compar, ds...);
+    sort_r_simple(end-(pre-pr), (pre-pr)/w, w, compar, ds...);
+  }
+}
+
+static inline void
+hb_qsort (void *base, size_t nel, size_t width,
+          int (*compar)(const void *_a, const void *_b))
+{
+#if defined(__OPTIMIZE_SIZE__) && !defined(HB_USE_INTERNAL_QSORT)
+  qsort (base, nel, width, compar);
+#else
+  sort_r_simple (base, nel, width, compar);
+#endif
+}
+
+static inline void
+hb_qsort (void *base, size_t nel, size_t width,
+          int (*compar)(const void *_a, const void *_b, void *_arg),
+          void *arg)
+{
+#ifdef HAVE_GNU_QSORT_R
+  qsort_r (base, nel, width, compar, arg);
+#else
+  sort_r_simple (base, nel, width, compar, arg);
+#endif
+}
+
+
+template <typename T, typename T2, typename T3> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2)
+{
+  for (unsigned int i = 1; i < len; i++)
+  {
+    unsigned int j = i;
+    while (j && compar (&array[j - 1], &array[i]) > 0)
+      j--;
+    if (i == j)
+      continue;
+    /* Move item i to occupy place for item j, shift what's in between. */
+    {
+      T t = array[i];
+      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
+      array[j] = t;
+    }
+    if (array2)
+    {
+      T3 t = array2[i];
+      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T3));
+      array2[j] = t;
+    }
+  }
+}
+
+template <typename T> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+{
+  hb_stable_sort (array, len, compar, (int *) nullptr);
+}
+
+static inline hb_bool_t
+hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
+{
+  unsigned int v;
+  const char *p = s;
+  const char *end = p + len;
+  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, base)))
+    return false;
+
+  *out = v;
+  return true;
+}
+
+
+/* Operators. */
+
+struct hb_bitwise_and
+{ HB_PARTIALIZE(2);
+  static constexpr bool passthru_left = false;
+  static constexpr bool passthru_right = false;
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
+}
+HB_FUNCOBJ (hb_bitwise_and);
+struct hb_bitwise_or
+{ HB_PARTIALIZE(2);
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = true;
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
+}
+HB_FUNCOBJ (hb_bitwise_or);
+struct hb_bitwise_xor
+{ HB_PARTIALIZE(2);
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = true;
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
+}
+HB_FUNCOBJ (hb_bitwise_xor);
+struct hb_bitwise_sub
+{ HB_PARTIALIZE(2);
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = false;
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
+}
+HB_FUNCOBJ (hb_bitwise_sub);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (const T &a) const HB_AUTO_RETURN (~a)
+}
+HB_FUNCOBJ (hb_bitwise_neg);
+
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a + b)
+}
+HB_FUNCOBJ (hb_add);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a - b)
+}
+HB_FUNCOBJ (hb_sub);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
+}
+HB_FUNCOBJ (hb_mul);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a / b)
+}
+HB_FUNCOBJ (hb_div);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a % b)
+}
+HB_FUNCOBJ (hb_mod);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (const T &a) const HB_AUTO_RETURN (+a)
+}
+HB_FUNCOBJ (hb_pos);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (const T &a) const HB_AUTO_RETURN (-a)
+}
+HB_FUNCOBJ (hb_neg);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (T &a) const HB_AUTO_RETURN (++a)
+}
+HB_FUNCOBJ (hb_inc);
+struct
+{
+  template <typename T> constexpr auto
+  operator () (T &a) const HB_AUTO_RETURN (--a)
+}
+HB_FUNCOBJ (hb_dec);
+
+
+/* Compiler-assisted vectorization. */
+
+/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
+ * basically a fixed-size bitset. */
+template <typename elt_t, unsigned int byte_size>
+struct hb_vector_size_t
+{
+  elt_t& operator [] (unsigned int i) { return v[i]; }
+  const elt_t& operator [] (unsigned int i) const { return v[i]; }
+
+  void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
+
+  template <typename Op>
+  hb_vector_size_t process (const Op& op) const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      r.v[i] = op (v[i]);
+    return r;
+  }
+  template <typename Op>
+  hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
+  {
+    hb_vector_size_t r;
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      r.v[i] = op (v[i], o.v[i]);
+    return r;
+  }
+  hb_vector_size_t operator | (const hb_vector_size_t &o) const
+  { return process (hb_bitwise_or, o); }
+  hb_vector_size_t operator & (const hb_vector_size_t &o) const
+  { return process (hb_bitwise_and, o); }
+  hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
+  { return process (hb_bitwise_xor, o); }
+  hb_vector_size_t operator ~ () const
+  { return process (hb_bitwise_neg); }
+
+  private:
+  static_assert (0 == byte_size % sizeof (elt_t), "");
+  elt_t v[byte_size / sizeof (elt_t)];
+};
+
+
+#endif /* HB_ALGS_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-array.hh
index 4034d92..c6766e6 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-array.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-array.hh
@@ -28,7 +28,7 @@
 #define HB_ARRAY_HH
 
 #include "hb.hh"
-#include "hb-dsalgs.hh"
+#include "hb-algs.hh"
 #include "hb-iter.hh"
 #include "hb-null.hh"
 
@@ -37,22 +37,31 @@
 struct hb_sorted_array_t;
 
 template <typename Type>
-struct hb_array_t :
-        hb_iter_t<hb_array_t<Type>, Type>,
-        hb_iter_mixin_t<hb_array_t<Type>, Type>
+struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 {
   /*
    * Constructors.
    */
-  hb_array_t () : arrayZ (nullptr), length (0) {}
-  hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
-  template <unsigned int length_> hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {}
+  hb_array_t () : arrayZ (nullptr), length (0), backwards_length (0) {}
+  hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_), backwards_length (0) {}
+  template <unsigned int length_>
+  hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_), backwards_length (0) {}
 
+  template <typename U,
+            hb_enable_if (hb_is_cr_convertible(U, Type))>
+  hb_array_t (const hb_array_t<U> &o) :
+    hb_iter_with_fallback_t<hb_array_t, Type&> (),
+    arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {}
+  template <typename U,
+            hb_enable_if (hb_is_cr_convertible(U, Type))>
+  hb_array_t& operator = (const hb_array_t<U> &o)
+  { arrayZ = o.arrayZ; length = o.length; backwards_length = o.backwards_length; return *this; }
 
   /*
    * Iterator implementation.
    */
-  typedef Type __item_type__;
+  typedef Type& __item_t__;
+  static constexpr bool is_random_access_iterator = true;
   Type& __item_at__ (unsigned i) const
   {
     if (unlikely (i >= length)) return CrapOrNull (Type);
@@ -63,16 +72,25 @@
     if (unlikely (n > length))
       n = length;
     length -= n;
+    backwards_length += n;
     arrayZ += n;
   }
   void __rewind__ (unsigned n)
   {
-    if (unlikely (n > length))
-      n = length;
-    length -= n;
+    if (unlikely (n > backwards_length))
+      n = backwards_length;
+    length += n;
+    backwards_length -= n;
+    arrayZ -= n;
   }
   unsigned __len__ () const { return length; }
-  bool __random_access__ () const { return true; }
+  /* Ouch. The operator== compares the contents of the array.  For range-based for loops,
+   * it's best if we can just compare arrayZ, though comparing contents is still fast,
+   * but also would require that Type has operator==.  As such, we optimize this operator
+   * for range-based for loop and just compare arrayZ.  No need to compare length, as we
+   * assume we're only compared to .end(). */
+  bool operator != (const hb_array_t& o) const
+  { return arrayZ != o.arrayZ; }
 
   /* Extra operators.
    */
@@ -80,70 +98,105 @@
   operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
   template <typename T> operator T * () const { return arrayZ; }
 
+  HB_INTERNAL bool operator == (const hb_array_t &o) const;
+
+  uint32_t hash () const {
+    uint32_t current = 0;
+    for (unsigned int i = 0; i < this->length; i++) {
+      current = current * 31 + hb_hash (this->arrayZ[i]);
+    }
+    return current;
+  }
+
   /*
    * Compare, Sort, and Search.
    */
 
   /* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
-  int cmp (const hb_array_t<Type> &a) const
+  int cmp (const hb_array_t &a) const
   {
     if (length != a.length)
       return (int) a.length - (int) length;
     return hb_memcmp (a.arrayZ, arrayZ, get_size ());
   }
-  static int cmp (const void *pa, const void *pb)
+  HB_INTERNAL static int cmp (const void *pa, const void *pb)
   {
-    hb_array_t<Type> *a = (hb_array_t<Type> *) pa;
-    hb_array_t<Type> *b = (hb_array_t<Type> *) pb;
+    hb_array_t *a = (hb_array_t *) pa;
+    hb_array_t *b = (hb_array_t *) pb;
     return b->cmp (*a);
   }
 
   template <typename T>
   Type *lsearch (const T &x, Type *not_found = nullptr)
   {
-    unsigned int count = length;
-    for (unsigned int i = 0; i < count; i++)
-      if (!this->arrayZ[i].cmp (x))
-        return &this->arrayZ[i];
-    return not_found;
+    unsigned i;
+    return lfind (x, &i) ? &this->arrayZ[i] : not_found;
   }
   template <typename T>
   const Type *lsearch (const T &x, const Type *not_found = nullptr) const
   {
-    unsigned int count = length;
-    for (unsigned int i = 0; i < count; i++)
+    unsigned i;
+    return lfind (x, &i) ? &this->arrayZ[i] : not_found;
+  }
+  template <typename T>
+  bool lfind (const T &x, unsigned *pos = nullptr) const
+  {
+    for (unsigned i = 0; i < length; ++i)
       if (!this->arrayZ[i].cmp (x))
-        return &this->arrayZ[i];
-    return not_found;
+      {
+        if (pos)
+          *pos = i;
+        return true;
+      }
+
+    return false;
   }
 
   hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
   {
     if (likely (length))
-      ::qsort (arrayZ, length, this->item_size, cmp_);
+      hb_qsort (arrayZ, length, this->get_item_size (), cmp_);
     return hb_sorted_array_t<Type> (*this);
   }
   hb_sorted_array_t<Type> qsort ()
   {
     if (likely (length))
-      ::qsort (arrayZ, length, this->item_size, Type::cmp);
+      hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
     return hb_sorted_array_t<Type> (*this);
   }
   void qsort (unsigned int start, unsigned int end)
   {
-    end = MIN (end, length);
+    end = hb_min (end, length);
     assert (start <= end);
     if (likely (start < end))
-      ::qsort (arrayZ + start, end - start, this->item_size, Type::cmp);
+      hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
   }
 
   /*
    * Other methods.
    */
 
-  unsigned int get_size () const { return length * this->item_size; }
+  unsigned int get_size () const { return length * this->get_item_size (); }
 
-  hb_array_t<Type> sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
+  /*
+   * Reverse the order of items in this array in the range [start, end).
+   */
+  void reverse (unsigned start = 0, unsigned end = -1)
+  {
+    start = hb_min (start, length);
+    end = hb_min (end, length);
+
+    if (end < start + 2)
+      return;
+
+    for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) {
+      Type temp = arrayZ[rhs];
+      arrayZ[rhs] = arrayZ[lhs];
+      arrayZ[lhs] = temp;
+    }
+  }
+
+  hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
   {
     if (!start_offset && !seg_count)
       return *this;
@@ -154,16 +207,45 @@
     else
       count -= start_offset;
     if (seg_count)
-      count = *seg_count = MIN (count, *seg_count);
-    return hb_array_t<Type> (arrayZ + start_offset, count);
+      count = *seg_count = hb_min (count, *seg_count);
+    return hb_array_t (arrayZ + start_offset, count);
   }
-  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
+  hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
   { return sub_array (start_offset, &seg_count); }
 
+  hb_array_t truncate (unsigned length) const { return sub_array (0, length); }
+
+  template <typename T,
+            unsigned P = sizeof (Type),
+            hb_enable_if (P == 1)>
+  const T *as () const
+  { return length < hb_null_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
+
+  template <typename T,
+            unsigned P = sizeof (Type),
+            hb_enable_if (P == 1)>
+  bool check_range (const T *p, unsigned int size = T::static_size) const
+  {
+    return arrayZ <= ((const char *) p)
+        && ((const char *) p) <= arrayZ + length
+        && (unsigned int) (arrayZ + length - (const char *) p) >= size;
+  }
+
   /* Only call if you allocated the underlying array using malloc() or similar. */
   void free ()
   { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
 
+  template <typename hb_serialize_context_t>
+  hb_array_t copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    auto* out = c->start_embed (arrayZ);
+    if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
+    for (unsigned i = 0; i < length; i++)
+      out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
+    return_trace (hb_array_t (out, length));
+  }
+
   template <typename hb_sanitize_context_t>
   bool sanitize (hb_sanitize_context_t *c) const
   { return c->check_array (arrayZ, length); }
@@ -175,6 +257,7 @@
   public:
   Type *arrayZ;
   unsigned int length;
+  unsigned int backwards_length;
 };
 template <typename T> inline hb_array_t<T>
 hb_array (T *array, unsigned int length)
@@ -183,7 +266,6 @@
 hb_array (T (&array_)[length_])
 { return hb_array_t<T> (array_); }
 
-
 enum hb_bfind_not_found_t
 {
   HB_BFIND_NOT_FOUND_DONT_STORE,
@@ -193,20 +275,40 @@
 
 template <typename Type>
 struct hb_sorted_array_t :
-        hb_sorted_iter_t<hb_sorted_array_t<Type>, Type>,
-        hb_array_t<Type>,
-        hb_iter_mixin_t<hb_sorted_array_t<Type>, Type>
+        hb_iter_t<hb_sorted_array_t<Type>, Type&>,
+        hb_array_t<Type>
 {
-  hb_sorted_array_t () : hb_array_t<Type> () {}
-  hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
-  hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
-  template <unsigned int length_> hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
+  typedef hb_iter_t<hb_sorted_array_t, Type&> iter_base_t;
+  HB_ITER_USING (iter_base_t);
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
 
-  hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
-  { return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
-  hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
+  hb_sorted_array_t () : hb_array_t<Type> () {}
+  hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
+  template <unsigned int length_>
+  hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
+
+  template <typename U,
+            hb_enable_if (hb_is_cr_convertible(U, Type))>
+  hb_sorted_array_t (const hb_array_t<U> &o) :
+    hb_iter_t<hb_sorted_array_t, Type&> (),
+    hb_array_t<Type> (o) {}
+  template <typename U,
+            hb_enable_if (hb_is_cr_convertible(U, Type))>
+  hb_sorted_array_t& operator = (const hb_array_t<U> &o)
+  { hb_array_t<Type> (*this) = o; return *this; }
+
+  /* Iterator implementation. */
+  bool operator != (const hb_sorted_array_t& o) const
+  { return this->arrayZ != o.arrayZ || this->length != o.length; }
+
+  hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
+  { return hb_sorted_array_t (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
+  hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
   { return sub_array (start_offset, &seg_count); }
 
+  hb_sorted_array_t truncate (unsigned length) const { return sub_array (0, length); }
+
   template <typename T>
   Type *bsearch (const T &x, Type *not_found = nullptr)
   {
@@ -221,26 +323,18 @@
   }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-                     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
-                     unsigned int to_store = (unsigned int) -1) const
+              hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+              unsigned int to_store = (unsigned int) -1) const
   {
-    int min = 0, max = (int) this->length - 1;
-    const Type *array = this->arrayZ;
-    while (min <= max)
+    unsigned pos;
+
+    if (bsearch_impl (x, &pos))
     {
-      int mid = ((unsigned int) min + (unsigned int) max) / 2;
-      int c = array[mid].cmp (x);
-      if (c < 0)
-        max = mid - 1;
-      else if (c > 0)
-        min = mid + 1;
-      else
-      {
-        if (i)
-          *i = mid;
-        return true;
-      }
+      if (i)
+        *i = pos;
+      return true;
     }
+
     if (i)
     {
       switch (not_found)
@@ -253,14 +347,22 @@
           break;
 
         case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
-          if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
-            max++;
-          *i = max;
+          *i = pos;
           break;
       }
     }
     return false;
   }
+  template <typename T>
+  bool bsearch_impl (const T &x, unsigned *pos) const
+  {
+    return hb_bsearch_impl (pos,
+                            x,
+                            this->arrayZ,
+                            this->length,
+                            sizeof (Type),
+                            _hb_cmp_method<T, Type>);
+  }
 };
 template <typename T> inline hb_sorted_array_t<T>
 hb_sorted_array (T *array, unsigned int length)
@@ -269,9 +371,38 @@
 hb_sorted_array (T (&array_)[length_])
 { return hb_sorted_array_t<T> (array_); }
 
+template <typename T>
+bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
+{
+  if (o.length != this->length) return false;
+  for (unsigned int i = 0; i < this->length; i++) {
+    if (this->arrayZ[i] != o.arrayZ[i]) return false;
+  }
+  return true;
+}
+
+/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */
+
+template <>
+inline uint32_t hb_array_t<const char>::hash () const {
+  uint32_t current = 0;
+  for (unsigned int i = 0; i < this->length; i++)
+    current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
+  return current;
+}
+
+template <>
+inline uint32_t hb_array_t<const unsigned char>::hash () const {
+  uint32_t current = 0;
+  for (unsigned int i = 0; i < this->length; i++)
+    current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
+  return current;
+}
+
 
 typedef hb_array_t<const char> hb_bytes_t;
 typedef hb_array_t<const unsigned char> hb_ubytes_t;
 
 
+
 #endif /* HB_ARRAY_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
index d1ff7a7..a6877f8 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
@@ -33,6 +33,7 @@
 #define HB_ATOMIC_HH
 
 #include "hb.hh"
+#include "hb-meta.hh"
 
 
 /*
@@ -85,11 +86,11 @@
 #define hb_atomic_int_impl_add(AI, V)           (reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
 #define hb_atomic_int_impl_set_relaxed(AI, V)   (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed))
 #define hb_atomic_int_impl_set(AI, V)           (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release))
-#define hb_atomic_int_impl_get_relaxed(AI)      (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed))
-#define hb_atomic_int_impl_get(AI)              (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_acquire))
+#define hb_atomic_int_impl_get_relaxed(AI)      (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_relaxed))
+#define hb_atomic_int_impl_get(AI)              (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_acquire))
 
 #define hb_atomic_ptr_impl_set_relaxed(P, V)    (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
-#define hb_atomic_ptr_impl_get_relaxed(P)       (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_relaxed))
+#define hb_atomic_ptr_impl_get_relaxed(P)       (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
 #define hb_atomic_ptr_impl_get(P)               (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
 static inline bool
 _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
@@ -106,7 +107,7 @@
 
 static inline void _hb_memory_barrier ()
 {
-#if !defined(MemoryBarrier)
+#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
   /* MinGW has a convoluted history of supporting MemoryBarrier. */
   LONG dummy = 0;
   InterlockedExchange (&dummy, 1);
@@ -211,25 +212,19 @@
 static_assert ((sizeof (long) == sizeof (void *)), "");
 
 
-#elif !defined(HB_NO_MT)
-
-#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
-
-#define _hb_memory_barrier()
+#elif defined(HB_NO_MT)
 
 #define hb_atomic_int_impl_add(AI, V)           ((*(AI) += (V)) - (V))
 
+#define _hb_memory_barrier()                    do {} while (0)
+
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)       (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
 
 
-#else /* HB_NO_MT */
+#else
 
-#define hb_atomic_int_impl_add(AI, V)           ((*(AI) += (V)) - (V))
-
-#define _hb_memory_barrier()
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)       (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
-
+#error "Could not find any system to define atomic_int macros."
+#error "Check hb-atomic.hh for possible resolutions."
 
 #endif
 
@@ -282,7 +277,7 @@
 template <typename P>
 struct hb_atomic_ptr_t
 {
-  typedef typename hb_remove_pointer (P) T;
+  typedef hb_remove_pointer<P> T;
 
   void init (T* v_ = nullptr) { set_relaxed (v_); }
   void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
new file mode 100644
index 0000000..ff47c6f
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
@@ -0,0 +1,166 @@
+/*
+ * Copyright © 2019 Adobe Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#ifndef HB_BIMAP_HH
+#define HB_BIMAP_HH
+
+#include "hb.hh"
+#include "hb-map.hh"
+
+/* Bi-directional map */
+struct hb_bimap_t
+{
+  hb_bimap_t () { init (); }
+  ~hb_bimap_t () { fini (); }
+
+  void init ()
+  {
+    forw_map.init ();
+    back_map.init ();
+  }
+
+  void fini ()
+  {
+    forw_map.fini ();
+    back_map.fini ();
+  }
+
+  void reset ()
+  {
+    forw_map.reset ();
+    back_map.reset ();
+  }
+
+  bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
+
+  void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
+  {
+    if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
+    if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
+    forw_map.set (lhs, rhs);
+    back_map.set (rhs, lhs);
+  }
+
+  hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
+  hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); }
+
+  hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
+  bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); }
+
+  void del (hb_codepoint_t lhs)
+  {
+    back_map.del (get (lhs));
+    forw_map.del (lhs);
+  }
+
+  void clear ()
+  {
+    forw_map.clear ();
+    back_map.clear ();
+  }
+
+  bool is_empty () const { return get_population () == 0; }
+
+  unsigned int get_population () const { return forw_map.get_population (); }
+
+  protected:
+  hb_map_t  forw_map;
+  hb_map_t  back_map;
+};
+
+/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
+struct hb_inc_bimap_t : hb_bimap_t
+{
+  hb_inc_bimap_t () { init (); }
+
+  void init ()
+  {
+    hb_bimap_t::init ();
+    next_value = 0;
+  }
+
+  /* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
+   * Return the rhs value as the result.
+   */
+  hb_codepoint_t add (hb_codepoint_t lhs)
+  {
+    hb_codepoint_t  rhs = forw_map[lhs];
+    if (rhs == HB_MAP_VALUE_INVALID)
+    {
+      rhs = next_value++;
+      set (lhs, rhs);
+    }
+    return rhs;
+  }
+
+  hb_codepoint_t skip ()
+  { return next_value++; }
+
+  hb_codepoint_t get_next_value () const
+  { return next_value; }
+
+  void add_set (const hb_set_t *set)
+  {
+    hb_codepoint_t i = HB_SET_VALUE_INVALID;
+    while (hb_set_next (set, &i)) add (i);
+  }
+
+  /* Create an identity map. */
+  bool identity (unsigned int size)
+  {
+    clear ();
+    for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
+    return !in_error ();
+  }
+
+  protected:
+  static int cmp_id (const void* a, const void* b)
+  { return (int)*(const hb_codepoint_t *)a - (int)*(const hb_codepoint_t *)b; }
+
+  public:
+  /* Optional: after finished adding all mappings in a random order,
+   * reassign rhs to lhs so that they are in the same order. */
+  void sort ()
+  {
+    hb_codepoint_t  count = get_population ();
+    hb_vector_t <hb_codepoint_t> work;
+    work.resize (count);
+
+    for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
+      work[rhs] = back_map[rhs];
+
+    work.qsort (cmp_id);
+
+    clear ();
+    for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
+      set (work[rhs], rhs);
+  }
+
+  protected:
+  unsigned int  next_value;
+};
+
+#endif /* HB_BIMAP_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc
index ffeecc2..fc18b61 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc
@@ -25,18 +25,6 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-
-/* https://github.com/harfbuzz/harfbuzz/issues/1308
- * http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
- * https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html
- */
-#ifndef _POSIX_C_SOURCE
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-macros"
-#define _POSIX_C_SOURCE 200809L
-#pragma GCC diagnostic pop
-#endif
-
 #include "hb.hh"
 #include "hb-blob.hh"
 
@@ -48,7 +36,6 @@
 #endif /* HAVE_SYS_MMAN_H */
 
 #include <stdio.h>
-#include <errno.h>
 #include <stdlib.h>
 
 
@@ -155,7 +142,7 @@
   hb_blob_make_immutable (parent);
 
   blob = hb_blob_create (parent->data + offset,
-                         MIN (length, parent->length - offset),
+                         hb_min (length, parent->length - offset),
                          HB_MEMORY_MODE_READONLY,
                          hb_blob_reference (parent),
                          _hb_blob_destroy);
@@ -202,7 +189,7 @@
 hb_blob_t *
 hb_blob_get_empty ()
 {
-  return const_cast<hb_blob_t *> (&Null(hb_blob_t));
+  return const_cast<hb_blob_t *> (&Null (hb_blob_t));
 }
 
 /**
@@ -487,7 +474,11 @@
  * Mmap
  */
 
+#ifndef HB_NO_OPEN
 #ifdef HAVE_MMAP
+# if !defined(HB_NO_RESOURCE_FORK) && defined(__APPLE__)
+#  include <sys/paths.h>
+# endif
 # include <sys/types.h>
 # include <sys/stat.h>
 # include <fcntl.h>
@@ -532,6 +523,39 @@
 }
 #endif
 
+#ifdef _PATH_RSRCFORKSPEC
+static int
+_open_resource_fork (const char *file_name, hb_mapped_file_t *file)
+{
+  size_t name_len = strlen (file_name);
+  size_t len = name_len + sizeof (_PATH_RSRCFORKSPEC);
+
+  char *rsrc_name = (char *) malloc (len);
+  if (unlikely (!rsrc_name)) return -1;
+
+  strncpy (rsrc_name, file_name, name_len);
+  strncpy (rsrc_name + name_len, _PATH_RSRCFORKSPEC,
+           sizeof (_PATH_RSRCFORKSPEC) - 1);
+
+  int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
+  free (rsrc_name);
+
+  if (fd != -1)
+  {
+    struct stat st;
+    if (fstat (fd, &st) != -1)
+      file->length = (unsigned long) st.st_size;
+    else
+    {
+      close (fd);
+      fd = -1;
+    }
+  }
+
+  return fd;
+}
+#endif
+
 /**
  * hb_blob_create_from_file:
  * @file_name: font filename.
@@ -556,6 +580,19 @@
   if (unlikely (fstat (fd, &st) == -1)) goto fail;
 
   file->length = (unsigned long) st.st_size;
+
+#ifdef _PATH_RSRCFORKSPEC
+  if (unlikely (file->length == 0))
+  {
+    int rfd = _open_resource_fork (file_name, file);
+    if (rfd != -1)
+    {
+      close (fd);
+      fd = rfd;
+    }
+  }
+#endif
+
   file->contents = (char *) mmap (nullptr, file->length, PROT_READ,
                                   MAP_PRIVATE | MAP_NORESERVE, fd, 0);
 
@@ -579,9 +616,9 @@
   HANDLE fd;
   unsigned int size = strlen (file_name) + 1;
   wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
-  if (unlikely (wchar_file_name == nullptr)) goto fail_without_close;
+  if (unlikely (!wchar_file_name)) goto fail_without_close;
   mbstowcs (wchar_file_name, file_name, size);
-#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
   {
     CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
     ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
@@ -602,7 +639,7 @@
 
   if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
 
-#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
   {
     LARGE_INTEGER length;
     GetFileSizeEx (fd, &length);
@@ -613,14 +650,14 @@
   file->length = (unsigned long) GetFileSize (fd, nullptr);
   file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
 #endif
-  if (unlikely (file->mapping == nullptr)) goto fail;
+  if (unlikely (!file->mapping)) goto fail;
 
-#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
   file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
 #else
   file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
 #endif
-  if (unlikely (file->contents == nullptr)) goto fail;
+  if (unlikely (!file->contents)) goto fail;
 
   CloseHandle (fd);
   return hb_blob_create (file->contents, file->length,
@@ -638,10 +675,10 @@
      It's used as a fallback for systems without mmap or to read from pipes */
   unsigned long len = 0, allocated = BUFSIZ * 16;
   char *data = (char *) malloc (allocated);
-  if (unlikely (data == nullptr)) return hb_blob_get_empty ();
+  if (unlikely (!data)) return hb_blob_get_empty ();
 
   FILE *fp = fopen (file_name, "rb");
-  if (unlikely (fp == nullptr)) goto fread_fail_without_close;
+  if (unlikely (!fp)) goto fread_fail_without_close;
 
   while (!feof (fp))
   {
@@ -652,7 +689,7 @@
          can cover files like that but lets limit our fallback reader */
       if (unlikely (allocated > (2 << 28))) goto fread_fail;
       char *new_data = (char *) realloc (data, allocated);
-      if (unlikely (new_data == nullptr)) goto fread_fail;
+      if (unlikely (!new_data)) goto fread_fail;
       data = new_data;
     }
 
@@ -666,6 +703,7 @@
 
     len += addition;
   }
+        fclose (fp);
 
   return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
                          (hb_destroy_func_t) free);
@@ -676,3 +714,4 @@
   free (data);
   return hb_blob_get_empty ();
 }
+#endif /* !HB_NO_OPEN */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.h b/src/java.desktop/share/native/libharfbuzz/hb-blob.h
index a714fb2..ddbcd1a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-blob.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.h
@@ -71,6 +71,9 @@
                 void              *user_data,
                 hb_destroy_func_t  destroy);
 
+HB_EXTERN hb_blob_t *
+hb_blob_create_from_file (const char *file_name);
+
 /* Always creates with MEMORY_MODE_READONLY.
  * Even if the parent blob is writable, we don't
  * want the user of the sub-blob to be able to
@@ -123,9 +126,6 @@
 HB_EXTERN char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
 
-HB_EXTERN hb_blob_t *
-hb_blob_create_from_file (const char *file_name);
-
 HB_END_DECLS
 
 #endif /* HB_BLOB_H */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.hh b/src/java.desktop/share/native/libharfbuzz/hb-blob.hh
index 4ea13f8..d85bd82 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-blob.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.hh
@@ -54,13 +54,9 @@
   HB_INTERNAL bool try_make_writable_inplace ();
   HB_INTERNAL bool try_make_writable_inplace_unix ();
 
+  hb_bytes_t as_bytes () const { return hb_bytes_t (data, length); }
   template <typename Type>
-  const Type* as () const
-  {
-    return length < hb_null_size (Type) ? &Null(Type) : reinterpret_cast<const Type *> (data);
-  }
-  hb_bytes_t as_bytes () const
-  { return hb_bytes_t (data, length); }
+  const Type* as () const { return as_bytes ().as<Type> (); }
 
   public:
   hb_object_header_t header;
@@ -81,7 +77,7 @@
 template <typename P>
 struct hb_blob_ptr_t
 {
-  typedef typename hb_remove_pointer (P) T;
+  typedef hb_remove_pointer<P> T;
 
   hb_blob_ptr_t (hb_blob_t *b_ = nullptr) : b (b_) {}
   hb_blob_t * operator = (hb_blob_t *b_) { return b = b_; }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc
index 14a9a56..52dbb84 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_BUFFER_SERIALIZE
+
 #include "hb-buffer.hh"
 
 
@@ -85,7 +89,7 @@
 const char *
 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
 {
-  switch (format)
+  switch ((unsigned) format)
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:       return serialize_formats[0];
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:       return serialize_formats[1];
@@ -138,34 +142,34 @@
       *p++ = '"';
     }
     else
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
     }
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
                              x+pos[i].x_offset, y+pos[i].y_offset));
       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
-        p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
                                pos[i].x_advance, pos[i].y_advance));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
     {
       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
-        p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
     {
       hb_glyph_extents_t extents;
       hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
                 extents.x_bearing, extents.y_bearing));
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
                 extents.width, extents.height));
     }
 
@@ -224,37 +228,37 @@
       p += strlen (p);
     }
     else
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
     }
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
       if (x+pos[i].x_offset || y+pos[i].y_offset)
-        p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
 
       if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
       {
         *p++ = '+';
-        p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
         if (pos[i].y_advance)
-          p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
+          p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
       }
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
     {
       if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
-        p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
+        p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
     }
 
     if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
     {
       hb_glyph_extents_t extents;
       hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
-      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
+      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
     }
 
     unsigned int l = p - b;
@@ -344,8 +348,8 @@
   if (buf_size)
     *buf = '\0';
 
-  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
-          buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+  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;
@@ -375,43 +379,24 @@
   }
 }
 
-
-static hb_bool_t
-parse_uint (const char *pp, const char *end, uint32_t *pv)
+static bool
+parse_int (const char *pp, const char *end, int32_t *pv)
 {
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
-  strncpy (buf, pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  uint32_t v;
-
-  errno = 0;
-  v = strtol (p, &pend, 10);
-  if (errno || p == pend || pend - p != end - pp)
+  int v;
+  const char *p = pp;
+  if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */)))
     return false;
 
   *pv = v;
   return true;
 }
 
-static hb_bool_t
-parse_int (const char *pp, const char *end, int32_t *pv)
+static bool
+parse_uint (const char *pp, const char *end, uint32_t *pv)
 {
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
-  strncpy (buf, pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  int32_t v;
-
-  errno = 0;
-  v = strtol (p, &pend, 10);
-  if (errno || p == pend || pend - p != end - pp)
+  unsigned int v;
+  const char *p = pp;
+  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */)))
     return false;
 
   *pv = v;
@@ -449,8 +434,8 @@
     end_ptr = &end;
   *end_ptr = buf;
 
-  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
-          buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+  assert ((!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)) ||
+          (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS));
 
   if (buf_len == -1)
     buf_len = strlen (buf);
@@ -484,3 +469,6 @@
 
   }
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
index f9a46d1..2da3c48 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc
@@ -324,7 +324,7 @@
   out_len = 0;
   out_info = info;
 
-  memset (pos, 0, sizeof (pos[0]) * len);
+  hb_memset (pos, 0, sizeof (pos[0]) * len);
 }
 
 void
@@ -438,13 +438,6 @@
   if (!mask)
     return;
 
-  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-      info[i].mask = (info[i].mask & not_mask) | value;
-    return;
-  }
-
   unsigned int count = len;
   for (unsigned int i = 0; i < count; i++)
     if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
@@ -455,27 +448,13 @@
 hb_buffer_t::reverse_range (unsigned int start,
                             unsigned int end)
 {
-  unsigned int i, j;
-
   if (end - start < 2)
     return;
 
-  for (i = start, j = end - 1; i < j; i++, j--) {
-    hb_glyph_info_t t;
-
-    t = info[i];
-    info[i] = info[j];
-    info[j] = t;
-  }
+  hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
 
   if (have_positions) {
-    for (i = start, j = end - 1; i < j; i++, j--) {
-      hb_glyph_position_t t;
-
-      t = pos[i];
-      pos[i] = pos[j];
-      pos[j] = t;
-    }
+    hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
   }
 }
 
@@ -524,7 +503,7 @@
   unsigned int cluster = info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN<unsigned int> (cluster, info[i].cluster);
+    cluster = hb_min (cluster, info[i].cluster);
 
   /* Extend end */
   while (end < len && info[end - 1].cluster == info[end].cluster)
@@ -555,7 +534,7 @@
   unsigned int cluster = out_info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN<unsigned int> (cluster, out_info[i].cluster);
+    cluster = hb_min (cluster, out_info[i].cluster);
 
   /* Extend start */
   while (start && out_info[start - 1].cluster == out_info[start].cluster)
@@ -612,7 +591,7 @@
 void
 hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
 {
-  unsigned int cluster = (unsigned int) -1;
+  unsigned int cluster = UINT_MAX;
   cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
   _unsafe_to_break_set_mask (info, start, end, cluster);
 }
@@ -628,7 +607,7 @@
   assert (start <= out_len);
   assert (idx <= end);
 
-  unsigned int cluster = (unsigned int) -1;
+  unsigned int cluster = UINT_MAX;
   cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
   cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
   _unsafe_to_break_set_mask (out_info, start, out_len, cluster);
@@ -638,8 +617,8 @@
 void
 hb_buffer_t::guess_segment_properties ()
 {
-  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
-          (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+  assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
+          (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
 
   /* If script is set to INVALID, guess from buffer contents */
   if (props.script == HB_SCRIPT_INVALID) {
@@ -736,7 +715,7 @@
 hb_buffer_t *
 hb_buffer_get_empty ()
 {
-  return const_cast<hb_buffer_t *> (&Null(hb_buffer_t));
+  return const_cast<hb_buffer_t *> (&Null (hb_buffer_t));
 }
 
 /**
@@ -776,8 +755,10 @@
 
   free (buffer->info);
   free (buffer->pos);
+#ifndef HB_NO_BUFFER_MESSAGE
   if (buffer->message_destroy)
     buffer->message_destroy (buffer->message_data);
+#endif
 
   free (buffer);
 }
@@ -956,7 +937,7 @@
  *
  * 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.
+ * corresponding script from an ISO 15924 script tag.
  *
  * Since: 0.9.2
  **/
@@ -999,7 +980,7 @@
  * 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 BCP 47 language tags to
+ * Use hb_language_from_string() to convert from BCP 47 language tags to
  * #hb_language_t.
  *
  * Since: 0.9.2
@@ -1115,8 +1096,8 @@
  * Since: 0.9.42
  **/
 void
-hb_buffer_set_cluster_level (hb_buffer_t       *buffer,
-                     hb_buffer_cluster_level_t  cluster_level)
+hb_buffer_set_cluster_level (hb_buffer_t               *buffer,
+                             hb_buffer_cluster_level_t  cluster_level)
 {
   if (unlikely (hb_object_is_immutable (buffer)))
     return;
@@ -1532,8 +1513,8 @@
   typedef typename utf_t::codepoint_t T;
   const hb_codepoint_t replacement = buffer->replacement;
 
-  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
-          (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+  assert ((buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
+          (!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
 
   if (unlikely (hb_object_is_immutable (buffer)))
     return;
@@ -1736,7 +1717,7 @@
  * @buffer: an #hb_buffer_t.
  * @source: source #hb_buffer_t.
  * @start: start index into source buffer to copy.  Use 0 to copy from start of buffer.
- * @end: end index into source buffer to copy.  Use (unsigned int) -1 to copy to end of buffer.
+ * @end: end index into source buffer to copy.  Use @HB_FEATURE_GLOBAL_END to copy to end of buffer.
  *
  * Append (part of) contents of another buffer to this buffer.
  *
@@ -1853,23 +1834,13 @@
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
 {
   assert (buffer->have_positions);
-  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS ||
-          (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+  assert ((buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS) ||
+          (!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
 
   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
-  unsigned int count = buffer->len;
-  if (unlikely (!count)) return;
-  hb_glyph_info_t *info = buffer->info;
-
-  unsigned int start = 0;
-  unsigned int end;
-  for (end = start + 1; end < count; end++)
-    if (info[start].cluster != info[end].cluster) {
-      normalize_glyphs_cluster (buffer, start, end, backward);
-      start = end;
-    }
-  normalize_glyphs_cluster (buffer, start, end, backward);
+  foreach_cluster (buffer, start, end)
+    normalize_glyphs_cluster (buffer, start, end, backward);
 }
 
 void
@@ -1993,6 +1964,7 @@
  * Debugging.
  */
 
+#ifndef HB_NO_BUFFER_MESSAGE
 /**
  * hb_buffer_set_message_func:
  * @buffer: an #hb_buffer_t.
@@ -2022,11 +1994,11 @@
     buffer->message_destroy = nullptr;
   }
 }
-
 bool
 hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
 {
   char buf[100];
-  vsnprintf (buf, sizeof (buf),  fmt, ap);
+  vsnprintf (buf, sizeof (buf), fmt, ap);
   return (bool) this->message_func (this, font, buf, this->message_data);
 }
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h
index f5a724c..1a7ca40 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h
@@ -284,6 +284,10 @@
  *                      space glyph and zeroing the advance width.)
  *                      @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes
  *                      precedence over this flag. Since: 1.8.0
+ * @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
+ *                      flag indicating that a dotted circle should
+ *                      not be inserted in the rendering of incorrect
+ *                      character sequences (such at <0905 093E>). Since: 2.4
  *
  * Since: 0.9.20
  */
@@ -292,7 +296,8 @@
   HB_BUFFER_FLAG_BOT                            = 0x00000001u, /* Beginning-of-text */
   HB_BUFFER_FLAG_EOT                            = 0x00000002u, /* End-of-text */
   HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES    = 0x00000004u,
-  HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES      = 0x00000008u
+  HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES      = 0x00000008u,
+  HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE    = 0x00000010u
 } hb_buffer_flags_t;
 
 HB_EXTERN void
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh
index 6416a53..c4ef466 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh
@@ -124,9 +124,11 @@
   unsigned int context_len[2];
 
   /* Debugging API */
+#ifndef HB_NO_BUFFER_MESSAGE
   hb_buffer_message_func_t message_func;
   void *message_data;
   hb_destroy_func_t message_destroy;
+#endif
 
   /* Internal debugging. */
   /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
@@ -226,10 +228,10 @@
   /* Makes a copy of the glyph at idx to output and replace glyph_index */
   hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
   {
-    if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t);
+    if (unlikely (!make_room_for (0, 1))) return Crap (hb_glyph_info_t);
 
     if (unlikely (idx == len && !out_len))
-      return Crap(hb_glyph_info_t);
+      return Crap (hb_glyph_info_t);
 
     out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
     out_info[out_len].codepoint = glyph_index;
@@ -316,7 +318,7 @@
   HB_INTERNAL void delete_glyph ();
 
   void unsafe_to_break (unsigned int start,
-                               unsigned int end)
+                        unsigned int end)
   {
     if (end - start < 2)
       return;
@@ -347,9 +349,19 @@
 
   HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
 
-  bool messaging () { return unlikely (message_func); }
+  bool messaging ()
+  {
+#ifdef HB_NO_BUFFER_MESSAGE
+    return false;
+#else
+    return unlikely (message_func);
+#endif
+  }
   bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
   {
+#ifdef HB_NO_BUFFER_MESSAGE
+   return true;
+#else
     if (!messaging ())
       return true;
     va_list ap;
@@ -357,6 +369,7 @@
     bool ret = message_impl (font, fmt, ap);
     va_end (ap);
     return ret;
+#endif
   }
   HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
 
@@ -373,13 +386,13 @@
     inf.cluster = cluster;
   }
 
-  int
+  unsigned int
   _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
                                      unsigned int start, unsigned int end,
                                      unsigned int cluster) const
   {
     for (unsigned int i = start; i < end; i++)
-      cluster = MIN<unsigned int> (cluster, infos[i].cluster);
+      cluster = hb_min (cluster, infos[i].cluster);
     return cluster;
   }
   void
@@ -395,8 +408,7 @@
       }
   }
 
-  void unsafe_to_break_all ()
-  { unsafe_to_break_impl (0, len); }
+  void unsafe_to_break_all () { unsafe_to_break_impl (0, len); }
   void safe_to_break_all ()
   {
     for (unsigned int i = 0; i < len; i++)
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh
index a013e96..3fcd557 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh
@@ -220,32 +220,22 @@
   void init () { set_real (0.0); }
   void fini () {}
 
-  void set_int (int v)       { value = (double) v; }
-  int to_int () const        { return (int) value; }
+  void set_int (int v)       { value = v; }
+  int to_int () const        { return value; }
 
   void set_fixed (int32_t v) { value = v / 65536.0; }
-  int32_t to_fixed () const  { return (int32_t) (value * 65536.0); }
+  int32_t to_fixed () const  { return value * 65536.0; }
 
-  void set_real (double v)       { value = v; }
+  void set_real (double v)   { value = v; }
   double to_real () const    { return value; }
 
-  int ceil () const          { return (int) ::ceil (value); }
-  int floor () const         { return (int) ::floor (value); }
-
   bool in_int_range () const
   { return ((double) (int16_t) to_int () == value); }
 
-  bool operator > (const number_t &n) const
-  { return value > n.to_real (); }
-
-  bool operator < (const number_t &n) const
-  { return n > *this; }
-
-  bool operator >= (const number_t &n) const
-  { return !(*this < n); }
-
-  bool operator <= (const number_t &n) const
-  { return !(*this > n); }
+  bool operator >  (const number_t &n) const { return value > n.to_real (); }
+  bool operator <  (const number_t &n) const { return n > *this; }
+  bool operator >= (const number_t &n) const { return !(*this < n); }
+  bool operator <= (const number_t &n) const { return !(*this > n); }
 
   const number_t &operator += (const number_t &n)
   {
@@ -255,37 +245,34 @@
   }
 
   protected:
-  double  value;
+  double value;
 };
 
 /* byte string */
 struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
 {
   // encode 2-byte int (Dict/CharString) or 4-byte int (Dict)
-  template <typename INTTYPE, int minVal, int maxVal>
-  static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, int value)
+  template <typename T, typename V>
+  static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value)
   {
     TRACE_SERIALIZE (this);
 
-    if (unlikely ((value < minVal || value > maxVal)))
-      return_trace (false);
-
     HBUINT8 *p = c->allocate_size<HBUINT8> (1);
-    if (unlikely (p == nullptr)) return_trace (false);
-    p->set (intOp);
+    if (unlikely (!p)) return_trace (false);
+    *p = intOp;
 
-    INTTYPE *ip = c->allocate_size<INTTYPE> (INTTYPE::static_size);
-    if (unlikely (ip == nullptr)) return_trace (false);
-    ip->set ((unsigned int)value);
-
-    return_trace (true);
+    T *ip = c->allocate_size<T> (T::static_size);
+    if (unlikely (!ip)) return_trace (false);
+    return_trace (c->check_assign (*ip, value));
   }
 
-  static bool serialize_int4 (hb_serialize_context_t *c, int value)
-  { return serialize_int<HBUINT32, 0, 0x7FFFFFFF> (c, OpCode_longintdict, value); }
+  template <typename V>
+  static bool serialize_int4 (hb_serialize_context_t *c, V value)
+  { return serialize_int<HBINT32> (c, OpCode_longintdict, value); }
 
-  static bool serialize_int2 (hb_serialize_context_t *c, int value)
-  { return serialize_int<HBUINT16, 0, 0x7FFF> (c, OpCode_shortint, value); }
+  template <typename V>
+  static bool serialize_int2 (hb_serialize_context_t *c, V value)
+  { return serialize_int<HBINT16> (c, OpCode_shortint, value); }
 
   /* Defining null_size allows a Null object may be created. Should be safe because:
    * A descendent struct Dict uses a Null pointer to indicate a missing table,
@@ -320,8 +307,7 @@
 /* A byte string associated with the current offset and an error condition */
 struct byte_str_ref_t
 {
-  byte_str_ref_t ()
-  { init (); }
+  byte_str_ref_t () { init (); }
 
   void init ()
   {
@@ -343,13 +329,12 @@
   }
 
   const unsigned char& operator [] (int i) {
-    if (unlikely ((unsigned int)(offset + i) >= str.length))
+    if (unlikely ((unsigned int) (offset + i) >= str.length))
     {
       set_error ();
-      return Null(unsigned char);
+      return Null (unsigned char);
     }
-    else
-      return str[offset + i];
+    return str[offset + i];
   }
 
   /* Conversion to byte_str_t */
@@ -359,9 +344,7 @@
   { return str.sub_str (offset_, len_); }
 
   bool avail (unsigned int count=1) const
-  {
-    return (!in_error () && str.check_limit (offset, count));
-  }
+  { return (!in_error () && str.check_limit (offset, count)); }
   void inc (unsigned int count=1)
   {
     if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length)))
@@ -389,7 +372,7 @@
 
 /* stack */
 template <typename ELEM, int LIMIT>
-struct stack_t
+struct cff_stack_t
 {
   void init ()
   {
@@ -400,11 +383,7 @@
     for (unsigned int i = 0; i < elements.length; i++)
       elements[i].init ();
   }
-
-  void fini ()
-  {
-    elements.fini_deep ();
-  }
+  void fini () { elements.fini_deep (); }
 
   ELEM& operator [] (unsigned int i)
   {
@@ -419,7 +398,6 @@
     else
       set_error ();
   }
-
   ELEM &push ()
   {
     if (likely (count < elements.length))
@@ -427,7 +405,7 @@
     else
     {
       set_error ();
-      return Crap(ELEM);
+      return Crap (ELEM);
     }
   }
 
@@ -438,10 +416,9 @@
     else
     {
       set_error ();
-      return Crap(ELEM);
+      return Crap (ELEM);
     }
   }
-
   void pop (unsigned int n)
   {
     if (likely (count >= n))
@@ -452,13 +429,12 @@
 
   const ELEM& peek ()
   {
-    if (likely (count > 0))
-      return elements[count-1];
-    else
+    if (unlikely (count < 0))
     {
       set_error ();
-      return Null(ELEM);
+      return Null (ELEM);
     }
+    return elements[count - 1];
   }
 
   void unpop ()
@@ -475,7 +451,7 @@
   void set_error ()      { error = true; }
 
   unsigned int get_count () const { return count; }
-  bool is_empty () const { return count == 0; }
+  bool is_empty () const          { return !count; }
 
   static constexpr unsigned kSizeLimit = LIMIT;
 
@@ -487,7 +463,7 @@
 
 /* argument stack */
 template <typename ARG=number_t>
-struct arg_stack_t : stack_t<ARG, 513>
+struct arg_stack_t : cff_stack_t<ARG, 513>
 {
   void push_int (int v)
   {
@@ -519,7 +495,7 @@
       i = 0;
       S::set_error ();
     }
-    return (unsigned)i;
+    return (unsigned) i;
   }
 
   void push_longint_from_substr (byte_str_ref_t& str_ref)
@@ -538,12 +514,10 @@
   }
 
   hb_array_t<const ARG> get_subarray (unsigned int start) const
-  {
-    return S::elements.sub_array (start);
-  }
+  { return S::elements.sub_array (start); }
 
   private:
-  typedef stack_t<ARG, 513> S;
+  typedef cff_stack_t<ARG, 513> S;
 };
 
 /* an operator prefixed by its operands in a byte string */
@@ -565,7 +539,7 @@
     TRACE_SERIALIZE (this);
 
     HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
-    if (unlikely (d == nullptr)) return_trace (false);
+    if (unlikely (!d)) return_trace (false);
     memcpy (d, &opstr.str[0], opstr.str.length);
     return_trace (true);
   }
@@ -605,7 +579,7 @@
   }
 
   unsigned get_count () const { return values.length; }
-  const VAL &get_value (unsigned int i) const { return values[i]; }
+  const VAL &get_value (unsigned int i)   const { return values[i]; }
   const VAL &operator [] (unsigned int i) const { return get_value (i); }
 
   unsigned int       opStart;
@@ -644,30 +618,19 @@
     return op;
   }
 
-  const ARG& eval_arg (unsigned int i)
-  {
-    return argStack[i];
-  }
+  const ARG& eval_arg (unsigned int i) { return argStack[i]; }
 
-  ARG& pop_arg ()
-  {
-    return argStack.pop ();
-  }
+  ARG& pop_arg () { return argStack.pop (); }
+  void pop_n_args (unsigned int n) { argStack.pop (n); }
 
-  void pop_n_args (unsigned int n)
-  {
-    argStack.pop (n);
-  }
+  void clear_args () { pop_n_args (argStack.get_count ()); }
 
-  void clear_args ()
-  {
-    pop_n_args (argStack.get_count ());
-  }
-
-  byte_str_ref_t    str_ref;
-  arg_stack_t<ARG> argStack;
+  byte_str_ref_t
+                str_ref;
+  arg_stack_t<ARG>
+                argStack;
   protected:
-  bool    error;
+  bool          error;
 };
 
 typedef interp_env_t<> num_interp_env_t;
@@ -691,7 +654,7 @@
 
       case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
       case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
-        env.argStack.push_int ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108));
+        env.argStack.push_int ((-(int16_t)(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108));
         env.str_ref.inc ();
         break;
 
@@ -711,8 +674,8 @@
 };
 
 template <typename ENV>
-struct interpreter_t {
-
+struct interpreter_t
+{
   ~interpreter_t() { fini (); }
 
   void fini () { env.fini (); }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh
index d6d7f85..1b0d795 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh
@@ -57,14 +57,14 @@
 
 /* call stack */
 const unsigned int kMaxCallLimit = 10;
-struct call_stack_t : stack_t<call_context_t, kMaxCallLimit> {};
+struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
 
 template <typename SUBRS>
 struct biased_subrs_t
 {
-  void init (const SUBRS &subrs_)
+  void init (const SUBRS *subrs_)
   {
-    subrs = &subrs_;
+    subrs = subrs_;
     unsigned int  nSubrs = get_count ();
     if (nSubrs < 1240)
       bias = 107;
@@ -76,13 +76,13 @@
 
   void fini () {}
 
-  unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
-  unsigned int get_bias () const { return bias; }
+  unsigned int get_count () const { return subrs ? subrs->count : 0; }
+  unsigned int get_bias () const  { return bias; }
 
   byte_str_t operator [] (unsigned int index) const
   {
-    if (unlikely ((subrs == nullptr) || index >= subrs->count))
-      return Null(byte_str_t);
+    if (unlikely (!subrs || index >= subrs->count))
+      return Null (byte_str_t);
     else
       return (*subrs)[index];
   }
@@ -118,7 +118,7 @@
 template <typename ARG, typename SUBRS>
 struct cs_interp_env_t : interp_env_t<ARG>
 {
-  void init (const byte_str_t &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_)
+  void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_)
   {
     interp_env_t<ARG>::init (str);
 
@@ -147,8 +147,9 @@
     return callStack.in_error () || SUPER::in_error ();
   }
 
-  bool popSubrNum (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
+  bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
   {
+    subr_num = 0;
     int n = SUPER::argStack.pop_int ();
     n += biasedSubrs.get_bias ();
     if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
@@ -158,11 +159,11 @@
     return true;
   }
 
-  void callSubr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
+  void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
   {
-    unsigned int subr_num;
+    unsigned int subr_num = 0;
 
-    if (unlikely (!popSubrNum (biasedSubrs, subr_num)
+    if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
                  || callStack.get_count () >= kMaxCallLimit))
     {
       SUPER::set_error ();
@@ -175,7 +176,7 @@
     SUPER::str_ref = context.str_ref;
   }
 
-  void returnFromSubr ()
+  void return_from_subr ()
   {
     if (unlikely (SUPER::str_ref.in_error ()))
       SUPER::set_error ();
@@ -246,7 +247,7 @@
   static void flex1 (ENV &env, PARAM& param) {}
 };
 
-template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM> >
+template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>>
 struct cs_opset_t : opset_t<ARG>
 {
   static void process_op (op_code_t op, ENV &env, PARAM& param)
@@ -254,7 +255,7 @@
     switch (op) {
 
       case OpCode_return:
-        env.returnFromSubr ();
+        env.return_from_subr ();
         break;
       case OpCode_endchar:
         OPSET::check_width (op, env, param);
@@ -267,11 +268,11 @@
         break;
 
       case OpCode_callsubr:
-        env.callSubr (env.localSubrs, CSType_LocalSubr);
+        env.call_subr (env.localSubrs, CSType_LocalSubr);
         break;
 
       case OpCode_callgsubr:
-        env.callSubr (env.globalSubrs, CSType_GlobalSubr);
+        env.call_subr (env.globalSubrs, CSType_GlobalSubr);
         break;
 
       case OpCode_hstem:
@@ -550,8 +551,13 @@
 
   static void rcurveline (ENV &env, PARAM& param)
   {
+    unsigned int arg_count = env.argStack.get_count ();
+    if (unlikely (arg_count < 8))
+      return;
+
     unsigned int i = 0;
-    for (; i + 6 <= env.argStack.get_count (); i += 6)
+    unsigned int curve_limit = arg_count - 2;
+    for (; i + 6 <= curve_limit; i += 6)
     {
       point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
@@ -561,34 +567,34 @@
       pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
       PATH::curve (env, param, pt1, pt2, pt3);
     }
-    for (; i + 2 <= env.argStack.get_count (); i += 2)
-    {
-      point_t pt1 = env.get_pt ();
-      pt1.move (env.eval_arg (i), env.eval_arg (i+1));
-      PATH::line (env, param, pt1);
-    }
+
+    point_t pt1 = env.get_pt ();
+    pt1.move (env.eval_arg (i), env.eval_arg (i+1));
+    PATH::line (env, param, pt1);
   }
 
   static void rlinecurve (ENV &env, PARAM& param)
   {
+    unsigned int arg_count = env.argStack.get_count ();
+    if (unlikely (arg_count < 8))
+      return;
+
     unsigned int i = 0;
-    unsigned int line_limit = (env.argStack.get_count () % 6);
+    unsigned int line_limit = arg_count - 6;
     for (; i + 2 <= line_limit; i += 2)
     {
       point_t pt1 = env.get_pt ();
       pt1.move (env.eval_arg (i), env.eval_arg (i+1));
       PATH::line (env, param, pt1);
     }
-    for (; i + 6 <= env.argStack.get_count (); i += 6)
-    {
-      point_t pt1 = env.get_pt ();
-      pt1.move (env.eval_arg (i), env.eval_arg (i+1));
-      point_t pt2 = pt1;
-      pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
-      point_t pt3 = pt2;
-      pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
-      PATH::curve (env, param, pt1, pt2, pt3);
-    }
+
+    point_t pt1 = env.get_pt ();
+    pt1.move (env.eval_arg (i), env.eval_arg (i+1));
+    point_t pt2 = pt1;
+    pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
+    point_t pt3 = pt2;
+    pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
+    PATH::curve (env, param, pt1, pt2, pt3);
   }
 
   static void vvcurveto (ENV &env, PARAM& param)
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh
index 256c96c..a0a9429 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh
@@ -27,8 +27,6 @@
 #define HB_CFF_INTERP_DICT_COMMON_HH
 
 #include "hb-cff-interp-common.hh"
-#include <math.h>
-#include <float.h>
 
 namespace CFF {
 
@@ -58,19 +56,6 @@
   }
   void fini () { dict_values_t<OPSTR>::fini (); }
 
-  unsigned int calculate_serialized_op_size (const OPSTR& opstr) const
-  {
-    switch (opstr.op)
-    {
-      case OpCode_CharStrings:
-      case OpCode_FDArray:
-        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
-
-      default:
-        return opstr.str.length;
-    }
-  }
-
   unsigned int  charStringsOffset;
   unsigned int  FDArrayOffset;
 };
@@ -94,130 +79,52 @@
     }
   }
 
+  /* Turns CFF's BCD format into strtod understandable string */
   static double parse_bcd (byte_str_ref_t& str_ref)
   {
-    bool    neg = false;
-    double  int_part = 0;
-    uint64_t frac_part = 0;
-    uint32_t  frac_count = 0;
-    bool    exp_neg = false;
-    uint32_t  exp_part = 0;
-    bool    exp_overflow = false;
-    enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART;
-    enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
-    const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
-    const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */
+    if (unlikely (str_ref.in_error ())) return .0;
 
-    double  value = 0.0;
+    enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
+
+    char buf[32];
     unsigned char byte = 0;
-    for (uint32_t i = 0;; i++)
+    for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count)
     {
-      char d;
-      if ((i & 1) == 0)
+      unsigned nibble;
+      if (!(i & 1))
       {
-        if (!str_ref.avail ())
-        {
-          str_ref.set_error ();
-          return 0.0;
-        }
+        if (unlikely (!str_ref.avail ())) break;
+
         byte = str_ref[0];
         str_ref.inc ();
-        d = byte >> 4;
+        nibble = byte >> 4;
       }
       else
-        d = byte & 0x0F;
+        nibble = byte & 0x0F;
 
-      switch (d)
+      if (unlikely (nibble == RESERVED)) break;
+      else if (nibble == END)
       {
-        case RESERVED:
-          str_ref.set_error ();
-          return value;
-
-        case END:
-          value = (double)(neg? -int_part: int_part);
-          if (frac_count > 0)
-          {
-            double frac = (frac_part / pow (10.0, (double)frac_count));
-            if (neg) frac = -frac;
-            value += frac;
-          }
-          if (unlikely (exp_overflow))
-          {
-            if (value == 0.0)
-              return value;
-            if (exp_neg)
-              return neg? -DBL_MIN: DBL_MIN;
-            else
-              return neg? -DBL_MAX: DBL_MAX;
-          }
-          if (exp_part != 0)
-          {
-            if (exp_neg)
-              value /= pow (10.0, (double)exp_part);
-            else
-              value *= pow (10.0, (double)exp_part);
-          }
-          return value;
-
-        case NEG:
-          if (i != 0)
-          {
-            str_ref.set_error ();
-            return 0.0;
-          }
-          neg = true;
+        const char *p = buf;
+        double pv;
+        if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */)))
           break;
-
-        case DECIMAL:
-          if (part != INT_PART)
-          {
-            str_ref.set_error ();
-            return value;
-          }
-          part = FRAC_PART;
-          break;
-
-        case EXP_NEG:
-          exp_neg = true;
-          HB_FALLTHROUGH;
-
-        case EXP_POS:
-          if (part == EXP_PART)
-          {
-            str_ref.set_error ();
-            return value;
-          }
-          part = EXP_PART;
-          break;
-
-        default:
-          switch (part) {
-            default:
-            case INT_PART:
-              int_part = (int_part * 10) + d;
-              break;
-
-            case FRAC_PART:
-              if (likely (frac_part <= MAX_FRACT / 10))
-              {
-                frac_part = (frac_part * 10) + (unsigned)d;
-                frac_count++;
-              }
-              break;
-
-            case EXP_PART:
-              if (likely (exp_part * 10 + d <= MAX_EXP))
-              {
-                exp_part = (exp_part * 10) + d;
-              }
-              else
-                exp_overflow = true;
-              break;
-          }
+        return pv;
+      }
+      else
+      {
+        buf[count] = "0123456789.EE?-?"[nibble];
+        if (nibble == EXP_NEG)
+        {
+          ++count;
+          if (unlikely (count == ARRAY_LENGTH (buf))) break;
+          buf[count] = '-';
+        }
       }
     }
 
-    return value;
+    str_ref.set_error ();
+    return .0;
   }
 
   static bool is_hint_op (op_code_t op)
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh
index a8208a3..96718f4 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh
@@ -40,7 +40,7 @@
   template <typename ACC>
   void init (const byte_str_t &str, ACC &acc, unsigned int fd)
   {
-    SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
+    SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
     processed_width = false;
     has_width = false;
     arg_start = 0;
@@ -81,7 +81,7 @@
   typedef cs_interp_env_t<number_t, CFF1Subrs> SUPER;
 };
 
-template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM> >
+template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM>>
 struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH>
 {
   /* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh
index 6971c2e..f1de1e3 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh
@@ -52,7 +52,7 @@
   void set_real (double v) { reset_blends (); number_t::set_real (v); }
 
   void set_blends (unsigned int numValues_, unsigned int valueIndex_,
-                          unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
+                   unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
   {
     numValues = numValues_;
     valueIndex = valueIndex_;
@@ -80,9 +80,9 @@
 {
   template <typename ACC>
   void init (const byte_str_t &str, ACC &acc, unsigned int fd,
-                    const int *coords_=nullptr, unsigned int num_coords_=0)
+             const int *coords_=nullptr, unsigned int num_coords_=0)
   {
-    SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
+    SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
 
     coords = coords_;
     num_coords = num_coords_;
@@ -90,7 +90,7 @@
     seen_blend = false;
     seen_vsindex_ = false;
     scalars.init ();
-    do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
+    do_blend = num_coords && coords && varStore->size;
     set_ivs (acc.privateDicts[fd].ivs);
   }
 
@@ -133,10 +133,11 @@
       region_count = varStore->varStore.get_region_index_count (get_ivs ());
       if (do_blend)
       {
-        scalars.resize (region_count);
-        varStore->varStore.get_scalars (get_ivs (),
-                                        (int *)coords, num_coords,
-                                        &scalars[0], region_count);
+        if (unlikely (!scalars.resize (region_count)))
+          set_error ();
+        else
+          varStore->varStore.get_scalars (get_ivs (), coords, num_coords,
+                                          &scalars[0], region_count);
       }
       seen_blend = true;
     }
@@ -193,7 +194,7 @@
 
   typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
 };
-template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM> >
+template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>>
 struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
 {
   static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-common.cc
index 890697c..4dd2479 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-common.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-common.cc
@@ -27,14 +27,13 @@
  */
 
 #include "hb.hh"
-
 #include "hb-machinery.hh"
 
 #include <locale.h>
-#ifdef HAVE_XLOCALE_H
-#include <xlocale.h>
-#endif
 
+#ifdef HB_NO_SETLOCALE
+#define setlocale(Category, Locale) "C"
+#endif
 
 /**
  * SECTION:hb-common
@@ -67,10 +66,9 @@
         p = c + strlen (c);
 
 #define OPTION(name, symbol) \
-        if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true;
+        if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
 
       OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
-      OPTION ("aat", aat);
 
 #undef OPTION
 
@@ -334,14 +332,14 @@
 /**
  * hb_language_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing
- *       a BCP 47 language tag
+ *       a BCP 47 language tag
  * @len: length of the @str, or -1 if it is %NULL-terminated.
  *
- * Converts @str representing a BCP 47 language tag to the corresponding
+ * Converts @str representing a BCP 47 language tag to the corresponding
  * #hb_language_t.
  *
  * Return value: (transfer none):
- * The #hb_language_t corresponding to the BCP 47 language tag.
+ * The #hb_language_t corresponding to the BCP 47 language tag.
  *
  * Since: 0.9.2
  **/
@@ -356,7 +354,7 @@
   {
     /* NUL-terminate it. */
     char strbuf[64];
-    len = MIN (len, (int) sizeof (strbuf) - 1);
+    len = hb_min (len, (int) sizeof (strbuf) - 1);
     memcpy (strbuf, str, len);
     strbuf[len] = '\0';
     item = lang_find_or_insert (strbuf);
@@ -382,7 +380,8 @@
 const char *
 hb_language_to_string (hb_language_t language)
 {
-  /* This is actually nullptr-safe! */
+  if (unlikely (!language)) return nullptr;
+
   return language->s;
 }
 
@@ -422,12 +421,12 @@
 
 /**
  * hb_script_from_iso15924_tag:
- * @tag: an #hb_tag_t representing an ISO 15924 tag.
+ * @tag: an #hb_tag_t representing an ISO 15924 tag.
  *
- * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
+ * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
  *
  * Return value:
- * An #hb_script_t corresponding to the ISO 15924 tag.
+ * An #hb_script_t corresponding to the ISO 15924 tag.
  *
  * Since: 0.9.2
  **/
@@ -468,15 +467,15 @@
 /**
  * hb_script_from_string:
  * @str: (array length=len) (element-type uint8_t): a string representing an
- *       ISO 15924 tag.
+ *       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
+ * 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.
+ * An #hb_script_t corresponding to the ISO 15924 tag.
  *
  * Since: 0.9.2
  **/
@@ -488,12 +487,12 @@
 
 /**
  * hb_script_to_iso15924_tag:
- * @script: an #hb_script_ to convert.
+ * @script: an #hb_script_t to convert.
  *
  * See hb_script_from_iso15924_tag().
  *
  * Return value:
- * An #hb_tag_t representing an ISO 15924 script tag.
+ * An #hb_tag_t representing an ISO 15924 script tag.
  *
  * Since: 0.9.2
  **/
@@ -575,6 +574,13 @@
     case HB_SCRIPT_OLD_SOGDIAN:
     case HB_SCRIPT_SOGDIAN:
 
+    /* Unicode-12.0 additions */
+    case HB_SCRIPT_ELYMAIC:
+
+    /* Unicode-13.0 additions */
+    case HB_SCRIPT_CHORASMIAN:
+    case HB_SCRIPT_YEZIDI:
+
       return HB_DIRECTION_RTL;
 
 
@@ -590,38 +596,6 @@
 }
 
 
-/* hb_user_data_array_t */
-
-bool
-hb_user_data_array_t::set (hb_user_data_key_t *key,
-                           void *              data,
-                           hb_destroy_func_t   destroy,
-                           hb_bool_t           replace)
-{
-  if (!key)
-    return false;
-
-  if (replace) {
-    if (!data && !destroy) {
-      items.remove (key, lock);
-      return true;
-    }
-  }
-  hb_user_data_item_t item = {key, data, destroy};
-  bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
-
-  return ret;
-}
-
-void *
-hb_user_data_array_t::get (hb_user_data_key_t *key)
-{
-  hb_user_data_item_t item = {nullptr, nullptr, nullptr};
-
-  return items.find (key, &item, lock) ? item.data : nullptr;
-}
-
-
 /* hb_version */
 
 
@@ -719,131 +693,24 @@
 static bool
 parse_uint (const char **pp, const char *end, unsigned int *pv)
 {
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
-  strncpy (buf, *pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  unsigned int v;
-
-  /* Intentionally use strtol instead of strtoul, such that
-   * -1 turns into "big number"... */
-  errno = 0;
-  v = strtol (p, &pend, 0);
-  if (errno || p == pend)
-    return false;
+  /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
+   * such that -1 turns into "big number"... */
+  int v;
+  if (unlikely (!hb_parse_int (pp, end, &v))) return false;
 
   *pv = v;
-  *pp += pend - p;
   return true;
 }
 
 static bool
 parse_uint32 (const char **pp, const char *end, uint32_t *pv)
 {
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
-  strncpy (buf, *pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  unsigned int v;
-
-  /* Intentionally use strtol instead of strtoul, such that
-   * -1 turns into "big number"... */
-  errno = 0;
-  v = strtol (p, &pend, 0);
-  if (errno || p == pend)
-    return false;
+  /* Intentionally use hb_parse_int inside instead of hb_parse_uint,
+   * such that -1 turns into "big number"... */
+  int v;
+  if (unlikely (!hb_parse_int (pp, end, &v))) return false;
 
   *pv = v;
-  *pp += pend - p;
-  return true;
-}
-
-#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
-#define USE_XLOCALE 1
-#define HB_LOCALE_T locale_t
-#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
-#define HB_FREE_LOCALE(loc) freelocale (loc)
-#elif defined(_MSC_VER)
-#define USE_XLOCALE 1
-#define HB_LOCALE_T _locale_t
-#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
-#define HB_FREE_LOCALE(loc) _free_locale (loc)
-#define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
-#endif
-
-#ifdef USE_XLOCALE
-
-#if HB_USE_ATEXIT
-static void free_static_C_locale ();
-#endif
-
-static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (HB_LOCALE_T),
-                                                          hb_C_locale_lazy_loader_t>
-{
-  static HB_LOCALE_T create ()
-  {
-    HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
-
-#if HB_USE_ATEXIT
-    atexit (free_static_C_locale);
-#endif
-
-    return C_locale;
-  }
-  static void destroy (HB_LOCALE_T p)
-  {
-    HB_FREE_LOCALE (p);
-  }
-  static HB_LOCALE_T get_null ()
-  {
-    return nullptr;
-  }
-} static_C_locale;
-
-#if HB_USE_ATEXIT
-static
-void free_static_C_locale ()
-{
-  static_C_locale.free_instance ();
-}
-#endif
-
-static HB_LOCALE_T
-get_C_locale ()
-{
-  return static_C_locale.get_unconst ();
-}
-#endif /* USE_XLOCALE */
-
-static bool
-parse_float (const char **pp, const char *end, float *pv)
-{
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
-  strncpy (buf, *pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  float v;
-
-  errno = 0;
-#ifdef USE_XLOCALE
-  v = strtod_l (p, &pend, get_C_locale ());
-#else
-  v = strtod (p, &pend);
-#endif
-  if (errno || p == pend)
-    return false;
-
-  *pv = v;
-  *pp += pend - p;
   return true;
 }
 
@@ -857,9 +724,14 @@
     (*pp)++;
 
   /* CSS allows on/off as aliases 1/0. */
-  if (*pp - p == 2 && 0 == strncmp (p, "on", 2))
+  if (*pp - p == 2
+      && TOLOWER (p[0]) == 'o'
+      && TOLOWER (p[1]) == 'n')
     *pv = 1;
-  else if (*pp - p == 3 && 0 == strncmp (p, "off", 3))
+  else if (*pp - p == 3
+           && TOLOWER (p[0]) == 'o'
+           && TOLOWER (p[1]) == 'f'
+           && TOLOWER (p[2]) == 'f')
     *pv = 0;
   else
     return false;
@@ -974,7 +846,41 @@
  *
  * Parses a string into a #hb_feature_t.
  *
- * TODO: document the syntax here.
+ * The format for specifying feature strings follows. All valid CSS
+ * font-feature-settings values other than 'normal' and the global values are
+ * also accepted, though not documented below. CSS string escapes are not
+ * supported.
+ *
+ * The range indices refer to the positions between Unicode characters. The
+ * position before the first character is always 0.
+ *
+ * The format is Python-esque.  Here is how it all works:
+ *
+ * <informaltable pgwide='1' align='left' frame='none'>
+ * <tgroup cols='5'>
+ * <thead>
+ * <row><entry>Syntax</entry>    <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
+ * </thead>
+ * <tbody>
+ * <row><entry>Setting value:</entry></row>
+ * <row><entry>kern</entry>      <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>+kern</entry>     <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>-kern</entry>     <entry>0</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature off</entry></row>
+ * <row><entry>kern=0</entry>    <entry>0</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature off</entry></row>
+ * <row><entry>kern=1</entry>    <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>aalt=2</entry>    <entry>2</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Choose 2nd alternate</entry></row>
+ * <row><entry>Setting index:</entry></row>
+ * <row><entry>kern[]</entry>    <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>kern[:]</entry>   <entry>1</entry>     <entry>0</entry>      <entry>∞</entry>   <entry>Turn feature on</entry></row>
+ * <row><entry>kern[5:]</entry>  <entry>1</entry>     <entry>5</entry>      <entry>∞</entry>   <entry>Turn feature on, partial</entry></row>
+ * <row><entry>kern[:5]</entry>  <entry>1</entry>     <entry>0</entry>      <entry>5</entry>   <entry>Turn feature on, partial</entry></row>
+ * <row><entry>kern[3:5]</entry> <entry>1</entry>     <entry>3</entry>      <entry>5</entry>   <entry>Turn feature on, range</entry></row>
+ * <row><entry>kern[3]</entry>   <entry>1</entry>     <entry>3</entry>      <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
+ * <row><entry>Mixing it all:</entry></row>
+ * <row><entry>aalt[3:5]=2</entry> <entry>2</entry>   <entry>3</entry>      <entry>5</entry>   <entry>Turn 2nd alternate on for range</entry></row>
+ * </tbody>
+ * </tgroup>
+ * </informaltable>
  *
  * Return value:
  * %true if @str is successfully parsed, %false otherwise.
@@ -1028,25 +934,25 @@
   len += 4;
   while (len && s[len - 1] == ' ')
     len--;
-  if (feature->start != 0 || feature->end != (unsigned int) -1)
+  if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END)
   {
     s[len++] = '[';
     if (feature->start)
-      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
+      len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
     if (feature->end != feature->start + 1) {
       s[len++] = ':';
-      if (feature->end != (unsigned int) -1)
-        len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
+      if (feature->end != HB_FEATURE_GLOBAL_END)
+        len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
     }
     s[len++] = ']';
   }
   if (feature->value > 1)
   {
     s[len++] = '=';
-    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
+    len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
   }
   assert (len < ARRAY_LENGTH (s));
-  len = MIN (len, size - 1);
+  len = hb_min (len, size - 1);
   memcpy (buf, s, len);
   buf[len] = '\0';
 }
@@ -1057,7 +963,11 @@
 parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
 {
   parse_char (pp, end, '='); /* Optional. */
-  return parse_float (pp, end, &variation->value);
+  double v;
+  if (unlikely (!hb_parse_double (pp, end, &v))) return false;
+
+  variation->value = v;
+  return true;
 }
 
 static bool
@@ -1113,14 +1023,71 @@
   while (len && s[len - 1] == ' ')
     len--;
   s[len++] = '=';
-  len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
+  len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
 
   assert (len < ARRAY_LENGTH (s));
-  len = MIN (len, size - 1);
+  len = hb_min (len, size - 1);
   memcpy (buf, s, len);
   buf[len] = '\0';
 }
 
+/**
+ * hb_color_get_alpha:
+ * color: a #hb_color_t we are interested in its channels.
+ *
+ * Return value: Alpha channel value of the given color
+ *
+ * Since: 2.1.0
+ */
+uint8_t
+(hb_color_get_alpha) (hb_color_t color)
+{
+  return hb_color_get_alpha (color);
+}
+
+/**
+ * hb_color_get_red:
+ * color: a #hb_color_t we are interested in its channels.
+ *
+ * Return value: Red channel value of the given color
+ *
+ * Since: 2.1.0
+ */
+uint8_t
+(hb_color_get_red) (hb_color_t color)
+{
+  return hb_color_get_red (color);
+}
+
+/**
+ * hb_color_get_green:
+ * color: a #hb_color_t we are interested in its channels.
+ *
+ * Return value: Green channel value of the given color
+ *
+ * Since: 2.1.0
+ */
+uint8_t
+(hb_color_get_green) (hb_color_t color)
+{
+  return hb_color_get_green (color);
+}
+
+/**
+ * hb_color_get_blue:
+ * color: a #hb_color_t we are interested in its channels.
+ *
+ * Return value: Blue channel value of the given color
+ *
+ * Since: 2.1.0
+ */
+uint8_t
+(hb_color_get_blue) (hb_color_t color)
+{
+  return hb_color_get_blue (color);
+}
+
+
 /* If there is no visibility control, then hb-static.cc will NOT
  * define anything.  Instead, we get it to define one set in here
  * only, so only libharfbuzz.so defines them, not other libs. */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.h b/src/java.desktop/share/native/libharfbuzz/hb-common.h
index fea193a..9614e72 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-common.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-common.h
@@ -63,6 +63,8 @@
 typedef unsigned __int32 uint32_t;
 typedef __int64 int64_t;
 typedef unsigned __int64 uint64_t;
+#elif defined (__KERNEL__)
+#  include <linux/types.h>
 #else
 #  include <stdint.h>
 #endif
@@ -357,6 +359,22 @@
   /*11.0*/HB_SCRIPT_OLD_SOGDIAN                 = HB_TAG ('S','o','g','o'),
   /*11.0*/HB_SCRIPT_SOGDIAN                     = HB_TAG ('S','o','g','d'),
 
+  /*
+   * Since 2.4.0
+   */
+  /*12.0*/HB_SCRIPT_ELYMAIC                     = HB_TAG ('E','l','y','m'),
+  /*12.0*/HB_SCRIPT_NANDINAGARI                 = HB_TAG ('N','a','n','d'),
+  /*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG      = HB_TAG ('H','m','n','p'),
+  /*12.0*/HB_SCRIPT_WANCHO                      = HB_TAG ('W','c','h','o'),
+
+  /*
+   * Since 2.6.7
+   */
+  /*13.0*/HB_SCRIPT_CHORASMIAN                  = HB_TAG ('C','h','r','s'),
+  /*13.0*/HB_SCRIPT_DIVES_AKURU                 = HB_TAG ('D','i','a','k'),
+  /*13.0*/HB_SCRIPT_KHITAN_SMALL_SCRIPT         = HB_TAG ('K','i','t','s'),
+  /*13.0*/HB_SCRIPT_YEZIDI                      = HB_TAG ('Y','e','z','i'),
+
   /* No script set. */
   HB_SCRIPT_INVALID                             = HB_TAG_NONE,
 
@@ -415,6 +433,21 @@
  */
 #define HB_FEATURE_GLOBAL_END   ((unsigned int) -1)
 
+/**
+ * hb_feature_t:
+ * @tag: a feature tag
+ * @value: 0 disables the feature, non-zero (usually 1) enables the feature.
+ * For features implemented as lookup type 3 (like 'salt') the @value is a one
+ * based index into the alternates.
+ * @start: the cluster to start applying this feature setting (inclusive).
+ * @end: the cluster to end applying this feature setting (exclusive).
+ *
+ * The #hb_feature_t is the structure that holds information about requested
+ * feature application. The feature will be applied with the given value to all
+ * glyphs which are in clusters between @start (inclusive) and @end (exclusive).
+ * Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
+ * specifies that the feature always applies to the entire buffer.
+ */
 typedef struct hb_feature_t {
   hb_tag_t      tag;
   uint32_t      value;
@@ -459,39 +492,21 @@
 
 #define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))
 
-/**
- * hb_color_get_alpha:
- *
- *
- *
- * Since: 2.1.0
- */
+HB_EXTERN uint8_t
+hb_color_get_alpha (hb_color_t color);
 #define hb_color_get_alpha(color)       ((color) & 0xFF)
-/**
- * hb_color_get_red:
- *
- *
- *
- * Since: 2.1.0
- */
-#define hb_color_get_red(color)         (((color) >> 8) & 0xFF)
-/**
- * hb_color_get_green:
- *
- *
- *
- * Since: 2.1.0
- */
-#define hb_color_get_green(color)       (((color) >> 16) & 0xFF)
-/**
- * hb_color_get_blue:
- *
- *
- *
- * Since: 2.1.0
- */
-#define hb_color_get_blue(color)        (((color) >> 24) & 0xFF)
 
+HB_EXTERN uint8_t
+hb_color_get_red (hb_color_t color);
+#define hb_color_get_red(color)         (((color) >> 8) & 0xFF)
+
+HB_EXTERN uint8_t
+hb_color_get_green (hb_color_t color);
+#define hb_color_get_green(color)       (((color) >> 16) & 0xFF)
+
+HB_EXTERN uint8_t
+hb_color_get_blue (hb_color_t color);
+#define hb_color_get_blue(color)        (((color) >> 24) & 0xFF)
 
 HB_END_DECLS
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-config.hh b/src/java.desktop/share/native/libharfbuzz/hb-config.hh
new file mode 100644
index 0000000..fc8d424
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-config.hh
@@ -0,0 +1,163 @@
+/*
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_CONFIG_HH
+#define HB_CONFIG_HH
+
+#if 0 /* Make test happy. */
+#include "hb.hh"
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#ifdef HB_TINY
+#define HB_LEAN
+#define HB_MINI
+#define HB_NO_MT
+#define HB_NO_UCD_UNASSIGNED
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+#ifndef __OPTIMIZE_SIZE__
+#define __OPTIMIZE_SIZE__
+#endif
+#endif
+
+#ifdef HB_LEAN
+#define HB_DISABLE_DEPRECATED
+#define HB_NDEBUG
+#define HB_NO_ATEXIT
+#define HB_NO_BUFFER_MESSAGE
+#define HB_NO_BUFFER_SERIALIZE
+#define HB_NO_BITMAP
+#define HB_NO_CFF
+#define HB_NO_COLOR
+#define HB_NO_DRAW
+#define HB_NO_ERRNO
+#define HB_NO_FACE_COLLECT_UNICODES
+#define HB_NO_GETENV
+#define HB_NO_HINTING
+#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
+#define HB_NO_LAYOUT_FEATURE_PARAMS
+#define HB_NO_LAYOUT_COLLECT_GLYPHS
+#define HB_NO_LAYOUT_UNUSED
+#define HB_NO_MATH
+#define HB_NO_META
+#define HB_NO_METRICS
+#define HB_NO_MMAP
+#define HB_NO_NAME
+#define HB_NO_OPEN
+#define HB_NO_SETLOCALE
+#define HB_NO_OT_FONT_GLYPH_NAMES
+#define HB_NO_OT_SHAPE_FRACTIONS
+#define HB_NO_STYLE
+#define HB_NO_SUBSET_LAYOUT
+#define HB_NO_VAR
+#endif
+
+#ifdef HB_MINI
+#define HB_NO_AAT
+#define HB_NO_LEGACY
+#endif
+
+
+/* Closure of options. */
+
+#ifdef HB_DISABLE_DEPRECATED
+#define HB_IF_NOT_DEPRECATED(x)
+#else
+#define HB_IF_NOT_DEPRECATED(x) x
+#endif
+
+#ifdef HB_NO_AAT
+#define HB_NO_OT_NAME_LANGUAGE_AAT
+#define HB_NO_AAT_SHAPE
+#endif
+
+#ifdef HB_NO_BITMAP
+#define HB_NO_OT_FONT_BITMAP
+#endif
+
+#ifdef HB_NO_CFF
+#define HB_NO_OT_FONT_CFF
+#define HB_NO_SUBSET_CFF
+#endif
+
+#ifdef HB_NO_GETENV
+#define HB_NO_UNISCRIBE_BUG_COMPATIBLE
+#endif
+
+#ifdef HB_NO_LEGACY
+#define HB_NO_CMAP_LEGACY_SUBTABLES
+#define HB_NO_FALLBACK_SHAPE
+#define HB_NO_OT_KERN
+#define HB_NO_OT_LAYOUT_BLACKLIST
+#define HB_NO_OT_SHAPE_FALLBACK
+#endif
+
+#ifdef HB_NO_NAME
+#define HB_NO_OT_NAME_LANGUAGE
+#endif
+
+#ifdef HB_NO_OT
+#define HB_NO_OT_FONT
+#define HB_NO_OT_LAYOUT
+#define HB_NO_OT_TAG
+#define HB_NO_OT_SHAPE
+#endif
+
+#ifdef HB_NO_OT_SHAPE
+#define HB_NO_AAT_SHAPE
+#endif
+
+#ifdef HB_NO_OT_SHAPE_FALLBACK
+#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
+#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
+#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
+#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
+#endif
+
+#ifdef NDEBUG
+#ifndef HB_NDEBUG
+#define HB_NDEBUG
+#endif
+#endif
+
+#ifdef __OPTIMIZE_SIZE__
+#ifndef HB_OPTIMIZE_SIZE
+#define HB_OPTIMIZE_SIZE
+#endif
+#endif
+
+#ifdef HAVE_CONFIG_OVERRIDE_H
+#include "config-override.h"
+#endif
+
+
+#endif /* HB_CONFIG_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-coretext.cc b/src/java.desktop/share/native/libharfbuzz/hb-coretext.cc
index f8d0308..a382228 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-coretext.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-coretext.cc
@@ -27,6 +27,9 @@
  */
 
 #include "hb.hh"
+
+#ifdef HAVE_CORETEXT
+
 #include "hb-shaper-impl.hh"
 
 #include "hb-coretext.h"
@@ -46,24 +49,6 @@
 /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
 #define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
 
-static CGFloat
-coretext_font_size_from_ptem (float ptem)
-{
-  /* CoreText points are CSS pixels (96 per inch),
-   * NOT typographic points (72 per inch).
-   *
-   * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
-   */
-  ptem *= 96.f / 72.f;
-  return ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : ptem;
-}
-static float
-coretext_font_size_to_ptem (CGFloat size)
-{
-  size *= 72.f / 96.f;
-  return size <= 0.f ? 0 : size;
-}
-
 static void
 release_table_data (void *user_data)
 {
@@ -72,7 +57,7 @@
 }
 
 static hb_blob_t *
-reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
   CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
   CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
@@ -171,7 +156,7 @@
   if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
       CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
   {
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
 # define kCTFontUIFontSystem kCTFontSystemFontType
 # define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
 #endif
@@ -214,7 +199,7 @@
   }
 
   CFURLRef original_url = nullptr;
-#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
   ATSFontRef atsFont;
   FSRef fsref;
   OSStatus status;
@@ -244,7 +229,7 @@
        * process in Blink. This can be detected by the new file URL location
        * that the newly found font points to. */
       CFURLRef new_url = nullptr;
-#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
       atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
       status = ATSFontGetFileReference (atsFont, &fsref);
       if (status == noErr)
@@ -293,13 +278,32 @@
   CFRelease ((CGFontRef) data);
 }
 
+/**
+ * hb_coretext_face_create:
+ * @cg_font: The CGFontRef to work upon
+ *
+ * Creates an #hb_face_t face object from the specified
+ * CGFontRef.
+ *
+ * Return value: the new #hb_face_t face object
+ *
+ * Since: 0.9.10
+ */
 hb_face_t *
 hb_coretext_face_create (CGFontRef cg_font)
 {
-  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
+  return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
 }
 
-/*
+/**
+ * hb_coretext_face_get_cg_font:
+ * @face: The #hb_face_t to work upon
+ *
+ * Fetches the CGFontRef associated with an #hb_face_t
+ * face object
+ *
+ * Return value: the CGFontRef found
+ *
  * Since: 0.9.10
  */
 CGFontRef
@@ -317,7 +321,8 @@
   if (unlikely (!face_data)) return nullptr;
   CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
 
-  CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size_from_ptem (font->ptem));
+  CGFloat font_size = (CGFloat) (font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem);
+  CTFontRef ct_font = create_ct_font (cg_font, font_size);
 
   if (unlikely (!ct_font))
   {
@@ -341,7 +346,7 @@
   const hb_coretext_font_data_t *data = font->data.coretext;
   if (unlikely (!data)) return nullptr;
 
-  if (fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) > .5)
+  if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > .5)
   {
     /* XXX-MT-bug
      * Note that evaluating condition above can be dangerous if another thread
@@ -365,10 +370,17 @@
   return font->data.coretext;
 }
 
-
-/*
+/**
+ * hb_coretext_font_create:
+ * @ct_font: The CTFontRef to work upon
+ *
+ * Creates an #hb_font_t font object from the specified
+ * CTFontRef.
+ *
+ * Return value: the new #hb_font_t font object
+ *
  * Since: 1.7.2
- */
+ **/
 hb_font_t *
 hb_coretext_font_create (CTFontRef ct_font)
 {
@@ -381,7 +393,7 @@
   if (unlikely (hb_object_is_immutable (font)))
     return font;
 
-  hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font)));
+  hb_font_set_ptem (font, CTFontGetSize (ct_font));
 
   /* Let there be dragons here... */
   font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
@@ -389,6 +401,17 @@
   return font;
 }
 
+/**
+ * hb_coretext_face_get_ct_font:
+ * @font: #hb_font_t to work upon
+ *
+ * Fetches the CTFontRef associated with the specified
+ * #hb_font_t font object.
+ *
+ * Return value: the CTFontRef found
+ *
+ * Since: 0.9.10
+ */
 CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font)
 {
@@ -410,7 +433,7 @@
   feature_record_t rec;
   unsigned int order;
 
-  static int cmp (const void *pa, const void *pb) {
+  HB_INTERNAL static int cmp (const void *pa, const void *pb) {
     const active_feature_t *a = (const active_feature_t *) pa;
     const active_feature_t *b = (const active_feature_t *) pb;
     return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
@@ -428,7 +451,7 @@
   bool start;
   active_feature_t feature;
 
-  static int cmp (const void *pa, const void *pb) {
+  HB_INTERNAL static int cmp (const void *pa, const void *pb) {
     const feature_event_t *a = (const feature_event_t *) pa;
     const feature_event_t *b = (const feature_event_t *) pb;
     return a->index < b->index ? -1 : a->index > b->index ? 1 :
@@ -489,13 +512,19 @@
     hb_vector_t<feature_event_t> feature_events;
     for (unsigned int i = 0; i < num_features; i++)
     {
+      active_feature_t feature;
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
       const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag);
       if (!mapping)
         continue;
 
-      active_feature_t feature;
       feature.rec.feature = mapping->aatFeatureType;
       feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
+#else
+      feature.rec.feature = features[i].tag;
+      feature.rec.setting = features[i].value;
+#endif
       feature.order = i;
 
       feature_event_t *event;
@@ -544,6 +573,7 @@
           /* active_features.qsort (); */
           for (unsigned int j = 0; j < active_features.length; j++)
           {
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
             CFStringRef keys[] = {
               kCTFontFeatureTypeIdentifierKey,
               kCTFontFeatureSelectorIdentifierKey
@@ -552,6 +582,17 @@
               CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
               CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
             };
+#else
+            char tag[5] = {HB_UNTAG (active_features[j].rec.feature)};
+            CFTypeRef keys[] = {
+              kCTFontOpenTypeFeatureTag,
+              kCTFontOpenTypeFeatureValue
+            };
+            CFTypeRef values[] = {
+              CFStringCreateWithCString (kCFAllocatorDefault, tag, kCFStringEncodingASCII),
+              CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
+            };
+#endif
             static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), "");
             CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
                                                        (const void **) keys,
@@ -598,7 +639,7 @@
       } else {
         active_feature_t *feature = active_features.find (&event->feature);
         if (feature)
-          active_features.remove (feature - active_features.arrayZ ());
+          active_features.remove (feature - active_features.arrayZ);
       }
     }
   }
@@ -608,7 +649,7 @@
 
 #define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
   Type *name = (Type *) scratch; \
-  { \
+  do { \
     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
     if (unlikely (_consumed > scratch_size)) \
     { \
@@ -617,9 +658,9 @@
     } \
     scratch += _consumed; \
     scratch_size -= _consumed; \
-  }
+  } while (0)
 
-  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
+  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, ((void)nullptr) /*nothing*/);
   unsigned int chars_len = 0;
   for (unsigned int i = 0; i < buffer->len; i++) {
     hb_codepoint_t c = buffer->info[i].codepoint;
@@ -633,7 +674,7 @@
     }
   }
 
-  ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/);
+  ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, ((void)nullptr) /*nothing*/);
   chars_len = 0;
   for (unsigned int i = 0; i < buffer->len; i++)
   {
@@ -649,7 +690,7 @@
     DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
     ret = false; \
     goto fail; \
-  } HB_STMT_END;
+  } HB_STMT_END
 
   bool ret = true;
   CFStringRef string_ref = nullptr;
@@ -711,7 +752,7 @@
 /* What's the iOS equivalent of this check?
  * The symbols was introduced in iOS 7.0.
  * At any rate, our fallback is safe and works fine. */
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1090
 #  define kCTLanguageAttributeName CFSTR ("NSLanguage")
 #endif
         CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
@@ -771,7 +812,7 @@
               feature.start < chars_len && feature.start < feature.end)
           {
             CFRange feature_range = CFRangeMake (feature.start,
-                                                 MIN (feature.end, chars_len) - feature.start);
+                                                 hb_min (feature.end, chars_len) - feature.start);
             if (feature.value)
               CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
             else
@@ -783,7 +824,7 @@
 
       int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
       CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
       extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
 #endif
       CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
@@ -977,7 +1018,7 @@
 
 #define SCRATCH_RESTORE() \
   scratch_size = scratch_size_saved; \
-  scratch = scratch_saved;
+  scratch = scratch_saved
 
       { /* Setup glyphs */
         SCRATCH_SAVE();
@@ -1069,7 +1110,7 @@
     if (false)
     {
       /* Make sure all runs had the expected direction. */
-      bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+      HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
       assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
       assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
     }
@@ -1116,7 +1157,7 @@
         unsigned int cluster = info[count - 1].cluster;
         for (unsigned int i = count - 1; i > 0; i--)
         {
-          cluster = MIN (cluster, info[i - 1].cluster);
+          cluster = hb_min (cluster, info[i - 1].cluster);
           info[i - 1].cluster = cluster;
         }
       }
@@ -1125,7 +1166,7 @@
         unsigned int cluster = info[0].cluster;
         for (unsigned int i = 1; i < count; i++)
         {
-          cluster = MIN (cluster, info[i].cluster);
+          cluster = hb_min (cluster, info[i].cluster);
           info[i].cluster = cluster;
         }
       }
@@ -1150,57 +1191,4 @@
 }
 
 
-/*
- * AAT shaper
- */
-
-/*
- * shaper face data
- */
-
-struct hb_coretext_aat_face_data_t {};
-
-hb_coretext_aat_face_data_t *
-_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
-{
-  return hb_aat_layout_has_substitution (face) || hb_aat_layout_has_positioning (face) ?
-         (hb_coretext_aat_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
-}
-
-void
-_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_face_data_t *data HB_UNUSED)
-{
-}
-
-
-/*
- * shaper font data
- */
-
-struct hb_coretext_aat_font_data_t {};
-
-hb_coretext_aat_font_data_t *
-_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
-{
-  return font->data.coretext ? (hb_coretext_aat_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
-}
-
-void
-_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_font_data_t *data HB_UNUSED)
-{
-}
-
-
-/*
- * shaper
- */
-
-hb_bool_t
-_hb_coretext_aat_shape (hb_shape_plan_t    *shape_plan,
-                        hb_font_t          *font,
-                        hb_buffer_t        *buffer,
-                        const hb_feature_t *features,
-                        unsigned int        num_features)
-{
-  return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
-}
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-coretext.h b/src/java.desktop/share/native/libharfbuzz/hb-coretext.h
index 4b0a6f0..55cac7e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-coretext.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-coretext.h
@@ -40,8 +40,40 @@
 HB_BEGIN_DECLS
 
 
+/**
+ * HB_CORETEXT_TAG_MORT:
+ *
+ * The #hb_tag_t tag for the `mort` (glyph metamorphosis) table,
+ * which holds AAT features.
+ *
+ * For more information, see
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
+ *
+ **/
 #define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
+
+/**
+ * HB_CORETEXT_TAG_MORX:
+ *
+ * The #hb_tag_t tag for the `morx` (extended glyph metamorphosis)
+ * table, which holds AAT features.
+ *
+ * For more information, see
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
+ *
+ **/
 #define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
+
+/**
+ * HB_CORETEXT_TAG_KERX:
+ *
+ * The #hb_tag_t tag for the `kerx` (extended kerning) table, which
+ * holds AAT kerning information.
+ *
+ * For more information, see
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
+ *
+ **/
 #define HB_CORETEXT_TAG_KERX HB_TAG('k','e','r','x')
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh
index d5ec94f..db60837 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh
@@ -29,7 +29,7 @@
 
 #include "hb.hh"
 #include "hb-atomic.hh"
-#include "hb-dsalgs.hh"
+#include "hb-algs.hh"
 
 
 #ifndef HB_DEBUG
@@ -46,7 +46,6 @@
   bool unused : 1; /* In-case sign bit is here. */
   bool initialized : 1;
   bool uniscribe_bug_compatible : 1;
-  bool aat : 1;
 };
 
 union hb_options_union_t {
@@ -63,6 +62,9 @@
 static inline hb_options_t
 hb_options ()
 {
+#ifdef HB_NO_GETENV
+  return hb_options_t ();
+#endif
   /* Make a local copy, so we can access bitfield threadsafely. */
   hb_options_union_t u;
   u.i = _hb_options.get_relaxed ();
@@ -158,7 +160,7 @@
       VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
     fprintf (stderr, "%2u %s" VRBAR "%s",
              level,
-             bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
+             bars + sizeof (bars) - 1 - hb_min ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
              level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
   } else
     fprintf (stderr, "   " VRBAR LBAR);
@@ -246,8 +248,8 @@
 };
 
 template <>
-struct hb_printer_t<hb_void_t> {
-  const char *print (hb_void_t) { return ""; }
+struct hb_printer_t<hb_empty_t> {
+  const char *print (hb_empty_t) { return ""; }
 };
 
 
@@ -263,7 +265,7 @@
   }
 }
 template <>
-/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
+/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
 {}
 
 template <int max_level, typename ret_t>
@@ -293,22 +295,23 @@
     if (plevel) --*plevel;
   }
 
-  ret_t ret (ret_t v,
-             const char *func = "",
-             unsigned int line = 0)
+  template <typename T>
+  T ret (T&& v,
+         const char *func = "",
+         unsigned int line = 0)
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
-      return v;
+      return hb_forward<T> (v);
     }
 
     _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
                               "return %s (line %d)",
-                              hb_printer_t<ret_t>().print (v), line);
+                              hb_printer_t<decltype (v)>().print (v), line);
     if (plevel) --*plevel;
     plevel = nullptr;
     returned = true;
-    return v;
+    return hb_forward<T> (v);
   }
 
   private:
@@ -327,18 +330,20 @@
                                    const char *message,
                                    ...) HB_PRINTF_FUNC(6, 7) {}
 
-  ret_t ret (ret_t v,
-             const char *func HB_UNUSED = nullptr,
-             unsigned int line HB_UNUSED = 0) { return v; }
+  template <typename T>
+  T ret (T&& v,
+         const char *func HB_UNUSED = nullptr,
+         unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
 };
 
 /* For disabled tracing; optimize out everything.
  * https://github.com/harfbuzz/harfbuzz/pull/605 */
 template <typename ret_t>
 struct hb_no_trace_t {
-  ret_t ret (ret_t v,
-             const char *func HB_UNUSED = "",
-             unsigned int line HB_UNUSED = 0) { return v; }
+  template <typename T>
+  T ret (T&& v,
+         const char *func HB_UNUSED = nullptr,
+         unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
 };
 
 #define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
@@ -368,10 +373,6 @@
 #define HB_DEBUG_FT (HB_DEBUG+0)
 #endif
 
-#ifndef HB_DEBUG_GET_COVERAGE
-#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
-#endif
-
 #ifndef HB_DEBUG_OBJECT
 #define HB_DEBUG_OBJECT (HB_DEBUG+0)
 #endif
@@ -408,7 +409,7 @@
 #define TRACE_SANITIZE(this) \
         hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-         " ");
+         " ")
 #else
 #define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
 #endif
@@ -420,7 +421,7 @@
 #define TRACE_SERIALIZE(this) \
         hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
         (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
-         " ");
+         " ")
 #else
 #define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
 #endif
@@ -432,37 +433,24 @@
 #define TRACE_SUBSET(this) \
   hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace \
   (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-   " ");
+   " ")
 #else
 #define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
 #endif
 
-#ifndef HB_DEBUG_WOULD_APPLY
-#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
-#endif
-#if HB_DEBUG_WOULD_APPLY
-#define TRACE_WOULD_APPLY(this) \
-        hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
-        (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-         "%d glyphs", c->len);
-#else
-#define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
-#endif
-
 #ifndef HB_DEBUG_DISPATCH
 #define HB_DEBUG_DISPATCH ( \
         HB_DEBUG_APPLY + \
         HB_DEBUG_SANITIZE + \
         HB_DEBUG_SERIALIZE + \
-  HB_DEBUG_SUBSET + \
-        HB_DEBUG_WOULD_APPLY + \
+        HB_DEBUG_SUBSET + \
         0)
 #endif
 #if HB_DEBUG_DISPATCH
 #define TRACE_DISPATCH(this, format) \
         hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
-         "format %d", (int) format);
+         "format %d", (int) format)
 #else
 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
 #endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h
index 9409f32..5dd0405 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h
@@ -63,7 +63,7 @@
                                                hb_codepoint_t *glyph,
                                                void *user_data);
 
-HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void
+HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
                               hb_font_get_glyph_func_t func,
                               void *user_data, hb_destroy_func_t destroy);
@@ -165,30 +165,9 @@
                                     hb_codepoint_t     *decomposed);
 
 
-typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
-                                                           hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
-                                                           void *user_data);
-typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
 typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
 
 /**
- * hb_font_funcs_set_glyph_h_kerning_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
- *
- *
- *
- * Since: 0.9.2
- * Deprecated: 2.0.0
- **/
-HB_EXTERN void
-hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
-                                        hb_font_get_glyph_h_kerning_func_t func,
-                                        void *user_data, hb_destroy_func_t destroy);
-
-/**
  * hb_font_funcs_set_glyph_v_kerning_func:
  * @ffuncs: font functions.
  * @func: (closure user_data) (destroy destroy) (scope notified):
@@ -206,19 +185,9 @@
                                         void *user_data, hb_destroy_func_t destroy);
 
 HB_EXTERN hb_position_t
-hb_font_get_glyph_h_kerning (hb_font_t *font,
-                             hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
-HB_EXTERN hb_position_t
 hb_font_get_glyph_v_kerning (hb_font_t *font,
                              hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
 
-HB_EXTERN void
-hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
-                                         hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
-                                         hb_direction_t direction,
-                                         hb_position_t *x, hb_position_t *y);
-
-
 #endif
 
 HB_END_DECLS
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-dispatch.hh b/src/java.desktop/share/native/libharfbuzz/hb-dispatch.hh
new file mode 100644
index 0000000..e946f21
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-dispatch.hh
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright © 2012,2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_DISPATCH_HH
+#define HB_DISPATCH_HH
+
+#include "hb.hh"
+
+/*
+ * Dispatch
+ */
+
+template <typename Context, typename Return=hb_empty_t, unsigned int MaxDebugDepth=0>
+struct hb_dispatch_context_t
+{
+  hb_dispatch_context_t () : debug_depth (0) {}
+  private:
+  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
+  const Context* thiz () const { return static_cast<const Context *> (this); }
+        Context* thiz ()       { return static_cast<      Context *> (this); }
+  public:
+  const char *get_name () { return "UNKNOWN"; }
+  static constexpr unsigned max_debug_depth = MaxDebugDepth;
+  typedef Return return_t;
+  template <typename T, typename F>
+  bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
+  template <typename T, typename ...Ts>
+  return_t dispatch (const T &obj, Ts&&... ds)
+  { return obj.dispatch (thiz (), hb_forward<Ts> (ds)...); }
+  static return_t no_dispatch_return_value () { return Context::default_return_value (); }
+  static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
+  unsigned debug_depth;
+};
+
+
+#endif /* HB_DISPATCH_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc
new file mode 100644
index 0000000..72444a9
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc
@@ -0,0 +1,261 @@
+/*
+ * Copyright © 2019-2020  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_DRAW
+#ifdef HB_EXPERIMENTAL_API
+
+#include "hb-draw.hh"
+#include "hb-ot.h"
+#include "hb-ot-glyf-table.hh"
+#include "hb-ot-cff1-table.hh"
+#include "hb-ot-cff2-table.hh"
+
+/**
+ * hb_draw_funcs_set_move_to_func:
+ * @funcs: draw functions object
+ * @move_to: move-to callback
+ *
+ * Sets move-to callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *funcs,
+                                hb_draw_move_to_func_t  move_to)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->move_to = move_to;
+}
+
+/**
+ * hb_draw_funcs_set_line_to_func:
+ * @funcs: draw functions object
+ * @line_to: line-to callback
+ *
+ * Sets line-to callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *funcs,
+                                hb_draw_line_to_func_t  line_to)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->line_to = line_to;
+}
+
+/**
+ * hb_draw_funcs_set_quadratic_to_func:
+ * @funcs: draw functions object
+ * @move_to: quadratic-to callback
+ *
+ * Sets quadratic-to callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *funcs,
+                                     hb_draw_quadratic_to_func_t  quadratic_to)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->quadratic_to = quadratic_to;
+  funcs->is_quadratic_to_set = true;
+}
+
+/**
+ * hb_draw_funcs_set_cubic_to_func:
+ * @funcs: draw functions
+ * @cubic_to: cubic-to callback
+ *
+ * Sets cubic-to callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *funcs,
+                                 hb_draw_cubic_to_func_t  cubic_to)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->cubic_to = cubic_to;
+}
+
+/**
+ * hb_draw_funcs_set_close_path_func:
+ * @funcs: draw functions object
+ * @close_path: close-path callback
+ *
+ * Sets close-path callback to the draw functions object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *funcs,
+                                   hb_draw_close_path_func_t  close_path)
+{
+  if (unlikely (hb_object_is_immutable (funcs))) return;
+  funcs->close_path = close_path;
+}
+
+static void
+_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
+
+static void
+_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
+
+static void
+_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
+                   hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
+                   void *user_data HB_UNUSED) {}
+
+static void
+_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
+               hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
+               hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
+               void *user_data HB_UNUSED) {}
+
+static void
+_close_path_nil (void *user_data HB_UNUSED) {}
+
+/**
+ * hb_draw_funcs_create:
+ *
+ * Creates a new draw callbacks object.
+ *
+ * Since: EXPERIMENTAL
+ **/
+hb_draw_funcs_t *
+hb_draw_funcs_create ()
+{
+  hb_draw_funcs_t *funcs;
+  if (unlikely (!(funcs = hb_object_create<hb_draw_funcs_t> ())))
+    return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
+
+  funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil;
+  funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil;
+  funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil;
+  funcs->is_quadratic_to_set = false;
+  funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil;
+  funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil;
+  return funcs;
+}
+
+/**
+ * hb_draw_funcs_reference:
+ * @funcs: draw functions
+ *
+ * Add to callbacks object refcount.
+ *
+ * Returns: The same object.
+ * Since: EXPERIMENTAL
+ **/
+hb_draw_funcs_t *
+hb_draw_funcs_reference (hb_draw_funcs_t *funcs)
+{
+  return hb_object_reference (funcs);
+}
+
+/**
+ * hb_draw_funcs_destroy:
+ * @funcs: draw functions
+ *
+ * Decreases refcount of callbacks object and deletes the object if it reaches
+ * to zero.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
+{
+  if (!hb_object_destroy (funcs)) return;
+
+  free (funcs);
+}
+
+/**
+ * hb_draw_funcs_make_immutable:
+ * @funcs: draw functions
+ *
+ * Makes funcs object immutable.
+ *
+ * Since: EXPERIMENTAL
+ **/
+void
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs)
+{
+  if (hb_object_is_immutable (funcs))
+    return;
+
+  hb_object_make_immutable (funcs);
+}
+
+/**
+ * hb_draw_funcs_is_immutable:
+ * @funcs: draw functions
+ *
+ * Checks whether funcs is immutable.
+ *
+ * Returns: If is immutable.
+ * Since: EXPERIMENTAL
+ **/
+hb_bool_t
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs)
+{
+  return hb_object_is_immutable (funcs);
+}
+
+/**
+ * hb_font_draw_glyph:
+ * @font: a font object
+ * @glyph: a glyph id
+ * @funcs: draw callbacks object
+ * @user_data: parameter you like be passed to the callbacks when are called
+ *
+ * Draw a glyph.
+ *
+ * Returns: Whether the font had the glyph and the operation completed successfully.
+ * Since: EXPERIMENTAL
+ **/
+hb_bool_t
+hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
+                    const hb_draw_funcs_t *funcs,
+                    void *user_data)
+{
+  if (unlikely (funcs == &Null (hb_draw_funcs_t) ||
+                glyph >= font->face->get_num_glyphs ()))
+    return false;
+
+  draw_helper_t draw_helper (funcs, user_data);
+  if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true;
+#ifndef HB_NO_CFF
+  if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true;
+  if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true;
+#endif
+
+  return false;
+}
+
+#endif
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.h b/src/java.desktop/share/native/libharfbuzz/hb-draw.h
new file mode 100644
index 0000000..d5eb6ec
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 2019-2020  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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_DRAW_H
+#define HB_DRAW_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+#ifdef HB_EXPERIMENTAL_API
+typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
+typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
+typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y,
+                                             hb_position_t to_x, hb_position_t to_y,
+                                             void *user_data);
+typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y,
+                                         hb_position_t control2_x, hb_position_t control2_y,
+                                         hb_position_t to_x, hb_position_t to_y,
+                                         void *user_data);
+typedef void (*hb_draw_close_path_func_t) (void *user_data);
+
+/**
+ * hb_draw_funcs_t:
+ *
+ * Glyph draw callbacks.
+ *
+ * _move_to, _line_to and _cubic_to calls are nessecary to be defined but we
+ * translate _quadratic_to calls to _cubic_to if the callback isn't defined.
+ *
+ * Since: EXPERIMENTAL
+ **/
+typedef struct hb_draw_funcs_t hb_draw_funcs_t;
+
+HB_EXTERN void
+hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *funcs,
+                                hb_draw_move_to_func_t  move_to);
+
+HB_EXTERN void
+hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *funcs,
+                                hb_draw_line_to_func_t  line_to);
+
+HB_EXTERN void
+hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *funcs,
+                                     hb_draw_quadratic_to_func_t  quadratic_to);
+
+HB_EXTERN void
+hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *funcs,
+                                 hb_draw_cubic_to_func_t  cubic_to);
+
+HB_EXTERN void
+hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *funcs,
+                                   hb_draw_close_path_func_t  close_path);
+
+HB_EXTERN hb_draw_funcs_t *
+hb_draw_funcs_create (void);
+
+HB_EXTERN hb_draw_funcs_t *
+hb_draw_funcs_reference (hb_draw_funcs_t *funcs);
+
+HB_EXTERN void
+hb_draw_funcs_destroy (hb_draw_funcs_t *funcs);
+
+HB_EXTERN void
+hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs);
+
+HB_EXTERN hb_bool_t
+hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs);
+#endif
+
+HB_END_DECLS
+
+#endif /* HB_DRAW_H */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.hh b/src/java.desktop/share/native/libharfbuzz/hb-draw.hh
new file mode 100644
index 0000000..0e5101f
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.hh
@@ -0,0 +1,139 @@
+/*
+ * Copyright © 2020  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_DRAW_HH
+#define HB_DRAW_HH
+
+#include "hb.hh"
+
+#ifdef HB_EXPERIMENTAL_API
+struct hb_draw_funcs_t
+{
+  hb_object_header_t header;
+
+  hb_draw_move_to_func_t move_to;
+  hb_draw_line_to_func_t line_to;
+  hb_draw_quadratic_to_func_t quadratic_to;
+  bool is_quadratic_to_set;
+  hb_draw_cubic_to_func_t cubic_to;
+  hb_draw_close_path_func_t close_path;
+};
+
+struct draw_helper_t
+{
+  draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_)
+  {
+    funcs = funcs_;
+    user_data = user_data_;
+    path_open = false;
+    path_start_x = current_x = path_start_y = current_y = 0;
+  }
+  ~draw_helper_t () { end_path (); }
+
+  void move_to (hb_position_t x, hb_position_t y)
+  {
+    if (path_open) end_path ();
+    current_x = path_start_x = x;
+    current_y = path_start_y = y;
+  }
+
+  void line_to (hb_position_t x, hb_position_t y)
+  {
+    if (equal_to_current (x, y)) return;
+    if (!path_open) start_path ();
+    funcs->line_to (x, y, user_data);
+    current_x = x;
+    current_y = y;
+  }
+
+  void
+  quadratic_to (hb_position_t control_x, hb_position_t control_y,
+                hb_position_t to_x, hb_position_t to_y)
+  {
+    if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y))
+      return;
+    if (!path_open) start_path ();
+    if (funcs->is_quadratic_to_set)
+      funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data);
+    else
+      funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f),
+                       roundf ((current_y + 2.f * control_y) / 3.f),
+                       roundf ((to_x + 2.f * control_x) / 3.f),
+                       roundf ((to_y + 2.f * control_y) / 3.f),
+                       to_x, to_y, user_data);
+    current_x = to_x;
+    current_y = to_y;
+  }
+
+  void
+  cubic_to (hb_position_t control1_x, hb_position_t control1_y,
+            hb_position_t control2_x, hb_position_t control2_y,
+            hb_position_t to_x, hb_position_t to_y)
+  {
+    if (equal_to_current (control1_x, control1_y) &&
+        equal_to_current (control2_x, control2_y) &&
+        equal_to_current (to_x, to_y))
+      return;
+    if (!path_open) start_path ();
+    funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data);
+    current_x = to_x;
+    current_y = to_y;
+  }
+
+  void end_path ()
+  {
+    if (path_open)
+    {
+      if ((path_start_x != current_x) || (path_start_y != current_y))
+        funcs->line_to (path_start_x, path_start_y, user_data);
+      funcs->close_path (user_data);
+    }
+    path_open = false;
+    path_start_x = current_x = path_start_y = current_y = 0;
+  }
+
+  protected:
+  bool equal_to_current (hb_position_t x, hb_position_t y)
+  { return current_x == x && current_y == y; }
+
+  void start_path ()
+  {
+    if (path_open) end_path ();
+    path_open = true;
+    funcs->move_to (path_start_x, path_start_y, user_data);
+  }
+
+  hb_position_t path_start_x;
+  hb_position_t path_start_y;
+
+  hb_position_t current_x;
+  hb_position_t current_y;
+
+  bool path_open;
+  const hb_draw_funcs_t *funcs;
+  void *user_data;
+};
+#endif
+
+#endif /* HB_DRAW_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-dsalgs.hh b/src/java.desktop/share/native/libharfbuzz/hb-dsalgs.hh
deleted file mode 100644
index f5f2868..0000000
--- a/src/java.desktop/share/native/libharfbuzz/hb-dsalgs.hh
+++ /dev/null
@@ -1,632 +0,0 @@
-/*
- * Copyright © 2017  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_DSALGS_HH
-#define HB_DSALGS_HH
-
-#include "hb.hh"
-#include "hb-null.hh"
-
-
-/* Void! For when we need a expression-type of void. */
-typedef const struct _hb_void_t *hb_void_t;
-#define HB_VOID ((const _hb_void_t *) nullptr)
-
-
-/*
- * Bithacks.
- */
-
-/* Return the number of 1 bits in v. */
-template <typename T>
-static inline HB_CONST_FUNC unsigned int
-hb_popcount (T v)
-{
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
-  if (sizeof (T) <= sizeof (unsigned int))
-    return __builtin_popcount (v);
-
-  if (sizeof (T) <= sizeof (unsigned long))
-    return __builtin_popcountl (v);
-
-  if (sizeof (T) <= sizeof (unsigned long long))
-    return __builtin_popcountll (v);
-#endif
-
-  if (sizeof (T) <= 4)
-  {
-    /* "HACKMEM 169" */
-    uint32_t y;
-    y = (v >> 1) &033333333333;
-    y = v - y - ((y >>1) & 033333333333);
-    return (((y + (y >> 3)) & 030707070707) % 077);
-  }
-
-  if (sizeof (T) == 8)
-  {
-    unsigned int shift = 32;
-    return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
-  }
-
-  if (sizeof (T) == 16)
-  {
-    unsigned int shift = 64;
-    return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
-  }
-
-  assert (0);
-  return 0; /* Shut up stupid compiler. */
-}
-
-/* Returns the number of bits needed to store number */
-template <typename T>
-static inline HB_CONST_FUNC unsigned int
-hb_bit_storage (T v)
-{
-  if (unlikely (!v)) return 0;
-
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
-  if (sizeof (T) <= sizeof (unsigned int))
-    return sizeof (unsigned int) * 8 - __builtin_clz (v);
-
-  if (sizeof (T) <= sizeof (unsigned long))
-    return sizeof (unsigned long) * 8 - __builtin_clzl (v);
-
-  if (sizeof (T) <= sizeof (unsigned long long))
-    return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
-#endif
-
-#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
-  if (sizeof (T) <= sizeof (unsigned int))
-  {
-    unsigned long where;
-    _BitScanReverse (&where, v);
-    return 1 + where;
-  }
-# if defined(_WIN64)
-  if (sizeof (T) <= 8)
-  {
-    unsigned long where;
-    _BitScanReverse64 (&where, v);
-    return 1 + where;
-  }
-# endif
-#endif
-
-  if (sizeof (T) <= 4)
-  {
-    /* "bithacks" */
-    const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
-    const unsigned int S[] = {1, 2, 4, 8, 16};
-    unsigned int r = 0;
-    for (int i = 4; i >= 0; i--)
-      if (v & b[i])
-      {
-        v >>= S[i];
-        r |= S[i];
-      }
-    return r + 1;
-  }
-  if (sizeof (T) <= 8)
-  {
-    /* "bithacks" */
-    const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
-    const unsigned int S[] = {1, 2, 4, 8, 16, 32};
-    unsigned int r = 0;
-    for (int i = 5; i >= 0; i--)
-      if (v & b[i])
-      {
-        v >>= S[i];
-        r |= S[i];
-      }
-    return r + 1;
-  }
-  if (sizeof (T) == 16)
-  {
-    unsigned int shift = 64;
-    return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
-                          hb_bit_storage<uint64_t> ((uint64_t) v);
-  }
-
-  assert (0);
-  return 0; /* Shut up stupid compiler. */
-}
-
-/* Returns the number of zero bits in the least significant side of v */
-template <typename T>
-static inline HB_CONST_FUNC unsigned int
-hb_ctz (T v)
-{
-  if (unlikely (!v)) return 0;
-
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
-  if (sizeof (T) <= sizeof (unsigned int))
-    return __builtin_ctz (v);
-
-  if (sizeof (T) <= sizeof (unsigned long))
-    return __builtin_ctzl (v);
-
-  if (sizeof (T) <= sizeof (unsigned long long))
-    return __builtin_ctzll (v);
-#endif
-
-#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
-  if (sizeof (T) <= sizeof (unsigned int))
-  {
-    unsigned long where;
-    _BitScanForward (&where, v);
-    return where;
-  }
-# if defined(_WIN64)
-  if (sizeof (T) <= 8)
-  {
-    unsigned long where;
-    _BitScanForward64 (&where, v);
-    return where;
-  }
-# endif
-#endif
-
-  if (sizeof (T) <= 4)
-  {
-    /* "bithacks" */
-    unsigned int c = 32;
-    v &= - (int32_t) v;
-    if (v) c--;
-    if (v & 0x0000FFFF) c -= 16;
-    if (v & 0x00FF00FF) c -= 8;
-    if (v & 0x0F0F0F0F) c -= 4;
-    if (v & 0x33333333) c -= 2;
-    if (v & 0x55555555) c -= 1;
-    return c;
-  }
-  if (sizeof (T) <= 8)
-  {
-    /* "bithacks" */
-    unsigned int c = 64;
-    v &= - (int64_t) (v);
-    if (v) c--;
-    if (v & 0x00000000FFFFFFFFULL) c -= 32;
-    if (v & 0x0000FFFF0000FFFFULL) c -= 16;
-    if (v & 0x00FF00FF00FF00FFULL) c -= 8;
-    if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
-    if (v & 0x3333333333333333ULL) c -= 2;
-    if (v & 0x5555555555555555ULL) c -= 1;
-    return c;
-  }
-  if (sizeof (T) == 16)
-  {
-    unsigned int shift = 64;
-    return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
-                          hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
-  }
-
-  assert (0);
-  return 0; /* Shut up stupid compiler. */
-}
-
-
-/*
- * Tiny stuff.
- */
-
-template <typename T>
-static inline T* hb_addressof (T& arg)
-{
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-  /* https://en.cppreference.com/w/cpp/memory/addressof */
-  return reinterpret_cast<T*>(
-           &const_cast<char&>(
-              reinterpret_cast<const volatile char&>(arg)));
-#pragma GCC diagnostic pop
-}
-
-/* ASCII tag/character handling */
-static inline bool ISALPHA (unsigned char c)
-{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
-static inline bool ISALNUM (unsigned char c)
-{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
-static inline bool ISSPACE (unsigned char c)
-{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
-static inline unsigned char TOUPPER (unsigned char c)
-{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
-static inline unsigned char TOLOWER (unsigned char c)
-{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
-
-#undef MIN
-template <typename Type>
-static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
-
-#undef MAX
-template <typename Type>
-static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
-
-static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
-{ return (a + (b - 1)) / b; }
-
-
-#undef  ARRAY_LENGTH
-template <typename Type, unsigned int n>
-static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
-/* A const version, but does not detect erratically being called on pointers. */
-#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
-
-
-static inline int
-hb_memcmp (const void *a, const void *b, unsigned int len)
-{
-  /* It's illegal to pass NULL to memcmp(), even if len is zero.
-   * So, wrap it.
-   * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
-  if (!len) return 0;
-  return memcmp (a, b, len);
-}
-
-static inline bool
-hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
-{
-  return (size > 0) && (count >= ((unsigned int) -1) / size);
-}
-
-static inline unsigned int
-hb_ceil_to_4 (unsigned int v)
-{
-  return ((v - 1) | 3) + 1;
-}
-
-template <typename T> struct hb_is_signed;
-/* https://github.com/harfbuzz/harfbuzz/issues/1535 */
-template <> struct hb_is_signed<int8_t> { enum { value = true }; };
-template <> struct hb_is_signed<int16_t> { enum { value = true }; };
-template <> struct hb_is_signed<int32_t> { enum { value = true }; };
-template <> struct hb_is_signed<int64_t> { enum { value = true }; };
-template <> struct hb_is_signed<uint8_t> { enum { value = false }; };
-template <> struct hb_is_signed<uint16_t> { enum { value = false }; };
-template <> struct hb_is_signed<uint32_t> { enum { value = false }; };
-template <> struct hb_is_signed<uint64_t> { enum { value = false }; };
-
-template <typename T> static inline bool
-hb_in_range (T u, T lo, T hi)
-{
-  /* The sizeof() is here to force template instantiation.
-   * I'm sure there are better ways to do this but can't think of
-   * one right now.  Declaring a variable won't work as HB_UNUSED
-   * is unusable on some platforms and unused types are less likely
-   * to generate a warning than unused variables. */
-  static_assert (!hb_is_signed<T>::value, "");
-
-  /* The casts below are important as if T is smaller than int,
-   * the subtract results will become a signed int! */
-  return (T)(u - lo) <= (T)(hi - lo);
-}
-template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
-{
-  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
-}
-template <typename T> static inline bool
-hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
-{
-  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
-}
-
-
-/*
- * Sort and search.
- */
-
-static inline void *
-hb_bsearch (const void *key, const void *base,
-            size_t nmemb, size_t size,
-            int (*compar)(const void *_key, const void *_item))
-{
-  int min = 0, max = (int) nmemb - 1;
-  while (min <= max)
-  {
-    int mid = (min + max) / 2;
-    const void *p = (const void *) (((const char *) base) + (mid * size));
-    int c = compar (key, p);
-    if (c < 0)
-      max = mid - 1;
-    else if (c > 0)
-      min = mid + 1;
-    else
-      return (void *) p;
-  }
-  return nullptr;
-}
-
-static inline void *
-hb_bsearch_r (const void *key, const void *base,
-              size_t nmemb, size_t size,
-              int (*compar)(const void *_key, const void *_item, void *_arg),
-              void *arg)
-{
-  int min = 0, max = (int) nmemb - 1;
-  while (min <= max)
-  {
-    int mid = ((unsigned int) min + (unsigned int) max) / 2;
-    const void *p = (const void *) (((const char *) base) + (mid * size));
-    int c = compar (key, p, arg);
-    if (c < 0)
-      max = mid - 1;
-    else if (c > 0)
-      min = mid + 1;
-    else
-      return (void *) p;
-  }
-  return nullptr;
-}
-
-
-/* From https://github.com/noporpoise/sort_r
- * With following modifications:
- *
- * 10 November 2018:
- * https://github.com/noporpoise/sort_r/issues/7
- */
-
-/* Isaac Turner 29 April 2014 Public Domain */
-
-/*
-
-hb_sort_r function to be exported.
-
-Parameters:
-  base is the array to be sorted
-  nel is the number of elements in the array
-  width is the size in bytes of each element of the array
-  compar is the comparison function
-  arg is a pointer to be passed to the comparison function
-
-void hb_sort_r(void *base, size_t nel, size_t width,
-               int (*compar)(const void *_a, const void *_b, void *_arg),
-               void *arg);
-*/
-
-
-/* swap a, b iff a>b */
-/* __restrict is same as restrict but better support on old machines */
-static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w,
-                          int (*compar)(const void *_a, const void *_b,
-                                        void *_arg),
-                          void *arg)
-{
-  char tmp, *end = a+w;
-  if(compar(a, b, arg) > 0) {
-    for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
-    return 1;
-  }
-  return 0;
-}
-
-/* Note: quicksort is not stable, equivalent values may be swapped */
-static inline void sort_r_simple(void *base, size_t nel, size_t w,
-                                 int (*compar)(const void *_a, const void *_b,
-                                               void *_arg),
-                                 void *arg)
-{
-  char *b = (char *)base, *end = b + nel*w;
-  if(nel < 7) {
-    /* Insertion sort for arbitrarily small inputs */
-    char *pi, *pj;
-    for(pi = b+w; pi < end; pi += w) {
-      for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {}
-    }
-  }
-  else
-  {
-    /* nel > 6; Quicksort */
-
-    /* Use median of first, middle and last items as pivot */
-    char *x, *y, *xend, ch;
-    char *pl, *pm, *pr;
-    char *last = b+w*(nel-1), *tmp;
-    char *l[3];
-    l[0] = b;
-    l[1] = b+w*(nel/2);
-    l[2] = last;
-
-    if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
-    if(compar(l[1],l[2],arg) > 0) {
-      tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */
-      if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
-    }
-
-    /* swap l[id], l[2] to put pivot as last element */
-    for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
-      ch = *x; *x = *y; *y = ch;
-    }
-
-    pl = b;
-    pr = last;
-
-    while(pl < pr) {
-      pm = pl+((pr-pl+1)>>1);
-      for(; pl < pm; pl += w) {
-        if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
-          pr -= w; /* pivot now at pl */
-          break;
-        }
-      }
-      pm = pl+((pr-pl)>>1);
-      for(; pm < pr; pr -= w) {
-        if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
-          pl += w; /* pivot now at pr */
-          break;
-        }
-      }
-    }
-
-    sort_r_simple(b, (pl-b)/w, w, compar, arg);
-    sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg);
-  }
-}
-
-static inline void hb_sort_r(void *base, size_t nel, size_t width,
-                             int (*compar)(const void *_a, const void *_b, void *_arg),
-                             void *arg)
-{
-    sort_r_simple(base, nel, width, compar, arg);
-}
-
-
-template <typename T, typename T2> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
-{
-  for (unsigned int i = 1; i < len; i++)
-  {
-    unsigned int j = i;
-    while (j && compar (&array[j - 1], &array[i]) > 0)
-      j--;
-    if (i == j)
-      continue;
-    /* Move item i to occupy place for item j, shift what's in between. */
-    {
-      T t = array[i];
-      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
-      array[j] = t;
-    }
-    if (array2)
-    {
-      T2 t = array2[i];
-      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
-      array2[j] = t;
-    }
-  }
-}
-
-template <typename T> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
-{
-  hb_stable_sort (array, len, compar, (int *) nullptr);
-}
-
-static inline hb_bool_t
-hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
-{
-  /* Pain because we don't know whether s is nul-terminated. */
-  char buf[64];
-  len = MIN (ARRAY_LENGTH (buf) - 1, len);
-  strncpy (buf, s, len);
-  buf[len] = '\0';
-
-  char *end;
-  errno = 0;
-  unsigned long v = strtoul (buf, &end, base);
-  if (errno) return false;
-  if (*end) return false;
-  *out = v;
-  return true;
-}
-
-
-struct HbOpOr
-{
-  static constexpr bool passthru_left = true;
-  static constexpr bool passthru_right = true;
-  template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
-};
-struct HbOpAnd
-{
-  static constexpr bool passthru_left = false;
-  static constexpr bool passthru_right = false;
-  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
-};
-struct HbOpMinus
-{
-  static constexpr bool passthru_left = true;
-  static constexpr bool passthru_right = false;
-  template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
-};
-struct HbOpXor
-{
-  static constexpr bool passthru_left = true;
-  static constexpr bool passthru_right = true;
-  template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
-};
-
-
-/* Compiler-assisted vectorization. */
-
-/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
- * using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128).
- * Define that to 0 to disable. */
-template <typename elt_t, unsigned int byte_size>
-struct hb_vector_size_t
-{
-  elt_t& operator [] (unsigned int i) { return u.v[i]; }
-  const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
-
-  void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
-
-  template <class Op>
-  hb_vector_size_t process (const hb_vector_size_t &o) const
-  {
-    hb_vector_size_t r;
-#if HB_VECTOR_SIZE
-    if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
-      for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
-        Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
-    else
-#endif
-      for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
-        Op::process (r.u.v[i], u.v[i], o.u.v[i]);
-    return r;
-  }
-  hb_vector_size_t operator | (const hb_vector_size_t &o) const
-  { return process<HbOpOr> (o); }
-  hb_vector_size_t operator & (const hb_vector_size_t &o) const
-  { return process<HbOpAnd> (o); }
-  hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
-  { return process<HbOpXor> (o); }
-  hb_vector_size_t operator ~ () const
-  {
-    hb_vector_size_t r;
-#if HB_VECTOR_SIZE && 0
-    if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
-      for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
-        r.u.vec[i] = ~u.vec[i];
-    else
-#endif
-    for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
-      r.u.v[i] = ~u.v[i];
-    return r;
-  }
-
-  private:
-  static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
-  union {
-    elt_t v[byte_size / sizeof (elt_t)];
-#if HB_VECTOR_SIZE
-    hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)];
-#endif
-  } u;
-};
-
-
-#endif /* HB_DSALGS_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.cc b/src/java.desktop/share/native/libharfbuzz/hb-face.cc
index e3dc469..6d96dcc 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-face.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-face.cc
@@ -200,10 +200,15 @@
   if (unlikely (!blob))
     blob = hb_blob_get_empty ();
 
-  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)), index);
+  blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
+
+  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index);
 
   if (unlikely (!closure))
+  {
+    hb_blob_destroy (blob);
     return hb_face_get_empty ();
+  }
 
   face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
                                     closure,
@@ -226,7 +231,7 @@
 hb_face_t *
 hb_face_get_empty ()
 {
-  return const_cast<hb_face_t *> (&Null(hb_face_t));
+  return const_cast<hb_face_t *> (&Null (hb_face_t));
 }
 
 
@@ -367,6 +372,9 @@
 hb_face_reference_table (const hb_face_t *face,
                          hb_tag_t tag)
 {
+  if (unlikely (tag == HB_TAG_NONE))
+    return hb_blob_get_empty ();
+
   return face->reference_table (tag);
 }
 
@@ -531,6 +539,7 @@
  */
 
 
+#ifndef HB_NO_FACE_COLLECT_UNICODES
 /**
  * hb_face_collect_unicodes:
  * @face: font face.
@@ -542,9 +551,8 @@
 hb_face_collect_unicodes (hb_face_t *face,
                           hb_set_t  *out)
 {
-  face->table.cmap->collect_unicodes (out);
+  face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
 }
-
 /**
  * hb_face_collect_variation_selectors:
  * @face: font face.
@@ -560,7 +568,6 @@
 {
   face->table.cmap->collect_variation_selectors (out);
 }
-
 /**
  * hb_face_collect_variation_unicodes:
  * @face: font face.
@@ -577,7 +584,7 @@
 {
   face->table.cmap->collect_variation_unicodes (variation_selector, out);
 }
-
+#endif
 
 
 /*
@@ -714,7 +721,10 @@
     return false;
 
   hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
+
   hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
+  if (data->tables.in_error())
+    return false;
 
   entry->tag = tag;
   entry->blob = hb_blob_reference (blob);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.hh b/src/java.desktop/share/native/libharfbuzz/hb-face.hh
index b2730eb..010eaba 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-face.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-face.hh
@@ -94,7 +94,7 @@
   unsigned int get_num_glyphs () const
   {
     unsigned int ret = num_glyphs.get_relaxed ();
-    if (unlikely (ret == (unsigned int) -1))
+    if (unlikely (ret == UINT_MAX))
       return load_num_glyphs ();
     return ret;
   }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc
index df30871..d1d26b6 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc
@@ -26,6 +26,7 @@
 
 #include "hb-shaper-impl.hh"
 
+#ifndef HB_NO_FALLBACK_SHAPE
 
 /*
  * shaper face data
@@ -120,3 +121,5 @@
 
   return true;
 }
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-font.cc
index 855c998..42bf3e9 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-font.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-font.cc
@@ -33,6 +33,9 @@
 
 #include "hb-ot.h"
 
+#include "hb-ot-var-avar-table.hh"
+#include "hb-ot-var-fvar-table.hh"
+
 
 /**
  * SECTION:hb-font
@@ -355,6 +358,7 @@
   return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 static hb_position_t
 hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
                                  void *font_data HB_UNUSED,
@@ -373,6 +377,7 @@
 {
   return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
 }
+#endif
 
 static hb_bool_t
 hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
@@ -672,7 +677,8 @@
                                  void                        *user_data, \
                                  hb_destroy_func_t            destroy)   \
 {                                                                        \
-  if (hb_object_is_immutable (ffuncs)) {                                 \
+  if (hb_object_is_immutable (ffuncs))                                   \
+  {                                                                      \
     if (destroy)                                                         \
       destroy (user_data);                                               \
     return;                                                              \
@@ -790,6 +796,29 @@
 }
 
 /**
+ * hb_font_get_nominal_glyphs:
+ * @font: a font.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 2.6.3
+ **/
+unsigned int
+hb_font_get_nominal_glyphs (hb_font_t *font,
+                            unsigned int count,
+                            const hb_codepoint_t *first_unicode,
+                            unsigned int unicode_stride,
+                            hb_codepoint_t *first_glyph,
+                            unsigned int glyph_stride)
+{
+  return font->get_nominal_glyphs (count,
+                                   first_unicode, unicode_stride,
+                                   first_glyph, glyph_stride);
+}
+
+/**
  * hb_font_get_variation_glyph:
  * @font: a font.
  * @unicode:
@@ -936,7 +965,6 @@
  * Return value:
  *
  * Since: 0.9.2
- * Deprecated: 2.0.0
  **/
 hb_position_t
 hb_font_get_glyph_h_kerning (hb_font_t *font,
@@ -945,6 +973,7 @@
   return font->get_glyph_h_kerning (left_glyph, right_glyph);
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_font_get_glyph_v_kerning:
  * @font: a font.
@@ -964,6 +993,7 @@
 {
   return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
 }
+#endif
 
 /**
  * hb_font_get_glyph_extents:
@@ -1185,7 +1215,6 @@
  *
  *
  * Since: 0.9.2
- * Deprecated: 2.0.0
  **/
 void
 hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
@@ -1298,6 +1327,8 @@
 
   1000, /* x_scale */
   1000, /* y_scale */
+  1<<16, /* x_mult */
+  1<<16, /* y_mult */
 
   0, /* x_ppem */
   0, /* y_ppem */
@@ -1305,6 +1336,7 @@
 
   0, /* num_coords */
   nullptr, /* coords */
+  nullptr, /* design_coords */
 
   const_cast<hb_font_funcs_t *> (&_hb_Null_hb_font_funcs_t),
 
@@ -1328,6 +1360,7 @@
   font->klass = hb_font_funcs_get_empty ();
   font->data.init0 (font);
   font->x_scale = font->y_scale = hb_face_get_upem (face);
+  font->x_mult = font->y_mult = 1 << 16;
 
   return font;
 }
@@ -1347,12 +1380,28 @@
 {
   hb_font_t *font = _hb_font_create (face);
 
+#ifndef HB_NO_OT_FONT
   /* Install our in-house, very lightweight, funcs. */
   hb_ot_font_set_funcs (font);
+#endif
 
   return font;
 }
 
+static void
+_hb_font_adopt_var_coords (hb_font_t *font,
+                           int *coords, /* 2.14 normalized */
+                           float *design_coords,
+                           unsigned int coords_length)
+{
+  free (font->coords);
+  free (font->design_coords);
+
+  font->coords = coords;
+  font->design_coords = design_coords;
+  font->num_coords = coords_length;
+}
+
 /**
  * hb_font_create_sub_font:
  * @parent: parent font.
@@ -1378,21 +1427,27 @@
 
   font->x_scale = parent->x_scale;
   font->y_scale = parent->y_scale;
+  font->mults_changed ();
   font->x_ppem = parent->x_ppem;
   font->y_ppem = parent->y_ppem;
   font->ptem = parent->ptem;
 
-  font->num_coords = parent->num_coords;
-  if (!font->num_coords)
-    font->coords = nullptr;
-  else
+  unsigned int num_coords = parent->num_coords;
+  if (num_coords)
   {
-    unsigned int size = parent->num_coords * sizeof (parent->coords[0]);
-    font->coords = (int *) malloc (size);
-    if (unlikely (!font->coords))
-      font->num_coords = 0;
+    int *coords = (int *) calloc (num_coords, sizeof (parent->coords[0]));
+    float *design_coords = (float *) calloc (num_coords, sizeof (parent->design_coords[0]));
+    if (likely (coords && design_coords))
+    {
+      memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
+      memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0]));
+      _hb_font_adopt_var_coords (font, coords, design_coords, num_coords);
+    }
     else
-      memcpy (font->coords, parent->coords, size);
+    {
+      free (coords);
+      free (design_coords);
+    }
   }
 
   return font;
@@ -1410,7 +1465,7 @@
 hb_font_t *
 hb_font_get_empty ()
 {
-  return const_cast<hb_font_t *> (&Null(hb_font_t));
+  return const_cast<hb_font_t *> (&Null (hb_font_t));
 }
 
 /**
@@ -1452,6 +1507,7 @@
   hb_font_funcs_destroy (font->klass);
 
   free (font->coords);
+  free (font->design_coords);
 
   free (font);
 }
@@ -1597,7 +1653,9 @@
 
   hb_face_t *old = font->face;
 
+  hb_face_make_immutable (face);
   font->face = hb_face_reference (face);
+  font->mults_changed ();
 
   hb_face_destroy (old);
 }
@@ -1707,6 +1765,7 @@
 
   font->x_scale = x_scale;
   font->y_scale = y_scale;
+  font->mults_changed ();
 }
 
 /**
@@ -1805,21 +1864,11 @@
   return font->ptem;
 }
 
+#ifndef HB_NO_VAR
 /*
  * Variations
  */
 
-static void
-_hb_font_adopt_var_coords_normalized (hb_font_t *font,
-                                      int *coords, /* 2.14 normalized */
-                                      unsigned int coords_length)
-{
-  free (font->coords);
-
-  font->coords = coords;
-  font->num_coords = coords_length;
-}
-
 /**
  * hb_font_set_variations:
  *
@@ -1842,13 +1891,30 @@
   unsigned int coords_length = hb_ot_var_get_axis_count (font->face);
 
   int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
-  if (unlikely (coords_length && !normalized))
-    return;
+  float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
 
-  hb_ot_var_normalize_variations (font->face,
-                                  variations, variations_length,
-                                  normalized, coords_length);
-  _hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
+  if (unlikely (coords_length && !(normalized && design_coords)))
+  {
+    free (normalized);
+    free (design_coords);
+    return;
+  }
+
+  const OT::fvar &fvar = *font->face->table.fvar;
+  for (unsigned int i = 0; i < variations_length; i++)
+  {
+    hb_ot_var_axis_info_t info;
+    if (hb_ot_var_find_axis_info (font->face, variations[i].tag, &info) &&
+        info.axis_index < coords_length)
+    {
+      float v = variations[i].value;
+      design_coords[info.axis_index] = v;
+      normalized[info.axis_index] = fvar.normalize_axis_value (info.axis_index, v);
+    }
+  }
+  font->face->table.avar->map_coords (normalized, coords_length);
+
+  _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
 }
 
 /**
@@ -1865,11 +1931,47 @@
     return;
 
   int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
-  if (unlikely (coords_length && !normalized))
+  float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
+
+  if (unlikely (coords_length && !(normalized && design_coords)))
+  {
+    free (normalized);
+    free (design_coords);
     return;
+  }
+
+  if (coords_length)
+    memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0]));
 
   hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
-  _hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
+  _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
+}
+
+/**
+ * hb_font_set_var_named_instance:
+ * @font: a font.
+ * @instance_index: named instance index.
+ *
+ * Sets design coords of a font from a named instance index.
+ *
+ * Since: 2.6.0
+ */
+void
+hb_font_set_var_named_instance (hb_font_t *font,
+                                unsigned instance_index)
+{
+  if (hb_object_is_immutable (font))
+    return;
+
+  unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr);
+
+  float *coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
+  if (unlikely (coords_length && !coords))
+    return;
+
+  hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords);
+  hb_font_set_var_coords_design (font, coords, coords_length);
+  free (coords);
 }
 
 /**
@@ -1886,13 +1988,30 @@
     return;
 
   int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
-  if (unlikely (coords_length && !copy))
+  int *unmapped = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
+  float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (design_coords[0])) : nullptr;
+
+  if (unlikely (coords_length && !(copy && unmapped && design_coords)))
+  {
+    free (copy);
+    free (unmapped);
+    free (design_coords);
     return;
+  }
 
   if (coords_length)
+  {
     memcpy (copy, coords, coords_length * sizeof (coords[0]));
+    memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
+  }
 
-  _hb_font_adopt_var_coords_normalized (font, copy, coords_length);
+  /* Best effort design coords simulation */
+  font->face->table.avar->unmap_coords (unmapped, coords_length);
+  for (unsigned int i = 0; i < coords_length; ++i)
+    design_coords[i] = font->face->table.fvar->unnormalize_axis_value (i, unmapped[i]);
+  free (unmapped);
+
+  _hb_font_adopt_var_coords (font, copy, design_coords, coords_length);
 }
 
 /**
@@ -1913,7 +2032,28 @@
   return font->coords;
 }
 
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_font_get_var_coords_design:
+ *
+ * Return value is valid as long as variation coordinates of the font
+ * are not modified.
+ *
+ * Since: EXPERIMENTAL
+ */
+const float *
+hb_font_get_var_coords_design (hb_font_t *font,
+                               unsigned int *length)
+{
+  if (length)
+    *length = font->num_coords;
 
+  return font->design_coords;
+}
+#endif
+#endif
+
+#ifndef HB_DISABLE_DEPRECATED
 /*
  * Deprecated get_glyph_func():
  */
@@ -2015,6 +2155,13 @@
                               hb_font_get_glyph_func_t func,
                               void *user_data, hb_destroy_func_t destroy)
 {
+  if (hb_object_is_immutable (ffuncs))
+  {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
+
   hb_font_get_glyph_trampoline_t *trampoline;
 
   trampoline = trampoline_create (func, user_data, destroy);
@@ -2036,3 +2183,4 @@
                                           trampoline,
                                           trampoline_destroy);
 }
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.h b/src/java.desktop/share/native/libharfbuzz/hb-font.h
index 85893f9..217bf33 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-font.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-font.h
@@ -33,6 +33,7 @@
 
 #include "hb-common.h"
 #include "hb-face.h"
+#include "hb-draw.h"
 
 HB_BEGIN_DECLS
 
@@ -157,6 +158,11 @@
 typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
 typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
 
+typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
+                                                           hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+                                                           void *user_data);
+typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
+
 
 typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
                                                        hb_codepoint_t glyph,
@@ -357,6 +363,22 @@
                                        void *user_data, hb_destroy_func_t destroy);
 
 /**
+ * hb_font_funcs_set_glyph_h_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
+                                        hb_font_get_glyph_h_kerning_func_t func,
+                                        void *user_data, hb_destroy_func_t destroy);
+
+/**
  * hb_font_funcs_set_glyph_extents_func:
  * @ffuncs: font functions.
  * @func: (closure user_data) (destroy destroy) (scope notified):
@@ -438,6 +460,14 @@
                              hb_codepoint_t unicode, hb_codepoint_t variation_selector,
                              hb_codepoint_t *glyph);
 
+HB_EXTERN unsigned int
+hb_font_get_nominal_glyphs (hb_font_t *font,
+                            unsigned int count,
+                            const hb_codepoint_t *first_unicode,
+                            unsigned int unicode_stride,
+                            hb_codepoint_t *first_glyph,
+                            unsigned int glyph_stride);
+
 HB_EXTERN hb_position_t
 hb_font_get_glyph_h_advance (hb_font_t *font,
                              hb_codepoint_t glyph);
@@ -469,6 +499,10 @@
                             hb_codepoint_t glyph,
                             hb_position_t *x, hb_position_t *y);
 
+HB_EXTERN hb_position_t
+hb_font_get_glyph_h_kerning (hb_font_t *font,
+                             hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
+
 HB_EXTERN hb_bool_t
 hb_font_get_glyph_extents (hb_font_t *font,
                            hb_codepoint_t glyph,
@@ -531,6 +565,12 @@
                                              hb_direction_t direction,
                                              hb_position_t *x, hb_position_t *y);
 
+HB_EXTERN void
+hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
+                                         hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+                                         hb_direction_t direction,
+                                         hb_position_t *x, hb_position_t *y);
+
 HB_EXTERN hb_bool_t
 hb_font_get_glyph_extents_for_origin (hb_font_t *font,
                                       hb_codepoint_t glyph,
@@ -665,6 +705,12 @@
                                const float *coords,
                                unsigned int coords_length);
 
+#ifdef HB_EXPERIMENTAL_API
+HB_EXTERN const float *
+hb_font_get_var_coords_design (hb_font_t *font,
+                               unsigned int *length);
+#endif
+
 HB_EXTERN void
 hb_font_set_var_coords_normalized (hb_font_t *font,
                                    const int *coords, /* 2.14 normalized */
@@ -674,6 +720,16 @@
 hb_font_get_var_coords_normalized (hb_font_t *font,
                                    unsigned int *length);
 
+HB_EXTERN void
+hb_font_set_var_named_instance (hb_font_t *font,
+                                unsigned instance_index);
+
+#ifdef HB_EXPERIMENTAL_API
+HB_EXTERN hb_bool_t
+hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
+                    const hb_draw_funcs_t *funcs, void *user_data);
+#endif
+
 HB_END_DECLS
 
 #endif /* HB_FONT_H */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.hh b/src/java.desktop/share/native/libharfbuzz/hb-font.hh
index dd33d2f..2fa9cea 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-font.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-font.hh
@@ -52,7 +52,7 @@
   HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
   HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
   HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
-  HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
+  HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \
   HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
   HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
   HB_FONT_FUNC_IMPLEMENT (glyph_name) \
@@ -107,8 +107,10 @@
   hb_font_t *parent;
   hb_face_t *face;
 
-  int x_scale;
-  int y_scale;
+  int32_t x_scale;
+  int32_t y_scale;
+  int64_t x_mult;
+  int64_t y_mult;
 
   unsigned int x_ppem;
   unsigned int y_ppem;
@@ -118,6 +120,7 @@
   /* Font variation coordinates. */
   unsigned int num_coords;
   int *coords;
+  float *design_coords;
 
   hb_font_funcs_t   *klass;
   void              *user_data;
@@ -127,16 +130,16 @@
 
 
   /* Convert from font-space to user-space */
-  int dir_scale (hb_direction_t direction)
-  { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
-  hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
-  hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
-  hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
-  hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
+  int64_t dir_mult (hb_direction_t direction)
+  { return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
+  hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
+  hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
+  hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
+  hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
   float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
   float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
   hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
-  { return em_scale (v, dir_scale (direction)); }
+  { return em_mult (v, dir_mult (direction)); }
 
   /* Convert from parent-font user-space to our user-space */
   hb_position_t parent_scale_x_distance (hb_position_t v)
@@ -214,7 +217,7 @@
   }
 
   hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
-                                      hb_codepoint_t *glyph)
+                               hb_codepoint_t *glyph)
   {
     *glyph = 0;
     return klass->get.f.nominal_glyph (this, user_data,
@@ -284,7 +287,7 @@
   }
 
   hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
-                                       hb_position_t *x, hb_position_t *y)
+                                hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
     return klass->get.f.glyph_h_origin (this, user_data,
@@ -304,21 +307,29 @@
   hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
                                      hb_codepoint_t right_glyph)
   {
+#ifdef HB_DISABLE_DEPRECATED
+    return 0;
+#else
     return klass->get.f.glyph_h_kerning (this, user_data,
                                          left_glyph, right_glyph,
                                          klass->user_data.glyph_h_kerning);
+#endif
   }
 
   hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
                                      hb_codepoint_t bottom_glyph)
   {
+#ifdef HB_DISABLE_DEPRECATED
+    return 0;
+#else
     return klass->get.f.glyph_v_kerning (this, user_data,
                                          top_glyph, bottom_glyph,
                                          klass->user_data.glyph_v_kerning);
+#endif
   }
 
   hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
-                                      hb_glyph_extents_t *extents)
+                               hb_glyph_extents_t *extents)
   {
     memset (extents, 0, sizeof (*extents));
     return klass->get.f.glyph_extents (this, user_data,
@@ -328,7 +339,7 @@
   }
 
   hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
-                                            hb_position_t *x, hb_position_t *y)
+                                     hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
     return klass->get.f.glyph_contour_point (this, user_data,
@@ -599,15 +610,19 @@
     return false;
   }
 
-  hb_position_t em_scale (int16_t v, int scale)
+  void mults_changed ()
   {
-    int upem = face->get_upem ();
-    int64_t scaled = v * (int64_t) scale;
-    scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
-    return (hb_position_t) (scaled / upem);
+    signed upem = face->get_upem ();
+    x_mult = ((int64_t) x_scale << 16) / upem;
+    y_mult = ((int64_t) y_scale << 16) / upem;
+  }
+
+  hb_position_t em_mult (int16_t v, int64_t mult)
+  {
+    return (hb_position_t) ((v * mult) >> 16);
   }
   hb_position_t em_scalef (float v, int scale)
-  { return (hb_position_t) round (v * scale / face->get_upem ()); }
+  { return (hb_position_t) roundf (v * scale / face->get_upem ()); }
   float em_fscale (int16_t v, int scale)
   { return (float) v * scale / face->get_upem (); }
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc
index d73c4aa..6b7b9e0 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc
@@ -29,6 +29,8 @@
 
 #include "hb.hh"
 
+#ifdef HAVE_FREETYPE
+
 #include "hb-ft.h"
 
 #include "hb-font.hh"
@@ -46,8 +48,13 @@
  * @short_description: FreeType integration
  * @include: hb-ft.h
  *
- * Functions for using HarfBuzz with the FreeType library to provide face and
+ * Functions for using HarfBuzz with the FreeType library.
+ *
+ * HarfBuzz supports using FreeType to provide face and
  * font data.
+ *
+ * <note>Note that FreeType is not thread-safe, therefore these
+ * functions are not thread-safe either.</note>
  **/
 
 
@@ -85,9 +92,7 @@
 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
 {
   hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
-
-  if (unlikely (!ft_font))
-    return nullptr;
+  if (unlikely (!ft_font)) return nullptr;
 
   ft_font->lock.init ();
   ft_font->ft_face = ft_face;
@@ -96,7 +101,7 @@
 
   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
-  ft_font->cached_x_scale.set (0);
+  ft_font->cached_x_scale.set_relaxed (0);
   ft_font->advance_cache.init ();
 
   return ft_font;
@@ -125,10 +130,13 @@
 
 /**
  * hb_ft_font_set_load_flags:
- * @font:
- * @load_flags:
+ * @font: #hb_font_t to work upon
+ * @load_flags: The FreeType load flags to set
  *
+ * Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
  *
+ * For more information, see
+ * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
  *
  * Since: 1.0.5
  **/
@@ -138,7 +146,7 @@
   if (hb_object_is_immutable (font))
     return;
 
-  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
     return;
 
   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
@@ -148,17 +156,21 @@
 
 /**
  * hb_ft_font_get_load_flags:
- * @font:
+ * @font: #hb_font_t to work upon
  *
+ * Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
  *
+ * For more information, see
+ * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
  *
- * Return value:
+ * Return value: FT_Load_Glyph flags found
+ *
  * 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)
+  if (unlikely (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;
@@ -166,10 +178,21 @@
   return ft_font->load_flags;
 }
 
+/**
+ * hb_ft_get_face:
+ * @font: #hb_font_t to work upon
+ *
+ * Fetches the FT_Face associated with the specified #hb_font_t
+ * font object.
+ *
+ * Return value: the FT_Face found
+ *
+ * Since: 0.9.2
+ **/
 FT_Face
 hb_ft_font_get_face (hb_font_t *font)
 {
-  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
+  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
     return nullptr;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
@@ -177,6 +200,47 @@
   return ft_font->ft_face;
 }
 
+/**
+ * hb_ft_font_lock_face:
+ * @font:
+ *
+ *
+ *
+ * Return value:
+ * Since: 2.6.5
+ **/
+FT_Face
+hb_ft_font_lock_face (hb_font_t *font)
+{
+  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
+    return nullptr;
+
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
+
+  ft_font->lock.lock ();
+
+  return ft_font->ft_face;
+}
+
+/**
+ * hb_ft_font_unlock_face:
+ * @font:
+ *
+ *
+ *
+ * Return value:
+ * Since: 2.6.5
+ **/
+void
+hb_ft_font_unlock_face (hb_font_t *font)
+{
+  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
+    return;
+
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
+
+  ft_font->lock.unlock ();
+}
 
 
 static hb_bool_t
@@ -346,6 +410,25 @@
   return true;
 }
 
+#ifndef HB_NO_OT_SHAPE_FALLBACK
+static hb_position_t
+hb_ft_get_glyph_h_kerning (hb_font_t *font,
+                           void *font_data,
+                           hb_codepoint_t left_glyph,
+                           hb_codepoint_t right_glyph,
+                           void *user_data HB_UNUSED)
+{
+  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+  FT_Vector kerningv;
+
+  FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
+  if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
+    return 0;
+
+  return kerningv.x;
+}
+#endif
+
 static hb_bool_t
 hb_ft_get_glyph_extents (hb_font_t *font,
                          void *font_data,
@@ -439,7 +522,7 @@
   else {
     /* Make a nul-terminated version. */
     char buf[128];
-    len = MIN (len, (int) sizeof (buf) - 1);
+    len = hb_min (len, (int) sizeof (buf) - 1);
     strncpy (buf, name, len);
     buf[len] = '\0';
     *glyph = FT_Get_Name_Index (ft_face, buf);
@@ -497,6 +580,10 @@
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
+#ifndef HB_NO_OT_SHAPE_FALLBACK
+    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
+#endif
+    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
@@ -531,15 +618,18 @@
 {
   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
 
+  hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref);
+  if (unlikely (!ft_font)) return;
+
   hb_font_set_funcs (font,
                      _hb_ft_get_font_funcs (),
-                     _hb_ft_font_create (ft_face, symbol, unref),
+                     ft_font,
                      _hb_ft_font_destroy);
 }
 
 
 static hb_blob_t *
-reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
   FT_Face ft_face = (FT_Face) user_data;
   FT_Byte *buffer;
@@ -570,12 +660,22 @@
 
 /**
  * hb_ft_face_create:
- * @ft_face: (destroy destroy) (scope notified):
- * @destroy:
+ * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
+ * @destroy: A callback to call when the face object is not needed anymore
  *
+ * Creates an #hb_face_t face object from the specified FT_Face.
  *
+ * This variant of the function does not provide any life-cycle management.
  *
- * Return value: (transfer full):
+ * Most client programs should use hb_ft_face_create_referenced()
+ * (or, perhaps, hb_ft_face_create_cached()) instead.
+ *
+ * If you know you have valid reasons not to use hb_ft_face_create_referenced(),
+ * then it is the client program's responsibility to destroy @ft_face
+ * after the #hb_face_t face object has been destroyed.
+ *
+ * Return value: (transfer full): the new #hb_face_t face object
+ *
  * Since: 0.9.2
  **/
 hb_face_t *
@@ -594,7 +694,7 @@
     face = hb_face_create (blob, ft_face->face_index);
     hb_blob_destroy (blob);
   } else {
-    face = hb_face_create_for_tables (reference_table, ft_face, destroy);
+    face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
   }
 
   hb_face_set_index (face, ft_face->face_index);
@@ -605,11 +705,20 @@
 
 /**
  * hb_ft_face_create_referenced:
- * @ft_face:
+ * @ft_face: FT_Face to work upon
  *
+ * Creates an #hb_face_t face object from the specified FT_Face.
  *
+ * This is the preferred variant of the hb_ft_face_create*
+ * function family, because it calls FT_Reference_Face() on @ft_face,
+ * ensuring that @ft_face remains alive as long as the resulting
+ * #hb_face_t face object remains alive. Also calls FT_Done_Face()
+ * when the #hb_face_t face object is destroyed.
  *
- * Return value: (transfer full):
+ * Use this version unless you know you have good reasons not to.
+ *
+ * Return value: (transfer full): the new #hb_face_t face object
+ *
  * Since: 0.9.38
  **/
 hb_face_t *
@@ -627,11 +736,21 @@
 
 /**
  * hb_ft_face_create_cached:
- * @ft_face:
+ * @ft_face: FT_Face to work upon
  *
+ * Creates an #hb_face_t face object from the specified FT_Face.
  *
+ * This variant of the function caches the newly created #hb_face_t
+ * face object, using the @generic pointer of @ft_face. Subsequent function
+ * calls that are passed the same @ft_face parameter will have the same
+ * #hb_face_t returned to them, and that #hb_face_t will be correctly
+ * reference counted.
  *
- * Return value: (transfer full):
+ * However, client programs are still responsible for destroying
+ * @ft_face after the last #hb_face_t face object has been destroyed.
+ *
+ * Return value: (transfer full): the new #hb_face_t face object
+ *
  * Since: 0.9.2
  **/
 hb_face_t *
@@ -649,15 +768,34 @@
   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
 }
 
-
 /**
  * hb_ft_font_create:
- * @ft_face: (destroy destroy) (scope notified):
- * @destroy:
+ * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
+ * @destroy: (optional): A callback to call when the font object is not needed anymore
  *
+ * Creates an #hb_font_t font object from the specified FT_Face.
  *
+ * <note>Note: You must set the face size on @ft_face before calling
+ * hb_ft_font_create() on it. Otherwise, HarfBuzz will not pick up
+ * the face size.</note>
  *
- * Return value: (transfer full):
+ * This variant of the function does not provide any life-cycle management.
+ *
+ * Most client programs should use hb_ft_font_create_referenced()
+ * instead.
+ *
+ * If you know you have valid reasons not to use hb_ft_font_create_referenced(),
+ * then it is the client program's responsibility to destroy @ft_face
+ * after the #hb_font_t font object has been destroyed.
+ *
+ * HarfBuzz will use the @destroy callback on the #hb_font_t font object
+ * if it is supplied when you use this function. However, even if @destroy
+ * is provided, it is the client program's responsibility to destroy @ft_face,
+ * and it is the client program's responsibility to ensure that @ft_face is
+ * destroyed only after the #hb_font_t font object has been destroyed.
+ *
+ * Return value: (transfer full): the new #hb_font_t font object
+ *
  * Since: 0.9.2
  **/
 hb_font_t *
@@ -675,6 +813,16 @@
   return font;
 }
 
+/**
+ * hb_ft_font_has_changed:
+ * @font: #hb_font_t to work upon
+ *
+ * Refreshes the state of @font when the underlying FT_Face has changed.
+ * This function should be called after changing the size or
+ * variation-axis settings on the FT_Face.
+ *
+ * Since: 1.0.5
+ **/
 void
 hb_ft_font_changed (hb_font_t *font)
 {
@@ -682,6 +830,7 @@
     return;
 
   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
+
   FT_Face ft_face = ft_font->ft_face;
 
   hb_font_set_scale (font,
@@ -693,7 +842,7 @@
                     ft_face->size->metrics.y_ppem);
 #endif
 
-#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
+#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
   FT_MM_Var *mm_var = nullptr;
   if (!FT_Get_MM_Var (ft_face, &mm_var))
   {
@@ -730,11 +879,23 @@
 
 /**
  * hb_ft_font_create_referenced:
- * @ft_face:
+ * @ft_face: FT_Face to work upon
  *
+ * Creates an #hb_font_t font object from the specified FT_Face.
  *
+ * <note>Note: You must set the face size on @ft_face before calling
+ * hb_ft_font_create_references() on it. Otherwise, HarfBuzz will not pick up
+ * the face size.</note>
  *
- * Return value: (transfer full):
+ * This is the preferred variant of the hb_ft_font_create*
+ * function family, because it calls FT_Reference_Face() on @ft_face,
+ * ensuring that @ft_face remains alive as long as the resulting
+ * #hb_font_t font object remains alive.
+ *
+ * Use this version unless you know you have good reasons not to.
+ *
+ * Return value: (transfer full): the new #hb_font_t font object
+ *
  * Since: 0.9.38
  **/
 hb_font_t *
@@ -748,7 +909,7 @@
 static void free_static_ft_library ();
 #endif
 
-static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (FT_Library),
+static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
                                                              hb_ft_library_lazy_loader_t>
 {
   static FT_Library create ()
@@ -793,6 +954,28 @@
   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
 }
 
+/**
+ * hb_ft_font_set_funcs:
+ * @font: #hb_font_t to work upon
+ *
+ * Configures the font-functions structure of the specified
+ * #hb_font_t font object to use FreeType font functions.
+ *
+ * In particular, you can use this function to configure an
+ * existing #hb_face_t face object for use with FreeType font
+ * functions even if that #hb_face_t face object was initially
+ * created with hb_face_create(), and therefore was not
+ * initially configured to use FreeType font functions.
+ *
+ * An #hb_face_t face object created with hb_ft_face_create()
+ * is preconfigured for FreeType font functions and does not
+ * require this function to be used.
+ *
+ * <note>Note: Internally, this function creates an FT_Face.
+* </note>
+ *
+ * Since: 1.0.5
+ **/
 void
 hb_ft_font_set_funcs (hb_font_t *font)
 {
@@ -815,8 +998,8 @@
     return;
   }
 
-  if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
-    FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
+  if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
+    FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
 
   FT_Set_Char_Size (ft_face,
                     abs (font->x_scale), abs (font->y_scale),
@@ -832,7 +1015,7 @@
     FT_Set_Transform (ft_face, &matrix, nullptr);
   }
 
-#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
+#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
   unsigned int num_coords;
   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
   if (num_coords)
@@ -841,7 +1024,7 @@
     if (ft_coords)
     {
       for (unsigned int i = 0; i < num_coords; i++)
-        ft_coords[i] = coords[i] << 2;
+        ft_coords[i] = coords[i] * 4;
       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
       free (ft_coords);
     }
@@ -854,3 +1037,6 @@
   _hb_ft_font_set_funcs (font, ft_face, true);
   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.h b/src/java.desktop/share/native/libharfbuzz/hb-ft.h
index dda30d3..4962eaf 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ft.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.h
@@ -110,6 +110,12 @@
 HB_EXTERN FT_Face
 hb_ft_font_get_face (hb_font_t *font);
 
+HB_EXTERN FT_Face
+hb_ft_font_lock_face (hb_font_t *font);
+
+HB_EXTERN void
+hb_ft_font_unlock_face (hb_font_t *font);
+
 HB_EXTERN void
 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh
index c4ab26d..99a441a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2018  Google, Inc.
+ * Copyright © 2019  Facebook, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -22,13 +23,15 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
+ * Facebook Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_ITER_HH
 #define HB_ITER_HH
 
 #include "hb.hh"
-#include "hb-null.hh"
+#include "hb-algs.hh"
+#include "hb-meta.hh"
 
 
 /* Unified iterator object.
@@ -39,16 +42,32 @@
  * copied by value.  If the collection / object being iterated on
  * is writable, then the iterator returns lvalues, otherwise it
  * returns rvalues.
+ *
+ * TODO Document more.
+ *
+ * If iterator implementation implements operator!=, then can be
+ * used in range-based for loop.  That comes free if the iterator
+ * is random-access.  Otherwise, the range-based for loop incurs
+ * one traversal to find end(), which can be avoided if written
+ * as a while-style for loop, or if iterator implements a faster
+ * __end__() method.
+ * TODO When opting in for C++17, address this by changing return
+ * type of .end()?
+ */
+
+/*
+ * Base classes for iterators.
  */
 
 /* Base class for all iterators. */
-template <typename Iter, typename Item = typename Iter::__item_type__>
+template <typename iter_t, typename Item = typename iter_t::__item_t__>
 struct hb_iter_t
 {
-  typedef Iter iter_t;
-  typedef iter_t const_iter_t;
   typedef Item item_t;
-  static constexpr unsigned item_size = hb_static_size (Item);
+  constexpr unsigned get_item_size () const { return hb_static_size (Item); }
+  static constexpr bool is_iterator = true;
+  static constexpr bool is_random_access_iterator = false;
+  static constexpr bool is_sorted_iterator = false;
 
   private:
   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -56,53 +75,119 @@
         iter_t* thiz ()       { return static_cast<      iter_t *> (this); }
   public:
 
+  /* TODO:
+   * Port operators below to use hb_enable_if to sniff which method implements
+   * an operator and use it, and remove hb_iter_fallback_mixin_t completely. */
+
   /* Operators. */
-  operator iter_t () { return iter(); }
-  explicit_operator bool () const { return more (); }
-  item_t& operator * () const { return item (); }
-  item_t& operator [] (signed i) const { return item_at ((unsigned) i); }
-  iter_t& operator += (unsigned count) { forward (count); return *thiz(); }
-  iter_t& operator ++ () { next (); return *thiz(); }
-  iter_t& operator -= (unsigned count) { rewind (count); return *thiz(); }
-  iter_t& operator -- () { prev (); return *thiz(); }
-  iter_t operator + (unsigned count) { iter_t c (*thiz()); c += count; return c; }
-  iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
-  iter_t operator - (unsigned count) { iter_t c (*thiz()); c -= count; return c; }
-  iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
-
-  /* Methods. */
   iter_t iter () const { return *thiz(); }
-  const_iter_t const_iter () const { return iter (); }
-  item_t& item () const { return thiz()->__item__ (); }
-  item_t& item_at (unsigned i) const { return thiz()->__item_at__ (i); }
-  bool more () const { return thiz()->__more__ (); }
+  iter_t operator + () const { return *thiz(); }
+  iter_t begin () const { return *thiz(); }
+  iter_t end () const { return thiz()->__end__ (); }
+  explicit operator bool () const { return thiz()->__more__ (); }
   unsigned len () const { return thiz()->__len__ (); }
-  void next () { thiz()->__next__ (); }
-  void forward (unsigned n) { thiz()->__forward__ (n); }
-  void prev () { thiz()->__prev__ (); }
-  void rewind (unsigned n) { thiz()->__rewind__ (n); }
-  bool random_access () const { return thiz()->__random_access__ (); }
+  /* The following can only be enabled if item_t is reference type.  Otherwise
+   * it will be returning pointer to temporary rvalue.
+   * TODO Use a wrapper return type to fix for non-reference type. */
+  template <typename T = item_t,
+            hb_enable_if (hb_is_reference (T))>
+  hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); }
+  item_t operator * () const { return thiz()->__item__ (); }
+  item_t operator * () { return thiz()->__item__ (); }
+  item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
+  item_t operator [] (unsigned i) { return thiz()->__item_at__ (i); }
+  iter_t& operator += (unsigned count) &  { thiz()->__forward__ (count); return *thiz(); }
+  iter_t  operator += (unsigned count) && { thiz()->__forward__ (count); return *thiz(); }
+  iter_t& operator ++ () &  { thiz()->__next__ (); return *thiz(); }
+  iter_t  operator ++ () && { thiz()->__next__ (); return *thiz(); }
+  iter_t& operator -= (unsigned count) &  { thiz()->__rewind__ (count); return *thiz(); }
+  iter_t  operator -= (unsigned count) && { thiz()->__rewind__ (count); return *thiz(); }
+  iter_t& operator -- () &  { thiz()->__prev__ (); return *thiz(); }
+  iter_t  operator -- () && { thiz()->__prev__ (); return *thiz(); }
+  iter_t operator + (unsigned count) const { auto c = thiz()->iter (); c += count; return c; }
+  friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; }
+  iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
+  iter_t operator - (unsigned count) const { auto c = thiz()->iter (); c -= count; return c; }
+  iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
+  template <typename T>
+  iter_t& operator >> (T &v) &  { v = **thiz(); ++*thiz(); return *thiz(); }
+  template <typename T>
+  iter_t  operator >> (T &v) && { v = **thiz(); ++*thiz(); return *thiz(); }
+  template <typename T>
+  iter_t& operator << (const T v) &  { **thiz() = v; ++*thiz(); return *thiz(); }
+  template <typename T>
+  iter_t  operator << (const T v) && { **thiz() = v; ++*thiz(); return *thiz(); }
 
   protected:
-  hb_iter_t () {}
-  hb_iter_t (const hb_iter_t &o HB_UNUSED) {}
-  void operator = (const hb_iter_t &o HB_UNUSED) {}
+  hb_iter_t () = default;
+  hb_iter_t (const hb_iter_t &o HB_UNUSED) = default;
+  hb_iter_t (hb_iter_t &&o HB_UNUSED) = default;
+  hb_iter_t& operator = (const hb_iter_t &o HB_UNUSED) = default;
+  hb_iter_t& operator = (hb_iter_t &&o HB_UNUSED) = default;
 };
 
-/* Base class for sorted iterators.  Does not enforce anything.
- * Just for class taxonomy and requirements. */
-template <typename Iter, typename Item = typename Iter::__item_type__>
-struct hb_sorted_iter_t : hb_iter_t<Iter, Item>
+#define HB_ITER_USING(Name) \
+  using item_t = typename Name::item_t; \
+  using Name::begin; \
+  using Name::end; \
+  using Name::get_item_size; \
+  using Name::is_iterator; \
+  using Name::iter; \
+  using Name::operator bool; \
+  using Name::len; \
+  using Name::operator ->; \
+  using Name::operator *; \
+  using Name::operator []; \
+  using Name::operator +=; \
+  using Name::operator ++; \
+  using Name::operator -=; \
+  using Name::operator --; \
+  using Name::operator +; \
+  using Name::operator -; \
+  using Name::operator >>; \
+  using Name::operator <<; \
+  static_assert (true, "")
+
+/* Returns iterator / item type of a type. */
+template <typename Iterable>
+using hb_iter_type = decltype (hb_deref (hb_declval (Iterable)).iter ());
+template <typename Iterable>
+using hb_item_type = decltype (*hb_deref (hb_declval (Iterable)).iter ());
+
+
+template <typename> struct hb_array_t;
+template <typename> struct hb_sorted_array_t;
+
+struct
 {
-  protected:
-  hb_sorted_iter_t () {}
-  hb_sorted_iter_t (const hb_sorted_iter_t &o) : hb_iter_t<Iter, Item> (o) {}
-  void operator = (const hb_sorted_iter_t &o HB_UNUSED) {}
-};
+  template <typename T> hb_iter_type<T>
+  operator () (T&& c) const
+  { return hb_deref (hb_forward<T> (c)).iter (); }
+
+  /* Specialization for C arrays. */
+
+  template <typename Type> inline hb_array_t<Type>
+  operator () (Type *array, unsigned int length) const
+  { return hb_array_t<Type> (array, length); }
+
+  template <typename Type, unsigned int length> hb_array_t<Type>
+  operator () (Type (&array)[length]) const
+  { return hb_array_t<Type> (array, length); }
+
+}
+HB_FUNCOBJ (hb_iter);
+struct
+{
+  template <typename T> unsigned
+  operator () (T&& c) const
+  { return c.len (); }
+
+}
+HB_FUNCOBJ (hb_len);
 
 /* Mixin to fill in what the subclass doesn't provide. */
-template <typename iter_t, typename item_t = typename iter_t::__item_type__>
-struct hb_iter_mixin_t
+template <typename iter_t, typename item_t = typename iter_t::__item_t__>
+struct hb_iter_fallback_mixin_t
 {
   private:
   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -111,42 +196,743 @@
   public:
 
   /* Access: Implement __item__(), or __item_at__() if random-access. */
-  item_t& __item__ () const { return thiz()->item_at (0); }
-  item_t& __item_at__ (unsigned i) const { return *(thiz() + i); }
+  item_t __item__ () const { return (*thiz())[0]; }
+  item_t __item_at__ (unsigned i) const { return *(*thiz() + i); }
 
   /* Termination: Implement __more__(), or __len__() if random-access. */
-  bool __more__ () const { return thiz()->__len__ (); }
+  bool __more__ () const { return bool (thiz()->len ()); }
   unsigned __len__ () const
-  { iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; }; return l; }
+  { iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; } return l; }
 
   /* Advancing: Implement __next__(), or __forward__() if random-access. */
-  void __next__ () { thiz()->forward (1); }
-  void __forward__ (unsigned n) { while (n--) thiz()->next (); }
+  void __next__ () { *thiz() += 1; }
+  void __forward__ (unsigned n) { while (*thiz() && n--) ++*thiz(); }
 
   /* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */
-  void __prev__ () { thiz()->rewind (1); }
-  void __rewind__ (unsigned n) { while (n--) thiz()->prev (); }
+  void __prev__ () { *thiz() -= 1; }
+  void __rewind__ (unsigned n) { while (*thiz() && n--) --*thiz(); }
 
-  /* Random access: Return true if item_at(), len(), forward() are fast. */
-  bool __random_access__ () const { return false; }
+  /* Range-based for: Implement __end__() if can be done faster,
+   * and operator!=. */
+  iter_t __end__ () const
+  {
+    if (thiz()->is_random_access_iterator)
+      return *thiz() + thiz()->len ();
+    /* Above expression loops twice. Following loops once. */
+    auto it = *thiz();
+    while (it) ++it;
+    return it;
+  }
+
+  protected:
+  hb_iter_fallback_mixin_t () = default;
+  hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
+  hb_iter_fallback_mixin_t (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
+  hb_iter_fallback_mixin_t& operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
+  hb_iter_fallback_mixin_t& operator = (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
 };
 
-
-/* Functions operating on iterators or iteratables. */
-
-template <typename C, typename V> inline void
-hb_fill (const C& c, const V &v)
+template <typename iter_t, typename item_t = typename iter_t::__item_t__>
+struct hb_iter_with_fallback_t :
+  hb_iter_t<iter_t, item_t>,
+  hb_iter_fallback_mixin_t<iter_t, item_t>
 {
-  for (typename C::iter_t i (c); i; i++)
-    hb_assign (*i, v);
+  protected:
+  hb_iter_with_fallback_t () = default;
+  hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
+  hb_iter_with_fallback_t (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
+  hb_iter_with_fallback_t& operator = (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
+  hb_iter_with_fallback_t& operator = (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
+};
+
+/*
+ * Meta-programming predicates.
+ */
+
+/* hb_is_iterator() / hb_is_iterator_of() */
+
+template<typename Iter, typename Item>
+struct hb_is_iterator_of
+{
+  template <typename Item2 = Item>
+  static hb_true_type impl (hb_priority<2>, hb_iter_t<Iter, hb_type_identity<Item2>> *);
+  static hb_false_type impl (hb_priority<0>, const void *);
+
+  public:
+  static constexpr bool value = decltype (impl (hb_prioritize, hb_declval (Iter*)))::value;
+};
+#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
+#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
+
+/* hb_is_iterable() */
+
+template <typename T>
+struct hb_is_iterable
+{
+  private:
+
+  template <typename U>
+  static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_type ());
+
+  template <typename>
+  static hb_false_type impl (hb_priority<0>);
+
+  public:
+  static constexpr bool value = decltype (impl<T> (hb_prioritize))::value;
+};
+#define hb_is_iterable(Iterable) hb_is_iterable<Iterable>::value
+
+/* hb_is_source_of() / hb_is_sink_of() */
+
+template<typename Iter, typename Item>
+struct hb_is_source_of
+{
+  private:
+  template <typename Iter2 = Iter,
+            hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))>
+  static hb_true_type impl (hb_priority<2>);
+  template <typename Iter2 = Iter>
+  static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ());
+  static hb_false_type impl (hb_priority<0>);
+
+  public:
+  static constexpr bool value = decltype (impl (hb_prioritize))::value;
+};
+#define hb_is_source_of(Iter, Item) hb_is_source_of<Iter, Item>::value
+
+template<typename Iter, typename Item>
+struct hb_is_sink_of
+{
+  private:
+  template <typename Iter2 = Iter,
+            hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<Item>))>
+  static hb_true_type impl (hb_priority<2>);
+  template <typename Iter2 = Iter>
+  static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) << hb_declval (Item), hb_true_type ());
+  static hb_false_type impl (hb_priority<0>);
+
+  public:
+  static constexpr bool value = decltype (impl (hb_prioritize))::value;
+};
+#define hb_is_sink_of(Iter, Item) hb_is_sink_of<Iter, Item>::value
+
+/* This is commonly used, so define: */
+#define hb_is_sorted_source_of(Iter, Item) \
+        (hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
+
+
+/* Range-based 'for' for iterables. */
+
+template <typename Iterable,
+          hb_requires (hb_is_iterable (Iterable))>
+static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
+
+template <typename Iterable,
+          hb_requires (hb_is_iterable (Iterable))>
+static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
+
+/* begin()/end() are NOT looked up non-ADL.  So each namespace must declare them.
+ * Do it for namespace OT. */
+namespace OT {
+
+template <typename Iterable,
+          hb_requires (hb_is_iterable (Iterable))>
+static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
+
+template <typename Iterable,
+          hb_requires (hb_is_iterable (Iterable))>
+static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
+
 }
 
-template <typename S, typename D> inline bool
-hb_copy (hb_iter_t<D> &id, hb_iter_t<S> &is)
+
+/*
+ * Adaptors, combiners, etc.
+ */
+
+template <typename Lhs, typename Rhs,
+          hb_requires (hb_is_iterator (Lhs))>
+static inline auto
+operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (hb_forward<Rhs> (rhs) (hb_forward<Lhs> (lhs)))
+
+/* hb_map(), hb_filter(), hb_reduce() */
+
+enum  class hb_function_sortedness_t {
+  NOT_SORTED,
+  RETAINS_SORTING,
+  SORTED,
+};
+
+template <typename Iter, typename Proj, hb_function_sortedness_t Sorted,
+         hb_requires (hb_is_iterator (Iter))>
+struct hb_map_iter_t :
+  hb_iter_t<hb_map_iter_t<Iter, Proj, Sorted>,
+            decltype (hb_get (hb_declval (Proj), *hb_declval (Iter)))>
 {
-  for (; id && is; ++id, ++is)
-    *id = *is;
-  return !is;
+  hb_map_iter_t (const Iter& it, Proj f_) : it (it), f (f_) {}
+
+  typedef decltype (hb_get (hb_declval (Proj), *hb_declval (Iter))) __item_t__;
+  static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
+  static constexpr bool is_sorted_iterator =
+    Sorted == hb_function_sortedness_t::SORTED ? true :
+    Sorted == hb_function_sortedness_t::RETAINS_SORTING ? Iter::is_sorted_iterator :
+    false;
+  __item_t__ __item__ () const { return hb_get (f.get (), *it); }
+  __item_t__ __item_at__ (unsigned i) const { return hb_get (f.get (), it[i]); }
+  bool __more__ () const { return bool (it); }
+  unsigned __len__ () const { return it.len (); }
+  void __next__ () { ++it; }
+  void __forward__ (unsigned n) { it += n; }
+  void __prev__ () { --it; }
+  void __rewind__ (unsigned n) { it -= n; }
+  hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
+  bool operator != (const hb_map_iter_t& o) const
+  { return it != o.it; }
+
+  private:
+  Iter it;
+  hb_reference_wrapper<Proj> f;
+};
+
+template <typename Proj, hb_function_sortedness_t Sorted>
+struct hb_map_iter_factory_t
+{
+  hb_map_iter_factory_t (Proj f) : f (f) {}
+
+  template <typename Iter,
+            hb_requires (hb_is_iterator (Iter))>
+  hb_map_iter_t<Iter, Proj, Sorted>
+  operator () (Iter it)
+  { return hb_map_iter_t<Iter, Proj, Sorted> (it, f); }
+
+  private:
+  Proj f;
+};
+struct
+{
+  template <typename Proj>
+  hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED>
+  operator () (Proj&& f) const
+  { return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED> (f); }
+}
+HB_FUNCOBJ (hb_map);
+struct
+{
+  template <typename Proj>
+  hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING>
+  operator () (Proj&& f) const
+  { return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING> (f); }
+}
+HB_FUNCOBJ (hb_map_retains_sorting);
+struct
+{
+  template <typename Proj>
+  hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED>
+  operator () (Proj&& f) const
+  { return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED> (f); }
+}
+HB_FUNCOBJ (hb_map_sorted);
+
+template <typename Iter, typename Pred, typename Proj,
+         hb_requires (hb_is_iterator (Iter))>
+struct hb_filter_iter_t :
+  hb_iter_with_fallback_t<hb_filter_iter_t<Iter, Pred, Proj>,
+                          typename Iter::item_t>
+{
+  hb_filter_iter_t (const Iter& it_, Pred p_, Proj f_) : it (it_), p (p_), f (f_)
+  { while (it && !hb_has (p.get (), hb_get (f.get (), *it))) ++it; }
+
+  typedef typename Iter::item_t __item_t__;
+  static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
+  __item_t__ __item__ () const { return *it; }
+  bool __more__ () const { return bool (it); }
+  void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
+  void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
+  hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
+  bool operator != (const hb_filter_iter_t& o) const
+  { return it != o.it; }
+
+  private:
+  Iter it;
+  hb_reference_wrapper<Pred> p;
+  hb_reference_wrapper<Proj> f;
+};
+template <typename Pred, typename Proj>
+struct hb_filter_iter_factory_t
+{
+  hb_filter_iter_factory_t (Pred p, Proj f) : p (p), f (f) {}
+
+  template <typename Iter,
+            hb_requires (hb_is_iterator (Iter))>
+  hb_filter_iter_t<Iter, Pred, Proj>
+  operator () (Iter it)
+  { return hb_filter_iter_t<Iter, Pred, Proj> (it, p, f); }
+
+  private:
+  Pred p;
+  Proj f;
+};
+struct
+{
+  template <typename Pred = decltype ((hb_identity)),
+            typename Proj = decltype ((hb_identity))>
+  hb_filter_iter_factory_t<Pred, Proj>
+  operator () (Pred&& p = hb_identity, Proj&& f = hb_identity) const
+  { return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
+}
+HB_FUNCOBJ (hb_filter);
+
+template <typename Redu, typename InitT>
+struct hb_reduce_t
+{
+  hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {}
+
+  template <typename Iter,
+            hb_requires (hb_is_iterator (Iter)),
+            typename AccuT = hb_decay<decltype (hb_declval (Redu) (hb_declval (InitT), hb_declval (typename Iter::item_t)))>>
+  AccuT
+  operator () (Iter it)
+  {
+    AccuT value = init_value;
+    for (; it; ++it)
+      value = r (value, *it);
+    return value;
+  }
+
+  private:
+  Redu r;
+  InitT init_value;
+};
+struct
+{
+  template <typename Redu, typename InitT>
+  hb_reduce_t<Redu, InitT>
+  operator () (Redu&& r, InitT init_value) const
+  { return hb_reduce_t<Redu, InitT> (r, init_value); }
+}
+HB_FUNCOBJ (hb_reduce);
+
+
+/* hb_zip() */
+
+template <typename A, typename B>
+struct hb_zip_iter_t :
+  hb_iter_t<hb_zip_iter_t<A, B>,
+            hb_pair_t<typename A::item_t, typename B::item_t>>
+{
+  hb_zip_iter_t () {}
+  hb_zip_iter_t (const A& a, const B& b) : a (a), b (b) {}
+
+  typedef hb_pair_t<typename A::item_t, typename B::item_t> __item_t__;
+  static constexpr bool is_random_access_iterator =
+    A::is_random_access_iterator &&
+    B::is_random_access_iterator;
+  /* Note.  The following categorization is only valid if A is strictly sorted,
+   * ie. does NOT have duplicates.  Previously I tried to categorize sortedness
+   * more granularly, see commits:
+   *
+   *   513762849a683914fc266a17ddf38f133cccf072
+   *   4d3cf2adb669c345cc43832d11689271995e160a
+   *
+   * However, that was not enough, since hb_sorted_array_t, hb_sorted_vector_t,
+   * SortedArrayOf, etc all needed to be updated to add more variants.  At that
+   * point I saw it not worth the effort, and instead we now deem all sorted
+   * collections as essentially strictly-sorted for the purposes of zip.
+   *
+   * The above assumption is not as bad as it sounds.  Our "sorted" comes with
+   * no guarantees.  It's just a contract, put in place to help you remember,
+   * and think about, whether an iterator you receive is expected to be
+   * sorted or not.  As such, it's not perfect by definition, and should not
+   * be treated so.  The inaccuracy here just errs in the direction of being
+   * more permissive, so your code compiles instead of erring on the side of
+   * marking your zipped iterator unsorted in which case your code won't
+   * compile.
+   *
+   * This semantical limitation does NOT affect logic in any other place I
+   * know of as of this writing.
+   */
+  static constexpr bool is_sorted_iterator = A::is_sorted_iterator;
+
+  __item_t__ __item__ () const { return __item_t__ (*a, *b); }
+  __item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
+  bool __more__ () const { return bool (a) && bool (b); }
+  unsigned __len__ () const { return hb_min (a.len (), b.len ()); }
+  void __next__ () { ++a; ++b; }
+  void __forward__ (unsigned n) { a += n; b += n; }
+  void __prev__ () { --a; --b; }
+  void __rewind__ (unsigned n) { a -= n; b -= n; }
+  hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
+  /* Note, we should stop if ANY of the iters reaches end.  As such two compare
+   * unequal if both items are unequal, NOT if either is unequal. */
+  bool operator != (const hb_zip_iter_t& o) const
+  { return a != o.a && b != o.b; }
+
+  private:
+  A a;
+  B b;
+};
+struct
+{ HB_PARTIALIZE(2);
+  template <typename A, typename B,
+            hb_requires (hb_is_iterable (A) && hb_is_iterable (B))>
+  hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>>
+  operator () (A&& a, B&& b) const
+  { return hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); }
+}
+HB_FUNCOBJ (hb_zip);
+
+/* hb_apply() */
+
+template <typename Appl>
+struct hb_apply_t
+{
+  hb_apply_t (Appl a) : a (a) {}
+
+  template <typename Iter,
+            hb_requires (hb_is_iterator (Iter))>
+  void operator () (Iter it)
+  {
+    for (; it; ++it)
+      (void) hb_invoke (a, *it);
+  }
+
+  private:
+  Appl a;
+};
+struct
+{
+  template <typename Appl> hb_apply_t<Appl>
+  operator () (Appl&& a) const
+  { return hb_apply_t<Appl> (a); }
+
+  template <typename Appl> hb_apply_t<Appl&>
+  operator () (Appl *a) const
+  { return hb_apply_t<Appl&> (*a); }
+}
+HB_FUNCOBJ (hb_apply);
+
+/* hb_range()/hb_iota()/hb_repeat() */
+
+template <typename T, typename S>
+struct hb_range_iter_t :
+  hb_iter_t<hb_range_iter_t<T, S>, T>
+{
+  hb_range_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {}
+
+  typedef T __item_t__;
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
+  __item_t__ __item__ () const { return hb_ridentity (v); }
+  __item_t__ __item_at__ (unsigned j) const { return v + j * step; }
+  bool __more__ () const { return v != end_; }
+  unsigned __len__ () const { return !step ? UINT_MAX : (end_ - v) / step; }
+  void __next__ () { v += step; }
+  void __forward__ (unsigned n) { v += n * step; }
+  void __prev__ () { v -= step; }
+  void __rewind__ (unsigned n) { v -= n * step; }
+  hb_range_iter_t __end__ () const { return hb_range_iter_t (end_, end_, step); }
+  bool operator != (const hb_range_iter_t& o) const
+  { return v != o.v; }
+
+  private:
+  static inline T end_for (T start, T end_, S step)
+  {
+    if (!step)
+      return end_;
+    auto res = (end_ - start) % step;
+    if (!res)
+      return end_;
+    end_ += step - res;
+    return end_;
+  }
+
+  private:
+  T v;
+  T end_;
+  S step;
+};
+struct
+{
+  template <typename T = unsigned> hb_range_iter_t<T, unsigned>
+  operator () (T end = (unsigned) -1) const
+  { return hb_range_iter_t<T, unsigned> (0, end, 1u); }
+
+  template <typename T, typename S = unsigned> hb_range_iter_t<T, S>
+  operator () (T start, T end, S step = 1u) const
+  { return hb_range_iter_t<T, S> (start, end, step); }
+}
+HB_FUNCOBJ (hb_range);
+
+template <typename T, typename S>
+struct hb_iota_iter_t :
+  hb_iter_with_fallback_t<hb_iota_iter_t<T, S>, T>
+{
+  hb_iota_iter_t (T start, S step) : v (start), step (step) {}
+
+  private:
+
+  template <typename S2 = S>
+  auto
+  inc (hb_type_identity<S2> s, hb_priority<1>)
+    -> hb_void_t<decltype (hb_invoke (hb_forward<S2> (s), hb_declval<T&> ()))>
+  { v = hb_invoke (hb_forward<S2> (s), v); }
+
+  void
+  inc (S s, hb_priority<0>)
+  { v += s; }
+
+  public:
+
+  typedef T __item_t__;
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
+  __item_t__ __item__ () const { return hb_ridentity (v); }
+  bool __more__ () const { return true; }
+  unsigned __len__ () const { return UINT_MAX; }
+  void __next__ () { inc (step, hb_prioritize); }
+  void __prev__ () { v -= step; }
+  hb_iota_iter_t __end__ () const { return *this; }
+  bool operator != (const hb_iota_iter_t& o) const { return true; }
+
+  private:
+  T v;
+  S step;
+};
+struct
+{
+  template <typename T = unsigned, typename S = unsigned> hb_iota_iter_t<T, S>
+  operator () (T start = 0u, S step = 1u) const
+  { return hb_iota_iter_t<T, S> (start, step); }
+}
+HB_FUNCOBJ (hb_iota);
+
+template <typename T>
+struct hb_repeat_iter_t :
+  hb_iter_t<hb_repeat_iter_t<T>, T>
+{
+  hb_repeat_iter_t (T value) : v (value) {}
+
+  typedef T __item_t__;
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
+  __item_t__ __item__ () const { return v; }
+  __item_t__ __item_at__ (unsigned j) const { return v; }
+  bool __more__ () const { return true; }
+  unsigned __len__ () const { return UINT_MAX; }
+  void __next__ () {}
+  void __forward__ (unsigned) {}
+  void __prev__ () {}
+  void __rewind__ (unsigned) {}
+  hb_repeat_iter_t __end__ () const { return *this; }
+  bool operator != (const hb_repeat_iter_t& o) const { return true; }
+
+  private:
+  T v;
+};
+struct
+{
+  template <typename T> hb_repeat_iter_t<T>
+  operator () (T value) const
+  { return hb_repeat_iter_t<T> (value); }
+}
+HB_FUNCOBJ (hb_repeat);
+
+/* hb_enumerate()/hb_take() */
+
+struct
+{
+  template <typename Iterable,
+            typename Index = unsigned,
+            hb_requires (hb_is_iterable (Iterable))>
+  auto operator () (Iterable&& it, Index start = 0u) const HB_AUTO_RETURN
+  ( hb_zip (hb_iota (start), it) )
+}
+HB_FUNCOBJ (hb_enumerate);
+
+struct
+{ HB_PARTIALIZE(2);
+  template <typename Iterable,
+            hb_requires (hb_is_iterable (Iterable))>
+  auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN
+  ( hb_zip (hb_range (count), it) | hb_map (hb_second) )
+
+  /* Specialization arrays. */
+
+  template <typename Type> inline hb_array_t<Type>
+  operator () (hb_array_t<Type> array, unsigned count) const
+  { return array.sub_array (0, count); }
+
+  template <typename Type> inline hb_sorted_array_t<Type>
+  operator () (hb_sorted_array_t<Type> array, unsigned count) const
+  { return array.sub_array (0, count); }
+}
+HB_FUNCOBJ (hb_take);
+
+struct
+{ HB_PARTIALIZE(2);
+  template <typename Iter,
+            hb_requires (hb_is_iterator (Iter))>
+  auto operator () (Iter it, unsigned count) const HB_AUTO_RETURN
+  (
+    + hb_iota (it, hb_add (count))
+    | hb_map (hb_take (count))
+    | hb_take ((hb_len (it) + count - 1) / count)
+  )
+}
+HB_FUNCOBJ (hb_chop);
+
+/* hb_sink() */
+
+template <typename Sink>
+struct hb_sink_t
+{
+  hb_sink_t (Sink s) : s (s) {}
+
+  template <typename Iter,
+            hb_requires (hb_is_iterator (Iter))>
+  void operator () (Iter it)
+  {
+    for (; it; ++it)
+      s << *it;
+  }
+
+  private:
+  Sink s;
+};
+struct
+{
+  template <typename Sink> hb_sink_t<Sink>
+  operator () (Sink&& s) const
+  { return hb_sink_t<Sink> (s); }
+
+  template <typename Sink> hb_sink_t<Sink&>
+  operator () (Sink *s) const
+  { return hb_sink_t<Sink&> (*s); }
+}
+HB_FUNCOBJ (hb_sink);
+
+/* hb-drain: hb_sink to void / blackhole / /dev/null. */
+
+struct
+{
+  template <typename Iter,
+            hb_requires (hb_is_iterator (Iter))>
+  void operator () (Iter it) const
+  {
+    for (; it; ++it)
+      (void) *it;
+  }
+}
+HB_FUNCOBJ (hb_drain);
+
+/* hb_unzip(): unzip and sink to two sinks. */
+
+template <typename Sink1, typename Sink2>
+struct hb_unzip_t
+{
+  hb_unzip_t (Sink1 s1, Sink2 s2) : s1 (s1), s2 (s2) {}
+
+  template <typename Iter,
+            hb_requires (hb_is_iterator (Iter))>
+  void operator () (Iter it)
+  {
+    for (; it; ++it)
+    {
+      const auto &v = *it;
+      s1 << v.first;
+      s2 << v.second;
+    }
+  }
+
+  private:
+  Sink1 s1;
+  Sink2 s2;
+};
+struct
+{
+  template <typename Sink1, typename Sink2> hb_unzip_t<Sink1, Sink2>
+  operator () (Sink1&& s1, Sink2&& s2) const
+  { return hb_unzip_t<Sink1, Sink2> (s1, s2); }
+
+  template <typename Sink1, typename Sink2> hb_unzip_t<Sink1&, Sink2&>
+  operator () (Sink1 *s1, Sink2 *s2) const
+  { return hb_unzip_t<Sink1&, Sink2&> (*s1, *s2); }
+}
+HB_FUNCOBJ (hb_unzip);
+
+
+/* hb-all, hb-any, hb-none. */
+
+struct
+{
+  template <typename Iterable,
+            typename Pred = decltype ((hb_identity)),
+            typename Proj = decltype ((hb_identity)),
+            hb_requires (hb_is_iterable (Iterable))>
+  bool operator () (Iterable&& c,
+                    Pred&& p = hb_identity,
+                    Proj&& f = hb_identity) const
+  {
+    for (auto it = hb_iter (c); it; ++it)
+      if (!hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
+        return false;
+    return true;
+  }
+}
+HB_FUNCOBJ (hb_all);
+struct
+{
+  template <typename Iterable,
+            typename Pred = decltype ((hb_identity)),
+            typename Proj = decltype ((hb_identity)),
+            hb_requires (hb_is_iterable (Iterable))>
+  bool operator () (Iterable&& c,
+                    Pred&& p = hb_identity,
+                    Proj&& f = hb_identity) const
+  {
+    for (auto it = hb_iter (c); it; ++it)
+      if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
+        return true;
+    return false;
+  }
+}
+HB_FUNCOBJ (hb_any);
+struct
+{
+  template <typename Iterable,
+            typename Pred = decltype ((hb_identity)),
+            typename Proj = decltype ((hb_identity)),
+            hb_requires (hb_is_iterable (Iterable))>
+  bool operator () (Iterable&& c,
+                    Pred&& p = hb_identity,
+                    Proj&& f = hb_identity) const
+  {
+    for (auto it = hb_iter (c); it; ++it)
+      if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
+        return false;
+    return true;
+  }
+}
+HB_FUNCOBJ (hb_none);
+
+/*
+ * Algorithms operating on iterators.
+ */
+
+template <typename C, typename V,
+          hb_requires (hb_is_iterable (C))>
+inline void
+hb_fill (C& c, const V &v)
+{
+  for (auto i = hb_iter (c); i; i++)
+    *i = v;
+}
+
+template <typename S, typename D>
+inline void
+hb_copy (S&& is, D&& id)
+{
+  hb_iter (is) | hb_sink (id);
 }
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh
index 43d70d7..42e5493 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh
@@ -52,8 +52,7 @@
     OT::hb_ot_apply_context_t c (1, font, buffer);
     c.set_lookup_mask (kern_mask);
     c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
-    OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
-    skippy_iter.init (&c);
+    auto &skippy_iter = c.iter_input;
 
     bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction);
     unsigned int count = buffer->len;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh
index 2ae2884..0c820e7 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh
@@ -32,30 +32,15 @@
 #include "hb.hh"
 #include "hb-blob.hh"
 
-#include "hb-array.hh"
-#include "hb-vector.hh"
+#include "hb-dispatch.hh"
+#include "hb-sanitize.hh"
+#include "hb-serialize.hh"
 
 
 /*
  * Casts
  */
 
-/* Cast to struct T, reference to reference */
-template<typename Type, typename TObject>
-static inline const Type& CastR(const TObject &X)
-{ return reinterpret_cast<const Type&> (X); }
-template<typename Type, typename TObject>
-static inline Type& CastR(TObject &X)
-{ return reinterpret_cast<Type&> (X); }
-
-/* Cast to struct T, pointer to pointer */
-template<typename Type, typename TObject>
-static inline const Type* CastP(const TObject *X)
-{ return reinterpret_cast<const Type*> (X); }
-template<typename Type, typename TObject>
-static inline Type* CastP(TObject *X)
-{ return reinterpret_cast<Type*> (X); }
-
 /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
  * location pointed to by P plus Ofs bytes. */
 template<typename Type>
@@ -69,7 +54,7 @@
 {
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-align"
-  return * reinterpret_cast<Type*> ((char *) P + offset);
+  return * reinterpret_cast<const Type*> ((const char *) P + offset);
 #pragma GCC diagnostic pop
 }
 template<typename Type>
@@ -134,7 +119,7 @@
 
 #define DEFINE_SIZE_ARRAY(size, array) \
   DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \
-  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof ((array)[0])) \
+  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + (HB_VAR_ARRAY+0) * sizeof ((array)[0])) \
   static constexpr unsigned null_size = (size); \
   static constexpr unsigned min_size = (size)
 
@@ -143,615 +128,6 @@
   DEFINE_SIZE_ARRAY(size, array)
 
 
-/*
- * Dispatch
- */
-
-template <typename Context, typename Return, unsigned int MaxDebugDepth>
-struct hb_dispatch_context_t
-{
-  static constexpr unsigned max_debug_depth = MaxDebugDepth;
-  typedef Return return_t;
-  template <typename T, typename F>
-  bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
-  static return_t no_dispatch_return_value () { return Context::default_return_value (); }
-  static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
-};
-
-
-/*
- * Sanitize
- *
- *
- * === Introduction ===
- *
- * The sanitize machinery is at the core of our zero-cost font loading.  We
- * mmap() font file into memory and create a blob out of it.  Font subtables
- * are returned as a readonly sub-blob of the main font blob.  These table
- * blobs are then sanitized before use, to ensure invalid memory access does
- * not happen.  The toplevel sanitize API use is like, eg. to load the 'head'
- * table:
- *
- *   hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face);
- *
- * The blob then can be converted to a head table struct with:
- *
- *   const head *head_table = head_blob->as<head> ();
- *
- * What the reference_table does is, to call hb_face_reference_table() to load
- * the table blob, sanitize it and return either the sanitized blob, or empty
- * blob if sanitization failed.  The blob->as() function returns the null
- * object of its template type argument if the blob is empty.  Otherwise, it
- * just casts the blob contents to the desired type.
- *
- * Sanitizing a blob of data with a type T works as follows (with minor
- * simplification):
- *
- *   - Cast blob content to T*, call sanitize() method of it,
- *   - If sanitize succeeded, return blob.
- *   - Otherwise, if blob is not writable, try making it writable,
- *     or copy if cannot be made writable in-place,
- *   - Call sanitize() again.  Return blob if sanitize succeeded.
- *   - Return empty blob otherwise.
- *
- *
- * === The sanitize() contract ===
- *
- * The sanitize() method of each object type shall return true if it's safe to
- * call other methods of the object, and false otherwise.
- *
- * Note that what sanitize() checks for might align with what the specification
- * describes as valid table data, but does not have to be.  In particular, we
- * do NOT want to be pedantic and concern ourselves with validity checks that
- * are irrelevant to our use of the table.  On the contrary, we want to be
- * lenient with error handling and accept invalid data to the extent that it
- * does not impose extra burden on us.
- *
- * Based on the sanitize contract, one can see that what we check for depends
- * on how we use the data in other table methods.  Ie. if other table methods
- * assume that offsets do NOT point out of the table data block, then that's
- * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way).  On
- * the other hand, if other methods do such checks themselves, then sanitize()
- * does not have to bother with them (glyf/local work this way).  The choice
- * depends on the table structure and sanitize() performance.  For example, to
- * check glyf/loca offsets in sanitize() would cost O(num-glyphs).  We try hard
- * to avoid such costs during font loading.  By postponing such checks to the
- * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime
- * cost to O(used-glyphs).  As such, this is preferred.
- *
- * The same argument can be made re GSUB/GPOS/GDEF, but there, the table
- * structure is so complicated that by checking all offsets at sanitize() time,
- * we make the code much simpler in other methods, as offsets and referenced
- * objects do not need to be validated at each use site.
- */
-
-/* This limits sanitizing time on really broken fonts. */
-#ifndef HB_SANITIZE_MAX_EDITS
-#define HB_SANITIZE_MAX_EDITS 32
-#endif
-#ifndef HB_SANITIZE_MAX_OPS_FACTOR
-#define HB_SANITIZE_MAX_OPS_FACTOR 8
-#endif
-#ifndef HB_SANITIZE_MAX_OPS_MIN
-#define HB_SANITIZE_MAX_OPS_MIN 16384
-#endif
-#ifndef HB_SANITIZE_MAX_OPS_MAX
-#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF
-#endif
-
-struct hb_sanitize_context_t :
-       hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
-{
-  hb_sanitize_context_t () :
-        debug_depth (0),
-        start (nullptr), end (nullptr),
-        max_ops (0),
-        writable (false), edit_count (0),
-        blob (nullptr),
-        num_glyphs (65536),
-        num_glyphs_set (false) {}
-
-  const char *get_name () { return "SANITIZE"; }
-  template <typename T, typename F>
-  bool may_dispatch (const T *obj HB_UNUSED, const F *format)
-  { return format->sanitize (this); }
-  template <typename T>
-  return_t dispatch (const T &obj) { return obj.sanitize (this); }
-  static return_t default_return_value () { return true; }
-  static return_t no_dispatch_return_value () { return false; }
-  bool stop_sublookup_iteration (const return_t r) const { return !r; }
-
-  void init (hb_blob_t *b)
-  {
-    this->blob = hb_blob_reference (b);
-    this->writable = false;
-  }
-
-  void set_num_glyphs (unsigned int num_glyphs_)
-  {
-    num_glyphs = num_glyphs_;
-    num_glyphs_set = true;
-  }
-  unsigned int get_num_glyphs () { return num_glyphs; }
-
-  void set_max_ops (int max_ops_) { max_ops = max_ops_; }
-
-  template <typename T>
-  void set_object (const T *obj)
-  {
-    reset_object ();
-
-    if (!obj) return;
-
-    const char *obj_start = (const char *) obj;
-    if (unlikely (obj_start < this->start || this->end <= obj_start))
-      this->start = this->end = nullptr;
-    else
-    {
-      this->start = obj_start;
-      this->end   = obj_start + MIN<uintptr_t> (this->end - obj_start, obj->get_size ());
-    }
-  }
-
-  void reset_object ()
-  {
-    this->start = this->blob->data;
-    this->end = this->start + this->blob->length;
-    assert (this->start <= this->end); /* Must not overflow. */
-  }
-
-  void start_processing ()
-  {
-    reset_object ();
-    this->max_ops = MAX ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
-                         (unsigned) HB_SANITIZE_MAX_OPS_MIN);
-    this->edit_count = 0;
-    this->debug_depth = 0;
-
-    DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
-                     "start [%p..%p] (%lu bytes)",
-                     this->start, this->end,
-                     (unsigned long) (this->end - this->start));
-  }
-
-  void end_processing ()
-  {
-    DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
-                     "end [%p..%p] %u edit requests",
-                     this->start, this->end, this->edit_count);
-
-    hb_blob_destroy (this->blob);
-    this->blob = nullptr;
-    this->start = this->end = nullptr;
-  }
-
-  bool check_range (const void *base,
-                           unsigned int len) const
-  {
-    const char *p = (const char *) base;
-    bool ok = this->start <= p &&
-              p <= this->end &&
-              (unsigned int) (this->end - p) >= len &&
-              this->max_ops-- > 0;
-
-    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
-       "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
-       p, p + len, len,
-       this->start, this->end,
-       ok ? "OK" : "OUT-OF-RANGE");
-
-    return likely (ok);
-  }
-
-  template <typename T>
-  bool check_range (const T *base,
-                           unsigned int a,
-                           unsigned int b) const
-  {
-    return !hb_unsigned_mul_overflows (a, b) &&
-           this->check_range (base, a * b);
-  }
-
-  template <typename T>
-  bool check_range (const T *base,
-                           unsigned int a,
-                           unsigned int b,
-                           unsigned int c) const
-  {
-    return !hb_unsigned_mul_overflows (a, b) &&
-           this->check_range (base, a * b, c);
-  }
-
-  template <typename T>
-  bool check_array (const T *base, unsigned int len) const
-  {
-    return this->check_range (base, len, hb_static_size (T));
-  }
-
-  template <typename T>
-  bool check_array (const T *base,
-                    unsigned int a,
-                    unsigned int b) const
-  {
-    return this->check_range (base, a, b, hb_static_size (T));
-  }
-
-  template <typename Type>
-  bool check_struct (const Type *obj) const
-  { return likely (this->check_range (obj, obj->min_size)); }
-
-  bool may_edit (const void *base, unsigned int len)
-  {
-    if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
-      return false;
-
-    const char *p = (const char *) base;
-    this->edit_count++;
-
-    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
-       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
-       this->edit_count,
-       p, p + len, len,
-       this->start, this->end,
-       this->writable ? "GRANTED" : "DENIED");
-
-    return this->writable;
-  }
-
-  template <typename Type, typename ValueType>
-  bool try_set (const Type *obj, const ValueType &v)
-  {
-    if (this->may_edit (obj, hb_static_size (Type)))
-    {
-      hb_assign (* const_cast<Type *> (obj), v);
-      return true;
-    }
-    return false;
-  }
-
-  template <typename Type>
-  hb_blob_t *sanitize_blob (hb_blob_t *blob)
-  {
-    bool sane;
-
-    init (blob);
-
-  retry:
-    DEBUG_MSG_FUNC (SANITIZE, start, "start");
-
-    start_processing ();
-
-    if (unlikely (!start))
-    {
-      end_processing ();
-      return blob;
-    }
-
-    Type *t = CastP<Type> (const_cast<char *> (start));
-
-    sane = t->sanitize (this);
-    if (sane)
-    {
-      if (edit_count)
-      {
-        DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count);
-
-        /* sanitize again to ensure no toe-stepping */
-        edit_count = 0;
-        sane = t->sanitize (this);
-        if (edit_count) {
-          DEBUG_MSG_FUNC (SANITIZE, start, "requested %d edits in second round; FAILLING", edit_count);
-          sane = false;
-        }
-      }
-    }
-    else
-    {
-      if (edit_count && !writable) {
-        start = hb_blob_get_data_writable (blob, nullptr);
-        end = start + blob->length;
-
-        if (start)
-        {
-          writable = true;
-          /* ok, we made it writable by relocating.  try again */
-          DEBUG_MSG_FUNC (SANITIZE, start, "retry");
-          goto retry;
-        }
-      }
-    }
-
-    end_processing ();
-
-    DEBUG_MSG_FUNC (SANITIZE, start, sane ? "PASSED" : "FAILED");
-    if (sane)
-    {
-      hb_blob_make_immutable (blob);
-      return blob;
-    }
-    else
-    {
-      hb_blob_destroy (blob);
-      return hb_blob_get_empty ();
-    }
-  }
-
-  template <typename Type>
-  hb_blob_t *reference_table (const hb_face_t *face, hb_tag_t tableTag = Type::tableTag)
-  {
-    if (!num_glyphs_set)
-      set_num_glyphs (hb_face_get_glyph_count (face));
-    return sanitize_blob<Type> (hb_face_reference_table (face, tableTag));
-  }
-
-  mutable unsigned int debug_depth;
-  const char *start, *end;
-  mutable int max_ops;
-  private:
-  bool writable;
-  unsigned int edit_count;
-  hb_blob_t *blob;
-  unsigned int num_glyphs;
-  bool  num_glyphs_set;
-};
-
-struct hb_sanitize_with_object_t
-{
-  template <typename T>
-  hb_sanitize_with_object_t (hb_sanitize_context_t *c,
-                                    const T& obj) : c (c)
-  { c->set_object (obj); }
-  ~hb_sanitize_with_object_t ()
-  { c->reset_object (); }
-
-  private:
-  hb_sanitize_context_t *c;
-};
-
-
-/*
- * Serialize
- */
-
-struct hb_serialize_context_t
-{
-  hb_serialize_context_t (void *start_, unsigned int size)
-  {
-    this->start = (char *) start_;
-    this->end = this->start + size;
-    reset ();
-  }
-
-  bool in_error () const { return !this->successful; }
-
-  void reset ()
-  {
-    this->successful = true;
-    this->head = this->start;
-    this->debug_depth = 0;
-  }
-
-  bool propagate_error (bool e)
-  { return this->successful = this->successful && e; }
-  template <typename T> bool propagate_error (const T &obj)
-  { return this->successful = this->successful && !obj.in_error (); }
-  template <typename T> bool propagate_error (const T *obj)
-  { return this->successful = this->successful && !obj->in_error (); }
-  template <typename T1, typename T2> bool propagate_error (T1 &o1, T2 &o2)
-  { return propagate_error (o1) && propagate_error (o2); }
-  template <typename T1, typename T2> bool propagate_error (T1 *o1, T2 *o2)
-  { return propagate_error (o1) && propagate_error (o2); }
-  template <typename T1, typename T2, typename T3>
-  bool propagate_error (T1 &o1, T2 &o2, T3 &o3)
-  { return propagate_error (o1) && propagate_error (o2, o3); }
-  template <typename T1, typename T2, typename T3>
-  bool propagate_error (T1 *o1, T2 *o2, T3 *o3)
-  { return propagate_error (o1) && propagate_error (o2, o3); }
-
-  /* To be called around main operation. */
-  template <typename Type>
-  Type *start_serialize ()
-  {
-    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
-                     "start [%p..%p] (%lu bytes)",
-                     this->start, this->end,
-                     (unsigned long) (this->end - this->start));
-
-    return start_embed<Type> ();
-  }
-  void end_serialize ()
-  {
-    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
-                     "end [%p..%p] serialized %d bytes; %s",
-                     this->start, this->end,
-                     (int) (this->head - this->start),
-                     this->successful ? "successful" : "UNSUCCESSFUL");
-  }
-
-  unsigned int length () const { return this->head - this->start; }
-
-  void align (unsigned int alignment)
-  {
-    unsigned int l = length () % alignment;
-    if (l)
-      allocate_size<void> (alignment - l);
-  }
-
-  template <typename Type>
-  Type *start_embed (const Type *_ HB_UNUSED = nullptr) const
-  {
-    Type *ret = reinterpret_cast<Type *> (this->head);
-    return ret;
-  }
-
-  template <typename Type>
-  Type *allocate_size (unsigned int size)
-  {
-    if (unlikely (!this->successful || this->end - this->head < ptrdiff_t (size))) {
-      this->successful = false;
-      return nullptr;
-    }
-    memset (this->head, 0, size);
-    char *ret = this->head;
-    this->head += size;
-    return reinterpret_cast<Type *> (ret);
-  }
-
-  template <typename Type>
-  Type *allocate_min ()
-  {
-    return this->allocate_size<Type> (Type::min_size);
-  }
-
-  template <typename Type>
-  Type *embed (const Type &obj)
-  {
-    unsigned int size = obj.get_size ();
-    Type *ret = this->allocate_size<Type> (size);
-    if (unlikely (!ret)) return nullptr;
-    memcpy (ret, &obj, size);
-    return ret;
-  }
-  template <typename Type>
-  hb_serialize_context_t &operator << (const Type &obj) { embed (obj); return *this; }
-
-  template <typename Type>
-  Type *extend_size (Type &obj, unsigned int size)
-  {
-    assert (this->start <= (char *) &obj);
-    assert ((char *) &obj <= this->head);
-    assert ((char *) &obj + size >= this->head);
-    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
-    return reinterpret_cast<Type *> (&obj);
-  }
-
-  template <typename Type>
-  Type *extend_min (Type &obj) { return extend_size (obj, obj.min_size); }
-
-  template <typename Type>
-  Type *extend (Type &obj) { return extend_size (obj, obj.get_size ()); }
-
-  /* Output routines. */
-  template <typename Type>
-  Type *copy () const
-  {
-    assert (this->successful);
-    unsigned int len = this->head - this->start;
-    void *p = malloc (len);
-    if (p)
-      memcpy (p, this->start, len);
-    return reinterpret_cast<Type *> (p);
-  }
-  hb_bytes_t copy_bytes () const
-  {
-    assert (this->successful);
-    unsigned int len = this->head - this->start;
-    void *p = malloc (len);
-    if (p)
-      memcpy (p, this->start, len);
-    else
-      return hb_bytes_t ();
-    return hb_bytes_t ((char *) p, len);
-  }
-  hb_blob_t *copy_blob () const
-  {
-    assert (this->successful);
-    return hb_blob_create (this->start,
-                           this->head - this->start,
-                           HB_MEMORY_MODE_DUPLICATE,
-                           nullptr, nullptr);
-  }
-
-  public:
-  unsigned int debug_depth;
-  char *start, *end, *head;
-  bool successful;
-};
-
-
-
-/*
- * Big-endian integers.
- */
-
-template <typename Type, int Bytes> struct BEInt;
-
-template <typename Type>
-struct BEInt<Type, 1>
-{
-  public:
-  void set (Type V)      { v = V; }
-  operator Type () const { return v; }
-  private: uint8_t v;
-};
-template <typename Type>
-struct BEInt<Type, 2>
-{
-  public:
-  void set (Type V)
-  {
-    v[0] = (V >>  8) & 0xFF;
-    v[1] = (V      ) & 0xFF;
-  }
-  operator Type () const
-  {
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
-    defined(__BYTE_ORDER) && \
-    (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
-    /* Spoon-feed the compiler a big-endian integer with alignment 1.
-     * https://github.com/harfbuzz/harfbuzz/pull/1398 */
-    struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-    return __builtin_bswap16 (((packed_uint16_t *) this)->v);
-#else /* __BYTE_ORDER == __BIG_ENDIAN */
-    return ((packed_uint16_t *) this)->v;
-#endif
-#endif
-    return (v[0] <<  8)
-         + (v[1]      );
-  }
-  private: uint8_t v[2];
-};
-template <typename Type>
-struct BEInt<Type, 3>
-{
-  public:
-  void set (Type V)
-  {
-    v[0] = (V >> 16) & 0xFF;
-    v[1] = (V >>  8) & 0xFF;
-    v[2] = (V      ) & 0xFF;
-  }
-  operator Type () const
-  {
-    return (v[0] << 16)
-         + (v[1] <<  8)
-         + (v[2]      );
-  }
-  private: uint8_t v[3];
-};
-template <typename Type>
-struct BEInt<Type, 4>
-{
-  public:
-  typedef Type type;
-  void set (Type V)
-  {
-    v[0] = (V >> 24) & 0xFF;
-    v[1] = (V >> 16) & 0xFF;
-    v[2] = (V >>  8) & 0xFF;
-    v[3] = (V      ) & 0xFF;
-  }
-  operator Type () const
-  {
-    return (v[0] << 24)
-         + (v[1] << 16)
-         + (v[2] <<  8)
-         + (v[3]      );
-  }
-  private: uint8_t v[4];
-};
-
 
 /*
  * Lazy loaders.
@@ -814,7 +190,7 @@
 
   const Returned * operator -> () const { return get (); }
   const Returned & operator * () const  { return *get (); }
-  explicit_operator bool () const
+  explicit operator bool () const
   { return get_stored () != Funcs::get_null (); }
   template <typename C> operator const C * () const { return get (); }
 
@@ -858,7 +234,7 @@
   static Returned* convert (Stored *p) { return p; }
 
   /* By default null/init/fini the object. */
-  static const Stored* get_null () { return &Null(Stored); }
+  static const Stored* get_null () { return &Null (Stored); }
   static Stored *create (Data *data)
   {
     Stored *p = (Stored *) calloc (1, sizeof (Stored));
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-map.cc
index 3fccfa0..114efcb 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-map.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-map.cc
@@ -69,7 +69,7 @@
 hb_map_t *
 hb_map_get_empty ()
 {
-  return const_cast<hb_map_t *> (&Null(hb_map_t));
+  return const_cast<hb_map_t *> (&Null (hb_map_t));
 }
 
 /**
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-map.hh
index c04a8df..a5c997c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-map.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-map.hh
@@ -30,31 +30,36 @@
 #include "hb.hh"
 
 
-template <typename T>
-inline uint32_t Hash (const T &v)
-{
-  /* Knuth's multiplicative method: */
-  return (uint32_t) v * 2654435761u;
-}
-
-
 /*
- * hb_map_t
+ * hb_hashmap_t
  */
 
-struct hb_map_t
+template <typename K, typename V,
+          K kINVALID = hb_is_pointer (K) ? 0 : hb_is_signed (K) ? hb_int_min (K) : (K) -1,
+          V vINVALID = hb_is_pointer (V) ? 0 : hb_is_signed (V) ? hb_int_min (V) : (V) -1>
+struct hb_hashmap_t
 {
-  HB_NO_COPY_ASSIGN (hb_map_t);
-  hb_map_t ()  { init (); }
-  ~hb_map_t () { fini (); }
+  HB_DELETE_COPY_ASSIGN (hb_hashmap_t);
+  hb_hashmap_t ()  { init (); }
+  ~hb_hashmap_t () { fini (); }
+
+  static_assert (hb_is_integral (K) || hb_is_pointer (K), "");
+  static_assert (hb_is_integral (V) || hb_is_pointer (V), "");
 
   struct item_t
   {
-    hb_codepoint_t key;
-    hb_codepoint_t value;
+    K key;
+    V value;
+    uint32_t hash;
 
-    bool is_unused () const    { return key == INVALID; }
-    bool is_tombstone () const { return key != INVALID && value == INVALID; }
+    void clear () { key = kINVALID; value = vINVALID; hash = 0; }
+
+    bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); }
+    bool operator == (const item_t &o) { return *this == o.key; }
+    bool is_unused () const    { return key == kINVALID; }
+    bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
+    bool is_real () const { return key != kINVALID && value != vINVALID; }
+    hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
   };
 
   hb_object_header_t header;
@@ -82,14 +87,22 @@
   {
     free (items);
     items = nullptr;
+    population = occupancy = 0;
   }
   void fini ()
   {
-    population = occupancy = 0;
     hb_object_fini (this);
     fini_shallow ();
   }
 
+  void reset ()
+  {
+    if (unlikely (hb_object_is_immutable (this)))
+      return;
+    successful = true;
+    clear ();
+  }
+
   bool in_error () const { return !successful; }
 
   bool resize ()
@@ -104,7 +117,8 @@
       successful = false;
       return false;
     }
-    memset (new_items, 0xFF, (size_t) new_size * sizeof (item_t));
+    for (auto &_ : hb_iter (new_items, new_size))
+      _.clear ();
 
     unsigned int old_size = mask + 1;
     item_t *old_items = items;
@@ -118,22 +132,96 @@
     /* Insert back old items. */
     if (old_items)
       for (unsigned int i = 0; i < old_size; i++)
-        if (old_items[i].key != INVALID && old_items[i].value != INVALID)
-          set (old_items[i].key, old_items[i].value);
+        if (old_items[i].is_real ())
+          set_with_hash (old_items[i].key,
+                         old_items[i].hash,
+                         old_items[i].value);
 
     free (old_items);
 
     return true;
   }
 
-  void set (hb_codepoint_t key, hb_codepoint_t value)
+  void set (K key, V value)
+  {
+    set_with_hash (key, hb_hash (key), value);
+  }
+
+  V get (K key) const
+  {
+    if (unlikely (!items)) return vINVALID;
+    unsigned int i = bucket_for (key);
+    return items[i].is_real () && items[i] == key ? items[i].value : vINVALID;
+  }
+
+  void del (K key) { set (key, vINVALID); }
+
+  /* Has interface. */
+  static constexpr V SENTINEL = vINVALID;
+  typedef V value_t;
+  value_t operator [] (K k) const { return get (k); }
+  bool has (K k, V *vp = nullptr) const
+  {
+    V v = (*this)[k];
+    if (vp) *vp = v;
+    return v != SENTINEL;
+  }
+  /* Projection. */
+  V operator () (K k) const { return get (k); }
+
+  void clear ()
+  {
+    if (unlikely (hb_object_is_immutable (this)))
+      return;
+    if (items)
+      for (auto &_ : hb_iter (items, mask + 1))
+        _.clear ();
+
+    population = occupancy = 0;
+  }
+
+  bool is_empty () const { return population == 0; }
+
+  unsigned int get_population () const { return population; }
+
+  /*
+   * Iterator
+   */
+  auto iter () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::get_pair)
+  )
+  auto keys () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::key)
+    | hb_map (hb_ridentity)
+  )
+  auto values () const HB_AUTO_RETURN
+  (
+    + hb_array (items, mask ? mask + 1 : 0)
+    | hb_filter (&item_t::is_real)
+    | hb_map (&item_t::value)
+    | hb_map (hb_ridentity)
+  )
+
+  /* Sink interface. */
+  hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
+  { set (v.first, v.second); return *this; }
+
+  protected:
+
+  void set_with_hash (K key, uint32_t hash, V value)
   {
     if (unlikely (!successful)) return;
-    if (unlikely (key == INVALID)) return;
+    if (unlikely (key == kINVALID)) return;
     if ((occupancy + occupancy / 2) >= mask && !resize ()) return;
-    unsigned int i = bucket_for (key);
+    unsigned int i = bucket_for_hash (key, hash);
 
-    if (value == INVALID && items[i].key != key)
+    if (value == vINVALID && items[i].key != key)
       return; /* Trying to delete non-existent key. */
 
     if (!items[i].is_unused ())
@@ -145,55 +233,32 @@
 
     items[i].key = key;
     items[i].value = value;
+    items[i].hash = hash;
 
     occupancy++;
     if (!items[i].is_tombstone ())
       population++;
-
-  }
-  hb_codepoint_t get (hb_codepoint_t key) const
-  {
-    if (unlikely (!items)) return INVALID;
-    unsigned int i = bucket_for (key);
-    return items[i].key == key ? items[i].value : INVALID;
   }
 
-  void del (hb_codepoint_t key) { set (key, INVALID); }
-
-  bool has (hb_codepoint_t key) const
-  { return get (key) != INVALID; }
-
-  hb_codepoint_t operator [] (unsigned int key) const
-  { return get (key); }
-
-  static constexpr hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID;
-
-  void clear ()
+  unsigned int bucket_for (K key) const
   {
-    memset (items, 0xFF, ((size_t) mask + 1) * sizeof (item_t));
-    population = occupancy = 0;
+    return bucket_for_hash (key, hb_hash (key));
   }
 
-  bool is_empty () const { return population == 0; }
-
-  unsigned int get_population () const { return population; }
-
-  protected:
-
-  unsigned int bucket_for (hb_codepoint_t key) const
+  unsigned int bucket_for_hash (K key, uint32_t hash) const
   {
-    unsigned int i = Hash (key) % prime;
+    unsigned int i = hash % prime;
     unsigned int step = 0;
-    unsigned int tombstone = INVALID;
+    unsigned int tombstone = (unsigned) -1;
     while (!items[i].is_unused ())
     {
-      if (items[i].key == key)
+      if (items[i].hash == hash && items[i] == key)
         return i;
-      if (tombstone == INVALID && items[i].is_tombstone ())
+      if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
         tombstone = i;
       i = (i + ++step) & mask;
     }
-    return tombstone == INVALID ? i : tombstone;
+    return tombstone == (unsigned) -1 ? i : tombstone;
   }
 
   static unsigned int prime_for (unsigned int shift)
@@ -248,5 +313,14 @@
   }
 };
 
+/*
+ * hb_map_t
+ */
+
+struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
+                               hb_codepoint_t,
+                               HB_MAP_VALUE_INVALID,
+                               HB_MAP_VALUE_INVALID> {};
+
 
 #endif /* HB_MAP_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-meta.hh b/src/java.desktop/share/native/libharfbuzz/hb-meta.hh
new file mode 100644
index 0000000..ea64416
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-meta.hh
@@ -0,0 +1,410 @@
+/*
+ * Copyright © 2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_META_HH
+#define HB_META_HH
+
+#include "hb.hh"
+
+
+/*
+ * C++ template meta-programming & fundamentals used with them.
+ */
+
+/* Void!  For when we need a expression-type of void. */
+struct hb_empty_t {};
+
+/* https://en.cppreference.com/w/cpp/types/void_t */
+template<typename... Ts> struct _hb_void_t { typedef void type; };
+template<typename... Ts> using hb_void_t = typename _hb_void_t<Ts...>::type;
+
+template<typename Head, typename... Ts> struct _hb_head_t { typedef Head type; };
+template<typename... Ts> using hb_head_t = typename _hb_head_t<Ts...>::type;
+
+template <typename T, T v> struct hb_integral_constant { static constexpr T value = v; };
+template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
+using hb_true_type = hb_bool_constant<true>;
+using hb_false_type = hb_bool_constant<false>;
+
+
+/* Basic type SFINAE. */
+
+template <bool B, typename T = void> struct hb_enable_if {};
+template <typename T>                struct hb_enable_if<true, T> { typedef T type; };
+#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type* = nullptr
+/* Concepts/Requires alias: */
+#define hb_requires(Cond) hb_enable_if((Cond))
+
+template <typename T, typename T2> struct hb_is_same : hb_false_type {};
+template <typename T>              struct hb_is_same<T, T> : hb_true_type {};
+#define hb_is_same(T, T2) hb_is_same<T, T2>::value
+
+/* Function overloading SFINAE and priority. */
+
+#define HB_RETURN(Ret, E) -> hb_head_t<Ret, decltype ((E))> { return (E); }
+#define HB_AUTO_RETURN(E) -> decltype ((E)) { return (E); }
+#define HB_VOID_RETURN(E) -> hb_void_t<decltype ((E))> { (E); }
+
+template <unsigned Pri> struct hb_priority : hb_priority<Pri - 1> {};
+template <>             struct hb_priority<0> {};
+#define hb_prioritize hb_priority<16> ()
+
+#define HB_FUNCOBJ(x) static_const x HB_UNUSED
+
+
+template <typename T> struct hb_type_identity_t { typedef T type; };
+template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type;
+
+struct
+{
+  template <typename T> constexpr T*
+  operator () (T& arg) const
+  {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+    /* https://en.cppreference.com/w/cpp/memory/addressof */
+    return reinterpret_cast<T*> (
+             &const_cast<char&> (
+                reinterpret_cast<const volatile char&> (arg)));
+#pragma GCC diagnostic pop
+  }
+}
+HB_FUNCOBJ (hb_addressof);
+
+template <typename T> static inline T hb_declval ();
+#define hb_declval(T) (hb_declval<T> ())
+
+template <typename T> struct hb_match_const             : hb_type_identity_t<T>, hb_bool_constant<false>{};
+template <typename T> struct hb_match_const<const T>    : hb_type_identity_t<T>, hb_bool_constant<true> {};
+template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
+template <typename T> using hb_add_const = const T;
+#define hb_is_const(T) hb_match_const<T>::value
+template <typename T> struct hb_match_reference         : hb_type_identity_t<T>, hb_bool_constant<false>{};
+template <typename T> struct hb_match_reference<T &>    : hb_type_identity_t<T>, hb_bool_constant<true> {};
+template <typename T> struct hb_match_reference<T &&>   : hb_type_identity_t<T>, hb_bool_constant<true> {};
+template <typename T> using hb_remove_reference = typename hb_match_reference<T>::type;
+template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<1>) -> hb_type_identity<T&>;
+template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
+template <typename T> using hb_add_lvalue_reference = decltype (_hb_try_add_lvalue_reference<T> (hb_prioritize));
+template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity<T&&>;
+template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
+template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize));
+#define hb_is_reference(T) hb_match_reference<T>::value
+template <typename T> struct hb_match_pointer           : hb_type_identity_t<T>, hb_bool_constant<false>{};
+template <typename T> struct hb_match_pointer<T *>      : hb_type_identity_t<T>, hb_bool_constant<true> {};
+template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
+template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>;
+template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>;
+template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize));
+#define hb_is_pointer(T) hb_match_pointer<T>::value
+
+
+/* TODO Add feature-parity to std::decay. */
+template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;
+
+
+template<bool B, class T, class F>
+struct _hb_conditional { typedef T type; };
+template<class T, class F>
+struct _hb_conditional<false, T, F> { typedef F type; };
+template<bool B, class T, class F>
+using hb_conditional = typename _hb_conditional<B, T, F>::type;
+
+
+template <typename From, typename To>
+struct hb_is_convertible
+{
+  private:
+  static constexpr bool   from_void = hb_is_same (void, hb_decay<From>);
+  static constexpr bool     to_void = hb_is_same (void, hb_decay<To>  );
+  static constexpr bool either_void = from_void || to_void;
+  static constexpr bool   both_void = from_void && to_void;
+
+  static hb_true_type impl2 (hb_conditional<to_void, int, To>);
+
+  template <typename T>
+  static auto impl (hb_priority<1>) -> decltype (impl2 (hb_declval (T)));
+  template <typename T>
+  static hb_false_type impl (hb_priority<0>);
+  public:
+  static constexpr bool value = both_void ||
+                       (!either_void &&
+                        decltype (impl<hb_conditional<from_void, int, From>> (hb_prioritize))::value);
+};
+#define hb_is_convertible(From,To) hb_is_convertible<From, To>::value
+
+template <typename Base, typename Derived>
+using hb_is_base_of = hb_is_convertible<hb_decay<Derived> *, hb_decay<Base> *>;
+#define hb_is_base_of(Base,Derived) hb_is_base_of<Base, Derived>::value
+
+template <typename From, typename To>
+using hb_is_cr_convertible = hb_bool_constant<
+  hb_is_same (hb_decay<From>, hb_decay<To>) &&
+  (!hb_is_const (From) || hb_is_const (To)) &&
+  (!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To))
+>;
+#define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value
+
+/* std::move and std::forward */
+
+template <typename T>
+static constexpr hb_remove_reference<T>&& hb_move (T&& t) { return (hb_remove_reference<T>&&) (t); }
+
+template <typename T>
+static constexpr T&& hb_forward (hb_remove_reference<T>& t) { return (T&&) t; }
+template <typename T>
+static constexpr T&& hb_forward (hb_remove_reference<T>&& t) { return (T&&) t; }
+
+struct
+{
+  template <typename T> constexpr auto
+  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
+
+  template <typename T> constexpr auto
+  operator () (T *v) const HB_AUTO_RETURN (*v)
+}
+HB_FUNCOBJ (hb_deref);
+
+struct
+{
+  template <typename T> constexpr auto
+  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
+
+  template <typename T> constexpr auto
+  operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v))
+}
+HB_FUNCOBJ (hb_ref);
+
+template <typename T>
+struct hb_reference_wrapper
+{
+  hb_reference_wrapper (T v) : v (v) {}
+  bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
+  bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
+  operator T () const { return v; }
+  T get () const { return v; }
+  T v;
+};
+template <typename T>
+struct hb_reference_wrapper<T&>
+{
+  hb_reference_wrapper (T& v) : v (hb_addressof (v)) {}
+  bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
+  bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
+  operator T& () const { return *v; }
+  T& get () const { return *v; }
+  T* v;
+};
+
+
+template <typename T>
+using hb_is_integral = hb_bool_constant<
+  hb_is_same (hb_decay<T>, char) ||
+  hb_is_same (hb_decay<T>, signed char) ||
+  hb_is_same (hb_decay<T>, unsigned char) ||
+  hb_is_same (hb_decay<T>, signed int) ||
+  hb_is_same (hb_decay<T>, unsigned int) ||
+  hb_is_same (hb_decay<T>, signed short) ||
+  hb_is_same (hb_decay<T>, unsigned short) ||
+  hb_is_same (hb_decay<T>, signed long) ||
+  hb_is_same (hb_decay<T>, unsigned long) ||
+  hb_is_same (hb_decay<T>, signed long long) ||
+  hb_is_same (hb_decay<T>, unsigned long long) ||
+  false
+>;
+#define hb_is_integral(T) hb_is_integral<T>::value
+template <typename T>
+using hb_is_floating_point = hb_bool_constant<
+  hb_is_same (hb_decay<T>, float) ||
+  hb_is_same (hb_decay<T>, double) ||
+  hb_is_same (hb_decay<T>, long double) ||
+  false
+>;
+#define hb_is_floating_point(T) hb_is_floating_point<T>::value
+template <typename T>
+using hb_is_arithmetic = hb_bool_constant<
+  hb_is_integral (T) ||
+  hb_is_floating_point (T) ||
+  false
+>;
+#define hb_is_arithmetic(T) hb_is_arithmetic<T>::value
+
+
+template <typename T>
+using hb_is_signed = hb_conditional<hb_is_arithmetic (T),
+                                    hb_bool_constant<(T) -1 < (T) 0>,
+                                    hb_false_type>;
+#define hb_is_signed(T) hb_is_signed<T>::value
+template <typename T>
+using hb_is_unsigned = hb_conditional<hb_is_arithmetic (T),
+                                      hb_bool_constant<(T) 0 < (T) -1>,
+                                      hb_false_type>;
+#define hb_is_unsigned(T) hb_is_unsigned<T>::value
+
+template <typename T> struct hb_int_min;
+template <> struct hb_int_min<char>                     : hb_integral_constant<char,                    CHAR_MIN>       {};
+template <> struct hb_int_min<signed char>              : hb_integral_constant<signed char,             SCHAR_MIN>      {};
+template <> struct hb_int_min<unsigned char>            : hb_integral_constant<unsigned char,           0>              {};
+template <> struct hb_int_min<signed short>             : hb_integral_constant<signed short,            SHRT_MIN>       {};
+template <> struct hb_int_min<unsigned short>           : hb_integral_constant<unsigned short,          0>              {};
+template <> struct hb_int_min<signed int>               : hb_integral_constant<signed int,              INT_MIN>        {};
+template <> struct hb_int_min<unsigned int>             : hb_integral_constant<unsigned int,            0>              {};
+template <> struct hb_int_min<signed long>              : hb_integral_constant<signed long,             LONG_MIN>       {};
+template <> struct hb_int_min<unsigned long>            : hb_integral_constant<unsigned long,           0>              {};
+template <> struct hb_int_min<signed long long>         : hb_integral_constant<signed long long,        LLONG_MIN>      {};
+template <> struct hb_int_min<unsigned long long>       : hb_integral_constant<unsigned long long,      0>              {};
+#define hb_int_min(T) hb_int_min<T>::value
+template <typename T> struct hb_int_max;
+template <> struct hb_int_max<char>                     : hb_integral_constant<char,                    CHAR_MAX>       {};
+template <> struct hb_int_max<signed char>              : hb_integral_constant<signed char,             SCHAR_MAX>      {};
+template <> struct hb_int_max<unsigned char>            : hb_integral_constant<unsigned char,           UCHAR_MAX>      {};
+template <> struct hb_int_max<signed short>             : hb_integral_constant<signed short,            SHRT_MAX>       {};
+template <> struct hb_int_max<unsigned short>           : hb_integral_constant<unsigned short,          USHRT_MAX>      {};
+template <> struct hb_int_max<signed int>               : hb_integral_constant<signed int,              INT_MAX>        {};
+template <> struct hb_int_max<unsigned int>             : hb_integral_constant<unsigned int,            UINT_MAX>       {};
+template <> struct hb_int_max<signed long>              : hb_integral_constant<signed long,             LONG_MAX>       {};
+template <> struct hb_int_max<unsigned long>            : hb_integral_constant<unsigned long,           ULONG_MAX>      {};
+template <> struct hb_int_max<signed long long>         : hb_integral_constant<signed long long,        LLONG_MAX>      {};
+template <> struct hb_int_max<unsigned long long>       : hb_integral_constant<unsigned long long,      ULLONG_MAX>     {};
+#define hb_int_max(T) hb_int_max<T>::value
+
+
+
+template <typename T, typename>
+struct _hb_is_destructible : hb_false_type {};
+template <typename T>
+struct _hb_is_destructible<T, hb_void_t<decltype (hb_declval (T).~T ())>> : hb_true_type {};
+template <typename T>
+using hb_is_destructible = _hb_is_destructible<T, void>;
+#define hb_is_destructible(T) hb_is_destructible<T>::value
+
+template <typename T, typename, typename ...Ts>
+struct _hb_is_constructible : hb_false_type {};
+template <typename T, typename ...Ts>
+struct _hb_is_constructible<T, hb_void_t<decltype (T (hb_declval (Ts)...))>, Ts...> : hb_true_type {};
+template <typename T, typename ...Ts>
+using hb_is_constructible = _hb_is_constructible<T, void, Ts...>;
+#define hb_is_constructible(...) hb_is_constructible<__VA_ARGS__>::value
+
+template <typename T>
+using hb_is_default_constructible = hb_is_constructible<T>;
+#define hb_is_default_constructible(T) hb_is_default_constructible<T>::value
+
+template <typename T>
+using hb_is_copy_constructible = hb_is_constructible<T, hb_add_lvalue_reference<hb_add_const<T>>>;
+#define hb_is_copy_constructible(T) hb_is_copy_constructible<T>::value
+
+template <typename T>
+using hb_is_move_constructible = hb_is_constructible<T, hb_add_rvalue_reference<hb_add_const<T>>>;
+#define hb_is_move_constructible(T) hb_is_move_constructible<T>::value
+
+template <typename T, typename U, typename>
+struct _hb_is_assignable : hb_false_type {};
+template <typename T, typename U>
+struct _hb_is_assignable<T, U, hb_void_t<decltype (hb_declval (T) = hb_declval (U))>> : hb_true_type {};
+template <typename T, typename U>
+using hb_is_assignable = _hb_is_assignable<T, U, void>;
+#define hb_is_assignable(T,U) hb_is_assignable<T, U>::value
+
+template <typename T>
+using hb_is_copy_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
+                                               hb_add_lvalue_reference<hb_add_const<T>>>;
+#define hb_is_copy_assignable(T) hb_is_copy_assignable<T>::value
+
+template <typename T>
+using hb_is_move_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
+                                               hb_add_rvalue_reference<T>>;
+#define hb_is_move_assignable(T) hb_is_move_assignable<T>::value
+
+/* Trivial versions. */
+
+template <typename T> union hb_trivial { T value; };
+
+template <typename T>
+using hb_is_trivially_destructible= hb_is_destructible<hb_trivial<T>>;
+#define hb_is_trivially_destructible(T) hb_is_trivially_destructible<T>::value
+
+/* Don't know how to do the following. */
+//template <typename T, typename ...Ts>
+//using hb_is_trivially_constructible= hb_is_constructible<hb_trivial<T>, hb_trivial<Ts>...>;
+//#define hb_is_trivially_constructible(...) hb_is_trivially_constructible<__VA_ARGS__>::value
+
+template <typename T>
+using hb_is_trivially_default_constructible= hb_is_default_constructible<hb_trivial<T>>;
+#define hb_is_trivially_default_constructible(T) hb_is_trivially_default_constructible<T>::value
+
+template <typename T>
+using hb_is_trivially_copy_constructible= hb_is_copy_constructible<hb_trivial<T>>;
+#define hb_is_trivially_copy_constructible(T) hb_is_trivially_copy_constructible<T>::value
+
+template <typename T>
+using hb_is_trivially_move_constructible= hb_is_move_constructible<hb_trivial<T>>;
+#define hb_is_trivially_move_constructible(T) hb_is_trivially_move_constructible<T>::value
+
+/* Don't know how to do the following. */
+//template <typename T, typename U>
+//using hb_is_trivially_assignable= hb_is_assignable<hb_trivial<T>, hb_trivial<U>>;
+//#define hb_is_trivially_assignable(T,U) hb_is_trivially_assignable<T, U>::value
+
+template <typename T>
+using hb_is_trivially_copy_assignable= hb_is_copy_assignable<hb_trivial<T>>;
+#define hb_is_trivially_copy_assignable(T) hb_is_trivially_copy_assignable<T>::value
+
+template <typename T>
+using hb_is_trivially_move_assignable= hb_is_move_assignable<hb_trivial<T>>;
+#define hb_is_trivially_move_assignable(T) hb_is_trivially_move_assignable<T>::value
+
+template <typename T>
+using hb_is_trivially_copyable= hb_bool_constant<
+  hb_is_trivially_destructible (T) &&
+  (!hb_is_move_assignable (T) || hb_is_trivially_move_assignable (T)) &&
+  (!hb_is_move_constructible (T) || hb_is_trivially_move_constructible (T)) &&
+  (!hb_is_copy_assignable (T) || hb_is_trivially_copy_assignable (T)) &&
+  (!hb_is_copy_constructible (T) || hb_is_trivially_copy_constructible (T)) &&
+  true
+>;
+#define hb_is_trivially_copyable(T) hb_is_trivially_copyable<T>::value
+
+template <typename T>
+using hb_is_trivial= hb_bool_constant<
+  hb_is_trivially_copyable (T) &&
+  hb_is_trivially_default_constructible (T)
+>;
+#define hb_is_trivial(T) hb_is_trivial<T>::value
+
+/* hb_unwrap_type (T)
+ * If T has no T::type, returns T. Otherwise calls itself on T::type recursively.
+ */
+
+template <typename T, typename>
+struct _hb_unwrap_type : hb_type_identity_t<T> {};
+template <typename T>
+struct _hb_unwrap_type<T, hb_void_t<typename T::type>> : _hb_unwrap_type<typename T::type, void> {};
+template <typename T>
+using hb_unwrap_type = _hb_unwrap_type<T, void>;
+#define hb_unwrap_type(T) typename hb_unwrap_type<T>::type
+
+#endif /* HB_META_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh b/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh
index 1582b40..f2d2962 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh
@@ -48,21 +48,6 @@
 /* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
 
 
-#elif !defined(HB_NO_MT) && defined(_WIN32)
-
-#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)
-
-
 #elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
 
 #include <pthread.h>
@@ -74,6 +59,20 @@
 #define hb_mutex_impl_finish(M) pthread_mutex_destroy (M)
 
 
+#elif !defined(HB_NO_MT) && defined(_WIN32)
+
+typedef CRITICAL_SECTION hb_mutex_impl_t;
+#define HB_MUTEX_IMPL_INIT      {0}
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#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)
+
+
 #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
 
 #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
@@ -92,25 +91,7 @@
 #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
 
 
-#elif !defined(HB_NO_MT)
-
-#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
-# include <sched.h>
-# define HB_SCHED_YIELD() sched_yield ()
-#else
-# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
-#endif
-
-#define HB_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */
-typedef volatile int hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT      0
-#define hb_mutex_impl_init(M)   *(M) = 0
-#define hb_mutex_impl_lock(M)   HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END
-#define hb_mutex_impl_unlock(M) (*(M))--;
-#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
-
-
-#else /* HB_NO_MT */
+#elif defined(HB_NO_MT)
 
 typedef int hb_mutex_impl_t;
 #define HB_MUTEX_IMPL_INIT      0
@@ -120,6 +101,11 @@
 #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
 
 
+#else
+
+#error "Could not find any system to define mutex macros."
+#error "Check hb-mutex.hh for possible resolutions."
+
 #endif
 
 
@@ -127,8 +113,6 @@
 
 struct hb_mutex_t
 {
-  /* TODO Add tracing. */
-
   hb_mutex_impl_t m;
 
   void init   () { hb_mutex_impl_init   (&m); }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-null.hh b/src/java.desktop/share/native/libharfbuzz/hb-null.hh
index 8a0e2d7..d2bc332 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-null.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-null.hh
@@ -28,6 +28,7 @@
 #define HB_NULL_HH
 
 #include "hb.hh"
+#include "hb-meta.hh"
 
 
 /*
@@ -36,7 +37,7 @@
 
 /* Global nul-content Null pool.  Enlarge as necessary. */
 
-#define HB_NULL_POOL_SIZE 9880
+#define HB_NULL_POOL_SIZE 384
 
 /* Use SFINAE to sniff whether T has min_size; in which case return T::null_size,
  * otherwise return sizeof(T). */
@@ -45,18 +46,13 @@
  * https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol
  */
 
-template<bool> struct _hb_bool_type {};
-
-template <typename T, typename B>
-struct _hb_null_size
-{ enum { value = sizeof (T) }; };
+template <typename T, typename>
+struct _hb_null_size : hb_integral_constant<unsigned, sizeof (T)> {};
 template <typename T>
-struct _hb_null_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
-{ enum { value = T::null_size }; };
+struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::null_size> {};
 
 template <typename T>
-struct hb_null_size
-{ enum { value = _hb_null_size<T, _hb_bool_type<true> >::value }; };
+using hb_null_size = _hb_null_size<T, void>;
 #define hb_null_size(T) hb_null_size<T>::value
 
 /* These doesn't belong here, but since is copy/paste from above, put it here. */
@@ -64,56 +60,36 @@
 /* hb_static_size (T)
  * Returns T::static_size if T::min_size is defined, or sizeof (T) otherwise. */
 
-template <typename T, typename B>
-struct _hb_static_size
-{ enum { value = sizeof (T) }; };
+template <typename T, typename>
+struct _hb_static_size : hb_integral_constant<unsigned, sizeof (T)> {};
 template <typename T>
-struct _hb_static_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
-{ enum { value = T::static_size }; };
-
+struct _hb_static_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::static_size> {};
 template <typename T>
-struct hb_static_size
-{ enum { value = _hb_static_size<T, _hb_bool_type<true> >::value }; };
+using hb_static_size = _hb_static_size<T, void>;
 #define hb_static_size(T) hb_static_size<T>::value
 
 
-/* hb_assign (obj, value)
- * Calls obj.set (value) if obj.min_size is defined and value has different type
- * from obj, or obj = v otherwise. */
-
-template <typename T, typename V, typename B>
-struct _hb_assign
-{ static inline void value (T &o, const V v) { o = v; } };
-template <typename T, typename V>
-struct _hb_assign<T, V, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
-{ static inline void value (T &o, const V v) { o.set (v); } };
-template <typename T>
-struct _hb_assign<T, T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
-{ static inline void value (T &o, const T v) { o = v; } };
-
-template <typename T, typename V>
-static inline void hb_assign (T &o, const V v)
-{ _hb_assign<T, V, _hb_bool_type<true> >::value (o, v); }
-
-
 /*
  * Null()
  */
 
 extern HB_INTERNAL
-hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
+uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
 
 /* Generic nul-content Null objects. */
 template <typename Type>
-static inline Type const & Null () {
-  static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
-  return *reinterpret_cast<Type const *> (_hb_NullPool);
-}
+struct Null {
+  static Type const & get_null ()
+  {
+    static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
+    return *reinterpret_cast<Type const *> (_hb_NullPool);
+  }
+};
 template <typename QType>
 struct NullHelper
 {
-  typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type;
-  static const Type & get_null () { return Null<Type> (); }
+  typedef hb_remove_const<hb_remove_reference<QType>> Type;
+  static const Type & get_null () { return Null<Type>::get_null (); }
 };
 #define Null(Type) NullHelper<Type>::get_null ()
 
@@ -122,11 +98,13 @@
         } /* Close namespace. */ \
         extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \
         template <> \
-        /*static*/ inline const Namespace::Type& Null<Namespace::Type> () { \
-          return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
-        } \
+        struct Null<Namespace::Type> { \
+          static Namespace::Type const & get_null () { \
+            return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
+          } \
+        }; \
         namespace Namespace { \
-        static_assert (true, "Just so we take semicolon after.")
+        static_assert (true, "") /* Require semicolon after. */
 #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
         const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]
 
@@ -134,10 +112,12 @@
 #define DECLARE_NULL_INSTANCE(Type) \
         extern HB_INTERNAL const Type _hb_Null_##Type; \
         template <> \
-        /*static*/ inline const Type& Null<Type> () { \
-          return _hb_Null_##Type; \
-        } \
-static_assert (true, "Just so we take semicolon after.")
+        struct Null<Type> { \
+          static Type const & get_null () { \
+            return _hb_Null_##Type; \
+          } \
+        }; \
+        static_assert (true, "") /* Require semicolon after. */
 #define DEFINE_NULL_INSTANCE(Type) \
         const Type _hb_Null_##Type
 
@@ -148,31 +128,31 @@
  * causing bad memory access. So, races there are not actually introducing incorrectness
  * in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */
 extern HB_INTERNAL
-/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
+/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
 
 /* CRAP pool: Common Region for Access Protection. */
 template <typename Type>
 static inline Type& Crap () {
   static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
   Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
-  memcpy (obj, &Null(Type), sizeof (*obj));
+  memcpy (obj, &Null (Type), sizeof (*obj));
   return *obj;
 }
 template <typename QType>
 struct CrapHelper
 {
-  typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type;
+  typedef hb_remove_const<hb_remove_reference<QType>> Type;
   static Type & get_crap () { return Crap<Type> (); }
 };
 #define Crap(Type) CrapHelper<Type>::get_crap ()
 
 template <typename Type>
 struct CrapOrNullHelper {
-  static Type & get () { return Crap(Type); }
+  static Type & get () { return Crap (Type); }
 };
 template <typename Type>
 struct CrapOrNullHelper<const Type> {
-  static const Type & get () { return Null(Type); }
+  static const Type & get () { return Null (Type); }
 };
 #define CrapOrNull(Type) CrapOrNullHelper<Type>::get ()
 
@@ -184,7 +164,7 @@
 template <typename P>
 struct hb_nonnull_ptr_t
 {
-  typedef typename hb_remove_pointer (P) T;
+  typedef hb_remove_pointer<P> T;
 
   hb_nonnull_ptr_t (T *v_ = nullptr) : v (v_) {}
   T * operator = (T *v_)   { return v = v_; }
@@ -194,7 +174,7 @@
   /* Only auto-cast to const types. */
   template <typename C> operator const C * () const { return get (); }
   operator const char * () const { return (const char *) get (); }
-  T * get () const { return v ? v : const_cast<T *> (&Null(T)); }
+  T * get () const { return v ? v : const_cast<T *> (&Null (T)); }
   T * get_raw () const { return v; }
 
   T *v;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
new file mode 100644
index 0000000..9d2867e
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
@@ -0,0 +1,237 @@
+
+#line 1 "hb-number-parser.rl"
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#ifndef HB_NUMBER_PARSER_HH
+#define HB_NUMBER_PARSER_HH
+
+#include "hb.hh"
+
+
+#line 35 "hb-number-parser.hh"
+static const unsigned char _double_parser_trans_keys[] = {
+        0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
+        46u, 101u, 0
+};
+
+static const char _double_parser_key_spans[] = {
+        0, 15, 12, 10, 15, 10, 54, 10,
+        56
+};
+
+static const unsigned char _double_parser_index_offsets[] = {
+        0, 0, 16, 29, 40, 56, 67, 122,
+        133
+};
+
+static const char _double_parser_indicies[] = {
+        0, 1, 2, 3, 1, 4, 4,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        1, 3, 1, 4, 4, 4, 4, 4,
+        4, 4, 4, 4, 4, 1, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5,
+        1, 6, 1, 7, 1, 1, 8, 8,
+        8, 8, 8, 8, 8, 8, 8, 8,
+        1, 8, 8, 8, 8, 8, 8, 8,
+        8, 8, 8, 1, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 9, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 9, 1, 8, 8, 8, 8, 8,
+        8, 8, 8, 8, 8, 1, 3, 1,
+        4, 4, 4, 4, 4, 4, 4, 4,
+        4, 4, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 9, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 9, 1, 0
+};
+
+static const char _double_parser_trans_targs[] = {
+        2, 0, 2, 3, 8, 6, 5, 5,
+        7, 4
+};
+
+static const char _double_parser_trans_actions[] = {
+        0, 0, 1, 0, 2, 3, 0, 4,
+        5, 0
+};
+
+static const int double_parser_start = 1;
+static const int double_parser_first_final = 6;
+static const int double_parser_error = 0;
+
+static const int double_parser_en_main = 1;
+
+
+#line 68 "hb-number-parser.rl"
+
+
+/* Works only for n < 512 */
+static inline double
+_pow10 (unsigned exponent)
+{
+  static const double _powers_of_10[] =
+  {
+    1.0e+256,
+    1.0e+128,
+    1.0e+64,
+    1.0e+32,
+    1.0e+16,
+    1.0e+8,
+    10000.,
+    100.,
+    10.
+  };
+  unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
+  double result = 1;
+  for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
+    if (exponent & mask) result *= *power;
+  return result;
+}
+
+/* a variant of strtod that also gets end of buffer in its second argument */
+static inline double
+strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
+{
+  double value = 0;
+  double frac = 0;
+  double frac_count = 0;
+  unsigned exp = 0;
+  bool neg = false, exp_neg = false, exp_overflow = false;
+  const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */
+  const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */
+
+  const char *pe = *end_ptr;
+  while (p < pe && ISSPACE (*p))
+    p++;
+
+  int cs;
+
+#line 139 "hb-number-parser.hh"
+        {
+        cs = double_parser_start;
+        }
+
+#line 144 "hb-number-parser.hh"
+        {
+        int _slen;
+        int _trans;
+        const unsigned char *_keys;
+        const char *_inds;
+        if ( p == pe )
+                goto _test_eof;
+        if ( cs == 0 )
+                goto _out;
+_resume:
+        _keys = _double_parser_trans_keys + (cs<<1);
+        _inds = _double_parser_indicies + _double_parser_index_offsets[cs];
+
+        _slen = _double_parser_key_spans[cs];
+        _trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+                (*p) <= _keys[1] ?
+                (*p) - _keys[0] : _slen ];
+
+        cs = _double_parser_trans_targs[_trans];
+
+        if ( _double_parser_trans_actions[_trans] == 0 )
+                goto _again;
+
+        switch ( _double_parser_trans_actions[_trans] ) {
+        case 1:
+#line 37 "hb-number-parser.rl"
+        { neg = true; }
+        break;
+        case 4:
+#line 38 "hb-number-parser.rl"
+        { exp_neg = true; }
+        break;
+        case 2:
+#line 40 "hb-number-parser.rl"
+        {
+        value = value * 10. + ((*p) - '0');
+}
+        break;
+        case 3:
+#line 43 "hb-number-parser.rl"
+        {
+        if (likely (frac <= MAX_FRACT / 10))
+        {
+          frac = frac * 10. + ((*p) - '0');
+          ++frac_count;
+        }
+}
+        break;
+        case 5:
+#line 50 "hb-number-parser.rl"
+        {
+        if (likely (exp * 10 + ((*p) - '0') <= MAX_EXP))
+          exp = exp * 10 + ((*p) - '0');
+        else
+          exp_overflow = true;
+}
+        break;
+#line 202 "hb-number-parser.hh"
+        }
+
+_again:
+        if ( cs == 0 )
+                goto _out;
+        if ( ++p != pe )
+                goto _resume;
+        _test_eof: {}
+        _out: {}
+        }
+
+#line 113 "hb-number-parser.rl"
+
+
+  *end_ptr = p;
+
+  if (frac_count) value += frac / _pow10 (frac_count);
+  if (neg) value *= -1.;
+
+  if (unlikely (exp_overflow))
+  {
+    if (value == 0) return value;
+    if (exp_neg)    return neg ? -DBL_MIN : DBL_MIN;
+    else            return neg ? -DBL_MAX : DBL_MAX;
+  }
+
+  if (exp)
+  {
+    if (exp_neg) value /= _pow10 (exp);
+    else         value *= _pow10 (exp);
+  }
+
+  return value;
+}
+
+#endif /* HB_NUMBER_PARSER_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number.cc b/src/java.desktop/share/native/libharfbuzz/hb-number.cc
new file mode 100644
index 0000000..f4ce693
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-number.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#include "hb.hh"
+#include "hb-machinery.hh"
+#include "hb-number.hh"
+#include "hb-number-parser.hh"
+
+template<typename T, typename Func>
+static bool
+_parse_number (const char **pp, const char *end, T *pv,
+               bool whole_buffer, Func f)
+{
+  char buf[32];
+  unsigned len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned) (end - *pp));
+  strncpy (buf, *pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+
+  errno = 0;
+  *pv = f (p, &pend);
+  if (unlikely (errno || p == pend ||
+                /* Check if consumed whole buffer if is requested */
+                (whole_buffer && pend - p != end - *pp)))
+    return false;
+
+  *pp += pend - p;
+  return true;
+}
+
+bool
+hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer)
+{
+  return _parse_number<int> (pp, end, pv, whole_buffer,
+                             [] (const char *p, char **end)
+                             { return strtol (p, end, 10); });
+}
+
+bool
+hb_parse_uint (const char **pp, const char *end, unsigned *pv,
+               bool whole_buffer, int base)
+{
+  return _parse_number<unsigned> (pp, end, pv, whole_buffer,
+                                  [base] (const char *p, char **end)
+                                  { return strtoul (p, end, base); });
+}
+
+bool
+hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer)
+{
+  const char *pend = end;
+  *pv = strtod_rl (*pp, &pend);
+  if (unlikely (*pp == pend)) return false;
+  *pp = pend;
+  return !whole_buffer || end == pend;
+}
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.hh b/src/java.desktop/share/native/libharfbuzz/hb-number.hh
similarity index 69%
copy from src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.hh
copy to src/java.desktop/share/native/libharfbuzz/hb-number.hh
index 385a8f9..47d902c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-number.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018  Google, Inc.
+ * Copyright © 2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -21,20 +21,21 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
- * Google Author(s): Garret Rieger
  */
 
-#ifndef HB_SUBSET_GLYF_HH
-#define HB_SUBSET_GLYF_HH
-
-#include "hb.hh"
-
-#include "hb-subset.hh"
+#ifndef HB_NUMBER_HH
+#define HB_NUMBER_HH
 
 HB_INTERNAL bool
-hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
-                         bool             *use_short_loca, /* OUT */
-                         hb_blob_t       **glyf_prime      /* OUT */,
-                         hb_blob_t       **loca_prime      /* OUT */);
+hb_parse_int (const char **pp, const char *end, int *pv,
+              bool whole_buffer = false);
 
-#endif /* HB_SUBSET_GLYF_HH */
+HB_INTERNAL bool
+hb_parse_uint (const char **pp, const char *end, unsigned int *pv,
+               bool whole_buffer = false, int base = 10);
+
+HB_INTERNAL bool
+hb_parse_double (const char **pp, const char *end, double *pv,
+                 bool whole_buffer = false);
+
+#endif /* HB_NUMBER_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-object.hh b/src/java.desktop/share/native/libharfbuzz/hb-object.hh
index 1d7b6bf..f01508e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-object.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-object.hh
@@ -168,8 +168,8 @@
     void *data;
     hb_destroy_func_t destroy;
 
-    bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; }
-    bool operator == (hb_user_data_item_t &other) const { return key == other.key; }
+    bool operator == (const hb_user_data_key_t *other_key) const { return key == other_key; }
+    bool operator == (const hb_user_data_item_t &other) const { return key == other.key; }
 
     void fini () { if (destroy) destroy (data); }
   };
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh
index 72b2030..95a8f75 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh
@@ -56,7 +56,7 @@
 {
   int cmp (Tag t) const { return -t.cmp (tag); }
 
-  static int cmp (const void *pa, const void *pb)
+  HB_INTERNAL static int cmp (const void *pa, const void *pb)
   {
     const TableRecord *a = (const TableRecord *) pa;
     const TableRecord *b = (const TableRecord *) pb;
@@ -86,27 +86,22 @@
   const TableRecord& get_table (unsigned int i) const
   { return tables[i]; }
   unsigned int get_table_tags (unsigned int  start_offset,
-                                      unsigned int *table_count, /* IN/OUT */
-                                      hb_tag_t     *table_tags /* OUT */) const
+                               unsigned int *table_count, /* IN/OUT */
+                               hb_tag_t     *table_tags /* OUT */) const
   {
     if (table_count)
     {
-      if (start_offset >= tables.len)
-        *table_count = 0;
-      else
-        *table_count = MIN<unsigned int> (*table_count, tables.len - start_offset);
-
-      const TableRecord *sub_tables = tables.arrayZ + start_offset;
-      unsigned int count = *table_count;
-      for (unsigned int i = 0; i < count; i++)
-        table_tags[i] = sub_tables[i].tag;
+      + tables.sub_array (start_offset, table_count)
+      | hb_map (&TableRecord::tag)
+      | hb_sink (hb_array (table_tags, *table_count))
+      ;
     }
     return tables.len;
   }
   bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
   {
     Tag t;
-    t.set (tag);
+    t = tag;
     return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
   }
   const TableRecord& get_table_by_tag (hb_tag_t tag) const
@@ -127,7 +122,7 @@
     /* Alloc 12 for the OTHeader. */
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     /* Write sfntVersion (bytes 0..3). */
-    sfnt_version.set (sfnt_tag);
+    sfnt_version = sfnt_tag;
     /* Take space for numTables, searchRange, entrySelector, RangeShift
      * and the TableRecords themselves.  */
     if (unlikely (!tables.serialize (c, items.length))) return_trace (false);
@@ -140,15 +135,16 @@
     {
       TableRecord &rec = tables.arrayZ[i];
       hb_blob_t *blob = items[i].blob;
-      rec.tag.set (items[i].tag);
-      rec.length.set (hb_blob_get_length (blob));
+      rec.tag = items[i].tag;
+      rec.length = blob->length;
       rec.offset.serialize (c, this);
 
       /* Allocate room for the table and copy it. */
       char *start = (char *) c->allocate_size<void> (rec.length);
-      if (unlikely (!start)) {return false;}
+      if (unlikely (!start)) return false;
 
-      memcpy (start, hb_blob_get_data (blob, nullptr), rec.length);
+      if (likely (rec.length))
+        memcpy (start, blob->data, rec.length);
 
       /* 4-byte alignment. */
       c->align (4);
@@ -159,7 +155,7 @@
       {
         head *h = (head *) start;
         checksum_adjustment = &h->checkSumAdjustment;
-        checksum_adjustment->set (0);
+        *checksum_adjustment = 0;
       }
 
       rec.checkSum.set_for_data (start, end - start);
@@ -177,10 +173,10 @@
       for (unsigned int i = 0; i < items.length; i++)
       {
         TableRecord &rec = tables.arrayZ[i];
-        checksum.set (checksum + rec.checkSum);
+        checksum = checksum + rec.checkSum;
       }
 
-      checksum_adjustment->set (0xB1B0AFBAu - checksum);
+      *checksum_adjustment = 0xB1B0AFBAu - checksum;
     }
 
     return_trace (true);
@@ -222,7 +218,7 @@
   Tag           ttcTag;         /* TrueType Collection ID string: 'ttcf' */
   FixedVersion<>version;        /* Version of the TTC Header (1.0),
                                  * 0x00010000u */
-  LArrayOf<LOffsetTo<OffsetTable> >
+  LArrayOf<LOffsetTo<OffsetTable>>
                 table;          /* Array of offsets to the OffsetTable for each font
                                  * from the beginning of the file */
   public:
@@ -248,7 +244,7 @@
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
     case 1: return u.version1.get_face (i);
-    default:return Null(OpenTypeFontFace);
+    default:return Null (OpenTypeFontFace);
     }
   }
 
@@ -283,10 +279,10 @@
 struct ResourceRecord
 {
   const OpenTypeFontFace & get_face (const void *data_base) const
-  { return CastR<OpenTypeFontFace> ((data_base+offset).arrayZ); }
+  { return * reinterpret_cast<const OpenTypeFontFace *> ((data_base+offset).arrayZ); }
 
   bool sanitize (hb_sanitize_context_t *c,
-                        const void *data_base) const
+                 const void *data_base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
@@ -334,7 +330,7 @@
   protected:
   Tag           tag;            /* Resource type. */
   HBUINT16      resCountM1;     /* Number of resources minus 1. */
-  NNOffsetTo<UnsizedArrayOf<ResourceRecord> >
+  NNOffsetTo<UnsizedArrayOf<ResourceRecord>>
                 resourcesZ;     /* Offset from beginning of resource type list
                                  * to reference item list for this type. */
   public:
@@ -390,7 +386,7 @@
   HBUINT32      reserved1;      /* Reserved for handle to next resource map */
   HBUINT16      resreved2;      /* Reserved for file reference number */
   HBUINT16      attrs;          /* Resource fork attribute */
-  NNOffsetTo<ArrayOfM1<ResourceTypeRecord> >
+  NNOffsetTo<ArrayOfM1<ResourceTypeRecord>>
                 typeList;       /* Offset from beginning of map to
                                  * resource type list */
   Offset16      nameList;       /* Offset from beginning of map to
@@ -422,7 +418,7 @@
   }
 
   protected:
-  LNNOffsetTo<UnsizedArrayOf<HBUINT8> >
+  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
                 data;           /* Offset from beginning of resource fork
                                  * to resource data */
   LNNOffsetTo<ResourceMap >
@@ -477,7 +473,7 @@
     case TrueTypeTag:   return u.fontFace;
     case TTCTag:        return u.ttcHeader.get_face (i);
     case DFontTag:      return u.rfHeader.get_face (i, base_offset);
-    default:            return Null(OpenTypeFontFace);
+    default:            return Null (OpenTypeFontFace);
     }
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh
index 5960993..6241946 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh
@@ -52,22 +52,34 @@
  * Int types
  */
 
-template <bool is_signed> struct hb_signedness_int;
-template <> struct hb_signedness_int<false> { typedef unsigned int value; };
-template <> struct hb_signedness_int<true>  { typedef   signed int value; };
-
 /* Integer types in big-endian order and no alignment requirement */
 template <typename Type, unsigned int Size>
 struct IntType
 {
   typedef Type type;
-  typedef typename hb_signedness_int<hb_is_signed<Type>::value>::value wide_type;
+  typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type;
 
-  void set (wide_type i) { v.set (i); }
+  IntType& operator = (wide_type i) { v = i; return *this; }
   operator wide_type () const { return v; }
-  bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
-  bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
-  static int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
+  bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
+  bool operator != (const IntType &o) const { return !(*this == o); }
+
+  IntType& operator += (unsigned count) { *this = *this + count; return *this; }
+  IntType& operator -= (unsigned count) { *this = *this - count; return *this; }
+  IntType& operator ++ () { *this += 1; return *this; }
+  IntType& operator -- () { *this -= 1; return *this; }
+  IntType operator ++ (int) { IntType c (*this); ++*this; return c; }
+  IntType operator -- (int) { IntType c (*this); --*this; return c; }
+
+  HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
+  { return b->cmp (*a); }
+  HB_INTERNAL static int cmp (const void *a, const void *b)
+  {
+    IntType *pa = (IntType *) a;
+    IntType *pb = (IntType *) b;
+
+    return pb->cmp (*pa);
+  }
   template <typename Type2>
   int cmp (Type2 a) const
   {
@@ -110,19 +122,21 @@
 /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
 struct F2DOT14 : HBINT16
 {
+  F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
   // 16384 means 1<<14
   float to_float () const  { return ((int32_t) v) / 16384.f; }
-  void set_float (float f) { v.set (round (f * 16384.f)); }
+  void set_float (float f) { v = roundf (f * 16384.f); }
   public:
   DEFINE_SIZE_STATIC (2);
 };
 
 /* 32-bit signed fixed-point number (16.16). */
-struct Fixed : HBINT32
+struct HBFixed : HBINT32
 {
+  HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
   // 65536 means 1<<16
   float to_float () const  { return ((int32_t) v) / 65536.f; }
-  void set_float (float f) { v.set (round (f * 65536.f)); }
+  void set_float (float f) { v = roundf (f * 65536.f); }
   public:
   DEFINE_SIZE_STATIC (4);
 };
@@ -147,6 +161,7 @@
  * system, feature, or baseline */
 struct Tag : HBUINT32
 {
+  Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
   /* What the char* converters return is NOT nul-terminated.  Print using "%.4s" */
   operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
   operator char* ()             { return reinterpret_cast<char *> (&this->v); }
@@ -155,11 +170,15 @@
 };
 
 /* Glyph index number, same as uint16 (length = 16 bits) */
-typedef HBUINT16 GlyphID;
+struct HBGlyphID : HBUINT16
+{
+  HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
+};
 
 /* Script/language-system/feature index */
 struct Index : HBUINT16 {
   static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
+  Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
 };
 DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
 
@@ -169,6 +188,8 @@
 template <typename Type, bool has_null=true>
 struct Offset : Type
 {
+  Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; }
+
   typedef Type type;
 
   bool is_null () const { return has_null && 0 == *this; }
@@ -176,7 +197,7 @@
   void *serialize (hb_serialize_context_t *c, const void *base)
   {
     void *t = c->start_embed<void> ();
-    this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
+    c->check_assign (*this, (unsigned) ((char *) t - (char *) base));
     return t;
   }
 
@@ -191,6 +212,8 @@
 /* CheckSum */
 struct CheckSum : HBUINT32
 {
+  CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
+
   /* This is reference implementation from the spec. */
   static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
   {
@@ -205,7 +228,7 @@
 
   /* Note: data should be 4byte aligned and have 4byte padding at the end. */
   void set_for_data (const void *data, unsigned int length)
-  { set (CalcTableChecksum ((const HBUINT32 *) data, length)); }
+  { *this = CalcTableChecksum ((const HBUINT32 *) data, length); }
 
   public:
   DEFINE_SIZE_STATIC (4);
@@ -248,13 +271,18 @@
 template <typename Type>
 struct _hb_has_null<Type, true>
 {
-  static const Type *get_null () { return &Null(Type); }
-  static Type *get_crap ()       { return &Crap(Type); }
+  static const Type *get_null () { return &Null (Type); }
+  static       Type *get_crap () { return &Crap (Type); }
 };
 
 template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
 struct OffsetTo : Offset<OffsetType, has_null>
 {
+  HB_DELETE_COPY_ASSIGN (OffsetTo);
+  OffsetTo () = default;
+
+  OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; }
+
   const Type& operator () (const void *base) const
   {
     if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null ();
@@ -266,24 +294,73 @@
     return StructAtOffset<Type> (base, *this);
   }
 
+  template <typename Base,
+            hb_enable_if (hb_is_convertible (const Base, const void *))>
+  friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
+  template <typename Base,
+            hb_enable_if (hb_is_convertible (const Base, const void *))>
+  friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
+  template <typename Base,
+            hb_enable_if (hb_is_convertible (Base, void *))>
+  friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
+  template <typename Base,
+            hb_enable_if (hb_is_convertible (Base, void *))>
+  friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
+
   Type& serialize (hb_serialize_context_t *c, const void *base)
   {
     return * (Type *) Offset<OffsetType>::serialize (c, base);
   }
 
-  template <typename T>
-  void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
+  template <typename ...Ts>
+  bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
+                         const void *src_base, Ts&&... ds)
   {
-    if (&src == &Null (T))
-    {
-      this->set (0);
-      return;
-    }
-    serialize (c->serializer, base);
-    if (!src.subset (c))
-      this->set (0);
+    *this = 0;
+    if (src.is_null ())
+      return false;
+
+    auto *s = c->serializer;
+
+    s->push ();
+
+    bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...);
+
+    if (ret || !has_null)
+      s->add_link (*this, s->pop_pack ());
+    else
+      s->pop_discard ();
+
+    return ret;
   }
 
+  /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
+  /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
+   * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
+   */
+  template <typename ...Ts>
+  bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
+                       const void *src_base, unsigned dst_bias,
+                       hb_serialize_context_t::whence_t whence,
+                       Ts&&... ds)
+  {
+    *this = 0;
+    if (src.is_null ())
+      return false;
+
+    c->push ();
+
+    bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...);
+
+    c->add_link (*this, c->pop_pack (), whence, dst_bias);
+
+    return ret;
+  }
+
+  bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
+                       const void *src_base, unsigned dst_bias = 0)
+  { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); }
+
   bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -293,39 +370,13 @@
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     return_trace (sanitize_shallow (c, base) &&
                   (this->is_null () ||
-                   StructAtOffset<Type> (base, *this).sanitize (c) ||
-                   neuter (c)));
-  }
-  template <typename T1>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (sanitize_shallow (c, base) &&
-                  (this->is_null () ||
-                   StructAtOffset<Type> (base, *this).sanitize (c, d1) ||
-                   neuter (c)));
-  }
-  template <typename T1, typename T2>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (sanitize_shallow (c, base) &&
-                  (this->is_null () ||
-                   StructAtOffset<Type> (base, *this).sanitize (c, d1, d2) ||
-                   neuter (c)));
-  }
-  template <typename T1, typename T2, typename T3>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (sanitize_shallow (c, base) &&
-                  (this->is_null () ||
-                   StructAtOffset<Type> (base, *this).sanitize (c, d1, d2, d3) ||
+                   c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) ||
                    neuter (c)));
   }
 
@@ -338,14 +389,12 @@
   DEFINE_SIZE_STATIC (sizeof (OffsetType));
 };
 /* Partial specializations. */
-template <typename Type,                               bool has_null=true> struct   LOffsetTo : OffsetTo<Type, HBUINT32,   has_null> {};
-template <typename Type, typename OffsetType=HBUINT16                    > struct  NNOffsetTo : OffsetTo<Type, OffsetType, false> {};
-template <typename Type                                                  > struct LNNOffsetTo : OffsetTo<Type, HBUINT32,   false> {};
-
-template <typename Base, typename OffsetType, bool has_null, typename Type>
-static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
-template <typename Base, typename OffsetType, bool has_null, typename Type>
-static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
+template <typename Type, bool has_null=true>
+using LOffsetTo = OffsetTo<Type, HBUINT32, has_null>;
+template <typename Type, typename OffsetType=HBUINT16>
+using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
+template <typename Type>
+using LNNOffsetTo = LOffsetTo<Type, false>;
 
 
 /*
@@ -358,7 +407,7 @@
   typedef Type item_t;
   static constexpr unsigned item_size = hb_static_size (Type);
 
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type);
+  HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
 
   const Type& operator [] (int i_) const
   {
@@ -384,7 +433,7 @@
   { return hb_array (arrayZ, len); }
   hb_array_t<const Type> as_array (unsigned int len) const
   { return hb_array (arrayZ, len); }
-  operator hb_array_t<Type> ()             { return as_array (); }
+  operator hb_array_t<      Type> ()       { return as_array (); }
   operator hb_array_t<const Type> () const { return as_array (); }
 
   template <typename T>
@@ -393,42 +442,49 @@
   template <typename T>
   const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
   { return *as_array (len).lsearch (x, &not_found); }
+  template <typename T>
+  bool lfind (unsigned int len, const T &x, unsigned *pos = nullptr) const
+  { return as_array (len).lfind (x, pos); }
 
   void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
   { as_array (len).qsort (start, end); }
 
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
-
-    /* Note: for structs that do not reference other structs,
-     * we do not need to call their sanitize() as we already did
-     * a bound check on the aggregate array size.  We just include
-     * a small unreachable expression to make sure the structs
-     * pointed to do have a simple sanitize(), ie. they do not
-     * reference other structs via offsets.
-     */
-    (void) (false && arrayZ[0].sanitize (c));
-
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend (*this, items_len))) return_trace (false);
     return_trace (true);
   }
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, Type))>
+  bool serialize (hb_serialize_context_t *c, Iterator items)
   {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base)))
-        return_trace (false);
+    TRACE_SERIALIZE (this);
+    unsigned count = items.len ();
+    if (unlikely (!serialize (c, count))) return_trace (false);
+    /* TODO Umm. Just exhaust the iterator instead?  Being extra
+     * cautious right now.. */
+    for (unsigned i = 0; i < count; i++, ++items)
+      arrayZ[i] = *items;
     return_trace (true);
   }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
+
+  UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!as_array (count).copy (c))) return_trace (nullptr);
+    return_trace (out);
+  }
+
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
+      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
         return_trace (false);
     return_trace (true);
   }
@@ -440,14 +496,14 @@
   }
 
   public:
-  Type          arrayZ[VAR];
+  Type          arrayZ[HB_VAR_ARRAY];
   public:
   DEFINE_SIZE_UNBOUNDED (0);
 };
 
 /* Unsized array of offset's */
 template <typename Type, typename OffsetType, bool has_null=true>
-struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null> > {};
+using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
 
 /* Unsized array of offsets relative to the beginning of the array itself. */
 template <typename Type, typename OffsetType, bool has_null=true>
@@ -468,17 +524,12 @@
     return this+*p;
   }
 
-
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this)));
-  }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this, user_data)));
+    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>
+                   ::sanitize (c, count, this, hb_forward<Ts> (ds)...)));
   }
 };
 
@@ -501,8 +552,8 @@
   { return *as_array (len).bsearch (x, &not_found); }
   template <typename T>
   bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
-                     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
-                     unsigned int to_store = (unsigned int) -1) const
+              hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+              unsigned int to_store = (unsigned int) -1) const
   { return as_array (len).bfind (x, i, not_found, to_store); }
 };
 
@@ -514,7 +565,7 @@
   typedef Type item_t;
   static constexpr unsigned item_size = hb_static_size (Type);
 
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType);
+  HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf);
 
   const Type& operator [] (int i_) const
   {
@@ -532,74 +583,83 @@
   unsigned int get_size () const
   { return len.static_size + len * Type::static_size; }
 
-  hb_array_t<Type> as_array ()
-  { return hb_array (arrayZ, len); }
-  hb_array_t<const Type> as_array () const
-  { return hb_array (arrayZ, len); }
-  operator hb_array_t<Type> (void)             { return as_array (); }
-  operator hb_array_t<const Type> (void) const { return as_array (); }
+  explicit operator bool () const { return len; }
+
+  void pop () { len--; }
+
+  hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, len); }
+  hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); }
+
+  /* Iterator. */
+  typedef hb_array_t<const Type>   iter_t;
+  typedef hb_array_t<      Type> writer_t;
+    iter_t   iter () const { return as_array (); }
+  writer_t writer ()       { return as_array (); }
+  operator   iter_t () const { return   iter (); }
+  operator writer_t ()       { return writer (); }
 
   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
 
-  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+  hb_success_t serialize (hb_serialize_context_t *c, unsigned items_len)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    len.set (items_len); /* TODO(serialize) Overflow? */
+    c->check_assign (len, items_len);
     if (unlikely (!c->extend (*this))) return_trace (false);
     return_trace (true);
   }
-  template <typename T>
-  bool serialize (hb_serialize_context_t *c, hb_array_t<const T> items)
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, Type))>
+  hb_success_t serialize (hb_serialize_context_t *c, Iterator items)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!serialize (c, items.length))) return_trace (false);
-    for (unsigned int i = 0; i < items.length; i++)
-      hb_assign (arrayZ[i], items[i]);
+    unsigned count = items.len ();
+    if (unlikely (!serialize (c, count))) return_trace (false);
+    /* TODO Umm. Just exhaust the iterator instead?  Being extra
+     * cautious right now.. */
+    for (unsigned i = 0; i < count; i++, ++items)
+      arrayZ[i] = *items;
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  Type* serialize_append (hb_serialize_context_t *c)
   {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return_trace (false);
-
-    /* Note: for structs that do not reference other structs,
-     * we do not need to call their sanitize() as we already did
-     * a bound check on the aggregate array size.  We just include
-     * a small unreachable expression to make sure the structs
-     * pointed to do have a simple sanitize(), ie. they do not
-     * reference other structs via offsets.
-     */
-    (void) (false && arrayZ[0].sanitize (c));
-
-    return_trace (true);
+    TRACE_SERIALIZE (this);
+    len++;
+    if (unlikely (!len || !c->extend (*this)))
+    {
+      len--;
+      return_trace (nullptr);
+    }
+    return_trace (&arrayZ[len - 1]);
   }
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+
+  ArrayOf* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!c->extend_min (out))) return_trace (nullptr);
+    c->check_assign (out->len, len);
+    if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
+    return_trace (out);
+  }
+
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base)))
-        return_trace (false);
-    return_trace (true);
-  }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
+      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
         return_trace (false);
     return_trace (true);
   }
@@ -610,6 +670,9 @@
   template <typename T>
   const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
   { return *as_array ().lsearch (x, &not_found); }
+  template <typename T>
+  bool lfind (const T &x, unsigned *pos = nullptr) const
+  { return as_array ().lfind (x, pos); }
 
   void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
   { as_array ().qsort (start, end); }
@@ -622,20 +685,21 @@
 
   public:
   LenType       len;
-  Type          arrayZ[VAR];
+  Type          arrayZ[HB_VAR_ARRAY];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
-template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
-typedef ArrayOf<HBUINT8, HBUINT8> PString;
+template <typename Type>
+using LArrayOf = ArrayOf<Type, HBUINT32>;
+using PString = ArrayOf<HBUINT8, HBUINT8>;
 
 /* Array of Offset's */
 template <typename Type>
-struct OffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT16> > {};
+using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>;
 template <typename Type>
-struct LOffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT32> > {};
+using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>;
 template <typename Type>
-struct LOffsetLArrayOf : ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32> {};
+using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
 
 /* Array of offsets relative to the beginning of the array itself. */
 template <typename Type>
@@ -661,20 +725,15 @@
     if (unlikely (!out)) return_trace (false);
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
-      out->arrayZ[i].serialize_subset (c, (*this)[i], out);
+      out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out);
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace (OffsetArrayOf<Type>::sanitize (c, this));
-  }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
+    return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
   }
 };
 
@@ -684,7 +743,7 @@
 {
   static constexpr unsigned item_size = Type::static_size;
 
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType);
+  HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf);
 
   const Type& operator [] (int i_) const
   {
@@ -699,34 +758,53 @@
     return arrayZ[i-1];
   }
   unsigned int get_size () const
-  { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; }
+  { return lenP1.static_size + get_length () * Type::static_size; }
 
-  bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const Type> items)
+  unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; }
+
+  hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, get_length ()); }
+  hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); }
+
+  /* Iterator. */
+  typedef hb_array_t<const Type>   iter_t;
+  typedef hb_array_t<      Type> writer_t;
+    iter_t   iter () const { return as_array (); }
+  writer_t writer ()       { return as_array (); }
+  operator   iter_t () const { return   iter (); }
+  operator writer_t ()       { return writer (); }
+
+  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    lenP1.set (items.length + 1); /* TODO(serialize) Overflow? */
+    c->check_assign (lenP1, items_len + 1);
     if (unlikely (!c->extend (*this))) return_trace (false);
-    for (unsigned int i = 0; i < items.length; i++)
-      arrayZ[i] = items[i];
+    return_trace (true);
+  }
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, Type))>
+  bool serialize (hb_serialize_context_t *c, Iterator items)
+  {
+    TRACE_SERIALIZE (this);
+    unsigned count = items.len ();
+    if (unlikely (!serialize (c, count))) return_trace (false);
+    /* TODO Umm. Just exhaust the iterator instead?  Being extra
+     * cautious right now.. */
+    for (unsigned i = 0; i < count; i++, ++items)
+      arrayZ[i] = *items;
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-
-    /* Note: for structs that do not reference other structs,
-     * we do not need to call their sanitize() as we already did
-     * a bound check on the aggregate array size.  We just include
-     * a small unreachable expression to make sure the structs
-     * pointed to do have a simple sanitize(), ie. they do not
-     * reference other structs via offsets.
-     */
-    (void) (false && arrayZ[0].sanitize (c));
-
+    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
+    unsigned int count = get_length ();
+    for (unsigned int i = 0; i < count; i++)
+      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
+        return_trace (false);
     return_trace (true);
   }
 
@@ -740,7 +818,7 @@
 
   public:
   LenType       lenP1;
-  Type          arrayZ[VAR];
+  Type          arrayZ[HB_VAR_ARRAY];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
@@ -749,7 +827,7 @@
 template <typename Type, typename LenType=HBUINT16>
 struct ArrayOfM1
 {
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOfM1, Type, LenType);
+  HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1);
 
   const Type& operator [] (int i_) const
   {
@@ -766,14 +844,14 @@
   unsigned int get_size () const
   { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
 
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     unsigned int count = lenM1 + 1;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
+      if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
         return_trace (false);
     return_trace (true);
   }
@@ -788,7 +866,7 @@
 
   public:
   LenType       lenM1;
-  Type          arrayZ[VAR];
+  Type          arrayZ[HB_VAR_ARRAY];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
@@ -797,21 +875,40 @@
 template <typename Type, typename LenType=HBUINT16>
 struct SortedArrayOf : ArrayOf<Type, LenType>
 {
-  hb_sorted_array_t<Type> as_array ()
-  { return hb_sorted_array (this->arrayZ, this->len); }
-  hb_sorted_array_t<const Type> as_array () const
-  { return hb_sorted_array (this->arrayZ, this->len); }
-  operator hb_sorted_array_t<Type> ()             { return as_array (); }
-  operator hb_sorted_array_t<const Type> () const { return as_array (); }
+  hb_sorted_array_t<      Type> as_array ()       { return hb_sorted_array (this->arrayZ, this->len); }
+  hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); }
 
-  hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_array ().sub_array (start_offset, count);}
-  hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
-  { return as_array ().sub_array (start_offset, count);}
-  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
-  { return as_array ().sub_array (start_offset, count);}
-  hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_array ().sub_array (start_offset, count);}
+  /* Iterator. */
+  typedef hb_sorted_array_t<const Type>   iter_t;
+  typedef hb_sorted_array_t<      Type> writer_t;
+    iter_t   iter () const { return as_array (); }
+  writer_t writer ()       { return as_array (); }
+  operator   iter_t () const { return   iter (); }
+  operator writer_t ()       { return writer (); }
+
+  hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
+  { return as_array ().sub_array (start_offset, count); }
+  hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
+  { return as_array ().sub_array (start_offset, count); }
+  hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
+  { return as_array ().sub_array (start_offset, count); }
+  hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
+  { return as_array ().sub_array (start_offset, count); }
+
+  bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+  {
+    TRACE_SERIALIZE (this);
+    bool ret = ArrayOf<Type, LenType>::serialize (c, items_len);
+    return_trace (ret);
+  }
+  template <typename Iterator,
+            hb_requires (hb_is_sorted_source_of (Iterator, Type))>
+  bool serialize (hb_serialize_context_t *c, Iterator items)
+  {
+    TRACE_SERIALIZE (this);
+    bool ret = ArrayOf<Type, LenType>::serialize (c, items);
+    return_trace (ret);
+  }
 
   template <typename T>
   Type &bsearch (const T &x, Type &not_found = Crap (Type))
@@ -821,8 +918,8 @@
   { return *as_array ().bsearch (x, &not_found); }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-                     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
-                     unsigned int to_store = (unsigned int) -1) const
+              hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+              unsigned int to_store = (unsigned int) -1) const
   { return as_array ().bfind (x, i, not_found, to_store); }
 };
 
@@ -841,15 +938,16 @@
     return_trace (c->check_struct (this));
   }
 
-  void set (unsigned int v)
+  BinSearchHeader& operator = (unsigned int v)
   {
-    len.set (v);
+    len = v;
     assert (len == v);
-    entrySelector.set (MAX (1u, hb_bit_storage (v)) - 1);
-    searchRange.set (16 * (1u << entrySelector));
-    rangeShift.set (v * 16 > searchRange
-                    ? 16 * v - searchRange
-                    : 0);
+    entrySelector = hb_max (1u, hb_bit_storage (v)) - 1;
+    searchRange = 16 * (1u << entrySelector);
+    rangeShift = v * 16 > searchRange
+                 ? 16 * v - searchRange
+                 : 0;
+    return *this;
   }
 
   protected:
@@ -863,7 +961,7 @@
 };
 
 template <typename Type, typename LenType=HBUINT16>
-struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader<LenType> > {};
+using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>;
 
 
 struct VarSizedBinSearchHeader
@@ -893,7 +991,7 @@
 {
   static constexpr unsigned item_size = Type::static_size;
 
-  HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type);
+  HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf);
 
   bool last_is_terminator () const
   {
@@ -928,40 +1026,15 @@
   unsigned int get_size () const
   { return header.static_size + header.nUnits * header.unitSize; }
 
-  bool sanitize (hb_sanitize_context_t *c) const
+  template <typename ...Ts>
+  bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
-
-    /* Note: for structs that do not reference other structs,
-     * we do not need to call their sanitize() as we already did
-     * a bound check on the aggregate array size.  We just include
-     * a small unreachable expression to make sure the structs
-     * pointed to do have a simple sanitize(), ie. they do not
-     * reference other structs via offsets.
-     */
-    (void) (false && StructAtOffset<Type> (&bytesZ, 0).sanitize (c));
-
-    return_trace (true);
-  }
-  bool sanitize (hb_sanitize_context_t *c, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
     unsigned int count = get_length ();
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(*this)[i].sanitize (c, base)))
-        return_trace (false);
-    return_trace (true);
-  }
-  template <typename T>
-  bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c))) return_trace (false);
-    unsigned int count = get_length ();
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(*this)[i].sanitize (c, base, user_data)))
+      if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...)))
         return_trace (false);
     return_trace (true);
   }
@@ -969,18 +1042,15 @@
   template <typename T>
   const Type *bsearch (const T &key) const
   {
-    unsigned int size = header.unitSize;
-    int min = 0, max = (int) get_length () - 1;
-    while (min <= max)
-    {
-      int mid = ((unsigned int) min + (unsigned int) max) / 2;
-      const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size));
-      int c = p->cmp (key);
-      if (c < 0) max = mid - 1;
-      else if (c > 0) min = mid + 1;
-      else return p;
-    }
-    return nullptr;
+    unsigned pos;
+    return hb_bsearch_impl (&pos,
+                            key,
+                            (const void *) bytesZ,
+                            get_length (),
+                            header.unitSize,
+                            _hb_cmp_method<T, Type>)
+           ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize))
+           : nullptr;
   }
 
   private:
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh
index d278e03..2807372 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh
@@ -27,6 +27,7 @@
 #define HB_OT_CFF_COMMON_HH
 
 #include "hb-open-type.hh"
+#include "hb-bimap.hh"
 #include "hb-ot-layout-common.hh"
 #include "hb-cff-interp-dict-common.hh"
 #include "hb-subset-plan.hh"
@@ -37,16 +38,19 @@
 
 #define CFF_UNDEF_CODE  0xFFFFFFFF
 
+using objidx_t = hb_serialize_context_t::objidx_t;
+using whence_t = hb_serialize_context_t::whence_t;
+
 /* utility macro */
 template<typename Type>
-static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset)
-{ return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); }
+static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
+{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
 
-inline unsigned int calcOffSize(unsigned int dataSize)
+inline unsigned int calcOffSize (unsigned int dataSize)
 {
   unsigned int size = 1;
   unsigned int offset = dataSize + 1;
-  while ((offset & ~0xFF) != 0)
+  while (offset & ~0xFF)
   {
     size++;
     offset >>= 8;
@@ -57,8 +61,8 @@
 
 struct code_pair_t
 {
-  hb_codepoint_t  code;
-  hb_codepoint_t  glyph;
+  hb_codepoint_t code;
+  hb_codepoint_t glyph;
 };
 
 typedef hb_vector_t<unsigned char> str_buff_t;
@@ -82,27 +86,20 @@
 template <typename COUNT>
 struct CFFIndex
 {
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
-                          (c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
-                           c->check_array (offsets, offSize, count + 1) &&
-                           c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1))));
-  }
-
   static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
   { return offSize * (count + 1); }
 
   unsigned int offset_array_size () const
   { return calculate_offset_array_size (offSize, count); }
 
-  static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize)
+  CFFIndex *copy (hb_serialize_context_t *c) const
   {
-    if (count == 0)
-      return COUNT::static_size;
-    else
-      return min_size + calculate_offset_array_size (offSize, count) + dataSize;
+    TRACE_SERIALIZE (this);
+    unsigned int size = get_size ();
+    CFFIndex *out = c->allocate_size<CFFIndex> (size);
+    if (likely (out))
+      memcpy (out, this, size);
+    return_trace (out);
   }
 
   bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
@@ -110,7 +107,7 @@
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size ();
     CFFIndex *dest = c->allocate_size<CFFIndex> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
@@ -123,16 +120,16 @@
     if (byteArray.length == 0)
     {
       COUNT *dest = c->allocate_min<COUNT> ();
-      if (unlikely (dest == nullptr)) return_trace (false);
-      dest->set (0);
+      if (unlikely (!dest)) return_trace (false);
+      *dest = 0;
     }
     else
     {
       /* serialize CFFIndex header */
       if (unlikely (!c->extend_min (*this))) return_trace (false);
-      this->count.set (byteArray.length);
-      this->offSize.set (offSize_);
-      if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
+      this->count = byteArray.length;
+      this->offSize = offSize_;
+      if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
         return_trace (false);
 
       /* serialize indices */
@@ -149,9 +146,8 @@
       for (unsigned int i = 0; i < byteArray.length; i++)
       {
         const byte_str_t &bs = byteArray[i];
-        unsigned char  *dest = c->allocate_size<unsigned char> (bs.length);
-        if (unlikely (dest == nullptr))
-          return_trace (false);
+        unsigned char *dest = c->allocate_size<unsigned char> (bs.length);
+        if (unlikely (!dest)) return_trace (false);
         memcpy (dest, &bs[0], bs.length);
       }
     }
@@ -166,14 +162,77 @@
     byteArray.init ();
     byteArray.resize (buffArray.length);
     for (unsigned int i = 0; i < byteArray.length; i++)
-    {
-      byteArray[i] = byte_str_t (buffArray[i].arrayZ (), buffArray[i].length);
-    }
+      byteArray[i] = byte_str_t (buffArray[i].arrayZ, buffArray[i].length);
     bool result = this->serialize (c, offSize_, byteArray);
     byteArray.fini ();
     return result;
   }
 
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator it)
+  {
+    TRACE_SERIALIZE (this);
+    if (it.len () == 0)
+    {
+      COUNT *dest = c->allocate_min<COUNT> ();
+      if (unlikely (!dest)) return_trace (false);
+      *dest = 0;
+    }
+    else
+    {
+      serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; }));
+      for (const byte_str_t &_ : +it)
+        _.copy (c);
+    }
+    return_trace (true);
+  }
+
+  bool serialize (hb_serialize_context_t *c,
+                  const byte_str_array_t &byteArray)
+  { return serialize (c, + hb_iter (byteArray)); }
+
+  bool serialize (hb_serialize_context_t *c,
+                  const str_buff_vec_t &buffArray)
+  {
+    auto it =
+    + hb_iter (buffArray)
+    | hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); })
+    ;
+    return serialize (c, it);
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  bool serialize_header (hb_serialize_context_t *c,
+                        Iterator it)
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned total = + it | hb_reduce (hb_add, 0);
+    unsigned off_size = calcOffSize (total);
+
+    /* serialize CFFIndex header */
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    this->count = it.len ();
+    this->offSize = off_size;
+    if (unlikely (!c->allocate_size<HBUINT8> (off_size * (it.len () + 1))))
+      return_trace (false);
+
+    /* serialize indices */
+    unsigned int offset = 1;
+    unsigned int i = 0;
+    for (unsigned _ : +it)
+    {
+      CFFIndex<COUNT>::set_offset_at (i++, offset);
+      offset += _;
+    }
+    CFFIndex<COUNT>::set_offset_at (i, offset);
+
+    return_trace (true);
+  }
+
   void set_offset_at (unsigned int index, unsigned int offset)
   {
     HBUINT8 *p = offsets + offSize * index + offSize;
@@ -181,7 +240,7 @@
     for (; size; size--)
     {
       --p;
-      p->set (offset & 0xFF);
+      *p = offset & 0xFF;
       offset >>= 8;
     }
   }
@@ -199,37 +258,38 @@
 
   unsigned int length_at (unsigned int index) const
   {
-        if (likely ((offset_at (index + 1) >= offset_at (index)) &&
-                    (offset_at (index + 1) <= offset_at (count))))
-          return offset_at (index + 1) - offset_at (index);
-        else
-          return 0;
+    if (unlikely ((offset_at (index + 1) < offset_at (index)) ||
+                  (offset_at (index + 1) > offset_at (count))))
+      return 0;
+    return offset_at (index + 1) - offset_at (index);
   }
 
   const unsigned char *data_base () const
-  { return (const unsigned char *)this + min_size + offset_array_size (); }
+  { return (const unsigned char *) this + min_size + offset_array_size (); }
 
   unsigned int data_size () const { return HBINT8::static_size; }
 
   byte_str_t operator [] (unsigned int index) const
   {
-    if (likely (index < count))
-      return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
-    else
-      return Null(byte_str_t);
+    if (unlikely (index >= count)) return Null (byte_str_t);
+    return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
   }
 
   unsigned int get_size () const
   {
-    if (this != &Null(CFFIndex))
-    {
-      if (count > 0)
-        return min_size + offset_array_size () + (offset_at (count) - 1);
-      else
-        return count.static_size;  /* empty CFFIndex contains count only */
-    }
-    else
-      return 0;
+    if (this == &Null (CFFIndex)) return 0;
+    if (count > 0)
+      return min_size + offset_array_size () + (offset_at (count) - 1);
+    return count.static_size;  /* empty CFFIndex contains count only */
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely ((c->check_struct (this) && count == 0) || /* empty INDEX */
+                          (c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
+                           c->check_array (offsets, offSize, count + 1) &&
+                           c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1))));
   }
 
   protected:
@@ -245,10 +305,11 @@
   }
 
   public:
-  COUNT     count;      /* Number of object data. Note there are (count+1) offsets */
-  HBUINT8   offSize;      /* The byte size of each offset in the offsets array. */
-  HBUINT8   offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
-  /* HBUINT8 data[VAR];      Object data */
+  COUNT         count;          /* Number of object data. Note there are (count+1) offsets */
+  HBUINT8       offSize;        /* The byte size of each offset in the offsets array. */
+  HBUINT8       offsets[HB_VAR_ARRAY];
+                                /* The array of (count + 1) offsets into objects array (1-base). */
+  /* HBUINT8 data[HB_VAR_ARRAY];        Object data */
   public:
   DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
 };
@@ -260,7 +321,7 @@
   {
     if (likely (index < CFFIndex<COUNT>::count))
       return byte_str_t (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
-    return Null(byte_str_t);
+    return Null (byte_str_t);
   }
 
   template <typename DATA, typename PARAM1, typename PARAM2>
@@ -275,9 +336,9 @@
     TRACE_SERIALIZE (this);
     /* serialize CFFIndex header */
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    this->count.set (dataArrayLen);
-    this->offSize.set (offSize_);
-    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
+    this->count = dataArrayLen;
+    this->offSize = offSize_;
+    if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
       return_trace (false);
 
     /* serialize indices */
@@ -293,112 +354,74 @@
     /* serialize data */
     for (unsigned int i = 0; i < dataArrayLen; i++)
     {
-      TYPE  *dest = c->start_embed<TYPE> ();
-      if (unlikely (dest == nullptr ||
-                    !dest->serialize (c, dataArray[i], param1, param2)))
+      TYPE *dest = c->start_embed<TYPE> ();
+      if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2)))
         return_trace (false);
     }
     return_trace (true);
   }
-
-  /* in parallel to above */
-  template <typename DATA, typename PARAM>
-  static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
-                                                 const DATA *dataArray,
-                                                 unsigned int dataArrayLen,
-                                                 hb_vector_t<unsigned int> &dataSizeArray, /* OUT */
-                                                 const PARAM &param)
-  {
-    /* determine offset size */
-    unsigned int  totalDataSize = 0;
-    for (unsigned int i = 0; i < dataArrayLen; i++)
-    {
-      unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
-      dataSizeArray[i] = dataSize;
-      totalDataSize += dataSize;
-    }
-    offSize_ = calcOffSize (totalDataSize);
-
-    return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize);
-  }
 };
 
 /* Top Dict, Font Dict, Private Dict */
 struct Dict : UnsizedByteStr
 {
-  template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
+  template <typename DICTVAL, typename OP_SERIALIZER, typename ...Ts>
   bool serialize (hb_serialize_context_t *c,
                   const DICTVAL &dictval,
                   OP_SERIALIZER& opszr,
-                  PARAM& param)
+                  Ts&&... ds)
   {
     TRACE_SERIALIZE (this);
     for (unsigned int i = 0; i < dictval.get_count (); i++)
-    {
-      if (unlikely (!opszr.serialize (c, dictval[i], param)))
+      if (unlikely (!opszr.serialize (c, dictval[i], hb_forward<Ts> (ds)...)))
         return_trace (false);
-    }
+
     return_trace (true);
   }
 
-  /* in parallel to above */
-  template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
-  static unsigned int calculate_serialized_size (const DICTVAL &dictval,
-                                                 OP_SERIALIZER& opszr,
-                                                 PARAM& param)
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < dictval.get_count (); i++)
-      size += opszr.calculate_serialized_size (dictval[i], param);
-    return size;
-  }
-
-  template <typename DICTVAL, typename OP_SERIALIZER>
-  static unsigned int calculate_serialized_size (const DICTVAL &dictval,
-                                                 OP_SERIALIZER& opszr)
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < dictval.get_count (); i++)
-      size += opszr.calculate_serialized_size (dictval[i]);
-    return size;
-  }
-
-  template <typename INTTYPE, int minVal, int maxVal>
-  static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, int value, op_code_t intOp)
+  template <typename T, typename V>
+  static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp)
   {
     // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
-    if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value)))
+    if (/*unlikely*/ (!serialize_int<T, V> (c, intOp, value)))
       return false;
 
     TRACE_SERIALIZE (this);
     /* serialize the opcode */
     HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
-    if (unlikely (p == nullptr)) return_trace (false);
+    if (unlikely (!p)) return_trace (false);
     if (Is_OpCode_ESC (op))
     {
-      p->set (OpCode_escape);
+      *p = OpCode_escape;
       op = Unmake_OpCode_ESC (op);
       p++;
     }
-    p->set (op);
+    *p = op;
     return_trace (true);
   }
 
-  static bool serialize_uint4_op (hb_serialize_context_t *c, op_code_t op, int value)
-  { return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
+  template <typename V>
+  static bool serialize_int4_op (hb_serialize_context_t *c, op_code_t op, V value)
+  { return serialize_int_op<HBINT32> (c, op, value, OpCode_longintdict); }
 
-  static bool serialize_uint2_op (hb_serialize_context_t *c, op_code_t op, int value)
-  { return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
+  template <typename V>
+  static bool serialize_int2_op (hb_serialize_context_t *c, op_code_t op, V value)
+  { return serialize_int_op<HBINT16> (c, op, value, OpCode_shortint); }
 
-  static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value)
+  template <typename T, int int_op>
+  static bool serialize_link_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence)
   {
-    return serialize_uint4_op (c, op, value);
+    T &ofs = *(T *) (c->head + OpCode_Size (int_op));
+    if (unlikely (!serialize_int_op<T> (c, op, 0, int_op))) return false;
+    c->add_link (ofs, link, whence);
+    return true;
   }
 
-  static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value)
-  {
-    return serialize_uint2_op (c, op, value);
-  }
+  static bool serialize_link4_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head)
+  { return serialize_link_op<HBINT32, OpCode_longintdict> (c, op, link, whence); }
+
+  static bool serialize_link2_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head)
+  { return serialize_link_op<HBINT16, OpCode_shortint> (c, op, link, whence); }
 };
 
 struct TopDict : Dict {};
@@ -407,155 +430,39 @@
 
 struct table_info_t
 {
-  void init () { offSize = offset = size = 0; }
+  void init () { offset = size = 0; link = 0; }
 
   unsigned int    offset;
   unsigned int    size;
-  unsigned int    offSize;
-};
-
-/* used to remap font index or SID from fullset to subset.
- * set to CFF_UNDEF_CODE if excluded from subset */
-struct remap_t : hb_vector_t<hb_codepoint_t>
-{
-  void init () { SUPER::init (); }
-
-  void fini () { SUPER::fini (); }
-
-  bool reset (unsigned int size)
-  {
-    if (unlikely (!SUPER::resize (size)))
-      return false;
-    for (unsigned int i = 0; i < length; i++)
-      (*this)[i] = CFF_UNDEF_CODE;
-    count = 0;
-    return true;
-  }
-
-  bool identity (unsigned int size)
-  {
-    if (unlikely (!SUPER::resize (size)))
-      return false;
-    unsigned int i;
-    for (i = 0; i < length; i++)
-      (*this)[i] = i;
-    count = i;
-    return true;
-  }
-
-  bool excludes (hb_codepoint_t id) const
-  { return (id < length) && ((*this)[id] == CFF_UNDEF_CODE); }
-
-  bool includes (hb_codepoint_t id) const
-  { return !excludes (id); }
-
-  unsigned int add (unsigned int i)
-  {
-    if ((*this)[i] == CFF_UNDEF_CODE)
-      (*this)[i] = count++;
-    return (*this)[i];
-  }
-
-  hb_codepoint_t get_count () const { return count; }
-
-  protected:
-  hb_codepoint_t  count;
-
-  private:
-  typedef hb_vector_t<hb_codepoint_t> SUPER;
+  objidx_t        link;
 };
 
 template <typename COUNT>
 struct FDArray : CFFIndexOf<COUNT, FontDict>
 {
-  /* used by CFF1 */
-  template <typename DICTVAL, typename OP_SERIALIZER>
+  template <typename DICTVAL, typename INFO, typename Iterator, typename OP_SERIALIZER>
   bool serialize (hb_serialize_context_t *c,
-                  unsigned int offSize_,
-                  const hb_vector_t<DICTVAL> &fontDicts,
+                  Iterator it,
                   OP_SERIALIZER& opszr)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    this->count.set (fontDicts.length);
-    this->offSize.set (offSize_);
-    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1))))
-      return_trace (false);
 
-    /* serialize font dict offsets */
-    unsigned int  offset = 1;
-    unsigned int fid = 0;
-    for (; fid < fontDicts.length; fid++)
-    {
-      CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
-      offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr);
-    }
-    CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
-
-    /* serialize font dicts */
-    for (unsigned int i = 0; i < fontDicts.length; i++)
+    /* serialize INDEX data */
+    hb_vector_t<unsigned> sizes;
+    c->push ();
+    + it
+    | hb_map ([&] (const hb_pair_t<const DICTVAL&, const INFO&> &_)
     {
       FontDict *dict = c->start_embed<FontDict> ();
-      if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i])))
-        return_trace (false);
-    }
-    return_trace (true);
-  }
+                dict->serialize (c, _.first, opszr, _.second);
+                return c->head - (const char*)dict;
+              })
+    | hb_sink (sizes)
+    ;
+    c->pop_pack (false);
 
-  /* used by CFF2 */
-  template <typename DICTVAL, typename OP_SERIALIZER>
-  bool serialize (hb_serialize_context_t *c,
-                  unsigned int offSize_,
-                  const hb_vector_t<DICTVAL> &fontDicts,
-                  unsigned int fdCount,
-                  const remap_t &fdmap,
-                  OP_SERIALIZER& opszr,
-                  const hb_vector_t<table_info_t> &privateInfos)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    this->count.set (fdCount);
-    this->offSize.set (offSize_);
-    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
-      return_trace (false);
-
-    /* serialize font dict offsets */
-    unsigned int  offset = 1;
-    unsigned int  fid = 0;
-    for (unsigned i = 0; i < fontDicts.length; i++)
-      if (fdmap.includes (i))
-      {
-        CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
-        offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
-      }
-    CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
-
-    /* serialize font dicts */
-    for (unsigned int i = 0; i < fontDicts.length; i++)
-      if (fdmap.includes (i))
-      {
-        FontDict *dict = c->start_embed<FontDict> ();
-        if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
-          return_trace (false);
-      }
-    return_trace (true);
-  }
-
-  /* in parallel to above */
-  template <typename OP_SERIALIZER, typename DICTVAL>
-  static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
-                                                 const hb_vector_t<DICTVAL> &fontDicts,
-                                                 unsigned int fdCount,
-                                                 const remap_t &fdmap,
-                                                 OP_SERIALIZER& opszr)
-  {
-    unsigned int dictsSize = 0;
-    for (unsigned int i = 0; i < fontDicts.len; i++)
-      if (fdmap.includes (i))
-        dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
-
-    offSize_ = calcOffSize (dictsSize);
-    return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize);
+    /* serialize INDEX header */
+    return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes)));
   }
 };
 
@@ -574,21 +481,20 @@
   }
 
   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
-  {
-    return (hb_codepoint_t)fds[glyph];
-  }
+  { return (hb_codepoint_t) fds[glyph]; }
 
   unsigned int get_size (unsigned int num_glyphs) const
   { return HBUINT8::static_size * num_glyphs; }
 
-  HBUINT8     fds[VAR];
+  HBUINT8     fds[HB_VAR_ARRAY];
 
-  DEFINE_SIZE_MIN (1);
+  DEFINE_SIZE_MIN (0);
 };
 
 template <typename GID_TYPE, typename FD_TYPE>
-struct FDSelect3_4_Range {
-  bool sanitize (hb_sanitize_context_t *c, const void */*nullptr*/, unsigned int fdcount) const
+struct FDSelect3_4_Range
+{
+  bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const
   {
     TRACE_SANITIZE (this);
     return_trace (first < c->get_num_glyphs () && (fd < fdcount));
@@ -596,12 +502,13 @@
 
   GID_TYPE    first;
   FD_TYPE     fd;
-
+  public:
   DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
 };
 
 template <typename GID_TYPE, typename FD_TYPE>
-struct FDSelect3_4 {
+struct FDSelect3_4
+{
   unsigned int get_size () const
   { return GID_TYPE::static_size * 2 + ranges.get_size (); }
 
@@ -613,10 +520,8 @@
       return_trace (false);
 
     for (unsigned int i = 1; i < nRanges (); i++)
-    {
       if (unlikely (ranges[i - 1].first >= ranges[i].first))
-          return_trace (false);
-    }
+        return_trace (false);
 
     if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
       return_trace (false);
@@ -631,13 +536,13 @@
       if (glyph < ranges[i].first)
         break;
 
-    return (hb_codepoint_t)ranges[i - 1].fd;
+    return (hb_codepoint_t) ranges[i - 1].fd;
   }
 
-  GID_TYPE &nRanges () { return ranges.len; }
-  GID_TYPE nRanges () const { return ranges.len; }
-  GID_TYPE &sentinel ()  { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
-  const GID_TYPE &sentinel () const  { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
+  GID_TYPE        &nRanges ()       { return ranges.len; }
+  GID_TYPE         nRanges () const { return ranges.len; }
+  GID_TYPE       &sentinel ()       { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
+  const GID_TYPE &sentinel () const { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
 
   ArrayOf<FDSelect3_4_Range<GID_TYPE, FD_TYPE>, GID_TYPE> ranges;
   /* GID_TYPE sentinel */
@@ -648,56 +553,60 @@
 typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
 typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
 
-struct FDSelect {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
-  {
-    TRACE_SANITIZE (this);
-
-    return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
-                          (format == 0)?
-                          u.format0.sanitize (c, fdcount):
-                          u.format3.sanitize (c, fdcount)));
-  }
-
+struct FDSelect
+{
   bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size (num_glyphs);
     FDSelect *dest = c->allocate_size<FDSelect> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
 
-  unsigned int calculate_serialized_size (unsigned int num_glyphs) const
-  { return get_size (num_glyphs); }
-
   unsigned int get_size (unsigned int num_glyphs) const
   {
-    unsigned int size = format.static_size;
-    if (format == 0)
-      size += u.format0.get_size (num_glyphs);
-    else
-      size += u.format3.get_size ();
-    return size;
+    switch (format)
+    {
+    case 0: return format.static_size + u.format0.get_size (num_glyphs);
+    case 3: return format.static_size + u.format3.get_size ();
+    default:return 0;
+    }
   }
 
   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
   {
-    if (this == &Null(FDSelect))
-      return 0;
-    if (format == 0)
-      return u.format0.get_fd (glyph);
-    else
-      return u.format3.get_fd (glyph);
+    if (this == &Null (FDSelect)) return 0;
+
+    switch (format)
+    {
+    case 0: return u.format0.get_fd (glyph);
+    case 3: return u.format3.get_fd (glyph);
+    default:return 0;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    switch (format)
+    {
+    case 0: return_trace (u.format0.sanitize (c, fdcount));
+    case 3: return_trace (u.format3.sanitize (c, fdcount));
+    default:return_trace (false);
+    }
   }
 
   HBUINT8       format;
   union {
-    FDSelect0   format0;
-    FDSelect3   format3;
+  FDSelect0     format0;
+  FDSelect3     format3;
   } u;
-
+  public:
   DEFINE_SIZE_MIN (1);
 };
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh
new file mode 100644
index 0000000..65d56ae
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh
@@ -0,0 +1,425 @@
+/*
+ * Copyright © 2019  Adobe, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#ifndef HB_OT_CFF1_STD_STR_HH
+#if 0 /* Make checks happy. */
+#define HB_OT_CFF1_STD_STR_HH
+#include "hb.hh"
+#endif
+
+_S(".notdef")
+_S("space")
+_S("exclam")
+_S("quotedbl")
+_S("numbersign")
+_S("dollar")
+_S("percent")
+_S("ampersand")
+_S("quoteright")
+_S("parenleft")
+_S("parenright")
+_S("asterisk")
+_S("plus")
+_S("comma")
+_S("hyphen")
+_S("period")
+_S("slash")
+_S("zero")
+_S("one")
+_S("two")
+_S("three")
+_S("four")
+_S("five")
+_S("six")
+_S("seven")
+_S("eight")
+_S("nine")
+_S("colon")
+_S("semicolon")
+_S("less")
+_S("equal")
+_S("greater")
+_S("question")
+_S("at")
+_S("A")
+_S("B")
+_S("C")
+_S("D")
+_S("E")
+_S("F")
+_S("G")
+_S("H")
+_S("I")
+_S("J")
+_S("K")
+_S("L")
+_S("M")
+_S("N")
+_S("O")
+_S("P")
+_S("Q")
+_S("R")
+_S("S")
+_S("T")
+_S("U")
+_S("V")
+_S("W")
+_S("X")
+_S("Y")
+_S("Z")
+_S("bracketleft")
+_S("backslash")
+_S("bracketright")
+_S("asciicircum")
+_S("underscore")
+_S("quoteleft")
+_S("a")
+_S("b")
+_S("c")
+_S("d")
+_S("e")
+_S("f")
+_S("g")
+_S("h")
+_S("i")
+_S("j")
+_S("k")
+_S("l")
+_S("m")
+_S("n")
+_S("o")
+_S("p")
+_S("q")
+_S("r")
+_S("s")
+_S("t")
+_S("u")
+_S("v")
+_S("w")
+_S("x")
+_S("y")
+_S("z")
+_S("braceleft")
+_S("bar")
+_S("braceright")
+_S("asciitilde")
+_S("exclamdown")
+_S("cent")
+_S("sterling")
+_S("fraction")
+_S("yen")
+_S("florin")
+_S("section")
+_S("currency")
+_S("quotesingle")
+_S("quotedblleft")
+_S("guillemotleft")
+_S("guilsinglleft")
+_S("guilsinglright")
+_S("fi")
+_S("fl")
+_S("endash")
+_S("dagger")
+_S("daggerdbl")
+_S("periodcentered")
+_S("paragraph")
+_S("bullet")
+_S("quotesinglbase")
+_S("quotedblbase")
+_S("quotedblright")
+_S("guillemotright")
+_S("ellipsis")
+_S("perthousand")
+_S("questiondown")
+_S("grave")
+_S("acute")
+_S("circumflex")
+_S("tilde")
+_S("macron")
+_S("breve")
+_S("dotaccent")
+_S("dieresis")
+_S("ring")
+_S("cedilla")
+_S("hungarumlaut")
+_S("ogonek")
+_S("caron")
+_S("emdash")
+_S("AE")
+_S("ordfeminine")
+_S("Lslash")
+_S("Oslash")
+_S("OE")
+_S("ordmasculine")
+_S("ae")
+_S("dotlessi")
+_S("lslash")
+_S("oslash")
+_S("oe")
+_S("germandbls")
+_S("onesuperior")
+_S("logicalnot")
+_S("mu")
+_S("trademark")
+_S("Eth")
+_S("onehalf")
+_S("plusminus")
+_S("Thorn")
+_S("onequarter")
+_S("divide")
+_S("brokenbar")
+_S("degree")
+_S("thorn")
+_S("threequarters")
+_S("twosuperior")
+_S("registered")
+_S("minus")
+_S("eth")
+_S("multiply")
+_S("threesuperior")
+_S("copyright")
+_S("Aacute")
+_S("Acircumflex")
+_S("Adieresis")
+_S("Agrave")
+_S("Aring")
+_S("Atilde")
+_S("Ccedilla")
+_S("Eacute")
+_S("Ecircumflex")
+_S("Edieresis")
+_S("Egrave")
+_S("Iacute")
+_S("Icircumflex")
+_S("Idieresis")
+_S("Igrave")
+_S("Ntilde")
+_S("Oacute")
+_S("Ocircumflex")
+_S("Odieresis")
+_S("Ograve")
+_S("Otilde")
+_S("Scaron")
+_S("Uacute")
+_S("Ucircumflex")
+_S("Udieresis")
+_S("Ugrave")
+_S("Yacute")
+_S("Ydieresis")
+_S("Zcaron")
+_S("aacute")
+_S("acircumflex")
+_S("adieresis")
+_S("agrave")
+_S("aring")
+_S("atilde")
+_S("ccedilla")
+_S("eacute")
+_S("ecircumflex")
+_S("edieresis")
+_S("egrave")
+_S("iacute")
+_S("icircumflex")
+_S("idieresis")
+_S("igrave")
+_S("ntilde")
+_S("oacute")
+_S("ocircumflex")
+_S("odieresis")
+_S("ograve")
+_S("otilde")
+_S("scaron")
+_S("uacute")
+_S("ucircumflex")
+_S("udieresis")
+_S("ugrave")
+_S("yacute")
+_S("ydieresis")
+_S("zcaron")
+_S("exclamsmall")
+_S("Hungarumlautsmall")
+_S("dollaroldstyle")
+_S("dollarsuperior")
+_S("ampersandsmall")
+_S("Acutesmall")
+_S("parenleftsuperior")
+_S("parenrightsuperior")
+_S("twodotenleader")
+_S("onedotenleader")
+_S("zerooldstyle")
+_S("oneoldstyle")
+_S("twooldstyle")
+_S("threeoldstyle")
+_S("fouroldstyle")
+_S("fiveoldstyle")
+_S("sixoldstyle")
+_S("sevenoldstyle")
+_S("eightoldstyle")
+_S("nineoldstyle")
+_S("commasuperior")
+_S("threequartersemdash")
+_S("periodsuperior")
+_S("questionsmall")
+_S("asuperior")
+_S("bsuperior")
+_S("centsuperior")
+_S("dsuperior")
+_S("esuperior")
+_S("isuperior")
+_S("lsuperior")
+_S("msuperior")
+_S("nsuperior")
+_S("osuperior")
+_S("rsuperior")
+_S("ssuperior")
+_S("tsuperior")
+_S("ff")
+_S("ffi")
+_S("ffl")
+_S("parenleftinferior")
+_S("parenrightinferior")
+_S("Circumflexsmall")
+_S("hyphensuperior")
+_S("Gravesmall")
+_S("Asmall")
+_S("Bsmall")
+_S("Csmall")
+_S("Dsmall")
+_S("Esmall")
+_S("Fsmall")
+_S("Gsmall")
+_S("Hsmall")
+_S("Ismall")
+_S("Jsmall")
+_S("Ksmall")
+_S("Lsmall")
+_S("Msmall")
+_S("Nsmall")
+_S("Osmall")
+_S("Psmall")
+_S("Qsmall")
+_S("Rsmall")
+_S("Ssmall")
+_S("Tsmall")
+_S("Usmall")
+_S("Vsmall")
+_S("Wsmall")
+_S("Xsmall")
+_S("Ysmall")
+_S("Zsmall")
+_S("colonmonetary")
+_S("onefitted")
+_S("rupiah")
+_S("Tildesmall")
+_S("exclamdownsmall")
+_S("centoldstyle")
+_S("Lslashsmall")
+_S("Scaronsmall")
+_S("Zcaronsmall")
+_S("Dieresissmall")
+_S("Brevesmall")
+_S("Caronsmall")
+_S("Dotaccentsmall")
+_S("Macronsmall")
+_S("figuredash")
+_S("hypheninferior")
+_S("Ogoneksmall")
+_S("Ringsmall")
+_S("Cedillasmall")
+_S("questiondownsmall")
+_S("oneeighth")
+_S("threeeighths")
+_S("fiveeighths")
+_S("seveneighths")
+_S("onethird")
+_S("twothirds")
+_S("zerosuperior")
+_S("foursuperior")
+_S("fivesuperior")
+_S("sixsuperior")
+_S("sevensuperior")
+_S("eightsuperior")
+_S("ninesuperior")
+_S("zeroinferior")
+_S("oneinferior")
+_S("twoinferior")
+_S("threeinferior")
+_S("fourinferior")
+_S("fiveinferior")
+_S("sixinferior")
+_S("seveninferior")
+_S("eightinferior")
+_S("nineinferior")
+_S("centinferior")
+_S("dollarinferior")
+_S("periodinferior")
+_S("commainferior")
+_S("Agravesmall")
+_S("Aacutesmall")
+_S("Acircumflexsmall")
+_S("Atildesmall")
+_S("Adieresissmall")
+_S("Aringsmall")
+_S("AEsmall")
+_S("Ccedillasmall")
+_S("Egravesmall")
+_S("Eacutesmall")
+_S("Ecircumflexsmall")
+_S("Edieresissmall")
+_S("Igravesmall")
+_S("Iacutesmall")
+_S("Icircumflexsmall")
+_S("Idieresissmall")
+_S("Ethsmall")
+_S("Ntildesmall")
+_S("Ogravesmall")
+_S("Oacutesmall")
+_S("Ocircumflexsmall")
+_S("Otildesmall")
+_S("Odieresissmall")
+_S("OEsmall")
+_S("Oslashsmall")
+_S("Ugravesmall")
+_S("Uacutesmall")
+_S("Ucircumflexsmall")
+_S("Udieresissmall")
+_S("Yacutesmall")
+_S("Thornsmall")
+_S("Ydieresissmall")
+_S("001.000")
+_S("001.001")
+_S("001.002")
+_S("001.003")
+_S("Black")
+_S("Bold")
+_S("Book")
+_S("Light")
+_S("Medium")
+_S("Regular")
+_S("Roman")
+_S("Semibold")
+
+#endif /* HB_OT_CFF1_STD_STR_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc
index a5ee1f3..2428736 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc
@@ -24,11 +24,29 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_CFF
+
+#include "hb-draw.hh"
+#include "hb-algs.hh"
 #include "hb-ot-cff1-table.hh"
 #include "hb-cff1-interp-cs.hh"
 
 using namespace CFF;
 
+struct sid_to_gid_t
+{
+  uint16_t  sid;
+  uint8_t   gid;
+
+  int cmp (uint16_t a) const
+  {
+    if (a == sid) return 0;
+    return (a < sid) ? -1 : 1;
+  }
+};
+
 /* SID to code */
 static const uint8_t standard_encoding_to_code [] =
 {
@@ -100,6 +118,80 @@
   340,  341,  342,  343,  344,  345,  346
 };
 
+/* SID to glyph ID */
+static const sid_to_gid_t expert_charset_sid_to_gid [] =
+{
+    { 1, 1 },     { 13, 12 },   { 14, 13 },   { 15, 14 },
+    { 27, 26 },   { 28, 27 },   { 99, 15 },   { 109, 46 },
+    { 110, 47 },  { 150, 111 }, { 155, 101 }, { 158, 100 },
+    { 163, 102 }, { 164, 112 }, { 169, 113 }, { 229, 2 },
+    { 230, 3 },   { 231, 4 },   { 232, 5 },   { 233, 6 },
+    { 234, 7 },   { 235, 8 },   { 236, 9 },   { 237, 10 },
+    { 238, 11 },  { 239, 16 },  { 240, 17 },  { 241, 18 },
+    { 242, 19 },  { 243, 20 },  { 244, 21 },  { 245, 22 },
+    { 246, 23 },  { 247, 24 },  { 248, 25 },  { 249, 28 },
+    { 250, 29 },  { 251, 30 },  { 252, 31 },  { 253, 32 },
+    { 254, 33 },  { 255, 34 },  { 256, 35 },  { 257, 36 },
+    { 258, 37 },  { 259, 38 },  { 260, 39 },  { 261, 40 },
+    { 262, 41 },  { 263, 42 },  { 264, 43 },  { 265, 44 },
+    { 266, 45 },  { 267, 48 },  { 268, 49 },  { 269, 50 },
+    { 270, 51 },  { 271, 52 },  { 272, 53 },  { 273, 54 },
+    { 274, 55 },  { 275, 56 },  { 276, 57 },  { 277, 58 },
+    { 278, 59 },  { 279, 60 },  { 280, 61 },  { 281, 62 },
+    { 282, 63 },  { 283, 64 },  { 284, 65 },  { 285, 66 },
+    { 286, 67 },  { 287, 68 },  { 288, 69 },  { 289, 70 },
+    { 290, 71 },  { 291, 72 },  { 292, 73 },  { 293, 74 },
+    { 294, 75 },  { 295, 76 },  { 296, 77 },  { 297, 78 },
+    { 298, 79 },  { 299, 80 },  { 300, 81 },  { 301, 82 },
+    { 302, 83 },  { 303, 84 },  { 304, 85 },  { 305, 86 },
+    { 306, 87 },  { 307, 88 },  { 308, 89 },  { 309, 90 },
+    { 310, 91 },  { 311, 92 },  { 312, 93 },  { 313, 94 },
+    { 314, 95 },  { 315, 96 },  { 316, 97 },  { 317, 98 },
+    { 318, 99 },  { 319, 103 }, { 320, 104 }, { 321, 105 },
+    { 322, 106 }, { 323, 107 }, { 324, 108 }, { 325, 109 },
+    { 326, 110 }, { 327, 114 }, { 328, 115 }, { 329, 116 },
+    { 330, 117 }, { 331, 118 }, { 332, 119 }, { 333, 120 },
+    { 334, 121 }, { 335, 122 }, { 336, 123 }, { 337, 124 },
+    { 338, 125 }, { 339, 126 }, { 340, 127 }, { 341, 128 },
+    { 342, 129 }, { 343, 130 }, { 344, 131 }, { 345, 132 },
+    { 346, 133 }, { 347, 134 }, { 348, 135 }, { 349, 136 },
+    { 350, 137 }, { 351, 138 }, { 352, 139 }, { 353, 140 },
+    { 354, 141 }, { 355, 142 }, { 356, 143 }, { 357, 144 },
+    { 358, 145 }, { 359, 146 }, { 360, 147 }, { 361, 148 },
+    { 362, 149 }, { 363, 150 }, { 364, 151 }, { 365, 152 },
+    { 366, 153 }, { 367, 154 }, { 368, 155 }, { 369, 156 },
+    { 370, 157 }, { 371, 158 }, { 372, 159 }, { 373, 160 },
+    { 374, 161 }, { 375, 162 }, { 376, 163 }, { 377, 164 },
+    { 378, 165 }
+};
+
+/* SID to glyph ID */
+static const sid_to_gid_t expert_subset_charset_sid_to_gid [] =
+{
+  { 1, 1 },       { 13, 8 },      { 14, 9 },      { 15, 10 },
+  { 27, 22 },     { 28, 23 },     { 99, 11 },     { 109, 41 },
+  { 110, 42 },    { 150, 64 },    { 155, 55 },    { 158, 54 },
+  { 163, 56 },    { 164, 65 },    { 169, 66 },    { 231, 2 },
+  { 232, 3 },     { 235, 4 },     { 236, 5 },     { 237, 6 },
+  { 238, 7 },     { 239, 12 },    { 240, 13 },    { 241, 14 },
+  { 242, 15 },    { 243, 16 },    { 244, 17 },    { 245, 18 },
+  { 246, 19 },    { 247, 20 },    { 248, 21 },    { 249, 24 },
+  { 250, 25 },    { 251, 26 },    { 253, 27 },    { 254, 28 },
+  { 255, 29 },    { 256, 30 },    { 257, 31 },    { 258, 32 },
+  { 259, 33 },    { 260, 34 },    { 261, 35 },    { 262, 36 },
+  { 263, 37 },    { 264, 38 },    { 265, 39 },    { 266, 40 },
+  { 267, 43 },    { 268, 44 },    { 269, 45 },    { 270, 46 },
+  { 272, 47 },    { 300, 48 },    { 301, 49 },    { 302, 50 },
+  { 305, 51 },    { 314, 52 },    { 315, 53 },    { 320, 57 },
+  { 321, 58 },    { 322, 59 },    { 323, 60 },    { 324, 61 },
+  { 325, 62 },    { 326, 63 },    { 327, 67 },    { 328, 68 },
+  { 329, 69 },    { 330, 70 },    { 331, 71 },    { 332, 72 },
+  { 333, 73 },    { 334, 74 },    { 335, 75 },    { 336, 76 },
+  { 337, 77 },    { 338, 78 },    { 339, 79 },    { 340, 80 },
+  { 341, 81 },    { 342, 82 },    { 343, 83 },    { 344, 84 },
+  { 345, 85 },    { 346, 86 }
+};
+
 /* code to SID */
 static const uint8_t standard_encoding_to_sid [] =
 {
@@ -153,6 +245,18 @@
     return 0;
 }
 
+hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph (hb_codepoint_t sid)
+{
+  const auto *pair = hb_sorted_array (expert_charset_sid_to_gid).bsearch (sid);
+  return pair ? pair->gid : 0;
+}
+
+hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid)
+{
+  const auto *pair = hb_sorted_array (expert_subset_charset_sid_to_gid).bsearch (sid);
+  return pair ? pair->gid : 0;
+}
+
 hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code)
 {
   if (code < ARRAY_LENGTH (standard_encoding_to_sid))
@@ -165,8 +269,8 @@
 {
   void init ()
   {
-    min.set_int (0x7FFFFFFF, 0x7FFFFFFF);
-    max.set_int (-0x80000000, -0x80000000);
+    min.set_int (INT_MAX, INT_MAX);
+    max.set_int (INT_MIN, INT_MIN);
   }
 
   void update (const point_t &pt)
@@ -199,14 +303,13 @@
     }
   }
 
-  bool empty () const
-  { return (min.x >= max.x) || (min.y >= max.y); }
+  bool empty () const { return (min.x >= max.x) || (min.y >= max.y); }
 
   point_t min;
   point_t max;
 };
 
-struct extents_param_t
+struct cff1_extents_param_t
 {
   void init (const OT::cff1::accelerator_t *_cff)
   {
@@ -215,25 +318,25 @@
     bounds.init ();
   }
 
-  void start_path ()         { path_open = true; }
-  void end_path ()           { path_open = false; }
+  void start_path   ()       { path_open = true; }
+  void end_path     ()       { path_open = false; }
   bool is_path_open () const { return path_open; }
 
-  bool    path_open;
-  bounds_t  bounds;
+  bool path_open;
+  bounds_t bounds;
 
   const OT::cff1::accelerator_t *cff;
 };
 
-struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, extents_param_t>
+struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
 {
-  static void moveto (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt)
+  static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt)
   {
     param.end_path ();
     env.moveto (pt);
   }
 
-  static void line (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1)
+  static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1)
   {
     if (!param.is_path_open ())
     {
@@ -244,7 +347,7 @@
     param.bounds.update (env.get_pt ());
   }
 
-  static void curve (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
+  static void curve (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
   {
     if (!param.is_path_open ())
     {
@@ -261,9 +364,9 @@
 
 static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
 
-struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, extents_param_t, cff1_path_procs_extents_t>
+struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
 {
-  static void process_seac (cff1_cs_interp_env_t &env, extents_param_t& param)
+  static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param)
   {
     unsigned int  n = env.argStack.get_count ();
     point_t delta;
@@ -292,20 +395,25 @@
   if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
 
   unsigned int fd = cff->fdSelect->get_fd (glyph);
-  cff1_cs_interpreter_t<cff1_cs_opset_extents_t, extents_param_t> interp;
+  cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp;
   const byte_str_t str = (*cff->charStrings)[glyph];
   interp.env.init (str, *cff, fd);
   interp.env.set_in_seac (in_seac);
-  extents_param_t  param;
+  cff1_extents_param_t  param;
   param.init (cff);
   if (unlikely (!interp.interpret (param))) return false;
   bounds = param.bounds;
   return true;
 }
 
-bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
 {
-  bounds_t  bounds;
+#ifdef HB_NO_OT_FONT_CFF
+  /* XXX Remove check when this code moves to .hh file. */
+  return true;
+#endif
+
+  bounds_t bounds;
 
   if (!_get_bounds (this, glyph, bounds))
     return false;
@@ -317,8 +425,8 @@
   }
   else
   {
-    extents->x_bearing = (int32_t)bounds.min.x.floor ();
-    extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing;
+    extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ());
+    extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ());
   }
   if (bounds.min.y >= bounds.max.y)
   {
@@ -327,13 +435,137 @@
   }
   else
   {
-    extents->y_bearing = (int32_t)bounds.max.y.ceil ();
-    extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing;
+    extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ());
+    extents->height = font->em_scalef_y (bounds.min.y.to_real () - bounds.max.y.to_real ());
   }
 
   return true;
 }
 
+#ifdef HB_EXPERIMENTAL_API
+struct cff1_path_param_t
+{
+  cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
+                     draw_helper_t &draw_helper_, point_t *delta_)
+  {
+    draw_helper = &draw_helper_;
+    cff = cff_;
+    font = font_;
+    delta = delta_;
+  }
+
+  void move_to (const point_t &p)
+  {
+    point_t point = p;
+    if (delta) point.move (*delta);
+    draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
+  }
+
+  void line_to (const point_t &p)
+  {
+    point_t point = p;
+    if (delta) point.move (*delta);
+    draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
+  }
+
+  void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
+  {
+    point_t point1 = p1, point2 = p2, point3 = p3;
+    if (delta)
+    {
+      point1.move (*delta);
+      point2.move (*delta);
+      point3.move (*delta);
+    }
+    draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()),
+                           font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()),
+                           font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ()));
+  }
+
+  void end_path () { draw_helper->end_path (); }
+
+  hb_font_t *font;
+  draw_helper_t *draw_helper;
+  point_t *delta;
+
+  const OT::cff1::accelerator_t *cff;
+};
+
+struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
+{
+  static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
+  {
+    param.move_to (pt);
+    env.moveto (pt);
+  }
+
+  static void line (cff1_cs_interp_env_t &env, cff1_path_param_t &param, const point_t &pt1)
+  {
+    param.line_to (pt1);
+    env.moveto (pt1);
+  }
+
+  static void curve (cff1_cs_interp_env_t &env, cff1_path_param_t &param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
+  {
+    param.cubic_to (pt1, pt2, pt3);
+    env.moveto (pt3);
+  }
+};
+
+static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
+                       draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr);
+
+struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
+{
+  static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
+  {
+    /* End previous path */
+    param.end_path ();
+
+    unsigned int n = env.argStack.get_count ();
+    point_t delta;
+    delta.x = env.argStack[n-4];
+    delta.y = env.argStack[n-3];
+    hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
+    hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
+
+    if (unlikely (!(!env.in_seac && base && accent
+                    && _get_path (param.cff, param.font, base, *param.draw_helper, true)
+                    && _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta))))
+      env.set_error ();
+  }
+};
+
+bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
+                draw_helper_t &draw_helper, bool in_seac, point_t *delta)
+{
+  if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
+
+  unsigned int fd = cff->fdSelect->get_fd (glyph);
+  cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp;
+  const byte_str_t str = (*cff->charStrings)[glyph];
+  interp.env.init (str, *cff, fd);
+  interp.env.set_in_seac (in_seac);
+  cff1_path_param_t param (cff, font, draw_helper, delta);
+  if (unlikely (!interp.interpret (param))) return false;
+
+  /* Let's end the path specially since it is called inside seac also */
+  param.end_path ();
+
+  return true;
+}
+
+bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
+{
+#ifdef HB_NO_OT_FONT_CFF
+  /* XXX Remove check when this code moves to .hh file. */
+  return true;
+#endif
+
+  return _get_path (this, font, glyph, draw_helper);
+}
+#endif
+
 struct get_seac_param_t
 {
   void init (const OT::cff1::accelerator_t *_cff)
@@ -383,3 +615,6 @@
   }
   return false;
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh
index 73258e7..6768e4ea1 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh
@@ -27,15 +27,21 @@
 #ifndef HB_OT_CFF1_TABLE_HH
 #define HB_OT_CFF1_TABLE_HH
 
-#include "hb-ot-head-table.hh"
 #include "hb-ot-cff-common.hh"
 #include "hb-subset-cff1.hh"
+#include "hb-draw.hh"
+
+#define HB_STRING_ARRAY_NAME cff1_std_strings
+#define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh"
+#include "hb-string-array.hh"
+#undef HB_STRING_ARRAY_LIST
+#undef HB_STRING_ARRAY_NAME
 
 namespace CFF {
 
 /*
  * CFF -- Compact Font Format (CFF)
- * http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
+ * https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
  */
 #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
 
@@ -49,7 +55,6 @@
 
 typedef CFFIndex<HBUINT16> CFF1Index;
 typedef CFF1Index          CFF1CharStrings;
-typedef FDArray<HBUINT16>  CFF1FDArray;
 typedef Subrs<HBUINT16>    CFF1Subrs;
 
 struct CFF1FDSelect : FDSelect {};
@@ -59,14 +64,14 @@
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && codes[nCodes - 1].sanitize (c));
+    return_trace (codes.sanitize (c));
   }
 
   hb_codepoint_t get_code (hb_codepoint_t glyph) const
   {
     assert (glyph > 0);
     glyph--;
-    if (glyph < nCodes)
+    if (glyph < nCodes ())
     {
       return (hb_codepoint_t)codes[glyph];
     }
@@ -74,13 +79,12 @@
       return CFF_UNDEF_CODE;
   }
 
-  unsigned int get_size () const
-  { return HBUINT8::static_size * (nCodes + 1); }
+  HBUINT8 &nCodes () { return codes.len; }
+  HBUINT8 nCodes () const { return codes.len; }
 
-  HBUINT8     nCodes;
-  HBUINT8     codes[VAR];
+  ArrayOf<HBUINT8, HBUINT8> codes;
 
-  DEFINE_SIZE_ARRAY(1, codes);
+  DEFINE_SIZE_ARRAY_SIZED (1, codes);
 };
 
 struct Encoding1_Range {
@@ -97,34 +101,34 @@
 };
 
 struct Encoding1 {
-  unsigned int get_size () const
-  { return HBUINT8::static_size + Encoding1_Range::static_size * nRanges; }
-
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c)));
+    return_trace (ranges.sanitize (c));
   }
 
   hb_codepoint_t get_code (hb_codepoint_t glyph) const
   {
     assert (glyph > 0);
     glyph--;
-    for (unsigned int i = 0; i < nRanges; i++)
+    for (unsigned int i = 0; i < nRanges (); i++)
     {
       if (glyph <= ranges[i].nLeft)
       {
-        return (hb_codepoint_t)ranges[i].first + glyph;
+        hb_codepoint_t code = (hb_codepoint_t) ranges[i].first + glyph;
+        return (likely (code < 0x100) ? code: CFF_UNDEF_CODE);
       }
       glyph -= (ranges[i].nLeft + 1);
     }
     return CFF_UNDEF_CODE;
   }
 
-  HBUINT8          nRanges;
-  Encoding1_Range   ranges[VAR];
+  HBUINT8 &nRanges () { return ranges.len; }
+  HBUINT8 nRanges () const { return ranges.len; }
 
-  DEFINE_SIZE_ARRAY (1, ranges);
+  ArrayOf<Encoding1_Range, HBUINT8> ranges;
+
+  DEFINE_SIZE_ARRAY_SIZED (1, ranges);
 };
 
 struct SuppEncoding {
@@ -144,47 +148,33 @@
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && ((nSups == 0) || (supps[nSups - 1]).sanitize (c)));
+    return_trace (supps.sanitize (c));
   }
 
   void get_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const
   {
-    for (unsigned int i = 0; i < nSups; i++)
+    for (unsigned int i = 0; i < nSups (); i++)
       if (sid == supps[i].glyph)
         codes.push (supps[i].code);
   }
 
-  unsigned int get_size () const
-  { return HBUINT8::static_size + SuppEncoding::static_size * nSups; }
+  HBUINT8 &nSups () { return supps.len; }
+  HBUINT8 nSups () const { return supps.len; }
 
-  HBUINT8        nSups;
-  SuppEncoding   supps[VAR];
+  ArrayOf<SuppEncoding, HBUINT8> supps;
 
-  DEFINE_SIZE_ARRAY (1, supps);
+  DEFINE_SIZE_ARRAY_SIZED (1, supps);
 };
 
-struct Encoding {
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-
-    if (unlikely (!c->check_struct (this)))
-      return_trace (false);
-    unsigned int fmt = format & 0x7F;
-    if (unlikely (fmt > 1))
-      return_trace (false);
-    if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c))))
-      return_trace (false);
-    return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c));
-  }
-
+struct Encoding
+{
   /* serialize a fullset Encoding */
   bool serialize (hb_serialize_context_t *c, const Encoding &src)
   {
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size ();
     Encoding *dest = c->allocate_size<Encoding> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
@@ -198,72 +188,66 @@
   {
     TRACE_SERIALIZE (this);
     Encoding *dest = c->extend_min (*this);
-    if (unlikely (dest == nullptr)) return_trace (false);
-    dest->format.set (format | ((supp_codes.length > 0)? 0x80: 0));
-    if (format == 0)
+    if (unlikely (!dest)) return_trace (false);
+    dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0);
+    switch (format) {
+    case 0:
     {
       Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count);
-    if (unlikely (fmt0 == nullptr)) return_trace (false);
-      fmt0->nCodes.set (enc_count);
+      if (unlikely (!fmt0)) return_trace (false);
+      fmt0->nCodes () = enc_count;
       unsigned int glyph = 0;
       for (unsigned int i = 0; i < code_ranges.length; i++)
       {
         hb_codepoint_t code = code_ranges[i].code;
         for (int left = (int)code_ranges[i].glyph; left >= 0; left--)
-          fmt0->codes[glyph++].set (code++);
+          fmt0->codes[glyph++] = code++;
         if (unlikely (!((glyph <= 0x100) && (code <= 0x100))))
           return_trace (false);
       }
     }
-    else
+    break;
+
+    case 1:
     {
       Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length);
-      if (unlikely (fmt1 == nullptr)) return_trace (false);
-      fmt1->nRanges.set (code_ranges.length);
+      if (unlikely (!fmt1)) return_trace (false);
+      fmt1->nRanges () = code_ranges.length;
       for (unsigned int i = 0; i < code_ranges.length; i++)
       {
         if (unlikely (!((code_ranges[i].code <= 0xFF) && (code_ranges[i].glyph <= 0xFF))))
           return_trace (false);
-        fmt1->ranges[i].first.set (code_ranges[i].code);
-        fmt1->ranges[i].nLeft.set (code_ranges[i].glyph);
+        fmt1->ranges[i].first = code_ranges[i].code;
+        fmt1->ranges[i].nLeft = code_ranges[i].glyph;
       }
     }
-    if (supp_codes.length > 0)
+    break;
+
+    }
+
+    if (supp_codes.length)
     {
       CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length);
-      if (unlikely (suppData == nullptr)) return_trace (false);
-      suppData->nSups.set (supp_codes.length);
+      if (unlikely (!suppData)) return_trace (false);
+      suppData->nSups () = supp_codes.length;
       for (unsigned int i = 0; i < supp_codes.length; i++)
       {
-        suppData->supps[i].code.set (supp_codes[i].code);
-        suppData->supps[i].glyph.set (supp_codes[i].glyph); /* actually SID */
+        suppData->supps[i].code = supp_codes[i].code;
+        suppData->supps[i].glyph = supp_codes[i].glyph; /* actually SID */
       }
     }
-    return_trace (true);
-  }
 
-  /* parallel to above: calculate the size of a subset Encoding */
-  static unsigned int calculate_serialized_size (uint8_t format,
-                                                 unsigned int enc_count,
-                                                 unsigned int supp_count)
-  {
-    unsigned int  size = min_size;
-    if (format == 0)
-      size += Encoding0::min_size + HBUINT8::static_size * enc_count;
-    else
-      size += Encoding1::min_size + Encoding1_Range::static_size * enc_count;
-    if (supp_count > 0)
-      size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count;
-    return size;
+    return_trace (true);
   }
 
   unsigned int get_size () const
   {
     unsigned int size = min_size;
-    if (table_format () == 0)
-      size += u.format0.get_size ();
-    else
-      size += u.format1.get_size ();
+    switch (table_format ())
+    {
+    case 0: size += u.format0.get_size (); break;
+    case 1: size += u.format1.get_size (); break;
+    }
     if (has_supplement ())
       size += suppEncData ().get_size ();
     return size;
@@ -271,14 +255,16 @@
 
   hb_codepoint_t get_code (hb_codepoint_t glyph) const
   {
-    if (table_format () == 0)
-      return u.format0.get_code (glyph);
-    else
-      return u.format1.get_code (glyph);
+    switch (table_format ())
+    {
+    case 0: return u.format0.get_code (glyph);
+    case 1: return u.format1.get_code (glyph);
+    default:return 0;
+    }
   }
 
-  uint8_t table_format () const { return (format & 0x7F); }
-  bool  has_supplement () const { return (format & 0x80) != 0; }
+  uint8_t table_format () const { return format & 0x7F; }
+  bool  has_supplement () const { return format & 0x80; }
 
   void get_supplement_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const
   {
@@ -287,21 +273,37 @@
       suppEncData().get_codes (sid, codes);
   }
 
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    switch (table_format ())
+    {
+    case 0: if (unlikely (!u.format0.sanitize (c))) { return_trace (false); } break;
+    case 1: if (unlikely (!u.format1.sanitize (c))) { return_trace (false); } break;
+    default:return_trace (false);
+    }
+    return_trace (likely (!has_supplement () || suppEncData ().sanitize (c)));
+  }
+
   protected:
   const CFF1SuppEncData &suppEncData () const
   {
-    if ((format & 0x7F) == 0)
-      return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes-1]);
-    else
-      return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges-1]);
+    switch (table_format ())
+    {
+    case 0: return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes ()-1]);
+    case 1: return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges ()-1]);
+    default:return Null (CFF1SuppEncData);
+    }
   }
 
   public:
   HBUINT8       format;
-
   union {
-    Encoding0   format0;
-    Encoding1   format1;
+  Encoding0     format0;
+  Encoding1     format1;
   } u;
   /* CFF1SuppEncData  suppEncData; */
 
@@ -343,7 +345,7 @@
     return HBUINT16::static_size * (num_glyphs - 1);
   }
 
-  HBUINT16  sids[VAR];
+  HBUINT16  sids[HB_VAR_ARRAY];
 
   DEFINE_SIZE_ARRAY(0, sids);
 };
@@ -425,7 +427,7 @@
     return size;
   }
 
-  Charset_Range<TYPE>   ranges[VAR];
+  Charset_Range<TYPE>   ranges[HB_VAR_ARRAY];
 
   DEFINE_SIZE_ARRAY (0, ranges);
 };
@@ -435,30 +437,15 @@
 typedef Charset_Range<HBUINT8>  Charset1_Range;
 typedef Charset_Range<HBUINT16> Charset2_Range;
 
-struct Charset {
-  bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-
-    if (unlikely (!c->check_struct (this)))
-      return_trace (false);
-    if (format == 0)
-      return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
-    else if (format == 1)
-      return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
-    else if (likely (format == 2))
-      return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
-    else
-      return_trace (false);
-  }
-
+struct Charset
+{
   /* serialize a fullset Charset */
   bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size (num_glyphs);
     Charset *dest = c->allocate_size<Charset> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
@@ -471,93 +458,103 @@
   {
     TRACE_SERIALIZE (this);
     Charset *dest = c->extend_min (*this);
-    if (unlikely (dest == nullptr)) return_trace (false);
-    dest->format.set (format);
-    if (format == 0)
+    if (unlikely (!dest)) return_trace (false);
+    dest->format = format;
+    switch (format)
+    {
+    case 0:
     {
       Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1));
-    if (unlikely (fmt0 == nullptr)) return_trace (false);
+      if (unlikely (!fmt0)) return_trace (false);
       unsigned int glyph = 0;
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
         hb_codepoint_t sid = sid_ranges[i].code;
         for (int left = (int)sid_ranges[i].glyph; left >= 0; left--)
-          fmt0->sids[glyph++].set (sid++);
+          fmt0->sids[glyph++] = sid++;
       }
     }
-    else if (format == 1)
+    break;
+
+    case 1:
     {
       Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length);
-      if (unlikely (fmt1 == nullptr)) return_trace (false);
+      if (unlikely (!fmt1)) return_trace (false);
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
         if (unlikely (!(sid_ranges[i].glyph <= 0xFF)))
           return_trace (false);
-        fmt1->ranges[i].first.set (sid_ranges[i].code);
-        fmt1->ranges[i].nLeft.set (sid_ranges[i].glyph);
+        fmt1->ranges[i].first = sid_ranges[i].code;
+        fmt1->ranges[i].nLeft = sid_ranges[i].glyph;
       }
     }
-    else /* format 2 */
+    break;
+
+    case 2:
     {
       Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length);
-      if (unlikely (fmt2 == nullptr)) return_trace (false);
+      if (unlikely (!fmt2)) return_trace (false);
       for (unsigned int i = 0; i < sid_ranges.length; i++)
       {
         if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF)))
           return_trace (false);
-        fmt2->ranges[i].first.set (sid_ranges[i].code);
-        fmt2->ranges[i].nLeft.set (sid_ranges[i].glyph);
+        fmt2->ranges[i].first = sid_ranges[i].code;
+        fmt2->ranges[i].nLeft = sid_ranges[i].glyph;
       }
     }
+    break;
+
+    }
     return_trace (true);
   }
 
-  /* parallel to above: calculate the size of a subset Charset */
-  static unsigned int calculate_serialized_size (
-                        uint8_t format,
-                        unsigned int count)
-  {
-    unsigned int  size = min_size;
-    if (format == 0)
-      size += Charset0::min_size + HBUINT16::static_size * (count - 1);
-    else if (format == 1)
-      size += Charset1::min_size + Charset1_Range::static_size * count;
-    else
-      size += Charset2::min_size + Charset2_Range::static_size * count;
-
-    return size;
-  }
-
   unsigned int get_size (unsigned int num_glyphs) const
   {
-    unsigned int size = min_size;
-    if (format == 0)
-      size += u.format0.get_size (num_glyphs);
-    else if (format == 1)
-      size += u.format1.get_size (num_glyphs);
-    else
-      size += u.format2.get_size (num_glyphs);
-    return size;
+    switch (format)
+    {
+    case 0: return min_size + u.format0.get_size (num_glyphs);
+    case 1: return min_size + u.format1.get_size (num_glyphs);
+    case 2: return min_size + u.format2.get_size (num_glyphs);
+    default:return 0;
+    }
   }
 
-  hb_codepoint_t get_sid (hb_codepoint_t glyph) const
+  hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const
   {
-    if (format == 0)
-      return u.format0.get_sid (glyph);
-    else if (format == 1)
-      return u.format1.get_sid (glyph);
-    else
-      return u.format2.get_sid (glyph);
+    if (unlikely (glyph >= num_glyphs)) return 0;
+    switch (format)
+    {
+    case 0: return u.format0.get_sid (glyph);
+    case 1: return u.format1.get_sid (glyph);
+    case 2: return u.format2.get_sid (glyph);
+    default:return 0;
+    }
   }
 
   hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
   {
-    if (format == 0)
-      return u.format0.get_glyph (sid, num_glyphs);
-    else if (format == 1)
-      return u.format1.get_glyph (sid, num_glyphs);
-    else
-      return u.format2.get_glyph (sid, num_glyphs);
+    switch (format)
+    {
+    case 0: return u.format0.get_glyph (sid, num_glyphs);
+    case 1: return u.format1.get_glyph (sid, num_glyphs);
+    case 2: return u.format2.get_glyph (sid, num_glyphs);
+    default:return 0;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    switch (format)
+    {
+    case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
+    case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
+    case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
+    default:return_trace (false);
+    }
   }
 
   HBUINT8       format;
@@ -573,48 +570,32 @@
 struct CFF1StringIndex : CFF1Index
 {
   bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings,
-                  unsigned int offSize_, const remap_t &sidmap)
+                  const hb_inc_bimap_t &sidmap)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0)))
+    if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0)))
     {
-      if (!unlikely (c->extend_min (this->count)))
+      if (unlikely (!c->extend_min (this->count)))
         return_trace (false);
-      count.set (0);
+      count = 0;
       return_trace (true);
     }
 
     byte_str_array_t bytesArray;
     bytesArray.init ();
-    if (!bytesArray.resize (sidmap.get_count ()))
+    if (!bytesArray.resize (sidmap.get_population ()))
       return_trace (false);
     for (unsigned int i = 0; i < strings.count; i++)
     {
       hb_codepoint_t  j = sidmap[i];
-      if (j != CFF_UNDEF_CODE)
+      if (j != HB_MAP_VALUE_INVALID)
         bytesArray[j] = strings[i];
     }
 
-    bool result = CFF1Index::serialize (c, offSize_, bytesArray);
+    bool result = CFF1Index::serialize (c, bytesArray);
     bytesArray.fini ();
     return_trace (result);
   }
-
-  /* in parallel to above */
-  unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const remap_t &sidmap) const
-  {
-    offSize = 0;
-    if ((count == 0) || (sidmap.get_count () == 0))
-      return count.static_size;
-
-    unsigned int dataSize = 0;
-    for (unsigned int i = 0; i < count; i++)
-      if (sidmap[i] != CFF_UNDEF_CODE)
-        dataSize += length_at (i);
-
-    offSize = calcOffSize(dataSize);
-    return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize);
-  }
 };
 
 struct cff1_top_dict_interp_env_t : num_interp_env_t
@@ -717,7 +698,7 @@
   unsigned int    EncodingOffset;
   unsigned int    CharsetOffset;
   unsigned int    FDSelectOffset;
-  table_info_t       privateDictInfo;
+  table_info_t    privateDictInfo;
 };
 
 struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
@@ -859,21 +840,10 @@
   {
     dict_values_t<VAL>::init ();
     subrsOffset = 0;
-    localSubrs = &Null(CFF1Subrs);
+    localSubrs = &Null (CFF1Subrs);
   }
   void fini () { dict_values_t<VAL>::fini (); }
 
-  unsigned int calculate_serialized_size () const
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++)
-      if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs)
-        size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
-      else
-        size += dict_values_t<VAL>::get_value (i).str.length;
-    return size;
-  }
-
   unsigned int      subrsOffset;
   const CFF1Subrs    *localSubrs;
 };
@@ -976,6 +946,37 @@
 typedef CFF1Index CFF1NameIndex;
 typedef CFF1IndexOf<TopDict> CFF1TopDictIndex;
 
+struct cff1_font_dict_values_mod_t
+{
+  cff1_font_dict_values_mod_t() { init (); }
+
+  void init () { init ( &Null (cff1_font_dict_values_t), CFF_UNDEF_SID ); }
+
+  void init (const cff1_font_dict_values_t *base_,
+             unsigned int fontName_)
+  {
+    base = base_;
+    fontName = fontName_;
+    privateDictInfo.init ();
+  }
+
+  unsigned get_count () const { return base->get_count (); }
+
+  const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; }
+
+  const cff1_font_dict_values_t    *base;
+  table_info_t             privateDictInfo;
+  unsigned int          fontName;
+};
+
+struct CFF1FDArray : FDArray<HBUINT16>
+{
+  /* FDArray::serialize() requires this partial specialization to compile */
+  template <typename ITER, typename OP_SERIALIZER>
+  bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr)
+  { return FDArray<HBUINT16>::serialize<cff1_font_dict_values_mod_t, cff1_font_dict_values_mod_t> (c, it, opszr); }
+};
+
 } /* namespace CFF */
 
 namespace OT {
@@ -1010,7 +1011,7 @@
 
       const OT::cff1 *cff = this->blob->template as<OT::cff1> ();
 
-      if (cff == &Null(OT::cff1))
+      if (cff == &Null (OT::cff1))
       { fini (); return; }
 
       nameIndex = &cff->nameIndex (cff);
@@ -1031,7 +1032,7 @@
       }
 
       if (is_predef_charset ())
-        charset = &Null(Charset);
+        charset = &Null (Charset);
       else
       {
         charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
@@ -1043,16 +1044,30 @@
       {
         fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset);
         fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
-        if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) ||
-            (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
+        if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) ||
+            (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
         { fini (); return; }
 
         fdCount = fdArray->count;
       }
       else
       {
-        fdArray = &Null(CFF1FDArray);
-        fdSelect = &Null(CFF1FDSelect);
+        fdArray = &Null (CFF1FDArray);
+        fdSelect = &Null (CFF1FDSelect);
+      }
+
+      encoding = &Null (Encoding);
+      if (is_CID ())
+      {
+        if (unlikely (charset == &Null (Charset))) { fini (); return; }
+      }
+      else
+      {
+        if (!is_predef_encoding ())
+        {
+          encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
+          if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; }
+        }
       }
 
       stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
@@ -1065,14 +1080,15 @@
 
       charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
 
-      if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
+      if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
       { fini (); return; }
 
       num_glyphs = charStrings->count;
       if (num_glyphs != sc.get_num_glyphs ())
       { fini (); return; }
 
-      privateDicts.resize (fdCount);
+      if (unlikely (!privateDicts.resize (fdCount)))
+      { fini (); return; }
       for (unsigned int i = 0; i < fdCount; i++)
         privateDicts[i].init ();
 
@@ -1083,14 +1099,14 @@
         {
           byte_str_t fontDictStr = (*fdArray)[i];
           if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
-          cff1_font_dict_values_t  *font;
+          cff1_font_dict_values_t *font;
           cff1_font_dict_interpreter_t font_interp;
           font_interp.env.init (fontDictStr);
           font = fontDicts.push ();
-          if (unlikely (font == &Crap(cff1_font_dict_values_t))) { fini (); return; }
+          if (unlikely (font == &Crap (cff1_font_dict_values_t))) { fini (); return; }
           font->init ();
           if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
-          PRIVDICTVAL  *priv = &privateDicts[i];
+          PRIVDICTVAL *priv = &privateDicts[i];
           const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
           if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
           dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp;
@@ -1099,15 +1115,15 @@
           if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
 
           priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
-          if (priv->localSubrs != &Null(CFF1Subrs) &&
+          if (priv->localSubrs != &Null (CFF1Subrs) &&
               unlikely (!priv->localSubrs->sanitize (&sc)))
           { fini (); return; }
         }
       }
       else  /* non-CID */
       {
-        cff1_top_dict_values_t  *font = &topDict;
-        PRIVDICTVAL  *priv = &privateDicts[0];
+        cff1_top_dict_values_t *font = &topDict;
+        PRIVDICTVAL *priv = &privateDicts[0];
 
         const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
         if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
@@ -1117,7 +1133,7 @@
         if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
 
         priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
-        if (priv->localSubrs != &Null(CFF1Subrs) &&
+        if (priv->localSubrs != &Null (CFF1Subrs) &&
             unlikely (!priv->localSubrs->sanitize (&sc)))
         { fini (); return; }
       }
@@ -1133,8 +1149,8 @@
       blob = nullptr;
     }
 
-    bool is_valid () const { return blob != nullptr; }
-    bool is_CID () const { return topDict.is_CID (); }
+    bool is_valid () const { return blob; }
+    bool   is_CID () const { return topDict.is_CID (); }
 
     bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; }
 
@@ -1144,85 +1160,34 @@
       if (unlikely (sid == CFF_UNDEF_SID))
         return 0;
 
-      if (charset != &Null(Charset))
+      if (charset != &Null (Charset))
         return charset->get_glyph (sid, num_glyphs);
       else if ((topDict.CharsetOffset == ISOAdobeCharset)
               && (code <= 228 /*zcaron*/)) return sid;
       return 0;
     }
 
-    protected:
-    hb_blob_t          *blob;
-    hb_sanitize_context_t   sc;
-
-    public:
-    const Charset          *charset;
-    const CFF1NameIndex     *nameIndex;
-    const CFF1TopDictIndex  *topDictIndex;
-    const CFF1StringIndex   *stringIndex;
-    const CFF1Subrs      *globalSubrs;
-    const CFF1CharStrings   *charStrings;
-    const CFF1FDArray       *fdArray;
-    const CFF1FDSelect      *fdSelect;
-    unsigned int            fdCount;
-
-    cff1_top_dict_values_t       topDict;
-    hb_vector_t<cff1_font_dict_values_t>   fontDicts;
-    hb_vector_t<PRIVDICTVAL>      privateDicts;
-
-    unsigned int            num_glyphs;
-  };
-
-  struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
-  {
-    HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
-    HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
-  };
-
-  struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t>
-  {
-    void init (hb_face_t *face)
-    {
-      SUPER::init (face);
-      if (blob == nullptr) return;
-
-      const OT::cff1 *cff = this->blob->as<OT::cff1> ();
-      encoding = &Null(Encoding);
-      if (is_CID ())
-      {
-        if (unlikely (charset == &Null(Charset))) { fini (); return; }
-      }
-      else
-      {
-        if (!is_predef_encoding ())
-        {
-          encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
-          if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; }
-        }
-      }
-    }
-
     bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; }
 
-    hb_codepoint_t  glyph_to_code (hb_codepoint_t glyph) const
+    hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const
     {
-      if (encoding != &Null(Encoding))
+      if (encoding != &Null (Encoding))
         return encoding->get_code (glyph);
       else
       {
-        hb_codepoint_t  sid = glyph_to_sid (glyph);
+        hb_codepoint_t sid = glyph_to_sid (glyph);
         if (sid == 0) return 0;
-        hb_codepoint_t  code = 0;
+        hb_codepoint_t code = 0;
         switch (topDict.EncodingOffset)
         {
-          case  StandardEncoding:
-            code = lookup_standard_encoding_for_code (sid);
-            break;
-          case  ExpertEncoding:
-            code = lookup_expert_encoding_for_code (sid);
-            break;
-          default:
-            break;
+        case StandardEncoding:
+          code = lookup_standard_encoding_for_code (sid);
+          break;
+        case ExpertEncoding:
+          code = lookup_expert_encoding_for_code (sid);
+          break;
+        default:
+          break;
         }
         return code;
       }
@@ -1230,20 +1195,20 @@
 
     hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const
     {
-      if (charset != &Null(Charset))
-        return charset->get_sid (glyph);
+      if (charset != &Null (Charset))
+        return charset->get_sid (glyph, num_glyphs);
       else
       {
         hb_codepoint_t sid = 0;
         switch (topDict.CharsetOffset)
         {
-          case  ISOAdobeCharset:
+          case ISOAdobeCharset:
             if (glyph <= 228 /*zcaron*/) sid = glyph;
             break;
-          case  ExpertCharset:
+          case ExpertCharset:
             sid = lookup_expert_charset_for_sid (glyph);
             break;
-          case  ExpertSubsetCharset:
+          case ExpertSubsetCharset:
               sid = lookup_expert_subset_charset_for_sid (glyph);
             break;
           default:
@@ -1253,35 +1218,174 @@
       }
     }
 
-    const Encoding        *encoding;
+    hb_codepoint_t sid_to_glyph (hb_codepoint_t sid) const
+    {
+      if (charset != &Null (Charset))
+        return charset->get_glyph (sid, num_glyphs);
+      else
+      {
+        hb_codepoint_t glyph = 0;
+        switch (topDict.CharsetOffset)
+        {
+          case ISOAdobeCharset:
+            if (sid <= 228 /*zcaron*/) glyph = sid;
+            break;
+          case ExpertCharset:
+            glyph = lookup_expert_charset_for_glyph (sid);
+            break;
+          case ExpertSubsetCharset:
+            glyph = lookup_expert_subset_charset_for_glyph (sid);
+            break;
+          default:
+            break;
+        }
+        return glyph;
+      }
+    }
 
-    private:
-    typedef accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> SUPER;
+    protected:
+    hb_blob_t              *blob;
+    hb_sanitize_context_t   sc;
+
+    public:
+    const Encoding          *encoding;
+    const Charset           *charset;
+    const CFF1NameIndex     *nameIndex;
+    const CFF1TopDictIndex  *topDictIndex;
+    const CFF1StringIndex   *stringIndex;
+    const CFF1Subrs         *globalSubrs;
+    const CFF1CharStrings   *charStrings;
+    const CFF1FDArray       *fdArray;
+    const CFF1FDSelect      *fdSelect;
+    unsigned int             fdCount;
+
+    cff1_top_dict_values_t   topDict;
+    hb_vector_t<cff1_font_dict_values_t>
+                             fontDicts;
+    hb_vector_t<PRIVDICTVAL> privateDicts;
+
+    unsigned int             num_glyphs;
   };
 
-  bool subset (hb_subset_plan_t *plan) const
+  struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
   {
-    hb_blob_t *cff_prime = nullptr;
+    void init (hb_face_t *face)
+    {
+      SUPER::init (face);
 
-    bool success = true;
-    if (hb_subset_cff1 (plan, &cff_prime)) {
-      success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime);
-      hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source);
-      success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob);
-      hb_blob_destroy (head_blob);
-    } else {
-      success = false;
+      if (!is_valid ()) return;
+      if (is_CID ()) return;
+
+      /* fill glyph_names */
+      for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+      {
+        hb_codepoint_t  sid = glyph_to_sid (gid);
+        gname_t gname;
+        gname.sid = sid;
+        if (sid < cff1_std_strings_length)
+          gname.name = cff1_std_strings (sid);
+        else
+        {
+          byte_str_t    ustr = (*stringIndex)[sid - cff1_std_strings_length];
+          gname.name = hb_bytes_t ((const char*)ustr.arrayZ, ustr.length);
+        }
+        if (unlikely (!gname.name.arrayZ)) { fini (); return; }
+        glyph_names.push (gname);
+      }
+      glyph_names.qsort ();
     }
-    hb_blob_destroy (cff_prime);
 
-    return success;
-  }
+    void fini ()
+    {
+      glyph_names.fini ();
+
+      SUPER::fini ();
+    }
+
+    bool get_glyph_name (hb_codepoint_t glyph,
+                         char *buf, unsigned int buf_len) const
+    {
+      if (!buf) return true;
+      if (unlikely (!is_valid ())) return false;
+      if (is_CID()) return false;
+      hb_codepoint_t sid = glyph_to_sid (glyph);
+      const char *str;
+      size_t str_len;
+      if (sid < cff1_std_strings_length)
+      {
+        hb_bytes_t byte_str = cff1_std_strings (sid);
+        str = byte_str.arrayZ;
+        str_len = byte_str.length;
+      }
+      else
+      {
+        byte_str_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length];
+        str = (const char *)ubyte_str.arrayZ;
+        str_len = ubyte_str.length;
+      }
+      if (!str_len) return false;
+      unsigned int len = hb_min (buf_len - 1, str_len);
+      strncpy (buf, (const char*)str, len);
+      buf[len] = '\0';
+      return true;
+    }
+
+    bool get_glyph_from_name (const char *name, int len,
+                              hb_codepoint_t *glyph) const
+    {
+      if (len < 0) len = strlen (name);
+      if (unlikely (!len)) return false;
+
+      gname_t key = { hb_bytes_t (name, len), 0 };
+      const gname_t *gname = glyph_names.bsearch (key);
+      if (!gname) return false;
+      hb_codepoint_t gid = sid_to_glyph (gname->sid);
+      if (!gid && gname->sid) return false;
+      *glyph = gid;
+      return true;
+    }
+
+    HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
+    HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
+#ifdef HB_EXPERIMENTAL_API
+    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
+#endif
+
+    private:
+    struct gname_t
+    {
+      hb_bytes_t        name;
+      uint16_t          sid;
+
+      static int cmp (const void *a_, const void *b_)
+      {
+        const gname_t *a = (const gname_t *)a_;
+        const gname_t *b = (const gname_t *)b_;
+        int minlen = hb_min (a->name.length, b->name.length);
+        int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen);
+        if (ret) return ret;
+        return a->name.length - b->name.length;
+      }
+
+      int cmp (const gname_t &a) const { return cmp (&a, this); }
+    };
+
+    hb_sorted_vector_t<gname_t> glyph_names;
+
+    typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER;
+  };
+
+  struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> {};
+
+  bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); }
 
   protected:
   HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid);
   HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid);
   HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph);
   HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph);
+  HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_glyph (hb_codepoint_t sid);
+  HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid);
   HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code);
 
   public:
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc
index 45eb8bd..56f331e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc
@@ -24,24 +24,29 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_FONT_CFF
+
 #include "hb-ot-cff2-table.hh"
 #include "hb-cff2-interp-cs.hh"
+#include "hb-draw.hh"
 
 using namespace CFF;
 
-struct extents_param_t
+struct cff2_extents_param_t
 {
   void init ()
   {
     path_open = false;
-    min_x.set_int (0x7FFFFFFF);
-    min_y.set_int (0x7FFFFFFF);
-    max_x.set_int (-0x80000000);
-    max_y.set_int (-0x80000000);
+    min_x.set_int (INT_MAX);
+    min_y.set_int (INT_MAX);
+    max_x.set_int (INT_MIN);
+    max_y.set_int (INT_MIN);
   }
 
-  void start_path ()         { path_open = true; }
-  void end_path ()           { path_open = false; }
+  void   start_path ()       { path_open = true; }
+  void     end_path ()       { path_open = false; }
   bool is_path_open () const { return path_open; }
 
   void update_bounds (const point_t &pt)
@@ -59,15 +64,15 @@
   number_t max_y;
 };
 
-struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, extents_param_t>
+struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t>
 {
-  static void moveto (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt)
+  static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt)
   {
     param.end_path ();
     env.moveto (pt);
   }
 
-  static void line (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1)
+  static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1)
   {
     if (!param.is_path_open ())
     {
@@ -78,7 +83,7 @@
     param.update_bounds (env.get_pt ());
   }
 
-  static void curve (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
+  static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
   {
     if (!param.is_path_open ())
     {
@@ -93,21 +98,24 @@
   }
 };
 
-struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, extents_param_t, cff2_path_procs_extents_t> {};
+struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {};
 
 bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
                                            hb_codepoint_t glyph,
                                            hb_glyph_extents_t *extents) const
 {
+#ifdef HB_NO_OT_FONT_CFF
+  /* XXX Remove check when this code moves to .hh file. */
+  return true;
+#endif
+
   if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
 
-  unsigned int num_coords;
-  const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
   unsigned int fd = fdSelect->get_fd (glyph);
-  cff2_cs_interpreter_t<cff2_cs_opset_extents_t, extents_param_t> interp;
+  cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp;
   const byte_str_t str = (*charStrings)[glyph];
-  interp.env.init (str, *this, fd, coords, num_coords);
-  extents_param_t  param;
+  interp.env.init (str, *this, fd, font->coords, font->num_coords);
+  cff2_extents_param_t  param;
   param.init ();
   if (unlikely (!interp.interpret (param))) return false;
 
@@ -118,8 +126,8 @@
   }
   else
   {
-    extents->x_bearing = (int32_t)param.min_x.floor ();
-    extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing;
+    extents->x_bearing = font->em_scalef_x (param.min_x.to_real ());
+    extents->width = font->em_scalef_x (param.max_x.to_real () - param.min_x.to_real ());
   }
   if (param.min_y >= param.max_y)
   {
@@ -128,9 +136,80 @@
   }
   else
   {
-    extents->y_bearing = (int32_t)param.max_y.ceil ();
-    extents->height = (int32_t)param.min_y.floor () - extents->y_bearing;
+    extents->y_bearing = font->em_scalef_y (param.max_y.to_real ());
+    extents->height = font->em_scalef_y (param.min_y.to_real () - param.max_y.to_real ());
   }
 
   return true;
 }
+
+#ifdef HB_EXPERIMENTAL_API
+struct cff2_path_param_t
+{
+  cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_)
+  {
+    draw_helper = &draw_helper_;
+    font = font_;
+  }
+
+  void move_to (const point_t &p)
+  { draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
+
+  void line_to (const point_t &p)
+  { draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
+
+  void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
+  {
+    draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()),
+                           font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()),
+                           font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ()));
+  }
+
+  protected:
+  draw_helper_t *draw_helper;
+  hb_font_t *font;
+};
+
+struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t, cff2_path_param_t>
+{
+  static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt)
+  {
+    param.move_to (pt);
+    env.moveto (pt);
+  }
+
+  static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1)
+  {
+    param.line_to (pt1);
+    env.moveto (pt1);
+  }
+
+  static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
+  {
+    param.cubic_to (pt1, pt2, pt3);
+    env.moveto (pt3);
+  }
+};
+
+struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {};
+
+bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
+{
+#ifdef HB_NO_OT_FONT_CFF
+  /* XXX Remove check when this code moves to .hh file. */
+  return true;
+#endif
+
+  if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
+
+  unsigned int fd = fdSelect->get_fd (glyph);
+  cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp;
+  const byte_str_t str = (*charStrings)[glyph];
+  interp.env.init (str, *this, fd, font->coords, font->num_coords);
+  cff2_path_param_t param (font, draw_helper);
+  if (unlikely (!interp.interpret (param))) return false;
+  return true;
+}
+#endif
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh
index 8111d50..90c0b5b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh
@@ -27,9 +27,9 @@
 #ifndef HB_OT_CFF2_TABLE_HH
 #define HB_OT_CFF2_TABLE_HH
 
-#include "hb-ot-head-table.hh"
 #include "hb-ot-cff-common.hh"
 #include "hb-subset-cff2.hh"
+#include "hb-draw.hh"
 
 namespace CFF {
 
@@ -43,7 +43,6 @@
 template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {};
 
 typedef CFF2Index         CFF2CharStrings;
-typedef FDArray<HBUINT32> CFF2FDArray;
 typedef Subrs<HBUINT32>   CFF2Subrs;
 
 typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
@@ -51,62 +50,63 @@
 
 struct CFF2FDSelect
 {
-  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
-  {
-    TRACE_SANITIZE (this);
-
-    return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) &&
-                          (format == 0)?
-                          u.format0.sanitize (c, fdcount):
-                            ((format == 3)?
-                            u.format3.sanitize (c, fdcount):
-                            u.format4.sanitize (c, fdcount))));
-  }
-
   bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
   {
     TRACE_SERIALIZE (this);
     unsigned int size = src.get_size (num_glyphs);
     CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, &src, size);
     return_trace (true);
   }
 
-  unsigned int calculate_serialized_size (unsigned int num_glyphs) const
-  { return get_size (num_glyphs); }
-
   unsigned int get_size (unsigned int num_glyphs) const
   {
-    unsigned int size = format.static_size;
-    if (format == 0)
-      size += u.format0.get_size (num_glyphs);
-    else if (format == 3)
-      size += u.format3.get_size ();
-    else
-      size += u.format4.get_size ();
-    return size;
+    switch (format)
+    {
+    case 0: return format.static_size + u.format0.get_size (num_glyphs);
+    case 3: return format.static_size + u.format3.get_size ();
+    case 4: return format.static_size + u.format4.get_size ();
+    default:return 0;
+    }
   }
 
   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
   {
-    if (this == &Null(CFF2FDSelect))
+    if (this == &Null (CFF2FDSelect))
       return 0;
-    if (format == 0)
-      return u.format0.get_fd (glyph);
-    else if (format == 3)
-      return u.format3.get_fd (glyph);
-    else
-      return u.format4.get_fd (glyph);
+
+    switch (format)
+    {
+    case 0: return u.format0.get_fd (glyph);
+    case 3: return u.format3.get_fd (glyph);
+    case 4: return u.format4.get_fd (glyph);
+    default:return 0;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return_trace (false);
+
+    switch (format)
+    {
+    case 0: return_trace (u.format0.sanitize (c, fdcount));
+    case 3: return_trace (u.format3.sanitize (c, fdcount));
+    case 4: return_trace (u.format4.sanitize (c, fdcount));
+    default:return_trace (false);
+    }
   }
 
   HBUINT8       format;
   union {
-    FDSelect0   format0;
-    FDSelect3   format3;
-    FDSelect4   format4;
+  FDSelect0     format0;
+  FDSelect3     format3;
+  FDSelect4     format4;
   } u;
-
+  public:
   DEFINE_SIZE_MIN (2);
 };
 
@@ -123,7 +123,7 @@
     TRACE_SERIALIZE (this);
     unsigned int size_ = varStore->get_size ();
     CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
-    if (unlikely (dest == nullptr)) return_trace (false);
+    if (unlikely (!dest)) return_trace (false);
     memcpy (dest, varStore, size_);
     return_trace (true);
   }
@@ -146,26 +146,6 @@
   }
   void fini () { top_dict_values_t<>::fini (); }
 
-  unsigned int calculate_serialized_size () const
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < get_count (); i++)
-    {
-      op_code_t op = get_value (i).op;
-      switch (op)
-      {
-        case OpCode_vstore:
-        case OpCode_FDSelect:
-          size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
-          break;
-        default:
-          size += top_dict_values_t<>::calculate_serialized_op_size (get_value (i));
-          break;
-      }
-    }
-    return size;
-  }
-
   unsigned int  vstoreOffset;
   unsigned int  FDSelectOffset;
 };
@@ -252,22 +232,11 @@
   {
     dict_values_t<VAL>::init ();
     subrsOffset = 0;
-    localSubrs = &Null(CFF2Subrs);
+    localSubrs = &Null (CFF2Subrs);
     ivs = 0;
   }
   void fini () { dict_values_t<VAL>::fini (); }
 
-  unsigned int calculate_serialized_size () const
-  {
-    unsigned int size = 0;
-    for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++)
-      if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs)
-        size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
-      else
-        size += dict_values_t<VAL>::get_value (i).str.length;
-    return size;
-  }
-
   unsigned int      subrsOffset;
   const CFF2Subrs   *localSubrs;
   unsigned int      ivs;
@@ -400,6 +369,14 @@
 typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t;
 typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t;
 
+struct CFF2FDArray : FDArray<HBUINT32>
+{
+  /* FDArray::serialize does not compile without this partial specialization */
+  template <typename ITER, typename OP_SERIALIZER>
+  bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr)
+  { return FDArray<HBUINT32>::serialize<cff2_font_dict_values_t, table_info_t> (c, it, opszr); }
+};
+
 } /* namespace CFF */
 
 namespace OT {
@@ -434,7 +411,7 @@
 
       const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
 
-      if (cff2 == &Null(OT::cff2))
+      if (cff2 == &Null (OT::cff2))
       { fini (); return; }
 
       { /* parse top dict */
@@ -452,11 +429,11 @@
       fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
       fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
 
-      if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
-          (charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
-          (globalSubrs == &Null(CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
-          (fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
-          (((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
+      if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
+          (charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
+          (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
+          (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
+          (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
       { fini (); return; }
 
       num_glyphs = charStrings->count;
@@ -464,7 +441,8 @@
       { fini (); return; }
 
       fdCount = fdArray->count;
-      privateDicts.resize (fdCount);
+      if (!privateDicts.resize (fdCount))
+      { fini (); return; }
 
       /* parse font dicts and gather private dicts */
       for (unsigned int i = 0; i < fdCount; i++)
@@ -475,7 +453,7 @@
         cff2_font_dict_interpreter_t font_interp;
         font_interp.env.init (fontDictStr);
         font = fontDicts.push ();
-        if (unlikely (font == &Crap(cff2_font_dict_values_t))) { fini (); return; }
+        if (unlikely (font == &Crap (cff2_font_dict_values_t))) { fini (); return; }
         font->init ();
         if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
 
@@ -487,7 +465,7 @@
         if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
 
         privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
-        if (privateDicts[i].localSubrs != &Null(CFF2Subrs) &&
+        if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
           unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
         { fini (); return; }
       }
@@ -503,7 +481,7 @@
       blob = nullptr;
     }
 
-    bool is_valid () const { return blob != nullptr; }
+    bool is_valid () const { return blob; }
 
     protected:
     hb_blob_t                   *blob;
@@ -529,27 +507,14 @@
     HB_INTERNAL bool get_extents (hb_font_t *font,
                                   hb_codepoint_t glyph,
                                   hb_glyph_extents_t *extents) const;
+#ifdef HB_EXPERIMENTAL_API
+    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
+#endif
   };
 
   typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
 
-  bool subset (hb_subset_plan_t *plan) const
-  {
-    hb_blob_t *cff2_prime = nullptr;
-
-    bool success = true;
-    if (hb_subset_cff2 (plan, &cff2_prime)) {
-      success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime);
-      hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source);
-      success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob);
-      hb_blob_destroy (head_blob);
-    } else {
-      success = false;
-    }
-    hb_blob_destroy (cff2_prime);
-
-    return success;
-  }
+  bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); }
 
   public:
   FixedVersion<HBUINT8>         version;        /* Version of CFF2 table. set to 0x0200u */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh
index 9e2ada6..7160b16 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh
@@ -56,6 +56,18 @@
         out->add (i);
   }
 
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+                        hb_map_t *mapping /* OUT */) const
+  {
+    for (unsigned i = 0; i < 256; i++)
+      if (glyphIdArray[i])
+      {
+        hb_codepoint_t glyph = glyphIdArray[i];
+        unicodes->add (i);
+        mapping->set (i, glyph);
+      }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -74,154 +86,203 @@
 
 struct CmapSubtableFormat4
 {
-  struct segment_plan
+
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  HBUINT16* serialize_endcode_array (hb_serialize_context_t *c,
+                                     Iterator it)
   {
-    HBUINT16 start_code;
-    HBUINT16 end_code;
-    bool use_delta;
-  };
+    HBUINT16 *endCode = c->start_embed<HBUINT16> ();
+    hb_codepoint_t prev_endcp = 0xFFFF;
 
-  bool serialize (hb_serialize_context_t *c,
-                  const hb_subset_plan_t *plan,
-                  const hb_vector_t<segment_plan> &segments)
-  {
-    TRACE_SERIALIZE (this);
-
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-
-    this->format.set (4);
-    this->length.set (get_sub_table_size (segments));
-
-    this->segCountX2.set (segments.length * 2);
-    this->entrySelector.set (MAX (1u, hb_bit_storage (segments.length)) - 1);
-    this->searchRange.set (2 * (1u << this->entrySelector));
-    this->rangeShift.set (segments.length * 2 > this->searchRange
-                          ? 2 * segments.length - this->searchRange
-                          : 0);
-
-    HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length);
-    c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
-    HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length);
-    HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.length);
-    HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length);
-
-    if (id_range_offset == nullptr)
-      return_trace (false);
-
-    for (unsigned int i = 0; i < segments.length; i++)
+    for (const hb_item_type<Iterator> _ : +it)
     {
-      end_count[i].set (segments[i].end_code);
-      start_count[i].set (segments[i].start_code);
-      if (segments[i].use_delta)
+      if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first)
       {
-        hb_codepoint_t cp = segments[i].start_code;
-        hb_codepoint_t start_gid = 0;
-        if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF))
-          return_trace (false);
-        id_delta[i].set (start_gid - segments[i].start_code);
-      } else {
-        id_delta[i].set (0);
-        unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
-        HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
-        if (glyph_id_array == nullptr)
-          return_trace (false);
-        // From the cmap spec:
-        //
-        // id_range_offset[i]/2
-        // + (cp - segments[i].start_code)
-        // + (id_range_offset + i)
-        // =
-        // glyph_id_array + (cp - segments[i].start_code)
-        //
-        // So, solve for id_range_offset[i]:
-        //
-        // id_range_offset[i]
-        // =
-        // 2 * (glyph_id_array - id_range_offset - i)
-        id_range_offset[i].set (2 * (
-            glyph_id_array - id_range_offset - i));
-        for (unsigned int j = 0; j < num_codepoints; j++)
-        {
-          hb_codepoint_t cp = segments[i].start_code + j;
-          hb_codepoint_t new_gid;
-          if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
-            return_trace (false);
-          glyph_id_array[j].set (new_gid);
-        }
+        HBUINT16 end_code;
+        end_code = prev_endcp;
+        c->copy<HBUINT16> (end_code);
+      }
+      prev_endcp = _.first;
+    }
+
+    {
+      // last endCode
+      HBUINT16 endcode;
+      endcode = prev_endcp;
+      if (unlikely (!c->copy<HBUINT16> (endcode))) return nullptr;
+      // There must be a final entry with end_code == 0xFFFF.
+      if (prev_endcp != 0xFFFF)
+      {
+        HBUINT16 finalcode;
+        finalcode = 0xFFFF;
+        if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr;
       }
     }
 
-    return_trace (true);
+    return endCode;
   }
 
-  static size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  HBUINT16* serialize_startcode_array (hb_serialize_context_t *c,
+                                       Iterator it)
   {
-    size_t segment_size = 0;
-    for (unsigned int i = 0; i < segments.length; i++)
-    {
-      // Parallel array entries
-      segment_size +=
-            2  // end count
-          + 2  // start count
-          + 2  // delta
-          + 2; // range offset
+    HBUINT16 *startCode = c->start_embed<HBUINT16> ();
+    hb_codepoint_t prev_cp = 0xFFFF;
 
-      if (!segments[i].use_delta)
-        // Add bytes for the glyph index array entries for this segment.
-        segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2;
+    for (const hb_item_type<Iterator> _ : +it)
+    {
+      if (prev_cp == 0xFFFF || prev_cp + 1u != _.first)
+      {
+        HBUINT16 start_code;
+        start_code = _.first;
+        c->copy<HBUINT16> (start_code);
+      }
+
+      prev_cp = _.first;
     }
 
-    return min_size
-        + 2 // Padding
-        + segment_size;
+    // There must be a final entry with end_code == 0xFFFF.
+    if (it.len () == 0 || prev_cp != 0xFFFF)
+    {
+      HBUINT16 finalcode;
+      finalcode = 0xFFFF;
+      if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr;
+    }
+
+    return startCode;
   }
 
-  static bool create_sub_table_plan (const hb_subset_plan_t *plan,
-                                     hb_vector_t<segment_plan> *segments)
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  HBINT16* serialize_idDelta_array (hb_serialize_context_t *c,
+                                    Iterator it,
+                                    HBUINT16 *endCode,
+                                    HBUINT16 *startCode,
+                                    unsigned segcount)
   {
-    segment_plan *segment = nullptr;
-    hb_codepoint_t last_gid = 0;
+    unsigned i = 0;
+    hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF;
+    bool use_delta = true;
 
-    hb_codepoint_t cp = HB_SET_VALUE_INVALID;
-    while (plan->unicodes->next (&cp)) {
-      hb_codepoint_t new_gid;
-      if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
-      {
-        DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
-        return false;
-      }
+    HBINT16 *idDelta = c->start_embed<HBINT16> ();
+    if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size)
+      return nullptr;
 
-      /* Stop adding to cmap if we are now outside of unicode BMP. */
-      if (cp > 0xFFFF) break;
-
-      if (!segment ||
-          cp != segment->end_code + 1u)
-      {
-        segment = segments->push ();
-        segment->start_code.set (cp);
-        segment->end_code.set (cp);
-        segment->use_delta = true;
-      } else {
-        segment->end_code.set (cp);
-        if (last_gid + 1u != new_gid)
-          // gid's are not consecutive in this segment so delta
-          // cannot be used.
-          segment->use_delta = false;
-      }
-
-      last_gid = new_gid;
-    }
-
-    // There must be a final entry with end_code == 0xFFFF. Check if we need to add one.
-    if (segment == nullptr || segment->end_code != 0xFFFF)
+    for (const hb_item_type<Iterator> _ : +it)
     {
-      segment = segments->push ();
-      segment->start_code.set (0xFFFF);
-      segment->end_code.set (0xFFFF);
-      segment->use_delta = true;
+      if (_.first == startCode[i])
+      {
+        use_delta = true;
+        start_gid = _.second;
+      }
+      else if (_.second != last_gid + 1) use_delta = false;
+
+      if (_.first == endCode[i])
+      {
+        HBINT16 delta;
+        if (use_delta) delta = (int)start_gid - (int)startCode[i];
+        else delta = 0;
+        c->copy<HBINT16> (delta);
+
+        i++;
+      }
+
+      last_gid = _.second;
+      last_cp = _.first;
     }
 
-    return true;
+    if (it.len () == 0 || last_cp != 0xFFFF)
+    {
+      HBINT16 delta;
+      delta = 1;
+      if (unlikely (!c->copy<HBINT16> (delta))) return nullptr;
+    }
+
+    return idDelta;
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c,
+                                         Iterator it,
+                                         HBUINT16 *endCode,
+                                         HBUINT16 *startCode,
+                                         HBINT16 *idDelta,
+                                         unsigned segcount)
+  {
+    HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
+    if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
+    if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
+
+    + hb_range (segcount)
+    | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })
+    | hb_apply ([&] (const unsigned i)
+                {
+                  idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
+
+                  + it
+                  | hb_filter ([&] (const hb_item_type<Iterator> _) { return _.first >= startCode[i] && _.first <= endCode[i]; })
+                  | hb_apply ([&] (const hb_item_type<Iterator> _)
+                              {
+                                HBUINT16 glyID;
+                                glyID = _.second;
+                                c->copy<HBUINT16> (glyID);
+                              })
+                  ;
+
+
+                })
+    ;
+
+    return idRangeOffset;
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  Iterator it)
+  {
+    auto format4_iter =
+    + it
+    | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+                 { return _.first <= 0xFFFF; })
+    ;
+
+    if (format4_iter.len () == 0) return;
+
+    unsigned table_initpos = c->length ();
+    if (unlikely (!c->extend_min (*this))) return;
+    this->format = 4;
+
+    //serialize endCode[]
+    HBUINT16 *endCode = serialize_endcode_array (c, format4_iter);
+    if (unlikely (!endCode)) return;
+
+    unsigned segcount = (c->length () - min_size) / HBUINT16::static_size;
+
+    // 2 bytes of padding.
+    if (unlikely (!c->allocate_size<HBUINT16> (HBUINT16::static_size))) return; // 2 bytes of padding.
+
+   // serialize startCode[]
+    HBUINT16 *startCode = serialize_startcode_array (c, format4_iter);
+    if (unlikely (!startCode)) return;
+
+    //serialize idDelta[]
+    HBINT16 *idDelta = serialize_idDelta_array (c, format4_iter, endCode, startCode, segcount);
+    if (unlikely (!idDelta)) return;
+
+    HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
+    if (unlikely (!c->check_success (idRangeOffset))) return;
+
+    if (unlikely (!c->check_assign(this->length, c->length () - table_initpos))) return;
+    this->segCountX2 = segcount * 2;
+    this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
+    this->searchRange = 2 * (1u << this->entrySelector);
+    this->rangeShift = segcount * 2 > this->searchRange
+                       ? 2 * segcount - this->searchRange
+                       : 0;
   }
 
   struct accelerator_t
@@ -244,27 +305,28 @@
 
     bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
     {
-      /* Custom two-array bsearch. */
-      int min = 0, max = (int) this->segCount - 1;
-      const HBUINT16 *startCount = this->startCount;
-      const HBUINT16 *endCount = this->endCount;
-      unsigned int i;
-      while (min <= max)
+      struct CustomRange
       {
-        int mid = ((unsigned int) min + (unsigned int) max) / 2;
-        if (codepoint < startCount[mid])
-          max = mid - 1;
-        else if (codepoint > endCount[mid])
-          min = mid + 1;
-        else
+        int cmp (hb_codepoint_t k,
+                 unsigned distance) const
         {
-          i = mid;
-          goto found;
+          if (k > last) return +1;
+          if (k < (&last)[distance]) return -1;
+          return 0;
         }
-      }
-      return false;
+        HBUINT16 last;
+      };
 
-    found:
+      const HBUINT16 *found = hb_bsearch (codepoint,
+                                          this->endCount,
+                                          this->segCount,
+                                          2,
+                                          _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
+                                          this->segCount + 1);
+      if (!found)
+        return false;
+      unsigned int i = found - endCount;
+
       hb_codepoint_t gid;
       unsigned int rangeOffset = this->idRangeOffset[i];
       if (rangeOffset == 0)
@@ -286,10 +348,10 @@
       *glyph = gid;
       return true;
     }
-    static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
-    {
-      return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph);
-    }
+
+    HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
+    { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); }
+
     void collect_unicodes (hb_set_t *out) const
     {
       unsigned int count = this->segCount;
@@ -297,14 +359,22 @@
         count--; /* Skip sentinel segment. */
       for (unsigned int i = 0; i < count; i++)
       {
+        hb_codepoint_t start = this->startCount[i];
+        hb_codepoint_t end = this->endCount[i];
         unsigned int rangeOffset = this->idRangeOffset[i];
         if (rangeOffset == 0)
-          out->add_range (this->startCount[i], this->endCount[i]);
+        {
+          for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
+          {
+            hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
+            if (unlikely (!gid))
+              continue;
+            out->add (codepoint);
+          }
+        }
         else
         {
-          for (hb_codepoint_t codepoint = this->startCount[i];
-               codepoint <= this->endCount[i];
-               codepoint++)
+          for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
           {
             unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
             if (unlikely (index >= this->glyphIdArrayLength))
@@ -318,6 +388,45 @@
       }
     }
 
+    void collect_mapping (hb_set_t *unicodes, /* OUT */
+                          hb_map_t *mapping /* OUT */) const
+    {
+      unsigned count = this->segCount;
+      if (count && this->startCount[count - 1] == 0xFFFFu)
+        count--; /* Skip sentinel segment. */
+      for (unsigned i = 0; i < count; i++)
+      {
+        hb_codepoint_t start = this->startCount[i];
+        hb_codepoint_t end = this->endCount[i];
+        unsigned rangeOffset = this->idRangeOffset[i];
+        if (rangeOffset == 0)
+        {
+          for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
+          {
+            hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
+            if (unlikely (!gid))
+              continue;
+            unicodes->add (codepoint);
+            mapping->set (codepoint, gid);
+          }
+        }
+        else
+        {
+          for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
+          {
+            unsigned index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
+            if (unlikely (index >= this->glyphIdArrayLength))
+              break;
+            hb_codepoint_t gid = this->glyphIdArray[index];
+            if (unlikely (!gid))
+              continue;
+            unicodes->add (codepoint);
+            mapping->set (codepoint, gid);
+          }
+        }
+      }
+    }
+
     const HBUINT16 *endCount;
     const HBUINT16 *startCount;
     const HBUINT16 *idDelta;
@@ -338,6 +447,13 @@
     accel.collect_unicodes (out);
   }
 
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+                        hb_map_t *mapping /* OUT */) const
+  {
+    accelerator_t accel (this);
+    accel.collect_mapping (unicodes, mapping);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -349,9 +465,9 @@
       /* Some broken fonts have too long of a "length" value.
        * If that is the case, just change the value to truncate
        * the subtable at the end of the blob. */
-      uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
-                                            (uintptr_t) (c->end -
-                                                         (char *) this));
+      uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535,
+                                               (uintptr_t) (c->end -
+                                                            (char *) this));
       if (!c->try_set (&length, new_length))
         return_trace (false);
     }
@@ -440,6 +556,21 @@
         out->add (start + i);
   }
 
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+                        hb_map_t *mapping /* OUT */) const
+  {
+    hb_codepoint_t start_cp = startCharCode;
+    unsigned count = glyphIdArray.len;
+    for (unsigned i = 0; i < count; i++)
+      if (glyphIdArray[i])
+      {
+        hb_codepoint_t unicode = start_cp + i;
+        hb_codepoint_t glyphid = glyphIdArray[i];
+        unicodes->add (unicode);
+        mapping->set (unicode, glyphid);
+      }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -451,7 +582,7 @@
   UINT          length;         /* Byte length of this subtable. */
   UINT          language;       /* Ignore. */
   UINT          startCharCode;  /* First character code covered. */
-  ArrayOf<GlyphID, UINT>
+  ArrayOf<HBGlyphID, UINT>
                 glyphIdArray;   /* Array of glyph index values for character
                                  * codes in the range. */
   public:
@@ -475,12 +606,56 @@
     return true;
   }
 
-  void collect_unicodes (hb_set_t *out) const
+  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
   {
-    for (unsigned int i = 0; i < this->groups.len; i++) {
-      out->add_range (this->groups[i].startCharCode,
-                      MIN ((hb_codepoint_t) this->groups[i].endCharCode,
-                           (hb_codepoint_t) HB_UNICODE_MAX));
+    for (unsigned int i = 0; i < this->groups.len; i++)
+    {
+      hb_codepoint_t start = this->groups[i].startCharCode;
+      hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
+                                   (hb_codepoint_t) HB_UNICODE_MAX);
+      hb_codepoint_t gid = this->groups[i].glyphID;
+      if (!gid)
+      {
+        /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
+        if (! T::group_get_glyph (this->groups[i], end)) continue;
+        start++;
+        gid++;
+      }
+      if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
+      if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
+        end = start + (hb_codepoint_t) num_glyphs - gid;
+
+      out->add_range (start, end);
+    }
+  }
+
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+                        hb_map_t *mapping, /* OUT */
+                        unsigned num_glyphs) const
+  {
+    for (unsigned i = 0; i < this->groups.len; i++)
+    {
+      hb_codepoint_t start = this->groups[i].startCharCode;
+      hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
+                                   (hb_codepoint_t) HB_UNICODE_MAX);
+      hb_codepoint_t gid = this->groups[i].glyphID;
+      if (!gid)
+      {
+        /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
+        if (! T::group_get_glyph (this->groups[i], end)) continue;
+        start++;
+        gid++;
+      }
+      if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
+      if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
+        end = start + (hb_codepoint_t) num_glyphs - gid;
+
+      for (unsigned cp = start; cp <= end; cp++)
+      {
+        unicodes->add (cp);
+        mapping->set (cp, gid);
+        gid++;
+      }
     }
   }
 
@@ -490,15 +665,6 @@
     return_trace (c->check_struct (this) && groups.sanitize (c));
   }
 
-  bool serialize (hb_serialize_context_t *c,
-                  const hb_vector_t<CmapSubtableLongGroup> &group_data)
-  {
-    TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false);
-    return true;
-  }
-
   protected:
   HBUINT16      format;         /* Subtable format; set to 12. */
   HBUINT16      reserved;       /* Reserved; set to 0. */
@@ -518,63 +684,66 @@
            group.glyphID + (u - group.startCharCode) : 0; }
 
 
-  bool serialize (hb_serialize_context_t *c,
-                  const hb_vector_t<CmapSubtableLongGroup> &groups)
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  Iterator it)
   {
-    if (unlikely (!c->extend_min (*this))) return false;
+    if (it.len () == 0) return;
+    unsigned table_initpos = c->length ();
+    if (unlikely (!c->extend_min (*this))) return;
 
-    this->format.set (12);
-    this->reserved.set (0);
-    this->length.set (get_sub_table_size (groups));
+    hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
+    hb_codepoint_t glyphID = 0;
 
-    return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
-  }
-
-  static size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
-  {
-    return 16 + 12 * groups.length;
-  }
-
-  static bool create_sub_table_plan (const hb_subset_plan_t *plan,
-                                     hb_vector_t<CmapSubtableLongGroup> *groups)
-  {
-    CmapSubtableLongGroup *group = nullptr;
-
-    hb_codepoint_t cp = HB_SET_VALUE_INVALID;
-    while (plan->unicodes->next (&cp)) {
-      hb_codepoint_t new_gid;
-      if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
+    for (const hb_item_type<Iterator> _ : +it)
+    {
+      if (startCharCode == 0xFFFF)
       {
-        DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
-        return false;
+        startCharCode = _.first;
+        endCharCode = _.first;
+        glyphID = _.second;
       }
-
-      if (!group || !_is_gid_consecutive (group, cp, new_gid))
+      else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second))
       {
-        group = groups->push ();
-        group->startCharCode.set (cp);
-        group->endCharCode.set (cp);
-        group->glyphID.set (new_gid);
+        CmapSubtableLongGroup  grouprecord;
+        grouprecord.startCharCode = startCharCode;
+        grouprecord.endCharCode = endCharCode;
+        grouprecord.glyphID = glyphID;
+        c->copy<CmapSubtableLongGroup> (grouprecord);
+
+        startCharCode = _.first;
+        endCharCode = _.first;
+        glyphID = _.second;
       }
-      else group->endCharCode.set (cp);
+      else
+        endCharCode = _.first;
     }
 
-    DEBUG_MSG(SUBSET, nullptr, "cmap");
-    for (unsigned int i = 0; i < groups->length; i++) {
-      CmapSubtableLongGroup& group = (*groups)[i];
-      DEBUG_MSG(SUBSET, nullptr, "  %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
-    }
+    CmapSubtableLongGroup record;
+    record.startCharCode = startCharCode;
+    record.endCharCode = endCharCode;
+    record.glyphID = glyphID;
+    c->copy<CmapSubtableLongGroup> (record);
 
-    return true;
+    this->format = 12;
+    this->reserved = 0;
+    this->length = c->length () - table_initpos;
+    this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size;
   }
 
- private:
-  static bool _is_gid_consecutive (CmapSubtableLongGroup *group,
+  static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
+  { return 16 + 12 * groups_data.length; }
+
+  private:
+  static bool _is_gid_consecutive (hb_codepoint_t endCharCode,
+                                   hb_codepoint_t startCharCode,
+                                   hb_codepoint_t glyphID,
                                    hb_codepoint_t cp,
                                    hb_codepoint_t new_gid)
   {
-    return (cp - 1 == group->endCharCode) &&
-        new_gid == group->glyphID + (cp - group->startCharCode);
+    return (cp - 1 == endCharCode) &&
+        new_gid == glyphID + (cp - startCharCode);
   }
 
 };
@@ -623,12 +792,69 @@
     for (unsigned int i = 0; i < count; i++)
     {
       hb_codepoint_t first = arrayZ[i].startUnicodeValue;
-      hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
-                                 (hb_codepoint_t) HB_UNICODE_MAX);
+      hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
+                                    (hb_codepoint_t) HB_UNICODE_MAX);
       out->add_range (first, last);
     }
   }
 
+  DefaultUVS* copy (hb_serialize_context_t *c,
+                    const hb_set_t *unicodes) const
+  {
+    DefaultUVS *out = c->start_embed<DefaultUVS> ();
+    if (unlikely (!out)) return nullptr;
+    auto snap = c->snapshot ();
+
+    HBUINT32 len;
+    len = 0;
+    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
+    unsigned init_len = c->length ();
+
+    hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID;
+    int count = -1;
+
+    for (const UnicodeValueRange& _ : as_array ())
+    {
+      for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1))
+      {
+        unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt;
+        if (!unicodes->has (curEntry)) continue;
+        count += 1;
+        if (lastCode == HB_MAP_VALUE_INVALID)
+          lastCode = curEntry;
+        else if (lastCode + count != curEntry)
+        {
+          UnicodeValueRange rec;
+          rec.startUnicodeValue = lastCode;
+          rec.additionalCount = count - 1;
+          c->copy<UnicodeValueRange> (rec);
+
+          lastCode = curEntry;
+          count = 0;
+        }
+      }
+    }
+
+    if (lastCode != HB_MAP_VALUE_INVALID)
+    {
+      UnicodeValueRange rec;
+      rec.startUnicodeValue = lastCode;
+      rec.additionalCount = count;
+      c->copy<UnicodeValueRange> (rec);
+    }
+
+    if (c->length () - init_len == 0)
+    {
+      c->revert (snap);
+      return nullptr;
+    }
+    else
+    {
+      if (unlikely (!c->check_assign (out->len, (c->length () - init_len) / UnicodeValueRange::static_size))) return nullptr;
+      return out;
+    }
+  }
+
   public:
   DEFINE_SIZE_ARRAY (4, *this);
 };
@@ -636,9 +862,7 @@
 struct UVSMapping
 {
   int cmp (const hb_codepoint_t &codepoint) const
-  {
-    return unicodeValue.cmp (codepoint);
-  }
+  { return unicodeValue.cmp (codepoint); }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -647,7 +871,7 @@
   }
 
   HBUINT24      unicodeValue;   /* Base Unicode value of the UVS */
-  GlyphID       glyphID;        /* Glyph ID of the UVS */
+  HBGlyphID     glyphID;        /* Glyph ID of the UVS */
   public:
   DEFINE_SIZE_STATIC (5);
 };
@@ -658,7 +882,63 @@
   {
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
-      out->add (arrayZ[i].glyphID);
+      out->add (arrayZ[i].unicodeValue);
+  }
+
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+                        hb_map_t *mapping /* OUT */) const
+  {
+    unsigned count = len;
+    for (unsigned i = 0; i < count; i++)
+    {
+      hb_codepoint_t unicode = arrayZ[i].unicodeValue;
+      hb_codepoint_t glyphid = arrayZ[i].glyphID;
+      unicodes->add (unicode);
+      mapping->set (unicode, glyphid);
+    }
+  }
+
+  void closure_glyphs (const hb_set_t      *unicodes,
+                       hb_set_t            *glyphset) const
+  {
+    + as_array ()
+    | hb_filter (unicodes, &UVSMapping::unicodeValue)
+    | hb_map (&UVSMapping::glyphID)
+    | hb_sink (glyphset)
+    ;
+  }
+
+  NonDefaultUVS* copy (hb_serialize_context_t *c,
+                       const hb_set_t *unicodes,
+                       const hb_set_t *glyphs_requested,
+                       const hb_map_t *glyph_map) const
+  {
+    NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
+    if (unlikely (!out)) return nullptr;
+
+    auto it =
+    + as_array ()
+    | hb_filter ([&] (const UVSMapping& _)
+                 {
+                   return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID);
+                 })
+    ;
+
+    if (!it) return nullptr;
+
+    HBUINT32 len;
+    len = it.len ();
+    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
+
+    for (const UVSMapping& _ : it)
+    {
+      UVSMapping mapping;
+      mapping.unicodeValue = _.unicodeValue;
+      mapping.glyphID = glyph_map->get (_.glyphID);
+      c->copy<UVSMapping> (mapping);
+    }
+
+    return out;
   }
 
   public:
@@ -682,17 +962,37 @@
     return GLYPH_VARIANT_NOT_FOUND;
   }
 
+  VariationSelectorRecord(const VariationSelectorRecord& other)
+  {
+    *this = other;
+  }
+
+  void operator= (const VariationSelectorRecord& other)
+  {
+    varSelector = other.varSelector;
+    HBUINT32 offset = other.defaultUVS;
+    defaultUVS = offset;
+    offset = other.nonDefaultUVS;
+    nonDefaultUVS = offset;
+  }
+
   void collect_unicodes (hb_set_t *out, const void *base) const
   {
     (base+defaultUVS).collect_unicodes (out);
     (base+nonDefaultUVS).collect_unicodes (out);
   }
 
-  int cmp (const hb_codepoint_t &variation_selector) const
+  void collect_mapping (const void *base,
+                        hb_set_t *unicodes, /* OUT */
+                        hb_map_t *mapping /* OUT */) const
   {
-    return varSelector.cmp (variation_selector);
+    (base+defaultUVS).collect_unicodes (unicodes);
+    (base+nonDefaultUVS).collect_mapping (unicodes, mapping);
   }
 
+  int cmp (const hb_codepoint_t &variation_selector) const
+  { return varSelector.cmp (variation_selector); }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -701,6 +1001,45 @@
                   nonDefaultUVS.sanitize (c, base));
   }
 
+  hb_pair_t<unsigned, unsigned>
+  copy (hb_serialize_context_t *c,
+        const hb_set_t *unicodes,
+        const hb_set_t *glyphs_requested,
+        const hb_map_t *glyph_map,
+        const void *base) const
+  {
+    auto snap = c->snapshot ();
+    auto *out = c->embed<VariationSelectorRecord> (*this);
+    if (unlikely (!out)) return hb_pair (0, 0);
+
+    out->defaultUVS = 0;
+    out->nonDefaultUVS = 0;
+
+    unsigned non_default_uvs_objidx = 0;
+    if (nonDefaultUVS != 0)
+    {
+      c->push ();
+      if (c->copy (base+nonDefaultUVS, unicodes, glyphs_requested, glyph_map))
+        non_default_uvs_objidx = c->pop_pack ();
+      else c->pop_discard ();
+    }
+
+    unsigned default_uvs_objidx = 0;
+    if (defaultUVS != 0)
+    {
+      c->push ();
+      if (c->copy (base+defaultUVS, unicodes))
+        default_uvs_objidx = c->pop_pack ();
+      else c->pop_discard ();
+    }
+
+
+    if (!default_uvs_objidx && !non_default_uvs_objidx)
+      c->revert (snap);
+
+    return hb_pair (default_uvs_objidx, non_default_uvs_objidx);
+  }
+
   HBUINT24      varSelector;    /* Variation selector. */
   LOffsetTo<DefaultUVS>
                 defaultUVS;     /* Offset to Default UVS Table.  May be 0. */
@@ -715,9 +1054,7 @@
   glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
                                      hb_codepoint_t variation_selector,
                                      hb_codepoint_t *glyph) const
-  {
-    return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this);
-  }
+  { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); }
 
   void collect_variation_selectors (hb_set_t *out) const
   {
@@ -727,8 +1064,110 @@
   }
   void collect_variation_unicodes (hb_codepoint_t variation_selector,
                                    hb_set_t *out) const
+  { record.bsearch (variation_selector).collect_unicodes (out, this); }
+
+  void serialize (hb_serialize_context_t *c,
+                  const hb_set_t *unicodes,
+                  const hb_set_t *glyphs_requested,
+                  const hb_map_t *glyph_map,
+                  const void *base)
   {
-    record.bsearch (variation_selector).collect_unicodes (out, this);
+    auto snap = c->snapshot ();
+    unsigned table_initpos = c->length ();
+    const char* init_tail = c->tail;
+
+    if (unlikely (!c->extend_min (*this))) return;
+    this->format = 14;
+
+    auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
+
+    /*
+     * Some versions of OTS require that offsets are in order. Due to the use
+     * of push()/pop_pack() serializing the variation records in order results
+     * in the offsets being in reverse order (first record has the largest
+     * offset). While this is perfectly valid, it will cause some versions of
+     * OTS to consider this table bad.
+     *
+     * So to prevent this issue we serialize the variation records in reverse
+     * order, so that the offsets are ordered from small to large. Since
+     * variation records are supposed to be in increasing order of varSelector
+     * we then have to reverse the order of the written variation selector
+     * records after everything is finalized.
+     */
+    hb_vector_t<hb_pair_t<unsigned, unsigned>> obj_indices;
+    for (int i = src_tbl->record.len - 1; i >= 0; i--)
+    {
+      hb_pair_t<unsigned, unsigned> result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base);
+      if (result.first || result.second)
+        obj_indices.push (result);
+    }
+
+    if (c->length () - table_initpos == CmapSubtableFormat14::min_size)
+    {
+      c->revert (snap);
+      return;
+    }
+
+    if (unlikely (!c->check_success (!obj_indices.in_error ())))
+      return;
+
+    int tail_len = init_tail - c->tail;
+    c->check_assign (this->length, c->length () - table_initpos + tail_len);
+    c->check_assign (this->record.len,
+                     (c->length () - table_initpos - CmapSubtableFormat14::min_size) /
+                     VariationSelectorRecord::static_size);
+
+    /* Correct the incorrect write order by reversing the order of the variation
+       records array. */
+    _reverse_variation_records ();
+
+    /* Now that records are in the right order, we can set up the offsets. */
+    _add_links_to_variation_records (c, obj_indices);
+  }
+
+  void _reverse_variation_records ()
+  {
+    record.as_array ().reverse ();
+  }
+
+  void _add_links_to_variation_records (hb_serialize_context_t *c,
+                                        const hb_vector_t<hb_pair_t<unsigned, unsigned>>& obj_indices)
+  {
+    for (unsigned i = 0; i < obj_indices.length; i++)
+    {
+      /*
+       * Since the record array has been reversed (see comments in copy())
+       * but obj_indices has not been, the indices at obj_indices[i]
+       * are for the variation record at record[j].
+       */
+      int j = obj_indices.length - 1 - i;
+      c->add_link (record[j].defaultUVS, obj_indices[i].first);
+      c->add_link (record[j].nonDefaultUVS, obj_indices[i].second);
+    }
+  }
+
+  void closure_glyphs (const hb_set_t      *unicodes,
+                       hb_set_t            *glyphset) const
+  {
+    + hb_iter (record)
+    | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS)
+    | hb_map (&VariationSelectorRecord::nonDefaultUVS)
+    | hb_map (hb_add (this))
+    | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })
+    ;
+  }
+
+  void collect_unicodes (hb_set_t *out) const
+  {
+    for (const VariationSelectorRecord& _ : record)
+      _.collect_unicodes (out, this);
+  }
+
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+                        hb_map_t *mapping /* OUT */) const
+  {
+    for (const VariationSelectorRecord& _ : record)
+      _.collect_mapping (this, unicodes, mapping);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -766,20 +1205,52 @@
     default: return false;
     }
   }
-  void collect_unicodes (hb_set_t *out) const
+  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const
   {
     switch (u.format) {
     case  0: u.format0 .collect_unicodes (out); return;
     case  4: u.format4 .collect_unicodes (out); return;
     case  6: u.format6 .collect_unicodes (out); return;
     case 10: u.format10.collect_unicodes (out); return;
-    case 12: u.format12.collect_unicodes (out); return;
-    case 13: u.format13.collect_unicodes (out); return;
+    case 12: u.format12.collect_unicodes (out, num_glyphs); return;
+    case 13: u.format13.collect_unicodes (out, num_glyphs); return;
     case 14:
     default: return;
     }
   }
 
+  void collect_mapping (hb_set_t *unicodes, /* OUT */
+                        hb_map_t *mapping, /* OUT */
+                        unsigned num_glyphs = UINT_MAX) const
+  {
+    switch (u.format) {
+    case  0: u.format0 .collect_mapping (unicodes, mapping); return;
+    case  4: u.format4 .collect_mapping (unicodes, mapping); return;
+    case  6: u.format6 .collect_mapping (unicodes, mapping); return;
+    case 10: u.format10.collect_mapping (unicodes, mapping); return;
+    case 12: u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
+    case 13: u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
+    case 14:
+    default: return;
+    }
+  }
+
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  Iterator it,
+                  unsigned format,
+                  const hb_subset_plan_t *plan,
+                  const void *base)
+  {
+    switch (format) {
+    case  4: return u.format4.serialize (c, it);
+    case 12: return u.format12.serialize (c, it);
+    case 14: return u.format14.serialize (c, plan->unicodes, plan->glyphs_requested, plan->glyph_map, base);
+    default: return;
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -831,6 +1302,40 @@
                   subtable.sanitize (c, base));
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  EncodingRecord* copy (hb_serialize_context_t *c,
+                        Iterator it,
+                        unsigned format,
+                        const void *base,
+                        const hb_subset_plan_t *plan,
+                        /* INOUT */ unsigned *objidx) const
+  {
+    TRACE_SERIALIZE (this);
+    auto snap = c->snapshot ();
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+    out->subtable = 0;
+
+    if (*objidx == 0)
+    {
+      CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
+      unsigned origin_length = c->length ();
+      cmapsubtable->serialize (c, it, format, plan, &(base+subtable));
+      if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
+      else c->pop_discard ();
+    }
+
+    if (*objidx == 0)
+    {
+      c->revert (snap);
+      return_trace (nullptr);
+    }
+
+    c->add_link (out->subtable, *objidx);
+    return_trace (out);
+  }
+
   HBUINT16      platformID;     /* Platform ID. */
   HBUINT16      encodingID;     /* Platform-specific encoding ID. */
   LOffsetTo<CmapSubtable>
@@ -843,124 +1348,128 @@
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
 
-  struct subset_plan
+  template<typename Iterator, typename EncodingRecIter,
+           hb_requires (hb_is_iterator (EncodingRecIter))>
+  void serialize (hb_serialize_context_t *c,
+                  Iterator it,
+                  EncodingRecIter encodingrec_iter,
+                  const void *base,
+                  const hb_subset_plan_t *plan)
   {
-    size_t final_size () const
+    if (unlikely (!c->extend_min ((*this))))  return;
+    this->version = 0;
+
+    unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
+
+    for (const EncodingRecord& _ : encodingrec_iter)
     {
-      return 4 // header
-          +  8 * 3 // 3 EncodingRecord
-          +  CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
-          +  CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
+      unsigned format = (base+_.subtable).u.format;
+      if (!plan->glyphs_requested->is_empty ())
+      {
+        hb_set_t unicodes_set;
+        hb_map_t cp_glyphid_map;
+        (base+_.subtable).collect_mapping (&unicodes_set, &cp_glyphid_map);
+
+        auto table_iter =
+        + hb_zip (unicodes_set.iter(), unicodes_set.iter() | hb_map(cp_glyphid_map))
+        | hb_filter (plan->_glyphset, hb_second)
+        | hb_filter ([plan] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& p)
+                     {
+                       return plan->unicodes->has (p.first) ||
+                              plan->glyphs_requested->has (p.second);
+                     })
+        | hb_map ([plan] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& p_org)
+                  {
+                    return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (p_org.first, plan->glyph_map->get(p_org.second));
+                  })
+        ;
+
+        if (format == 4) c->copy (_, table_iter, 4u, base, plan, &format4objidx);
+        else if (format == 12) c->copy (_, table_iter, 12u, base, plan, &format12objidx);
+        else if (format == 14) c->copy (_, table_iter, 14u, base, plan, &format14objidx);
+      }
+      /* when --gids option is not used, we iterate input unicodes instead of
+       * all codepoints in each subtable, which is more efficient */
+      else
+      {
+        hb_set_t unicodes_set;
+        (base+_.subtable).collect_unicodes (&unicodes_set);
+
+        if (format == 4) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
+        else if (format == 12) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx);
+        else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
+      }
     }
 
-    hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
-    hb_vector_t<CmapSubtableLongGroup> format12_groups;
-  };
-
-  bool _create_plan (const hb_subset_plan_t *plan,
-                     subset_plan *cmap_plan) const
-  {
-    if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
-      return false;
-
-    return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
+    c->check_assign(this->encodingRecord.len, (c->length () - cmap::min_size)/EncodingRecord::static_size);
   }
 
-  bool _subset (const hb_subset_plan_t *plan,
-                const subset_plan &cmap_subset_plan,
-                size_t dest_sz,
-                void *dest) const
+  void closure_glyphs (const hb_set_t      *unicodes,
+                       hb_set_t            *glyphset) const
   {
-    hb_serialize_context_t c (dest, dest_sz);
-
-    cmap *table = c.start_serialize<cmap> ();
-    if (unlikely (!c.extend_min (*table)))
-    {
-      return false;
-    }
-
-    table->version.set (0);
-
-    if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3)))
-      return false;
-
-    // TODO(grieger): Convert the below to a for loop
-
-    // Format 4, Plat 0 Encoding Record
-    EncodingRecord &format4_plat0_rec = table->encodingRecord[0];
-    format4_plat0_rec.platformID.set (0); // Unicode
-    format4_plat0_rec.encodingID.set (3);
-
-    // Format 4, Plat 3 Encoding Record
-    EncodingRecord &format4_plat3_rec = table->encodingRecord[1];
-    format4_plat3_rec.platformID.set (3); // Windows
-    format4_plat3_rec.encodingID.set (1); // Unicode BMP
-
-    // Format 12 Encoding Record
-    EncodingRecord &format12_rec = table->encodingRecord[2];
-    format12_rec.platformID.set (3); // Windows
-    format12_rec.encodingID.set (10); // Unicode UCS-4
-
-    // Write out format 4 sub table
-    {
-      CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table);
-      format4_plat3_rec.subtable.set (format4_plat0_rec.subtable);
-      subtable.u.format.set (4);
-
-      CmapSubtableFormat4 &format4 = subtable.u.format4;
-      if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments)))
-        return false;
-    }
-
-    // Write out format 12 sub table.
-    {
-      CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table);
-      subtable.u.format.set (12);
-
-      CmapSubtableFormat12 &format12 = subtable.u.format12;
-      if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups)))
-        return false;
-    }
-
-    c.end_serialize ();
-
-    return true;
+    + hb_iter (encodingRecord)
+    | hb_map (&EncodingRecord::subtable)
+    | hb_map (hb_add (this))
+    | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; })
+    | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); })
+    ;
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  bool subset (hb_subset_context_t *c) const
   {
-    subset_plan cmap_subset_plan;
+    TRACE_SUBSET (this);
 
-    if (unlikely (!_create_plan (plan, &cmap_subset_plan)))
+    cmap *cmap_prime = c->serializer->start_embed<cmap> ();
+    if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
+
+    auto encodingrec_iter =
+    + hb_iter (encodingRecord)
+    | hb_filter ([&] (const EncodingRecord& _)
+                {
+                  if ((_.platformID == 0 && _.encodingID == 3) ||
+                      (_.platformID == 0 && _.encodingID == 4) ||
+                      (_.platformID == 3 && _.encodingID == 1) ||
+                      (_.platformID == 3 && _.encodingID == 10) ||
+                      (this + _.subtable).u.format == 14)
+                    return true;
+
+                  return false;
+                })
+    ;
+
+    if (unlikely (!encodingrec_iter.len ())) return_trace (false);
+
+    const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
+    bool has_format12 = false;
+
+    for (const EncodingRecord& _ : encodingrec_iter)
     {
-      DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan.");
-      return false;
+      unsigned format = (this + _.subtable).u.format;
+      if (format == 12) has_format12 = true;
+
+      const EncodingRecord *table = hb_addressof (_);
+      if      (_.platformID == 0 && _.encodingID ==  3) unicode_bmp = table;
+      else if (_.platformID == 0 && _.encodingID ==  4) unicode_ucs4 = table;
+      else if (_.platformID == 3 && _.encodingID ==  1) ms_bmp = table;
+      else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table;
     }
 
-    // We now know how big our blob needs to be
-    size_t dest_sz = cmap_subset_plan.final_size ();
-    void *dest = malloc (dest_sz);
-    if (unlikely (!dest)) {
-      DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
-      return false;
-    }
+    if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false);
+    if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
 
-    if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest)))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
-      free (dest);
-      return false;
-    }
-
-    // all done, write the blob into dest
-    hb_blob_t *cmap_prime = hb_blob_create ((const char *) dest,
-                                            dest_sz,
-                                            HB_MEMORY_MODE_READONLY,
-                                            dest,
-                                            free);
-    bool result =  plan->add_table (HB_OT_TAG_cmap, cmap_prime);
-    hb_blob_destroy (cmap_prime);
-    return result;
+    auto it =
+    + hb_iter (c->plan->unicodes)
+    | hb_map ([&] (hb_codepoint_t _)
+              {
+                hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID;
+                c->plan->new_gid_for_codepoint (_, &new_gid);
+                return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, new_gid);
+              })
+    | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+                 { return (_.second != HB_MAP_VALUE_INVALID); })
+    ;
+    cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan);
+    return_trace (true);
   }
 
   const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
@@ -969,6 +1478,15 @@
 
     const CmapSubtable *subtable;
 
+    /* Symbol subtable.
+     * Prefer symbol if available.
+     * https://github.com/harfbuzz/harfbuzz/issues/1918 */
+    if ((subtable = this->find_subtable (3, 0)))
+    {
+      if (symbol) *symbol = true;
+      return subtable;
+    }
+
     /* 32-bit subtables. */
     if ((subtable = this->find_subtable (3, 10))) return subtable;
     if ((subtable = this->find_subtable (0, 6))) return subtable;
@@ -981,13 +1499,6 @@
     if ((subtable = this->find_subtable (0, 1))) return subtable;
     if ((subtable = this->find_subtable (0, 0))) return subtable;
 
-    /* Symbol subtable. */
-    if ((subtable = this->find_subtable (3, 0)))
-    {
-      if (symbol) *symbol = true;
-      return subtable;
-    }
-
     /* Meh. */
     return &Null (CmapSubtable);
   }
@@ -1008,9 +1519,9 @@
 
       this->get_glyph_data = subtable;
       if (unlikely (symbol))
-      {
         this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;
-      } else {
+      else
+      {
         switch (subtable->u.format) {
         /* Accelerate format 4 and format 12. */
         default:
@@ -1020,20 +1531,20 @@
           this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
           break;
         case  4:
-          {
-            this->format4_accel.init (&subtable->u.format4);
-            this->get_glyph_data = &this->format4_accel;
-            this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
-          }
+        {
+          this->format4_accel.init (&subtable->u.format4);
+          this->get_glyph_data = &this->format4_accel;
+          this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
           break;
         }
+        }
       }
     }
 
     void fini () { this->table.destroy (); }
 
     bool get_nominal_glyph (hb_codepoint_t  unicode,
-                                   hb_codepoint_t *glyph) const
+                            hb_codepoint_t *glyph) const
     {
       if (unlikely (!this->get_glyph_funcZ)) return false;
       return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
@@ -1076,19 +1587,16 @@
       return get_nominal_glyph (unicode, glyph);
     }
 
-    void collect_unicodes (hb_set_t *out) const
-    {
-      subtable->collect_unicodes (out);
-    }
+    void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
+    { subtable->collect_unicodes (out, num_glyphs); }
+    void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping,
+                          unsigned num_glyphs = UINT_MAX) const
+    { subtable->collect_mapping (unicodes, mapping, num_glyphs); }
     void collect_variation_selectors (hb_set_t *out) const
-    {
-      subtable_uvs->collect_variation_selectors (out);
-    }
+    { subtable_uvs->collect_variation_selectors (out); }
     void collect_variation_unicodes (hb_codepoint_t variation_selector,
                                      hb_set_t *out) const
-    {
-      subtable_uvs->collect_variation_unicodes (variation_selector, out);
-    }
+    { subtable_uvs->collect_variation_unicodes (variation_selector, out); }
 
     protected:
     typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
@@ -1096,18 +1604,18 @@
                                               hb_codepoint_t *glyph);
 
     template <typename Type>
-    static bool get_glyph_from (const void *obj,
-                                hb_codepoint_t codepoint,
-                                hb_codepoint_t *glyph)
+    HB_INTERNAL static bool get_glyph_from (const void *obj,
+                                            hb_codepoint_t codepoint,
+                                            hb_codepoint_t *glyph)
     {
       const Type *typed_obj = (const Type *) obj;
       return typed_obj->get_glyph (codepoint, glyph);
     }
 
     template <typename Type>
-    static bool get_glyph_from_symbol (const void *obj,
-                                              hb_codepoint_t codepoint,
-                                              hb_codepoint_t *glyph)
+    HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
+                                                   hb_codepoint_t codepoint,
+                                                   hb_codepoint_t *glyph)
     {
       const Type *typed_obj = (const Type *) obj;
       if (likely (typed_obj->get_glyph (codepoint, glyph)))
@@ -1135,6 +1643,7 @@
 
     CmapSubtableFormat4::accelerator_t format4_accel;
 
+    public:
     hb_blob_ptr_t<cmap> table;
   };
 
@@ -1144,8 +1653,8 @@
                                      unsigned int encoding_id) const
   {
     EncodingRecord key;
-    key.platformID.set (platform_id);
-    key.encodingID.set (encoding_id);
+    key.platformID = platform_id;
+    key.encodingID = encoding_id;
 
     const EncodingRecord &result = encodingRecord.bsearch (key);
     if (!result.subtable)
@@ -1154,6 +1663,28 @@
     return &(this+result.subtable);
   }
 
+  const EncodingRecord *find_encodingrec (unsigned int platform_id,
+                                          unsigned int encoding_id) const
+  {
+    EncodingRecord key;
+    key.platformID = platform_id;
+    key.encodingID = encoding_id;
+
+    return encodingRecord.as_array ().bsearch (key);
+  }
+
+  bool find_subtable (unsigned format) const
+  {
+    auto it =
+    + hb_iter (encodingRecord)
+    | hb_map (&EncodingRecord::subtable)
+    | hb_map (hb_add (this))
+    | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; })
+    ;
+
+    return it.len ();
+  }
+
   public:
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1165,9 +1696,9 @@
   }
 
   protected:
-  HBUINT16              version;        /* Table version number (0). */
+  HBUINT16      version;        /* Table version number (0). */
   SortedArrayOf<EncodingRecord>
-                        encodingRecord; /* Encoding tables. */
+                encodingRecord; /* Encoding tables. */
   public:
   DEFINE_SIZE_ARRAY (4, encodingRecord);
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh
index 36ec2be..3e619bd 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh
@@ -21,7 +21,7 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
- * Google Author(s): Seigo Nonaka
+ * Google Author(s): Seigo Nonaka, Calder Kitagawa
  */
 
 #ifndef HB_OT_COLOR_CBDT_TABLE_HH
@@ -43,6 +43,35 @@
 
 namespace OT {
 
+struct cblc_bitmap_size_subset_context_t
+{
+  const char *cbdt;
+  unsigned int cbdt_length;
+  hb_vector_t<char> *cbdt_prime;
+  unsigned int size;            /* INOUT
+                                 *  Input: old size of IndexSubtable
+                                 *  Output: new size of IndexSubtable
+                                 */
+  unsigned int num_tables;      /* INOUT
+                                 *  Input: old number of subtables.
+                                 *  Output: new number of subtables.
+                                 */
+  hb_codepoint_t start_glyph;   /* OUT */
+  hb_codepoint_t end_glyph;     /* OUT */
+};
+
+static inline bool
+_copy_data_to_cbdt (hb_vector_t<char> *cbdt_prime,
+                    const void        *data,
+                    unsigned           length)
+{
+  unsigned int new_len = cbdt_prime->length + length;
+  if (unlikely (!cbdt_prime->alloc (new_len))) return false;
+  memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length);
+  cbdt_prime->length = new_len;
+  return true;
+}
+
 struct SmallGlyphMetrics
 {
   bool sanitize (hb_sanitize_context_t *c) const
@@ -51,12 +80,12 @@
     return_trace (c->check_struct (this));
   }
 
-  void get_extents (hb_glyph_extents_t *extents) const
+  void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const
   {
-    extents->x_bearing = bearingX;
-    extents->y_bearing = bearingY;
-    extents->width = width;
-    extents->height = - (hb_position_t) height;
+    extents->x_bearing = font->em_scale_x (bearingX);
+    extents->y_bearing = font->em_scale_y (bearingY);
+    extents->width = font->em_scale_x (width);
+    extents->height = font->em_scale_y (-static_cast<int>(height));
   }
 
   HBUINT8       height;
@@ -65,7 +94,7 @@
   HBINT8        bearingY;
   HBUINT8       advance;
   public:
-  DEFINE_SIZE_STATIC(5);
+  DEFINE_SIZE_STATIC (5);
 };
 
 struct BigGlyphMetrics : SmallGlyphMetrics
@@ -74,7 +103,7 @@
   HBINT8        vertBearingY;
   HBUINT8       vertAdvance;
   public:
-  DEFINE_SIZE_STATIC(8);
+  DEFINE_SIZE_STATIC (8);
 };
 
 struct SBitLineMetrics
@@ -98,7 +127,7 @@
   HBINT8        padding1;
   HBINT8        padding2;
   public:
-  DEFINE_SIZE_STATIC(12);
+  DEFINE_SIZE_STATIC (12);
 };
 
 
@@ -118,7 +147,7 @@
   HBUINT16      imageFormat;
   HBUINT32      imageDataOffset;
   public:
-  DEFINE_SIZE_STATIC(8);
+  DEFINE_SIZE_STATIC (8);
 };
 
 template <typename OffsetType>
@@ -143,11 +172,23 @@
     return true;
   }
 
+  bool add_offset (hb_serialize_context_t *c,
+                   unsigned int offset,
+                   unsigned int *size /* OUT (accumulated) */)
+  {
+    TRACE_SERIALIZE (this);
+    Offset<OffsetType> embedded_offset;
+    embedded_offset = offset;
+    *size += sizeof (OffsetType);
+    auto *o = c->embed (embedded_offset);
+    return_trace ((bool) o);
+  }
+
   IndexSubtableHeader   header;
-  UnsizedArrayOf<Offset<OffsetType> >
+  UnsizedArrayOf<Offset<OffsetType>>
                         offsetArrayZ;
   public:
-  DEFINE_SIZE_ARRAY(8, offsetArrayZ);
+  DEFINE_SIZE_ARRAY (8, offsetArrayZ);
 };
 
 struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<HBUINT32> {};
@@ -159,35 +200,153 @@
   {
     TRACE_SANITIZE (this);
     if (!u.header.sanitize (c)) return_trace (false);
-    switch (u.header.indexFormat) {
+    switch (u.header.indexFormat)
+    {
     case 1: return_trace (u.format1.sanitize (c, glyph_count));
     case 3: return_trace (u.format3.sanitize (c, glyph_count));
     default:return_trace (true);
     }
   }
 
+  bool
+  finish_subtable (hb_serialize_context_t *c,
+                   unsigned int cbdt_prime_len,
+                   unsigned int num_glyphs,
+                   unsigned int *size /* OUT (accumulated) */)
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset;
+    switch (u.header.indexFormat)
+    {
+    case 1: return_trace (u.format1.add_offset (c, local_offset, size));
+    case 3: {
+      if (!u.format3.add_offset (c, local_offset, size))
+        return_trace (false);
+      if (!(num_glyphs & 0x01))  // Pad to 32-bit alignment if needed.
+        return_trace (u.format3.add_offset (c, 0, size));
+      return_trace (true);
+    }
+    // TODO: implement 2, 4, 5.
+    case 2: case 4:  // No-op.
+    case 5:  // Pad to 32-bit aligned.
+    default: return_trace (false);
+    }
+  }
+
+  bool
+  fill_missing_glyphs (hb_serialize_context_t *c,
+                       unsigned int cbdt_prime_len,
+                       unsigned int num_missing,
+                       unsigned int *size /* OUT (accumulated) */,
+                       unsigned int *num_glyphs /* OUT (accumulated) */)
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset;
+    switch (u.header.indexFormat)
+    {
+    case 1: {
+      for (unsigned int i = 0; i < num_missing; i++)
+      {
+        if (unlikely (!u.format1.add_offset (c, local_offset, size)))
+          return_trace (false);
+        *num_glyphs += 1;
+      }
+      return_trace (true);
+    }
+    case 3: {
+      for (unsigned int i = 0; i < num_missing; i++)
+      {
+        if (unlikely (!u.format3.add_offset (c, local_offset, size)))
+          return_trace (false);
+        *num_glyphs += 1;
+      }
+      return_trace (true);
+    }
+    // TODO: implement 2, 4, 5.
+    case 2:  // Add empty space in cbdt_prime?.
+    case 4: case 5:  // No-op as sparse is supported.
+    default: return_trace (false);
+    }
+  }
+
+  bool
+  copy_glyph_at_idx (hb_serialize_context_t *c, unsigned int idx,
+                     const char *cbdt, unsigned int cbdt_length,
+                     hb_vector_t<char> *cbdt_prime /* INOUT */,
+                     IndexSubtable *subtable_prime /* INOUT */,
+                     unsigned int *size /* OUT (accumulated) */) const
+  {
+    TRACE_SERIALIZE (this);
+
+    unsigned int offset, length, format;
+    if (unlikely (!get_image_data (idx, &offset, &length, &format))) return_trace (false);
+    if (unlikely (offset > cbdt_length || cbdt_length - offset < length)) return_trace (false);
+
+    auto *header_prime = subtable_prime->get_header ();
+    unsigned int new_local_offset = cbdt_prime->length - (unsigned int) header_prime->imageDataOffset;
+    if (unlikely (!_copy_data_to_cbdt (cbdt_prime, cbdt + offset, length))) return_trace (false);
+
+    return_trace (subtable_prime->add_offset (c, new_local_offset, size));
+  }
+
+  bool
+  add_offset (hb_serialize_context_t *c, unsigned int local_offset,
+              unsigned int *size /* OUT (accumulated) */)
+  {
+    TRACE_SERIALIZE (this);
+    switch (u.header.indexFormat)
+    {
+    case 1: return_trace (u.format1.add_offset (c, local_offset, size));
+    case 3: return_trace (u.format3.add_offset (c, local_offset, size));
+    // TODO: Implement tables 2, 4, 5
+    case 2:  // Should be a no-op.
+    case 4: case 5:  // Handle sparse cases.
+    default: return_trace (false);
+    }
+  }
+
   bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
   {
-    switch (u.header.indexFormat) {
+    switch (u.header.indexFormat)
+    {
     case 2: case 5: /* TODO */
     case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
     default:return (false);
     }
   }
 
-  bool get_image_data (unsigned int idx,
-                       unsigned int *offset,
-                       unsigned int *length,
-                       unsigned int *format) const
+  bool
+  get_image_data (unsigned int idx, unsigned int *offset,
+                  unsigned int *length, unsigned int *format) const
   {
     *format = u.header.imageFormat;
-    switch (u.header.indexFormat) {
+    switch (u.header.indexFormat)
+    {
     case 1: return u.format1.get_image_data (idx, offset, length);
     case 3: return u.format3.get_image_data (idx, offset, length);
     default: return false;
     }
   }
 
+  const IndexSubtableHeader* get_header () const { return &u.header; }
+
+  void populate_header (unsigned index_format,
+                        unsigned image_format,
+                        unsigned int image_data_offset,
+                        unsigned int *size)
+  {
+    u.header.indexFormat = index_format;
+    u.header.imageFormat = image_format;
+    u.header.imageDataOffset = image_data_offset;
+    switch (u.header.indexFormat)
+    {
+    case 1: *size += IndexSubtableFormat1::min_size; break;
+    case 3: *size += IndexSubtableFormat3::min_size; break;
+    }
+  }
+
   protected:
   union {
   IndexSubtableHeader   header;
@@ -209,12 +368,135 @@
                   offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
   }
 
-  bool get_extents (hb_glyph_extents_t *extents,
-                    const void *base) const
+  const IndexSubtable* get_subtable (const void *base) const
   {
-    return (base+offsetToSubtable).get_extents (extents);
+    return &(base+offsetToSubtable);
   }
 
+  bool add_new_subtable (hb_subset_context_t* c,
+                         cblc_bitmap_size_subset_context_t *bitmap_size_context,
+                         IndexSubtableRecord *record,
+                         const hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> *lookup, /* IN */
+                         const void *base,
+                         unsigned int *start /* INOUT */) const
+  {
+    TRACE_SERIALIZE (this);
+
+    auto *subtable = c->serializer->start_embed<IndexSubtable> ();
+    if (unlikely (!subtable)) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false);
+
+    auto *old_subtable = get_subtable (base);
+    auto *old_header = old_subtable->get_header ();
+
+    subtable->populate_header (old_header->indexFormat,
+                               old_header->imageFormat,
+                               bitmap_size_context->cbdt_prime->length,
+                               &bitmap_size_context->size);
+
+    unsigned int num_glyphs = 0;
+    bool early_exit = false;
+    for (unsigned int i = *start; i < lookup->length; i++)
+    {
+      hb_codepoint_t new_gid = (*lookup)[i].first;
+      const IndexSubtableRecord *next_record = (*lookup)[i].second;
+      const IndexSubtable *next_subtable = next_record->get_subtable (base);
+      auto *next_header = next_subtable->get_header ();
+      if (next_header != old_header)
+      {
+        *start = i;
+        early_exit = true;
+        break;
+      }
+      unsigned int num_missing = record->add_glyph_for_subset (new_gid);
+      if (unlikely (!subtable->fill_missing_glyphs (c->serializer,
+                                                    bitmap_size_context->cbdt_prime->length,
+                                                    num_missing,
+                                                    &bitmap_size_context->size,
+                                                    &num_glyphs)))
+        return_trace (false);
+
+      hb_codepoint_t old_gid = 0;
+      c->plan->old_gid_for_new_gid (new_gid, &old_gid);
+      if (old_gid < next_record->firstGlyphIndex)
+        return_trace (false);
+
+      unsigned int old_idx = (unsigned int) old_gid - next_record->firstGlyphIndex;
+      if (unlikely (!next_subtable->copy_glyph_at_idx (c->serializer,
+                                                       old_idx,
+                                                       bitmap_size_context->cbdt,
+                                                       bitmap_size_context->cbdt_length,
+                                                       bitmap_size_context->cbdt_prime,
+                                                       subtable,
+                                                       &bitmap_size_context->size)))
+        return_trace (false);
+      num_glyphs += 1;
+    }
+    if (!early_exit)
+      *start = lookup->length;
+    if (unlikely (!subtable->finish_subtable (c->serializer,
+                                              bitmap_size_context->cbdt_prime->length,
+                                              num_glyphs,
+                                              &bitmap_size_context->size)))
+      return_trace (false);
+    return_trace (true);
+  }
+
+  bool add_new_record (hb_subset_context_t *c,
+                       cblc_bitmap_size_subset_context_t *bitmap_size_context,
+                       const hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> *lookup, /* IN */
+                       const void *base,
+                       unsigned int *start, /* INOUT */
+                       hb_vector_t<IndexSubtableRecord>* records /* INOUT */) const
+  {
+    TRACE_SERIALIZE (this);
+    auto snap = c->serializer->snapshot ();
+    unsigned int old_size = bitmap_size_context->size;
+    unsigned int old_cbdt_prime_length = bitmap_size_context->cbdt_prime->length;
+
+    // Set to invalid state to indicate filling glyphs is not yet started.
+    if (unlikely (!records->resize (records->length + 1)))
+      return_trace (c->serializer->check_success (false));
+
+    (*records)[records->length - 1].firstGlyphIndex = 1;
+    (*records)[records->length - 1].lastGlyphIndex = 0;
+    bitmap_size_context->size += IndexSubtableRecord::min_size;
+
+    c->serializer->push ();
+
+    if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start)))
+    {
+      c->serializer->pop_discard ();
+      c->serializer->revert (snap);
+      bitmap_size_context->cbdt_prime->shrink (old_cbdt_prime_length);
+      bitmap_size_context->size = old_size;
+      records->resize (records->length - 1);
+      return_trace (false);
+    }
+
+    bitmap_size_context->num_tables += 1;
+    return_trace (true);
+  }
+
+  unsigned int add_glyph_for_subset (hb_codepoint_t gid)
+  {
+    if (firstGlyphIndex > lastGlyphIndex)
+    {
+      firstGlyphIndex = gid;
+      lastGlyphIndex = gid;
+      return 0;
+    }
+    // TODO maybe assert? this shouldn't occur.
+    if (lastGlyphIndex > gid)
+      return 0;
+    unsigned int num_missing = (unsigned int) (gid - lastGlyphIndex - 1);
+    lastGlyphIndex = gid;
+    return num_missing;
+  }
+
+  bool get_extents (hb_glyph_extents_t *extents, const void *base) const
+  { return (base+offsetToSubtable).get_extents (extents); }
+
   bool get_image_data (unsigned int  gid,
                        const void   *base,
                        unsigned int *offset,
@@ -226,11 +508,11 @@
                                                    offset, length, format);
   }
 
-  GlyphID                       firstGlyphIndex;
-  GlyphID                       lastGlyphIndex;
+  HBGlyphID                     firstGlyphIndex;
+  HBGlyphID                     lastGlyphIndex;
   LOffsetTo<IndexSubtable>      offsetToSubtable;
   public:
-  DEFINE_SIZE_STATIC(8);
+  DEFINE_SIZE_STATIC (8);
 };
 
 struct IndexSubtableArray
@@ -243,6 +525,79 @@
     return_trace (indexSubtablesZ.sanitize (c, count, this));
   }
 
+  void
+  build_lookup (hb_subset_context_t *c, cblc_bitmap_size_subset_context_t *bitmap_size_context,
+                hb_vector_t<hb_pair_t<hb_codepoint_t,
+                const IndexSubtableRecord*>> *lookup /* OUT */) const
+  {
+    bool start_glyph_is_set = false;
+    for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++)
+    {
+      hb_codepoint_t old_gid;
+      if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue;
+
+      const IndexSubtableRecord* record = find_table (old_gid, bitmap_size_context->num_tables);
+      if (unlikely (!record)) continue;
+
+      // Don't add gaps to the lookup. The best way to determine if a glyph is a
+      // gap is that it has no image data.
+      unsigned int offset, length, format;
+      if (unlikely (!record->get_image_data (old_gid, this, &offset, &length, &format))) continue;
+
+      lookup->push (hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*> (new_gid, record));
+
+      if (!start_glyph_is_set)
+      {
+        bitmap_size_context->start_glyph = new_gid;
+        start_glyph_is_set = true;
+      }
+
+      bitmap_size_context->end_glyph = new_gid;
+    }
+  }
+
+  bool
+  subset (hb_subset_context_t *c,
+          cblc_bitmap_size_subset_context_t *bitmap_size_context) const
+  {
+    TRACE_SUBSET (this);
+
+    auto *dst = c->serializer->start_embed<IndexSubtableArray> ();
+    if (unlikely (!dst)) return_trace (false);
+
+    hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup;
+    build_lookup (c, bitmap_size_context, &lookup);
+    if (unlikely (lookup.in_error ()))
+      return c->serializer->check_success (false);
+
+    bitmap_size_context->size = 0;
+    bitmap_size_context->num_tables = 0;
+    hb_vector_t<IndexSubtableRecord> records;
+    for (unsigned int start = 0; start < lookup.length;)
+    {
+      if (unlikely (!lookup[start].second->add_new_record (c, bitmap_size_context, &lookup, this, &start, &records)))
+      {
+        // Discard any leftover pushes to the serializer from successful records.
+        for (unsigned int i = 0; i < records.length; i++)
+          c->serializer->pop_discard ();
+        return_trace (false);
+      }
+    }
+
+    /* Workaround to ensure offset ordering is from least to greatest when
+     * resolving links. */
+    hb_vector_t<hb_serialize_context_t::objidx_t> objidxs;
+    for (unsigned int i = 0; i < records.length; i++)
+      objidxs.push (c->serializer->pop_pack ());
+    for (unsigned int i = 0; i < records.length; i++)
+    {
+      IndexSubtableRecord* record = c->serializer->embed (records[i]);
+      if (unlikely (!record)) return_trace (false);
+      c->serializer->add_link (record->offsetToSubtable, objidxs[records.length - 1 - i]);
+    }
+    return_trace (true);
+  }
+
   public:
   const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
   {
@@ -274,14 +629,48 @@
                   vertical.sanitize (c));
   }
 
-  const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
-                                         const void *base,
-                                         const void **out_base) const
+  const IndexSubtableRecord *
+  find_table (hb_codepoint_t glyph, const void *base, const void **out_base) const
   {
     *out_base = &(base+indexSubtableArrayOffset);
     return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
   }
 
+  bool
+  subset (hb_subset_context_t *c, const void *base,
+          const char *cbdt, unsigned int cbdt_length,
+          hb_vector_t<char> *cbdt_prime /* INOUT */) const
+  {
+    TRACE_SUBSET (this);
+    auto *out_table = c->serializer->embed (this);
+    if (unlikely (!out_table)) return_trace (false);
+
+    cblc_bitmap_size_subset_context_t bitmap_size_context;
+    bitmap_size_context.cbdt = cbdt;
+    bitmap_size_context.cbdt_length = cbdt_length;
+    bitmap_size_context.cbdt_prime = cbdt_prime;
+    bitmap_size_context.size = indexTablesSize;
+    bitmap_size_context.num_tables = numberOfIndexSubtables;
+    bitmap_size_context.start_glyph = 1;
+    bitmap_size_context.end_glyph = 0;
+
+    if (!out_table->indexSubtableArrayOffset.serialize_subset (c,
+                                                               indexSubtableArrayOffset,
+                                                               base,
+                                                               &bitmap_size_context))
+      return_trace (false);
+    if (!bitmap_size_context.size ||
+        !bitmap_size_context.num_tables ||
+        bitmap_size_context.start_glyph > bitmap_size_context.end_glyph)
+      return_trace (false);
+
+    out_table->indexTablesSize = bitmap_size_context.size;
+    out_table->numberOfIndexSubtables = bitmap_size_context.num_tables;
+    out_table->startGlyphIndex = bitmap_size_context.start_glyph;
+    out_table->endGlyphIndex = bitmap_size_context.end_glyph;
+    return_trace (true);
+  }
+
   protected:
   LNNOffsetTo<IndexSubtableArray>
                         indexSubtableArrayOffset;
@@ -290,14 +679,14 @@
   HBUINT32              colorRef;
   SBitLineMetrics       horizontal;
   SBitLineMetrics       vertical;
-  GlyphID               startGlyphIndex;
-  GlyphID               endGlyphIndex;
+  HBGlyphID             startGlyphIndex;
+  HBGlyphID             endGlyphIndex;
   HBUINT8               ppemX;
   HBUINT8               ppemY;
   HBUINT8               bitDepth;
   HBINT8                flags;
   public:
-  DEFINE_SIZE_STATIC(48);
+  DEFINE_SIZE_STATIC (48);
 };
 
 
@@ -310,7 +699,7 @@
   SmallGlyphMetrics     glyphMetrics;
   LArrayOf<HBUINT8>     data;
   public:
-  DEFINE_SIZE_ARRAY(9, data);
+  DEFINE_SIZE_ARRAY (9, data);
 };
 
 struct GlyphBitmapDataFormat18
@@ -318,14 +707,14 @@
   BigGlyphMetrics       glyphMetrics;
   LArrayOf<HBUINT8>     data;
   public:
-  DEFINE_SIZE_ARRAY(12, data);
+  DEFINE_SIZE_ARRAY (12, data);
 };
 
 struct GlyphBitmapDataFormat19
 {
   LArrayOf<HBUINT8>     data;
   public:
-  DEFINE_SIZE_ARRAY(4, data);
+  DEFINE_SIZE_ARRAY (4, data);
 };
 
 struct CBLC
@@ -342,22 +731,60 @@
                   sizeTables.sanitize (c, this));
   }
 
+  static bool
+  sink_cbdt (hb_subset_context_t *c, hb_vector_t<char>* cbdt_prime)
+  {
+    hb_blob_t *cbdt_prime_blob = hb_blob_create (cbdt_prime->arrayZ,
+                                                 cbdt_prime->length,
+                                                 HB_MEMORY_MODE_WRITABLE,
+                                                 cbdt_prime->arrayZ,
+                                                 free);
+    cbdt_prime->init ();  // Leak arrayZ to the blob.
+    bool ret = c->plan->add_table (HB_OT_TAG_CBDT, cbdt_prime_blob);
+    hb_blob_destroy (cbdt_prime_blob);
+    return ret;
+  }
+
+  bool
+  subset_size_table (hb_subset_context_t *c, const BitmapSizeTable& table,
+                     const char *cbdt /* IN */, unsigned int cbdt_length,
+                     CBLC *cblc_prime /* INOUT */, hb_vector_t<char> *cbdt_prime /* INOUT */) const
+  {
+    TRACE_SUBSET (this);
+    cblc_prime->sizeTables.len++;
+
+    auto snap = c->serializer->snapshot ();
+    auto cbdt_prime_len = cbdt_prime->length;
+
+    if (!table.subset (c, this, cbdt, cbdt_length, cbdt_prime))
+    {
+      cblc_prime->sizeTables.len--;
+      c->serializer->revert (snap);
+      cbdt_prime->shrink (cbdt_prime_len);
+      return_trace (false);
+    }
+    return_trace (true);
+  }
+
+  // Implemented in cc file as it depends on definition of CBDT.
+  HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+
   protected:
   const BitmapSizeTable &choose_strike (hb_font_t *font) const
   {
     unsigned count = sizeTables.len;
     if (unlikely (!count))
-      return Null(BitmapSizeTable);
+      return Null (BitmapSizeTable);
 
-    unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
+    unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
     if (!requested_ppem)
       requested_ppem = 1<<30; /* Choose largest strike. */
     unsigned int best_i = 0;
-    unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY);
+    unsigned int best_ppem = hb_max (sizeTables[0].ppemX, sizeTables[0].ppemY);
 
     for (unsigned int i = 1; i < count; i++)
     {
-      unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY);
+      unsigned int ppem = hb_max (sizeTables[i].ppemX, sizeTables[i].ppemY);
       if ((requested_ppem <= ppem && ppem < best_ppem) ||
           (requested_ppem > best_ppem && ppem > best_ppem))
       {
@@ -373,7 +800,7 @@
   FixedVersion<>                version;
   LArrayOf<BitmapSizeTable>     sizeTables;
   public:
-  DEFINE_SIZE_ARRAY(8, sizeTables);
+  DEFINE_SIZE_ARRAY (8, sizeTables);
 };
 
 struct CBDT
@@ -384,8 +811,8 @@
   {
     void init (hb_face_t *face)
     {
-      cblc = hb_sanitize_context_t().reference_table<CBLC> (face);
-      cbdt = hb_sanitize_context_t().reference_table<CBDT> (face);
+      cblc = hb_sanitize_context_t ().reference_table<CBLC> (face);
+      cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face);
 
       upem = hb_face_get_upem (face);
     }
@@ -396,8 +823,8 @@
       this->cbdt.destroy ();
     }
 
-    bool get_extents (hb_font_t *font, hb_codepoint_t glyph,
-                      hb_glyph_extents_t *extents) const
+    bool
+    get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
     {
       const void *base;
       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
@@ -412,48 +839,42 @@
       if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
         return false;
 
-      {
-        unsigned int cbdt_len = cbdt.get_length ();
-        if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
-          return false;
+      unsigned int cbdt_len = cbdt.get_length ();
+      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+        return false;
 
-        switch (image_format)
-        {
-          case 17: {
-            if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
-              return false;
-            const GlyphBitmapDataFormat17& glyphFormat17 =
-                StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
-            glyphFormat17.glyphMetrics.get_extents (extents);
-            break;
-          }
-          case 18: {
-            if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
-              return false;
-            const GlyphBitmapDataFormat18& glyphFormat18 =
-                StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
-            glyphFormat18.glyphMetrics.get_extents (extents);
-            break;
-          }
-          default:
-            // TODO: Support other image formats.
-            return false;
-        }
+      switch (image_format)
+      {
+      case 17: {
+        if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
+          return false;
+        auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+        glyphFormat17.glyphMetrics.get_extents (font, extents);
+        break;
+      }
+      case 18: {
+        if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
+          return false;
+        auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
+        glyphFormat18.glyphMetrics.get_extents (font, extents);
+        break;
+      }
+      default: return false; /* TODO: Support other image formats. */
       }
 
       /* Convert to font units. */
-      double x_scale = upem / (double) strike.ppemX;
-      double y_scale = upem / (double) strike.ppemY;
-      extents->x_bearing = round (extents->x_bearing * x_scale);
-      extents->y_bearing = round (extents->y_bearing * y_scale);
-      extents->width = round (extents->width * x_scale);
-      extents->height = round (extents->height * y_scale);
+      float x_scale = upem / (float) strike.ppemX;
+      float y_scale = upem / (float) strike.ppemY;
+      extents->x_bearing = roundf (extents->x_bearing * x_scale);
+      extents->y_bearing = roundf (extents->y_bearing * y_scale);
+      extents->width = roundf (extents->width * x_scale);
+      extents->height = roundf (extents->height * y_scale);
 
       return true;
     }
 
-    hb_blob_t* reference_png (hb_font_t      *font,
-                                     hb_codepoint_t  glyph) const
+    hb_blob_t*
+    reference_png (hb_font_t *font, hb_codepoint_t glyph) const
     {
       const void *base;
       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
@@ -465,44 +886,41 @@
       if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
         return hb_blob_get_empty ();
 
+      unsigned int cbdt_len = cbdt.get_length ();
+      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+        return hb_blob_get_empty ();
+
+      switch (image_format)
       {
-        unsigned int cbdt_len = cbdt.get_length ();
-        if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+      case 17:
+      {
+        if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
           return hb_blob_get_empty ();
-
-        switch (image_format)
-        {
-          case 17: {
-            if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
-              return hb_blob_get_empty ();
-            const GlyphBitmapDataFormat17& glyphFormat17 =
-              StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
-            return hb_blob_create_sub_blob (cbdt.get_blob (),
-                                            image_offset + GlyphBitmapDataFormat17::min_size,
-                                            glyphFormat17.data.len);
-          }
-          case 18: {
-            if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
-              return hb_blob_get_empty ();
-            const GlyphBitmapDataFormat18& glyphFormat18 =
-              StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
-            return hb_blob_create_sub_blob (cbdt.get_blob (),
-                                            image_offset + GlyphBitmapDataFormat18::min_size,
-                                            glyphFormat18.data.len);
-          }
-          case 19: {
-            if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
-              return hb_blob_get_empty ();
-            const GlyphBitmapDataFormat19& glyphFormat19 =
-              StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
-            return hb_blob_create_sub_blob (cbdt.get_blob (),
-                                            image_offset + GlyphBitmapDataFormat19::min_size,
-                                            glyphFormat19.data.len);
-          }
-        }
+        auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+        return hb_blob_create_sub_blob (cbdt.get_blob (),
+                                        image_offset + GlyphBitmapDataFormat17::min_size,
+                                        glyphFormat17.data.len);
       }
-
-      return hb_blob_get_empty ();
+      case 18:
+      {
+        if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
+          return hb_blob_get_empty ();
+        auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
+        return hb_blob_create_sub_blob (cbdt.get_blob (),
+                                        image_offset + GlyphBitmapDataFormat18::min_size,
+                                        glyphFormat18.data.len);
+      }
+      case 19:
+      {
+        if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
+          return hb_blob_get_empty ();
+        auto &glyphFormat19 = StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
+        return hb_blob_create_sub_blob (cbdt.get_blob (),
+                                        image_offset + GlyphBitmapDataFormat19::min_size,
+                                        glyphFormat19.data.len);
+      }
+      default: return hb_blob_get_empty (); /* TODO: Support other image formats. */
+      }
     }
 
     bool has_data () const { return cbdt.get_length (); }
@@ -525,9 +943,41 @@
   FixedVersion<>                version;
   UnsizedArrayOf<HBUINT8>       dataZ;
   public:
-  DEFINE_SIZE_ARRAY(4, dataZ);
+  DEFINE_SIZE_ARRAY (4, dataZ);
 };
 
+inline bool
+CBLC::subset (hb_subset_context_t *c) const
+{
+  TRACE_SUBSET (this);
+
+  auto *cblc_prime = c->serializer->start_embed<CBLC> ();
+
+  // Use a vector as a secondary buffer as the tables need to be built in parallel.
+  hb_vector_t<char> cbdt_prime;
+
+  if (unlikely (!cblc_prime)) return_trace (false);
+  if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false);
+  cblc_prime->version = version;
+
+  hb_blob_t* cbdt_blob = hb_sanitize_context_t ().reference_table<CBDT> (c->plan->source);
+  unsigned int cbdt_length;
+  CBDT* cbdt = (CBDT *) hb_blob_get_data (cbdt_blob, &cbdt_length);
+  if (unlikely (cbdt_length < CBDT::min_size))
+  {
+    hb_blob_destroy (cbdt_blob);
+    return_trace (false);
+  }
+  _copy_data_to_cbdt (&cbdt_prime, cbdt, CBDT::min_size);
+
+  for (const BitmapSizeTable& table : + sizeTables.iter ())
+    subset_size_table (c, table, (const char *) cbdt, cbdt_length, cblc_prime, &cbdt_prime);
+
+  hb_blob_destroy (cbdt_blob);
+
+  return_trace (CBLC::sink_cbdt (c, &cbdt_prime));
+}
+
 struct CBDT_accelerator_t : CBDT::accelerator_t {};
 
 } /* namespace OT */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh
index 362b4a1..21821d4 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2018  Ebrahim Byagowi
+ * Copyright © 2020  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -20,6 +21,8 @@
  * 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): Calder Kitagawa
  */
 
 #ifndef HB_OT_COLOR_COLR_TABLE_HH
@@ -39,6 +42,8 @@
 
 struct LayerRecord
 {
+  operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -46,7 +51,7 @@
   }
 
   public:
-  GlyphID       glyphId;        /* Glyph ID of layer glyph */
+  HBGlyphID     glyphId;        /* Glyph ID of layer glyph */
   Index         colorIdx;       /* Index value to use with a
                                  * selected color palette.
                                  * An index value of 0xFFFF
@@ -73,7 +78,7 @@
   }
 
   public:
-  GlyphID       glyphId;        /* Glyph ID of reference glyph */
+  HBGlyphID     glyphId;        /* Glyph ID of reference glyph */
   HBUINT16      firstLayerIdx;  /* Index (from beginning of
                                  * the Layer Records) to the
                                  * layer record. There will be
@@ -98,22 +103,50 @@
   {
     const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
 
-    hb_array_t<const LayerRecord> all_layers ((this+layersZ).arrayZ, numLayers);
+    hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
     hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
                                                                        record.numLayers);
     if (count)
     {
-      hb_array_t<const LayerRecord> segment_layers = glyph_layers.sub_array (start_offset, *count);
-      *count = segment_layers.length;
-      for (unsigned int i = 0; i < segment_layers.length; i++)
-      {
-        layers[i].glyph = segment_layers.arrayZ[i].glyphId;
-        layers[i].color_index = segment_layers.arrayZ[i].colorIdx;
-      }
+      + glyph_layers.sub_array (start_offset, count)
+      | hb_sink (hb_array (layers, *count))
+      ;
     }
     return glyph_layers.length;
   }
 
+  struct accelerator_t
+  {
+    accelerator_t () {}
+    ~accelerator_t () { fini (); }
+
+    void init (hb_face_t *face)
+    { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
+
+    void fini () { this->colr.destroy (); }
+
+    bool is_valid () { return colr.get_blob ()->length; }
+
+    void closure_glyphs (hb_codepoint_t glyph,
+                         hb_set_t *related_ids /* OUT */) const
+    { colr->closure_glyphs (glyph, related_ids); }
+
+    private:
+    hb_blob_ptr_t<COLR> colr;
+  };
+
+  void closure_glyphs (hb_codepoint_t glyph,
+                       hb_set_t *related_ids /* OUT */) const
+  {
+    const BaseGlyphRecord *record = get_base_glyph_record (glyph);
+    if (!record) return;
+
+    auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
+                                                                       record->numLayers);
+    if (!glyph_layers.length) return;
+    related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -122,12 +155,117 @@
                           (this+layersZ).sanitize (c, numLayers)));
   }
 
+  template<typename BaseIterator, typename LayerIterator,
+           hb_requires (hb_is_iterator (BaseIterator)),
+           hb_requires (hb_is_iterator (LayerIterator))>
+  bool serialize (hb_serialize_context_t *c,
+                  unsigned version,
+                  BaseIterator base_it,
+                  LayerIterator layer_it)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (base_it.len () != layer_it.len ()))
+      return_trace (false);
+
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    this->version = version;
+    numLayers = 0;
+    numBaseGlyphs = base_it.len ();
+    baseGlyphsZ = COLR::min_size;
+    layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size;
+
+    for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
+    {
+      auto* record = c->embed (_);
+      if (unlikely (!record)) return_trace (false);
+      record->firstLayerIdx = numLayers;
+      numLayers += record->numLayers;
+    }
+
+    for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
+      _.as_array ().copy (c);
+
+    return_trace (true);
+  }
+
+  const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
+  {
+    if ((unsigned int) gid == 0) // Ignore notdef.
+      return nullptr;
+    const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
+    if ((record && (hb_codepoint_t) record->glyphId != gid))
+      record = nullptr;
+    return record;
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
+
+    auto base_it =
+    + hb_range (c->plan->num_output_glyphs ())
+    | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
+                              {
+                                hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
+
+                                const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
+                                if (unlikely (!old_record))
+                                  return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
+
+                                BaseGlyphRecord new_record;
+                                new_record.glyphId = new_gid;
+                                new_record.numLayers = old_record->numLayers;
+                                return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
+                              })
+    | hb_filter (hb_first)
+    | hb_map_retains_sorting (hb_second)
+    ;
+
+    auto layer_it =
+    + hb_range (c->plan->num_output_glyphs ())
+    | hb_map (reverse_glyph_map)
+    | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
+                              {
+                                const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
+                                hb_vector_t<LayerRecord> out_layers;
+
+                                if (unlikely (!old_record ||
+                                              old_record->firstLayerIdx >= numLayers ||
+                                              old_record->firstLayerIdx + old_record->numLayers > numLayers))
+                                  return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
+
+                                auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
+                                                                                             old_record->numLayers);
+                                out_layers.resize (layers.length);
+                                for (unsigned int i = 0; i < layers.length; i++) {
+                                  out_layers[i] = layers[i];
+                                  hb_codepoint_t new_gid = 0;
+                                  if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
+                                    return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
+                                  out_layers[i].glyphId = new_gid;
+                                }
+
+                                return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
+                              })
+    | hb_filter (hb_first)
+    | hb_map_retains_sorting (hb_second)
+    ;
+
+    if (unlikely (!base_it || !layer_it || base_it.len () != layer_it.len ()))
+      return_trace (false);
+
+    COLR *colr_prime = c->serializer->start_embed<COLR> ();
+    return_trace (colr_prime->serialize (c->serializer, version, base_it, layer_it));
+  }
+
   protected:
   HBUINT16      version;        /* Table version number (starts at 0). */
   HBUINT16      numBaseGlyphs;  /* Number of Base Glyph Records. */
-  LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord> >
+  LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord>>
                 baseGlyphsZ;    /* Offset to Base Glyph records. */
-  LNNOffsetTo<UnsizedArrayOf<LayerRecord> >
+  LNNOffsetTo<UnsizedArrayOf<LayerRecord>>
                 layersZ;        /* Offset to Layer Records. */
   HBUINT16      numLayers;      /* Number of Layer Records. */
   public:
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh
index f4ef697..f5f642d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh
@@ -87,15 +87,15 @@
   }
 
   protected:
-  LNNOffsetTo<UnsizedArrayOf<HBUINT32> >
+  LNNOffsetTo<UnsizedArrayOf<HBUINT32>>
                 paletteFlagsZ;          /* Offset from the beginning of CPAL table to
                                          * the Palette Type Array. Set to 0 if no array
                                          * is provided. */
-  LNNOffsetTo<UnsizedArrayOf<NameID> >
+  LNNOffsetTo<UnsizedArrayOf<NameID>>
                 paletteLabelsZ;         /* Offset from the beginning of CPAL table to
                                          * the palette labels array. Set to 0 if no
                                          * array is provided. */
-  LNNOffsetTo<UnsizedArrayOf<NameID> >
+  LNNOffsetTo<UnsizedArrayOf<NameID>>
                 colorLabelsZ;           /* Offset from the beginning of CPAL table to
                                          * the color labels array. Set to 0
                                          * if no array is provided. */
@@ -115,7 +115,7 @@
   { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); }
 
   unsigned int get_palette_count () const { return numPalettes; }
-  unsigned int get_color_count () const   { return numColors; }
+  unsigned int   get_color_count () const { return numColors; }
 
   hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const
   { return v1 ().get_palette_flags (this, palette_index, numPalettes); }
@@ -142,12 +142,9 @@
                                                                        numColors);
     if (color_count)
     {
-      hb_array_t<const BGRAColor> segment_colors = palette_colors.sub_array (start_offset, *color_count);
-      /* Always return numColors colors per palette even if it has out-of-bounds start index. */
-      unsigned int count = MIN<unsigned int> (MAX<int> (numColors - start_offset, 0), *color_count);
-      *color_count = count;
-      for (unsigned int i = 0; i < count; i++)
-        colors[i] = segment_colors[i]; /* Bound-checked read. */
+      + palette_colors.sub_array (start_offset, color_count)
+      | hb_sink (hb_array (colors, *color_count))
+      ;
     }
     return numColors;
   }
@@ -155,7 +152,7 @@
   private:
   const CPALV1Tail& v1 () const
   {
-    if (version == 0) return Null(CPALV1Tail);
+    if (version == 0) return Null (CPALV1Tail);
     return StructAfter<CPALV1Tail> (*this);
   }
 
@@ -176,7 +173,7 @@
   HBUINT16      numPalettes;            /* Number of palettes in the table. */
   HBUINT16      numColorRecords;        /* Total number of color records, combined for
                                          * all palettes. */
-  LNNOffsetTo<UnsizedArrayOf<BGRAColor> >
+  LNNOffsetTo<UnsizedArrayOf<BGRAColor>>
                 colorRecordsZ;          /* Offset from the beginning of CPAL table to
                                          * the first ColorRecord. */
   UnsizedArrayOf<HBUINT16>
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh
index 5b89796..27b935e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2018  Ebrahim Byagowi
+ * Copyright © 2020  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -20,12 +21,15 @@
  * 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): Calder Kitagawa
  */
 
 #ifndef HB_OT_COLOR_SBIX_TABLE_HH
 #define HB_OT_COLOR_SBIX_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
 
 /*
  * sbix -- Standard Bitmap Graphics
@@ -40,6 +44,20 @@
 
 struct SBIXGlyph
 {
+  SBIXGlyph* copy (hb_serialize_context_t *c, unsigned int data_length) const
+  {
+    TRACE_SERIALIZE (this);
+    SBIXGlyph* new_glyph = c->start_embed<SBIXGlyph> ();
+    if (unlikely (!new_glyph)) return_trace (nullptr);
+    if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr);
+
+    new_glyph->xOffset = xOffset;
+    new_glyph->yOffset = yOffset;
+    new_glyph->graphicType = graphicType;
+    data.copy (c, data_length);
+    return_trace (new_glyph);
+  }
+
   HBINT16       xOffset;        /* The horizontal (x-axis) offset from the left
                                  * edge of the graphic to the glyph’s origin.
                                  * That is, the x-coordinate of the point on the
@@ -62,6 +80,9 @@
 
 struct SBIXStrike
 {
+  static unsigned int get_size (unsigned num_glyphs)
+  { return min_size + num_glyphs * HBUINT32::static_size; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -116,16 +137,59 @@
     return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length);
   }
 
+  bool subset (hb_subset_context_t *c, unsigned int available_len) const
+  {
+    TRACE_SUBSET (this);
+    unsigned int num_output_glyphs = c->plan->num_output_glyphs ();
+
+    auto* out = c->serializer->start_embed<SBIXStrike> ();
+    if (unlikely (!out)) return_trace (false);
+    auto snap = c->serializer->snapshot ();
+    if (unlikely (!c->serializer->extend (*out, num_output_glyphs + 1))) return_trace (false);
+    out->ppem = ppem;
+    out->resolution = resolution;
+    HBUINT32 head;
+    head = get_size (num_output_glyphs + 1);
+
+    bool has_glyphs = false;
+    for (unsigned new_gid = 0; new_gid < num_output_glyphs; new_gid++)
+    {
+      hb_codepoint_t old_gid;
+      if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid) ||
+          unlikely (imageOffsetsZ[old_gid].is_null () ||
+                    imageOffsetsZ[old_gid + 1].is_null () ||
+                    imageOffsetsZ[old_gid + 1] <= imageOffsetsZ[old_gid] ||
+                    imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid] <= SBIXGlyph::min_size) ||
+                    (unsigned int) imageOffsetsZ[old_gid + 1] > available_len)
+      {
+        out->imageOffsetsZ[new_gid] = head;
+        continue;
+      }
+      has_glyphs = true;
+      unsigned int delta = imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid];
+      unsigned int glyph_data_length = delta - SBIXGlyph::min_size;
+      if (!(this+imageOffsetsZ[old_gid]).copy (c->serializer, glyph_data_length))
+        return_trace (false);
+      out->imageOffsetsZ[new_gid] = head;
+      head += delta;
+    }
+    if (has_glyphs)
+      out->imageOffsetsZ[num_output_glyphs] = head;
+    else
+      c->serializer->revert (snap);
+    return_trace (has_glyphs);
+  }
+
   public:
   HBUINT16      ppem;           /* The PPEM size for which this strike was designed. */
   HBUINT16      resolution;     /* The device pixel density (in PPI) for which this
                                  * strike was designed. (E.g., 96 PPI, 192 PPI.) */
   protected:
-  UnsizedArrayOf<LOffsetTo<SBIXGlyph> >
+  UnsizedArrayOf<LOffsetTo<SBIXGlyph>>
                 imageOffsetsZ;  /* Offset from the beginning of the strike data header
                                  * to bitmap data for an individual glyph ID. */
   public:
-  DEFINE_SIZE_STATIC (8);
+  DEFINE_SIZE_ARRAY (4, imageOffsetsZ);
 };
 
 struct sbix
@@ -140,7 +204,7 @@
   {
     void init (hb_face_t *face)
     {
-      table = hb_sanitize_context_t().reference_table<sbix> (face);
+      table = hb_sanitize_context_t ().reference_table<sbix> (face);
       num_glyphs = face->get_num_glyphs ();
     }
     void fini () { table.destroy (); }
@@ -173,9 +237,9 @@
     {
       unsigned count = table->strikes.len;
       if (unlikely (!count))
-        return Null(SBIXStrike);
+        return Null (SBIXStrike);
 
-      unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
+      unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
       if (!requested_ppem)
         requested_ppem = 1<<30; /* Choose largest strike. */
       /* TODO Add DPI sensitivity as well? */
@@ -235,18 +299,25 @@
       const PNGHeader &png = *blob->as<PNGHeader>();
 
       extents->x_bearing = x_offset;
-      extents->y_bearing = y_offset;
+      extents->y_bearing = png.IHDR.height + y_offset;
       extents->width     = png.IHDR.width;
-      extents->height    = png.IHDR.height;
+      extents->height    = -1 * png.IHDR.height;
 
       /* Convert to font units. */
       if (strike_ppem)
       {
-        double scale = font->face->get_upem () / (double) strike_ppem;
-        extents->x_bearing = round (extents->x_bearing * scale);
-        extents->y_bearing = round (extents->y_bearing * scale);
-        extents->width = round (extents->width * scale);
-        extents->height = round (extents->height * scale);
+        float scale = font->face->get_upem () / (float) strike_ppem;
+        extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale);
+        extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale);
+        extents->width = font->em_scalef_x (extents->width * scale);
+        extents->height = font->em_scalef_y (extents->height * scale);
+      }
+      else
+      {
+        extents->x_bearing = font->em_scale_x (extents->x_bearing);
+        extents->y_bearing = font->em_scale_y (extents->y_bearing);
+        extents->width = font->em_scale_x (extents->width);
+        extents->height = font->em_scale_y (extents->height);
       }
 
       hb_blob_destroy (blob);
@@ -268,6 +339,63 @@
                           strikes.sanitize (c, this)));
   }
 
+  bool
+  add_strike (hb_subset_context_t *c, unsigned i) const
+  {
+    if (strikes[i].is_null () || c->source_blob->length < (unsigned) strikes[i])
+      return false;
+
+    return (this+strikes[i]).subset (c, c->source_blob->length - (unsigned) strikes[i]);
+  }
+
+  bool serialize_strike_offsets (hb_subset_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+
+    auto *out = c->serializer->start_embed<LOffsetLArrayOf<SBIXStrike>> ();
+    if (unlikely (!out)) return_trace (false);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    hb_vector_t<LOffsetTo<SBIXStrike>*> new_strikes;
+    hb_vector_t<hb_serialize_context_t::objidx_t> objidxs;
+    for (int i = strikes.len - 1; i >= 0; --i)
+    {
+      auto* o = out->serialize_append (c->serializer);
+      if (unlikely (!o)) return_trace (false);
+      *o = 0;
+      auto snap = c->serializer->snapshot ();
+      c->serializer->push ();
+      bool ret = add_strike (c, i);
+      if (!ret)
+      {
+        c->serializer->pop_discard ();
+        out->pop ();
+        c->serializer->revert (snap);
+      }
+      else
+      {
+        objidxs.push (c->serializer->pop_pack ());
+        new_strikes.push (o);
+      }
+    }
+    for (unsigned int i = 0; i < new_strikes.length; ++i)
+      c->serializer->add_link (*new_strikes[i], objidxs[new_strikes.length - 1 - i]);
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t* c) const
+  {
+    TRACE_SUBSET (this);
+
+    sbix *sbix_prime = c->serializer->start_embed<sbix> ();
+    if (unlikely (!sbix_prime)) return_trace (false);
+    if (unlikely (!c->serializer->embed (this->version))) return_trace (false);
+    if (unlikely (!c->serializer->embed (this->flags))) return_trace (false);
+
+    return_trace (serialize_strike_offsets (c));
+  }
+
   protected:
   HBUINT16      version;        /* Table version number — set to 1 */
   HBUINT16      flags;          /* Bit 0: Set to 1. Bit 1: Draw outlines.
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh
index eb0ba22..ccf9ed3 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh
@@ -62,7 +62,7 @@
                                  * this index entry. */
   HBUINT16      endGlyphID;     /* The last glyph ID in the range described by
                                  * this index entry. Must be >= startGlyphID. */
-  LNNOffsetTo<UnsizedArrayOf<HBUINT8> >
+  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
                 svgDoc;         /* Offset from the beginning of the SVG Document Index
                                  * to an SVG document. Must be non-zero. */
   HBUINT32      svgDocLength;   /* Length of the SVG document.
@@ -80,7 +80,7 @@
   struct accelerator_t
   {
     void init (hb_face_t *face)
-    { table = hb_sanitize_context_t().reference_table<SVG> (face); }
+    { table = hb_sanitize_context_t ().reference_table<SVG> (face); }
     void fini () { table.destroy (); }
 
     hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const
@@ -107,7 +107,7 @@
 
   protected:
   HBUINT16      version;        /* Table version (starting at 0). */
-  LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry> >
+  LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry>>
                 svgDocEntries;  /* Offset (relative to the start of the SVG table) to the
                                  * SVG Documents Index. Must be non-zero. */
                                 /* Array of SVG Document Index Entries. */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc
index 84aeb96..d37e134 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc
@@ -25,20 +25,21 @@
  * Google Author(s): Sascha Brawer, Behdad Esfahbod
  */
 
-#include "hb-open-type.hh"
+#include "hb.hh"
+
+#ifndef HB_NO_COLOR
+
+#include "hb-ot.h"
+
 #include "hb-ot-color-cbdt-table.hh"
 #include "hb-ot-color-colr-table.hh"
 #include "hb-ot-color-cpal-table.hh"
 #include "hb-ot-color-sbix-table.hh"
 #include "hb-ot-color-svg-table.hh"
-#include "hb-ot-face.hh"
-#include "hb-ot.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-#include "hb-ot-layout.hh"
-
 
 /**
  * SECTION:hb-ot-color
@@ -47,6 +48,8 @@
  * @include: hb-ot.h
  *
  * Functions for fetching color-font information from OpenType font faces.
+ *
+ * HarfBuzz supports `COLR`/`CPAL`, `sbix`, `CBDT`, and `SVG` color fonts.
  **/
 
 
@@ -57,9 +60,11 @@
 
 /**
  * hb_ot_color_has_palettes:
- * @face: a font face.
+ * @face: #hb_face_t to work upon
  *
- * Returns: whether CPAL table is available.
+ * Tests whether a face includes a `CPAL` color-palette table.
+ *
+ * Return value: true if data found, false otherwise
  *
  * Since: 2.1.0
  */
@@ -71,10 +76,11 @@
 
 /**
  * hb_ot_color_palette_get_count:
- * @face: a font face.
+ * @face: #hb_face_t to work upon
  *
- * Returns: the number of color palettes in @face, or zero if @face has
- * no colors.
+ * Fetches the number of color palettes in a face.
+ *
+ * Return value: the number of palettes found
  *
  * Since: 2.1.0
  */
@@ -86,13 +92,16 @@
 
 /**
  * hb_ot_color_palette_get_name_id:
- * @face:    a font face.
- * @palette_index: the index of the color palette whose name is being requested.
+ * @face: #hb_face_t to work upon
+ * @palette_index: The index of the color palette
  *
- * Retrieves the name id of a color palette. For example, a color font can
- * have themed palettes like "Spring", "Summer", "Fall", and "Winter".
+ * Fetches the `name` table Name ID that provides display names for
+ * a `CPAL` color palette.
  *
- * Returns: an identifier within @face's `name` table.
+ * Palette display names can be generic (e.g., "Default") or provide
+ * specific, themed names (e.g., "Spring", "Summer", "Fall", and "Winter").
+ *
+ * Return value: the Named ID found for the palette.
  * If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID.
  *
  * Since: 2.1.0
@@ -106,10 +115,16 @@
 
 /**
  * hb_ot_color_palette_color_get_name_id:
- * @face:        a font face.
- * @color_index: palette entry index.
+ * @face: #hb_face_t to work upon
+ * @color_index: The index of the color
  *
- * Returns: Name ID associated with a palette entry, e.g. eye color
+ * Fetches the `name` table Name ID that provides display names for
+ * the specificed color in a face's `CPAL` color palette.
+ *
+ * Display names can be generic (e.g., "Background") or specific
+ * (e.g., "Eye color").
+ *
+ * Return value: the Name ID found for the color.
  *
  * Since: 2.1.0
  */
@@ -122,10 +137,12 @@
 
 /**
  * hb_ot_color_palette_get_flags:
- * @face:          a font face
- * @palette_index: the index of the color palette whose flags are being requested
+ * @face: #hb_face_t to work upon
+ * @palette_index: The index of the color palette
  *
- * Returns: the flags for the requested color palette.
+ * Fetches the flags defined for a color palette.
+ *
+ * Return value: the #hb_ot_color_palette_flags_t of the requested color palette
  *
  * Since: 2.1.0
  */
@@ -138,25 +155,22 @@
 
 /**
  * hb_ot_color_palette_get_colors:
- * @face:         a font face.
- * @palette_index:the index of the color palette whose colors
- *                are being requested.
- * @start_offset: the index of the first color being requested.
- * @color_count:  (inout) (optional): on input, how many colors
- *                can be maximally stored into the @colors array;
- *                on output, how many colors were actually stored.
- * @colors: (array length=color_count) (out) (optional):
- *                an array of #hb_color_t records. After calling
- *                this function, @colors will be filled with
- *                the palette colors. If @colors is NULL, the function
- *                will just return the number of total colors
- *                without storing any actual colors; this can be used
- *                for allocating a buffer of suitable size before calling
- *                hb_ot_color_palette_get_colors() a second time.
+ * @face: #hb_face_t to work upon
+ * @palette_index: the index of the color palette to query
+ * @start_offset: offset of the first color to retrieve
+ * @color_count: (inout) (optional): Input = the maximum number of colors to return;
+ *               Output = the actual number of colors returned (may be zero)
+ * @colors: (out) (array length=color_count) (nullable): The array of #hb_color_t records found
  *
- * Retrieves the colors in a color palette.
+ * Fetches a list of the colors in a color palette.
  *
- * Returns: the total number of colors in the palette.
+ * After calling this function, @colors will be filled with the palette
+ * colors. If @colors is NULL, the function will just return the number
+ * of total colors without storing any actual colors; this can be used
+ * for allocating a buffer of suitable size before calling
+ * hb_ot_color_palette_get_colors() a second time.
+ *
+ * Return value: the total number of colors in the palette
  *
  * Since: 2.1.0
  */
@@ -177,9 +191,11 @@
 
 /**
  * hb_ot_color_has_layers:
- * @face: a font face.
+ * @face: #hb_face_t to work upon
  *
- * Returns: whether COLR table is available.
+ * Tests whether a face includes any `COLR` color layers.
+ *
+ * Return value: true if data found, false otherwise
  *
  * Since: 2.1.0
  */
@@ -191,14 +207,17 @@
 
 /**
  * hb_ot_color_glyph_get_layers:
- * @face:         a font face.
- * @glyph:        a layered color glyph id.
- * @start_offset: starting offset of layers.
- * @count:  (inout) (optional): gets number of layers available to be written on buffer
- *                              and returns number of written layers.
- * @layers: (array length=count) (out) (optional): layers buffer to buffer.
+ * @face: #hb_face_t to work upon
+ * @glyph: The glyph index to query
+ * @start_offset: offset of the first layer to retrieve
+ * @layer_count: (inout) (optional): Input = the maximum number of layers to return;
+ *         Output = the actual number of layers returned (may be zero)
+ * @layers: (out) (array length=layer_count) (nullable): The array of layers found
  *
- * Returns: Total number of layers a layered color glyph have.
+ * Fetches a list of all color layers for the specified glyph index in the specified
+ * face. The list returned will begin at the offset provided.
+ *
+ * Return value: Total number of layers available for the glyph index queried
  *
  * Since: 2.1.0
  */
@@ -206,10 +225,10 @@
 hb_ot_color_glyph_get_layers (hb_face_t           *face,
                               hb_codepoint_t       glyph,
                               unsigned int         start_offset,
-                              unsigned int        *count, /* IN/OUT.  May be NULL. */
+                              unsigned int        *layer_count, /* IN/OUT.  May be NULL. */
                               hb_ot_color_layer_t *layers /* OUT.     May be NULL. */)
 {
-  return face->table.COLR->get_glyph_layers (glyph, start_offset, count, layers);
+  return face->table.COLR->get_glyph_layers (glyph, start_offset, layer_count, layers);
 }
 
 
@@ -219,11 +238,11 @@
 
 /**
  * hb_ot_color_has_svg:
- * @face: a font face.
+ * @face: #hb_face_t to work upon.
  *
- * Check whether @face has SVG glyph images.
+ * Tests whether a face includes any `SVG` glyph images.
  *
- * Returns true if available, false otherwise.
+ * Return value: true if data found, false otherwise.
  *
  * Since: 2.1.0
  */
@@ -235,12 +254,12 @@
 
 /**
  * hb_ot_color_glyph_reference_svg:
- * @face:  a font face.
- * @glyph: a svg glyph index.
+ * @face: #hb_face_t to work upon
+ * @glyph: a svg glyph index
  *
- * Get SVG document for a glyph. The blob may be either plain text or gzip-encoded.
+ * Fetches the SVG document for a glyph. The blob may be either plain text or gzip-encoded.
  *
- * Returns: (transfer full): respective svg blob of the glyph, if available.
+ * Return value: (transfer full): An #hb_blob_t containing the SVG document of the glyph, if available
  *
  * Since: 2.1.0
  */
@@ -257,11 +276,11 @@
 
 /**
  * hb_ot_color_has_png:
- * @face: a font face.
+ * @face: #hb_face_t to work upon
  *
- * Check whether @face has PNG glyph images (either CBDT or sbix tables).
+ * Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
  *
- * Returns true if available, false otherwise.
+ * Return value: true if data found, false otherwise
  *
  * Since: 2.1.0
  */
@@ -273,14 +292,14 @@
 
 /**
  * hb_ot_color_glyph_reference_png:
- * @font:  a font object, not face. upem should be set on
- *         that font object if one wants to get optimal png blob, otherwise
- *         return the biggest one
- * @glyph: a glyph index.
+ * @font: #hb_font_t to work upon
+ * @glyph: a glyph index
  *
- * Get PNG image for a glyph.
+ * Fetches the PNG image for a glyph. This function takes a font object, not a face object,
+ * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font
+ * object. If UPEM is unset, the blob returned will be the largest PNG available.
  *
- * Returns: (transfer full): respective PNG blob of the glyph, if available.
+ * Return value: (transfer full): An #hb_blob_t containing the PNG image for the glyph, if available
  *
  * Since: 2.1.0
  */
@@ -297,3 +316,6 @@
 
   return blob;
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h
index 5736890..5934475 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h
@@ -59,11 +59,11 @@
 
 /**
  * hb_ot_color_palette_flags_t:
- * @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: default indicating that there is nothing special
+ * @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: Default indicating that there is nothing special
  *   to note about a color palette.
- * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: flag indicating that the color
+ * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: Flag indicating that the color
  *   palette is appropriate to use when displaying the font on a light background such as white.
- * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: flag indicating that the color
+ * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: Flag indicating that the color
  *   palette is appropriate to use when displaying the font on a dark background such as black.
  *
  * Since: 2.1.0
@@ -110,7 +110,7 @@
 hb_ot_color_glyph_get_layers (hb_face_t           *face,
                               hb_codepoint_t       glyph,
                               unsigned int         start_offset,
-                              unsigned int        *count, /* IN/OUT.  May be NULL. */
+                              unsigned int        *layer_count, /* IN/OUT.  May be NULL. */
                               hb_ot_color_layer_t *layers /* OUT.     May be NULL. */);
 
 /*
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h
index 2a31b32..4fdb2b3 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h
@@ -40,6 +40,10 @@
 #ifndef HB_DISABLE_DEPRECATED
 
 
+/* https://github.com/harfbuzz/harfbuzz/issues/1734 */
+#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
+
+
 /* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */
 HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t
 hb_ot_layout_table_choose_script (hb_face_t      *face,
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh
new file mode 100644
index 0000000..367e143
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh
@@ -0,0 +1,138 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2012,2013  Google, Inc.
+ * Copyright © 2019, Facebook Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_FACE_TABLE_LIST_HH
+#define HB_OT_FACE_TABLE_LIST_HH
+#endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */
+
+#ifndef HB_OT_ACCELERATOR
+#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
+#define _HB_OT_ACCELERATOR_UNDEF
+#endif
+
+
+/* This lists font tables that the hb_face_t will contain and lazily
+ * load.  Don't add a table unless it's used though.  This is not
+ * exactly free. */
+
+/* v--- Add new tables in the right place here. */
+
+
+/* OpenType fundamentals. */
+HB_OT_TABLE (OT, head)
+#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
+HB_OT_ACCELERATOR (OT, cmap)
+#endif
+HB_OT_TABLE (OT, hhea)
+HB_OT_ACCELERATOR (OT, hmtx)
+HB_OT_TABLE (OT, OS2)
+#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE)
+HB_OT_ACCELERATOR (OT, post)
+#endif
+#ifndef HB_NO_NAME
+HB_OT_ACCELERATOR (OT, name)
+#endif
+#ifndef HB_NO_STYLE
+HB_OT_TABLE (OT, STAT)
+#endif
+#ifndef HB_NO_META
+HB_OT_ACCELERATOR (OT, meta)
+#endif
+
+/* Vertical layout. */
+HB_OT_TABLE (OT, vhea)
+HB_OT_ACCELERATOR (OT, vmtx)
+
+/* TrueType outlines. */
+HB_OT_ACCELERATOR (OT, glyf)
+
+/* CFF outlines. */
+#ifndef HB_NO_CFF
+HB_OT_ACCELERATOR (OT, cff1)
+HB_OT_ACCELERATOR (OT, cff2)
+HB_OT_TABLE (OT, VORG)
+#endif
+
+/* OpenType variations. */
+#ifndef HB_NO_VAR
+HB_OT_TABLE (OT, fvar)
+HB_OT_TABLE (OT, avar)
+HB_OT_ACCELERATOR (OT, gvar)
+HB_OT_TABLE (OT, MVAR)
+#endif
+
+/* Legacy kern. */
+#ifndef HB_NO_OT_KERN
+HB_OT_TABLE (OT, kern)
+#endif
+
+/* OpenType shaping. */
+#ifndef HB_NO_OT_LAYOUT
+HB_OT_ACCELERATOR (OT, GDEF)
+HB_OT_ACCELERATOR (OT, GSUB)
+HB_OT_ACCELERATOR (OT, GPOS)
+//HB_OT_TABLE (OT, JSTF)
+#endif
+
+/* OpenType baseline. */
+#ifndef HB_NO_BASE
+HB_OT_TABLE (OT, BASE)
+#endif
+
+/* AAT shaping. */
+#ifndef HB_NO_AAT
+HB_OT_TABLE (AAT, morx)
+HB_OT_TABLE (AAT, mort)
+HB_OT_TABLE (AAT, kerx)
+HB_OT_TABLE (AAT, ankr)
+HB_OT_TABLE (AAT, trak)
+HB_OT_TABLE (AAT, ltag)
+HB_OT_TABLE (AAT, feat)
+// HB_OT_TABLE (AAT, opbd)
+#endif
+
+/* OpenType color fonts. */
+#ifndef HB_NO_COLOR
+HB_OT_TABLE (OT, COLR)
+HB_OT_TABLE (OT, CPAL)
+HB_OT_ACCELERATOR (OT, CBDT)
+HB_OT_ACCELERATOR (OT, sbix)
+HB_OT_ACCELERATOR (OT, SVG)
+#endif
+
+/* OpenType math. */
+#ifndef HB_NO_MATH
+HB_OT_TABLE (OT, MATH)
+#endif
+
+
+#ifdef _HB_OT_ACCELERATOR_UNDEF
+#undef HB_OT_ACCELERATOR
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc
index 9b17526..5ef8df4 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc
@@ -32,6 +32,7 @@
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-kern-table.hh"
+#include "hb-ot-meta-table.hh"
 #include "hb-ot-name-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-color-cbdt-table.hh"
@@ -46,16 +47,12 @@
 {
   this->face = face;
 #define HB_OT_TABLE(Namespace, Type) Type.init0 ();
-#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
-  HB_OT_TABLES
-#undef HB_OT_ACCELERATOR
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_TABLE
 }
 void hb_ot_face_t::fini ()
 {
 #define HB_OT_TABLE(Namespace, Type) Type.fini ();
-#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
-  HB_OT_TABLES
-#undef HB_OT_ACCELERATOR
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_TABLE
 }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh
index 7f47ba6..e24d380 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh
@@ -38,54 +38,10 @@
  * hb_ot_face_t
  */
 
-#define HB_OT_TABLES \
-    /* OpenType fundamentals. */ \
-    HB_OT_TABLE(OT, head) \
-    HB_OT_ACCELERATOR(OT, cmap) \
-    HB_OT_ACCELERATOR(OT, hmtx) \
-    HB_OT_ACCELERATOR(OT, vmtx) \
-    HB_OT_ACCELERATOR(OT, post) \
-    HB_OT_TABLE(OT, kern) \
-    HB_OT_ACCELERATOR(OT, glyf) \
-    HB_OT_ACCELERATOR(OT, cff1) \
-    HB_OT_ACCELERATOR(OT, cff2) \
-    HB_OT_TABLE(OT, VORG) \
-    HB_OT_ACCELERATOR(OT, name) \
-    HB_OT_TABLE(OT, OS2) \
-    HB_OT_TABLE(OT, STAT) \
-    /* OpenType shaping. */ \
-    HB_OT_ACCELERATOR(OT, GDEF) \
-    HB_OT_ACCELERATOR(OT, GSUB) \
-    HB_OT_ACCELERATOR(OT, GPOS) \
-    HB_OT_TABLE(OT, BASE) \
-    HB_OT_TABLE(OT, JSTF) \
-    /* AAT shaping. */ \
-    HB_OT_TABLE(AAT, mort) \
-    HB_OT_TABLE(AAT, morx) \
-    HB_OT_TABLE(AAT, kerx) \
-    HB_OT_TABLE(AAT, ankr) \
-    HB_OT_TABLE(AAT, trak) \
-    HB_OT_TABLE(AAT, lcar) \
-    HB_OT_TABLE(AAT, ltag) \
-    HB_OT_TABLE(AAT, feat) \
-    /* OpenType variations. */ \
-    HB_OT_TABLE(OT, fvar) \
-    HB_OT_TABLE(OT, avar) \
-    HB_OT_TABLE(OT, MVAR) \
-    /* OpenType math. */ \
-    HB_OT_TABLE(OT, MATH) \
-    /* OpenType color fonts. */ \
-    HB_OT_TABLE(OT, COLR) \
-    HB_OT_TABLE(OT, CPAL) \
-    HB_OT_ACCELERATOR(OT, CBDT) \
-    HB_OT_ACCELERATOR(OT, sbix) \
-    HB_OT_ACCELERATOR(OT, SVG) \
-    /* */
-
 /* Declare tables. */
 #define HB_OT_TABLE(Namespace, Type) namespace Namespace { struct Type; }
 #define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type##_accelerator_t)
-HB_OT_TABLES
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_ACCELERATOR
 #undef HB_OT_TABLE
 
@@ -100,9 +56,7 @@
   {
     ORDER_ZERO,
 #define HB_OT_TABLE(Namespace, Type) HB_OT_TABLE_ORDER (Namespace, Type),
-#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
-    HB_OT_TABLES
-#undef HB_OT_ACCELERATOR
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_TABLE
   };
 
@@ -111,7 +65,7 @@
   hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
 #define HB_OT_ACCELERATOR(Namespace, Type) \
   hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
-  HB_OT_TABLES
+#include "hb-ot-face-table-list.hh"
 #undef HB_OT_ACCELERATOR
 #undef HB_OT_TABLE
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc
index b290c49..f28de2a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc
@@ -26,6 +26,8 @@
 
 #include "hb.hh"
 
+#ifndef HB_NO_OT_FONT
+
 #include "hb-ot.h"
 
 #include "hb-font.hh"
@@ -37,7 +39,6 @@
 #include "hb-ot-cff1-table.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-hmtx-table.hh"
-#include "hb-ot-kern-table.hh"
 #include "hb-ot-os2-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
@@ -52,7 +53,7 @@
  * @short_description: OpenType font implementation
  * @include: hb-ot.h
  *
- * Functions for using OpenType fonts with hb_shape().  Not that fonts returned
+ * Functions for using OpenType fonts with hb_shape().  Note that fonts returned
  * by hb_font_create() default to using these functions, so most clients would
  * never need to call these functions directly.
  **/
@@ -149,19 +150,21 @@
 
   *x = font->get_glyph_h_advance (glyph) / 2;
 
+#ifndef HB_NO_OT_FONT_CFF
   const OT::VORG &VORG = *ot_face->VORG;
   if (VORG.has_data ())
   {
     *y = font->em_scale_y (VORG.get_y_origin (glyph));
     return true;
   }
+#endif
 
   hb_glyph_extents_t extents = {0};
-  if (ot_face->glyf->get_extents (glyph, &extents))
+  if (ot_face->glyf->get_extents (font, glyph, &extents))
   {
     const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
-    hb_position_t tsb = vmtx.get_side_bearing (glyph);
-    *y = font->em_scale_y (extents.y_bearing + tsb);
+    hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
+    *y = extents.y_bearing + font->em_scale_y (tsb);
     return true;
   }
 
@@ -180,23 +183,24 @@
                          void *user_data HB_UNUSED)
 {
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  bool ret = ot_face->sbix->get_extents (font, glyph, extents);
-  if (!ret)
-    ret = ot_face->glyf->get_extents (glyph, extents);
-  if (!ret)
-    ret = ot_face->cff1->get_extents (glyph, extents);
-  if (!ret)
-    ret = ot_face->cff2->get_extents (font, glyph, extents);
-  if (!ret)
-    ret = ot_face->CBDT->get_extents (font, glyph, extents);
+
+#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
+  if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
+#endif
+  if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
+#ifndef HB_NO_OT_FONT_CFF
+  if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
+  if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
+#endif
+#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
+  if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
+#endif
+
   // TODO Hook up side-bearings variations.
-  extents->x_bearing = font->em_scale_x (extents->x_bearing);
-  extents->y_bearing = font->em_scale_y (extents->y_bearing);
-  extents->width     = font->em_scale_x (extents->width);
-  extents->height    = font->em_scale_y (extents->height);
-  return ret;
+  return false;
 }
 
+#ifndef HB_NO_OT_FONT_GLYPH_NAMES
 static hb_bool_t
 hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
                       void *font_data,
@@ -205,9 +209,12 @@
                       void *user_data HB_UNUSED)
 {
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  return ot_face->post->get_glyph_name (glyph, name, size);
+  if (ot_face->post->get_glyph_name (glyph, name, size)) return true;
+#ifndef HB_NO_OT_FONT_CFF
+  if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true;
+#endif
+  return false;
 }
-
 static hb_bool_t
 hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
                            void *font_data,
@@ -216,37 +223,34 @@
                            void *user_data HB_UNUSED)
 {
   const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  return ot_face->post->get_glyph_from_name (name, len, glyph);
+  if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true;
+#ifndef HB_NO_OT_FONT_CFF
+    if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true;
+#endif
+  return false;
 }
+#endif
 
 static hb_bool_t
 hb_ot_get_font_h_extents (hb_font_t *font,
-                          void *font_data,
+                          void *font_data HB_UNUSED,
                           hb_font_extents_t *metrics,
                           void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
-  metrics->ascender = font->em_scale_y (hmtx.ascender);
-  metrics->descender = font->em_scale_y (hmtx.descender);
-  metrics->line_gap = font->em_scale_y (hmtx.line_gap);
-  // TODO Hook up variations.
-  return hmtx.has_font_extents;
+  return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
+         _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
+         _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
 }
 
 static hb_bool_t
 hb_ot_get_font_v_extents (hb_font_t *font,
-                          void *font_data,
+                          void *font_data HB_UNUSED,
                           hb_font_extents_t *metrics,
                           void *user_data HB_UNUSED)
 {
-  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
-  const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
-  metrics->ascender = font->em_scale_x (vmtx.ascender);
-  metrics->descender = font->em_scale_x (vmtx.descender);
-  metrics->line_gap = font->em_scale_x (vmtx.line_gap);
-  // TODO Hook up variations.
-  return vmtx.has_font_extents;
+  return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_ASCENDER, &metrics->ascender) &&
+         _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) &&
+         _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
 }
 
 #if HB_USE_ATEXIT
@@ -270,8 +274,10 @@
     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
     //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
+#ifndef HB_NO_OT_FONT_GLYPH_NAMES
     hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
+#endif
 
     hb_font_funcs_make_immutable (funcs);
 
@@ -311,3 +317,20 @@
                      &font->face->table,
                      nullptr);
 }
+
+#ifndef HB_NO_VAR
+int
+_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+{
+  return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical);
+}
+
+unsigned
+_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+{
+  return font->face->table.glyf->get_advance_var (font, glyph, is_vertical);
+}
+#endif
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-glyf-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-glyf-table.hh
index 252d0b4..cd95828 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-glyf-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-glyf-table.hh
@@ -1,5 +1,7 @@
 /*
  * Copyright © 2015  Google, Inc.
+ * Copyright © 2019  Adobe Inc.
+ * Copyright © 2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -21,7 +23,8 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
- * Google Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter
+ * Adobe Author(s): Michiharu Ariza
  */
 
 #ifndef HB_OT_GLYF_TABLE_HH
@@ -29,7 +32,9 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-head-table.hh"
-#include "hb-subset-glyf.hh"
+#include "hb-ot-hmtx-table.hh"
+#include "hb-ot-var-gvar-table.hh"
+#include "hb-draw.hh"
 
 namespace OT {
 
@@ -54,11 +59,12 @@
   }
 
   protected:
-  UnsizedArrayOf<HBUINT8>       dataZ;          /* Location data. */
+  UnsizedArrayOf<HBUINT8>
+                dataZ;  /* Location data. */
   public:
-  DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
-                        * check the size externally, allow Null() object of it by
-                        * defining it MIN() instead. */
+  DEFINE_SIZE_MIN (0);  /* In reality, this is UNBOUNDED() type; but since we always
+                         * check the size externally, allow Null() object of it by
+                         * defining it _MIN instead. */
 };
 
 
@@ -76,29 +82,143 @@
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
     TRACE_SANITIZE (this);
-    /* We don't check for anything specific here.  The users of the
-     * struct do all the hard work... */
+    /* Runtime checks as eager sanitizing each glyph is costy */
     return_trace (true);
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  template<typename Iterator,
+           hb_requires (hb_is_source_of (Iterator, unsigned int))>
+  static bool
+  _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets)
   {
-    hb_blob_t *glyf_prime = nullptr;
-    hb_blob_t *loca_prime = nullptr;
+    unsigned max_offset =
+    + padded_offsets
+    | hb_reduce (hb_add, 0)
+    ;
+    unsigned num_offsets = padded_offsets.len () + 1;
+    bool use_short_loca = max_offset < 0x1FFFF;
+    unsigned entry_size = use_short_loca ? 2 : 4;
+    char *loca_prime_data = (char *) calloc (entry_size, num_offsets);
 
-    bool success = true;
-    bool use_short_loca = false;
-    if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) {
-      success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime);
-      success = success && plan->add_table (HB_OT_TAG_loca, loca_prime);
-      success = success && _add_head_and_set_loca_version (plan, use_short_loca);
-    } else {
-      success = false;
+    if (unlikely (!loca_prime_data)) return false;
+
+    DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d "
+                                "max_offset %d size %d",
+               entry_size, num_offsets, max_offset, entry_size * num_offsets);
+
+    if (use_short_loca)
+      _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets));
+    else
+      _write_loca (padded_offsets, 0, hb_array ((HBUINT32 *) loca_prime_data, num_offsets));
+
+    hb_blob_t *loca_blob = hb_blob_create (loca_prime_data,
+                                           entry_size * num_offsets,
+                                           HB_MEMORY_MODE_WRITABLE,
+                                           loca_prime_data,
+                                           free);
+
+    bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
+               && _add_head_and_set_loca_version (plan, use_short_loca);
+
+    hb_blob_destroy (loca_blob);
+    return result;
+  }
+
+  template<typename IteratorIn, typename IteratorOut,
+           hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
+           hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
+  static void
+  _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest)
+  {
+    unsigned int offset = 0;
+    dest << 0;
+    + it
+    | hb_map ([=, &offset] (unsigned int padded_size)
+              {
+                offset += padded_size;
+                DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset);
+                return offset >> right_shift;
+              })
+    | hb_sink (dest)
+    ;
+  }
+
+  /* requires source of SubsetGlyph complains the identifier isn't declared */
+  template <typename Iterator>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator it,
+                  const hb_subset_plan_t *plan)
+  {
+    TRACE_SERIALIZE (this);
+    unsigned init_len = c->length ();
+    for (const auto &_ : it) _.serialize (c, plan);
+
+    /* As a special case when all glyph in the font are empty, add a zero byte
+     * to the table, so that OTS doesn’t reject it, and to make the table work
+     * on Windows as well.
+     * See https://github.com/khaledhosny/ots/issues/52 */
+    if (init_len == c->length ())
+    {
+      HBUINT8 empty_byte;
+      empty_byte = 0;
+      c->copy (empty_byte);
     }
-    hb_blob_destroy (loca_prime);
-    hb_blob_destroy (glyf_prime);
+    return_trace (true);
+  }
 
-    return success;
+  /* Byte region(s) per glyph to output
+     unpadded, hints removed if so requested
+     If we fail to process a glyph we produce an empty (0-length) glyph */
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    glyf *glyf_prime = c->serializer->start_embed <glyf> ();
+    if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
+
+    hb_vector_t<SubsetGlyph> glyphs;
+    _populate_subset_glyphs (c->plan, &glyphs);
+
+    glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan);
+
+    auto padded_offsets =
+    + hb_iter (glyphs)
+    | hb_map (&SubsetGlyph::padded_size)
+    ;
+
+    if (c->serializer->in_error ()) return_trace (false);
+    return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
+                                                                    padded_offsets)));
+  }
+
+  template <typename SubsetGlyph>
+  void
+  _populate_subset_glyphs (const hb_subset_plan_t   *plan,
+                           hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const
+  {
+    OT::glyf::accelerator_t glyf;
+    glyf.init (plan->source);
+
+    + hb_range (plan->num_output_glyphs ())
+    | hb_map ([&] (hb_codepoint_t new_gid)
+              {
+                SubsetGlyph subset_glyph = {0};
+                subset_glyph.new_gid = new_gid;
+
+                /* should never fail: all old gids should be mapped */
+                if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
+                  return subset_glyph;
+
+                subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
+                if (plan->drop_hints) subset_glyph.drop_hints_bytes ();
+                else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
+
+                return subset_glyph;
+              })
+    | hb_sink (glyphs)
+    ;
+
+    glyf.fini ();
   }
 
   static bool
@@ -112,218 +232,292 @@
       return false;
 
     head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
-    head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1);
+    head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
     bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
 
     hb_blob_destroy (head_prime_blob);
     return success;
   }
 
-  struct GlyphHeader
+  struct CompositeGlyphChain
   {
-    HBINT16             numberOfContours;       /* If the number of contours is
-                                                 * greater than or equal to zero,
-                                                 * this is a simple glyph; if negative,
-                                                 * this is a composite glyph. */
-    FWORD               xMin;                   /* Minimum x for coordinate data. */
-    FWORD               yMin;                   /* Minimum y for coordinate data. */
-    FWORD               xMax;                   /* Maximum x for coordinate data. */
-    FWORD               yMax;                   /* Maximum y for coordinate data. */
-
-    DEFINE_SIZE_STATIC (10);
-  };
-
-  struct CompositeGlyphHeader
-  {
-    enum composite_glyph_flag_t {
-      ARG_1_AND_2_ARE_WORDS =      0x0001,
-      ARGS_ARE_XY_VALUES =         0x0002,
-      ROUND_XY_TO_GRID =           0x0004,
-      WE_HAVE_A_SCALE =            0x0008,
-      MORE_COMPONENTS =            0x0020,
-      WE_HAVE_AN_X_AND_Y_SCALE =   0x0040,
-      WE_HAVE_A_TWO_BY_TWO =       0x0080,
-      WE_HAVE_INSTRUCTIONS =       0x0100,
-      USE_MY_METRICS =             0x0200,
-      OVERLAP_COMPOUND =           0x0400,
-      SCALED_COMPONENT_OFFSET =    0x0800,
-      UNSCALED_COMPONENT_OFFSET =  0x1000
+    protected:
+    enum composite_glyph_flag_t
+    {
+      ARG_1_AND_2_ARE_WORDS     = 0x0001,
+      ARGS_ARE_XY_VALUES        = 0x0002,
+      ROUND_XY_TO_GRID          = 0x0004,
+      WE_HAVE_A_SCALE           = 0x0008,
+      MORE_COMPONENTS           = 0x0020,
+      WE_HAVE_AN_X_AND_Y_SCALE  = 0x0040,
+      WE_HAVE_A_TWO_BY_TWO      = 0x0080,
+      WE_HAVE_INSTRUCTIONS      = 0x0100,
+      USE_MY_METRICS            = 0x0200,
+      OVERLAP_COMPOUND          = 0x0400,
+      SCALED_COMPONENT_OFFSET   = 0x0800,
+      UNSCALED_COMPONENT_OFFSET = 0x1000
     };
 
-    HBUINT16 flags;
-    GlyphID  glyphIndex;
-
+    public:
     unsigned int get_size () const
     {
       unsigned int size = min_size;
-      // arg1 and 2 are int16
+      /* arg1 and 2 are int16 */
       if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
-      // arg1 and 2 are int8
+      /* arg1 and 2 are int8 */
       else size += 2;
 
-      // One x 16 bit (scale)
+      /* One x 16 bit (scale) */
       if (flags & WE_HAVE_A_SCALE) size += 2;
-      // Two x 16 bit (xscale, yscale)
+      /* Two x 16 bit (xscale, yscale) */
       else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4;
-      // Four x 16 bit (xscale, scale01, scale10, yscale)
+      /* Four x 16 bit (xscale, scale01, scale10, yscale) */
       else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8;
 
       return size;
     }
 
-    struct Iterator
+    void set_glyph_index (hb_codepoint_t new_gid) { glyphIndex = new_gid; }
+    hb_codepoint_t get_glyph_index ()       const { return glyphIndex; }
+
+    void drop_instructions_flag ()  { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
+    bool has_instructions ()  const { return   flags & WE_HAVE_INSTRUCTIONS; }
+
+    bool has_more ()          const { return   flags & MORE_COMPONENTS; }
+    bool is_use_my_metrics () const { return   flags & USE_MY_METRICS; }
+    bool is_anchored ()       const { return !(flags & ARGS_ARE_XY_VALUES); }
+    void get_anchor_points (unsigned int &point1, unsigned int &point2) const
     {
-      const char *glyph_start;
-      const char *glyph_end;
-      const CompositeGlyphHeader *current;
-
-      bool move_to_next ()
+      const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex);
+      if (flags & ARG_1_AND_2_ARE_WORDS)
       {
-        if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS)
-        {
-          const CompositeGlyphHeader *possible =
-            &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current);
-          if (!in_range (possible))
-            return false;
-          current = possible;
-          return true;
-        }
-        return false;
+        point1 = ((const HBUINT16 *) p)[0];
+        point2 = ((const HBUINT16 *) p)[1];
       }
-
-      bool in_range (const CompositeGlyphHeader *composite) const
+      else
       {
-        return (const char *) composite >= glyph_start
-          && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end
-          && ((const char *) composite + composite->get_size ()) <= glyph_end;
+        point1 = p[0];
+        point2 = p[1];
       }
-    };
-
-    static bool get_iterator (const char * glyph_data,
-                              unsigned int length,
-                              CompositeGlyphHeader::Iterator *iterator /* OUT */)
-    {
-      if (length < GlyphHeader::static_size)
-        return false; /* Empty glyph; zero extents. */
-
-      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0);
-      if (glyph_header.numberOfContours < 0)
-      {
-        const CompositeGlyphHeader *possible =
-          &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header);
-
-        iterator->glyph_start = glyph_data;
-        iterator->glyph_end = (const char *) glyph_data + length;
-        if (!iterator->in_range (possible))
-          return false;
-        iterator->current = possible;
-        return true;
-      }
-
-      return false;
     }
 
+    void transform_points (contour_point_vector_t &points) const
+    {
+      float matrix[4];
+      contour_point_t trans;
+      if (get_transformation (matrix, trans))
+      {
+        if (scaled_offsets ())
+        {
+          points.translate (trans);
+          points.transform (matrix);
+        }
+        else
+        {
+          points.transform (matrix);
+          points.translate (trans);
+        }
+      }
+    }
+
+    protected:
+    bool scaled_offsets () const
+    { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
+
+    bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
+    {
+      matrix[0] = matrix[3] = 1.f;
+      matrix[1] = matrix[2] = 0.f;
+
+      int tx, ty;
+      const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex);
+      if (flags & ARG_1_AND_2_ARE_WORDS)
+      {
+        tx = *(const HBINT16 *) p;
+        p += HBINT16::static_size;
+        ty = *(const HBINT16 *) p;
+        p += HBINT16::static_size;
+      }
+      else
+      {
+        tx = *p++;
+        ty = *p++;
+      }
+      if (is_anchored ()) tx = ty = 0;
+
+      trans.init ((float) tx, (float) ty);
+
+      {
+        const F2DOT14 *points = (const F2DOT14 *) p;
+        if (flags & WE_HAVE_A_SCALE)
+        {
+          matrix[0] = matrix[3] = points[0].to_float ();
+          return true;
+        }
+        else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
+        {
+          matrix[0] = points[0].to_float ();
+          matrix[3] = points[1].to_float ();
+          return true;
+        }
+        else if (flags & WE_HAVE_A_TWO_BY_TWO)
+        {
+          matrix[0] = points[0].to_float ();
+          matrix[1] = points[1].to_float ();
+          matrix[2] = points[2].to_float ();
+          matrix[3] = points[3].to_float ();
+          return true;
+        }
+      }
+      return tx || ty;
+    }
+
+    protected:
+    HBUINT16    flags;
+    HBGlyphID   glyphIndex;
+    public:
     DEFINE_SIZE_MIN (4);
   };
 
-  struct accelerator_t
+  struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphChain &>
   {
-    void init (hb_face_t *face)
+    typedef const CompositeGlyphChain *__item_t__;
+    composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
+      glyph (glyph_), current (current_)
+    { if (!check_range (current)) current = nullptr; }
+    composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {}
+
+    const CompositeGlyphChain &__item__ () const { return *current; }
+    bool __more__ () const { return current; }
+    void __next__ ()
     {
-      memset (this, 0, sizeof (accelerator_t));
+      if (!current->has_more ()) { current = nullptr; return; }
 
-      const OT::head &head = *face->table.head;
-      if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0)
-        /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
-        return;
-      short_offset = 0 == head.indexToLocFormat;
+      const CompositeGlyphChain *possible = &StructAfter<CompositeGlyphChain,
+                                                         CompositeGlyphChain> (*current);
+      if (!check_range (possible)) { current = nullptr; return; }
+      current = possible;
+    }
+    bool operator != (const composite_iter_t& o) const
+    { return glyph != o.glyph || current != o.current; }
 
-      loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
-      glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
-
-      num_glyphs = MAX (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
+    bool check_range (const CompositeGlyphChain *composite) const
+    {
+      return glyph.check_range (composite, CompositeGlyphChain::min_size)
+          && glyph.check_range (composite, composite->get_size ());
     }
 
-    void fini ()
+    private:
+    hb_bytes_t glyph;
+    __item_t__ current;
+  };
+
+  enum phantom_point_index_t
+  {
+    PHANTOM_LEFT   = 0,
+    PHANTOM_RIGHT  = 1,
+    PHANTOM_TOP    = 2,
+    PHANTOM_BOTTOM = 3,
+    PHANTOM_COUNT  = 4
+  };
+
+  struct accelerator_t;
+
+  struct Glyph
+  {
+    enum simple_glyph_flag_t
     {
-      loca_table.destroy ();
-      glyf_table.destroy ();
-    }
-
-    /*
-     * Returns true if the referenced glyph is a valid glyph and a composite glyph.
-     * If true is returned a pointer to the composite glyph will be written into
-     * composite.
-     */
-    bool get_composite (hb_codepoint_t glyph,
-                        CompositeGlyphHeader::Iterator *composite /* OUT */) const
-    {
-      if (unlikely (!num_glyphs))
-        return false;
-
-      unsigned int start_offset, end_offset;
-      if (!get_offsets (glyph, &start_offset, &end_offset))
-        return false; /* glyph not found */
-
-      return CompositeGlyphHeader::get_iterator ((const char *) this->glyf_table + start_offset,
-                                                 end_offset - start_offset,
-                                                 composite);
-    }
-
-    enum simple_glyph_flag_t {
-      FLAG_ON_CURVE = 0x01,
-      FLAG_X_SHORT = 0x02,
-      FLAG_Y_SHORT = 0x04,
-      FLAG_REPEAT = 0x08,
-      FLAG_X_SAME = 0x10,
-      FLAG_Y_SAME = 0x20,
+      FLAG_ON_CURVE  = 0x01,
+      FLAG_X_SHORT   = 0x02,
+      FLAG_Y_SHORT   = 0x04,
+      FLAG_REPEAT    = 0x08,
+      FLAG_X_SAME    = 0x10,
+      FLAG_Y_SAME    = 0x20,
       FLAG_RESERVED1 = 0x40,
       FLAG_RESERVED2 = 0x80
     };
 
-    /* based on FontTools _g_l_y_f.py::trim */
-    bool remove_padding (unsigned int start_offset,
-                                unsigned int *end_offset) const
+    private:
+    struct GlyphHeader
     {
-      if (*end_offset - start_offset < GlyphHeader::static_size) return true;
+      bool has_data () const { return numberOfContours; }
 
-      const char *glyph = ((const char *) glyf_table) + start_offset;
-      const char * const glyph_end = glyph + (*end_offset - start_offset);
-      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph, 0);
-      int16_t num_contours = (int16_t) glyph_header.numberOfContours;
-
-      if (num_contours < 0)
-        /* Trimming for composites not implemented.
-         * If removing hints it falls out of that. */
-        return true;
-      else if (num_contours > 0)
+      bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
+                        hb_codepoint_t gid, hb_glyph_extents_t *extents) const
       {
+        /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
+        /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
+        extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid));
+        extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax));
+        extents->width     = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax));
+        extents->height    = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax));
+
+        return true;
+      }
+
+      HBINT16   numberOfContours;
+                        /* If the number of contours is
+                         * greater than or equal to zero,
+                         * this is a simple glyph; if negative,
+                         * this is a composite glyph. */
+      FWORD     xMin;   /* Minimum x for coordinate data. */
+      FWORD     yMin;   /* Minimum y for coordinate data. */
+      FWORD     xMax;   /* Maximum x for coordinate data. */
+      FWORD     yMax;   /* Maximum y for coordinate data. */
+      public:
+      DEFINE_SIZE_STATIC (10);
+    };
+
+    struct SimpleGlyph
+    {
+      const GlyphHeader &header;
+      hb_bytes_t bytes;
+      SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+        header (header_), bytes (bytes_) {}
+
+      unsigned int instruction_len_offset () const
+      { return GlyphHeader::static_size + 2 * header.numberOfContours; }
+
+      unsigned int length (unsigned int instruction_len) const
+      { return instruction_len_offset () + 2 + instruction_len; }
+
+      unsigned int instructions_length () const
+      {
+        unsigned int instruction_length_offset = instruction_len_offset ();
+        if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0;
+
+        const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset);
+        /* Out of bounds of the current glyph */
+        if (unlikely (length (instructionLength) > bytes.length)) return 0;
+        return instructionLength;
+      }
+
+      const Glyph trim_padding () const
+      {
+        /* based on FontTools _g_l_y_f.py::trim */
+        const char *glyph = bytes.arrayZ;
+        const char *glyph_end = glyph + bytes.length;
         /* simple glyph w/contours, possibly trimmable */
-        glyph += GlyphHeader::static_size + 2 * num_contours;
+        glyph += instruction_len_offset ();
 
-        if (unlikely (glyph + 2 >= glyph_end)) return false;
-        uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
-        uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16> (glyph, 0);
+        if (unlikely (glyph + 2 >= glyph_end)) return Glyph ();
+        unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
+        unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
 
-        glyph += 2 + nInstructions;
-        if (unlikely (glyph + 2 >= glyph_end)) return false;
+        glyph += 2 + num_instructions;
 
-        unsigned int coordBytes = 0;
-        unsigned int coordsWithFlags = 0;
+        unsigned int coord_bytes = 0;
+        unsigned int coords_with_flags = 0;
         while (glyph < glyph_end)
         {
-          uint8_t flag = (uint8_t) *glyph;
+          uint8_t flag = *glyph;
           glyph++;
 
           unsigned int repeat = 1;
           if (flag & FLAG_REPEAT)
           {
-            if (glyph >= glyph_end)
-            {
-              DEBUG_MSG(SUBSET, nullptr, "Bad flag");
-              return false;
-            }
-            repeat = ((uint8_t) *glyph) + 1;
+            if (unlikely (glyph >= glyph_end)) return Glyph ();
+            repeat = *glyph + 1;
             glyph++;
           }
 
@@ -335,143 +529,728 @@
           if (flag & FLAG_Y_SHORT) yBytes = 1;
           else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
 
-          coordBytes += (xBytes + yBytes) * repeat;
-          coordsWithFlags += repeat;
-          if (coordsWithFlags >= nCoordinates)
-            break;
+          coord_bytes += (xBytes + yBytes) * repeat;
+          coords_with_flags += repeat;
+          if (coords_with_flags >= num_coordinates) break;
         }
 
-        if (coordsWithFlags != nCoordinates)
-        {
-          DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags);
-          return false;
-        }
-        glyph += coordBytes;
-
-        if (glyph < glyph_end)
-          *end_offset -= glyph_end - glyph;
+        if (unlikely (coords_with_flags != num_coordinates)) return Glyph ();
+        return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph)));
       }
+
+      /* zero instruction length */
+      void drop_hints ()
+      {
+        GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
+        (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
+      }
+
+      void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
+      {
+        unsigned int instructions_len = instructions_length ();
+        unsigned int glyph_length = length (instructions_len);
+        dest_start = bytes.sub_array (0, glyph_length - instructions_len);
+        dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
+      }
+
+      static bool read_points (const HBUINT8 *&p /* IN/OUT */,
+                               contour_point_vector_t &points_ /* IN/OUT */,
+                               const hb_bytes_t &bytes,
+                               void (* setter) (contour_point_t &_, float v),
+                               const simple_glyph_flag_t short_flag,
+                               const simple_glyph_flag_t same_flag)
+      {
+        float v = 0;
+        for (unsigned i = 0; i < points_.length; i++)
+        {
+          uint8_t flag = points_[i].flag;
+          if (flag & short_flag)
+          {
+            if (unlikely (!bytes.check_range (p))) return false;
+            if (flag & same_flag)
+              v += *p++;
+            else
+              v -= *p++;
+          }
+          else
+          {
+            if (!(flag & same_flag))
+            {
+              if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false;
+              v += *(const HBINT16 *) p;
+              p += HBINT16::static_size;
+            }
+          }
+          setter (points_[i], v);
+        }
+        return true;
+      }
+
+      bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
+                               bool phantom_only = false) const
+      {
+        const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
+        int num_contours = header.numberOfContours;
+        if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false;
+        unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
+
+        points_.resize (num_points);
+        for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
+        if (phantom_only) return true;
+
+        for (int i = 0; i < num_contours; i++)
+          points_[endPtsOfContours[i]].is_end_point = true;
+
+        /* Skip instructions */
+        const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
+                                                     endPtsOfContours[num_contours]);
+
+        /* Read flags */
+        for (unsigned int i = 0; i < num_points; i++)
+        {
+          if (unlikely (!bytes.check_range (p))) return false;
+          uint8_t flag = *p++;
+          points_[i].flag = flag;
+          if (flag & FLAG_REPEAT)
+          {
+            if (unlikely (!bytes.check_range (p))) return false;
+            unsigned int repeat_count = *p++;
+            while ((repeat_count-- > 0) && (++i < num_points))
+              points_[i].flag = flag;
+          }
+        }
+
+        /* Read x & y coordinates */
+        return read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.x = v; },
+                            FLAG_X_SHORT, FLAG_X_SAME)
+            && read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.y = v; },
+                            FLAG_Y_SHORT, FLAG_Y_SAME);
+      }
+    };
+
+    struct CompositeGlyph
+    {
+      const GlyphHeader &header;
+      hb_bytes_t bytes;
+      CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
+        header (header_), bytes (bytes_) {}
+
+      composite_iter_t get_iterator () const
+      { return composite_iter_t (bytes, &StructAfter<CompositeGlyphChain, GlyphHeader> (header)); }
+
+      unsigned int instructions_length (hb_bytes_t bytes) const
+      {
+        unsigned int start = bytes.length;
+        unsigned int end = bytes.length;
+        const CompositeGlyphChain *last = nullptr;
+        for (auto &item : get_iterator ())
+          last = &item;
+        if (unlikely (!last)) return 0;
+
+        if (last->has_instructions ())
+          start = (char *) last - &bytes + last->get_size ();
+        if (unlikely (start > end)) return 0;
+        return end - start;
+      }
+
+      /* Trimming for composites not implemented.
+       * If removing hints it falls out of that. */
+      const Glyph trim_padding () const { return Glyph (bytes); }
+
+      void drop_hints ()
+      {
+        for (const auto &_ : get_iterator ())
+          const_cast<CompositeGlyphChain &> (_).drop_instructions_flag ();
+      }
+
+      /* Chop instructions off the end */
+      void drop_hints_bytes (hb_bytes_t &dest_start) const
+      { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
+    };
+
+    enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
+
+    public:
+    composite_iter_t get_composite_iterator () const
+    {
+      if (type != COMPOSITE) return composite_iter_t ();
+      return CompositeGlyph (*header, bytes).get_iterator ();
+    }
+
+    const Glyph trim_padding () const
+    {
+      switch (type) {
+      case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
+      case SIMPLE:    return SimpleGlyph (*header, bytes).trim_padding ();
+      default:        return bytes;
+      }
+    }
+
+    void drop_hints ()
+    {
+      switch (type) {
+      case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
+      case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints (); return;
+      default:        return;
+      }
+    }
+
+    void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
+    {
+      switch (type) {
+      case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
+      case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
+      default:        return;
+      }
+    }
+
+    /* Note: Recursively calls itself.
+     * all_points includes phantom points
+     */
+    bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
+                     contour_point_vector_t &all_points /* OUT */,
+                     bool phantom_only = false,
+                     unsigned int depth = 0) const
+    {
+      if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
+      contour_point_vector_t points;
+
+      switch (type) {
+      case COMPOSITE:
+      {
+        /* pseudo component points for each component in composite glyph */
+        unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ());
+        if (unlikely (!points.resize (num_points))) return false;
+        for (unsigned i = 0; i < points.length; i++)
+          points[i].init ();
+        break;
+      }
+      case SIMPLE:
+        if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
+          return false;
+        break;
+      }
+
+      /* Init phantom points */
+      if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
+      hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
+      {
+        for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init ();
+        int h_delta = (int) header->xMin - glyf_accelerator.hmtx->get_side_bearing (gid);
+        int v_orig  = (int) header->yMax + glyf_accelerator.vmtx->get_side_bearing (gid);
+        unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
+        unsigned v_adv = glyf_accelerator.vmtx->get_advance (gid);
+        phantoms[PHANTOM_LEFT].x = h_delta;
+        phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
+        phantoms[PHANTOM_TOP].y = v_orig;
+        phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
+      }
+
+#ifndef HB_NO_VAR
+      if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ())))
+        return false;
+#endif
+
+      switch (type) {
+      case SIMPLE:
+        all_points.extend (points.as_array ());
+        break;
+      case COMPOSITE:
+      {
+        unsigned int comp_index = 0;
+        for (auto &item : get_composite_iterator ())
+        {
+          contour_point_vector_t comp_points;
+          if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_glyph_index ())
+                                         .get_points (font, glyf_accelerator, comp_points,
+                                                      phantom_only, depth + 1)
+                        || comp_points.length < PHANTOM_COUNT))
+            return false;
+
+          /* Copy phantom points from component if USE_MY_METRICS flag set */
+          if (item.is_use_my_metrics ())
+            for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+              phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
+
+          /* Apply component transformation & translation */
+          item.transform_points (comp_points);
+
+          /* Apply translation from gvar */
+          comp_points.translate (points[comp_index]);
+
+          if (item.is_anchored ())
+          {
+            unsigned int p1, p2;
+            item.get_anchor_points (p1, p2);
+            if (likely (p1 < all_points.length && p2 < comp_points.length))
+            {
+              contour_point_t delta;
+              delta.init (all_points[p1].x - comp_points[p2].x,
+                          all_points[p1].y - comp_points[p2].y);
+
+              comp_points.translate (delta);
+            }
+          }
+
+          all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
+
+          comp_index++;
+        }
+
+        all_points.extend (phantoms);
+      } break;
+      default:
+        all_points.extend (phantoms);
+      }
+
+      if (depth == 0) /* Apply at top level */
+      {
+        /* Undocumented rasterizer behavior:
+         * Shift points horizontally by the updated left side bearing
+         */
+        contour_point_t delta;
+        delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
+        if (delta.x) all_points.translate (delta);
+      }
+
       return true;
     }
 
-    bool get_offsets (hb_codepoint_t  glyph,
-                      unsigned int   *start_offset /* OUT */,
-                      unsigned int   *end_offset   /* OUT */) const
+    bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
+                      hb_glyph_extents_t *extents) const
     {
-      if (unlikely (glyph >= num_glyphs))
+      if (type == EMPTY) return true; /* Empty glyph; zero extents. */
+      return header->get_extents (font, glyf_accelerator, gid, extents);
+    }
+
+    hb_bytes_t get_bytes () const { return bytes; }
+
+    Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
+           hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_),
+                                                        header (bytes.as<GlyphHeader> ())
+    {
+      int num_contours = header->numberOfContours;
+      if (unlikely (num_contours == 0)) type = EMPTY;
+      else if (num_contours > 0) type = SIMPLE;
+      else type = COMPOSITE; /* negative numbers */
+    }
+
+    protected:
+    hb_bytes_t bytes;
+    hb_codepoint_t gid;
+    const GlyphHeader *header;
+    unsigned type;
+  };
+
+  struct accelerator_t
+  {
+    void init (hb_face_t *face_)
+    {
+      short_offset = false;
+      num_glyphs = 0;
+      loca_table = nullptr;
+      glyf_table = nullptr;
+#ifndef HB_NO_VAR
+      gvar = nullptr;
+#endif
+      hmtx = nullptr;
+      vmtx = nullptr;
+      face = face_;
+      const OT::head &head = *face->table.head;
+      if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
+        /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
+        return;
+      short_offset = 0 == head.indexToLocFormat;
+
+      loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
+      glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
+#ifndef HB_NO_VAR
+      gvar = face->table.gvar;
+#endif
+      hmtx = face->table.hmtx;
+      vmtx = face->table.vmtx;
+
+      num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
+      num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
+    }
+
+    void fini ()
+    {
+      loca_table.destroy ();
+      glyf_table.destroy ();
+    }
+
+    protected:
+    template<typename T>
+    bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const
+    {
+      if (gid >= num_glyphs) return false;
+
+      /* Making this alloc free is not that easy
+         https://github.com/harfbuzz/harfbuzz/issues/2095
+         mostly because of gvar handling in VF fonts,
+         perhaps a separate path for non-VF fonts can be considered */
+      contour_point_vector_t all_points;
+
+      bool phantom_only = !consumer.is_consuming_contour_points ();
+      if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only)))
         return false;
 
+      if (consumer.is_consuming_contour_points ())
+      {
+        for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index)
+          consumer.consume_point (all_points[point_index]);
+        consumer.points_end ();
+      }
+
+      /* Where to write phantoms, nullptr if not requested */
+      contour_point_t *phantoms = consumer.get_phantoms_sink ();
+      if (phantoms)
+        for (unsigned i = 0; i < PHANTOM_COUNT; ++i)
+          phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i];
+
+      return true;
+    }
+
+#ifndef HB_NO_VAR
+    struct points_aggregator_t
+    {
+      hb_font_t *font;
+      hb_glyph_extents_t *extents;
+      contour_point_t *phantoms;
+
+      struct contour_bounds_t
+      {
+        contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; }
+
+        void add (const contour_point_t &p)
+        {
+          min_x = hb_min (min_x, p.x);
+          min_y = hb_min (min_y, p.y);
+          max_x = hb_max (max_x, p.x);
+          max_y = hb_max (max_y, p.y);
+        }
+
+        bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
+
+        void get_extents (hb_font_t *font, hb_glyph_extents_t *extents)
+        {
+          if (unlikely (empty ()))
+          {
+            extents->width = 0;
+            extents->x_bearing = 0;
+            extents->height = 0;
+            extents->y_bearing = 0;
+            return;
+          }
+          extents->x_bearing = font->em_scalef_x (min_x);
+          extents->width = font->em_scalef_x (max_x - min_x);
+          extents->y_bearing = font->em_scalef_y (max_y);
+          extents->height = font->em_scalef_y (min_y - max_y);
+        }
+
+        protected:
+        float min_x, min_y, max_x, max_y;
+      } bounds;
+
+      points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_)
+      {
+        font = font_;
+        extents = extents_;
+        phantoms = phantoms_;
+        if (extents) bounds = contour_bounds_t ();
+      }
+
+      void consume_point (const contour_point_t &point) { bounds.add (point); }
+      void points_end () { bounds.get_extents (font, extents); }
+
+      bool is_consuming_contour_points () { return extents; }
+      contour_point_t *get_phantoms_sink () { return phantoms; }
+    };
+
+    public:
+    unsigned
+    get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+    {
+      if (unlikely (gid >= num_glyphs)) return 0;
+
+      bool success = false;
+
+      contour_point_t phantoms[PHANTOM_COUNT];
+      if (likely (font->num_coords == gvar->get_axis_count ()))
+        success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms));
+
+      if (unlikely (!success))
+        return is_vertical ? vmtx->get_advance (gid) : hmtx->get_advance (gid);
+
+      float result = is_vertical
+                   ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y
+                   : phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x;
+      return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2);
+    }
+
+    int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
+    {
+      if (unlikely (gid >= num_glyphs)) return 0;
+
+      hb_glyph_extents_t extents;
+
+      contour_point_t phantoms[PHANTOM_COUNT];
+      if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms))))
+        return is_vertical ? vmtx->get_side_bearing (gid) : hmtx->get_side_bearing (gid);
+
+      return is_vertical
+           ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing
+           : floorf (phantoms[PHANTOM_LEFT].x);
+    }
+#endif
+
+    public:
+    bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
+    {
+      if (unlikely (gid >= num_glyphs)) return false;
+
+#ifndef HB_NO_VAR
+      if (font->num_coords && font->num_coords == gvar->get_axis_count ())
+        return get_points (font, gid, points_aggregator_t (font, extents, nullptr));
+#endif
+      return glyph_for_gid (gid).get_extents (font, *this, extents);
+    }
+
+    const Glyph
+    glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
+    {
+      if (unlikely (gid >= num_glyphs)) return Glyph ();
+
+      unsigned int start_offset, end_offset;
+
       if (short_offset)
       {
         const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
-        *start_offset = 2 * offsets[glyph];
-        *end_offset   = 2 * offsets[glyph + 1];
+        start_offset = 2 * offsets[gid];
+        end_offset   = 2 * offsets[gid + 1];
       }
       else
       {
         const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
-
-        *start_offset = offsets[glyph];
-        *end_offset   = offsets[glyph + 1];
+        start_offset = offsets[gid];
+        end_offset   = offsets[gid + 1];
       }
 
-      if (*start_offset > *end_offset || *end_offset > glyf_table.get_length ())
-        return false;
+      if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ()))
+        return Glyph ();
 
-      return true;
+      Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
+                               end_offset - start_offset), gid);
+      return needs_padding_removal ? glyph.trim_padding () : glyph;
     }
 
-    bool get_instruction_offsets (unsigned int start_offset,
-                                  unsigned int end_offset,
-                                  unsigned int *instruction_start /* OUT */,
-                                  unsigned int *instruction_end /* OUT */) const
+    void
+    add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain,
+                          unsigned int depth = 0) const
     {
-      if (end_offset - start_offset < GlyphHeader::static_size)
-      {
-        *instruction_start = 0;
-        *instruction_end = 0;
-        return true; /* Empty glyph; no instructions. */
-      }
-      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
-      int16_t num_contours = (int16_t) glyph_header.numberOfContours;
-      if (num_contours < 0)
-      {
-        CompositeGlyphHeader::Iterator composite_it;
-        if (unlikely (!CompositeGlyphHeader::get_iterator (
-            (const char*) this->glyf_table + start_offset,
-             end_offset - start_offset, &composite_it))) return false;
-        const CompositeGlyphHeader *last;
-        do {
-          last = composite_it.current;
-        } while (composite_it.move_to_next ());
+      if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return;
+      /* Check if is already visited */
+      if (gids_to_retain->has (gid)) return;
 
-        if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
-          *instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size ();
+      gids_to_retain->add (gid);
+
+      for (auto &item : glyph_for_gid (gid).get_composite_iterator ())
+        add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth);
+    }
+
+#ifdef HB_EXPERIMENTAL_API
+    struct path_builder_t
+    {
+      hb_font_t *font;
+      draw_helper_t *draw_helper;
+
+      struct optional_point_t
+      {
+        optional_point_t () { has_data = false; }
+        optional_point_t (float x_, float y_) { x = x_; y = y_; has_data = true; }
+
+        bool has_data;
+        float x;
+        float y;
+
+        optional_point_t lerp (optional_point_t p, float t)
+        { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
+      } first_oncurve, first_offcurve, last_offcurve;
+
+      path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_)
+      {
+        font = font_;
+        draw_helper = &draw_helper_;
+        first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
+      }
+
+      /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
+         See also:
+         * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
+         * https://stackoverflow.com/a/20772557 */
+      void consume_point (const contour_point_t &point)
+      {
+        /* Skip empty contours */
+        if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data))
+          return;
+
+        bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE;
+        optional_point_t p (point.x, point.y);
+        if (!first_oncurve.has_data)
+        {
+          if (is_on_curve)
+          {
+            first_oncurve = p;
+            draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
+          }
+          else
+          {
+            if (first_offcurve.has_data)
+            {
+              optional_point_t mid = first_offcurve.lerp (p, .5f);
+              first_oncurve = mid;
+              last_offcurve = p;
+              draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
+            }
+            else
+              first_offcurve = p;
+          }
+        }
         else
-          *instruction_start = end_offset;
-        *instruction_end = end_offset;
-        if (unlikely (*instruction_start > *instruction_end))
         {
-          DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset);
-          return false;
+          if (last_offcurve.has_data)
+          {
+            if (is_on_curve)
+            {
+              draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
+                                         font->em_scalef_x (p.x), font->em_scalef_y (p.y));
+              last_offcurve = optional_point_t ();
+            }
+            else
+            {
+              optional_point_t mid = last_offcurve.lerp (p, .5f);
+              draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
+                                         font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
+              last_offcurve = p;
+            }
+          }
+          else
+          {
+            if (is_on_curve)
+              draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
+            else
+              last_offcurve = p;
+          }
+        }
+
+        if (point.is_end_point)
+        {
+          if (first_offcurve.has_data && last_offcurve.has_data)
+          {
+            optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
+            draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
+                                       font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
+            last_offcurve = optional_point_t ();
+            /* now check the rest */
+          }
+
+          if (first_offcurve.has_data && first_oncurve.has_data)
+            draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y),
+                                       font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
+          else if (last_offcurve.has_data && first_oncurve.has_data)
+            draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
+                                       font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
+          else if (first_oncurve.has_data)
+            draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
+
+          /* Getting ready for the next contour */
+          first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
+          draw_helper->end_path ();
         }
       }
-      else
-      {
-        unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours;
-        if (unlikely (instruction_length_offset + 2 > end_offset))
-        {
-          DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength.");
-          return false;
-        }
+      void points_end () {}
 
-        const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset);
-        unsigned int start = instruction_length_offset + 2;
-        unsigned int end = start + (uint16_t) instruction_length;
-        if (unlikely (end > end_offset)) // Out of bounds of the current glyph
-        {
-          DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries.");
-          return false;
-        }
+      bool is_consuming_contour_points () { return true; }
+      contour_point_t *get_phantoms_sink () { return nullptr; }
+    };
 
-        *instruction_start = start;
-        *instruction_end = end;
-      }
-      return true;
-    }
+    bool
+    get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const
+    { return get_points (font, gid, path_builder_t (font, draw_helper)); }
+#endif
 
-    bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
-    {
-      unsigned int start_offset, end_offset;
-      if (!get_offsets (glyph, &start_offset, &end_offset))
-        return false;
-
-      if (end_offset - start_offset < GlyphHeader::static_size)
-        return true; /* Empty glyph; zero extents. */
-
-      const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
-
-      extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
-      extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
-      extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
-      extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
-
-      return true;
-    }
+#ifndef HB_NO_VAR
+    const gvar_accelerator_t *gvar;
+#endif
+    const hmtx_accelerator_t *hmtx;
+    const vmtx_accelerator_t *vmtx;
 
     private:
     bool short_offset;
     unsigned int num_glyphs;
     hb_blob_ptr_t<loca> loca_table;
     hb_blob_ptr_t<glyf> glyf_table;
+    hb_face_t *face;
+  };
+
+  struct SubsetGlyph
+  {
+    hb_codepoint_t new_gid;
+    hb_codepoint_t old_gid;
+    Glyph source_glyph;
+    hb_bytes_t dest_start;  /* region of source_glyph to copy first */
+    hb_bytes_t dest_end;    /* region of source_glyph to copy second */
+
+    bool serialize (hb_serialize_context_t *c,
+                    const hb_subset_plan_t *plan) const
+    {
+      TRACE_SERIALIZE (this);
+
+      hb_bytes_t dest_glyph = dest_start.copy (c);
+      dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
+      unsigned int pad_length = padding ();
+      DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
+
+      HBUINT8 pad;
+      pad = 0;
+      while (pad_length > 0)
+      {
+        c->embed (pad);
+        pad_length--;
+      }
+
+      if (unlikely (!dest_glyph.length)) return_trace (true);
+
+      /* update components gids */
+      for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
+      {
+        hb_codepoint_t new_gid;
+        if (plan->new_gid_for_old_gid (_.get_glyph_index (), &new_gid))
+          const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid);
+      }
+
+      if (plan->drop_hints) Glyph (dest_glyph).drop_hints ();
+
+      return_trace (true);
+    }
+
+    void drop_hints_bytes ()
+    { source_glyph.drop_hints_bytes (dest_start, dest_end); }
+
+    unsigned int      length () const { return dest_start.length + dest_end.length; }
+    /* pad to 2 to ensure 2-byte loca will be ok */
+    unsigned int     padding () const { return length () % 2; }
+    unsigned int padded_size () const { return length () + padding (); }
   };
 
   protected:
-  UnsizedArrayOf<HBUINT8>       dataZ;          /* Glyphs data. */
+  UnsizedArrayOf<HBUINT8>
+                dataZ;  /* Glyphs data. */
   public:
-  DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always
-                        * check the size externally, allow Null() object of it by
-                        * defining it MIN() instead. */
+  DEFINE_SIZE_MIN (0);  /* In reality, this is UNBOUNDED() type; but since we always
+                         * check the size externally, allow Null() object of it by
+                         * defining it _MIN instead. */
 };
 
 struct glyf_accelerator_t : glyf::accelerator_t {};
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh
index d27d098..201ffc5 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh
@@ -41,68 +41,31 @@
 
 struct DeviceRecord
 {
-  struct SubsetView
-  {
-    const DeviceRecord *source_device_record;
-    unsigned int sizeDeviceRecord;
-    hb_subset_plan_t *subset_plan;
-
-    void init (const DeviceRecord *source_device_record,
-               unsigned int sizeDeviceRecord,
-               hb_subset_plan_t   *subset_plan)
-    {
-      this->source_device_record = source_device_record;
-      this->sizeDeviceRecord = sizeDeviceRecord;
-      this->subset_plan = subset_plan;
-    }
-
-    unsigned int len () const
-    { return this->subset_plan->glyphs.length; }
-
-    const HBUINT8* operator [] (unsigned int i) const
-    {
-      if (unlikely (i >= len ())) return nullptr;
-      hb_codepoint_t gid = this->subset_plan->glyphs [i];
-
-      if (gid >= sizeDeviceRecord - DeviceRecord::min_size)
-        return nullptr;
-      return &(this->source_device_record->widthsZ[gid]);
-    }
-  };
-
-  static unsigned int get_size (unsigned int count)
+  static unsigned int get_size (unsigned count)
   { return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); }
 
-  bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view)
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
   {
     TRACE_SERIALIZE (this);
 
-    unsigned int size = get_size (subset_view.len ());
-    if (unlikely (!c->allocate_size<DeviceRecord> (size)))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
-                 size);
-      return_trace (false);
-    }
+    unsigned length = it.len ();
 
-    this->pixelSize.set (subset_view.source_device_record->pixelSize);
-    this->maxWidth.set (subset_view.source_device_record->maxWidth);
+    if (unlikely (!c->extend (*this, length)))  return_trace (false);
 
-    for (unsigned int i = 0; i < subset_view.len (); i++)
-    {
-      const HBUINT8 *width = subset_view[i];
-      if (!width)
-      {
-        DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i);
-        return_trace (false);
-      }
-      widthsZ[i].set (*width);
-    }
+    this->pixelSize = pixelSize;
+    this->maxWidth =
+    + it
+    | hb_reduce (hb_max, 0u);
+
+    + it
+    | hb_sink (widthsZ.as_array (length));
 
     return_trace (true);
   }
 
-  bool sanitize (hb_sanitize_context_t *c, unsigned int sizeDeviceRecord) const
+  bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
@@ -132,62 +95,60 @@
     return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
   }
 
-  bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan)
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
   {
     TRACE_SERIALIZE (this);
 
     if (unlikely (!c->extend_min ((*this))))  return_trace (false);
 
-    this->version.set (source_hdmx->version);
-    this->numRecords.set (source_hdmx->numRecords);
-    this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->glyphs.length));
+    this->version = version;
+    this->numRecords = it.len ();
+    this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
 
-    for (unsigned int i = 0; i < source_hdmx->numRecords; i++)
-    {
-      DeviceRecord::SubsetView subset_view;
-      subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan);
+    for (const hb_item_type<Iterator>& _ : +it)
+      c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
 
-      if (!c->start_embed<DeviceRecord> ()->serialize (c, subset_view))
-        return_trace (false);
-    }
+    return_trace (c->successful);
+  }
 
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    hdmx *hdmx_prime = c->serializer->start_embed <hdmx> ();
+    if (unlikely (!hdmx_prime)) return_trace (false);
+
+    auto it =
+    + hb_range ((unsigned) numRecords)
+    | hb_map ([c, this] (unsigned _)
+        {
+          const DeviceRecord *device_record =
+            &StructAtOffset<DeviceRecord> (&firstDeviceRecord,
+                                           _ * sizeDeviceRecord);
+          auto row =
+            + hb_range (c->plan->num_output_glyphs ())
+            | hb_map (c->plan->reverse_glyph_map)
+            | hb_map ([this, c, device_record] (hb_codepoint_t _)
+                      {
+                        if (c->plan->is_empty_glyph (_))
+                          return Null (HBUINT8);
+                        return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
+                      })
+            ;
+          return hb_pair ((unsigned) device_record->pixelSize, +row);
+        })
+    ;
+
+    hdmx_prime->serialize (c->serializer, version, it);
     return_trace (true);
   }
 
-  static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
+  unsigned get_num_glyphs () const
   {
-    return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->glyphs.length);
-  }
-
-  bool subset (hb_subset_plan_t *plan) const
-  {
-    size_t dest_size = get_subsetted_size (this, plan);
-    hdmx *dest = (hdmx *) malloc (dest_size);
-    if (unlikely (!dest))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for hdmx subset output.", (unsigned long) dest_size);
-      return false;
-    }
-
-    hb_serialize_context_t c (dest, dest_size);
-    hdmx *hdmx_prime = c.start_serialize<hdmx> ();
-    if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan))
-    {
-      free (dest);
-      DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx.");
-      return false;
-    }
-    c.end_serialize ();
-
-    hb_blob_t *hdmx_prime_blob = hb_blob_create ((const char *) dest,
-                                                 dest_size,
-                                                 HB_MEMORY_MODE_READONLY,
-                                                 dest,
-                                                 free);
-    bool result = plan->add_table (HB_OT_TAG_hdmx, hdmx_prime_blob);
-    hb_blob_destroy (hdmx_prime_blob);
-
-    return result;
+    return sizeDeviceRecord - DeviceRecord::min_size;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -200,10 +161,12 @@
   }
 
   protected:
-  HBUINT16              version;                /* Table version number (0) */
-  HBUINT16              numRecords;             /* Number of device records. */
-  HBUINT32              sizeDeviceRecord;       /* Size of a device record, 32-bit aligned. */
-  DeviceRecord          firstDeviceRecord;      /* Array of device records. */
+  HBUINT16      version;        /* Table version number (0) */
+  HBUINT16      numRecords;     /* Number of device records. */
+  HBUINT32      sizeDeviceRecord;
+                                /* Size of a device record, 32-bit aligned. */
+  DeviceRecord  firstDeviceRecord;
+                                /* Array of device records. */
   public:
   DEFINE_SIZE_MIN (8);
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh
index d7448d2..3f4af70 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh
@@ -54,6 +54,18 @@
     return 16 <= upem && upem <= 16384 ? upem : 1000;
   }
 
+  bool serialize (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace ((bool) c->embed (this));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace (serialize (c->serializer));
+  }
+
   enum mac_style_flag_t {
     BOLD        = 1u<<0,
     ITALIC      = 1u<<1,
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh
index 66879a0..37ef874 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh
@@ -45,6 +45,8 @@
 template <typename T>
 struct _hea
 {
+  bool has_data () const { return version.major; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -52,35 +54,38 @@
   }
 
   public:
-  FixedVersion<>version;                /* 0x00010000u for version 1.0. */
-  FWORD         ascender;               /* Typographic ascent. */
-  FWORD         descender;              /* Typographic descent. */
-  FWORD         lineGap;                /* Typographic line gap. */
-  UFWORD        advanceMax;             /* Maximum advance width/height value in
-                                         * metrics table. */
-  FWORD         minLeadingBearing;      /* Minimum left/top sidebearing value in
-                                         * metrics table. */
-  FWORD         minTrailingBearing;     /* Minimum right/bottom sidebearing value;
-                                         * calculated as Min(aw - lsb -
-                                         * (xMax - xMin)) for horizontal. */
-  FWORD         maxExtent;              /* horizontal: Max(lsb + (xMax - xMin)),
-                                         * vertical: minLeadingBearing+(yMax-yMin). */
-  HBINT16               caretSlopeRise;         /* Used to calculate the slope of the
-                                         * cursor (rise/run); 1 for vertical caret,
-                                         * 0 for horizontal.*/
-  HBINT16               caretSlopeRun;          /* 0 for vertical caret, 1 for horizontal. */
-  HBINT16               caretOffset;            /* The amount by which a slanted
-                                         * highlight on a glyph needs
-                                         * to be shifted to produce the
-                                         * best appearance. Set to 0 for
-                                         * non-slanted fonts. */
-  HBINT16               reserved1;              /* Set to 0. */
-  HBINT16               reserved2;              /* Set to 0. */
-  HBINT16               reserved3;              /* Set to 0. */
-  HBINT16               reserved4;              /* Set to 0. */
-  HBINT16               metricDataFormat;       /* 0 for current format. */
-  HBUINT16      numberOfLongMetrics;    /* Number of LongMetric entries in metric
-                                         * table. */
+  FixedVersion<>version;        /* 0x00010000u for version 1.0. */
+  FWORD         ascender;       /* Typographic ascent. */
+  FWORD         descender;      /* Typographic descent. */
+  FWORD         lineGap;        /* Typographic line gap. */
+  UFWORD        advanceMax;     /* Maximum advance width/height value in
+                                 * metrics table. */
+  FWORD         minLeadingBearing;
+                                /* Minimum left/top sidebearing value in
+                                 * metrics table. */
+  FWORD         minTrailingBearing;
+                                /* Minimum right/bottom sidebearing value;
+                                 * calculated as Min(aw - lsb -
+                                 * (xMax - xMin)) for horizontal. */
+  FWORD         maxExtent;      /* horizontal: Max(lsb + (xMax - xMin)),
+                                 * vertical: minLeadingBearing+(yMax-yMin). */
+  HBINT16       caretSlopeRise; /* Used to calculate the slope of the
+                                 * cursor (rise/run); 1 for vertical caret,
+                                 * 0 for horizontal.*/
+  HBINT16       caretSlopeRun;  /* 0 for vertical caret, 1 for horizontal. */
+  HBINT16       caretOffset;    /* The amount by which a slanted
+                                 * highlight on a glyph needs
+                                 * to be shifted to produce the
+                                 * best appearance. Set to 0 for
+                                 * non-slanted fonts. */
+  HBINT16       reserved1;      /* Set to 0. */
+  HBINT16       reserved2;      /* Set to 0. */
+  HBINT16       reserved3;      /* Set to 0. */
+  HBINT16       reserved4;      /* Set to 0. */
+  HBINT16       metricDataFormat;/* 0 for current format. */
+  HBUINT16      numberOfLongMetrics;
+                                /* Number of LongMetric entries in metric
+                                 * table. */
   public:
   DEFINE_SIZE_STATIC (36);
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh
index dfb0f78..0a2973d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh
@@ -29,8 +29,8 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-hhea-table.hh"
-#include "hb-ot-os2-table.hh"
 #include "hb-ot-var-hvar-table.hh"
+#include "hb-ot-metrics.hh"
 
 /*
  * hmtx -- Horizontal Metrics
@@ -42,6 +42,13 @@
 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
 
 
+HB_INTERNAL int
+_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+
+HB_INTERNAL unsigned
+_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+
+
 namespace OT {
 
 
@@ -53,6 +60,7 @@
   DEFINE_SIZE_STATIC (4);
 };
 
+
 template <typename T, typename H>
 struct hmtxvmtx
 {
@@ -66,7 +74,7 @@
 
 
   bool subset_update_header (hb_subset_plan_t *plan,
-                                    unsigned int num_hmetrics) const
+                             unsigned int num_hmetrics) const
   {
     hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (plan->source, H::tableTag);
     hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
@@ -78,7 +86,7 @@
 
     unsigned int length;
     H *table = (H *) hb_blob_get_data (dest_blob, &length);
-    table->numberOfLongMetrics.set (num_hmetrics);
+    table->numberOfLongMetrics = num_hmetrics;
 
     bool result = plan->add_table (H::tableTag, dest_blob);
     hb_blob_destroy (dest_blob);
@@ -86,100 +94,66 @@
     return result;
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  Iterator it,
+                  unsigned num_advances)
   {
-    typename T::accelerator_t _mtx;
-    _mtx.init (plan->source);
-
-    /* All the trailing glyphs with the same advance can use one LongMetric
-     * and just keep LSB */
-    hb_vector_t<hb_codepoint_t> &gids = plan->glyphs;
-    unsigned int num_advances = gids.length;
-    unsigned int last_advance = _mtx.get_advance (gids[num_advances - 1]);
-    while (num_advances > 1 &&
-           last_advance == _mtx.get_advance (gids[num_advances - 2]))
+    unsigned idx = 0;
+    for (auto _ : it)
     {
-      num_advances--;
-    }
-
-    /* alloc the new table */
-    size_t dest_sz = num_advances * 4
-                  + (gids.length - num_advances) * 2;
-    void *dest = (void *) malloc (dest_sz);
-    if (unlikely (!dest))
-    {
-      return false;
-    }
-    DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in src has %d advances, %d lsbs", HB_UNTAG(T::tableTag), _mtx.num_advances, _mtx.num_metrics - _mtx.num_advances);
-    DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, gids.length - num_advances, (unsigned int) dest_sz);
-
-    const char *source_table = hb_blob_get_data (_mtx.table.get_blob (), nullptr);
-    // Copy everything over
-    LongMetric * old_metrics = (LongMetric *) source_table;
-    FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances);
-    char * dest_pos = (char *) dest;
-
-    bool failed = false;
-    for (unsigned int i = 0; i < gids.length; i++)
-    {
-      /* the last metric or the one for gids[i] */
-      LongMetric *src_metric = old_metrics + MIN ((hb_codepoint_t) _mtx.num_advances - 1, gids[i]);
-      if (gids[i] < _mtx.num_advances)
+      if (idx < num_advances)
       {
-        /* src is a LongMetric */
-        if (i < num_advances)
-        {
-          /* dest is a LongMetric, copy it */
-          *((LongMetric *) dest_pos) = *src_metric;
-        }
-        else
-        {
-          /* dest just sb */
-          *((FWORD *) dest_pos) = src_metric->sb;
-        }
+        LongMetric lm;
+        lm.advance = _.first;
+        lm.sb = _.second;
+        if (unlikely (!c->embed<LongMetric> (&lm))) return;
       }
       else
       {
-        if (gids[i] >= _mtx.num_metrics)
-        {
-          DEBUG_MSG(SUBSET, nullptr, "gid %d is >= number of source metrics %d",
-                    gids[i], _mtx.num_metrics);
-          failed = true;
-          break;
-        }
-        FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances);
-        if (i < num_advances)
-        {
-          /* dest needs a full LongMetric */
-          LongMetric *metric = (LongMetric *)dest_pos;
-          metric->advance = src_metric->advance;
-          metric->sb = src_sb;
-        }
-        else
-        {
-          /* dest just needs an sb */
-          *((FWORD *) dest_pos) = src_sb;
-        }
+        FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
+        if (unlikely (!sb)) return;
+        *sb = _.second;
       }
-      dest_pos += (i < num_advances ? 4 : 2);
+      idx++;
     }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    T *table_prime = c->serializer->start_embed <T> ();
+    if (unlikely (!table_prime)) return_trace (false);
+
+    accelerator_t _mtx;
+    _mtx.init (c->plan->source);
+    unsigned num_advances = _mtx.num_advances_for_subset (c->plan);
+
+    auto it =
+    + hb_range (c->plan->num_output_glyphs ())
+    | hb_map ([c, &_mtx] (unsigned _)
+              {
+                hb_codepoint_t old_gid;
+                if (!c->plan->old_gid_for_new_gid (_, &old_gid))
+                  return hb_pair (0u, 0);
+                return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid));
+              })
+    ;
+
+    table_prime->serialize (c->serializer, it, num_advances);
+
     _mtx.fini ();
 
-    // Amend header num hmetrics
-    if (failed || unlikely (!subset_update_header (plan, num_advances)))
-    {
-      free (dest);
-      return false;
-    }
+    if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ()))
+      return_trace (false);
 
-    hb_blob_t *result = hb_blob_create ((const char *)dest,
-                                        dest_sz,
-                                        HB_MEMORY_MODE_READONLY,
-                                        dest,
-                                        free);
-    bool success = plan->add_table (T::tableTag, result);
-    hb_blob_destroy (result);
-    return success;
+    // Amend header num hmetrics
+    if (unlikely (!subset_update_header (c->plan, num_advances)))
+      return_trace (false);
+
+    return_trace (true);
   }
 
   struct accelerator_t
@@ -187,34 +161,13 @@
     friend struct hmtxvmtx;
 
     void init (hb_face_t *face,
-                      unsigned int default_advance_ = 0)
+               unsigned int default_advance_ = 0)
     {
       default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
 
-      bool got_font_extents = false;
-      if (T::os2Tag != HB_TAG_NONE && face->table.OS2->is_typo_metrics ())
-      {
-        ascender = abs (face->table.OS2->sTypoAscender);
-        descender = -abs (face->table.OS2->sTypoDescender);
-        line_gap = face->table.OS2->sTypoLineGap;
-        got_font_extents = (ascender | descender) != 0;
-      }
+      num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics;
 
-      hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table<H> (face);
-      const H *_hea_table = _hea_blob->as<H> ();
-      num_advances = _hea_table->numberOfLongMetrics;
-      if (!got_font_extents)
-      {
-        ascender = abs (_hea_table->ascender);
-        descender = -abs (_hea_table->descender);
-        line_gap = _hea_table->lineGap;
-        got_font_extents = (ascender | descender) != 0;
-      }
-      hb_blob_destroy (_hea_blob);
-
-      has_font_extents = got_font_extents;
-
-      table = hb_sanitize_context_t().reference_table<hmtxvmtx> (face, T::tableTag);
+      table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
 
       /* Cap num_metrics() and num_advances() based on table length. */
       unsigned int len = table.get_length ();
@@ -231,7 +184,7 @@
         table = hb_blob_get_empty ();
       }
 
-      var_table = hb_sanitize_context_t().reference_table<HVARVVAR> (face, T::variationsTag);
+      var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
     }
 
     void fini ()
@@ -240,8 +193,7 @@
       var_table.destroy ();
     }
 
-    /* TODO Add variations version. */
-    unsigned int get_side_bearing (hb_codepoint_t glyph) const
+    int get_side_bearing (hb_codepoint_t glyph) const
     {
       if (glyph < num_advances)
         return table->longMetricZ[glyph].sb;
@@ -253,6 +205,23 @@
       return bearings[glyph - num_advances];
     }
 
+    int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
+    {
+      int side_bearing = get_side_bearing (glyph);
+
+#ifndef HB_NO_VAR
+      if (unlikely (glyph >= num_metrics) || !font->num_coords)
+        return side_bearing;
+
+      if (var_table.get_length ())
+        return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
+
+      return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+#else
+      return side_bearing;
+#endif
+    }
+
     unsigned int get_advance (hb_codepoint_t glyph) const
     {
       if (unlikely (glyph >= num_metrics))
@@ -266,25 +235,52 @@
           return default_advance;
       }
 
-      return table->longMetricZ[MIN (glyph, (uint32_t) num_advances - 1)].advance;
+      return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
     }
 
     unsigned int get_advance (hb_codepoint_t  glyph,
                               hb_font_t      *font) const
     {
       unsigned int advance = get_advance (glyph);
-      if (likely (glyph < num_metrics))
-      {
-        advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?!
-      }
+
+#ifndef HB_NO_VAR
+      if (unlikely (glyph >= num_metrics) || !font->num_coords)
+        return advance;
+
+      if (var_table.get_length ())
+        return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?!
+
+      return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+#else
       return advance;
+#endif
     }
 
-    public:
-    bool has_font_extents;
-    int ascender;
-    int descender;
-    int line_gap;
+    unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const
+    {
+      unsigned int num_advances = plan->num_output_glyphs ();
+      unsigned int last_advance = _advance_for_new_gid (plan,
+                                                        num_advances - 1);
+      while (num_advances > 1 &&
+             last_advance == _advance_for_new_gid (plan,
+                                                   num_advances - 2))
+      {
+        num_advances--;
+      }
+
+      return num_advances;
+    }
+
+    private:
+    unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan,
+                                       hb_codepoint_t new_gid) const
+    {
+      hb_codepoint_t old_gid;
+      if (!plan->old_gid_for_new_gid (new_gid, &old_gid))
+        return 0;
+
+      return get_advance (old_gid);
+    }
 
     protected:
     unsigned int num_metrics;
@@ -297,27 +293,29 @@
   };
 
   protected:
-  UnsizedArrayOf<LongMetric>longMetricZ;/* Paired advance width and leading
-                                         * bearing values for each glyph. The
-                                         * value numOfHMetrics comes from
-                                         * the 'hhea' table. If the font is
-                                         * monospaced, only one entry need
-                                         * be in the array, but that entry is
-                                         * required. The last entry applies to
-                                         * all subsequent glyphs. */
-/*UnsizedArrayOf<FWORD> leadingBearingX;*//* Here the advance is assumed
-                                         * to be the same as the advance
-                                         * for the last entry above. The
-                                         * number of entries in this array is
-                                         * derived from numGlyphs (from 'maxp'
-                                         * table) minus numberOfLongMetrics.
-                                         * This generally is used with a run
-                                         * of monospaced glyphs (e.g., Kanji
-                                         * fonts or Courier fonts). Only one
-                                         * run is allowed and it must be at
-                                         * the end. This allows a monospaced
-                                         * font to vary the side bearing
-                                         * values for each glyph. */
+  UnsizedArrayOf<LongMetric>
+                longMetricZ;    /* Paired advance width and leading
+                                 * bearing values for each glyph. The
+                                 * value numOfHMetrics comes from
+                                 * the 'hhea' table. If the font is
+                                 * monospaced, only one entry need
+                                 * be in the array, but that entry is
+                                 * required. The last entry applies to
+                                 * all subsequent glyphs. */
+/*UnsizedArrayOf<FWORD> leadingBearingX;*/
+                                /* Here the advance is assumed
+                                 * to be the same as the advance
+                                 * for the last entry above. The
+                                 * number of entries in this array is
+                                 * derived from numGlyphs (from 'maxp'
+                                 * table) minus numberOfLongMetrics.
+                                 * This generally is used with a run
+                                 * of monospaced glyphs (e.g., Kanji
+                                 * fonts or Courier fonts). Only one
+                                 * run is allowed and it must be at
+                                 * the end. This allows a monospaced
+                                 * font to vary the side bearing
+                                 * values for each glyph. */
   public:
   DEFINE_SIZE_ARRAY (0, longMetricZ);
 };
@@ -325,12 +323,12 @@
 struct hmtx : hmtxvmtx<hmtx, hhea> {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
   static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
-  static constexpr hb_tag_t os2Tag = HB_OT_TAG_OS2;
+  static constexpr bool is_horizontal = true;
 };
 struct vmtx : hmtxvmtx<vmtx, vhea> {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
   static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
-  static constexpr hb_tag_t os2Tag = HB_TAG_NONE;
+  static constexpr bool is_horizontal = false;
 };
 
 struct hmtx_accelerator_t : hmtx::accelerator_t {};
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh
index 9d870ec..37ea127 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh
@@ -47,9 +47,9 @@
   int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
   {
     hb_array_t<const FWORD> kernValue = kernValueZ.as_array (kernValueCount);
-    hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (kernValue).as_array (glyphCount);
-    hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (leftClass).as_array (glyphCount);
-    hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8> > (rightClass).as_array (leftClassCount * rightClassCount);
+    hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (kernValue).as_array (glyphCount);
+    hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (leftClass).as_array (glyphCount);
+    hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8>> (rightClass).as_array (leftClassCount * rightClassCount);
 
     unsigned int leftC = leftClass[left];
     unsigned int rightC = rightClass[right];
@@ -86,21 +86,26 @@
   }
 
   protected:
-  KernSubTableHeader    header;
-  HBUINT16              glyphCount;     /* The number of glyphs in this font. */
-  HBUINT8               kernValueCount; /* The number of kerning values. */
-  HBUINT8               leftClassCount; /* The number of left-hand classes. */
-  HBUINT8               rightClassCount;/* The number of right-hand classes. */
-  HBUINT8               flags;          /* Set to zero (reserved for future use). */
-  UnsizedArrayOf<FWORD> kernValueZ;     /* The kerning values.
-                                         * Length kernValueCount. */
+  KernSubTableHeader
+                header;
+  HBUINT16      glyphCount;     /* The number of glyphs in this font. */
+  HBUINT8       kernValueCount; /* The number of kerning values. */
+  HBUINT8       leftClassCount; /* The number of left-hand classes. */
+  HBUINT8       rightClassCount;/* The number of right-hand classes. */
+  HBUINT8       flags;          /* Set to zero (reserved for future use). */
+  UnsizedArrayOf<FWORD>
+                kernValueZ;     /* The kerning values.
+                                 * Length kernValueCount. */
 #if 0
-  UnsizedArrayOf<HBUINT8>leftClass;     /* The left-hand classes.
-                                         * Length glyphCount. */
-  UnsizedArrayOf<HBUINT8>rightClass;    /* The right-hand classes.
-                                         * Length glyphCount. */
-  UnsizedArrayOf<HBUINT8>kernIndex;     /* The indices into the kernValue array.
-                                         * Length leftClassCount * rightClassCount */
+  UnsizedArrayOf<HBUINT8>
+                leftClass;      /* The left-hand classes.
+                                 * Length glyphCount. */
+  UnsizedArrayOf<HBUINT8>
+                rightClass;     /* The right-hand classes.
+                                 * Length glyphCount. */
+  UnsizedArrayOf<HBUINT8>kernIndex;
+                                /* The indices into the kernValue array.
+                                 * Length leftClassCount * rightClassCount */
 #endif
   public:
   DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ);
@@ -121,16 +126,20 @@
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
     case 0:     return_trace (c->dispatch (u.format0));
-    case 1:     return_trace (u.header.apple ? c->dispatch (u.format1) : c->default_return_value ());
+#ifndef HB_NO_AAT_SHAPE
+    case 1:     return_trace (u.header.apple ? c->dispatch (u.format1, hb_forward<Ts> (ds)...) : c->default_return_value ());
+#endif
     case 2:     return_trace (c->dispatch (u.format2));
-    case 3:     return_trace (u.header.apple ? c->dispatch (u.format3) : c->default_return_value ());
+#ifndef HB_NO_AAT_SHAPE
+    case 3:     return_trace (u.header.apple ? c->dispatch (u.format3, hb_forward<Ts> (ds)...) : c->default_return_value ());
+#endif
     default:    return_trace (c->default_return_value ());
     }
   }
@@ -163,8 +172,8 @@
   static constexpr bool apple = false;
   typedef AAT::ObsoleteTypes Types;
 
-  unsigned int tuple_count () const { return 0; }
-  bool is_horizontal () const { return (coverage & Horizontal); }
+  unsigned   tuple_count () const { return 0; }
+  bool     is_horizontal () const { return (coverage & Horizontal); }
 
   enum Coverage
   {
@@ -218,8 +227,8 @@
   static constexpr bool apple = true;
   typedef AAT::ObsoleteTypes Types;
 
-  unsigned int tuple_count () const { return 0; }
-  bool is_horizontal () const       { return !(coverage & Vertical); }
+  unsigned   tuple_count () const { return 0; }
+  bool     is_horizontal () const { return !(coverage & Vertical); }
 
   enum Coverage
   {
@@ -242,8 +251,8 @@
   HBUINT8       coverage;       /* Coverage bits. */
   HBUINT8       format;         /* Subtable format. */
   HBUINT16      tupleIndex;     /* The tuple index (used for variations fonts).
-                               * This value specifies which tuple this subtable covers.
-                               * Note: We don't implement. */
+                                 * This value specifies which tuple this subtable covers.
+                                 * Note: We don't implement. */
   public:
   DEFINE_SIZE_STATIC (8);
 };
@@ -271,14 +280,16 @@
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
 
-  bool has_data () const { return u.version32; }
-  unsigned int get_type () const { return u.major; }
+  bool     has_data () const { return u.version32; }
+  unsigned get_type () const { return u.major; }
 
   bool has_state_machine () const
   {
     switch (get_type ()) {
     case 0: return u.ot.has_state_machine ();
+#ifndef HB_NO_AAT_SHAPE
     case 1: return u.aat.has_state_machine ();
+#endif
     default:return false;
     }
   }
@@ -287,7 +298,9 @@
   {
     switch (get_type ()) {
     case 0: return u.ot.has_cross_stream ();
+#ifndef HB_NO_AAT_SHAPE
     case 1: return u.aat.has_cross_stream ();
+#endif
     default:return false;
     }
   }
@@ -296,7 +309,9 @@
   {
     switch (get_type ()) {
     case 0: return u.ot.get_h_kerning (left, right);
+#ifndef HB_NO_AAT_SHAPE
     case 1: return u.aat.get_h_kerning (left, right);
+#endif
     default:return 0;
     }
   }
@@ -304,14 +319,16 @@
   bool apply (AAT::hb_aat_apply_context_t *c) const
   { return dispatch (c); }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case 0:     return_trace (c->dispatch (u.ot));
-    case 1:     return_trace (c->dispatch (u.aat));
+    case 0:     return_trace (c->dispatch (u.ot, hb_forward<Ts> (ds)...));
+#ifndef HB_NO_AAT_SHAPE
+    case 1:     return_trace (c->dispatch (u.aat, hb_forward<Ts> (ds)...));
+#endif
     default:    return_trace (c->default_return_value ());
     }
   }
@@ -328,7 +345,9 @@
   HBUINT32              version32;
   HBUINT16              major;
   KernOT                ot;
+#ifndef HB_NO_AAT_SHAPE
   KernAAT               aat;
+#endif
   } u;
   public:
   DEFINE_SIZE_UNION (4, version32);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh
index fe30e27..f8cdb04 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh
@@ -1,7 +1,7 @@
 /*
- * Copyright © 2016 Elie Roux <elie.roux@telecom-bretagne.eu>
+ * Copyright © 2016  Elie Roux <elie.roux@telecom-bretagne.eu>
  * Copyright © 2018  Google, Inc.
- * Copyright © 2018  Ebrahim Byagowi
+ * Copyright © 2018-2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -32,9 +32,6 @@
 #include "hb-open-type.hh"
 #include "hb-ot-layout-common.hh"
 
-/* To be removed */
-typedef hb_tag_t hb_ot_layout_baseline_t;
-
 namespace OT {
 
 /*
@@ -76,7 +73,7 @@
   protected:
   HBUINT16      format;         /* Format identifier--format = 2 */
   FWORD         coordinate;     /* X or Y value, in design units */
-  GlyphID       referenceGlyph; /* Glyph ID of control glyph */
+  HBGlyphID     referenceGlyph; /* Glyph ID of control glyph */
   HBUINT16      coordPoint;     /* Index of contour point on the
                                  * reference glyph */
   public:
@@ -116,9 +113,11 @@
 
 struct BaseCoord
 {
-  hb_position_t get_coord (hb_font_t *font,
+  bool has_data () const { return u.format; }
+
+  hb_position_t get_coord (hb_font_t            *font,
                            const VariationStore &var_store,
-                           hb_direction_t direction) const
+                           hb_direction_t        direction) const
   {
     switch (u.format) {
     case 1: return u.format1.get_coord ();
@@ -142,10 +141,10 @@
 
   protected:
   union {
-    HBUINT16            format;
-    BaseCoordFormat1    format1;
-    BaseCoordFormat2    format2;
-    BaseCoordFormat3    format3;
+  HBUINT16              format;
+  BaseCoordFormat1      format1;
+  BaseCoordFormat2      format2;
+  BaseCoordFormat3      format3;
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
@@ -153,14 +152,9 @@
 
 struct FeatMinMaxRecord
 {
-  static int cmp (const void *key_, const void *entry_)
-  {
-    hb_tag_t key = * (hb_tag_t *) key_;
-    const FeatMinMaxRecord &entry = * (const FeatMinMaxRecord *) entry_;
-    return key < (unsigned int) entry.tag ? -1 :
-           key > (unsigned int) entry.tag ? 1 :
-           0;
-  }
+  int cmp (hb_tag_t key) const { return tag.cmp (key); }
+
+  bool has_data () const { return tag; }
 
   void get_min_max (const BaseCoord **min, const BaseCoord **max) const
   {
@@ -195,17 +189,12 @@
 struct MinMax
 {
   void get_min_max (hb_tag_t          feature_tag,
-                           const BaseCoord **min,
-                           const BaseCoord **max) const
+                    const BaseCoord **min,
+                    const BaseCoord **max) const
   {
-    /* TODO Replace hb_bsearch() with .bsearch(). */
-    const FeatMinMaxRecord *minMaxCoord = (const FeatMinMaxRecord *)
-                                          hb_bsearch (&feature_tag, featMinMaxRecords.arrayZ,
-                                                      featMinMaxRecords.len,
-                                                      FeatMinMaxRecord::static_size,
-                                                      FeatMinMaxRecord::cmp);
-    if (minMaxCoord)
-      minMaxCoord->get_min_max (min, max);
+    const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag);
+    if (minMaxCoord.has_data ())
+      minMaxCoord.get_min_max (min, max);
     else
     {
       if (likely (min)) *min = &(this+minCoord);
@@ -271,17 +260,11 @@
 
 struct BaseLangSysRecord
 {
-  static int cmp (const void *key_, const void *entry_)
-  {
-    hb_tag_t key = * (hb_tag_t *) key_;
-    const BaseLangSysRecord &entry = * (const BaseLangSysRecord *) entry_;
-    return key < (unsigned int) entry.baseLangSysTag ? -1 :
-           key > (unsigned int) entry.baseLangSysTag ? 1 :
-           0;
-  }
+  int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); }
 
-  const MinMax &get_min_max () const
-  { return this+minMax; }
+  bool has_data () const { return baseLangSysTag; }
+
+  const MinMax &get_min_max () const { return this+minMax; }
 
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
@@ -303,19 +286,14 @@
 {
   const MinMax &get_min_max (hb_tag_t language_tag) const
   {
-    /* TODO Replace hb_bsearch() with .bsearch(). */
-    const BaseLangSysRecord* record = (const BaseLangSysRecord *)
-                                      hb_bsearch (&language_tag, baseLangSysRecords.arrayZ,
-                                                  baseLangSysRecords.len,
-                                                  BaseLangSysRecord::static_size,
-                                                  BaseLangSysRecord::cmp);
-    return record ? record->get_min_max () : this+defaultMinMax;
+    const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag);
+    return record.has_data () ? record.get_min_max () : this+defaultMinMax;
   }
 
   const BaseCoord &get_base_coord (int baseline_tag_index) const
   { return (this+baseValues).get_base_coord (baseline_tag_index); }
 
-  bool is_empty () const { return !baseValues; }
+  bool has_data () const { return baseValues; }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -345,14 +323,9 @@
 struct BaseScriptList;
 struct BaseScriptRecord
 {
-  static int cmp (const void *key_, const void *entry_)
-  {
-    hb_tag_t key = * (hb_tag_t *) key_;
-    const BaseScriptRecord &entry = * (const BaseScriptRecord *) entry_;
-    return key < (unsigned int) entry.baseScriptTag ? -1 :
-           key > (unsigned int) entry.baseScriptTag ? 1 :
-           0;
-  }
+  int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); }
+
+  bool has_data () const { return baseScriptTag; }
 
   const BaseScript &get_base_script (const BaseScriptList *list) const
   { return list+baseScript; }
@@ -376,22 +349,11 @@
 
 struct BaseScriptList
 {
-  const BaseScriptRecord *find_record (hb_tag_t script) const
-  {
-    /* TODO Replace hb_bsearch() with .bsearch(). */
-    return (const BaseScriptRecord *) hb_bsearch (&script, baseScriptRecords.arrayZ,
-                                                  baseScriptRecords.len,
-                                                  BaseScriptRecord::static_size,
-                                                  BaseScriptRecord::cmp);
-  }
-
-  /* TODO: Or client should handle fallback? */
   const BaseScript &get_base_script (hb_tag_t script) const
   {
-    const BaseScriptRecord *record = find_record (script);
-    if (!record) record = find_record ((hb_script_t) HB_TAG ('D','F','L','T'));
-
-    return record ? record->get_base_script (this) : Null (BaseScript);
+    const BaseScriptRecord *record = &baseScriptRecords.bsearch (script);
+    if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T'));
+    return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -411,15 +373,20 @@
 
 struct Axis
 {
-  bool get_baseline (hb_ot_layout_baseline_t   baseline,
-                            hb_tag_t                  script_tag,
-                            hb_tag_t                  language_tag,
-                            const BaseCoord         **coord) const
+  bool get_baseline (hb_tag_t          baseline_tag,
+                     hb_tag_t          script_tag,
+                     hb_tag_t          language_tag,
+                     const BaseCoord **coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (base_script.is_empty ()) return false;
+    if (!base_script.has_data ()) return false;
 
-    if (likely (coord)) *coord = &base_script.get_base_coord ((this+baseTagList).bsearch (baseline));
+    if (likely (coord))
+    {
+      unsigned int tag_index = 0;
+      (this+baseTagList).bfind (baseline_tag, &tag_index);
+      *coord = &base_script.get_base_coord (tag_index);
+    }
 
     return true;
   }
@@ -431,7 +398,7 @@
                     const BaseCoord **max_coord) const
   {
     const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
-    if (base_script.is_empty ()) return false;
+    if (!base_script.has_data ()) return false;
 
     base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord);
 
@@ -447,7 +414,7 @@
   }
 
   protected:
-  OffsetTo<SortedArrayOf<Tag> >
+  OffsetTo<SortedArrayOf<Tag>>
                 baseTagList;    /* Offset to BaseTagList table, from beginning
                                  * of Axis table (may be NULL)
                                  * Array of 4-byte baseline identification tags — must
@@ -472,20 +439,21 @@
   const VariationStore &get_var_store () const
   { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; }
 
-  bool get_baseline (hb_font_t               *font,
-                     hb_ot_layout_baseline_t  baseline,
-                     hb_direction_t           direction,
-                     hb_tag_t                 script_tag,
-                     hb_tag_t                 language_tag,
-                     hb_position_t           *base) const
+  bool get_baseline (hb_font_t      *font,
+                     hb_tag_t        baseline_tag,
+                     hb_direction_t  direction,
+                     hb_tag_t        script_tag,
+                     hb_tag_t        language_tag,
+                     hb_position_t  *base) const
   {
-    const BaseCoord *base_coord;
-    if (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord))
+    const BaseCoord *base_coord = nullptr;
+    if (unlikely (!get_axis (direction).get_baseline (baseline_tag, script_tag, language_tag, &base_coord) ||
+                  !base_coord || !base_coord->has_data ()))
       return false;
 
-    if (likely (base && base_coord)) *base = base_coord->get_coord (font,
-                                                                    get_var_store (),
-                                                                    direction);
+    if (likely (base))
+      *base = base_coord->get_coord (font, get_var_store (), direction);
+
     return true;
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh
index 7618057..56773e6 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh
@@ -33,6 +33,7 @@
 #include "hb-ot-layout.hh"
 #include "hb-open-type.hh"
 #include "hb-set.hh"
+#include "hb-bimap.hh"
 
 
 #ifndef HB_MAX_NESTING_LEVEL
@@ -59,6 +60,18 @@
 #define HB_MAX_LANGSYS  2000
 #endif
 
+#ifndef HB_MAX_FEATURES
+#define HB_MAX_FEATURES 750
+#endif
+
+#ifndef HB_MAX_FEATURE_INDICES
+#define HB_MAX_FEATURE_INDICES  1500
+#endif
+
+#ifndef HB_MAX_LOOKUP_INDICES
+#define HB_MAX_LOOKUP_INDICES   20000
+#endif
+
 
 namespace OT {
 
@@ -66,6 +79,213 @@
 #define NOT_COVERED             ((unsigned int) -1)
 
 
+template<typename Iterator>
+static inline void Coverage_serialize (hb_serialize_context_t *c,
+                                       Iterator it);
+
+template<typename Iterator>
+static inline void ClassDef_serialize (hb_serialize_context_t *c,
+                                       Iterator it);
+
+static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
+                                          const hb_set_t &glyphset,
+                                          const hb_map_t &gid_klass_map,
+                                          hb_sorted_vector_t<HBGlyphID> &glyphs,
+                                          const hb_set_t &klasses,
+                                          hb_map_t *klass_map /*INOUT*/);
+
+struct hb_subset_layout_context_t :
+  hb_dispatch_context_t<hb_subset_layout_context_t, hb_empty_t, HB_DEBUG_SUBSET>
+{
+  const char *get_name () { return "SUBSET_LAYOUT"; }
+  static return_t default_return_value () { return hb_empty_t (); }
+
+  bool visitScript ()
+  {
+    return script_count++ < HB_MAX_SCRIPTS;
+  }
+
+  bool visitLangSys ()
+  {
+    return langsys_count++ < HB_MAX_LANGSYS;
+  }
+
+  bool visitFeatureIndex (int count)
+  {
+    feature_index_count += count;
+    return feature_index_count < HB_MAX_FEATURE_INDICES;
+  }
+
+  bool visitLookupIndex()
+  {
+    lookup_index_count++;
+    return lookup_index_count < HB_MAX_LOOKUP_INDICES;
+  }
+
+  hb_subset_context_t *subset_context;
+  const hb_tag_t table_tag;
+  const hb_map_t *lookup_index_map;
+  const hb_map_t *feature_index_map;
+
+  hb_subset_layout_context_t (hb_subset_context_t *c_,
+                              hb_tag_t tag_,
+                              hb_map_t *lookup_map_,
+                              hb_map_t *feature_map_) :
+                                subset_context (c_),
+                                table_tag (tag_),
+                                lookup_index_map (lookup_map_),
+                                feature_index_map (feature_map_),
+                                script_count (0),
+                                langsys_count (0),
+                                feature_index_count (0),
+                                lookup_index_count (0)
+  {}
+
+  private:
+  unsigned script_count;
+  unsigned langsys_count;
+  unsigned feature_index_count;
+  unsigned lookup_index_count;
+};
+
+struct hb_collect_variation_indices_context_t :
+       hb_dispatch_context_t<hb_collect_variation_indices_context_t>
+{
+  template <typename T>
+  return_t dispatch (const T &obj) { obj.collect_variation_indices (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
+
+  hb_set_t *layout_variation_indices;
+  const hb_set_t *glyph_set;
+  const hb_map_t *gpos_lookups;
+
+  hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
+                                          const hb_set_t *glyph_set_,
+                                          const hb_map_t *gpos_lookups_) :
+                                        layout_variation_indices (layout_variation_indices_),
+                                        glyph_set (glyph_set_),
+                                        gpos_lookups (gpos_lookups_) {}
+};
+
+template<typename OutputArray>
+struct subset_offset_array_t
+{
+  subset_offset_array_t (hb_subset_context_t *subset_context_,
+                         OutputArray& out_,
+                         const void *base_) : subset_context (subset_context_),
+                                              out (out_), base (base_) {}
+
+  template <typename T>
+  bool operator () (T&& offset)
+  {
+    auto *o = out.serialize_append (subset_context->serializer);
+    if (unlikely (!o)) return false;
+    auto snap = subset_context->serializer->snapshot ();
+    bool ret = o->serialize_subset (subset_context, offset, base);
+    if (!ret)
+    {
+      out.pop ();
+      subset_context->serializer->revert (snap);
+    }
+    return ret;
+  }
+
+  private:
+  hb_subset_context_t *subset_context;
+  OutputArray &out;
+  const void *base;
+};
+
+
+template<typename OutputArray, typename Arg>
+struct subset_offset_array_arg_t
+{
+  subset_offset_array_arg_t (hb_subset_context_t *subset_context_,
+                             OutputArray& out_,
+                             const void *base_,
+                             Arg &&arg_) : subset_context (subset_context_), out (out_),
+                                          base (base_), arg (arg_) {}
+
+  template <typename T>
+  bool operator () (T&& offset)
+  {
+    auto *o = out.serialize_append (subset_context->serializer);
+    if (unlikely (!o)) return false;
+    auto snap = subset_context->serializer->snapshot ();
+    bool ret = o->serialize_subset (subset_context, offset, base, arg);
+    if (!ret)
+    {
+      out.pop ();
+      subset_context->serializer->revert (snap);
+    }
+    return ret;
+  }
+
+  private:
+  hb_subset_context_t *subset_context;
+  OutputArray &out;
+  const void *base;
+  Arg &&arg;
+};
+
+/*
+ * Helper to subset an array of offsets. Subsets the thing pointed to by each offset
+ * and discards the offset in the array if the subset operation results in an empty
+ * thing.
+ */
+struct
+{
+  template<typename OutputArray>
+  subset_offset_array_t<OutputArray>
+  operator () (hb_subset_context_t *subset_context, OutputArray& out,
+               const void *base) const
+  { return subset_offset_array_t<OutputArray> (subset_context, out, base); }
+
+  /* Variant with one extra argument passed to serialize_subset */
+  template<typename OutputArray, typename Arg>
+  subset_offset_array_arg_t<OutputArray, Arg>
+  operator () (hb_subset_context_t *subset_context, OutputArray& out,
+               const void *base, Arg &&arg) const
+  { return subset_offset_array_arg_t<OutputArray, Arg> (subset_context, out, base, arg); }
+}
+HB_FUNCOBJ (subset_offset_array);
+
+template<typename OutputArray>
+struct subset_record_array_t
+{
+  subset_record_array_t (hb_subset_layout_context_t *c_, OutputArray* out_,
+                         const void *base_) : subset_layout_context (c_),
+                                              out (out_), base (base_) {}
+
+  template <typename T>
+  void
+  operator () (T&& record)
+  {
+    auto snap = subset_layout_context->subset_context->serializer->snapshot ();
+    bool ret = record.subset (subset_layout_context, base);
+    if (!ret) subset_layout_context->subset_context->serializer->revert (snap);
+    else out->len++;
+  }
+
+  private:
+  hb_subset_layout_context_t *subset_layout_context;
+  OutputArray *out;
+  const void *base;
+};
+
+/*
+ * Helper to subset a RecordList/record array. Subsets each Record in the array and
+ * discards the record if the subset operation returns false.
+ */
+struct
+{
+  template<typename OutputArray>
+  subset_record_array_t<OutputArray>
+  operator () (hb_subset_layout_context_t *c, OutputArray* out,
+               const void *base) const
+  { return subset_record_array_t<OutputArray> (c, out, base); }
+}
+HB_FUNCOBJ (subset_record_array);
 
 /*
  *
@@ -88,6 +308,15 @@
 {
   int cmp (hb_tag_t a) const { return tag.cmp (a); }
 
+  bool subset (hb_subset_layout_context_t *c, const void *base) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->subset_context->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag);
+    return_trace (ret);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -104,7 +333,7 @@
 };
 
 template <typename Type>
-struct RecordArrayOf : SortedArrayOf<Record<Type> >
+struct RecordArrayOf : SortedArrayOf<Record<Type>>
 {
   const OffsetTo<Type>& get_offset (unsigned int i) const
   { return (*this)[i].offset; }
@@ -116,11 +345,12 @@
                          unsigned int *record_count /* IN/OUT */,
                          hb_tag_t     *record_tags /* OUT */) const
   {
-    if (record_count) {
-      const Record<Type> *arr = this->sub_array (start_offset, record_count);
-      unsigned int count = *record_count;
-      for (unsigned int i = 0; i < count; i++)
-        record_tags[i] = arr[i].tag;
+    if (record_count)
+    {
+      + this->sub_array (start_offset, record_count)
+      | hb_map (&Record<Type>::tag)
+      | hb_sink (hb_array (record_tags, *record_count))
+      ;
     }
     return this->len;
   }
@@ -136,14 +366,16 @@
   const Type& operator [] (unsigned int i) const
   { return this+this->get_offset (i); }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               hb_subset_layout_context_t *l) const
   {
     TRACE_SUBSET (this);
-    struct RecordListOf<Type> *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-    unsigned int count = this->len;
-    for (unsigned int i = 0; i < count; i++)
-      out->get_offset (i).serialize_subset (c, (*this)[i], out);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + this->iter ()
+    | hb_apply (subset_record_array (l, out, this))
+    ;
     return_trace (true);
   }
 
@@ -154,11 +386,31 @@
   }
 };
 
+struct Feature;
+
+struct RecordListOfFeature : RecordListOf<Feature>
+{
+  bool subset (hb_subset_context_t *c,
+               hb_subset_layout_context_t *l) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    unsigned count = this->len;
+    + hb_zip (*this, hb_range (count))
+    | hb_filter (l->feature_index_map, hb_second)
+    | hb_map (hb_first)
+    | hb_apply (subset_record_array (l, out, this))
+    ;
+    return_trace (true);
+  }
+};
 
 struct RangeRecord
 {
   int cmp (hb_codepoint_t g) const
-  { return g < start ? -1 : g <= end ? 0 : +1; }
+  { return g < first ? -1 : g <= last ? 0 : +1; }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -167,14 +419,14 @@
   }
 
   bool intersects (const hb_set_t *glyphs) const
-  { return glyphs->intersects (start, end); }
+  { return glyphs->intersects (first, last); }
 
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
-  { return glyphs->add_range (start, end); }
+  bool collect_coverage (set_t *glyphs) const
+  { return glyphs->add_range (first, last); }
 
-  GlyphID       start;          /* First GlyphID in the range */
-  GlyphID       end;            /* Last GlyphID in the range */
+  HBGlyphID     first;          /* First GlyphID in the range */
+  HBGlyphID     last;           /* Last GlyphID in the range */
   HBUINT16      value;          /* Value */
   public:
   DEFINE_SIZE_STATIC (6);
@@ -184,15 +436,38 @@
 
 struct IndexArray : ArrayOf<Index>
 {
+  bool intersects (const hb_map_t *indexes) const
+  { return hb_any (*this, indexes); }
+
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  hb_subset_layout_context_t *l,
+                  Iterator it)
+  {
+    if (!it) return;
+    if (unlikely (!c->extend_min ((*this)))) return;
+
+    for (const auto _ : it)
+    {
+      if (!l->visitLookupIndex()) break;
+
+      Index i;
+      i = _;
+      c->copy (i);
+      this->len++;
+    }
+  }
+
   unsigned int get_indexes (unsigned int start_offset,
                             unsigned int *_count /* IN/OUT */,
                             unsigned int *_indexes /* OUT */) const
   {
-    if (_count) {
-      const HBUINT16 *arr = this->sub_array (start_offset, _count);
-      unsigned int count = *_count;
-      for (unsigned int i = 0; i < count; i++)
-        _indexes[i] = arr[i];
+    if (_count)
+    {
+      + this->sub_array (start_offset, _count)
+      | hb_sink (hb_array (_indexes, *_count))
+      ;
     }
     return this->len;
   }
@@ -204,11 +479,6 @@
 };
 
 
-struct Script;
-struct LangSys;
-struct Feature;
-
-
 struct LangSys
 {
   unsigned int get_feature_count () const
@@ -227,13 +497,49 @@
   {
     if (reqFeatureIndex == 0xFFFFu)
       return Index::NOT_FOUND_INDEX;
-   return reqFeatureIndex;;
+   return reqFeatureIndex;
   }
 
-  bool subset (hb_subset_context_t *c) const
+  LangSys* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed (*this));
+  }
+
+  bool operator == (const LangSys& o) const
+  {
+    if (featureIndex.len != o.featureIndex.len ||
+        reqFeatureIndex != o.reqFeatureIndex)
+      return false;
+
+    for (const auto _ : + hb_zip (featureIndex, o.featureIndex))
+      if (_.first != _.second) return false;
+
+    return true;
+  }
+
+  bool subset (hb_subset_context_t        *c,
+               hb_subset_layout_context_t *l,
+               const Tag                  *tag = nullptr) const
   {
     TRACE_SUBSET (this);
-    return_trace (c->serializer->embed (*this));
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex) ? l->feature_index_map->get (reqFeatureIndex) : 0xFFFFu;
+
+    if (!l->visitFeatureIndex (featureIndex.len))
+      return_trace (false);
+
+    auto it =
+    + hb_iter (featureIndex)
+    | hb_filter (l->feature_index_map)
+    | hb_map (l->feature_index_map)
+    ;
+
+    bool ret = bool (it);
+    out->featureIndex.serialize (c->serializer, l, it);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c,
@@ -275,16 +581,46 @@
   bool has_default_lang_sys () const           { return defaultLangSys != 0; }
   const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t         *c,
+               hb_subset_layout_context_t  *l,
+               const Tag                   *tag) const
   {
     TRACE_SUBSET (this);
-    struct Script *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-    out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
-    unsigned int count = langSys.len;
-    for (unsigned int i = 0; i < count; i++)
-      out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
-    return_trace (true);
+    if (!l->visitScript ()) return_trace (false);
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    bool defaultLang = false;
+    if (has_default_lang_sys ())
+    {
+      c->serializer->push ();
+      const LangSys& ls = this+defaultLangSys;
+      bool ret = ls.subset (c, l);
+      if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T'))
+      {
+        c->serializer->pop_discard ();
+        out->defaultLangSys = 0;
+      }
+      else
+      {
+        c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ());
+        defaultLang = true;
+      }
+    }
+
+    + langSys.iter ()
+    | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
+    | hb_filter ([&] (const Record<LangSys>& record)
+                 {
+                   const LangSys& d = this+defaultLangSys;
+                   const LangSys& l = this+record.offset;
+                   return !(l == d);
+                 })
+    | hb_apply (subset_record_array (l, &(out->langSys), this))
+    ;
+
+    return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB);
   }
 
   bool sanitize (hb_sanitize_context_t *c,
@@ -381,6 +717,12 @@
       return_trace (true);
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace ((bool) c->serializer->embed (*this));
+  }
+
   HBUINT16      designSize;     /* Represents the design size in 720/inch
                                  * units (decipoints).  The design size entry
                                  * must be non-zero.  When there is a design
@@ -431,6 +773,12 @@
     return_trace (c->check_struct (this));
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace ((bool) c->serializer->embed (*this));
+  }
+
   HBUINT16      version;        /* (set to 0): This corresponds to a “minor”
                                  * version number. Additional data may be
                                  * added to the end of this Feature Parameters
@@ -457,6 +805,27 @@
 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
 struct FeatureParamsCharacterVariants
 {
+  unsigned
+  get_characters (unsigned start_offset, unsigned *char_count, hb_codepoint_t *chars) const
+  {
+    if (char_count)
+    {
+      + characters.sub_array (start_offset, char_count)
+      | hb_sink (hb_array (chars, *char_count))
+      ;
+    }
+    return characters.len;
+  }
+
+  unsigned get_size () const
+  { return min_size + characters.len * HBUINT24::static_size; }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace ((bool) c->serializer->embed (*this));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -500,6 +869,9 @@
 {
   bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
   {
+#ifdef HB_NO_LAYOUT_FEATURE_PARAMS
+    return true;
+#endif
     TRACE_SANITIZE (this);
     if (tag == HB_TAG ('s','i','z','e'))
       return_trace (u.size.sanitize (c));
@@ -510,26 +882,39 @@
     return_trace (true);
   }
 
+  bool subset (hb_subset_context_t *c, const Tag* tag) const
+  {
+    TRACE_SUBSET (this);
+    if (!tag) return_trace (false);
+    if (*tag == HB_TAG ('s','i','z','e'))
+      return_trace (u.size.subset (c));
+    if ((*tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+      return_trace (u.stylisticSet.subset (c));
+    if ((*tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+      return_trace (u.characterVariants.subset (c));
+    return_trace (false);
+  }
+
+#ifndef HB_NO_LAYOUT_FEATURE_PARAMS
   const FeatureParamsSize& get_size_params (hb_tag_t tag) const
   {
     if (tag == HB_TAG ('s','i','z','e'))
       return u.size;
     return Null (FeatureParamsSize);
   }
-
   const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const
   {
     if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
       return u.stylisticSet;
     return Null (FeatureParamsStylisticSet);
   }
-
   const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const
   {
     if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
       return u.characterVariants;
     return Null (FeatureParamsCharacterVariants);
   }
+#endif
 
   private:
   union {
@@ -538,7 +923,7 @@
   FeatureParamsCharacterVariants        characterVariants;
   } u;
   public:
-  DEFINE_SIZE_STATIC (17);
+  DEFINE_SIZE_MIN (0);
 };
 
 struct Feature
@@ -557,13 +942,28 @@
   const FeatureParams &get_feature_params () const
   { return this+featureParams; }
 
-  bool subset (hb_subset_context_t *c) const
+  bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const
+  { return lookupIndex.intersects (lookup_indexes); }
+
+  bool subset (hb_subset_context_t         *c,
+               hb_subset_layout_context_t  *l,
+               const Tag                   *tag = nullptr) const
   {
     TRACE_SUBSET (this);
-    struct Feature *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
-    out->featureParams.set (0); /* TODO(subset) FeatureParams. */
-    return_trace (true);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    bool subset_featureParams = out->featureParams.serialize_subset (c, featureParams, this, tag);
+
+    auto it =
+    + hb_iter (lookupIndex)
+    | hb_filter (l->lookup_index_map)
+    | hb_map (l->lookup_index_map)
+    ;
+
+    out->lookupIndex.serialize (c->serializer, l, it);
+    return_trace (bool (it) || subset_featureParams
+                  || (tag && *tag == HB_TAG ('p', 'r', 'e', 'f')));
   }
 
   bool sanitize (hb_sanitize_context_t *c,
@@ -584,25 +984,25 @@
      * Adobe tools, only the 'size' feature had FeatureParams defined.
      */
 
-    OffsetTo<FeatureParams> orig_offset = featureParams;
+    if (likely (featureParams.is_null ()))
+      return_trace (true);
+
+    unsigned int orig_offset = featureParams;
     if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
       return_trace (false);
 
-    if (likely (orig_offset.is_null ()))
-      return_trace (true);
-
     if (featureParams == 0 && closure &&
         closure->tag == HB_TAG ('s','i','z','e') &&
         closure->list_base && closure->list_base < this)
     {
-      unsigned int new_offset_int = (unsigned int) orig_offset -
+      unsigned int new_offset_int = orig_offset -
                                     (((char *) this) - ((char *) closure->list_base));
 
       OffsetTo<FeatureParams> new_offset;
-      /* Check that it did not overflow. */
-      new_offset.set (new_offset_int);
+      /* Check that it would not overflow. */
+      new_offset = new_offset_int;
       if (new_offset == new_offset_int &&
-          c->try_set (&featureParams, new_offset) &&
+          c->try_set (&featureParams, new_offset_int) &&
           !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
         return_trace (false);
     }
@@ -649,15 +1049,18 @@
   unsigned int get_subtable_count () const { return subTable.len; }
 
   template <typename TSubTable>
-  const TSubTable& get_subtable (unsigned int i) const
-  { return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
-
-  template <typename TSubTable>
   const OffsetArrayOf<TSubTable>& get_subtables () const
-  { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
+  { return reinterpret_cast<const OffsetArrayOf<TSubTable> &> (subTable); }
   template <typename TSubTable>
   OffsetArrayOf<TSubTable>& get_subtables ()
-  { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
+  { return reinterpret_cast<OffsetArrayOf<TSubTable> &> (subTable); }
+
+  template <typename TSubTable>
+  const TSubTable& get_subtable (unsigned int i) const
+  { return this+get_subtables<TSubTable> ()[i]; }
+  template <typename TSubTable>
+  TSubTable& get_subtable (unsigned int i)
+  { return this+get_subtables<TSubTable> ()[i]; }
 
   unsigned int get_size () const
   {
@@ -683,14 +1086,14 @@
     return flag;
   }
 
-  template <typename TSubTable, typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename TSubTable, typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     unsigned int lookup_type = get_type ();
     TRACE_DISPATCH (this, lookup_type);
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
-      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
+      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, hb_forward<Ts> (ds)...);
       if (c->stop_sublookup_iteration (r))
         return_trace (r);
     }
@@ -704,95 +1107,73 @@
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
-    lookupType.set (lookup_type);
-    lookupFlag.set (lookup_props & 0xFFFFu);
+    lookupType = lookup_type;
+    lookupFlag = lookup_props & 0xFFFFu;
     if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
       if (unlikely (!c->extend (*this))) return_trace (false);
       HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
-      markFilteringSet.set (lookup_props >> 16);
+      markFilteringSet = lookup_props >> 16;
     }
     return_trace (true);
   }
 
-  /* Older compilers need this to NOT be locally defined in a function. */
-  template <typename TSubTable>
-  struct SubTableSubsetWrapper
-  {
-    SubTableSubsetWrapper (const TSubTable &subtable_,
-                           unsigned int lookup_type_) :
-                             subtable (subtable_),
-                             lookup_type (lookup_type_) {}
-
-    bool subset (hb_subset_context_t *c) const
-    { return subtable.dispatch (c, lookup_type); }
-
-    private:
-    const TSubTable &subtable;
-    unsigned int lookup_type;
-  };
-
   template <typename TSubTable>
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct Lookup *out = c->serializer->embed (*this);
-    if (unlikely (!out)) return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+    out->lookupType = lookupType;
+    out->lookupFlag = lookupFlag;
 
-    /* Subset the actual subtables. */
-    /* TODO Drop empty ones, either by calling intersects() beforehand,
-     * or just dropping null offsets after. */
-    const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
-    OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
-    unsigned int count = subTable.len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ());
-
-      out_subtables[i].serialize_subset (c, wrapper, out);
-    }
+    const hb_set_t *glyphset = c->plan->glyphset ();
+    unsigned int lookup_type = get_type ();
+    + hb_iter (get_subtables <TSubTable> ())
+    | hb_filter ([this, glyphset, lookup_type] (const OffsetTo<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); })
+    | hb_apply (subset_offset_array (c, out->get_subtables<TSubTable> (), this, lookup_type))
+    ;
 
     return_trace (true);
   }
 
-  /* Older compilers need this to NOT be locally defined in a function. */
-  template <typename TSubTable>
-  struct SubTableSanitizeWrapper : TSubTable
-  {
-    bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) const
-    { return this->dispatch (c, lookup_type); }
-  };
-
   template <typename TSubTable>
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
+
+    unsigned subtables = get_subtable_count ();
+    if (unlikely (!c->visit_subtables (subtables))) return_trace (false);
+
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
       const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
       if (!markFilteringSet.sanitize (c)) return_trace (false);
     }
 
-    if (unlikely (!CastR<OffsetArrayOf<SubTableSanitizeWrapper<TSubTable> > > (subTable)
-                   .sanitize (c, this, get_type ())))
+    if (unlikely (!get_subtables<TSubTable> ().sanitize (c, this, get_type ())))
       return_trace (false);
 
-    if (unlikely (get_type () == TSubTable::Extension))
+    if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
     {
       /* The spec says all subtables of an Extension lookup should
        * have the same type, which shall not be the Extension type
        * itself (but we already checked for that).
-       * This is specially important if one has a reverse type! */
+       * This is specially important if one has a reverse type!
+       *
+       * We only do this if sanitizer edit_count is zero.  Otherwise,
+       * some of the subtables might have become insane after they
+       * were sanity-checked by the edits of subsequent subtables.
+       * https://bugs.chromium.org/p/chromium/issues/detail?id=960331
+       */
       unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
-      unsigned int count = get_subtable_count ();
-      for (unsigned int i = 1; i < count; i++)
+      for (unsigned int i = 1; i < subtables; i++)
         if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
           return_trace (false);
     }
     return_trace (true);
-    return_trace (true);
   }
 
   private:
@@ -800,7 +1181,7 @@
   HBUINT16      lookupFlag;             /* Lookup qualifiers */
   ArrayOf<Offset16>
                 subTable;               /* Array of SubTables */
-/*HBUINT16      markFilteringSetX[VAR];*//* Index (base 0) into GDEF mark glyph sets
+/*HBUINT16      markFilteringSetX[HB_VAR_ARRAY];*//* Index (base 0) into GDEF mark glyph sets
                                          * structure. This field is only present if bit
                                          * UseMarkFilteringSet of lookup flags is set. */
   public:
@@ -809,6 +1190,32 @@
 
 typedef OffsetListOf<Lookup> LookupList;
 
+template <typename TLookup>
+struct LookupOffsetList : OffsetListOf<TLookup>
+{
+  bool subset (hb_subset_context_t        *c,
+               hb_subset_layout_context_t *l) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    unsigned count = this->len;
+    + hb_zip (*this, hb_range (count))
+    | hb_filter (l->lookup_index_map, hb_second)
+    | hb_map (hb_first)
+    | hb_apply (subset_offset_array (c, *out, this))
+    ;
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (OffsetListOf<TLookup>::sanitize (c, this));
+  }
+};
+
 
 /*
  * Coverage Table
@@ -826,8 +1233,9 @@
     return i;
   }
 
-  bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs)
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
     return_trace (glyphArray.serialize (c, glyphs));
@@ -852,20 +1260,20 @@
   { return glyphs->has (glyphArray[index]); }
 
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
-  {
-    return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len);
-  }
+  bool collect_coverage (set_t *glyphs) const
+  { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); }
 
   public:
   /* Older compilers need this to be public. */
-  struct Iter {
+  struct iter_t
+  {
     void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }
     void fini () {}
-    bool more () { return i < c->glyphArray.len; }
+    bool more () const { return i < c->glyphArray.len; }
     void next () { i++; }
-    hb_codepoint_t get_glyph () { return c->glyphArray[i]; }
-    unsigned int get_coverage () { return i; }
+    hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
+    bool operator != (const iter_t& o) const
+    { return i != o.i || c != o.c; }
 
     private:
     const struct CoverageFormat1 *c;
@@ -875,7 +1283,7 @@
 
   protected:
   HBUINT16      coverageFormat; /* Format identifier--format = 1 */
-  SortedArrayOf<GlyphID>
+  SortedArrayOf<HBGlyphID>
                 glyphArray;     /* Array of GlyphIDs--in numerical order */
   public:
   DEFINE_SIZE_ARRAY (4, glyphArray);
@@ -889,43 +1297,53 @@
   unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     const RangeRecord &range = rangeRecord.bsearch (glyph_id);
-    return likely (range.start <= range.end) ?
-           (unsigned int) range.value + (glyph_id - range.start) :
-           NOT_COVERED;
+    return likely (range.first <= range.last)
+         ? (unsigned int) range.value + (glyph_id - range.first)
+         : NOT_COVERED;
   }
 
-  bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs)
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    if (unlikely (!glyphs.length))
+    if (unlikely (!glyphs))
     {
-      rangeRecord.len.set (0);
+      rangeRecord.len = 0;
       return_trace (true);
     }
 
-    unsigned int num_ranges = 1;
-    for (unsigned int i = 1; i < glyphs.length; i++)
-      if (glyphs[i - 1] + 1 != glyphs[i])
-        num_ranges++;
-    rangeRecord.len.set (num_ranges);
-    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
+    /* TODO(iter) Write more efficiently? */
 
-    unsigned int range = 0;
-    rangeRecord[range].start = glyphs[0];
-    rangeRecord[range].value.set (0);
-    for (unsigned int i = 1; i < glyphs.length; i++)
+    unsigned num_ranges = 0;
+    hb_codepoint_t last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
     {
-      if (glyphs[i - 1] + 1 != glyphs[i])
+      if (last + 1 != g)
+        num_ranges++;
+      last = g;
+    }
+
+    if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
+
+    unsigned count = 0;
+    unsigned range = (unsigned) -1;
+    last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
+    {
+      if (last + 1 != g)
       {
         range++;
-        rangeRecord[range].start = glyphs[i];
-        rangeRecord[range].value.set (i);
+        rangeRecord[range].first = g;
+        rangeRecord[range].value = count;
       }
-      rangeRecord[range].end = glyphs[i];
+      rangeRecord[range].last = g;
+      last = g;
+      count++;
     }
+
     return_trace (true);
   }
 
@@ -951,7 +1369,7 @@
     for (i = 0; i < count; i++) {
       const RangeRecord &range = rangeRecord[i];
       if (range.value <= index &&
-          index < (unsigned int) range.value + (range.end - range.start) &&
+          index < (unsigned int) range.value + (range.last - range.first) &&
           range.intersects (glyphs))
         return true;
       else if (index < range.value)
@@ -961,57 +1379,61 @@
   }
 
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
+  bool collect_coverage (set_t *glyphs) const
   {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
+      if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
         return false;
     return true;
   }
 
   public:
   /* Older compilers need this to be public. */
-  struct Iter
+  struct iter_t
   {
     void init (const CoverageFormat2 &c_)
     {
       c = &c_;
       coverage = 0;
       i = 0;
-      j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
-      if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
+      j = c->rangeRecord.len ? c->rangeRecord[0].first : 0;
+      if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last))
       {
         /* Broken table. Skip. */
         i = c->rangeRecord.len;
       }
     }
     void fini () {}
-    bool more () { return i < c->rangeRecord.len; }
+    bool more () const { return i < c->rangeRecord.len; }
     void next ()
     {
-      if (j >= c->rangeRecord[i].end)
+      if (j >= c->rangeRecord[i].last)
       {
         i++;
         if (more ())
         {
-          hb_codepoint_t old = j;
-          j = c->rangeRecord[i].start;
-          if (unlikely (j <= old))
+          unsigned int old = coverage;
+          j = c->rangeRecord[i].first;
+          coverage = c->rangeRecord[i].value;
+          if (unlikely (coverage != old + 1))
           {
-            /* Broken table. Skip. Important to avoid DoS. */
+            /* Broken table. Skip. Important to avoid DoS.
+             * Also, our callers depend on coverage being
+             * consecutive and monotonically increasing,
+             * ie. iota(). */
            i = c->rangeRecord.len;
            return;
           }
-          coverage = c->rangeRecord[i].value;
         }
         return;
       }
       coverage++;
       j++;
     }
-    hb_codepoint_t get_glyph () { return j; }
-    unsigned int get_coverage () { return coverage; }
+    hb_codepoint_t get_glyph () const { return j; }
+    bool operator != (const iter_t& o) const
+    { return i != o.i || j != o.j || c != o.c; }
 
     private:
     const struct CoverageFormat2 *c;
@@ -1032,6 +1454,15 @@
 
 struct Coverage
 {
+  /* Has interface. */
+  static constexpr unsigned SENTINEL = NOT_COVERED;
+  typedef unsigned int value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Predicate. */
+  bool operator () (hb_codepoint_t k) const { return has (k); }
+
+  unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
   unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
@@ -1041,17 +1472,24 @@
     }
   }
 
-  bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs)
+  template <typename Iterator,
+      hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
+  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    unsigned int num_ranges = 1;
-    for (unsigned int i = 1; i < glyphs.length; i++)
-      if (glyphs[i - 1] + 1 != glyphs[i])
+    unsigned count = 0;
+    unsigned num_ranges = 0;
+    hb_codepoint_t last = (hb_codepoint_t) -2;
+    for (auto g: glyphs)
+    {
+      if (last + 1 != g)
         num_ranges++;
-    u.format.set (glyphs.length * 2 < num_ranges * 3 ? 1 : 2);
+      last = g;
+      count++;
+    }
+    u.format = count <= num_ranges * 3 ? 1 : 2;
 
     switch (u.format)
     {
@@ -1061,6 +1499,23 @@
     }
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + iter ()
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    bool ret = bool (it);
+    Coverage_serialize (c->serializer, it);
+    return_trace (ret);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1095,19 +1550,20 @@
   /* Might return false if array looks unsorted.
    * Used for faster rejection of corrupt data. */
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
+  bool collect_coverage (set_t *glyphs) const
   {
     switch (u.format)
     {
-    case 1: return u.format1.add_coverage (glyphs);
-    case 2: return u.format2.add_coverage (glyphs);
+    case 1: return u.format1.collect_coverage (glyphs);
+    case 2: return u.format2.collect_coverage (glyphs);
     default:return false;
     }
   }
 
-  struct Iter
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
   {
-    Iter (const Coverage &c_)
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const Coverage &c_ = Null (Coverage))
     {
       memset (this, 0, sizeof (*this));
       format = c_.u.format;
@@ -1118,7 +1574,7 @@
       default:                               return;
       }
     }
-    bool more ()
+    bool __more__ () const
     {
       switch (format)
       {
@@ -1127,7 +1583,7 @@
       default:return false;
       }
     }
-    void next ()
+    void __next__ ()
     {
       switch (format)
       {
@@ -1136,7 +1592,10 @@
       default:                   break;
       }
     }
-    hb_codepoint_t get_glyph ()
+    typedef hb_codepoint_t __item_t__;
+    __item_t__ __item__ () const { return get_glyph (); }
+
+    hb_codepoint_t get_glyph () const
     {
       switch (format)
       {
@@ -1145,23 +1604,25 @@
       default:return 0;
       }
     }
-    unsigned int get_coverage ()
+    bool operator != (const iter_t& o) const
     {
+      if (format != o.format) return true;
       switch (format)
       {
-      case 1: return u.format1.get_coverage ();
-      case 2: return u.format2.get_coverage ();
-      default:return -1;
+      case 1: return u.format1 != o.u.format1;
+      case 2: return u.format2 != o.u.format2;
+      default:return false;
       }
     }
 
     private:
     unsigned int format;
     union {
-    CoverageFormat2::Iter       format2; /* Put this one first since it's larger; helps shut up compiler. */
-    CoverageFormat1::Iter       format1;
+    CoverageFormat2::iter_t     format2; /* Put this one first since it's larger; helps shut up compiler. */
+    CoverageFormat1::iter_t     format1;
     } u;
   };
+  iter_t iter () const { return iter_t (*this); }
 
   protected:
   union {
@@ -1173,15 +1634,56 @@
   DEFINE_SIZE_UNION (2, format);
 };
 
+template<typename Iterator>
+static inline void
+Coverage_serialize (hb_serialize_context_t *c,
+                    Iterator it)
+{ c->start_embed<Coverage> ()->serialize (c, it); }
+
+static void ClassDef_remap_and_serialize (hb_serialize_context_t *c,
+                                          const hb_set_t &glyphset,
+                                          const hb_map_t &gid_klass_map,
+                                          hb_sorted_vector_t<HBGlyphID> &glyphs,
+                                          const hb_set_t &klasses,
+                                          hb_map_t *klass_map /*INOUT*/)
+{
+  if (!klass_map)
+  {
+    ClassDef_serialize (c, hb_zip (glyphs.iter (), + glyphs.iter ()
+                                                   | hb_map (gid_klass_map)));
+    return;
+  }
+
+  /* any glyph not assigned a class value falls into Class zero (0),
+   * if any glyph assigned to class 0, remapping must start with 0->0*/
+  if (glyphset.get_population () > gid_klass_map.get_population ())
+    klass_map->set (0, 0);
+
+  unsigned idx = klass_map->has (0) ? 1 : 0;
+  for (const unsigned k: klasses.iter ())
+  {
+    if (klass_map->has (k)) continue;
+    klass_map->set (k, idx);
+    idx++;
+  }
+
+  auto it =
+  + glyphs.iter ()
+  | hb_map_retains_sorting ([&] (const HBGlyphID& gid) -> hb_pair_t<hb_codepoint_t, unsigned>
+                            {
+                              unsigned new_klass = klass_map->get (gid_klass_map[gid]);
+                              return hb_pair ((hb_codepoint_t)gid, new_klass);
+                            })
+  ;
+
+  c->propagate_error (glyphs, klasses);
+  ClassDef_serialize (c, it);
+}
 
 /*
  * Class Definition Table
  */
 
-static inline void ClassDef_serialize (hb_serialize_context_t *c,
-                                       hb_array_t<const GlyphID> glyphs,
-                                       hb_array_t<const HBUINT16> klasses);
-
 struct ClassDefFormat1
 {
   friend struct ClassDef;
@@ -1192,54 +1694,64 @@
     return classValue[(unsigned int) (glyph_id - startGlyph)];
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const HBUINT16> glyphs,
-                  hb_array_t<const HBUINT16> klasses)
+                  Iterator it)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    if (unlikely (!glyphs.length))
+    if (unlikely (!it))
     {
-      startGlyph.set (0);
-      classValue.len.set (0);
+      startGlyph = 0;
+      classValue.len = 0;
       return_trace (true);
     }
 
-    hb_codepoint_t glyph_min = glyphs[0];
-    hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
+    hb_codepoint_t glyph_min = (*it).first;
+    hb_codepoint_t glyph_max = + it
+                               | hb_map (hb_first)
+                               | hb_reduce (hb_max, 0u);
+    unsigned glyph_count = glyph_max - glyph_min + 1;
 
-    startGlyph.set (glyph_min);
-    classValue.len.set (glyph_max - glyph_min + 1);
-    if (unlikely (!c->extend (classValue))) return_trace (false);
-
-    for (unsigned int i = 0; i < glyphs.length; i++)
-      classValue[glyphs[i] - glyph_min] = klasses[i];
-
+    startGlyph = glyph_min;
+    if (unlikely (!classValue.serialize (c, glyph_count))) return_trace (false);
+    for (const hb_pair_t<hb_codepoint_t, unsigned> gid_klass_pair : + it)
+    {
+      unsigned idx = gid_klass_pair.first - glyph_min;
+      classValue[idx] = gid_klass_pair.second;
+    }
     return_trace (true);
   }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               hb_map_t *klass_map = nullptr /*OUT*/) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset;
+    const hb_set_t &glyphset = *c->plan->_glyphset_gsub;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
-    hb_vector_t<GlyphID> glyphs;
-    hb_vector_t<HBUINT16> klasses;
+
+    hb_sorted_vector_t<HBGlyphID> glyphs;
+    hb_set_t orig_klasses;
+    hb_map_t gid_org_klass_map;
 
     hb_codepoint_t start = startGlyph;
     hb_codepoint_t end   = start + classValue.len;
-    for (hb_codepoint_t g = start; g < end; g++)
+    for (const hb_codepoint_t gid : + hb_range (start, end)
+                                    | hb_filter (glyphset))
     {
-      unsigned int value = classValue[g - start];
-      if (!value) continue;
-      if (!glyphset.has (g)) continue;
-      glyphs.push()->set (glyph_map[g]);
-      klasses.push()->set (value);
+      unsigned klass = classValue[gid - start];
+      if (!klass) continue;
+
+      glyphs.push (glyph_map[gid]);
+      gid_org_klass_map.set (glyph_map[gid], klass);
+      orig_klasses.add (klass);
     }
-    c->serializer->propagate_error (glyphs, klasses);
-    ClassDef_serialize (c->serializer, glyphs, klasses);
-    return_trace (glyphs.length);
+
+    ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map,
+                                  glyphs, orig_klasses, klass_map);
+    return_trace ((bool) glyphs);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1249,7 +1761,7 @@
   }
 
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
+  bool collect_coverage (set_t *glyphs) const
   {
     unsigned int start = 0;
     unsigned int count = classValue.len;
@@ -1272,7 +1784,7 @@
   }
 
   template <typename set_t>
-  bool add_class (set_t *glyphs, unsigned int klass) const
+  bool collect_class (set_t *glyphs, unsigned int klass) const
   {
     unsigned int count = classValue.len;
     for (unsigned int i = 0; i < count; i++)
@@ -1311,7 +1823,7 @@
 
   protected:
   HBUINT16      classFormat;    /* Format identifier--format = 1 */
-  GlyphID       startGlyph;     /* First GlyphID of the classValueArray */
+  HBGlyphID     startGlyph;     /* First GlyphID of the classValueArray */
   ArrayOf<HBUINT16>
                 classValue;     /* Array of Class Values--one per GlyphID */
   public:
@@ -1328,69 +1840,90 @@
     return rangeRecord.bsearch (glyph_id).value;
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const HBUINT16> glyphs,
-                  hb_array_t<const HBUINT16> klasses)
+                  Iterator it)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    if (unlikely (!glyphs.length))
+    if (unlikely (!it))
     {
-      rangeRecord.len.set (0);
+      rangeRecord.len = 0;
       return_trace (true);
     }
 
-    unsigned int num_ranges = 1;
-    for (unsigned int i = 1; i < glyphs.length; i++)
-      if (glyphs[i - 1] + 1 != glyphs[i] ||
-          klasses[i - 1] != klasses[i])
-        num_ranges++;
-    rangeRecord.len.set (num_ranges);
-    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
+    unsigned num_ranges = 1;
+    hb_codepoint_t prev_gid = (*it).first;
+    unsigned prev_klass = (*it).second;
 
-    unsigned int range = 0;
-    rangeRecord[range].start = glyphs[0];
-    rangeRecord[range].value.set (klasses[0]);
-    for (unsigned int i = 1; i < glyphs.length; i++)
+    RangeRecord range_rec;
+    range_rec.first = prev_gid;
+    range_rec.last = prev_gid;
+    range_rec.value = prev_klass;
+
+    RangeRecord *record = c->copy (range_rec);
+    if (unlikely (!record)) return_trace (false);
+
+    for (const auto gid_klass_pair : + (++it))
     {
-      if (glyphs[i - 1] + 1 != glyphs[i] ||
-          klasses[i - 1] != klasses[i])
+      hb_codepoint_t cur_gid = gid_klass_pair.first;
+      unsigned cur_klass = gid_klass_pair.second;
+
+      if (cur_gid != prev_gid + 1 ||
+          cur_klass != prev_klass)
       {
-        range++;
-        rangeRecord[range].start = glyphs[i];
-        rangeRecord[range].value = klasses[i];
+        if (unlikely (!record)) break;
+        record->last = prev_gid;
+        num_ranges++;
+
+        range_rec.first = cur_gid;
+        range_rec.last = cur_gid;
+        range_rec.value = cur_klass;
+
+        record = c->copy (range_rec);
       }
-      rangeRecord[range].end = glyphs[i];
+
+      prev_klass = cur_klass;
+      prev_gid = cur_gid;
     }
+
+    if (likely (record)) record->last = prev_gid;
+    rangeRecord.len = num_ranges;
     return_trace (true);
   }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               hb_map_t *klass_map = nullptr /*OUT*/) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset;
+    const hb_set_t &glyphset = *c->plan->_glyphset_gsub;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
-    hb_vector_t<GlyphID> glyphs;
-    hb_vector_t<HBUINT16> klasses;
 
-    unsigned int count = rangeRecord.len;
-    for (unsigned int i = 0; i < count; i++)
+    hb_sorted_vector_t<HBGlyphID> glyphs;
+    hb_set_t orig_klasses;
+    hb_map_t gid_org_klass_map;
+
+    unsigned count = rangeRecord.len;
+    for (unsigned i = 0; i < count; i++)
     {
-      unsigned int value = rangeRecord[i].value;
-      if (!value) continue;
-      hb_codepoint_t start = rangeRecord[i].start;
-      hb_codepoint_t end   = rangeRecord[i].end + 1;
+      unsigned klass = rangeRecord[i].value;
+      if (!klass) continue;
+      hb_codepoint_t start = rangeRecord[i].first;
+      hb_codepoint_t end   = rangeRecord[i].last + 1;
       for (hb_codepoint_t g = start; g < end; g++)
       {
         if (!glyphset.has (g)) continue;
-        glyphs.push ()->set (glyph_map[g]);
-        klasses.push ()->set (value);
+        glyphs.push (glyph_map[g]);
+        gid_org_klass_map.set (glyph_map[g], klass);
+        orig_klasses.add (klass);
       }
     }
-    c->serializer->propagate_error (glyphs, klasses);
-    ClassDef_serialize (c->serializer, glyphs, klasses);
-    return_trace (glyphs.length);
+
+    ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map,
+                                  glyphs, orig_klasses, klass_map);
+    return_trace ((bool) glyphs);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1400,24 +1933,24 @@
   }
 
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
+  bool collect_coverage (set_t *glyphs) const
   {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
       if (rangeRecord[i].value)
-        if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
+        if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
           return false;
     return true;
   }
 
   template <typename set_t>
-  bool add_class (set_t *glyphs, unsigned int klass) const
+  bool collect_class (set_t *glyphs, unsigned int klass) const
   {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
     {
       if (rangeRecord[i].value == klass)
-        if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
+        if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
           return false;
     }
     return true;
@@ -1443,9 +1976,9 @@
       {
         if (!hb_set_next (glyphs, &g))
           break;
-        if (g < rangeRecord[i].start)
+        if (g < rangeRecord[i].first)
           return true;
-        g = rangeRecord[i].end;
+        g = rangeRecord[i].last;
       }
       if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
         return true;
@@ -1468,6 +2001,15 @@
 
 struct ClassDef
 {
+  /* Has interface. */
+  static constexpr unsigned SENTINEL = 0;
+  typedef unsigned int value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Projection. */
+  hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
+
+  unsigned int get (hb_codepoint_t k) const { return get_class (k); }
   unsigned int get_class (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
@@ -1477,44 +2019,58 @@
     }
   }
 
-  bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs,
-                  hb_array_t<const HBUINT16> klasses)
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c, Iterator it)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
 
-    unsigned int format = 2;
-    if (glyphs.length)
+    unsigned format = 2;
+    if (likely (it))
     {
-      hb_codepoint_t glyph_min = glyphs[0];
-      hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
+      hb_codepoint_t glyph_min = (*it).first;
+      hb_codepoint_t glyph_max = + it
+                                 | hb_map (hb_first)
+                                 | hb_reduce (hb_max, 0u);
 
-      unsigned int num_ranges = 1;
-      for (unsigned int i = 1; i < glyphs.length; i++)
-        if (glyphs[i - 1] + 1 != glyphs[i] ||
-            klasses[i - 1] != klasses[i])
+      unsigned num_ranges = 1;
+      hb_codepoint_t prev_gid = glyph_min;
+      unsigned prev_klass = (*it).second;
+
+      for (const auto gid_klass_pair : it)
+      {
+        hb_codepoint_t cur_gid = gid_klass_pair.first;
+        unsigned cur_klass = gid_klass_pair.second;
+        if (cur_gid == glyph_min || !cur_klass) continue;
+        if (cur_gid != prev_gid + 1 ||
+            cur_klass != prev_klass)
           num_ranges++;
 
-      if (1 + (glyph_max - glyph_min + 1) < num_ranges * 3)
+        prev_gid = cur_gid;
+        prev_klass = cur_klass;
+      }
+
+      if (1 + (glyph_max - glyph_min + 1) <= num_ranges * 3)
         format = 1;
     }
-    u.format.set (format);
+    u.format = format;
 
     switch (u.format)
     {
-    case 1: return_trace (u.format1.serialize (c, glyphs, klasses));
-    case 2: return_trace (u.format2.serialize (c, glyphs, klasses));
+    case 1: return_trace (u.format1.serialize (c, it));
+    case 2: return_trace (u.format2.serialize (c, it));
     default:return_trace (false);
     }
   }
 
-  bool subset (hb_subset_context_t *c) const
+  bool subset (hb_subset_context_t *c,
+               hb_map_t *klass_map = nullptr /*OUT*/) const
   {
     TRACE_SUBSET (this);
     switch (u.format) {
-    case 1: return_trace (u.format1.subset (c));
-    case 2: return_trace (u.format2.subset (c));
+    case 1: return_trace (u.format1.subset (c, klass_map));
+    case 2: return_trace (u.format2.subset (c, klass_map));
     default:return_trace (false);
     }
   }
@@ -1533,11 +2089,11 @@
   /* Might return false if array looks unsorted.
    * Used for faster rejection of corrupt data. */
   template <typename set_t>
-  bool add_coverage (set_t *glyphs) const
+  bool collect_coverage (set_t *glyphs) const
   {
     switch (u.format) {
-    case 1: return u.format1.add_coverage (glyphs);
-    case 2: return u.format2.add_coverage (glyphs);
+    case 1: return u.format1.collect_coverage (glyphs);
+    case 2: return u.format2.collect_coverage (glyphs);
     default:return false;
     }
   }
@@ -1545,11 +2101,11 @@
   /* Might return false if array looks unsorted.
    * Used for faster rejection of corrupt data. */
   template <typename set_t>
-  bool add_class (set_t *glyphs, unsigned int klass) const
+  bool collect_class (set_t *glyphs, unsigned int klass) const
   {
     switch (u.format) {
-    case 1: return u.format1.add_class (glyphs, klass);
-    case 2: return u.format2.add_class (glyphs, klass);
+    case 1: return u.format1.collect_class (glyphs, klass);
+    case 2: return u.format2.collect_class (glyphs, klass);
     default:return false;
     }
   }
@@ -1581,10 +2137,10 @@
   DEFINE_SIZE_UNION (2, format);
 };
 
+template<typename Iterator>
 static inline void ClassDef_serialize (hb_serialize_context_t *c,
-                                       hb_array_t<const GlyphID> glyphs,
-                                       hb_array_t<const HBUINT16> klasses)
-{ c->start_embed<ClassDef> ()->serialize (c, glyphs, klasses); }
+                                       Iterator it)
+{ c->start_embed<ClassDef> ()->serialize (c, it); }
 
 
 /*
@@ -1635,7 +2191,7 @@
 struct VarRegionList
 {
   float evaluate (unsigned int region_index,
-                         const int *coords, unsigned int coord_len) const
+                  const int *coords, unsigned int coord_len) const
   {
     if (unlikely (region_index >= regionCount))
       return 0.;
@@ -1662,6 +2218,26 @@
                   axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
   }
 
+  bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t &region_map)
+  {
+    TRACE_SERIALIZE (this);
+    VarRegionList *out = c->allocate_min<VarRegionList> ();
+    if (unlikely (!out)) return_trace (false);
+    axisCount = src->axisCount;
+    regionCount = region_map.get_population ();
+    if (unlikely (!c->allocate_size<VarRegionList> (get_size () - min_size))) return_trace (false);
+    unsigned int region_count = src->get_region_count ();
+    for (unsigned int r = 0; r < regionCount; r++)
+    {
+      unsigned int backward = region_map.backward (r);
+      if (backward >= region_count) return_trace (false);
+      memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount);
+    }
+
+    return_trace (true);
+  }
+
+  unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; }
   unsigned int get_region_count () const { return regionCount; }
 
   protected:
@@ -1685,8 +2261,8 @@
   { return itemCount * get_row_size (); }
 
   float get_delta (unsigned int inner,
-                          const int *coords, unsigned int coord_count,
-                          const VarRegionList &regions) const
+                   const int *coords, unsigned int coord_count,
+                   const VarRegionList &regions) const
   {
     if (unlikely (inner >= itemCount))
       return 0.;
@@ -1694,7 +2270,7 @@
    unsigned int count = regionIndices.len;
    unsigned int scount = shortCount;
 
-   const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
+   const HBUINT8 *bytes = get_delta_bytes ();
    const HBUINT8 *row = bytes + inner * (scount + count);
 
    float delta = 0.;
@@ -1716,16 +2292,16 @@
    return delta;
   }
 
-  void get_scalars (int *coords, unsigned int coord_count,
+  void get_scalars (const int *coords, unsigned int coord_count,
                     const VarRegionList &regions,
                     float *scalars /*OUT */,
                     unsigned int num_scalars) const
   {
-    assert (num_scalars == regionIndices.len);
-   for (unsigned int i = 0; i < num_scalars; i++)
-   {
-     scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
-   }
+    unsigned count = hb_min (num_scalars, regionIndices.len);
+    for (unsigned int i = 0; i < count; i++)
+      scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
+    for (unsigned int i = count; i < num_scalars; i++)
+      scalars[i] = 0.f;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1734,11 +2310,117 @@
     return_trace (c->check_struct (this) &&
                   regionIndices.sanitize (c) &&
                   shortCount <= regionIndices.len &&
-                  c->check_range (&StructAfter<HBUINT8> (regionIndices),
+                  c->check_range (get_delta_bytes (),
                                   itemCount,
                                   get_row_size ()));
   }
 
+  bool serialize (hb_serialize_context_t *c,
+                  const VarData *src,
+                  const hb_inc_bimap_t &inner_map,
+                  const hb_bimap_t &region_map)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    itemCount = inner_map.get_next_value ();
+
+    /* Optimize short count */
+    unsigned short ri_count = src->regionIndices.len;
+    enum delta_size_t { kZero=0, kByte, kShort };
+    hb_vector_t<delta_size_t> delta_sz;
+    hb_vector_t<unsigned int> ri_map;   /* maps old index to new index */
+    delta_sz.resize (ri_count);
+    ri_map.resize (ri_count);
+    unsigned int new_short_count = 0;
+    unsigned int r;
+    for (r = 0; r < ri_count; r++)
+    {
+      delta_sz[r] = kZero;
+      for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
+      {
+        unsigned int old = inner_map.backward (i);
+        int16_t delta = src->get_item_delta (old, r);
+        if (delta < -128 || 127 < delta)
+        {
+          delta_sz[r] = kShort;
+          new_short_count++;
+          break;
+        }
+        else if (delta != 0)
+          delta_sz[r] = kByte;
+      }
+    }
+    unsigned int short_index = 0;
+    unsigned int byte_index = new_short_count;
+    unsigned int new_ri_count = 0;
+    for (r = 0; r < ri_count; r++)
+      if (delta_sz[r])
+      {
+        ri_map[r] = (delta_sz[r] == kShort)? short_index++ : byte_index++;
+        new_ri_count++;
+      }
+
+    shortCount = new_short_count;
+    regionIndices.len = new_ri_count;
+
+    unsigned int size = regionIndices.get_size () - HBUINT16::static_size/*regionIndices.len*/ + (get_row_size () * itemCount);
+    if (unlikely (!c->allocate_size<HBUINT8> (size)))
+      return_trace (false);
+
+    for (r = 0; r < ri_count; r++)
+      if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]];
+
+    for (unsigned int i = 0; i < itemCount; i++)
+    {
+      unsigned int      old = inner_map.backward (i);
+      for (unsigned int r = 0; r < ri_count; r++)
+        if (delta_sz[r]) set_item_delta (i, ri_map[r], src->get_item_delta (old, r));
+    }
+
+    return_trace (true);
+  }
+
+  void collect_region_refs (hb_inc_bimap_t &region_map, const hb_inc_bimap_t &inner_map) const
+  {
+    for (unsigned int r = 0; r < regionIndices.len; r++)
+    {
+      unsigned int region = regionIndices[r];
+      if (region_map.has (region)) continue;
+      for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
+        if (get_item_delta (inner_map.backward (i), r) != 0)
+        {
+          region_map.add (region);
+          break;
+        }
+    }
+  }
+
+  protected:
+  const HBUINT8 *get_delta_bytes () const
+  { return &StructAfter<HBUINT8> (regionIndices); }
+
+  HBUINT8 *get_delta_bytes ()
+  { return &StructAfter<HBUINT8> (regionIndices); }
+
+  int16_t get_item_delta (unsigned int item, unsigned int region) const
+  {
+    if ( item >= itemCount || unlikely (region >= regionIndices.len)) return 0;
+    const HBINT8 *p = (const HBINT8 *)get_delta_bytes () + item * get_row_size ();
+    if (region < shortCount)
+      return ((const HBINT16 *)p)[region];
+    else
+      return (p + HBINT16::static_size * shortCount)[region - shortCount];
+  }
+
+  void set_item_delta (unsigned int item, unsigned int region, int16_t delta)
+  {
+    HBINT8 *p = (HBINT8 *)get_delta_bytes () + item * get_row_size ();
+    if (region < shortCount)
+      ((HBINT16 *)p)[region] = delta;
+    else
+      (p + HBINT16::static_size * shortCount)[region - shortCount] = delta;
+  }
+
   protected:
   HBUINT16              itemCount;
   HBUINT16              shortCount;
@@ -1753,8 +2435,12 @@
   float get_delta (unsigned int outer, unsigned int inner,
                    const int *coords, unsigned int coord_count) const
   {
+#ifdef HB_NO_VAR
+    return 0.f;
+#endif
+
     if (unlikely (outer >= dataSets.len))
-      return 0.;
+      return 0.f;
 
     return (this+dataSets[outer]).get_delta (inner,
                                              coords, coord_count,
@@ -1771,6 +2457,10 @@
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
+#ifdef HB_NO_VAR
+    return true;
+#endif
+
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
                   format == 1 &&
@@ -1778,18 +2468,98 @@
                   dataSets.sanitize (c, this));
   }
 
+  bool serialize (hb_serialize_context_t *c,
+                  const VariationStore *src,
+                  const hb_array_t <hb_inc_bimap_t> &inner_maps)
+  {
+    TRACE_SERIALIZE (this);
+    unsigned int set_count = 0;
+    for (unsigned int i = 0; i < inner_maps.length; i++)
+      if (inner_maps[i].get_population () > 0) set_count++;
+
+    unsigned int size = min_size + HBUINT32::static_size * set_count;
+    if (unlikely (!c->allocate_size<HBUINT32> (size))) return_trace (false);
+    format = 1;
+
+    hb_inc_bimap_t region_map;
+    for (unsigned int i = 0; i < inner_maps.length; i++)
+      (src+src->dataSets[i]).collect_region_refs (region_map, inner_maps[i]);
+    region_map.sort ();
+
+    if (unlikely (!regions.serialize (c, this)
+                  .serialize (c, &(src+src->regions), region_map))) return_trace (false);
+
+    /* TODO: The following code could be simplified when
+     * OffsetListOf::subset () can take a custom param to be passed to VarData::serialize ()
+     */
+    dataSets.len = set_count;
+    unsigned int set_index = 0;
+    for (unsigned int i = 0; i < inner_maps.length; i++)
+    {
+      if (inner_maps[i].get_population () == 0) continue;
+      if (unlikely (!dataSets[set_index++].serialize (c, this)
+                      .serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map)))
+        return_trace (false);
+    }
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
+    if (unlikely (!varstore_prime)) return_trace (false);
+
+    const hb_set_t *variation_indices = c->plan->layout_variation_indices;
+    if (variation_indices->is_empty ()) return_trace (false);
+
+    hb_vector_t<hb_inc_bimap_t> inner_maps;
+    inner_maps.resize ((unsigned) dataSets.len);
+    for (unsigned i = 0; i < inner_maps.length; i++)
+      inner_maps[i].init ();
+
+    for (unsigned idx : c->plan->layout_variation_indices->iter ())
+    {
+      uint16_t major = idx >> 16;
+      uint16_t minor = idx & 0xFFFF;
+
+      if (major >= inner_maps.length)
+      {
+        for (unsigned i = 0; i < inner_maps.length; i++)
+          inner_maps[i].fini ();
+        return_trace (false);
+      }
+      inner_maps[major].add (minor);
+    }
+    varstore_prime->serialize (c->serializer, this, inner_maps.as_array ());
+
+    for (unsigned i = 0; i < inner_maps.length; i++)
+      inner_maps[i].fini ();
+    return_trace (bool (varstore_prime->dataSets));
+  }
+
   unsigned int get_region_index_count (unsigned int ivs) const
   { return (this+dataSets[ivs]).get_region_index_count (); }
 
   void get_scalars (unsigned int ivs,
-                    int *coords, unsigned int coord_count,
+                    const int *coords, unsigned int coord_count,
                     float *scalars /*OUT*/,
                     unsigned int num_scalars) const
   {
+#ifdef HB_NO_VAR
+    for (unsigned i = 0; i < num_scalars; i++)
+      scalars[i] = 0.f;
+    return;
+#endif
+
     (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
                                       &scalars[0], num_scalars);
   }
 
+  unsigned int get_sub_table_count () const { return dataSets.len; }
+
   protected:
   HBUINT16                              format;
   LOffsetTo<VarRegionList>              regions;
@@ -1806,6 +2576,14 @@
 {
   friend struct Condition;
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    return_trace (true);
+  }
+
   private:
   bool evaluate (const int *coords, unsigned int coord_len) const
   {
@@ -1838,6 +2616,17 @@
     }
   }
 
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1868,6 +2657,18 @@
     return true;
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    + conditions.iter ()
+    | hb_apply (subset_offset_array (c, out->conditions, this))
+    ;
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1884,6 +2685,30 @@
 {
   friend struct FeatureTableSubstitution;
 
+  void collect_lookups (const void *base, hb_set_t *lookup_indexes /* OUT */) const
+  {
+    return (base+feature).add_lookup_indexes_to (lookup_indexes);
+  }
+
+  void closure_features (const void *base,
+                         const hb_map_t *lookup_indexes,
+                         hb_set_t       *feature_indexes /* OUT */) const
+  {
+    if ((base+feature).intersects_lookup_indexes (lookup_indexes))
+      feature_indexes->add (featureIndex);
+  }
+
+  bool subset (hb_subset_layout_context_t *c, const void *base) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->subset_context->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    out->featureIndex = c->feature_index_map->get (featureIndex);
+    bool ret = out->feature.serialize_subset (c->subset_context, feature, base, c);
+    return_trace (ret);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -1911,6 +2736,39 @@
     return nullptr;
   }
 
+  void collect_lookups (const hb_set_t *feature_indexes,
+                        hb_set_t       *lookup_indexes /* OUT */) const
+  {
+    + hb_iter (substitutions)
+    | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
+    | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
+                { r.collect_lookups (this, lookup_indexes); })
+    ;
+  }
+
+  void closure_features (const hb_map_t *lookup_indexes,
+                         hb_set_t       *feature_indexes /* OUT */) const
+  {
+    for (const FeatureTableSubstitutionRecord& record : substitutions)
+      record.closure_features (this, lookup_indexes, feature_indexes);
+  }
+
+  bool subset (hb_subset_context_t        *c,
+               hb_subset_layout_context_t *l) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    out->version.major = version.major;
+    out->version.minor = version.minor;
+
+    + substitutions.iter ()
+    | hb_apply (subset_record_array (l, &(out->substitutions), this))
+    ;
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1931,6 +2789,32 @@
 {
   friend struct FeatureVariations;
 
+  void collect_lookups (const void     *base,
+                        const hb_set_t *feature_indexes,
+                        hb_set_t       *lookup_indexes /* OUT */) const
+  {
+    return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
+  }
+
+  void closure_features (const void     *base,
+                         const hb_map_t *lookup_indexes,
+                         hb_set_t       *feature_indexes /* OUT */) const
+  {
+    (base+substitutions).closure_features (lookup_indexes, feature_indexes);
+  }
+
+  bool subset (hb_subset_layout_context_t *c, const void *base) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->subset_context->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    out->conditions.serialize_subset (c->subset_context, conditions, base);
+    out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -1952,7 +2836,7 @@
   static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
 
   bool find_index (const int *coords, unsigned int coord_len,
-                          unsigned int *index) const
+                   unsigned int *index) const
   {
     unsigned int count = varRecords.len;
     for (unsigned int i = 0; i < count; i++)
@@ -1975,10 +2859,40 @@
     return (this+record.substitutions).find_substitute (feature_index);
   }
 
-  bool subset (hb_subset_context_t *c) const
+  FeatureVariations* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed (*this));
+  }
+
+  void collect_lookups (const hb_set_t *feature_indexes,
+                        hb_set_t       *lookup_indexes /* OUT */) const
+  {
+    for (const FeatureVariationRecord& r : varRecords)
+      r.collect_lookups (this, feature_indexes, lookup_indexes);
+  }
+
+  void closure_features (const hb_map_t *lookup_indexes,
+                         hb_set_t       *feature_indexes /* OUT */) const
+  {
+    for (const FeatureVariationRecord& record : varRecords)
+      record.closure_features (this, lookup_indexes, feature_indexes);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               hb_subset_layout_context_t *l) const
   {
     TRACE_SUBSET (this);
-    return_trace (c->serializer->embed (*this));
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+    out->version.major = version.major;
+    out->version.minor = version.minor;
+
+    + varRecords.iter ()
+    | hb_apply (subset_record_array (l, &(out->varRecords), this))
+    ;
+    return_trace (bool (out->varRecords));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2014,6 +2928,8 @@
   hb_position_t get_y_delta (hb_font_t *font) const
   { return get_delta (font->y_ppem, font->y_scale); }
 
+  public:
+
   unsigned int get_size () const
   {
     unsigned int f = deltaFormat;
@@ -2027,6 +2943,12 @@
     return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
   }
 
+  HintingDevice* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed<HintingDevice> (this));
+  }
+
   private:
 
   int get_delta (unsigned int ppem, int scale) const
@@ -2088,6 +3010,32 @@
   hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
   { return font->em_scalef_y (get_delta (font, store)); }
 
+  VariationDevice* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto snap = c->snapshot ();
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+    if (!layout_variation_idx_map || layout_variation_idx_map->is_empty ()) return_trace (out);
+
+    unsigned org_idx = (outerIndex << 16) + innerIndex;
+    if (!layout_variation_idx_map->has (org_idx))
+    {
+      c->revert (snap);
+      return_trace (nullptr);
+    }
+    unsigned new_idx = layout_variation_idx_map->get (org_idx);
+    out->outerIndex = new_idx >> 16;
+    out->innerIndex = new_idx & 0xFFFF;
+    return_trace (out);
+  }
+
+  void record_variation_index (hb_set_t *layout_variation_indices) const
+  {
+    unsigned var_idx = (outerIndex << 16) + innerIndex;
+    layout_variation_indices->add (var_idx);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -2126,10 +3074,14 @@
   {
     switch (u.b.format)
     {
+#ifndef HB_NO_HINTING
     case 1: case 2: case 3:
       return u.hinting.get_x_delta (font);
+#endif
+#ifndef HB_NO_VAR
     case 0x8000:
       return u.variation.get_x_delta (font, store);
+#endif
     default:
       return 0;
     }
@@ -2139,9 +3091,13 @@
     switch (u.b.format)
     {
     case 1: case 2: case 3:
+#ifndef HB_NO_HINTING
       return u.hinting.get_y_delta (font);
+#endif
+#ifndef HB_NO_VAR
     case 0x8000:
       return u.variation.get_y_delta (font, store);
+#endif
     default:
       return 0;
     }
@@ -2152,20 +3108,64 @@
     TRACE_SANITIZE (this);
     if (!u.b.format.sanitize (c)) return_trace (false);
     switch (u.b.format) {
+#ifndef HB_NO_HINTING
     case 1: case 2: case 3:
       return_trace (u.hinting.sanitize (c));
+#endif
+#ifndef HB_NO_VAR
     case 0x8000:
       return_trace (u.variation.sanitize (c));
+#endif
     default:
       return_trace (true);
     }
   }
 
+  Device* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map=nullptr) const
+  {
+    TRACE_SERIALIZE (this);
+    switch (u.b.format) {
+#ifndef HB_NO_HINTING
+    case 1:
+    case 2:
+    case 3:
+      return_trace (reinterpret_cast<Device *> (u.hinting.copy (c)));
+#endif
+#ifndef HB_NO_VAR
+    case 0x8000:
+      return_trace (reinterpret_cast<Device *> (u.variation.copy (c, layout_variation_idx_map)));
+#endif
+    default:
+      return_trace (nullptr);
+    }
+  }
+
+  void collect_variation_indices (hb_set_t *layout_variation_indices) const
+  {
+    switch (u.b.format) {
+#ifndef HB_NO_HINTING
+    case 1:
+    case 2:
+    case 3:
+      return;
+#endif
+#ifndef HB_NO_VAR
+    case 0x8000:
+      u.variation.record_variation_index (layout_variation_indices);
+      return;
+#endif
+    default:
+      return;
+    }
+  }
+
   protected:
   union {
   DeviceHeader          b;
   HintingDevice         hinting;
+#ifndef HB_NO_VAR
   VariationDevice       variation;
+#endif
   } u;
   public:
   DEFINE_SIZE_UNION (6, b);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gdef-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gdef-table.hh
index 533c95a..201a6c9 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gdef-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gdef-table.hh
@@ -41,8 +41,18 @@
  * Attachment List Table
  */
 
-typedef ArrayOf<HBUINT16> AttachPoint;  /* Array of contour point indices--in
-                                         * increasing numerical order */
+/* Array of contour point indices--in increasing numerical order */
+struct AttachPoint : ArrayOf<HBUINT16>
+{
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    return_trace (out->serialize (c->serializer, + iter ()));
+  }
+};
 
 struct AttachList
 {
@@ -63,15 +73,36 @@
 
     if (point_count)
     {
-      hb_array_t<const HBUINT16> array = points.sub_array (start_offset, point_count);
-      unsigned int count = array.length;
-      for (unsigned int i = 0; i < count; i++)
-        point_array[i] = array[i];
+      + points.sub_array (start_offset, point_count)
+      | hb_sink (hb_array (point_array, *point_count))
+      ;
     }
 
     return points.len;
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, attachPoint)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize (c->serializer, out)
+                 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -96,6 +127,13 @@
 struct CaretValueFormat1
 {
   friend struct CaretValue;
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    return_trace (true);
+  }
 
   private:
   hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
@@ -119,6 +157,13 @@
 struct CaretValueFormat2
 {
   friend struct CaretValue;
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    return_trace (true);
+  }
 
   private:
   hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
@@ -153,6 +198,19 @@
            font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
+                                                   hb_serialize_context_t::Head, c->plan->layout_variation_idx_map));
+  }
+
+  void collect_variation_indices (hb_set_t *layout_variation_indices) const
+  { (this+deviceTable).collect_variation_indices (layout_variation_indices); }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -173,9 +231,9 @@
 struct CaretValue
 {
   hb_position_t get_caret_value (hb_font_t *font,
-                                        hb_direction_t direction,
-                                        hb_codepoint_t glyph_id,
-                                        const VariationStore &var_store) const
+                                 hb_direction_t direction,
+                                 hb_codepoint_t glyph_id,
+                                 const VariationStore &var_store) const
   {
     switch (u.format) {
     case 1: return u.format1.get_caret_value (font, direction);
@@ -185,6 +243,32 @@
     }
   }
 
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  void collect_variation_indices (hb_set_t *layout_variation_indices) const
+  {
+    switch (u.format) {
+    case 1:
+    case 2:
+      return;
+    case 3:
+      u.format3.collect_variation_indices (layout_variation_indices);
+      return;
+    default: return;
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -210,25 +294,45 @@
 
 struct LigGlyph
 {
-  unsigned int get_lig_carets (hb_font_t *font,
-                               hb_direction_t direction,
-                               hb_codepoint_t glyph_id,
-                               const VariationStore &var_store,
-                               unsigned int start_offset,
-                               unsigned int *caret_count /* IN/OUT */,
-                               hb_position_t *caret_array /* OUT */) const
+  unsigned get_lig_carets (hb_font_t            *font,
+                           hb_direction_t        direction,
+                           hb_codepoint_t        glyph_id,
+                           const VariationStore &var_store,
+                           unsigned              start_offset,
+                           unsigned             *caret_count /* IN/OUT */,
+                           hb_position_t        *caret_array /* OUT */) const
   {
     if (caret_count)
     {
-      hb_array_t <const OffsetTo<CaretValue> > array = carets.sub_array (start_offset, caret_count);
-      unsigned int count = array.length;
-      for (unsigned int i = 0; i < count; i++)
-        caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
+      + carets.sub_array (start_offset, caret_count)
+      | hb_map (hb_add (this))
+      | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
+      | hb_sink (hb_array (caret_array, *caret_count))
+      ;
     }
 
     return carets.len;
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + hb_iter (carets)
+    | hb_apply (subset_offset_array (c, out->carets, this))
+    ;
+
+    return_trace (bool (out->carets));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    for (const OffsetTo<CaretValue>& offset : carets.iter ())
+      (this+offset).collect_variation_indices (c->layout_variation_indices);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -265,6 +369,38 @@
     return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, ligGlyph)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize (c->serializer, out)
+                 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+coverage, ligGlyph)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
+    ;
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -288,6 +424,34 @@
   bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    bool ret = true;
+    for (const LOffsetTo<Coverage>& offset : coverage.iter ())
+    {
+      auto *o = out->coverage.serialize_append (c->serializer);
+      if (unlikely (!o))
+      {
+        ret = false;
+        break;
+      }
+
+      //not using o->serialize_subset (c, offset, this, out) here because
+      //OTS doesn't allow null offset.
+      //See issue: https://github.com/khaledhosny/ots/issues/172
+      c->serializer->push ();
+      c->dispatch (this+offset);
+      c->serializer->add_link (*o, c->serializer->pop_pack ());
+    }
+
+    return_trace (ret && out->coverage.len);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -296,7 +460,7 @@
 
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
-  ArrayOf<LOffsetTo<Coverage> >
+  ArrayOf<LOffsetTo<Coverage>>
                 coverage;               /* Array of long offsets to mark set
                                          * coverage tables */
   public:
@@ -313,6 +477,15 @@
     }
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    switch (u.format) {
+    case 1: return_trace (u.format1.subset (c));
+    default:return_trace (false);
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -356,7 +529,7 @@
   unsigned int get_glyph_class (hb_codepoint_t glyph) const
   { return (this+glyphClassDef).get_class (glyph); }
   void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
-  { (this+glyphClassDef).add_class (glyphs, klass); }
+  { (this+glyphClassDef).collect_class (glyphs, klass); }
 
   bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
   unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
@@ -386,7 +559,7 @@
 
   bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
   const VariationStore &get_var_store () const
-  { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
+  { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); }
 
   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
    * glyph class and other bits, and high 8-bit the mark attachment type (if any).
@@ -409,15 +582,15 @@
     }
   }
 
-  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
+  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
                                    hb_face_t *face) const;
 
   struct accelerator_t
   {
     void init (hb_face_t *face)
     {
-      this->table = hb_sanitize_context_t().reference_table<GDEF> (face);
-      if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
+      this->table = hb_sanitize_context_t ().reference_table<GDEF> (face);
+      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
       {
         hb_blob_destroy (this->table.get_blob ());
         this->table = hb_blob_get_empty ();
@@ -436,24 +609,66 @@
            (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
   }
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  { (this+ligCaretList).collect_variation_indices (c); }
+
+  void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
+                                       hb_map_t *layout_variation_idx_map /* OUT */) const
+  {
+    if (version.to_int () < 0x00010003u || !varStore) return;
+    if (layout_variation_indices->is_empty ()) return;
+
+    unsigned new_major = 0, new_minor = 0;
+    unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
+    for (unsigned idx : layout_variation_indices->iter ())
+    {
+      uint16_t major = idx >> 16;
+      if (major >= (this+varStore).get_sub_table_count ()) break;
+      if (major != last_major)
+      {
+        new_minor = 0;
+        ++new_major;
+      }
+
+      unsigned new_idx = (new_major << 16) + new_minor;
+      layout_variation_idx_map->set (idx, new_idx);
+      ++new_minor;
+      last_major = major;
+    }
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct GDEF *out = c->serializer->embed (*this);
+    auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
 
-    out->glyphClassDef.serialize_subset (c, this+glyphClassDef, out);
-    out->attachList.set (0);//TODO(subset) serialize_subset (c, this+attachList, out);
-    out->ligCaretList.set (0);//TODO(subset) serialize_subset (c, this+ligCaretList, out);
-    out->markAttachClassDef.serialize_subset (c, this+markAttachClassDef, out);
+    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this);
+    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this);
 
+    bool subset_markglyphsetsdef = true;
     if (version.to_int () >= 0x00010002u)
-      out->markGlyphSetsDef.set (0);// TODO(subset) serialize_subset (c, this+markGlyphSetsDef, out);
+    {
+      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
+      if (!subset_markglyphsetsdef &&
+          version.to_int () == 0x00010002u)
+        out->version.minor = 0;
+    }
 
+    bool subset_varstore = true;
     if (version.to_int () >= 0x00010003u)
-      out->varStore.set (0);// TODO(subset) serialize_subset (c, this+varStore, out);
+    {
+      subset_varstore = out->varStore.serialize_subset (c, varStore, this);
+      if (!subset_varstore && version.to_int () == 0x00010003u)
+        out->version.minor = 2;
+    }
 
-    return_trace (true);
+    return_trace (subset_glyphclassdef || subset_attachlist ||
+                  subset_ligcaretlist || subset_markattachclassdef ||
+                  (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
+                  (out->version.to_int () >= 0x00010003u && subset_varstore));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh
index 2a51650..eddae15 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh
@@ -34,6 +34,11 @@
 
 namespace OT {
 
+struct MarkArray;
+static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
+                                                 const MarkArray &mark_array,
+                                                 const hb_set_t  &glyphset,
+                                                 hb_map_t*        klass_mapping /* INOUT */);
 
 /* buffer **position** var allocations */
 #define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
@@ -74,14 +79,14 @@
 
 /* All fields are options.  Only those available advance the value pointer. */
 #if 0
-  HBINT16               xPlacement;             /* Horizontal adjustment for
+  HBINT16               xPlacement;     /* Horizontal adjustment for
                                          * placement--in design units */
-  HBINT16               yPlacement;             /* Vertical adjustment for
+  HBINT16               yPlacement;     /* Vertical adjustment for
                                          * placement--in design units */
-  HBINT16               xAdvance;               /* Horizontal adjustment for
+  HBINT16               xAdvance;       /* Horizontal adjustment for
                                          * advance--in design units (only used
                                          * for horizontal writing) */
-  HBINT16               yAdvance;               /* Vertical adjustment for advance--in
+  HBINT16               yAdvance;       /* Vertical adjustment for advance--in
                                          * design units (only used for vertical
                                          * writing) */
   OffsetTo<Device>      xPlaDevice;     /* Offset to Device table for
@@ -101,10 +106,10 @@
   unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
   unsigned int get_size () const { return get_len () * Value::static_size; }
 
-  bool apply_value (hb_ot_apply_context_t   *c,
-                    const void           *base,
-                    const Value          *values,
-                    hb_glyph_position_t  &glyph_pos) const
+  bool apply_value (hb_ot_apply_context_t *c,
+                    const void            *base,
+                    const Value           *values,
+                    hb_glyph_position_t   &glyph_pos) const
   {
     bool ret = false;
     unsigned int format = *this;
@@ -155,6 +160,60 @@
     return ret;
   }
 
+  void serialize_copy (hb_serialize_context_t *c, const void *base,
+                       const Value *values, const hb_map_t *layout_variation_idx_map) const
+  {
+    unsigned int format = *this;
+    if (!format) return;
+
+    if (format & xPlacement) c->copy (*values++);
+    if (format & yPlacement) c->copy (*values++);
+    if (format & xAdvance)   c->copy (*values++);
+    if (format & yAdvance)   c->copy (*values++);
+
+    if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
+    if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
+    if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
+    if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const void *base,
+                                  const hb_array_t<const Value>& values) const
+  {
+    unsigned format = *this;
+    unsigned i = 0;
+    if (format & xPlacement) i++;
+    if (format & yPlacement) i++;
+    if (format & xAdvance) i++;
+    if (format & yAdvance) i++;
+    if (format & xPlaDevice)
+    {
+      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+      i++;
+    }
+
+    if (format & ValueFormat::yPlaDevice)
+    {
+      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+      i++;
+    }
+
+    if (format & ValueFormat::xAdvDevice)
+    {
+
+      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+      i++;
+    }
+
+    if (format & ValueFormat::yAdvDevice)
+    {
+
+      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
+      i++;
+    }
+  }
+
   private:
   bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
   {
@@ -173,18 +232,42 @@
     return true;
   }
 
-  static OffsetTo<Device>& get_device (Value* value)
-  { return *CastP<OffsetTo<Device> > (value); }
-  static const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr)
+  static inline OffsetTo<Device>& get_device (Value* value)
+  {
+    return *static_cast<OffsetTo<Device> *> (value);
+  }
+  static inline const OffsetTo<Device>& get_device (const Value* value, bool *worked=nullptr)
   {
     if (worked) *worked |= bool (*value);
-    return *CastP<OffsetTo<Device> > (value);
+    return *static_cast<const OffsetTo<Device> *> (value);
   }
 
-  static const HBINT16& get_short (const Value* value, bool *worked=nullptr)
+  bool copy_device (hb_serialize_context_t *c, const void *base,
+                    const Value *src_value, const hb_map_t *layout_variation_idx_map) const
+  {
+    Value       *dst_value = c->copy (*src_value);
+
+    if (!dst_value) return false;
+    if (*dst_value == 0) return true;
+
+    *dst_value = 0;
+    c->push ();
+    if ((base + get_device (src_value)).copy (c, layout_variation_idx_map))
+    {
+      c->add_link (*dst_value, c->pop_pack ());
+      return true;
+    }
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+  }
+
+  static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
   {
     if (worked) *worked |= bool (*value);
-    return *CastP<HBINT16> (value);
+    return *reinterpret_cast<const HBINT16 *> (value);
   }
 
   public:
@@ -236,6 +319,13 @@
   }
 };
 
+template<typename Iterator>
+static void SinglePos_serialize (hb_serialize_context_t *c,
+                                 const void *src,
+                                 Iterator it,
+                                 ValueFormat valFormat,
+                                 const hb_map_t *layout_variation_idx_map);
+
 
 struct AnchorFormat1
 {
@@ -253,6 +343,12 @@
     return_trace (c->check_struct (this));
   }
 
+  AnchorFormat1* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed<AnchorFormat1> (this));
+  }
+
   protected:
   HBUINT16      format;                 /* Format identifier--format = 1 */
   FWORD         xCoordinate;            /* Horizontal value--in design units */
@@ -267,6 +363,13 @@
                    float *x, float *y) const
   {
     hb_font_t *font = c->font;
+
+#ifdef HB_NO_HINTING
+    *x = font->em_fscale_x (xCoordinate);
+    *y = font->em_fscale_y (yCoordinate);
+    return;
+#endif
+
     unsigned int x_ppem = font->x_ppem;
     unsigned int y_ppem = font->y_ppem;
     hb_position_t cx = 0, cy = 0;
@@ -284,6 +387,12 @@
     return_trace (c->check_struct (this));
   }
 
+  AnchorFormat2* copy (hb_serialize_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    return_trace (c->embed<AnchorFormat2> (this));
+  }
+
   protected:
   HBUINT16      format;                 /* Format identifier--format = 2 */
   FWORD         xCoordinate;            /* Horizontal value--in design units */
@@ -314,6 +423,26 @@
     return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
+  AnchorFormat3* copy (hb_serialize_context_t *c,
+                       const hb_map_t *layout_variation_idx_map) const
+  {
+    TRACE_SERIALIZE (this);
+    if (!layout_variation_idx_map) return_trace (nullptr);
+
+    auto *out = c->embed<AnchorFormat3> (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
+    out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
+    return_trace (out);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices);
+    (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices);
+  }
+
   protected:
   HBUINT16      format;                 /* Format identifier--format = 3 */
   FWORD         xCoordinate;            /* Horizontal value--in design units */
@@ -356,6 +485,29 @@
     }
   }
 
+  Anchor* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const
+  {
+    TRACE_SERIALIZE (this);
+    switch (u.format) {
+    case 1: return_trace (reinterpret_cast<Anchor *> (u.format1.copy (c)));
+    case 2: return_trace (reinterpret_cast<Anchor *> (u.format2.copy (c)));
+    case 3: return_trace (reinterpret_cast<Anchor *> (u.format3.copy (c, layout_variation_idx_map)));
+    default:return_trace (nullptr);
+    }
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    switch (u.format) {
+    case 1: case 2:
+      return;
+    case 3:
+      u.format3.collect_variation_indices (c);
+      return;
+    default: return;
+    }
+  }
+
   protected:
   union {
   HBUINT16              format;         /* Format identifier */
@@ -374,11 +526,46 @@
                             unsigned int cols, bool *found) const
   {
     *found = false;
-    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
+    if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
     *found = !matrixZ[row * cols + col].is_null ();
     return this+matrixZ[row * cols + col];
   }
 
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  Iterator index_iter) const
+  {
+    for (unsigned i : index_iter)
+      (this+matrixZ[i]).collect_variation_indices (c);
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  bool serialize (hb_serialize_context_t *c,
+                  unsigned                num_rows,
+                  AnchorMatrix const     *offset_matrix,
+                  const hb_map_t         *layout_variation_idx_map,
+                  Iterator                index_iter)
+  {
+    TRACE_SERIALIZE (this);
+    if (!index_iter) return_trace (false);
+    if (unlikely (!c->extend_min ((*this))))  return_trace (false);
+
+    this->rows = num_rows;
+    for (const unsigned i : index_iter)
+    {
+      auto *offset = c->embed (offset_matrix->matrixZ[i]);
+      if (!offset) return_trace (false);
+      offset->serialize_copy (c, offset_matrix->matrixZ[i],
+                              offset_matrix, c->to_bias (this),
+                              hb_serialize_context_t::Head,
+                              layout_variation_idx_map);
+    }
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
   {
     TRACE_SANITIZE (this);
@@ -392,8 +579,7 @@
   }
 
   HBUINT16      rows;                   /* Number of rows */
-  protected:
-  UnsizedArrayOf<OffsetTo<Anchor> >
+  UnsizedArrayOf<OffsetTo<Anchor>>
                 matrixZ;                /* Matrix of offsets to Anchor tables--
                                          * from beginning of AnchorMatrix table */
   public:
@@ -405,12 +591,34 @@
 {
   friend struct MarkArray;
 
+  unsigned get_class () const { return (unsigned) klass; }
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
   }
 
+  MarkRecord *copy (hb_serialize_context_t *c,
+                    const void             *src_base,
+                    unsigned                dst_bias,
+                    const hb_map_t         *klass_mapping,
+                    const hb_map_t         *layout_variation_idx_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    out->klass = klass_mapping->get (klass);
+    out->markAnchor.serialize_copy (c, markAnchor, src_base, dst_bias, hb_serialize_context_t::Head, layout_variation_idx_map);
+    return_trace (out);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const void *src_base) const
+  {
+    (src_base+markAnchor).collect_variation_indices (c);
+  }
+
   protected:
   HBUINT16      klass;                  /* Class defined for this mark */
   OffsetTo<Anchor>
@@ -446,8 +654,8 @@
     glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
     hb_glyph_position_t &o = buffer->cur_pos();
-    o.x_offset = round (base_x - mark_x);
-    o.y_offset = round (base_y - mark_y);
+    o.x_offset = roundf (base_x - mark_x);
+    o.y_offset = roundf (base_y - mark_y);
     o.attach_type() = ATTACH_TYPE_MARK;
     o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
@@ -456,6 +664,21 @@
     return_trace (true);
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_source_of (Iterator, MarkRecord))>
+  bool serialize (hb_serialize_context_t *c,
+                  const hb_map_t         *klass_mapping,
+                  const hb_map_t         *layout_variation_idx_map,
+                  const void             *base,
+                  Iterator                it)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->check_assign (len, it.len ()))) return_trace (false);
+    c->copy_all (it, base, c->to_bias (this), klass_mapping, layout_variation_idx_map);
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -471,8 +694,22 @@
   bool intersects (const hb_set_t *glyphs) const
   { return (this+coverage).intersects (glyphs); }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if (!valueFormat.has_device ()) return;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (c->glyph_set)
+    ;
+
+    if (!it) return;
+    valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
+  }
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
@@ -489,11 +726,48 @@
     return_trace (true);
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  const void *src,
+                  Iterator it,
+                  ValueFormat valFormat,
+                  const hb_map_t *layout_variation_idx_map)
+  {
+    auto out = c->extend_min (*this);
+    if (unlikely (!out)) return;
+    if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+
+    + it
+    | hb_map (hb_second)
+    | hb_apply ([&] (hb_array_t<const Value> _)
+                { valFormat.serialize_copy (c, src, &_, layout_variation_idx_map); })
+    ;
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize (c, this).serialize (c, glyphs);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, this, it, valueFormat, c->plan->layout_variation_idx_map);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -523,8 +797,29 @@
   bool intersects (const hb_set_t *glyphs) const
   { return (this+coverage).intersects (glyphs); }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if (!valueFormat.has_device ()) return;
+
+    auto it =
+    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+    | hb_filter (c->glyph_set, hb_first)
+    ;
+
+    if (!it) return;
+
+    unsigned sub_length = valueFormat.get_len ();
+    const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length);
+
+    for (unsigned i : + it
+                      | hb_map (hb_second))
+      valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length));
+
+  }
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
@@ -545,11 +840,56 @@
     return_trace (true);
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  const void *src,
+                  Iterator it,
+                  ValueFormat valFormat,
+                  const hb_map_t *layout_variation_idx_map)
+  {
+    auto out = c->extend_min (*this);
+    if (unlikely (!out)) return;
+    if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+    if (unlikely (!c->check_assign (valueCount, it.len ()))) return;
+
+    + it
+    | hb_map (hb_second)
+    | hb_apply ([&] (hb_array_t<const Value> _)
+                { valFormat.serialize_copy (c, src, &_, layout_variation_idx_map); })
+    ;
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize (c, this).serialize (c, glyphs);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned sub_length = valueFormat.get_len ();
+    auto values_array = values.as_array (valueCount * sub_length);
+
+    auto it =
+    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+    | hb_filter (glyphset, hb_first)
+    | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
+                              {
+                                return hb_pair (glyph_map[_.first],
+                                                values_array.sub_array (_.second * sub_length,
+                                                                        sub_length));
+                              })
+    ;
+
+    bool ret = bool (it);
+    SinglePos_serialize (c->serializer, this, it, valueFormat, c->plan->layout_variation_idx_map);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -576,14 +916,52 @@
 
 struct SinglePos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  unsigned get_format (Iterator glyph_val_iter_pairs)
+  {
+    hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
+
+    for (const auto iter : glyph_val_iter_pairs)
+      for (const auto _ : hb_zip (iter.second, first_val_iter))
+        if (_.first != _.second)
+          return 2;
+
+    return 1;
+  }
+
+
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  const void *src,
+                  Iterator glyph_val_iter_pairs,
+                  ValueFormat valFormat,
+                  const hb_map_t *layout_variation_idx_map)
+  {
+    if (unlikely (!c->extend_min (u.format))) return;
+    unsigned format = 2;
+
+    if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs);
+
+    u.format = format;
+    switch (u.format) {
+    case 1: u.format1.serialize (c, src, glyph_val_iter_pairs, valFormat, layout_variation_idx_map);
+            return;
+    case 2: u.format2.serialize (c, src, glyph_val_iter_pairs, valFormat, layout_variation_idx_map);
+            return;
+    default:return;
+    }
+  }
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -596,13 +974,64 @@
   } u;
 };
 
+template<typename Iterator>
+static void
+SinglePos_serialize (hb_serialize_context_t *c,
+                     const void *src,
+                     Iterator it,
+                     ValueFormat valFormat,
+                     const hb_map_t *layout_variation_idx_map)
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, valFormat, layout_variation_idx_map); }
+
 
 struct PairValueRecord
 {
   friend struct PairSet;
 
+  int cmp (hb_codepoint_t k) const
+  { return secondGlyph.cmp (k); }
+
+  struct serialize_closure_t
+  {
+    const void          *base;
+    const ValueFormat   *valueFormats;
+    unsigned            len1; /* valueFormats[0].get_len() */
+    const hb_map_t      *glyph_map;
+    const hb_map_t      *layout_variation_idx_map;
+  };
+
+  bool serialize (hb_serialize_context_t *c,
+                  serialize_closure_t *closure) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (*this);
+    if (unlikely (!c->extend_min (out))) return_trace (false);
+
+    out->secondGlyph = (*closure->glyph_map)[secondGlyph];
+
+    closure->valueFormats[0].serialize_copy (c, closure->base, &values[0], closure->layout_variation_idx_map);
+    closure->valueFormats[1].serialize_copy (c, closure->base, &values[closure->len1], closure->layout_variation_idx_map);
+
+    return_trace (true);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const ValueFormat *valueFormats,
+                                  const void *base) const
+  {
+    unsigned record1_len = valueFormats[0].get_len ();
+    unsigned record2_len = valueFormats[1].get_len ();
+    const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
+
+    if (valueFormats[0].has_device ())
+      valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
+
+    if (valueFormats[1].has_device ())
+      valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
+  }
+
   protected:
-  GlyphID       secondGlyph;            /* GlyphID of second glyph in the
+  HBGlyphID     secondGlyph;            /* GlyphID of second glyph in the
                                          * pair--first glyph is listed in the
                                          * Coverage table */
   ValueRecord   values;                 /* Positioning data for the first glyph
@@ -616,7 +1045,7 @@
   friend struct PairPosFormat1;
 
   bool intersects (const hb_set_t *glyphs,
-                          const ValueFormat *valueFormats) const
+                   const ValueFormat *valueFormats) const
   {
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
@@ -634,7 +1063,7 @@
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c,
-                              const ValueFormat *valueFormats) const
+                       const ValueFormat *valueFormats) const
   {
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
@@ -644,9 +1073,27 @@
     c->input->add_array (&record->secondGlyph, len, record_size);
   }
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const ValueFormat *valueFormats) const
+  {
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned count = len;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (c->glyph_set->has (record->secondGlyph))
+      { record->collect_variation_indices (c, valueFormats, this); }
+
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+  }
+
   bool apply (hb_ot_apply_context_t *c,
-                     const ValueFormat *valueFormats,
-                     unsigned int pos) const
+              const ValueFormat *valueFormats,
+              unsigned int pos) const
   {
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
@@ -654,41 +1101,66 @@
     unsigned int len2 = valueFormats[1].get_len ();
     unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
 
-    unsigned int count = len;
-
-    /* Hand-coded bsearch. */
-    if (unlikely (!count))
-      return_trace (false);
-    hb_codepoint_t x = buffer->info[pos].codepoint;
-    int min = 0, max = (int) count - 1;
-    while (min <= max)
+    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
+                                                &firstPairValueRecord,
+                                                len,
+                                                record_size);
+    if (record)
     {
-      int mid = ((unsigned int) min + (unsigned int) max) / 2;
-      const PairValueRecord *record = &StructAtOffset<PairValueRecord> (&firstPairValueRecord, record_size * mid);
-      hb_codepoint_t mid_x = record->secondGlyph;
-      if (x < mid_x)
-        max = mid - 1;
-      else if (x > mid_x)
-        min = mid + 1;
-      else
-      {
-        /* Note the intentional use of "|" instead of short-circuit "||". */
-        if (valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()) |
-            valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]))
-          buffer->unsafe_to_break (buffer->idx, pos + 1);
-        if (len2)
-          pos++;
-        buffer->idx = pos;
-        return_trace (true);
-      }
+      /* Note the intentional use of "|" instead of short-circuit "||". */
+      if (valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()) |
+          valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]))
+        buffer->unsafe_to_break (buffer->idx, pos + 1);
+      if (len2)
+        pos++;
+      buffer->idx = pos;
+      return_trace (true);
+    }
+    return_trace (false);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const ValueFormat valueFormats[2]) const
+  {
+    TRACE_SUBSET (this);
+    auto snap = c->serializer->snapshot ();
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->len = 0;
+
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+
+    PairValueRecord::serialize_closure_t closure =
+    {
+      this,
+      valueFormats,
+      len1,
+      &glyph_map,
+      c->plan->layout_variation_idx_map
+    };
+
+    const PairValueRecord *record = &firstPairValueRecord;
+    unsigned count = len, num = 0;
+    for (unsigned i = 0; i < count; i++)
+    {
+      if (glyphset.has (record->secondGlyph)
+         && record->serialize (c->serializer, &closure)) num++;
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
     }
 
-    return_trace (false);
+    out->len = num;
+    if (!num) c->serializer->revert (snap);
+    return_trace (num);
   }
 
   struct sanitize_closure_t
   {
-    const void *base;
     const ValueFormat *valueFormats;
     unsigned int len1; /* valueFormats[0].get_len() */
     unsigned int stride; /* 1 + len1 + len2 */
@@ -705,8 +1177,8 @@
 
     unsigned int count = len;
     const PairValueRecord *record = &firstPairValueRecord;
-    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));
+    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
+                  closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
   }
 
   protected:
@@ -722,21 +1194,37 @@
 {
   bool intersects (const hb_set_t *glyphs) const
   {
-    unsigned int count = pairSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (glyphs->has (iter.get_glyph ()) &&
-          (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
-        return true;
-    }
-    return false;
+    return
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map ([glyphs, this] (const OffsetTo<PairSet> &_)
+              { return (this+_).intersects (glyphs, valueFormat); })
+    | hb_any
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
+
+    auto it =
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    if (!it) return;
+    + it
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
     unsigned int count = pairSet.len;
     for (unsigned int i = 0; i < count; i++)
       (this+pairSet[i]).collect_glyphs (c, valueFormat);
@@ -761,8 +1249,43 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    out->valueFormat[0] = valueFormat[0];
+    out->valueFormat[1] = valueFormat[1];
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+
+    + hb_zip (this+coverage, pairSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter ([this, c, out] (const OffsetTo<PairSet>& _)
+                 {
+                   auto *o = out->pairSet.serialize_append (c->serializer);
+                   if (unlikely (!o)) return false;
+                   auto snap = c->serializer->snapshot ();
+                   bool ret = o->serialize_subset (c, _, this, valueFormat);
+                   if (!ret)
+                   {
+                     out->pairSet.pop ();
+                     c->serializer->revert (snap);
+                   }
+                   return ret;
+                 },
+                 hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    out->coverage.serialize (c->serializer, out)
+                 .serialize (c->serializer, new_coverage.iter ());
+
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -775,7 +1298,6 @@
     unsigned int len2 = valueFormat[1].get_len ();
     PairSet::sanitize_closure_t closure =
     {
-      this,
       valueFormat,
       len1,
       1 + len1 + len2
@@ -810,10 +1332,43 @@
            (this+classDef2).intersects (glyphs);
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
+
+    hb_set_t class1_set, class2_set;
+    for (const unsigned cp : c->glyph_set->iter ())
+    {
+      unsigned klass1 = (this+classDef1).get (cp);
+      unsigned klass2 = (this+classDef2).get (cp);
+      class1_set.add (klass1);
+      class2_set.add (klass2);
+    }
+
+    if (class1_set.is_empty () || class2_set.is_empty ()) return;
+
+    unsigned len1 = valueFormat1.get_len ();
+    unsigned len2 = valueFormat2.get_len ();
+    const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2));
+    for (const unsigned class1_idx : class1_set.iter ())
+    {
+      for (const unsigned class2_idx : class2_set.iter ())
+      {
+        unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+        if (valueFormat1.has_device ())
+          valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1));
+
+        if (valueFormat2.has_device ())
+          valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2));
+      }
+    }
+  }
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    if (unlikely (!(this+classDef2).add_coverage (c->input))) return;
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+classDef2).collect_coverage (c->input))) return;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
@@ -853,8 +1408,50 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    out->valueFormat1 = valueFormat1;
+    out->valueFormat2 = valueFormat2;
+
+    hb_map_t klass1_map;
+    out->classDef1.serialize_subset (c, classDef1, this, &klass1_map);
+    out->class1Count = klass1_map.get_population ();
+
+    hb_map_t klass2_map;
+    out->classDef2.serialize_subset (c, classDef2, this, &klass2_map);
+    out->class2Count = klass2_map.get_population ();
+
+    unsigned len1 = valueFormat1.get_len ();
+    unsigned len2 = valueFormat2.get_len ();
+
+    + hb_range ((unsigned) class1Count)
+    | hb_filter (klass1_map)
+    | hb_apply ([&] (const unsigned class1_idx)
+                {
+                  + hb_range ((unsigned) class2Count)
+                  | hb_filter (klass2_map)
+                  | hb_apply ([&] (const unsigned class2_idx)
+                              {
+                                unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+                                valueFormat1.serialize_copy (c->serializer, this, &values[idx], c->plan->layout_variation_idx_map);
+                                valueFormat2.serialize_copy (c->serializer, this, &values[idx + len1], c->plan->layout_variation_idx_map);
+                              })
+                  ;
+                })
+    ;
+
+    const hb_set_t &glyphset = *c->plan->_glyphset_gsub;
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting (glyph_map)
+    ;
+
+    out->coverage.serialize (c->serializer, out).serialize (c->serializer, it);
+    return_trace (out->class1Count && out->class2Count && bool (it));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -909,14 +1506,14 @@
 
 struct PairPos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -940,6 +1537,27 @@
     return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
   }
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
+                                  const void *src_base) const
+  {
+    (src_base+entryAnchor).collect_variation_indices (c);
+    (src_base+exitAnchor).collect_variation_indices (c);
+  }
+
+  EntryExitRecord* copy (hb_serialize_context_t *c,
+                         const void *src_base,
+                         const void *dst_base,
+                         const hb_map_t *layout_variation_idx_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    out->entryAnchor.serialize_copy (c, entryAnchor, src_base, c->to_bias (dst_base), hb_serialize_context_t::Head, layout_variation_idx_map);
+    out->exitAnchor.serialize_copy (c, exitAnchor, src_base, c->to_bias (dst_base), hb_serialize_context_t::Head, layout_variation_idx_map);
+    return_trace (out);
+  }
+
   protected:
   OffsetTo<Anchor>
                 entryAnchor;            /* Offset to EntryAnchor table--from
@@ -961,8 +1579,19 @@
   bool intersects (const hb_set_t *glyphs) const
   { return (this+coverage).intersects (glyphs); }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+coverage, entryExitRecord)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
+    ;
+  }
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
-  { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
+  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
@@ -995,32 +1624,32 @@
     /* Main-direction adjustment */
     switch (c->direction) {
       case HB_DIRECTION_LTR:
-        pos[i].x_advance  = round (exit_x) + pos[i].x_offset;
+        pos[i].x_advance  = roundf (exit_x) + pos[i].x_offset;
 
-        d = round (entry_x) + pos[j].x_offset;
+        d = roundf (entry_x) + pos[j].x_offset;
         pos[j].x_advance -= d;
         pos[j].x_offset  -= d;
         break;
       case HB_DIRECTION_RTL:
-        d = round (exit_x) + pos[i].x_offset;
+        d = roundf (exit_x) + pos[i].x_offset;
         pos[i].x_advance -= d;
         pos[i].x_offset  -= d;
 
-        pos[j].x_advance  = round (entry_x) + pos[j].x_offset;
+        pos[j].x_advance  = roundf (entry_x) + pos[j].x_offset;
         break;
       case HB_DIRECTION_TTB:
-        pos[i].y_advance  = round (exit_y) + pos[i].y_offset;
+        pos[i].y_advance  = roundf (exit_y) + pos[i].y_offset;
 
-        d = round (entry_y) + pos[j].y_offset;
+        d = roundf (entry_y) + pos[j].y_offset;
         pos[j].y_advance -= d;
         pos[j].y_offset  -= d;
         break;
       case HB_DIRECTION_BTT:
-        d = round (exit_y) + pos[i].y_offset;
+        d = roundf (exit_y) + pos[i].y_offset;
         pos[i].y_advance -= d;
         pos[i].y_offset  -= d;
 
-        pos[j].y_advance  = round (entry_y);
+        pos[j].y_advance  = roundf (entry_y);
         break;
       case HB_DIRECTION_INVALID:
       default:
@@ -1063,15 +1692,58 @@
     else
       pos[child].x_offset = x_offset;
 
+    /* If parent was attached to child, break them free.
+     * https://github.com/harfbuzz/harfbuzz/issues/2469
+     */
+    if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
+      pos[parent].attach_chain() = 0;
+
     buffer->idx++;
     return_trace (true);
   }
 
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  Iterator it,
+                  const void *src_base,
+                  const hb_map_t *layout_variation_idx_map)
+  {
+    if (unlikely (!c->extend_min ((*this)))) return;
+    this->format = 1;
+    this->entryExitRecord.len = it.len ();
+
+    for (const EntryExitRecord& entry_record : + it
+                                               | hb_map (hb_second))
+      c->copy (entry_record, src_base, this, layout_variation_idx_map);
+
+    auto glyphs =
+    + it
+    | hb_map_retains_sorting (hb_first)
+    ;
+
+    coverage.serialize (c, this).serialize (c, glyphs);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    auto it =
+    + hb_zip (this+coverage, entryExitRecord)
+    | hb_filter (glyphset, hb_first)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
+                              { return hb_pair (glyph_map[p.first], p.second);})
+    ;
+
+    bool ret = bool (it);
+    out->serialize (c->serializer, it, this, c->plan->layout_variation_idx_map);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1094,13 +1766,13 @@
 
 struct CursivePos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1118,16 +1790,73 @@
                                          * mark-minor--
                                          * ordered by class--zero-based. */
 
+static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
+                                                 const MarkArray &mark_array,
+                                                 const hb_set_t  &glyphset,
+                                                 hb_map_t*        klass_mapping /* INOUT */)
+{
+  hb_set_t orig_classes;
+
+  + hb_zip (mark_coverage, mark_array)
+  | hb_filter (glyphset, hb_first)
+  | hb_map (hb_second)
+  | hb_map (&MarkRecord::get_class)
+  | hb_sink (orig_classes)
+  ;
+
+  unsigned idx = 0;
+  for (auto klass : orig_classes.iter ())
+  {
+    if (klass_mapping->has (klass)) continue;
+    klass_mapping->set (klass, idx);
+    idx++;
+  }
+}
+
 struct MarkBasePosFormat1
 {
   bool intersects (const hb_set_t *glyphs) const
-  { return (this+markCoverage).intersects (glyphs) &&
-           (this+baseCoverage).intersects (glyphs); }
+  {
+    return (this+markCoverage).intersects (glyphs) &&
+           (this+baseCoverage).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
+    ;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
+
+    unsigned basecount = (this+baseArray).rows;
+    auto base_iter =
+    + hb_zip (this+baseCoverage, hb_range (basecount))
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    hb_sorted_vector_t<unsigned> base_indexes;
+    for (const unsigned row : base_iter)
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (base_indexes)
+      ;
+    }
+    (this+baseArray).collect_variation_indices (c, base_indexes.iter ());
+  }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
-    if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return;
+    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return;
   }
 
   const Coverage &get_coverage () const { return this+markCoverage; }
@@ -1175,8 +1904,70 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+    if (!klass_mapping.get_population ()) return_trace (false);
+    out->classCount = klass_mapping.get_population ();
+
+    auto mark_iter =
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + mark_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->markCoverage.serialize (c->serializer, out)
+                          .serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    out->markArray.serialize (c->serializer, out)
+                  .serialize (c->serializer, &klass_mapping, c->plan->layout_variation_idx_map, &(this+markArray), + mark_iter
+                                                                                                                   | hb_map (hb_second));
+
+    unsigned basecount = (this+baseArray).rows;
+    auto base_iter =
+    + hb_zip (this+baseCoverage, hb_range (basecount))
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    new_coverage.reset ();
+    + base_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->baseCoverage.serialize (c->serializer, out)
+                          .serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    hb_sorted_vector_t<unsigned> base_indexes;
+    for (const unsigned row : + base_iter
+                              | hb_map (hb_second))
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (base_indexes)
+      ;
+    }
+    out->baseArray.serialize (c->serializer, out)
+                  .serialize (c->serializer, base_iter.len (), &(this+baseArray), c->plan->layout_variation_idx_map, base_indexes.iter ());
+
+    return_trace (true);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1210,13 +2001,13 @@
 
 struct MarkBasePos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1242,13 +2033,53 @@
 struct MarkLigPosFormat1
 {
   bool intersects (const hb_set_t *glyphs) const
-  { return (this+markCoverage).intersects (glyphs) &&
-           (this+ligatureCoverage).intersects (glyphs); }
+  {
+    return (this+markCoverage).intersects (glyphs) &&
+           (this+ligatureCoverage).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+markCoverage, this+markArray)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
+    ;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
+
+    unsigned ligcount = (this+ligatureArray).len;
+    auto lig_iter =
+    + hb_zip (this+ligatureCoverage, hb_range (ligcount))
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    const LigatureArray& lig_array = this+ligatureArray;
+    for (const unsigned i : lig_iter)
+    {
+      hb_sorted_vector_t<unsigned> lig_indexes;
+      unsigned row_count = lig_array[i].rows;
+      for (unsigned row : + hb_range (row_count))
+      {
+        + hb_range ((unsigned) classCount)
+        | hb_filter (klass_mapping)
+        | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+        | hb_sink (lig_indexes)
+        ;
+      }
+
+      lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
+    }
+  }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
-    if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return;
+    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
   }
 
   const Coverage &get_coverage () const { return this+markCoverage; }
@@ -1289,7 +2120,7 @@
     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
     if (lig_id && lig_id == mark_id && mark_comp > 0)
-      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
+      comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
     else
       comp_index = comp_count - 1;
 
@@ -1335,13 +2166,13 @@
 
 struct MarkLigPos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1362,13 +2193,47 @@
 struct MarkMarkPosFormat1
 {
   bool intersects (const hb_set_t *glyphs) const
-  { return (this+mark1Coverage).intersects (glyphs) &&
-           (this+mark2Coverage).intersects (glyphs); }
+  {
+    return (this+mark1Coverage).intersects (glyphs) &&
+           (this+mark2Coverage).intersects (glyphs);
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+mark1Coverage, this+mark1Array)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
+    ;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
+
+    unsigned mark2_count = (this+mark2Array).rows;
+    auto mark2_iter =
+    + hb_zip (this+mark2Coverage, hb_range (mark2_count))
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    ;
+
+    hb_sorted_vector_t<unsigned> mark2_indexes;
+    for (const unsigned row : mark2_iter)
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (mark2_indexes)
+      ;
+    }
+    (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
+  }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return;
-    if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return;
+    if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
+    if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
   }
 
   const Coverage &get_coverage () const { return this+mark1Coverage; }
@@ -1395,12 +2260,15 @@
     unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
     unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
 
-    if (likely (id1 == id2)) {
+    if (likely (id1 == id2))
+    {
       if (id1 == 0) /* Marks belonging to the same base. */
         goto good;
       else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
         goto good;
-    } else {
+    }
+    else
+    {
       /* If ligature ids don't match, it may be the case that one of the marks
        * itself is a ligature.  In which case match. */
       if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
@@ -1420,8 +2288,70 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_map_t klass_mapping;
+    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
+
+    if (!klass_mapping.get_population ()) return_trace (false);
+    out->classCount = klass_mapping.get_population ();
+
+    auto mark1_iter =
+    + hb_zip (this+mark1Coverage, this+mark1Array)
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + mark1_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->mark1Coverage.serialize (c->serializer, out)
+                           .serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    out->mark1Array.serialize (c->serializer, out)
+                   .serialize (c->serializer, &klass_mapping, c->plan->layout_variation_idx_map, &(this+mark1Array), + mark1_iter
+                                                                                                                     | hb_map (hb_second));
+
+    unsigned mark2count = (this+mark2Array).rows;
+    auto mark2_iter =
+    + hb_zip (this+mark2Coverage, hb_range (mark2count))
+    | hb_filter (glyphset, hb_first)
+    ;
+
+    new_coverage.reset ();
+    + mark2_iter
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    if (!out->mark2Coverage.serialize (c->serializer, out)
+                           .serialize (c->serializer, new_coverage.iter ()))
+      return_trace (false);
+
+    hb_sorted_vector_t<unsigned> mark2_indexes;
+    for (const unsigned row : + mark2_iter
+                              | hb_map (hb_second))
+    {
+      + hb_range ((unsigned) classCount)
+      | hb_filter (klass_mapping)
+      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
+      | hb_sink (mark2_indexes)
+      ;
+    }
+    out->mark2Array.serialize (c->serializer, out)
+                   .serialize (c->serializer, mark2_iter.len (), &(this+mark2Array), c->plan->layout_variation_idx_map, mark2_indexes.iter ());
+
+    return_trace (true);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1457,13 +2387,13 @@
 
 struct MarkMarkPos
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1509,24 +2439,30 @@
     Extension           = 9
   };
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, lookup_type);
     switch (lookup_type) {
-    case Single:                return_trace (u.single.dispatch (c));
-    case Pair:                  return_trace (u.pair.dispatch (c));
-    case Cursive:               return_trace (u.cursive.dispatch (c));
-    case MarkBase:              return_trace (u.markBase.dispatch (c));
-    case MarkLig:               return_trace (u.markLig.dispatch (c));
-    case MarkMark:              return_trace (u.markMark.dispatch (c));
-    case Context:               return_trace (u.context.dispatch (c));
-    case ChainContext:          return_trace (u.chainContext.dispatch (c));
-    case Extension:             return_trace (u.extension.dispatch (c));
+    case Single:                return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
+    case Pair:                  return_trace (u.pair.dispatch (c, hb_forward<Ts> (ds)...));
+    case Cursive:               return_trace (u.cursive.dispatch (c, hb_forward<Ts> (ds)...));
+    case MarkBase:              return_trace (u.markBase.dispatch (c, hb_forward<Ts> (ds)...));
+    case MarkLig:               return_trace (u.markLig.dispatch (c, hb_forward<Ts> (ds)...));
+    case MarkMark:              return_trace (u.markMark.dispatch (c, hb_forward<Ts> (ds)...));
+    case Context:               return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
+    case ChainContext:          return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
+    case Extension:             return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
     default:                    return_trace (c->default_return_value ());
     }
   }
 
+  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c, lookup_type);
+  }
+
   protected:
   union {
   SinglePos             single;
@@ -1571,21 +2507,40 @@
   hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   { return dispatch (c); }
 
-  template <typename set_t>
-  void add_coverage (set_t *glyphs) const
+  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
   {
-    hb_add_coverage_context_t<set_t> c (glyphs);
+    if (c->is_lookup_visited (this_index))
+      return hb_closure_lookups_context_t::default_return_value ();
+
+    c->set_lookup_visited (this_index);
+    if (!intersects (c->glyphs))
+    {
+      c->set_lookup_inactive (this_index);
+      return hb_closure_lookups_context_t::default_return_value ();
+    }
+    c->set_recurse_func (dispatch_closure_lookups_recurse_func);
+
+    hb_closure_lookups_context_t::return_t ret = dispatch (c);
+    return ret;
+  }
+
+  template <typename set_t>
+  void collect_coverage (set_t *glyphs) const
+  {
+    hb_collect_coverage_context_t<set_t> c (glyphs);
     dispatch (&c);
   }
 
-  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
+  static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
 
   template <typename context_t>
   static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
-  { return Lookup::dispatch<SubTable> (c); }
+  HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index);
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
 
   bool subset (hb_subset_context_t *c) const
   { return Lookup::subset<SubTable> (c); }
@@ -1604,21 +2559,39 @@
   static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
 
   const PosLookup& get_lookup (unsigned int i) const
-  { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
+  { return static_cast<const PosLookup &> (GSUBGPOS::get_lookup (i)); }
 
   static inline void position_start (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);
 
   bool subset (hb_subset_context_t *c) const
-  { return GSUBGPOS::subset<PosLookup> (c); }
+  {
+    hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_features);
+    return GSUBGPOS::subset<PosLookup> (&l);
+  }
 
   bool sanitize (hb_sanitize_context_t *c) const
   { return GSUBGPOS::sanitize<PosLookup> (c); }
 
-  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
+  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
                                    hb_face_t *face) const;
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
+    {
+      if (!c->gpos_lookups->has (i)) continue;
+      const PosLookup &l = get_lookup (i);
+      l.dispatch (c);
+    }
+  }
+
+  void closure_lookups (hb_face_t      *face,
+                        const hb_set_t *glyphs,
+                        hb_set_t       *lookup_indexes /* IN/OUT */) const
+  { GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); }
+
   typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
 };
 
@@ -1732,14 +2705,21 @@
 
 /* Out-of-class implementation for methods recursing */
 
+#ifndef HB_NO_OT_LAYOUT
 template <typename context_t>
-/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
+/*static*/ typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
   return l.dispatch (c);
 }
 
-/*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
+/*static*/ inline hb_closure_lookups_context_t::return_t PosLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
+{
+  const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (this_index);
+  return l.closure_lookups (c, this_index);
+}
+
+/*static*/ bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
   const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
@@ -1751,6 +2731,7 @@
   c->set_lookup_props (saved_lookup_props);
   return ret;
 }
+#endif
 
 
 } /* namespace OT */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh
index 288c07b..de49c4e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh
@@ -34,10 +34,12 @@
 
 namespace OT {
 
+typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
 
-static inline void SingleSubst_serialize (hb_serialize_context_t *c,
-                                          hb_array_t<const GlyphID> glyphs,
-                                          hb_array_t<const GlyphID> substitutes);
+template<typename Iterator>
+static void SingleSubst_serialize (hb_serialize_context_t *c,
+                                   Iterator it);
+
 
 struct SingleSubstFormat1
 {
@@ -46,35 +48,30 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      /* TODO Switch to range-based API to work around malicious fonts.
-       * https://github.com/harfbuzz/harfbuzz/issues/363 */
-      hb_codepoint_t glyph_id = iter.get_glyph ();
-      if (c->glyphs->has (glyph_id))
-        c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
-    }
+    unsigned d = deltaGlyphID;
+    + hb_iter (this+coverage)
+    | hb_filter (*c->glyphs)
+    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    | hb_sink (c->output)
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      /* TODO Switch to range-based API to work around malicious fonts.
-       * https://github.com/harfbuzz/harfbuzz/issues/363 */
-      hb_codepoint_t glyph_id = iter.get_glyph ();
-      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
-    }
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    unsigned d = deltaGlyphID;
+    + hb_iter (this+coverage)
+    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
+    | hb_sink (c->output)
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -91,34 +88,41 @@
     return_trace (true);
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs,
-                  int delta)
+                  Iterator glyphs,
+                  unsigned delta)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
-    deltaGlyphID.set (delta); /* TODO(serialize) overflow? */
+    c->check_assign (deltaGlyphID, delta);
     return_trace (true);
   }
 
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset;
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
-    hb_vector_t<GlyphID> from;
-    hb_vector_t<GlyphID> to;
+
     hb_codepoint_t delta = deltaGlyphID;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (!glyphset.has (iter.get_glyph ())) continue;
-      from.push ()->set (glyph_map[iter.get_glyph ()]);
-      to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]);
-    }
-    c->serializer->propagate_error (from, to);
-    SingleSubst_serialize (c->serializer, from, to);
-    return_trace (from.length);
+
+    auto it =
+    + hb_iter (this+coverage)
+    | hb_filter (glyphset)
+    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
+                                return hb_codepoint_pair_t (g,
+                                                            (g + delta) & 0xFFFF); })
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
+                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    bool ret = bool (it);
+    SingleSubst_serialize (c->serializer, it);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -132,8 +136,8 @@
   OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  HBINT16       deltaGlyphID;           /* Add to original GlyphID to get
-                                         * substitute GlyphID */
+  HBUINT16      deltaGlyphID;           /* Add to original GlyphID to get
+                                         * substitute GlyphID, modulo 0x10000 */
   public:
   DEFINE_SIZE_STATIC (6);
 };
@@ -145,35 +149,28 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    unsigned int count = substitute.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-        c->out->add (substitute[iter.get_coverage ()]);
-    }
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    unsigned int count = substitute.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      c->output->add (substitute[iter.get_coverage ()]);
-    }
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    + hb_zip (this+coverage, substitute)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -188,11 +185,21 @@
     return_trace (true);
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_source_of (Iterator,
+                                                hb_codepoint_pair_t))>
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs,
-                  hb_array_t<const GlyphID> substitutes)
+                  Iterator it)
   {
     TRACE_SERIALIZE (this);
+    auto substitutes =
+      + it
+      | hb_map (hb_second)
+      ;
+    auto glyphs =
+      + it
+      | hb_map_retains_sorting (hb_first)
+      ;
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
@@ -202,19 +209,20 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    const hb_set_t &glyphset = *c->plan->glyphset;
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
     const hb_map_t &glyph_map = *c->plan->glyph_map;
-    hb_vector_t<GlyphID> from;
-    hb_vector_t<GlyphID> to;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (!glyphset.has (iter.get_glyph ())) continue;
-      from.push ()->set (glyph_map[iter.get_glyph ()]);
-      to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]);
-    }
-    c->serializer->propagate_error (from, to);
-    SingleSubst_serialize (c->serializer, from, to);
-    return_trace (from.length);
+
+    auto it =
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID &> p) -> hb_codepoint_pair_t
+                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    bool ret = bool (it);
+    SingleSubst_serialize (c->serializer, it);
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -228,7 +236,7 @@
   OffsetTo<Coverage>
                 coverage;               /* Offset to Coverage table--from
                                          * beginning of Substitution table */
-  ArrayOf<GlyphID>
+  ArrayOf<HBGlyphID>
                 substitute;             /* Array of substitute
                                          * GlyphIDs--ordered by Coverage Index */
   public:
@@ -237,41 +245,44 @@
 
 struct SingleSubst
 {
+
+  template<typename Iterator,
+           hb_requires (hb_is_sorted_source_of (Iterator,
+                                                const hb_codepoint_pair_t))>
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs,
-                  hb_array_t<const GlyphID> substitutes)
+                  Iterator glyphs)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
-    unsigned int format = 2;
-    int delta = 0;
-    if (glyphs.length)
+    unsigned format = 2;
+    unsigned delta = 0;
+    if (glyphs)
     {
       format = 1;
-      /* TODO(serialize) check for wrap-around */
-      delta = substitutes[0] - glyphs[0];
-      for (unsigned int i = 1; i < glyphs.length; i++)
-        if (delta != (int) (substitutes[i] - glyphs[i])) {
-          format = 2;
-          break;
-        }
+      auto get_delta = [=] (hb_codepoint_pair_t _)
+                       { return (unsigned) (_.second - _.first) & 0xFFFF; };
+      delta = get_delta (*glyphs);
+      if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
     }
-    u.format.set (format);
+    u.format = format;
     switch (u.format) {
-    case 1: return_trace (u.format1.serialize (c, glyphs, delta));
-    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes));
+    case 1: return_trace (u.format1.serialize (c,
+                                               + glyphs
+                                               | hb_map_retains_sorting (hb_first),
+                                               delta));
+    case 2: return_trace (u.format2.serialize (c, glyphs));
     default:return_trace (false);
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -284,20 +295,19 @@
   } u;
 };
 
-static inline void
+template<typename Iterator>
+static void
 SingleSubst_serialize (hb_serialize_context_t *c,
-                       hb_array_t<const GlyphID> glyphs,
-                       hb_array_t<const GlyphID> substitutes)
-{ c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); }
+                       Iterator it)
+{ c->start_embed<SingleSubst> ()->serialize (c, it); }
 
 struct Sequence
 {
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_all (substitute, glyphs); }
+
   void closure (hb_closure_context_t *c) const
-  {
-    unsigned int count = substitute.len;
-    for (unsigned int i = 0; i < count; i++)
-      c->out->add (substitute[i]);
-  }
+  { c->output->add_array (substitute.arrayZ, substitute.len); }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   { c->output->add_array (substitute.arrayZ, substitute.len); }
@@ -334,11 +344,30 @@
     return_trace (true);
   }
 
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs)
+                  Iterator subst)
   {
     TRACE_SERIALIZE (this);
-    return_trace (substitute.serialize (c, glyphs));
+    return_trace (substitute.serialize (c, subst));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    if (!intersects (&glyphset)) return_trace (false);
+
+    auto it =
+    + hb_iter (substitute)
+    | hb_map (glyph_map)
+    ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer, it));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -348,7 +377,7 @@
   }
 
   protected:
-  ArrayOf<GlyphID>
+  ArrayOf<HBGlyphID>
                 substitute;             /* String of GlyphIDs to substitute */
   public:
   DEFINE_SIZE_ARRAY (2, substitute);
@@ -361,31 +390,30 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    unsigned int count = sequence.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-        (this+sequence[iter.get_coverage ()]).closure (c);
-    }
+    + hb_zip (this+coverage, sequence)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Sequence &_) { _.closure (c); })
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    unsigned int count = sequence.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+sequence[i]).collect_glyphs (c);
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    + hb_zip (this+coverage, sequence)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -398,9 +426,9 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs,
+                  hb_sorted_array_t<const HBGlyphID> glyphs,
                   hb_array_t<const unsigned int> substitute_len_list,
-                  hb_array_t<const GlyphID> substitute_glyphs_list)
+                  hb_array_t<const HBGlyphID> substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
@@ -419,8 +447,24 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, sequence)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->sequence, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize (c->serializer, out)
+                 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -444,27 +488,27 @@
 struct MultipleSubst
 {
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs,
+                  hb_sorted_array_t<const HBGlyphID> glyphs,
                   hb_array_t<const unsigned int> substitute_len_list,
-                  hb_array_t<const GlyphID> substitute_glyphs_list)
+                  hb_array_t<const HBGlyphID> substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 1;
-    u.format.set (format);
+    u.format = format;
     switch (u.format) {
     case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
     default:return_trace (false);
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -478,12 +522,11 @@
 
 struct AlternateSet
 {
+  bool intersects (const hb_set_t *glyphs) const
+  { return hb_any (alternates, glyphs); }
+
   void closure (hb_closure_context_t *c) const
-  {
-    unsigned int count = alternates.len;
-    for (unsigned int i = 0; i < count; i++)
-      c->out->add (alternates[i]);
-  }
+  { c->output->add_array (alternates.arrayZ, alternates.len); }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   { c->output->add_array (alternates.arrayZ, alternates.len); }
@@ -502,7 +545,7 @@
     unsigned int shift = hb_ctz (lookup_mask);
     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
 
-    /* If alt_index is MAX, randomize feature if it is the rand feature. */
+    /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
     if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
       alt_index = c->random_number () % count + 1;
 
@@ -513,11 +556,44 @@
     return_trace (true);
   }
 
+  unsigned
+  get_alternates (unsigned        start_offset,
+                  unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
+                  hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
+  {
+    if (alternates.len && alternate_count)
+    {
+      + alternates.sub_array (start_offset, alternate_count)
+      | hb_sink (hb_array (alternate_glyphs, *alternate_count))
+      ;
+    }
+    return alternates.len;
+  }
+
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs)
+                  Iterator alts)
   {
     TRACE_SERIALIZE (this);
-    return_trace (alternates.serialize (c, glyphs));
+    return_trace (alternates.serialize (c, alts));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto it =
+      + hb_iter (alternates)
+      | hb_filter (glyphset)
+      | hb_map (glyph_map)
+      ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer, it) &&
+                  out->alternates);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -527,7 +603,7 @@
   }
 
   protected:
-  ArrayOf<GlyphID>
+  ArrayOf<HBGlyphID>
                 alternates;             /* Array of alternate GlyphIDs--in
                                          * arbitrary order */
   public:
@@ -541,35 +617,38 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    unsigned int count = alternateSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-        (this+alternateSet[iter.get_coverage ()]).closure (c);
-    }
+    + hb_zip (this+coverage, alternateSet)
+    | hb_filter (c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    unsigned int count = alternateSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
-    }
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+    + hb_zip (this+coverage, alternateSet)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+
+  unsigned
+  get_glyph_alternates (hb_codepoint_t  gid,
+                        unsigned        start_offset,
+                        unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
+                        hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */) const
+  { return (this+alternateSet[(this+coverage).get_coverage (gid)])
+           .get_alternates (start_offset, alternate_count, alternate_glyphs); }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -582,9 +661,9 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs,
+                  hb_sorted_array_t<const HBGlyphID> glyphs,
                   hb_array_t<const unsigned int> alternate_len_list,
-                  hb_array_t<const GlyphID> alternate_glyphs_list)
+                  hb_array_t<const HBGlyphID> alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
@@ -603,8 +682,24 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, alternateSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize (c->serializer, out)
+                 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -628,27 +723,27 @@
 struct AlternateSubst
 {
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> glyphs,
+                  hb_sorted_array_t<const HBGlyphID> glyphs,
                   hb_array_t<const unsigned int> alternate_len_list,
-                  hb_array_t<const GlyphID> alternate_glyphs_list)
+                  hb_array_t<const HBGlyphID> alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 1;
-    u.format.set (format);
+    u.format = format;
     switch (u.format) {
     case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
     default:return_trace (false);
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -664,40 +759,30 @@
 struct Ligature
 {
   bool intersects (const hb_set_t *glyphs) const
-  {
-    unsigned int count = component.lenP1;
-    for (unsigned int i = 1; i < count; i++)
-      if (!glyphs->has (component[i]))
-        return false;
-    return true;
-  }
+  { return hb_all (component, glyphs); }
 
   void closure (hb_closure_context_t *c) const
   {
-    unsigned int count = component.lenP1;
-    for (unsigned int i = 1; i < count; i++)
-      if (!c->glyphs->has (component[i]))
-        return;
-    c->out->add (ligGlyph);
+    if (!intersects (c->glyphs)) return;
+    c->output->add (ligGlyph);
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
+    c->input->add_array (component.arrayZ, component.get_length ());
     c->output->add (ligGlyph);
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
     if (c->len != component.lenP1)
-      return_trace (false);
+      return false;
 
     for (unsigned int i = 1; i < c->len; i++)
       if (likely (c->glyphs[i] != component[i]))
-        return_trace (false);
+        return false;
 
-    return_trace (true);
+    return true;
   }
 
   bool apply (hb_ot_apply_context_t *c) const
@@ -739,9 +824,11 @@
     return_trace (true);
   }
 
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
   bool serialize (hb_serialize_context_t *c,
-                  GlyphID ligature,
-                  hb_array_t<const GlyphID> components /* Starting from second */)
+                  hb_codepoint_t ligature,
+                  Iterator components /* Starting from second */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
@@ -750,6 +837,25 @@
     return_trace (true);
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
+
+    auto it =
+      + hb_iter (component)
+      | hb_map (glyph_map)
+      ;
+
+    auto *out = c->serializer->start_embed (*this);
+    return_trace (out->serialize (c->serializer,
+                                  glyph_map[ligGlyph],
+                                  it));
+  }
+
   public:
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -758,8 +864,8 @@
   }
 
   protected:
-  GlyphID       ligGlyph;               /* GlyphID of ligature to substitute */
-  HeadlessArrayOf<GlyphID>
+  HBGlyphID     ligGlyph;               /* GlyphID of ligature to substitute */
+  HeadlessArrayOf<HBGlyphID>
                 component;              /* Array of component GlyphIDs--start
                                          * with the second  component--ordered
                                          * in writing direction */
@@ -771,38 +877,38 @@
 {
   bool intersects (const hb_set_t *glyphs) const
   {
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-      if ((this+ligature[i]).intersects (glyphs))
-        return true;
-    return false;
+    return
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
   {
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-      (this+ligature[i]).closure (c);
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Ligature &_) { _.closure (c); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-      (this+ligature[i]).collect_glyphs (c);
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-    unsigned int num_ligs = ligature.len;
-    for (unsigned int i = 0; i < num_ligs; i++)
-    {
-      const Ligature &lig = this+ligature[i];
-      if (lig.would_apply (c))
-        return_trace (true);
-    }
-    return_trace (false);
+    return
+    + hb_iter (ligature)
+    | hb_map (hb_add (this))
+    | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
+    | hb_any
+    ;
   }
 
   bool apply (hb_ot_apply_context_t *c) const
@@ -819,16 +925,16 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> ligatures,
+                  hb_array_t<const HBGlyphID> ligatures,
                   hb_array_t<const unsigned int> component_count_list,
-                  hb_array_t<const GlyphID> &component_list /* Starting from second for each ligature */)
+                  hb_array_t<const HBGlyphID> &component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
     if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
     for (unsigned int i = 0; i < ligatures.length; i++)
     {
-      unsigned int component_count = MAX<int> (component_count_list[i] - 1, 0);
+      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
       if (unlikely (!ligature[i].serialize (c, this)
                                 .serialize (c,
                                             ligatures[i],
@@ -839,6 +945,19 @@
     return_trace (true);
   }
 
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + hb_iter (ligature)
+    | hb_filter (subset_offset_array (c, out->ligature, this))
+    | hb_drain
+    ;
+    return_trace (bool (out->ligature));
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -857,59 +976,55 @@
 {
   bool intersects (const hb_set_t *glyphs) const
   {
-    unsigned int count = ligatureSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (glyphs->has (iter.get_glyph ()) &&
-          (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
-        return true;
-    }
-    return false;
+    return
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
+              { return (this+_).intersects (glyphs); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
   {
-    unsigned int count = ligatureSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-        (this+ligatureSet[iter.get_coverage ()]).closure (c);
-    }
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
-    unsigned int count = ligatureSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
-    }
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
+
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
+    ;
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
     unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
-    if (likely (index == NOT_COVERED)) return_trace (false);
+    if (likely (index == NOT_COVERED)) return false;
 
     const LigatureSet &lig_set = this+ligatureSet[index];
-    return_trace (lig_set.would_apply (c));
+    return lig_set.would_apply (c);
   }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
 
-    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LigatureSet &lig_set = this+ligatureSet[index];
@@ -917,11 +1032,11 @@
   }
 
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> first_glyphs,
+                  hb_sorted_array_t<const HBGlyphID> first_glyphs,
                   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-                  hb_array_t<const GlyphID> ligatures_list,
+                  hb_array_t<const HBGlyphID> ligatures_list,
                   hb_array_t<const unsigned int> component_count_list,
-                  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
+                  hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return_trace (false);
@@ -943,8 +1058,24 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, ligatureSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->ligatureSet, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize (c->serializer, out)
+                 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -968,16 +1099,16 @@
 struct LigatureSubst
 {
   bool serialize (hb_serialize_context_t *c,
-                  hb_array_t<const GlyphID> first_glyphs,
+                  hb_sorted_array_t<const HBGlyphID> first_glyphs,
                   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-                  hb_array_t<const GlyphID> ligatures_list,
+                  hb_array_t<const HBGlyphID> ligatures_list,
                   hb_array_t<const unsigned int> component_count_list,
-                  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
+                  hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return_trace (false);
     unsigned int format = 1;
-    u.format.set (format);
+    u.format = format;
     switch (u.format) {
     case 1: return_trace (u.format1.serialize (c,
                                                first_glyphs,
@@ -989,13 +1120,13 @@
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1015,7 +1146,6 @@
 struct ExtensionSubst : Extension<ExtensionSubst>
 {
   typedef struct SubstLookupSubTable SubTable;
-
   bool is_reverse () const;
 };
 
@@ -1027,7 +1157,7 @@
     if (!(this+coverage).intersects (glyphs))
       return false;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
     unsigned int count;
 
@@ -1046,47 +1176,36 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    if (!intersects (c->glyphs)) return;
 
-    unsigned int count;
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
 
-    count = backtrack.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+backtrack[i]).intersects (c->glyphs))
-        return;
-
-    count = lookahead.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+lookahead[i]).intersects (c->glyphs))
-        return;
-
-    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
-    count = substitute.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-        c->out->add (substitute[iter.get_coverage ()]);
-    }
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_sink (c->output)
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
+    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
 
     unsigned int count;
 
     count = backtrack.len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return;
+      if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
     count = lookahead.len;
     for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
+      if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
 
-    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
     count = substitute.len;
     c->output->add_array (substitute.arrayZ, substitute.len);
   }
@@ -1094,10 +1213,7 @@
   const Coverage &get_coverage () const { return this+coverage; }
 
   bool would_apply (hb_would_apply_context_t *c) const
-  {
-    TRACE_WOULD_APPLY (this);
-    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
-  }
+  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1105,13 +1221,15 @@
     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);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
-    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
 
-  unsigned int start_index = 0, end_index = 0;
+    if (unlikely (index >= substitute.len)) return_trace (false);
+
+    unsigned int start_index = 0, end_index = 0;
     if (match_backtrack (c,
                          backtrack.len, (HBUINT16 *) backtrack.arrayZ,
                          match_coverage, this,
@@ -1144,10 +1262,10 @@
     TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return_trace (false);
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
     if (!lookahead.sanitize (c, this))
       return_trace (false);
-    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
     return_trace (substitute.sanitize (c));
   }
 
@@ -1164,7 +1282,7 @@
                 lookaheadX;             /* Array of coverage tables
                                          * in lookahead sequence, in glyph
                                          * sequence order */
-  ArrayOf<GlyphID>
+  ArrayOf<HBGlyphID>
                 substituteX;            /* Array of substitute
                                          * GlyphIDs--ordered by Coverage Index */
   public:
@@ -1173,13 +1291,13 @@
 
 struct ReverseChainSingleSubst
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1213,23 +1331,29 @@
     ReverseChainSingle  = 8
   };
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, lookup_type);
     switch (lookup_type) {
-    case Single:                return_trace (u.single.dispatch (c));
-    case Multiple:              return_trace (u.multiple.dispatch (c));
-    case Alternate:             return_trace (u.alternate.dispatch (c));
-    case Ligature:              return_trace (u.ligature.dispatch (c));
-    case Context:               return_trace (u.context.dispatch (c));
-    case ChainContext:          return_trace (u.chainContext.dispatch (c));
-    case Extension:             return_trace (u.extension.dispatch (c));
-    case ReverseChainSingle:    return_trace (u.reverseChainContextSingle.dispatch (c));
+    case Single:                return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
+    case Multiple:              return_trace (u.multiple.dispatch (c, hb_forward<Ts> (ds)...));
+    case Alternate:             return_trace (u.alternate.dispatch (c, hb_forward<Ts> (ds)...));
+    case Ligature:              return_trace (u.ligature.dispatch (c, hb_forward<Ts> (ds)...));
+    case Context:               return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
+    case ChainContext:          return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
+    case Extension:             return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
+    case ReverseChainSingle:    return_trace (u.reverseChainContextSingle.dispatch (c, hb_forward<Ts> (ds)...));
     default:                    return_trace (c->default_return_value ());
     }
   }
 
+  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c, lookup_type);
+  }
+
   protected:
   union {
   SingleSubst                   single;
@@ -1253,14 +1377,14 @@
   const SubTable& get_subtable (unsigned int i) const
   { return Lookup::get_subtable<SubTable> (i); }
 
-  static bool lookup_type_is_reverse (unsigned int lookup_type)
+  static inline bool lookup_type_is_reverse (unsigned int lookup_type)
   { return lookup_type == SubTable::ReverseChainSingle; }
 
   bool is_reverse () const
   {
     unsigned int type = get_type ();
     if (unlikely (type == SubTable::Extension))
-      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
+      return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
     return lookup_type_is_reverse (type);
   }
 
@@ -1290,6 +1414,24 @@
     return ret;
   }
 
+  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
+  {
+    if (c->is_lookup_visited (this_index))
+      return hb_closure_lookups_context_t::default_return_value ();
+
+    c->set_lookup_visited (this_index);
+    if (!intersects (c->glyphs))
+    {
+      c->set_lookup_inactive (this_index);
+      return hb_closure_lookups_context_t::default_return_value ();
+    }
+
+    c->set_recurse_func (dispatch_closure_lookups_recurse_func);
+
+    hb_closure_lookups_context_t::return_t ret = dispatch (c);
+    return ret;
+  }
+
   hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
@@ -1297,90 +1439,93 @@
   }
 
   template <typename set_t>
-  void add_coverage (set_t *glyphs) const
+  void collect_coverage (set_t *glyphs) const
   {
-    hb_add_coverage_context_t<set_t> c (glyphs);
+    hb_collect_coverage_context_t<set_t> c (glyphs);
     dispatch (&c);
   }
 
   bool would_apply (hb_would_apply_context_t *c,
                     const hb_ot_layout_lookup_accelerator_t *accel) const
   {
-    TRACE_WOULD_APPLY (this);
-    if (unlikely (!c->len))  return_trace (false);
-    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
-      return_trace (dispatch (c));
+    if (unlikely (!c->len)) return false;
+    if (!accel->may_have (c->glyphs[0])) return false;
+      return dispatch (c);
   }
 
-  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
+  static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
 
   SubTable& serialize_subtable (hb_serialize_context_t *c,
-                                       unsigned int i)
+                                unsigned int i)
   { return get_subtables<SubTable> ()[i].serialize (c, this); }
 
   bool serialize_single (hb_serialize_context_t *c,
                          uint32_t lookup_props,
-                         hb_array_t<const GlyphID> glyphs,
-                         hb_array_t<const GlyphID> substitutes)
+                         hb_sorted_array_t<const HBGlyphID> glyphs,
+                         hb_array_t<const HBGlyphID> substitutes)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes));
+    return_trace (serialize_subtable (c, 0).u.single.
+                  serialize (c, hb_zip (glyphs, substitutes)));
   }
 
   bool serialize_multiple (hb_serialize_context_t *c,
                            uint32_t lookup_props,
-                           hb_array_t<const GlyphID> glyphs,
+                           hb_sorted_array_t<const HBGlyphID> glyphs,
                            hb_array_t<const unsigned int> substitute_len_list,
-                           hb_array_t<const GlyphID> substitute_glyphs_list)
+                           hb_array_t<const HBGlyphID> substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
-                                                                  glyphs,
-                                                                  substitute_len_list,
-                                                                  substitute_glyphs_list));
+    return_trace (serialize_subtable (c, 0).u.multiple.
+                  serialize (c,
+                             glyphs,
+                             substitute_len_list,
+                             substitute_glyphs_list));
   }
 
   bool serialize_alternate (hb_serialize_context_t *c,
                             uint32_t lookup_props,
-                            hb_array_t<const GlyphID> glyphs,
+                            hb_sorted_array_t<const HBGlyphID> glyphs,
                             hb_array_t<const unsigned int> alternate_len_list,
-                            hb_array_t<const GlyphID> alternate_glyphs_list)
+                            hb_array_t<const HBGlyphID> alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
-                                                                   glyphs,
-                                                                   alternate_len_list,
-                                                                   alternate_glyphs_list));
+    return_trace (serialize_subtable (c, 0).u.alternate.
+                  serialize (c,
+                             glyphs,
+                             alternate_len_list,
+                             alternate_glyphs_list));
   }
 
   bool serialize_ligature (hb_serialize_context_t *c,
                            uint32_t lookup_props,
-                           hb_array_t<const GlyphID> first_glyphs,
+                           hb_sorted_array_t<const HBGlyphID> first_glyphs,
                            hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
-                           hb_array_t<const GlyphID> ligatures_list,
+                           hb_array_t<const HBGlyphID> ligatures_list,
                            hb_array_t<const unsigned int> component_count_list,
-                           hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
+                           hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
-                                                                  first_glyphs,
-                                                                  ligature_per_first_glyph_count_list,
-                                                                  ligatures_list,
-                                                                  component_count_list,
-                                                                  component_list));
+    return_trace (serialize_subtable (c, 0).u.ligature.
+                  serialize (c,
+                             first_glyphs,
+                             ligature_per_first_glyph_count_list,
+                             ligatures_list,
+                             component_count_list,
+                             component_list));
   }
 
   template <typename context_t>
-  static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
+  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
-  static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
+  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
   {
     if (!c->should_visit_lookup (lookup_index))
-      return HB_VOID;
+      return hb_empty_t ();
 
     hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);
 
@@ -1392,9 +1537,11 @@
     return ret;
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
-  { return Lookup::dispatch<SubTable> (c); }
+  HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index);
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
 
   bool subset (hb_subset_context_t *c) const
   { return Lookup::subset<SubTable> (c); }
@@ -1413,17 +1560,25 @@
   static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
 
   const SubstLookup& get_lookup (unsigned int i) const
-  { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
+  { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
 
   bool subset (hb_subset_context_t *c) const
-  { return GSUBGPOS::subset<SubstLookup> (c); }
+  {
+    hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_features);
+    return GSUBGPOS::subset<SubstLookup> (&l);
+  }
 
   bool sanitize (hb_sanitize_context_t *c) const
   { return GSUBGPOS::sanitize<SubstLookup> (c); }
 
-  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
+  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
                                    hb_face_t *face) const;
 
+  void closure_lookups (hb_face_t      *face,
+                        const hb_set_t *glyphs,
+                        hb_set_t       *lookup_indexes /* IN/OUT */) const
+  { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
+
   typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
 };
 
@@ -1433,22 +1588,25 @@
 
 /* Out-of-class implementation for methods recursing */
 
+#ifndef HB_NO_OT_LAYOUT
 /*static*/ inline bool ExtensionSubst::is_reverse () const
 {
-  unsigned int type = get_type ();
-  if (unlikely (type == SubTable::Extension))
-    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
-  return SubstLookup::lookup_type_is_reverse (type);
+  return SubstLookup::lookup_type_is_reverse (get_type ());
 }
-
 template <typename context_t>
-/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
+/*static*/ typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
   return l.dispatch (c);
 }
 
-/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
+/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
+{
+  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index);
+  return l.closure_lookups (c, this_index);
+}
+
+/*static*/ bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
@@ -1460,6 +1618,8 @@
   c->set_lookup_props (saved_lookup_props);
   return ret;
 }
+#endif
+
 
 } /* namespace OT */
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh
index 11d757a..1e7d76d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh
@@ -42,30 +42,26 @@
 
 
 struct hb_intersects_context_t :
-       hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
+       hb_dispatch_context_t<hb_intersects_context_t, bool>
 {
-  const char *get_name () { return "INTERSECTS"; }
   template <typename T>
   return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
   static return_t default_return_value () { return false; }
   bool stop_sublookup_iteration (return_t r) const { return r; }
 
   const hb_set_t *glyphs;
-  unsigned int debug_depth;
 
   hb_intersects_context_t (const hb_set_t *glyphs_) :
-                             glyphs (glyphs_),
-                             debug_depth (0) {}
+                             glyphs (glyphs_) {}
 };
 
 struct hb_closure_context_t :
-       hb_dispatch_context_t<hb_closure_context_t, hb_void_t, 0>
+       hb_dispatch_context_t<hb_closure_context_t>
 {
-  const char *get_name () { return "CLOSURE"; }
   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
   template <typename T>
-  return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
-  static return_t default_return_value () { return HB_VOID; }
+  return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
   void recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
@@ -76,26 +72,35 @@
     nesting_level_left++;
   }
 
+  bool lookup_limit_exceeded ()
+  { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+
   bool should_visit_lookup (unsigned int lookup_index)
   {
+    if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
+      return false;
+
     if (is_lookup_done (lookup_index))
       return false;
+
     done_lookups->set (lookup_index, glyphs->get_population ());
     return true;
   }
 
   bool is_lookup_done (unsigned int lookup_index)
   {
+    if (done_lookups->in_error ())
+      return true;
+
     /* Have we visited this lookup with the current set of glyphs? */
     return done_lookups->get (lookup_index) == glyphs->get_population ();
   }
 
   hb_face_t *face;
   hb_set_t *glyphs;
-  hb_set_t out[1];
+  hb_set_t output[1];
   recurse_func_t recurse_func;
   unsigned int nesting_level_left;
-  unsigned int debug_depth;
 
   hb_closure_context_t (hb_face_t *face_,
                         hb_set_t *glyphs_,
@@ -105,8 +110,9 @@
                           glyphs (glyphs_),
                           recurse_func (nullptr),
                           nesting_level_left (nesting_level_left_),
-                          debug_depth (0),
-                          done_lookups (done_lookups_) {}
+                          done_lookups (done_lookups_),
+                          lookup_count (0)
+  {}
 
   ~hb_closure_context_t () { flush (); }
 
@@ -114,19 +120,87 @@
 
   void flush ()
   {
-    hb_set_union (glyphs, out);
-    hb_set_clear (out);
+    hb_set_del_range (output, face->get_num_glyphs (), hb_set_get_max (output));        /* Remove invalid glyphs. */
+    hb_set_union (glyphs, output);
+    hb_set_clear (output);
   }
 
   private:
   hb_map_t *done_lookups;
+  unsigned int lookup_count;
 };
 
+struct hb_closure_lookups_context_t :
+       hb_dispatch_context_t<hb_closure_lookups_context_t>
+{
+  typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
+  template <typename T>
+  return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
+  void recurse (unsigned lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return;
+
+    /* Return if new lookup was recursed to before. */
+    if (is_lookup_visited (lookup_index))
+      return;
+
+    set_lookup_visited (lookup_index);
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+  }
+
+  void set_lookup_visited (unsigned lookup_index)
+  { visited_lookups->add (lookup_index); }
+
+  void set_lookup_inactive (unsigned lookup_index)
+  { inactive_lookups->add (lookup_index); }
+
+  bool lookup_limit_exceeded ()
+  { return lookup_count > HB_MAX_LOOKUP_INDICES; }
+
+  bool is_lookup_visited (unsigned lookup_index)
+  {
+    if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
+      return true;
+
+    if (visited_lookups->in_error ())
+      return true;
+
+    return visited_lookups->has (lookup_index);
+  }
+
+  hb_face_t *face;
+  const hb_set_t *glyphs;
+  recurse_func_t recurse_func;
+  unsigned int nesting_level_left;
+
+  hb_closure_lookups_context_t (hb_face_t *face_,
+                                const hb_set_t *glyphs_,
+                                hb_set_t *visited_lookups_,
+                                hb_set_t *inactive_lookups_,
+                                unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
+                                face (face_),
+                                glyphs (glyphs_),
+                                recurse_func (nullptr),
+                                nesting_level_left (nesting_level_left_),
+                                visited_lookups (visited_lookups_),
+                                inactive_lookups (inactive_lookups_),
+                                lookup_count (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+
+  private:
+  hb_set_t *visited_lookups;
+  hb_set_t *inactive_lookups;
+  unsigned int lookup_count;
+};
 
 struct hb_would_apply_context_t :
-       hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
+       hb_dispatch_context_t<hb_would_apply_context_t, bool>
 {
-  const char *get_name () { return "WOULD_APPLY"; }
   template <typename T>
   return_t dispatch (const T &obj) { return obj.would_apply (this); }
   static return_t default_return_value () { return false; }
@@ -136,7 +210,6 @@
   const hb_codepoint_t *glyphs;
   unsigned int len;
   bool zero_context;
-  unsigned int debug_depth;
 
   hb_would_apply_context_t (hb_face_t *face_,
                             const hb_codepoint_t *glyphs_,
@@ -145,19 +218,16 @@
                               face (face_),
                               glyphs (glyphs_),
                               len (len_),
-                              zero_context (zero_context_),
-                              debug_depth (0) {}
+                              zero_context (zero_context_) {}
 };
 
-
 struct hb_collect_glyphs_context_t :
-       hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, 0>
+       hb_dispatch_context_t<hb_collect_glyphs_context_t>
 {
-  const char *get_name () { return "COLLECT_GLYPHS"; }
   typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
   template <typename T>
-  return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
-  static return_t default_return_value () { return HB_VOID; }
+  return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
   void recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
@@ -204,7 +274,6 @@
   recurse_func_t recurse_func;
   hb_set_t *recursed_lookups;
   unsigned int nesting_level_left;
-  unsigned int debug_depth;
 
   hb_collect_glyphs_context_t (hb_face_t *face_,
                                hb_set_t  *glyphs_before, /* OUT.  May be NULL */
@@ -219,8 +288,7 @@
                               output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
                               recurse_func (nullptr),
                               recursed_lookups (hb_set_create ()),
-                              nesting_level_left (nesting_level_left_),
-                              debug_depth (0) {}
+                              nesting_level_left (nesting_level_left_) {}
   ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
@@ -229,26 +297,23 @@
 
 
 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>
+struct hb_collect_coverage_context_t :
+       hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &>
 {
-  const char *get_name () { return "GET_COVERAGE"; }
-  typedef const Coverage &return_t;
+  typedef const Coverage &return_t; // Stoopid that we have to dupe this here.
   template <typename T>
   return_t dispatch (const T &obj) { return obj.get_coverage (); }
-  static return_t default_return_value () { return Null(Coverage); }
+  static return_t default_return_value () { return Null (Coverage); }
   bool stop_sublookup_iteration (return_t r) const
   {
-    r.add_coverage (set);
+    r.collect_coverage (set);
     return false;
   }
 
-  hb_add_coverage_context_t (set_t *set_) :
-                            set (set_),
-                            debug_depth (0) {}
+  hb_collect_coverage_context_t (set_t *set_) :
+                                   set (set_) {}
 
   set_t *set;
-  unsigned int debug_depth;
 };
 
 
@@ -276,7 +341,7 @@
     void set_mask (hb_mask_t mask_) { mask = mask_; }
     void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
     void set_match_func (match_func_t match_func_,
-                                const void *match_data_)
+                         const void *match_data_)
     { match_func = match_func_; match_data = match_data_; }
 
     enum may_match_t {
@@ -286,7 +351,7 @@
     };
 
     may_match_t may_match (const hb_glyph_info_t &info,
-                                  const HBUINT16        *glyph_data) const
+                           const HBUINT16        *glyph_data) const
     {
       if (!(info.mask & mask) ||
           (syllable && syllable != info.syllable ()))
@@ -355,7 +420,7 @@
     }
 
     void reset (unsigned int start_index_,
-                       unsigned int num_items_)
+                unsigned int num_items_)
     {
       idx = start_index_;
       num_items = num_items_;
@@ -363,7 +428,11 @@
       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
     }
 
-    void reject () { num_items++; match_glyph_data--; }
+    void reject ()
+    {
+      num_items++;
+      if (match_glyph_data) match_glyph_data--;
+    }
 
     matcher_t::may_skip_t
     may_skip (const hb_glyph_info_t &info) const
@@ -387,7 +456,7 @@
              skip == matcher_t::SKIP_NO))
         {
           num_items--;
-          match_glyph_data++;
+          if (match_glyph_data) match_glyph_data++;
           return true;
         }
 
@@ -414,7 +483,7 @@
              skip == matcher_t::SKIP_NO))
         {
           num_items--;
-          match_glyph_data++;
+          if (match_glyph_data) match_glyph_data++;
           return true;
         }
 
@@ -467,7 +536,6 @@
   unsigned int lookup_index;
   unsigned int lookup_props;
   unsigned int nesting_level_left;
-  unsigned int debug_depth;
 
   bool has_glyph_classes;
   bool auto_zwnj;
@@ -478,12 +546,18 @@
 
 
   hb_ot_apply_context_t (unsigned int table_index_,
-                      hb_font_t *font_,
-                      hb_buffer_t *buffer_) :
+                         hb_font_t *font_,
+                         hb_buffer_t *buffer_) :
                         iter_input (), iter_context (),
                         font (font_), face (font->face), buffer (buffer_),
                         recurse_func (nullptr),
-                        gdef (*face->table.GDEF->table),
+                        gdef (
+#ifndef HB_NO_OT_LAYOUT
+                              *face->table.GDEF->table
+#else
+                              Null (GDEF)
+#endif
+                             ),
                         var_store (gdef.get_var_store ()),
                         direction (buffer_->props.direction),
                         lookup_mask (1),
@@ -491,7 +565,6 @@
                         lookup_index ((unsigned int) -1),
                         lookup_props (0),
                         nesting_level_left (HB_MAX_NESTING_LEVEL),
-                        debug_depth (0),
                         has_glyph_classes (gdef.has_glyph_classes ()),
                         auto_zwnj (true),
                         auto_zwj (true),
@@ -595,13 +668,13 @@
     buffer->cur().codepoint = glyph_index;
   }
   void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
-                                           unsigned int class_guess) const
+                                    unsigned int class_guess) const
   {
     _set_glyph_props (glyph_index, class_guess, true);
     buffer->replace_glyph (glyph_index);
   }
   void output_glyph_for_component (hb_codepoint_t glyph_index,
-                                          unsigned int class_guess) const
+                                   unsigned int class_guess) const
   {
     _set_glyph_props (glyph_index, class_guess, false, true);
     buffer->output_glyph (glyph_index);
@@ -610,10 +683,10 @@
 
 
 struct hb_get_subtables_context_t :
-       hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
+       hb_dispatch_context_t<hb_get_subtables_context_t>
 {
   template <typename Type>
-  static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
+  static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
   {
     const Type *typed_obj = (const Type *) obj;
     return typed_obj->apply (c);
@@ -629,7 +702,7 @@
       obj = &obj_;
       apply_func = apply_func_;
       digest.init ();
-      obj_.get_coverage ().add_coverage (&digest);
+      obj_.get_coverage ().collect_coverage (&digest);
     }
 
     bool apply (OT::hb_ot_apply_context_t *c) const
@@ -646,22 +719,19 @@
   typedef hb_vector_t<hb_applicable_t> array_t;
 
   /* Dispatch interface. */
-  const char *get_name () { return "GET_SUBTABLES"; }
   template <typename T>
   return_t dispatch (const T &obj)
   {
     hb_applicable_t *entry = array.push();
     entry->init (obj, apply_to<T>);
-    return HB_VOID;
+    return hb_empty_t ();
   }
-  static return_t default_return_value () { return HB_VOID; }
+  static return_t default_return_value () { return hb_empty_t (); }
 
   hb_get_subtables_context_t (array_t &array_) :
-                              array (array_),
-                              debug_depth (0) {}
+                              array (array_) {}
 
   array_t &array;
-  unsigned int debug_depth;
 };
 
 
@@ -700,15 +770,14 @@
   return (data+coverage).intersects (glyphs);
 }
 
-static inline bool intersects_array (const hb_set_t *glyphs,
-                                     unsigned int count,
-                                     const HBUINT16 values[],
-                                     intersects_func_t intersects_func,
-                                     const void *intersects_data)
+static inline bool array_is_subset_of (const hb_set_t *glyphs,
+                                       unsigned int count,
+                                       const HBUINT16 values[],
+                                       intersects_func_t intersects_func,
+                                       const void *intersects_data)
 {
-  for (unsigned int i = 0; i < count; i++)
-    if (likely (!intersects_func (glyphs, values[i], intersects_data)))
-      return false;
+  for (const HBUINT16 &_ : + hb_iter (values, count))
+    if (!intersects_func (glyphs, _, intersects_data)) return false;
   return true;
 }
 
@@ -720,12 +789,12 @@
 static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
-  class_def.add_class (glyphs, value);
+  class_def.collect_class (glyphs, value);
 }
 static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
-  (data+coverage).add_coverage (glyphs);
+  (data+coverage).collect_coverage (glyphs);
 }
 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
                                   hb_set_t *glyphs,
@@ -734,8 +803,10 @@
                                   collect_glyphs_func_t collect_func,
                                   const void *collect_data)
 {
-  for (unsigned int i = 0; i < count; i++)
-    collect_func (glyphs, values[i], collect_data);
+  return
+  + hb_iter (values, count)
+  | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
+  ;
 }
 
 
@@ -846,7 +917,7 @@
         if (ligbase == LIGBASE_NOT_CHECKED)
         {
           bool found = false;
-          const hb_glyph_info_t *out = buffer->out_info;
+          const auto *out = buffer->out_info;
           unsigned int j = buffer->out_len;
           while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
           {
@@ -970,7 +1041,7 @@
         if (this_comp == 0)
           this_comp = last_num_components;
         unsigned int new_lig_comp = components_so_far - last_num_components +
-                                    MIN (this_comp, last_num_components);
+                                    hb_min (this_comp, last_num_components);
           _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
       }
       buffer->next_glyph ();
@@ -984,18 +1055,19 @@
     buffer->idx++;
   }
 
-  if (!is_mark_ligature && last_lig_id) {
+  if (!is_mark_ligature && last_lig_id)
+  {
     /* 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 (this_comp, last_num_components);
-        _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
-      } else
-        break;
+    for (unsigned i = buffer->idx; i < buffer->len; ++i)
+    {
+      if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
+
+      unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
+      if (!this_comp) break;
+
+      unsigned new_lig_comp = components_so_far - last_num_components +
+                              hb_min (this_comp, last_num_components);
+      _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
     }
   }
   return_trace (true);
@@ -1050,6 +1122,17 @@
 
 struct LookupRecord
 {
+  LookupRecord* copy (hb_serialize_context_t *c,
+                      const hb_map_t         *lookup_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->embed (*this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    out->lookupListIndex = hb_map_get (lookup_map, lookupListIndex);
+    return_trace (out);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1170,7 +1253,7 @@
     else
     {
       /* NOTE: delta is negative. */
-      delta = MAX (delta, (int) next - (int) count);
+      delta = hb_max (delta, (int) next - (int) count);
       next -= delta;
     }
 
@@ -1221,9 +1304,9 @@
                                        const HBUINT16 input[], /* Array of input values--start with second glyph */
                                        ContextClosureLookupContext &lookup_context)
 {
-  return intersects_array (glyphs,
-                           inputCount ? inputCount - 1 : 0, input,
-                           lookup_context.funcs.intersects, lookup_context.intersects_data);
+  return array_is_subset_of (glyphs,
+                             inputCount ? inputCount - 1 : 0, input,
+                             lookup_context.funcs.intersects, lookup_context.intersects_data);
 }
 
 static inline void context_closure_lookup (hb_closure_context_t *c,
@@ -1296,7 +1379,9 @@
 
   void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
                                                        (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
     context_closure_lookup (c,
                             inputCount, inputZ.arrayZ,
@@ -1304,10 +1389,19 @@
                             lookup_context);
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+                                                       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
+    recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
+  }
+
   void collect_glyphs (hb_collect_glyphs_context_t *c,
                        ContextCollectGlyphsLookupContext &lookup_context) const
   {
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
                                                        (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     context_collect_glyphs_lookup (c,
                                    inputCount, inputZ.arrayZ,
@@ -1318,21 +1412,64 @@
   bool would_apply (hb_would_apply_context_t *c,
                     ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY (this);
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
                                                        (inputZ.as_array (inputCount ? inputCount - 1 : 0));
-    return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
+    return context_would_apply_lookup (c,
+                                       inputCount, inputZ.arrayZ,
+                                       lookupCount, lookupRecord.arrayZ,
+                                       lookup_context);
   }
 
   bool apply (hb_ot_apply_context_t *c,
               ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
                                                        (inputZ.as_array (inputCount ? inputCount - 1 : 0));
     return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
   }
 
+  bool serialize (hb_serialize_context_t *c,
+                  const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
+                  const hb_map_t *lookup_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!c->extend_min (out))) return_trace (false);
+
+    out->inputCount = inputCount;
+    out->lookupCount = lookupCount;
+
+    const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
+    for (const auto org : input)
+    {
+      HBUINT16 d;
+      d = input_mapping->get (org);
+      c->copy (d);
+    }
+
+    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
+                                                       (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
+    for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+      c->copy (lookupRecord[i], lookup_map);
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_map_t *lookup_map,
+               const hb_map_t *klass_map = nullptr) const
+  {
+    TRACE_SUBSET (this);
+
+    const hb_array_t<const HBUINT16> input = inputZ.as_array ((inputCount ? inputCount - 1 : 0));
+    if (!input.length) return_trace (false);
+
+    const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
+    if (!hb_all (input, mapping)) return_trace (false);
+    return_trace (serialize (c->serializer, mapping, lookup_map));
+  }
+
   public:
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -1364,53 +1501,99 @@
   bool intersects (const hb_set_t *glyphs,
                    ContextClosureLookupContext &lookup_context) const
   {
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if ((this+rule[i]).intersects (glyphs, lookup_context))
-        return true;
-    return false;
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c,
                 ContextClosureLookupContext &lookup_context) const
   {
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      (this+rule[i]).closure (c, lookup_context);
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const Rule &_) { _.closure_lookups (c); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c,
                        ContextCollectGlyphsLookupContext &lookup_context) const
   {
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      (this+rule[i]).collect_glyphs (c, lookup_context);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c,
                     ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-    {
-      if ((this+rule[i]).would_apply (c, lookup_context))
-        return_trace (true);
-    }
-    return_trace (false);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
+    | hb_any
+    ;
   }
 
   bool apply (hb_ot_apply_context_t *c,
               ContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
+    return_trace (
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
+    | hb_any
+    )
+    ;
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_map_t *lookup_map,
+               const hb_map_t *klass_map = nullptr) const
+  {
+    TRACE_SUBSET (this);
+
+    auto snap = c->serializer->snapshot ();
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    for (const OffsetTo<Rule>& _ : rule)
     {
-      if ((this+rule[i]).apply (c, lookup_context))
-        return_trace (true);
+      if (!_) continue;
+      auto *o = out->rule.serialize_append (c->serializer);
+      if (unlikely (!o)) continue;
+
+      auto o_snap = c->serializer->snapshot ();
+      if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
+      {
+        out->rule.pop ();
+        c->serializer->revert (o_snap);
+      }
     }
-    return_trace (false);
+
+    bool ret = bool (out->rule);
+    if (!ret) c->serializer->revert (snap);
+
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1437,16 +1620,14 @@
       nullptr
     };
 
-    unsigned int count = ruleSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (glyphs->has (iter.get_glyph ()) &&
-          (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
-        return true;
-    }
-    return false;
+    return
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
@@ -1456,40 +1637,47 @@
       nullptr
     };
 
-    unsigned int count = ruleSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-        (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
-    }
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
+    ;
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverage).add_coverage (c->input);
+    (this+coverage).collect_coverage (c->input);
 
     struct ContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
       nullptr
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ContextApplyLookupContext lookup_context = {
       {match_glyph},
       nullptr
     };
-    return_trace (rule_set.would_apply (c, lookup_context));
+    return rule_set.would_apply (c, lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
@@ -1512,8 +1700,26 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    out->coverage.serialize (c->serializer, out)
+                 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1549,13 +1755,15 @@
       &class_def
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (class_def.intersects_class (glyphs, i) &&
-          (this+ruleSet[i]).intersects (glyphs, lookup_context))
-        return true;
-
-    return false;
+    return
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_enumerate
+    | hb_map ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
+              { return class_def.intersects_class (glyphs, p.first) &&
+                       p.second.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
@@ -1570,17 +1778,30 @@
       &class_def
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (class_def.intersects_class (c->glyphs, i)) {
-        const RuleSet &rule_set = this+ruleSet[i];
-        rule_set.closure (c, lookup_context);
-      }
+    return
+    + hb_enumerate (ruleSet)
+    | hb_filter ([&] (unsigned _)
+                 { return class_def.intersects_class (c->glyphs, _); },
+                 hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
+    ;
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverage).add_coverage (c->input);
+    (this+coverage).collect_coverage (c->input);
 
     const ClassDef &class_def = this+classDef;
     struct ContextCollectGlyphsLookupContext lookup_context = {
@@ -1588,15 +1809,14 @@
       &class_def
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const ClassDef &class_def = this+classDef;
     unsigned int index = class_def.get_class (c->glyphs[0]);
     const RuleSet &rule_set = this+ruleSet[index];
@@ -1604,7 +1824,7 @@
       {match_class},
       &class_def
     };
-    return_trace (rule_set.would_apply (c, lookup_context));
+    return rule_set.would_apply (c, lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
@@ -1628,8 +1848,45 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
+      return_trace (false);
+
+    hb_map_t klass_map;
+    out->classDef.serialize_subset (c, classDef, this, &klass_map);
+
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    bool ret = true;
+    unsigned non_zero_index = 0, index = 0;
+    for (const hb_pair_t<unsigned, const OffsetTo<RuleSet>&> _ : + hb_enumerate (ruleSet)
+                                                                 | hb_filter (klass_map, hb_first))
+    {
+      auto *o = out->ruleSet.serialize_append (c->serializer);
+      if (unlikely (!o))
+      {
+        ret = false;
+        break;
+      }
+
+      if (o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
+        non_zero_index = index;
+
+      index++;
+    }
+
+    if (!ret) return_trace (ret);
+
+    //prune empty trailing ruleSets
+    --index;
+    while (index > non_zero_index)
+    {
+      out->ruleSet.pop ();
+      index--;
+    }
+
+    return_trace (bool (out->ruleSet));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1686,9 +1943,17 @@
                             lookup_context);
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
+    recurse_lookups (c, lookupCount, lookupRecord);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverageZ[0]).add_coverage (c->input);
+    (this+coverageZ[0]).collect_coverage (c->input);
 
     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
     struct ContextCollectGlyphsLookupContext lookup_context = {
@@ -1704,14 +1969,15 @@
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
     struct ContextApplyLookupContext lookup_context = {
       {match_coverage},
       this
     };
-    return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
+    return context_would_apply_lookup (c,
+                                       glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
+                                       lookupCount, lookupRecord,
+                                       lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverageZ[0]; }
@@ -1733,8 +1999,28 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    out->format = format;
+    out->glyphCount = glyphCount;
+    out->lookupCount = lookupCount;
+
+    auto coverages = coverageZ.as_array (glyphCount);
+
+    for (const OffsetTo<Coverage>& offset : coverages)
+    {
+      auto *o = c->serializer->allocate_size<OffsetTo<Coverage>> (OffsetTo<Coverage>::static_size);
+      if (unlikely (!o)) return_trace (false);
+      if (!o->serialize_subset (c, offset, this)) return_trace (false);
+    }
+
+    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+      c->serializer->copy (lookupRecord[i], lookup_map);
+
+    return_trace (true);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1755,7 +2041,7 @@
   HBUINT16      glyphCount;             /* Number of glyphs in the input glyph
                                          * sequence */
   HBUINT16      lookupCount;            /* Number of LookupRecords */
-  UnsizedArrayOf<OffsetTo<Coverage> >
+  UnsizedArrayOf<OffsetTo<Coverage>>
                 coverageZ;              /* Array of offsets to Coverage
                                          * table in glyph sequence order */
 /*UnsizedArrayOf<LookupRecord>
@@ -1767,15 +2053,15 @@
 
 struct Context
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
-    case 3: return_trace (c->dispatch (u.format3));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -1819,15 +2105,15 @@
                                              const HBUINT16 lookahead[],
                                              ChainContextClosureLookupContext &lookup_context)
 {
-  return intersects_array (glyphs,
-                           backtrackCount, backtrack,
-                           lookup_context.funcs.intersects, lookup_context.intersects_data[0])
-      && intersects_array (glyphs,
-                           inputCount ? inputCount - 1 : 0, input,
-                           lookup_context.funcs.intersects, lookup_context.intersects_data[1])
-      && intersects_array (glyphs,
-                          lookaheadCount, lookahead,
-                          lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
+  return array_is_subset_of (glyphs,
+                             backtrackCount, backtrack,
+                             lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+      && array_is_subset_of (glyphs,
+                             inputCount ? inputCount - 1 : 0, input,
+                             lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+      && array_is_subset_of (glyphs,
+                             lookaheadCount, lookahead,
+                             lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
 }
 
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
@@ -1927,8 +2213,8 @@
 {
   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
     return chain_context_intersects (glyphs,
                                      backtrack.len, backtrack.arrayZ,
                                      input.lenP1, input.arrayZ,
@@ -1939,9 +2225,11 @@
   void closure (hb_closure_context_t *c,
                 ChainContextClosureLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     chain_context_closure_lookup (c,
                                   backtrack.len, backtrack.arrayZ,
                                   input.lenP1, input.arrayZ,
@@ -1950,12 +2238,22 @@
                                   lookup_context);
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    recurse_lookups (c, lookup.len, lookup.arrayZ);
+  }
+
   void collect_glyphs (hb_collect_glyphs_context_t *c,
                        ChainContextCollectGlyphsLookupContext &lookup_context) const
   {
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     chain_context_collect_glyphs_lookup (c,
                                          backtrack.len, backtrack.arrayZ,
                                          input.lenP1, input.arrayZ,
@@ -1967,23 +2265,22 @@
   bool would_apply (hb_would_apply_context_t *c,
                     ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY (this);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
-    return_trace (chain_context_would_apply_lookup (c,
-                                                    backtrack.len, backtrack.arrayZ,
-                                                    input.lenP1, input.arrayZ,
-                                                    lookahead.len, lookahead.arrayZ, lookup.len,
-                                                    lookup.arrayZ, lookup_context));
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    return chain_context_would_apply_lookup (c,
+                                             backtrack.len, backtrack.arrayZ,
+                                             input.lenP1, input.arrayZ,
+                                             lookahead.len, lookahead.arrayZ, lookup.len,
+                                             lookup.arrayZ, lookup_context);
   }
 
   bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     return_trace (chain_context_apply_lookup (c,
                                               backtrack.len, backtrack.arrayZ,
                                               input.lenP1, input.arrayZ,
@@ -1991,15 +2288,99 @@
                                               lookup.arrayZ, lookup_context));
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  void serialize_array (hb_serialize_context_t *c,
+                        HBUINT16 len,
+                        Iterator it) const
+  {
+    c->copy (len);
+    for (const auto g : it)
+    {
+      HBUINT16 gid;
+      gid = g;
+      c->copy (gid);
+    }
+  }
+
+  ChainRule* copy (hb_serialize_context_t *c,
+                   const hb_map_t *lookup_map,
+                   const hb_map_t *backtrack_map,
+                   const hb_map_t *input_map = nullptr,
+                   const hb_map_t *lookahead_map = nullptr) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->start_embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+
+    const hb_map_t *mapping = backtrack_map;
+    serialize_array (c, backtrack.len, + backtrack.iter ()
+                                       | hb_map (mapping));
+
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    if (input_map) mapping = input_map;
+    serialize_array (c, input.lenP1, + input.iter ()
+                                     | hb_map (mapping));
+
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+    if (lookahead_map) mapping = lookahead_map;
+    serialize_array (c, lookahead.len, + lookahead.iter ()
+                                       | hb_map (mapping));
+
+    const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    HBUINT16 lookupCount;
+    lookupCount = lookupRecord.len;
+    if (!c->copy (lookupCount)) return_trace (nullptr);
+
+    for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+      if (!c->copy (lookupRecord[i], lookup_map)) return_trace (nullptr);
+
+    return_trace (out);
+  }
+
+  bool subset (hb_subset_context_t *c,
+               const hb_map_t *lookup_map,
+               const hb_map_t *backtrack_map = nullptr,
+               const hb_map_t *input_map = nullptr,
+               const hb_map_t *lookahead_map = nullptr) const
+  {
+    TRACE_SUBSET (this);
+
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
+
+    if (!backtrack_map)
+    {
+      const hb_set_t &glyphset = *c->plan->glyphset ();
+      if (!hb_all (backtrack, glyphset) ||
+          !hb_all (input, glyphset) ||
+          !hb_all (lookahead, glyphset))
+        return_trace (false);
+
+      copy (c->serializer, lookup_map, c->plan->glyph_map);
+    }
+    else
+    {
+      if (!hb_all (backtrack, backtrack_map) ||
+          !hb_all (input, input_map) ||
+          !hb_all (lookahead, lookahead_map))
+        return_trace (false);
+
+      copy (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map);
+    }
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return_trace (false);
-    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
     if (!input.sanitize (c)) return_trace (false);
-    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
     if (!lookahead.sanitize (c)) return_trace (false);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
@@ -2025,46 +2406,100 @@
 {
   bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
   {
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if ((this+rule[i]).intersects (glyphs, lookup_context))
-        return true;
-    return false;
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
   void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      (this+rule[i]).closure (c, lookup_context);
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
+    ;
+  }
+
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    if (unlikely (c->lookup_limit_exceeded ())) return;
+
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c); })
+    ;
   }
 
   void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
   {
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      (this+rule[i]).collect_glyphs (c, lookup_context);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if ((this+rule[i]).would_apply (c, lookup_context))
-        return_trace (true);
-
-    return_trace (false);
+    return
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
+    | hb_any
+    ;
   }
 
   bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
     TRACE_APPLY (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if ((this+rule[i]).apply (c, lookup_context))
-        return_trace (true);
+    return_trace (
+    + hb_iter (rule)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
+    | hb_any
+    )
+    ;
+  }
 
-    return_trace (false);
+  bool subset (hb_subset_context_t *c,
+               const hb_map_t *lookup_map,
+               const hb_map_t *backtrack_klass_map = nullptr,
+               const hb_map_t *input_klass_map = nullptr,
+               const hb_map_t *lookahead_klass_map = nullptr) const
+  {
+    TRACE_SUBSET (this);
+
+    auto snap = c->serializer->snapshot ();
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    for (const OffsetTo<ChainRule>& _ : rule)
+    {
+      if (!_) continue;
+      auto *o = out->rule.serialize_append (c->serializer);
+      if (unlikely (!o)) continue;
+
+      auto o_snap = c->serializer->snapshot ();
+      if (!o->serialize_subset (c, _, this,
+                                lookup_map,
+                                backtrack_klass_map,
+                                input_klass_map,
+                                lookahead_klass_map))
+      {
+        out->rule.pop ();
+        c->serializer->revert (o_snap);
+      }
+    }
+
+    bool ret = bool (out->rule);
+    if (!ret) c->serializer->revert (snap);
+
+    return_trace (ret);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2090,16 +2525,14 @@
       {nullptr, nullptr, nullptr}
     };
 
-    unsigned int count = ruleSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (glyphs->has (iter.get_glyph ()) &&
-          (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
-        return true;
-    }
-    return false;
+    return
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (*glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
 
   void closure (hb_closure_context_t *c) const
@@ -2109,40 +2542,47 @@
       {nullptr, nullptr, nullptr}
     };
 
-    unsigned int count = ruleSet.len;
-    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
-    {
-      if (unlikely (iter.get_coverage () >= count))
-        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ()))
-        (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
-    }
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (*c->glyphs, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
+    ;
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverage).add_coverage (c->input);
+    (this+coverage).collect_coverage (c->input);
 
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_glyph},
       {nullptr, nullptr, nullptr}
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ChainContextApplyLookupContext lookup_context = {
       {match_glyph},
       {nullptr, nullptr, nullptr}
     };
-    return_trace (rule_set.would_apply (c, lookup_context));
+    return rule_set.would_apply (c, lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
@@ -2164,8 +2604,26 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, ruleSet)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+
+    out->coverage.serialize (c->serializer, out)
+                 .serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2204,13 +2662,15 @@
        &lookahead_class_def}
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (input_class_def.intersects_class (glyphs, i) &&
-          (this+ruleSet[i]).intersects (glyphs, lookup_context))
-        return true;
-
-    return false;
+    return
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_enumerate
+    | hb_map ([&] (const hb_pair_t<unsigned, const ChainRuleSet &> p)
+              { return input_class_def.intersects_class (glyphs, p.first) &&
+                       p.second.intersects (glyphs, lookup_context); })
+    | hb_any
+    ;
   }
   void closure (hb_closure_context_t *c) const
   {
@@ -2228,17 +2688,30 @@
        &lookahead_class_def}
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (input_class_def.intersects_class (c->glyphs, i)) {
-        const ChainRuleSet &rule_set = this+ruleSet[i];
-        rule_set.closure (c, lookup_context);
-      }
+    return
+    + hb_enumerate (ruleSet)
+    | hb_filter ([&] (unsigned _)
+                 { return input_class_def.intersects_class (c->glyphs, _); },
+                 hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
+    ;
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
+    ;
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    (this+coverage).add_coverage (c->input);
+    (this+coverage).collect_coverage (c->input);
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
@@ -2251,15 +2724,14 @@
        &lookahead_class_def}
     };
 
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+    + hb_iter (ruleSet)
+    | hb_map (hb_add (this))
+    | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
+    ;
   }
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
@@ -2272,7 +2744,7 @@
        &input_class_def,
        &lookahead_class_def}
     };
-    return_trace (rule_set.would_apply (c, lookup_context));
+    return rule_set.would_apply (c, lookup_context);
   }
 
   const Coverage &get_coverage () const { return this+coverage; }
@@ -2301,8 +2773,61 @@
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+    out->coverage.serialize_subset (c, coverage, this);
+
+    hb_map_t backtrack_klass_map;
+    out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
+    if (unlikely (!c->serializer->check_success (!backtrack_klass_map.in_error ())))
+      return_trace (false);
+
+    // subset inputClassDef based on glyphs survived in Coverage subsetting
+    hb_map_t input_klass_map;
+    out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
+    if (unlikely (!c->serializer->check_success (!input_klass_map.in_error ())))
+      return_trace (false);
+
+    hb_map_t lookahead_klass_map;
+    out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
+    if (unlikely (!c->serializer->check_success (!lookahead_klass_map.in_error ())))
+      return_trace (false);
+
+    unsigned non_zero_index = 0, index = 0;
+    bool ret = true;
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
+                                           | hb_filter (input_klass_map, hb_first)
+                                           | hb_map (hb_second))
+    {
+      auto *o = out->ruleSet.serialize_append (c->serializer);
+      if (unlikely (!o))
+      {
+        ret = false;
+        break;
+      }
+      if (o->serialize_subset (c, _, this,
+                               lookup_map,
+                               &backtrack_klass_map,
+                               &input_klass_map,
+                               &lookahead_klass_map))
+        non_zero_index = index;
+
+      index++;
+    }
+
+    if (!ret) return_trace (ret);
+
+    //prune empty trailing ruleSets
+    --index;
+    while (index > non_zero_index)
+    {
+      out->ruleSet.pop ();
+      index--;
+    }
+
+    return_trace (bool (out->ruleSet));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -2343,12 +2868,12 @@
 {
   bool intersects (const hb_set_t *glyphs) const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
     if (!(this+input[0]).intersects (glyphs))
       return false;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_coverage},
       {this, this, this}
@@ -2362,13 +2887,13 @@
 
   void closure (hb_closure_context_t *c) const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
       return;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_coverage},
       {this, this, this}
@@ -2381,14 +2906,24 @@
                                   lookup_context);
   }
 
+  void closure_lookups (hb_closure_lookups_context_t *c) const
+  {
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    recurse_lookups (c, lookup.len, lookup.arrayZ);
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
+
   void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
-    (this+input[0]).add_coverage (c->input);
+    (this+input[0]).collect_coverage (c->input);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     struct ChainContextCollectGlyphsLookupContext lookup_context = {
       {collect_coverage},
       {this, this, this}
@@ -2403,38 +2938,36 @@
 
   bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY (this);
-
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
     };
-    return_trace (chain_context_would_apply_lookup (c,
-                                                    backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
-                                                    input.len, (const HBUINT16 *) input.arrayZ + 1,
-                                                    lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
-                                                    lookup.len, lookup.arrayZ, lookup_context));
+    return chain_context_would_apply_lookup (c,
+                                             backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
+                                             input.len, (const HBUINT16 *) input.arrayZ + 1,
+                                             lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
+                                             lookup.len, lookup.arrayZ, lookup_context);
   }
 
   const Coverage &get_coverage () const
   {
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
     return this+input[0];
   }
 
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
 
     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
       {match_coverage},
       {this, this, this}
@@ -2446,23 +2979,63 @@
                                               lookup.len, lookup.arrayZ, lookup_context));
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
+
+    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
+
+    + it
+    | hb_apply (subset_offset_array (c, *out, base))
+    ;
+
+    return_trace (out->len);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!out)) return_trace (false);
+    if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
+
+    if (!serialize_coverage_offsets (c, backtrack.iter (), this))
+      return_trace (false);
+
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    if (!serialize_coverage_offsets (c, input.iter (), this))
+      return_trace (false);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
+    if (!serialize_coverage_offsets (c, lookahead.iter (), this))
+      return_trace (false);
+
+    const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
+    HBUINT16 lookupCount;
+    lookupCount = lookupRecord.len;
+    if (!c->serializer->copy (lookupCount)) return_trace (false);
+
+    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+    for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+      if (!c->serializer->copy (lookupRecord[i], lookup_map)) return_trace (false);
+
+    return_trace (true);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c, this)) return_trace (false);
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
     if (!input.sanitize (c, this)) return_trace (false);
     if (!input.len) return_trace (false); /* To be consistent with Context. */
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
     if (!lookahead.sanitize (c, this)) return_trace (false);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
     return_trace (lookup.sanitize (c));
   }
 
@@ -2489,15 +3062,15 @@
 
 struct ChainContext
 {
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (c->dispatch (u.format1));
-    case 2: return_trace (c->dispatch (u.format2));
-    case 3: return_trace (c->dispatch (u.format3));
+    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -2519,26 +3092,24 @@
 
   template <typename X>
   const X& get_subtable () const
-  {
-    unsigned int offset = extensionOffset;
-    if (unlikely (!offset)) return Null(typename T::SubTable);
-    return StructAtOffset<typename T::SubTable> (this, offset);
-  }
+  { return this + reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset); }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, format);
     if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
-    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
+    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
   }
 
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  { dispatch (c); }
+
   /* This is called from may_dispatch() above with hb_sanitize_context_t. */
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
-                  extensionOffset != 0 &&
                   extensionLookupType != T::SubTable::Extension);
   }
 
@@ -2547,7 +3118,7 @@
   HBUINT16      extensionLookupType;    /* Lookup type of subtable referenced
                                          * by ExtensionOffset (i.e. the
                                          * extension subtable). */
-  HBUINT32      extensionOffset;        /* Offset to the extension subtable,
+  Offset32      extensionOffset;        /* Offset to the extension subtable,
                                          * of lookup type subtable. */
   public:
   DEFINE_SIZE_STATIC (8);
@@ -2568,17 +3139,17 @@
   {
     switch (u.format) {
     case 1: return u.format1.template get_subtable<typename T::SubTable> ();
-    default:return Null(typename T::SubTable);
+    default:return Null (typename T::SubTable);
     }
   }
 
-  template <typename context_t>
-  typename context_t::return_t dispatch (context_t *c) const
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
     TRACE_DISPATCH (this, u.format);
     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
-    case 1: return_trace (u.format1.dispatch (c));
+    case 1: return_trace (u.format1.dispatch (c, hb_forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     }
   }
@@ -2601,7 +3172,7 @@
   void init (const TLookup &lookup)
   {
     digest.init ();
-    lookup.add_coverage (&digest);
+    lookup.collect_coverage (&digest);
 
     subtables.init ();
     OT::hb_get_subtables_context_t c_get_subtables (subtables);
@@ -2661,11 +3232,18 @@
 
   bool find_variations_index (const int *coords, unsigned int num_coords,
                               unsigned int *index) const
-  { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
-           .find_index (coords, num_coords, index); }
+  {
+#ifdef HB_NO_VAR
+    *index = FeatureVariations::NOT_FOUND_INDEX;
+    return false;
+#endif
+    return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
+            .find_index (coords, num_coords, index);
+  }
   const Feature& get_feature_variation (unsigned int feature_index,
                                         unsigned int variations_index) const
   {
+#ifndef HB_NO_VAR
     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
         version.to_int () >= 0x00010001u)
     {
@@ -2674,32 +3252,90 @@
       if (feature)
         return *feature;
     }
+#endif
     return get_feature (feature_index);
   }
 
+  void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
+                                          hb_set_t       *lookup_indexes /* OUT */) const
+  {
+#ifndef HB_NO_VAR
+    if (version.to_int () >= 0x00010001u)
+      (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
+#endif
+  }
+
   template <typename TLookup>
-  bool subset (hb_subset_context_t *c) const
+  void closure_lookups (hb_face_t      *face,
+                        const hb_set_t *glyphs,
+                        hb_set_t       *lookup_indexes /* IN/OUT */) const
+  {
+    hb_set_t visited_lookups, inactive_lookups;
+    OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
+
+    for (unsigned lookup_index : + hb_iter (lookup_indexes))
+      reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
+
+    hb_set_union (lookup_indexes, &visited_lookups);
+    hb_set_subtract (lookup_indexes, &inactive_lookups);
+  }
+
+  template <typename TLookup>
+  bool subset (hb_subset_layout_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct GSUBGPOS *out = c->serializer->embed (*this);
+    auto *out = c->subset_context->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
 
-    out->scriptList.serialize_subset (c, this+scriptList, out);
-    out->featureList.serialize_subset (c, this+featureList, out);
+    typedef LookupOffsetList<TLookup> TLookupList;
+    reinterpret_cast<OffsetTo<TLookupList> &> (out->lookupList)
+        .serialize_subset (c->subset_context,
+                           reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList),
+                           this,
+                           c);
 
-    typedef OffsetListOf<TLookup> TLookupList;
-    /* TODO Use intersects() to count how many subtables survive? */
-    CastR<OffsetTo<TLookupList> > (out->lookupList)
-      .serialize_subset (c,
-                         this+CastR<const OffsetTo<TLookupList> > (lookupList),
-                         out);
+    reinterpret_cast<OffsetTo<RecordListOfFeature> &> (out->featureList)
+        .serialize_subset (c->subset_context,
+                           reinterpret_cast<const OffsetTo<RecordListOfFeature> &> (featureList),
+                           this,
+                           c);
 
+    out->scriptList.serialize_subset (c->subset_context,
+                                      scriptList,
+                                      this,
+                                      c);
+
+#ifndef HB_NO_VAR
     if (version.to_int () >= 0x00010001u)
-     out->featureVars.serialize_subset (c, this+featureVars, out);
+    {
+      bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
+      if (!ret)
+      {
+        out->version.major = 1;
+        out->version.minor = 0;
+      }
+    }
+#endif
 
     return_trace (true);
   }
 
+  void closure_features (const hb_map_t *lookup_indexes, /* IN */
+                         hb_set_t       *feature_indexes /* OUT */) const
+  {
+    unsigned int feature_count = hb_min (get_feature_count (), (unsigned) HB_MAX_FEATURES);
+    for (unsigned i = 0; i < feature_count; i++)
+    {
+      const Feature& f = get_feature (i);
+      if ((!f.featureParams.is_null ()) || f.intersects_lookup_indexes (lookup_indexes))
+        feature_indexes->add (i);
+    }
+#ifndef HB_NO_VAR
+    if (version.to_int () >= 0x00010001u)
+      (this+featureVars).closure_features (lookup_indexes, feature_indexes);
+#endif
+  }
+
   unsigned int get_size () const
   {
     return min_size +
@@ -2711,12 +3347,19 @@
   {
     TRACE_SANITIZE (this);
     typedef OffsetListOf<TLookup> TLookupList;
-    return_trace (version.sanitize (c) &&
-                  likely (version.major == 1) &&
-                  scriptList.sanitize (c, this) &&
-                  featureList.sanitize (c, this) &&
-                  CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
-                  (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
+    if (unlikely (!(version.sanitize (c) &&
+                    likely (version.major == 1) &&
+                    scriptList.sanitize (c, this) &&
+                    featureList.sanitize (c, this) &&
+                    reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
+      return_trace (false);
+
+#ifndef HB_NO_VAR
+    if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
+      return_trace (false);
+#endif
+
+    return_trace (true);
   }
 
   template <typename T>
@@ -2724,8 +3367,8 @@
   {
     void init (hb_face_t *face)
     {
-      this->table = hb_sanitize_context_t().reference_table<T> (face);
-      if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
+      this->table = hb_sanitize_context_t ().reference_table<T> (face);
+      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
       {
         hb_blob_destroy (this->table.get_blob ());
         this->table = hb_blob_get_empty ();
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh
index 7a543b0..f8cd27f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh
@@ -136,7 +136,7 @@
  * ExtenderGlyphs -- Extender Glyph Table
  */
 
-typedef SortedArrayOf<GlyphID> ExtenderGlyphs;
+typedef SortedArrayOf<HBGlyphID> ExtenderGlyphs;
 
 
 /*
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc
index a8e579b..c326120 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc
@@ -28,6 +28,14 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_LAYOUT
+
+#ifdef HB_NO_OT_TAG
+#error "Cannot compile hb-ot-layout.cc with HB_NO_OT_TAG."
+#endif
+
 #include "hb-open-type.hh"
 #include "hb-ot-layout.hh"
 #include "hb-ot-face.hh"
@@ -35,7 +43,6 @@
 #include "hb-map.hh"
 
 #include "hb-ot-kern-table.hh"
-#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
@@ -44,9 +51,8 @@
 #include "hb-ot-name-table.hh"
 #include "hb-ot-os2-table.hh"
 
-#include "hb-aat-layout-lcar-table.hh"
 #include "hb-aat-layout-morx-table.hh"
-
+#include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise.
 
 /**
  * SECTION:hb-ot-layout
@@ -62,18 +68,53 @@
  * kern
  */
 
+#ifndef HB_NO_OT_KERN
+/**
+ * hb_ot_layout_has_kerning:
+ * @face: The #hb_face_t to work on
+ *
+ * Tests whether a face includes any kerning data in the 'kern' table.
+ * Does NOT test for kerning lookups in the GPOS table.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ **/
 bool
 hb_ot_layout_has_kerning (hb_face_t *face)
 {
   return face->table.kern->has_data ();
 }
 
+/**
+ * hb_ot_layout_has_machine_kerning:
+ * @face: The #hb_face_t to work on
+ *
+ * Tests whether a face includes any state-machine kerning in the 'kern' table.
+ * Does NOT examine the GPOS table.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ **/
 bool
 hb_ot_layout_has_machine_kerning (hb_face_t *face)
 {
   return face->table.kern->has_state_machine ();
 }
 
+/**
+ * hb_ot_layout_has_cross_kerning:
+ * @face: The #hb_face_t to work on
+ *
+ * Tests whether a face has any cross-stream kerning (i.e., kerns
+ * that make adjustments perpendicular to the direction of the text
+ * flow: Y adjustments in horizontal text or X adjustments in
+ * vertical text) in the 'kern' table.
+ *
+ * Does NOT examine the GPOS table.
+ *
+ * Return value: true is data found, false otherwise
+ *
+ **/
 bool
 hb_ot_layout_has_cross_kerning (hb_face_t *face)
 {
@@ -92,6 +133,7 @@
 
   kern.apply (&c);
 }
+#endif
 
 
 /*
@@ -99,10 +141,13 @@
  */
 
 bool
-OT::GDEF::is_blacklisted (hb_blob_t *blob,
+OT::GDEF::is_blocklisted (hb_blob_t *blob,
                           hb_face_t *face) const
 {
-  /* The ugly business of blacklisting individual fonts' tables happen here!
+#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+  return false;
+#endif
+  /* The ugly business of blocklisting individual fonts' tables happen here!
    * See this thread for why we finally had to bend in and do this:
    * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
    *
@@ -119,84 +164,82 @@
    *     https://bugzilla.mozilla.org/show_bug.cgi?id=1279693
    *     https://bugzilla.mozilla.org/show_bug.cgi?id=1279875
    */
-#define ENCODE(x,y,z) (((uint64_t) (x) << 48) | ((uint64_t) (y) << 24) | (uint64_t) (z))
-  switch ENCODE(blob->length,
-                face->table.GSUB->table.get_length (),
-                face->table.GPOS->table.get_length ())
+  switch HB_CODEPOINT_ENCODE3(blob->length,
+                              face->table.GSUB->table.get_length (),
+                              face->table.GPOS->table.get_length ())
   {
     /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
-    case ENCODE (442, 2874, 42038):
+    case HB_CODEPOINT_ENCODE3 (442, 2874, 42038):
     /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
-    case ENCODE (430, 2874, 40662):
+    case HB_CODEPOINT_ENCODE3 (430, 2874, 40662):
     /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
-    case ENCODE (442, 2874, 39116):
+    case HB_CODEPOINT_ENCODE3 (442, 2874, 39116):
     /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
-    case ENCODE (430, 2874, 39374):
+    case HB_CODEPOINT_ENCODE3 (430, 2874, 39374):
     /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
-    case ENCODE (490, 3046, 41638):
+    case HB_CODEPOINT_ENCODE3 (490, 3046, 41638):
     /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
-    case ENCODE (478, 3046, 41902):
+    case HB_CODEPOINT_ENCODE3 (478, 3046, 41902):
     /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c  tahoma.ttf from Windows 8 */
-    case ENCODE (898, 12554, 46470):
+    case HB_CODEPOINT_ENCODE3 (898, 12554, 46470):
     /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc  tahomabd.ttf from Windows 8 */
-    case ENCODE (910, 12566, 47732):
+    case HB_CODEPOINT_ENCODE3 (910, 12566, 47732):
     /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e  tahoma.ttf from Windows 8.1 */
-    case ENCODE (928, 23298, 59332):
+    case HB_CODEPOINT_ENCODE3 (928, 23298, 59332):
     /* sha1sum:6d400781948517c3c0441ba42acb309584b73033  tahomabd.ttf from Windows 8.1 */
-    case ENCODE (940, 23310, 60732):
+    case HB_CODEPOINT_ENCODE3 (940, 23310, 60732):
     /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
-    case ENCODE (964, 23836, 60072):
+    case HB_CODEPOINT_ENCODE3 (964, 23836, 60072):
     /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
-    case ENCODE (976, 23832, 61456):
+    case HB_CODEPOINT_ENCODE3 (976, 23832, 61456):
     /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846  tahoma.ttf from Windows 10 */
-    case ENCODE (994, 24474, 60336):
+    case HB_CODEPOINT_ENCODE3 (994, 24474, 60336):
     /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343  tahomabd.ttf from Windows 10 */
-    case ENCODE (1006, 24470, 61740):
+    case HB_CODEPOINT_ENCODE3 (1006, 24470, 61740):
     /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
-    case ENCODE (1006, 24576, 61346):
+    case HB_CODEPOINT_ENCODE3 (1006, 24576, 61346):
     /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
-    case ENCODE (1018, 24572, 62828):
+    case HB_CODEPOINT_ENCODE3 (1018, 24572, 62828):
     /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5  tahoma.ttf from Windows 10 AU */
-    case ENCODE (1006, 24576, 61352):
+    case HB_CODEPOINT_ENCODE3 (1006, 24576, 61352):
     /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2  tahomabd.ttf from Windows 10 AU */
-    case ENCODE (1018, 24572, 62834):
+    case HB_CODEPOINT_ENCODE3 (1018, 24572, 62834):
     /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7  Tahoma.ttf from Mac OS X 10.9 */
-    case ENCODE (832, 7324, 47162):
+    case HB_CODEPOINT_ENCODE3 (832, 7324, 47162):
     /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba  Tahoma Bold.ttf from Mac OS X 10.9 */
-    case ENCODE (844, 7302, 45474):
+    case HB_CODEPOINT_ENCODE3 (844, 7302, 45474):
     /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc  himalaya.ttf from Windows 7 */
-    case ENCODE (180, 13054, 7254):
+    case HB_CODEPOINT_ENCODE3 (180, 13054, 7254):
     /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0  himalaya.ttf from Windows 8 */
-    case ENCODE (192, 12638, 7254):
+    case HB_CODEPOINT_ENCODE3 (192, 12638, 7254):
     /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427  himalaya.ttf from Windows 8.1 */
-    case ENCODE (192, 12690, 7254):
+    case HB_CODEPOINT_ENCODE3 (192, 12690, 7254):
     /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44  cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */
     /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371  cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */
-    case ENCODE (188, 248, 3852):
+    case HB_CODEPOINT_ENCODE3 (188, 248, 3852):
     /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f  cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
     /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b  cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
-    case ENCODE (188, 264, 3426):
+    case HB_CODEPOINT_ENCODE3 (188, 264, 3426):
     /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */
-    case ENCODE (1058, 47032, 11818):
+    case HB_CODEPOINT_ENCODE3 (1058, 47032, 11818):
     /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/
-    case ENCODE (1046, 47030, 12600):
+    case HB_CODEPOINT_ENCODE3 (1046, 47030, 12600):
     /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */
-    case ENCODE (1058, 71796, 16770):
+    case HB_CODEPOINT_ENCODE3 (1058, 71796, 16770):
     /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */
-    case ENCODE (1046, 71790, 17862):
+    case HB_CODEPOINT_ENCODE3 (1046, 71790, 17862):
     /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
-    case ENCODE (1046, 71788, 17112):
+    case HB_CODEPOINT_ENCODE3 (1046, 71788, 17112):
     /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
-    case ENCODE (1058, 71794, 17514):
+    case HB_CODEPOINT_ENCODE3 (1058, 71794, 17514):
     /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */
-    case ENCODE (1330, 109904, 57938):
+    case HB_CODEPOINT_ENCODE3 (1330, 109904, 57938):
     /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
-    case ENCODE (1330, 109904, 58972):
+    case HB_CODEPOINT_ENCODE3 (1330, 109904, 58972):
     /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85  Padauk.ttf
      *  "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
-    case ENCODE (1004, 59092, 14836):
+    case HB_CODEPOINT_ENCODE3 (1004, 59092, 14836):
       return true;
-#undef ENCODE
   }
   return false;
 }
@@ -219,6 +262,15 @@
 
 /* Public API */
 
+/**
+ * hb_ot_layout_has_glyph_classes:
+ * @face: #hb_face_t to work upon
+ *
+ * Tests whether a face has any glyph classes defined in its GDEF table.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face)
 {
@@ -227,6 +279,13 @@
 
 /**
  * hb_ot_layout_get_glyph_class:
+ * @face: The #hb_face_t to work on
+ * @glyph: The #hb_codepoint_t code point to query
+ *
+ * Fetches the GDEF class of the requested glyph in the specified face.
+ *
+ * Return value: The #hb_ot_layout_glyph_class_t glyph class of the given code
+ * point in the GDEF table of the face.
  *
  * Since: 0.9.7
  **/
@@ -239,6 +298,13 @@
 
 /**
  * hb_ot_layout_get_glyphs_in_class:
+ * @face: The #hb_face_t to work on
+ * @klass: The #hb_ot_layout_glyph_class_t GDEF class to retrieve
+ * @glyphs: (out): The #hb_set_t set of all glyphs belonging to the requested
+ *          class.
+ *
+ * Retrieves the set of all glyphs from the face that belong to the requested
+ * glyph class in the face's GDEF table.
  *
  * Since: 0.9.7
  **/
@@ -250,6 +316,22 @@
   return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs);
 }
 
+#ifndef HB_NO_LAYOUT_UNUSED
+/**
+ * hb_ot_layout_get_attach_points:
+ * @face: The #hb_face_t to work on
+ * @glyph: The #hb_codepoint_t code point to query
+ * @start_offset: offset of the first attachment point to retrieve
+ * @point_count: (inout) (allow-none): Input = the maximum number of attachment points to return;
+ *               Output = the actual number of attachment points returned (may be zero)
+ * @point_array: (out) (array length=point_count): The array of attachment points found for the query
+ *
+ * Fetches a list of all attachment points for the specified glyph in the GDEF
+ * table of the face. The list returned will begin at the offset provided.
+ *
+ * Useful if the client program wishes to cache the list.
+ *
+ **/
 unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
                                 hb_codepoint_t  glyph,
@@ -262,7 +344,20 @@
                                                      point_count,
                                                      point_array);
 }
-
+/**
+ * hb_ot_layout_get_ligature_carets:
+ * @font: The #hb_font_t to work on
+ * @direction: The #hb_direction_t text direction to use
+ * @glyph: The #hb_codepoint_t code point to query
+ * @start_offset: offset of the first caret position to retrieve
+ * @caret_count: (inout) (allow-none): Input = the maximum number of caret positions to return;
+ *               Output = the actual number of caret positions returned (may be zero)
+ * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query
+ *
+ * Fetches a list of the caret positions defined for a ligature glyph in the GDEF
+ * table of the font. The list returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_get_ligature_carets (hb_font_t      *font,
                                   hb_direction_t  direction,
@@ -271,16 +366,9 @@
                                   unsigned int   *caret_count /* IN/OUT */,
                                   hb_position_t  *caret_array /* OUT */)
 {
-  unsigned int result_caret_count = 0;
-  unsigned int result = font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, &result_caret_count, caret_array);
-  if (result)
-  {
-    if (caret_count) *caret_count = result_caret_count;
-  }
-  else
-    result = font->face->table.lcar->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
-  return result;
+  return font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
 }
+#endif
 
 
 /*
@@ -288,34 +376,22 @@
  */
 
 bool
-OT::GSUB::is_blacklisted (hb_blob_t *blob HB_UNUSED,
+OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
                           hb_face_t *face) const
 {
-  /* Mac OS X prefers morx over GSUB.  It also ships with various Indic fonts,
-   * all by 'MUTF' foundry (Tamil MN, Tamil Sangam MN, etc.), that have broken
-   * GSUB/GPOS tables.  Some have GSUB with zero scripts, those are ignored by
-   * our morx/GSUB preference code.  But if GSUB has non-zero scripts, we tend
-   * to prefer it over morx because we want to be consistent with other OpenType
-   * shapers.
-   *
-   * To work around broken Indic Mac system fonts, we ignore GSUB table if
-   * OS/2 VendorId is 'MUTF' and font has morx table as well.
-   *
-   * https://github.com/harfbuzz/harfbuzz/issues/1410
-   * https://github.com/harfbuzz/harfbuzz/issues/1348
-   * https://github.com/harfbuzz/harfbuzz/issues/1391
-   */
-  if (unlikely (face->table.OS2->achVendID == HB_TAG ('M','U','T','F') &&
-                face->table.morx->has_data ()))
-    return true;
-
+#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+  return false;
+#endif
   return false;
 }
 
 bool
-OT::GPOS::is_blacklisted (hb_blob_t *blob HB_UNUSED,
+OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
                           hb_face_t *face HB_UNUSED) const
 {
+#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+  return false;
+#endif
   return false;
 }
 
@@ -326,11 +402,24 @@
   switch (table_tag) {
     case HB_OT_TAG_GSUB: return *face->table.GSUB->table;
     case HB_OT_TAG_GPOS: return *face->table.GPOS->table;
-    default:             return Null(OT::GSUBGPOS);
+    default:             return Null (OT::GSUBGPOS);
   }
 }
 
 
+/**
+ * hb_ot_layout_table_get_script_tags:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @start_offset: offset of the first script tag to retrieve
+ * @script_count: (inout) (allow-none): Input = the maximum number of script tags to return;
+ *                Output = the actual number of script tags returned (may be zero)
+ * @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query
+ *
+ * Fetches a list of all scripts enumerated in the specified face's GSUB table
+ * or GPOS table. The list returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_table_get_script_tags (hb_face_t    *face,
                                     hb_tag_t      table_tag,
@@ -345,11 +434,24 @@
 
 #define HB_OT_TAG_LATIN_SCRIPT          HB_TAG ('l', 'a', 't', 'n')
 
+/**
+ * hb_ot_layout_table_find_script:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_tag: #hb_tag_t of the script tag requested
+ * @script_index: (out): The index of the requested script tag
+ *
+ * Fetches the index if a given script tag in the specified face's GSUB table
+ * or GPOS table.
+ *
+ * Return value: true if the script is found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_table_find_script (hb_face_t    *face,
                                 hb_tag_t      table_tag,
                                 hb_tag_t      script_tag,
-                                unsigned int *script_index)
+                                unsigned int *script_index /* OUT */)
 {
   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -375,20 +477,38 @@
   return false;
 }
 
+#ifndef HB_DISABLE_DEPRECATED
+/**
+ * hb_ot_layout_table_choose_script:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_tags: Array of #hb_tag_t script tags
+ * @script_index: (out): The index of the requested script tag
+ * @chosen_script: (out): #hb_tag_t of the script tag requested
+ *
+ * Deprecated since 2.0.0
+ **/
 hb_bool_t
 hb_ot_layout_table_choose_script (hb_face_t      *face,
                                   hb_tag_t        table_tag,
                                   const hb_tag_t *script_tags,
-                                  unsigned int   *script_index,
-                                  hb_tag_t       *chosen_script)
+                                  unsigned int   *script_index  /* OUT */,
+                                  hb_tag_t       *chosen_script /* OUT */)
 {
   const hb_tag_t *t;
   for (t = script_tags; *t; t++);
   return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script);
 }
+#endif
 
 /**
  * hb_ot_layout_table_select_script:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_count: Number of script tags in the array
+ * @script_tags: Array of #hb_tag_t script tags
+ * @script_index: (out): The index of the requested script
+ * @chosen_script: (out): #hb_tag_t of the requested script
  *
  * Since: 2.0.0
  **/
@@ -442,6 +562,19 @@
   return false;
 }
 
+
+/**
+ * hb_ot_layout_table_get_feature_tags:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @start_offset: offset of the first feature tag to retrieve
+ * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ *                 Output = the actual number of feature tags returned (may be zero)
+ * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table
+ *
+ * Fetches a list of all feature tags in the given face's GSUB or GPOS table.
+ *
+ **/
 unsigned int
 hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
                                      hb_tag_t      table_tag,
@@ -454,11 +587,24 @@
   return g.get_feature_tags (start_offset, feature_count, feature_tags);
 }
 
+
+/**
+ * hb_ot_layout_table_find_feature:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @feature_tag: The #hb_tag_t og the requested feature tag
+ * @feature_index: (out): The index of the requested feature
+ *
+ * Fetches the index for a given feature tag in the specified face's GSUB table
+ * or GPOS table.
+ *
+ * Return value: true if the feature is found, false otherwise
+ **/
 bool
 hb_ot_layout_table_find_feature (hb_face_t    *face,
                                  hb_tag_t      table_tag,
                                  hb_tag_t      feature_tag,
-                                 unsigned int *feature_index)
+                                 unsigned int *feature_index /* OUT */)
 {
   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -477,6 +623,20 @@
 }
 
 
+/**
+ * hb_ot_layout_script_get_language_tags:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @start_offset: offset of the first language tag to retrieve
+ * @language_count: (inout) (allow-none): Input = the maximum number of language tags to return;
+ *                  Output = the actual number of language tags returned (may be zero)
+ * @language_tags: (out) (array length=language_count): Array of language tags found in the table
+ *
+ * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath
+ * the specified script index. The list returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_script_get_language_tags (hb_face_t    *face,
                                        hb_tag_t      table_tag,
@@ -490,6 +650,24 @@
   return s.get_lang_sys_tags (start_offset, language_count, language_tags);
 }
 
+
+#ifndef HB_DISABLE_DEPRECATED
+/**
+ * hb_ot_layout_script_find_language:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_tag: The #hb_tag_t of the requested language
+ * @language_index: The index of the requested language
+ *
+ * Fetches the index of a given language tag in the specified face's GSUB table
+ * or GPOS table, underneath the specified script tag.
+ *
+ * Return value: true if the language tag is found, false otherwise
+ *
+ * Since: ??
+ * Deprecated: ??
+ **/
 hb_bool_t
 hb_ot_layout_script_find_language (hb_face_t    *face,
                                    hb_tag_t      table_tag,
@@ -504,9 +682,22 @@
                                               &language_tag,
                                               language_index);
 }
+#endif
+
 
 /**
  * hb_ot_layout_script_select_language:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_count: The number of languages in the specified script
+ * @language_tags: The array of language tags
+ * @language_index: (out): The index of the requested language
+ *
+ * Fetches the index of a given language tag in the specified face's GSUB table
+ * or GPOS table, underneath the specified script index.
+ *
+ * Return value: true if the language tag is found, false otherwise
  *
  * Since: 2.0.0
  **/
@@ -536,12 +727,27 @@
   return false;
 }
 
+
+/**
+ * hb_ot_layout_language_get_required_feature_index:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @feature_index: (out): The index of the requested feature
+ *
+ * Fetches the index of a requested feature in the given face's GSUB or GPOS table,
+ * underneath the specified script and language.
+ *
+ * Return value: true if the feature is found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
                                                   hb_tag_t      table_tag,
                                                   unsigned int  script_index,
                                                   unsigned int  language_index,
-                                                  unsigned int *feature_index)
+                                                  unsigned int *feature_index /* OUT */)
 {
   return hb_ot_layout_language_get_required_feature (face,
                                                      table_tag,
@@ -551,8 +757,20 @@
                                                      nullptr);
 }
 
+
 /**
  * hb_ot_layout_language_get_required_feature:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @feature_index: (out): The index of the requested feature
+ * @feature_tag: (out): The #hb_tag_t of the requested feature
+ *
+ * Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,
+ * underneath the specified script and language.
+ *
+ * Return value: true if the feature is found, false otherwise
  *
  * Since: 0.9.30
  **/
@@ -561,8 +779,8 @@
                                             hb_tag_t      table_tag,
                                             unsigned int  script_index,
                                             unsigned int  language_index,
-                                            unsigned int *feature_index,
-                                            hb_tag_t     *feature_tag)
+                                            unsigned int *feature_index /* OUT */,
+                                            hb_tag_t     *feature_tag   /* OUT */)
 {
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
@@ -574,6 +792,22 @@
   return l.has_required_feature ();
 }
 
+
+/**
+ * hb_ot_layout_language_get_feature_indexes:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @start_offset: offset of the first feature tag to retrieve
+ * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ *                 Output: the actual number of feature tags returned (may be zero)
+ * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query
+ *
+ * Fetches a list of all features in the specified face's GSUB table
+ * or GPOS table, underneath the specified script and language. The list
+ * returned will begin at the offset provided.
+ **/
 unsigned int
 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
                                            hb_tag_t      table_tag,
@@ -589,6 +823,23 @@
   return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
 }
 
+
+/**
+ * hb_ot_layout_language_get_feature_tags:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @start_offset: offset of the first feature tag to retrieve
+ * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ *                 Output = the actual number of feature tags returned (may be zero)
+ * @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query
+ *
+ * Fetches a list of all features in the specified face's GSUB table
+ * or GPOS table, underneath the specified script and language. The list
+ * returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
                                         hb_tag_t      table_tag,
@@ -614,13 +865,28 @@
 }
 
 
+/**
+ * hb_ot_layout_language_find_feature:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @feature_tag: #hb_tag_t of the feature tag requested
+ * @feature_index: (out): The index of the requested feature
+ *
+ * Fetches the index of a given feature tag in the specified face's GSUB table
+ * or GPOS table, underneath the specified script and language.
+ *
+ * Return value: true if the feature is found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_language_find_feature (hb_face_t    *face,
                                     hb_tag_t      table_tag,
                                     unsigned int  script_index,
                                     unsigned int  language_index,
                                     hb_tag_t      feature_tag,
-                                    unsigned int *feature_index)
+                                    unsigned int *feature_index /* OUT */)
 {
   static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), "");
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -640,8 +906,20 @@
   return false;
 }
 
+
 /**
  * hb_ot_layout_feature_get_lookups:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @feature_index: The index of the requested feature
+ * @start_offset: offset of the first lookup to retrieve
+ * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ *                Output = the actual number of lookups returned (may be zero)
+ * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query
+ *
+ * Fetches a list of all lookups enumerated for the specified feature, in
+ * the specified face's GSUB table or GPOS table. The list returned will
+ * begin at the offset provided.
  *
  * Since: 0.9.7
  **/
@@ -662,8 +940,14 @@
                                                            lookup_indexes);
 }
 
+
 /**
  * hb_ot_layout_table_get_lookup_count:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ *
+ * Fetches the total number of lookups enumerated in the specified
+ * face's GSUB table or GPOS table.
  *
  * Since: 0.9.22
  **/
@@ -677,12 +961,12 @@
 
 struct hb_collect_features_context_t
 {
-  hb_collect_features_context_t (hb_face_t       *face,
-                                 hb_tag_t         table_tag,
-                                 hb_set_t        *feature_indexes_)
+  hb_collect_features_context_t (hb_face_t *face,
+                                 hb_tag_t   table_tag,
+                                 hb_set_t  *feature_indexes_)
     : g (get_gsubgpos_table (face, table_tag)),
       feature_indexes (feature_indexes_),
-      script_count(0),langsys_count(0) {}
+      script_count (0),langsys_count (0), feature_index_count (0) {}
 
   bool visited (const OT::Script &s)
   {
@@ -711,6 +995,12 @@
     return visited (l, visited_langsys);
   }
 
+  bool visited_feature_indices (unsigned count)
+  {
+    feature_index_count += count;
+    return feature_index_count > HB_MAX_FEATURE_INDICES;
+  }
+
   private:
   template <typename T>
   bool visited (const T &p, hb_set_t &visited_set)
@@ -732,6 +1022,7 @@
   hb_set_t visited_langsys;
   unsigned int script_count;
   unsigned int langsys_count;
+  unsigned int feature_index_count;
 };
 
 static void
@@ -744,10 +1035,11 @@
   if (!features)
   {
     /* All features. */
-    if (l.has_required_feature ())
+    if (l.has_required_feature () && !c->visited_feature_indices (1))
       c->feature_indexes->add (l.get_required_feature_index ());
 
-    l.add_feature_indexes_to (c->feature_indexes);
+    if (!c->visited_feature_indices (l.featureIndex.len))
+      l.add_feature_indexes_to (c->feature_indexes);
   }
   else
   {
@@ -805,8 +1097,21 @@
   }
 }
 
+
 /**
  * hb_ot_layout_collect_features:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @scripts: The array of scripts to collect features for
+ * @languages: The array of languages to collect features for
+ * @features: The array of features to collect
+ * @feature_indexes: (out): The array of feature indexes found for the query
+ *
+ * Fetches a list of all feature indexes in the specified face's GSUB table
+ * or GPOS table, underneath the specified scripts, languages, and features.
+ * If no list of scripts is provided, all scripts will be queried. If no list
+ * of languages is provided, all languages will be queried. If no list of
+ * features is provided, all features will be queried.
  *
  * Since: 1.8.5
  **/
@@ -843,8 +1148,21 @@
   }
 }
 
+
 /**
  * hb_ot_layout_collect_lookups:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @scripts: The array of scripts to collect lookups for
+ * @languages: The array of languages to collect lookups for
+ * @features: The array of features to collect lookups for
+ * @lookup_indexes: (out): The array of lookup indexes found for the query
+ *
+ * Fetches a list of all feature-lookup indexes in the specified face's GSUB
+ * table or GPOS table, underneath the specified scripts, languages, and
+ * features. If no list of scripts is provided, all scripts will be queried.
+ * If no list of languages is provided, all languages will be queried. If no
+ * list of features is provided, all features will be queried.
  *
  * Since: 0.9.8
  **/
@@ -864,10 +1182,24 @@
   for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
        hb_set_next (&feature_indexes, &feature_index);)
     g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
+
+  g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes);
 }
 
+
+#ifndef HB_NO_LAYOUT_COLLECT_GLYPHS
 /**
  * hb_ot_layout_lookup_collect_glyphs:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @lookup_index: The index of the feature lookup to query
+ * @glyphs_before: (out): Array of glyphs preceding the substitution range
+ * @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup
+ * @glyphs_after: (out): Array of glyphs following the substitution range
+ * @glyphs_output: (out): Array of glyphs that would be the substitued output of the lookup
+ *
+ * Fetches a list of all glyphs affected by the specified lookup in the
+ * specified face's GSUB table or GPOS table.
  *
  * Since: 0.9.7
  **/
@@ -902,10 +1234,24 @@
     }
   }
 }
+#endif
 
 
 /* Variations support */
 
+
+/**
+ * hb_ot_layout_table_find_feature_variations:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @coords: The variation coordinates to query
+ * @num_coords: The number of variation coorinates
+ * @variations_index: (out): The array of feature variations found for the query
+ *
+ * Fetches a list of feature variations in the specified face's GSUB table
+ * or GPOS table, at the specified variation coordinates.
+ *
+ **/
 hb_bool_t
 hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
                                             hb_tag_t      table_tag,
@@ -918,6 +1264,23 @@
   return g.find_variations_index (coords, num_coords, variations_index);
 }
 
+
+/**
+ * hb_ot_layout_feature_with_variations_get_lookups:
+ * @face: #hb_face_t to work upon
+ * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @feature_index: The index of the feature to query
+ * @variations_index: The index of the feature variation to query
+ * @start_offset: offset of the first lookup to retrieve
+ * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ *                Output = the actual number of lookups returned (may be zero)
+ * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query
+ *
+ * Fetches a list of all lookups enumerated for the specified feature, in
+ * the specified face's GSUB table or GPOS table, enabled at the specified
+ * variations index. The list returned will begin at the offset provided.
+ *
+ **/
 unsigned int
 hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
                                                   hb_tag_t      table_tag,
@@ -940,14 +1303,35 @@
  * OT::GSUB
  */
 
+
+/**
+ * hb_ot_layout_has_substitution:
+ * @face: #hb_face_t to work upon
+ *
+ * Tests whether the specified face includes any GSUB substitutions.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face)
 {
   return face->table.GSUB->table->has_data ();
 }
 
+
 /**
  * hb_ot_layout_lookup_would_substitute:
+ * @face: #hb_face_t to work upon
+ * @lookup_index: The index of the lookup to query
+ * @glyphs: The sequence of glyphs to query for substitution
+ * @glyphs_length: The length of the glyph sequence
+ * @zero_context: #hb_bool_t indicating whether substitutions should be context-free
+ *
+ * Tests whether a specified lookup in the specified face would
+ * trigger a substitution on the given glyph sequence.
+ *
+ * Return value: true if a substitution would be triggered, false otherwise
  *
  * Since: 0.9.7
  **/
@@ -958,32 +1342,28 @@
                                       unsigned int          glyphs_length,
                                       hb_bool_t             zero_context)
 {
-  return hb_ot_layout_lookup_would_substitute_fast (face,
-                                                    lookup_index,
-                                                    glyphs, glyphs_length,
-                                                    zero_context);
-}
-
-bool
-hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
-                                           unsigned int          lookup_index,
-                                           const hb_codepoint_t *glyphs,
-                                           unsigned int          glyphs_length,
-                                           bool                  zero_context)
-{
   if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false;
   OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
 
   const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
-
   return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]);
 }
 
+
+/**
+ * hb_ot_layout_substitute_start:
+ * @font: #hb_font_t to use
+ * @buffer: #hb_buffer_t buffer to work upon
+ *
+ * Called before substitution lookups are performed, to ensure that glyph
+ * class and other properties are set on the glyphs in the buffer.
+ *
+ **/
 void
 hb_ot_layout_substitute_start (hb_font_t    *font,
                                hb_buffer_t  *buffer)
 {
-_hb_ot_layout_set_glyph_props (font, buffer);
+  _hb_ot_layout_set_glyph_props (font, buffer);
 }
 
 void
@@ -1038,13 +1418,19 @@
 
 /**
  * hb_ot_layout_lookup_substitute_closure:
+ * @face: #hb_face_t to work upon
+ * @lookup_index: index of the feature lookup to query
+ * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookup
+ *
+ * Compute the transitive closure of glyphs needed for a
+ * specified lookup.
  *
  * Since: 0.9.7
  **/
 void
 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
                                         unsigned int  lookup_index,
-                                        hb_set_t     *glyphs)
+                                        hb_set_t     *glyphs /* OUT */)
 {
   hb_map_t done_lookups;
   OT::hb_closure_context_t c (face, glyphs, &done_lookups);
@@ -1056,6 +1442,9 @@
 
 /**
  * hb_ot_layout_lookups_substitute_closure:
+ * @face: #hb_face_t to work upon
+ * @lookups: The set of lookups to query
+ * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookups
  *
  * Compute the transitive closure of glyphs needed for all of the
  * provided lookups.
@@ -1065,7 +1454,7 @@
 void
 hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
                                          const hb_set_t *lookups,
-                                         hb_set_t       *glyphs)
+                                         hb_set_t       *glyphs /* OUT */)
 {
   hb_map_t done_lookups;
   OT::hb_closure_context_t c (face, glyphs, &done_lookups);
@@ -1076,7 +1465,7 @@
   do
   {
     glyphs_length = glyphs->get_population ();
-    if (lookups != nullptr)
+    if (lookups)
     {
       for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
         gsub.get_lookup (lookup_index).closure (&c, lookup_index);
@@ -1094,32 +1483,85 @@
  * OT::GPOS
  */
 
+
+/**
+ * hb_ot_layout_has_positioning:
+ * @face: #hb_face_t to work upon
+ *
+ * Return value: true if the face has GPOS data, false otherwise
+ *
+ **/
 hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face)
 {
   return face->table.GPOS->table->has_data ();
 }
 
+/**
+ * hb_ot_layout_position_start:
+ * @font: #hb_font_t to use
+ * @buffer: #hb_buffer_t buffer to work upon
+ *
+ * Called before positioning lookups are performed, to ensure that glyph
+ * attachment types and glyph-attachment chains are set for the glyphs in the buffer.
+ *
+ **/
 void
 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GPOS::position_start (font, buffer);
 }
 
+
+/**
+ * hb_ot_layout_position_finish_advances:
+ * @font: #hb_font_t to use
+ * @buffer: #hb_buffer_t buffer to work upon
+ *
+ * Called after positioning lookups are performed, to finish glyph advances.
+ *
+ **/
 void
 hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GPOS::position_finish_advances (font, buffer);
 }
 
+/**
+ * hb_ot_layout_position_finish_offsets:
+ * @font: #hb_font_t to use
+ * @buffer: #hb_buffer_t buffer to work upon
+ *
+ * Called after positioning lookups are performed, to finish glyph offsets.
+ *
+ **/
 void
 hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GPOS::position_finish_offsets (font, buffer);
 }
 
+
+#ifndef HB_NO_LAYOUT_FEATURE_PARAMS
 /**
  * hb_ot_layout_get_size_params:
+ * @face: #hb_face_t to work upon
+ * @design_size: (out): The design size of the face
+ * @subfamily_id: (out): The identifier of the face within the font subfamily
+ * @subfamily_name_id: (out): The ‘name’ table name ID of the face within the font subfamily
+ * @range_start: (out): The minimum size of the recommended size range for the face
+ * @range_end: (out): The maximum size of the recommended size range for the face
+ *
+ * Fetches optical-size feature data (i.e., the `size` feature from GPOS). Note that
+ * the subfamily_id and the subfamily name string (accessible via the subfamily_name_id)
+ * as used here are defined as pertaining only to fonts within a font family that differ
+ * specifically in their respective size ranges; other ways to differentiate fonts within
+ * a subfamily are not covered by the `size` feature.
+ *
+ * For more information on this distinction, see the [`size` feature documentation](
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size).
+ *
+ * Return value: true if data found, false otherwise
  *
  * Since: 0.9.10
  **/
@@ -1163,7 +1605,6 @@
 
   return false;
 }
-
 /**
  * hb_ot_layout_feature_get_name_ids:
  * @face: #hb_face_t to work upon
@@ -1238,24 +1679,20 @@
   if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID;
   return false;
 }
-
 /**
  * hb_ot_layout_feature_get_characters:
  * @face: #hb_face_t to work upon
  * @table_tag: table tag to query, "GSUB" or "GPOS".
  * @feature_index: index of feature to query.
- * @start_offset: In case the resulting char_count was equal to its input value, there
- *                is a chance there were more characters on the tag so this API can be
- *                called with an offset till resulting char_count gets to a number
- *                lower than input buffer (or consider using just a bigger buffer for
- *                one shot copying).
- * @char_count: (inout) (allow-none): The count of characters for which this feature
- *              provides glyph variants. (May be zero.)
- * @characters: (out caller-allocates) (array length=char_count): A buffer pointer. The Unicode codepoints
- *              of the characters for which this feature provides glyph variants.
+ * @start_offset: offset of the first character to retrieve
+ * @char_count: (inout) (allow-none): Input = the maximum number of characters to return;
+ *              Output = the actual number of characters returned (may be zero)
+ * @characters: (out caller-allocates) (array length=char_count): A buffer pointer.
+ *              The Unicode codepoints of the characters for which this feature provides
+ *               glyph variants.
  *
- * Fetches characters listed by designer under feature parameters for "Character
- * Variant" ("cvXX") features.
+ * Fetches a list of the characters defined as having a variant under the specified
+ * "Character Variant" ("cvXX") feature tag.
  *
  * Return value: Number of total sample characters in the cvXX feature.
  *
@@ -1270,25 +1707,12 @@
                                      hb_codepoint_t *characters  /* OUT.     May be NULL */)
 {
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
-
-  hb_tag_t feature_tag = g.get_feature_tag (feature_index);
-  const OT::Feature &f = g.get_feature (feature_index);
-
-  const OT::FeatureParams &feature_params = f.get_feature_params ();
-
-  const OT::FeatureParamsCharacterVariants& cv_params =
-    feature_params.get_character_variants_params(feature_tag);
-
-  unsigned int len = 0;
-  if (char_count && characters && start_offset < cv_params.characters.len)
-  {
-    len = MIN (cv_params.characters.len - start_offset, *char_count);
-    for (unsigned int i = 0; i < len; ++i)
-      characters[i] = cv_params.characters[start_offset + i];
-  }
-  if (char_count) *char_count = len;
-  return cv_params.characters.len;
+  return g.get_feature (feature_index)
+          .get_feature_params ()
+          .get_character_variants_params(g.get_feature_tag (feature_index))
+          .get_characters (start_offset, char_count, characters);
 }
+#endif
 
 
 /*
@@ -1455,13 +1879,17 @@
 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
 {
   GSUBProxy proxy (font->face);
+  if (!buffer->message (font, "start table GSUB")) return;
   apply (proxy, plan, font, buffer);
+  (void)buffer->message (font, "end table GSUB");
 }
 
 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
 {
   GPOSProxy proxy (font->face);
+  if (!buffer->message (font, "start table GPOS")) return;
   apply (proxy, plan, font, buffer);
+  (void)buffer->message (font, "end table GPOS");
 }
 
 void
@@ -1472,60 +1900,94 @@
   apply_string<GSUBProxy> (c, lookup, accel);
 }
 
-#if 0
-static const OT::BASE& _get_base (hb_face_t *face)
-{
-  return *face->table.BASE;
-}
-
+#ifndef HB_NO_BASE
+/**
+ * hb_ot_layout_get_baseline:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script_tag:  script tag.
+ * @language_tag: language tag.
+ * @coord: (out): baseline value if found.
+ *
+ * Fetches a baseline value from the face.
+ *
+ * Return value: if found baseline value in the font.
+ *
+ * Since: 2.6.0
+ **/
 hb_bool_t
-hb_ot_layout_get_baseline (hb_font_t               *font,
-                           hb_ot_layout_baseline_t  baseline,
-                           hb_direction_t           direction,
-                           hb_tag_t                 script_tag,
-                           hb_tag_t                 language_tag,
-                           hb_position_t           *coord        /* OUT.  May be NULL. */)
+hb_ot_layout_get_baseline (hb_font_t                   *font,
+                           hb_ot_layout_baseline_tag_t  baseline_tag,
+                           hb_direction_t               direction,
+                           hb_tag_t                     script_tag,
+                           hb_tag_t                     language_tag,
+                           hb_position_t               *coord        /* OUT.  May be NULL. */)
 {
-  const OT::BASE &base = _get_base (font->face);
-  bool result = base.get_baseline (font, baseline, direction, script_tag,
-                                   language_tag, coord);
+  bool result = font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord);
 
-  /* TODO: Simulate https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags#ideographic-em-box */
-  if (!result && coord) *coord = 0;
-
-  if (coord) *coord = font->em_scale_dir (*coord, direction);
+  if (result && coord)
+    *coord = HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (*coord) : font->em_scale_x (*coord);
 
   return result;
 }
+#endif
 
-/* To be moved to public header */
-/*
- * BASE
- */
+
+struct hb_get_glyph_alternates_dispatch_t :
+       hb_dispatch_context_t<hb_get_glyph_alternates_dispatch_t, unsigned>
+{
+  static return_t default_return_value () { return 0; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+
+  hb_face_t *face;
+
+  hb_get_glyph_alternates_dispatch_t (hb_face_t *face) :
+                                        face (face) {}
+
+  private:
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.get_glyph_alternates (hb_forward<Ts> (ds)...) )
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
+  ( default_return_value () )
+  public:
+  template <typename T, typename ...Ts> auto
+  dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
+  ( _dispatch (obj, hb_prioritize, hb_forward<Ts> (ds)...) )
+};
 
 /**
- * hb_ot_layout_baseline_t:
+ * hb_ot_layout_lookup_get_glyph_alternates:
+ * @face: a face.
+ * @lookup_index: index of the feature lookup to query.
+ * @glyph: a glyph id.
+ * @start_offset: starting offset.
+ * @alternate_count: (inout) (allow-none): Input = the maximum number of alternate glyphs to return;
+ *                   Output = the actual number of alternate glyphs returned (may be zero).
+ * @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer.
+ *                    Alternate glyphs associated with the glyph id.
  *
- * https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
+ * Fetches alternates of a glyph from a given GSUB lookup index.
  *
- * Since: DONTREPLACEME
- */
-typedef enum {
-  HB_OT_LAYOUT_BASELINE_HANG = HB_TAG('h','a','n','g'),
-  HB_OT_LAYOUT_BASELINE_ICFB = HB_TAG('i','c','f','b'),
-  HB_OT_LAYOUT_BASELINE_ICFT = HB_TAG('i','c','f','t'),
-  HB_OT_LAYOUT_BASELINE_IDEO = HB_TAG('i','d','e','o'),
-  HB_OT_LAYOUT_BASELINE_IDTB = HB_TAG('i','d','t','b'),
-  HB_OT_LAYOUT_BASELINE_MATH = HB_TAG('m','a','t','h'),
-  HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n')
-} hb_ot_layout_baseline_t;
-
-HB_EXTERN hb_bool_t
-hb_ot_layout_get_baseline (hb_font_t               *font,
-                           hb_ot_layout_baseline_t  baseline,
-                           hb_direction_t           direction,
-                           hb_tag_t                 script_tag,
-                           hb_tag_t                 language_tag,
-                           hb_position_t           *coord        /* OUT.  May be NULL. */);
+ * Return value: total number of alternates found in the specific lookup index for the given glyph id.
+ *
+ * Since: 2.6.8
+ **/
+HB_EXTERN unsigned
+hb_ot_layout_lookup_get_glyph_alternates (hb_face_t      *face,
+                                          unsigned        lookup_index,
+                                          hb_codepoint_t  glyph,
+                                          unsigned        start_offset,
+                                          unsigned       *alternate_count  /* IN/OUT.  May be NULL. */,
+                                          hb_codepoint_t *alternate_glyphs /* OUT.     May be NULL. */)
+{
+  hb_get_glyph_alternates_dispatch_t c (face);
+  const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index);
+  auto ret = lookup.dispatch (&c, glyph, start_offset, alternate_count, alternate_glyphs);
+  if (!ret && alternate_count) *alternate_count = 0;
+  return ret;
+}
 
 #endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h
index 0419f60..cdb1955 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h
@@ -93,6 +93,17 @@
 HB_EXTERN hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face);
 
+/**
+ * hb_ot_layout_glyph_class_t:
+ * @HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: Glyphs not matching the other classifications
+ * @HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: Spacing, single characters, capable of accepting marks
+ * @HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: Glyphs that represent ligation of multiple characters
+ * @HB_OT_LAYOUT_GLYPH_CLASS_MARK: Non-spacing, combining glyphs that represent marks
+ * @HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: Spacing glyphs that represent part of a single character
+ *
+ * The GDEF classes defined for glyphs.
+ *
+ **/
 typedef enum {
   HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0,
   HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH   = 1,
@@ -110,7 +121,6 @@
                                   hb_ot_layout_glyph_class_t  klass,
                                   hb_set_t                   *glyphs /* OUT */);
 
-
 /* Not that useful.  Provides list of attach points for a glyph that a
  * client may want to cache */
 HB_EXTERN unsigned int
@@ -150,7 +160,7 @@
 hb_ot_layout_table_find_script (hb_face_t    *face,
                                 hb_tag_t      table_tag,
                                 hb_tag_t      script_tag,
-                                unsigned int *script_index);
+                                unsigned int *script_index /* OUT */);
 
 HB_EXTERN hb_bool_t
 hb_ot_layout_table_select_script (hb_face_t      *face,
@@ -188,15 +198,15 @@
                                                   hb_tag_t      table_tag,
                                                   unsigned int  script_index,
                                                   unsigned int  language_index,
-                                                  unsigned int *feature_index);
+                                                  unsigned int *feature_index /* OUT */);
 
 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,
                                             unsigned int  language_index,
-                                            unsigned int *feature_index,
-                                            hb_tag_t     *feature_tag);
+                                            unsigned int *feature_index /* OUT */,
+                                            hb_tag_t     *feature_tag /* OUT */);
 
 HB_EXTERN unsigned int
 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
@@ -222,7 +232,7 @@
                                     unsigned int  script_index,
                                     unsigned int  language_index,
                                     hb_tag_t      feature_tag,
-                                    unsigned int *feature_index);
+                                    unsigned int *feature_index /* OUT */);
 
 HB_EXTERN unsigned int
 hb_ot_layout_feature_get_lookups (hb_face_t    *face,
@@ -313,6 +323,14 @@
 HB_EXTERN hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face);
 
+HB_EXTERN unsigned
+hb_ot_layout_lookup_get_glyph_alternates (hb_face_t      *face,
+                                          unsigned        lookup_index,
+                                          hb_codepoint_t  glyph,
+                                          unsigned        start_offset,
+                                          unsigned       *alternate_count /* IN/OUT */,
+                                          hb_codepoint_t *alternate_glyphs /* OUT */);
+
 HB_EXTERN hb_bool_t
 hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
                                       unsigned int          lookup_index,
@@ -391,6 +409,54 @@
                                      unsigned int   *char_count    /* IN/OUT.  May be NULL */,
                                      hb_codepoint_t *characters    /* OUT.     May be NULL */);
 
+/*
+ * BASE
+ */
+
+/**
+ * hb_ot_layout_baseline_tag_t:
+ * @HB_OT_LAYOUT_BASELINE_TAG_ROMAN: The baseline used by alphabetic scripts such as Latin, Cyrillic and Greek.
+ * In vertical writing mode, the alphabetic baseline for characters rotated 90 degrees clockwise.
+ * (This would not apply to alphabetic characters that remain upright in vertical writing mode, since these
+ * characters are not rotated.)
+ * @HB_OT_LAYOUT_BASELINE_TAG_HANGING: The hanging baseline. In horizontal direction, this is the horizontal
+ * line from which syllables seem, to hang in Tibetan and other similar scripts. In vertical writing mode,
+ * for Tibetan (or some other similar script) characters rotated 90 degrees clockwise.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT: Ideographic character face bottom or left edge,
+ * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: Ideographic character face top or right edge,
+ * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: Ideographic em-box bottom or left edge,
+ * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: Ideographic em-box top or right edge baseline,
+ * if the direction is horizontal or vertical, respectively.
+ * @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered.
+ * In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered.
+ *
+ * Baseline tags from https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
+ *
+ * Since: 2.6.0
+ */
+typedef enum {
+  HB_OT_LAYOUT_BASELINE_TAG_ROMAN                       = HB_TAG ('r','o','m','n'),
+  HB_OT_LAYOUT_BASELINE_TAG_HANGING                     = HB_TAG ('h','a','n','g'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT    = HB_TAG ('i','c','f','b'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT      = HB_TAG ('i','c','f','t'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT   = HB_TAG ('i','d','e','o'),
+  HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT     = HB_TAG ('i','d','t','p'),
+  HB_OT_LAYOUT_BASELINE_TAG_MATH                        = HB_TAG ('m','a','t','h'),
+
+  _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
+} hb_ot_layout_baseline_tag_t;
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_baseline (hb_font_t                   *font,
+                           hb_ot_layout_baseline_tag_t  baseline_tag,
+                           hb_direction_t               direction,
+                           hb_tag_t                     script_tag,
+                           hb_tag_t                     language_tag,
+                           hb_position_t               *coord        /* OUT.  May be NULL. */);
+
 HB_END_DECLS
 
 #endif /* HB_OT_LAYOUT_H */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh
index 9025bc5..07447f9 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh
@@ -96,13 +96,6 @@
  * GSUB/GPOS
  */
 
-HB_INTERNAL bool
-hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
-                                           unsigned int          lookup_index,
-                                           const hb_codepoint_t *glyphs,
-                                           unsigned int          glyphs_length,
-                                           bool                  zero_context);
-
 
 /* Should be called before all the substitute_lookup's are done. */
 HB_INTERNAL void
@@ -175,6 +168,17 @@
   return start;
 }
 
+static inline void
+_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                     hb_font_t *font HB_UNUSED,
+                     hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].syllable() = 0;
+}
+
 
 /* unicode_props */
 
@@ -215,7 +219,7 @@
   unsigned int gen_cat = (unsigned int) unicode->general_category (u);
   unsigned int props = gen_cat;
 
-  if (u >= 0x80)
+  if (u >= 0x80u)
   {
     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
 
@@ -232,10 +236,10 @@
        * FVSes are GC=Mn, we have use a separate bit to remember them.
        * Fixes:
        * https://github.com/harfbuzz/harfbuzz/issues/234 */
-      else if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
+      else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
       /* TAG characters need similar treatment. Fixes:
        * https://github.com/harfbuzz/harfbuzz/issues/463 */
-      else if (unlikely (hb_in_range (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
+      else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
       /* COMBINING GRAPHEME JOINER should not be skipped; at least some times.
        * https://github.com/harfbuzz/harfbuzz/issues/554 */
       else if (unlikely (u == 0x034Fu))
@@ -558,6 +562,17 @@
   info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
 }
 
+static inline void
+_hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                              hb_font_t *font HB_UNUSED,
+                              hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    _hb_glyph_info_clear_substituted (&info[i]);
+}
+
 
 /* Allocation / deallocation. */
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc
index a428b4b..d256a04 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc
@@ -26,6 +26,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-map.hh"
 #include "hb-ot-shape.hh"
 #include "hb-ot-layout.hh"
@@ -34,7 +38,7 @@
 void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
 {
   for (unsigned int i = 0; i < lookups[table_index].length; i++)
-    hb_set_add (lookups_out, lookups[table_index][i].index);
+    lookups_out->add (lookups[table_index][i].index);
 }
 
 
@@ -187,13 +191,14 @@
           feature_infos[j].max_value = feature_infos[i].max_value;
           feature_infos[j].default_value = feature_infos[i].default_value;
         } else {
-          feature_infos[j].flags &= ~F_GLOBAL;
-          feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
+          if (feature_infos[j].flags & F_GLOBAL)
+            feature_infos[j].flags ^= F_GLOBAL;
+          feature_infos[j].max_value = hb_max (feature_infos[j].max_value, feature_infos[i].max_value);
           /* Inherit default_value from j */
         }
         feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
-        feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]);
-        feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]);
+        feature_infos[j].stage[0] = hb_min (feature_infos[j].stage[0], feature_infos[i].stage[0]);
+        feature_infos[j].stage[1] = hb_min (feature_infos[j].stage[1], feature_infos[i].stage[1]);
       }
     feature_infos.shrink (j + 1);
   }
@@ -213,34 +218,34 @@
       bits_needed = 0;
     else
       /* Limit bits per feature. */
-      bits_needed = MIN(HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
+      bits_needed = hb_min (HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
 
     if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
       continue; /* Feature disabled, or not enough bits. */
 
 
-    hb_bool_t found = false;
+    bool found = false;
     unsigned int feature_index[2];
     for (unsigned int table_index = 0; table_index < 2; table_index++)
     {
       if (required_feature_tag[table_index] == info->tag)
         required_feature_stage[table_index] = info->stage[table_index];
 
-      found |= hb_ot_layout_language_find_feature (face,
-                                                   table_tags[table_index],
-                                                   script_index[table_index],
-                                                   language_index[table_index],
-                                                   info->tag,
-                                                   &feature_index[table_index]);
+      found |= (bool) hb_ot_layout_language_find_feature (face,
+                                                          table_tags[table_index],
+                                                          script_index[table_index],
+                                                          language_index[table_index],
+                                                          info->tag,
+                                                          &feature_index[table_index]);
     }
     if (!found && (info->flags & F_GLOBAL_SEARCH))
     {
       for (unsigned int table_index = 0; table_index < 2; table_index++)
       {
-        found |= hb_ot_layout_table_find_feature (face,
-                                                  table_tags[table_index],
-                                                  info->tag,
-                                                  &feature_index[table_index]);
+        found |= (bool) hb_ot_layout_table_find_feature (face,
+                                                         table_tags[table_index],
+                                                         info->tag,
+                                                         &feature_index[table_index]);
       }
     }
     if (!found && !(info->flags & F_HAS_FALLBACK))
@@ -332,3 +337,6 @@
     }
   }
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh
index 7505adf..5c23eb5 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh
@@ -68,7 +68,7 @@
     unsigned short random : 1;
     hb_mask_t mask;
 
-    static int cmp (const void *pa, const void *pb)
+    HB_INTERNAL static int cmp (const void *pa, const void *pb)
     {
       const lookup_map_t *a = (const lookup_map_t *) pa;
       const lookup_map_t *b = (const lookup_map_t *) pb;
@@ -134,13 +134,13 @@
   unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const
   {
     const feature_map_t *map = features.bsearch (feature_tag);
-    return map ? map->stage[table_index] : (unsigned int) -1;
+    return map ? map->stage[table_index] : UINT_MAX;
   }
 
   void get_stage_lookups (unsigned int table_index, unsigned int stage,
                           const struct lookup_map_t **plookups, unsigned int *lookup_count) const
   {
-    if (unlikely (stage == (unsigned int) -1)) {
+    if (unlikely (stage == UINT_MAX)) {
       *plookups = nullptr;
       *lookup_count = 0;
       return;
@@ -154,8 +154,8 @@
 
   HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
   template <typename Proxy>
-  HB_INTERNAL inline void apply (const Proxy &proxy,
-                                 const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+  HB_INTERNAL void apply (const Proxy &proxy,
+                          const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
   HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
   HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
 
@@ -167,7 +167,7 @@
 
   hb_mask_t global_mask;
 
-  hb_vector_t<feature_map_t> features;
+  hb_sorted_vector_t<feature_map_t> features;
   hb_vector_t<lookup_map_t> lookups[2]; /* GSUB/GPOS */
   hb_vector_t<stage_map_t> stages[2]; /* GSUB/GPOS */
 };
@@ -213,8 +213,8 @@
   { add_feature (feat.tag, feat.flags); }
 
   void enable_feature (hb_tag_t tag,
-                              hb_ot_map_feature_flags_t flags=F_NONE,
-                              unsigned int value=1)
+                       hb_ot_map_feature_flags_t flags=F_NONE,
+                       unsigned int value=1)
   { add_feature (tag, F_GLOBAL | flags, value); }
 
   void disable_feature (hb_tag_t tag)
@@ -247,7 +247,7 @@
     unsigned int default_value; /* for non-global features, what should the unset glyphs take */
     unsigned int stage[2]; /* GSUB/GPOS */
 
-    static int cmp (const void *pa, const void *pb)
+    HB_INTERNAL static int cmp (const void *pa, const void *pb)
     {
       const feature_info_t *a = (const feature_info_t *) pa;
       const feature_info_t *b = (const feature_info_t *) pb;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh
index 07112e0..6cacf8e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh
@@ -48,7 +48,7 @@
   }
 
   protected:
-  HBINT16                       value;          /* The X or Y value in design units */
+  HBINT16               value;          /* The X or Y value in design units */
   OffsetTo<Device>      deviceTable;    /* Offset to the device table - from the
                                          * beginning of parent table.  May be NULL.
                                          * Suggested format for device table is 1. */
@@ -78,7 +78,7 @@
   }
 
   hb_position_t get_value (hb_ot_math_constant_t constant,
-                                  hb_font_t *font) const
+                           hb_font_t *font) const
   {
     switch (constant) {
 
@@ -279,14 +279,15 @@
   protected:
   HBUINT16      heightCount;
   UnsizedArrayOf<MathValueRecord>
-                mathValueRecordsZ;      /* Array of correction heights at
-                                         * which the kern value changes.
-                                         * Sorted by the height value in
-                                         * design units (heightCount entries),
-                                         * Followed by:
-                                         * Array of kern values corresponding
-                                         * to heights. (heightCount+1 entries).
-                                         */
+                mathValueRecordsZ;
+                                /* Array of correction heights at
+                                 * which the kern value changes.
+                                 * Sorted by the height value in
+                                 * design units (heightCount entries),
+                                 * Followed by:
+                                 * Array of kern values corresponding
+                                 * to heights. (heightCount+1 entries).
+                                 */
 
   public:
   DEFINE_SIZE_ARRAY (2, mathValueRecordsZ);
@@ -345,15 +346,18 @@
   }
 
   protected:
-  OffsetTo<Coverage>            mathKernCoverage;    /* Offset to Coverage table -
-                                                      * from the beginning of the
-                                                      * MathKernInfo table. */
-  ArrayOf<MathKernInfoRecord>   mathKernInfoRecords; /* Array of
-                                                      * MathKernInfoRecords,
-                                                      * per-glyph information for
-                                                      * mathematical positioning
-                                                      * of subscripts and
-                                                      * superscripts. */
+  OffsetTo<Coverage>
+                mathKernCoverage;
+                                /* Offset to Coverage table -
+                                 * from the beginning of the
+                                 * MathKernInfo table. */
+  ArrayOf<MathKernInfoRecord>
+                mathKernInfoRecords;
+                                /* Array of MathKernInfoRecords,
+                                 * per-glyph information for
+                                 * mathematical positioning
+                                 * of subscripts and
+                                 * superscripts. */
 
   public:
   DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
@@ -423,7 +427,7 @@
   }
 
   protected:
-  GlyphID variantGlyph;       /* Glyph ID for the variant. */
+  HBGlyphID variantGlyph;       /* Glyph ID for the variant. */
   HBUINT16  advanceMeasurement; /* Advance width/height, in design units, of the
                                  * variant, in the direction of requested
                                  * glyph extension. */
@@ -453,16 +457,16 @@
   }
 
   void extract (hb_ot_math_glyph_part_t &out,
-                int scale,
+                int64_t mult,
                 hb_font_t *font) const
   {
     out.glyph                   = glyph;
 
-    out.start_connector_length  = font->em_scale (startConnectorLength, scale);
-    out.end_connector_length    = font->em_scale (endConnectorLength, scale);
-    out.full_advance            = font->em_scale (fullAdvance, scale);
+    out.start_connector_length  = font->em_mult (startConnectorLength, mult);
+    out.end_connector_length    = font->em_mult (endConnectorLength, mult);
+    out.full_advance            = font->em_mult (fullAdvance, mult);
 
-    static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
+    static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
                    (unsigned int) PartFlags::Extender, "");
 
     out.flags = (hb_ot_math_glyph_part_flags_t)
@@ -471,19 +475,21 @@
   }
 
   protected:
-  GlyphID   glyph;                /* Glyph ID for the part. */
-  HBUINT16    startConnectorLength; /* Advance width/ height of the straight bar
-                                   * connector material, in design units, is at
-                                   * the beginning of the glyph, in the
-                                   * direction of the extension. */
-  HBUINT16    endConnectorLength;   /* Advance width/ height of the straight bar
-                                   * connector material, in design units, is at
-                                   * the end of the glyph, in the direction of
-                                   * the extension. */
-  HBUINT16    fullAdvance;        /* Full advance width/height for this part,
-                                   * in the direction of the extension.
-                                   * In design units. */
-  PartFlags partFlags;            /* Part qualifiers. */
+  HBGlyphID     glyph;          /* Glyph ID for the part. */
+  HBUINT16      startConnectorLength;
+                                /* Advance width/ height of the straight bar
+                                 * connector material, in design units, is at
+                                 * the beginning of the glyph, in the
+                                 * direction of the extension. */
+  HBUINT16      endConnectorLength;
+                                /* Advance width/ height of the straight bar
+                                 * connector material, in design units, is at
+                                 * the end of the glyph, in the direction of
+                                 * the extension. */
+  HBUINT16      fullAdvance;    /* Full advance width/height for this part,
+                                 * in the direction of the extension.
+                                 * In design units. */
+  PartFlags     partFlags;      /* Part qualifiers. */
 
   public:
   DEFINE_SIZE_STATIC (10);
@@ -508,11 +514,10 @@
   {
     if (parts_count)
     {
-      int scale = font->dir_scale (direction);
-      hb_array_t<const MathGlyphPartRecord> arr = partRecords.sub_array (start_offset, parts_count);
-      unsigned int count = arr.length;
-      for (unsigned int i = 0; i < count; i++)
-        arr[i].extract (parts[i], scale, font);
+      int64_t mult = font->dir_mult (direction);
+      for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count),
+                            hb_array (parts, *parts_count)))
+        _.first.extract (_.second, mult, font);
     }
 
     if (italics_correction)
@@ -522,12 +527,15 @@
   }
 
   protected:
-  MathValueRecord          italicsCorrection; /* Italics correction of this
-                                               * MathGlyphAssembly. Should not
-                                               * depend on the assembly size. */
-  ArrayOf<MathGlyphPartRecord> partRecords;   /* Array of part records, from
-                                               * left to right and bottom to
-                                               * top. */
+  MathValueRecord
+                italicsCorrection;
+                                /* Italics correction of this
+                                 * MathGlyphAssembly. Should not
+                                 * depend on the assembly size. */
+  ArrayOf<MathGlyphPartRecord>
+                partRecords;    /* Array of part records, from
+                                 * left to right and bottom to
+                                 * top. */
 
   public:
   DEFINE_SIZE_ARRAY (6, partRecords);
@@ -553,14 +561,10 @@
   {
     if (variants_count)
     {
-      int scale = font->dir_scale (direction);
-      hb_array_t<const MathGlyphVariantRecord> arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count);
-      unsigned int count = arr.length;
-      for (unsigned int i = 0; i < count; i++)
-      {
-        variants[i].glyph = arr[i].variantGlyph;
-        variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale);
-      }
+      int64_t mult = font->dir_mult (direction);
+      for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count),
+                            hb_array (variants, *variants_count)))
+        _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
     }
     return mathGlyphVariantRecord.len;
   }
@@ -612,12 +616,12 @@
            .get_variants (direction, font, start_offset, variants_count, variants); }
 
   unsigned int get_glyph_parts (hb_codepoint_t glyph,
-                                       hb_direction_t direction,
-                                       hb_font_t *font,
-                                       unsigned int start_offset,
-                                       unsigned int *parts_count, /* IN/OUT */
-                                       hb_ot_math_glyph_part_t *parts /* OUT */,
-                                       hb_position_t *italics_correction /* OUT */) const
+                                hb_direction_t direction,
+                                hb_font_t *font,
+                                unsigned int start_offset,
+                                unsigned int *parts_count, /* IN/OUT */
+                                hb_ot_math_glyph_part_t *parts /* OUT */,
+                                hb_position_t *italics_correction /* OUT */) const
   { return get_glyph_construction (glyph, direction, font)
            .get_assembly ()
            .get_parts (direction, font,
@@ -645,26 +649,29 @@
   }
 
   protected:
-  HBUINT16           minConnectorOverlap; /* Minimum overlap of connecting
-                                           * glyphs during glyph construction,
-                                           * in design units. */
-  OffsetTo<Coverage> vertGlyphCoverage;   /* Offset to Coverage table -
-                                           * from the beginning of MathVariants
-                                           * table. */
-  OffsetTo<Coverage> horizGlyphCoverage;  /* Offset to Coverage table -
-                                           * from the beginning of MathVariants
-                                           * table. */
-  HBUINT16           vertGlyphCount;      /* Number of glyphs for which
-                                           * information is provided for
-                                           * vertically growing variants. */
-  HBUINT16           horizGlyphCount;     /* Number of glyphs for which
-                                           * information is provided for
-                                           * horizontally growing variants. */
+  HBUINT16      minConnectorOverlap;
+                                /* Minimum overlap of connecting
+                                 * glyphs during glyph construction,
+                                 * in design units. */
+  OffsetTo<Coverage> vertGlyphCoverage;
+                                /* Offset to Coverage table -
+                                 * from the beginning of MathVariants
+                                 * table. */
+  OffsetTo<Coverage> horizGlyphCoverage;
+                                /* Offset to Coverage table -
+                                 * from the beginning of MathVariants
+                                 * table. */
+  HBUINT16      vertGlyphCount; /* Number of glyphs for which
+                                 * information is provided for
+                                 * vertically growing variants. */
+  HBUINT16      horizGlyphCount;/* Number of glyphs for which
+                                 * information is provided for
+                                 * horizontally growing variants. */
 
   /* Array of offsets to MathGlyphConstruction tables - from the beginning of
      the MathVariants table, for shapes growing in vertical/horizontal
      direction. */
-  UnsizedArrayOf<OffsetTo<MathGlyphConstruction> >
+  UnsizedArrayOf<OffsetTo<MathGlyphConstruction>>
                         glyphConstruction;
 
   public:
@@ -694,7 +701,7 @@
   }
 
   hb_position_t get_constant (hb_ot_math_constant_t  constant,
-                                     hb_font_t             *font) const
+                              hb_font_t            *font) const
   { return (this+mathConstants).get_value (constant, font); }
 
   const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
@@ -702,11 +709,14 @@
   const MathVariants &get_variants () const    { return this+mathVariants; }
 
   protected:
-  FixedVersion<>version;                /* Version of the MATH table
-                                         * initially set to 0x00010000u */
-  OffsetTo<MathConstants> mathConstants;/* MathConstants table */
-  OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */
-  OffsetTo<MathVariants>  mathVariants; /* MathVariants table */
+  FixedVersion<>version;        /* Version of the MATH table
+                                 * initially set to 0x00010000u */
+  OffsetTo<MathConstants>
+                mathConstants;  /* MathConstants table */
+  OffsetTo<MathGlyphInfo>
+                mathGlyphInfo;  /* MathGlyphInfo table */
+  OffsetTo<MathVariants>
+                mathVariants;   /* MathVariants table */
 
   public:
   DEFINE_SIZE_STATIC (10);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc
index e10cf38..94a5720 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc
@@ -24,9 +24,10 @@
  * Igalia Author(s): Frédéric Wang
  */
 
-#include "hb-open-type.hh"
+#include "hb.hh"
 
-#include "hb-ot-face.hh"
+#ifndef HB_NO_MATH
+
 #include "hb-ot-math-table.hh"
 
 
@@ -37,6 +38,11 @@
  * @include: hb-ot.h
  *
  * Functions for fetching mathematics layout data from OpenType fonts.
+ *
+ * HarfBuzz itself does not implement a math layout solution. The
+ * functions and types provided can be used by client programs to access
+ * the font data necessary for typesetting OpenType Math layout.
+ *
  **/
 
 
@@ -48,10 +54,9 @@
  * hb_ot_math_has_data:
  * @face: #hb_face_t to test
  *
- * This function allows to verify the presence of an OpenType MATH table on the
- * face.
+ * Tests whether a face has a `MATH` table.
  *
- * Return value: true if face has a MATH table, false otherwise
+ * Return value: true if the table is found, false otherwise
  *
  * Since: 1.3.3
  **/
@@ -63,16 +68,18 @@
 
 /**
  * hb_ot_math_get_constant:
- * @font: #hb_font_t from which to retrieve the value
+ * @font: #hb_font_t to work upon
  * @constant: #hb_ot_math_constant_t the constant to retrieve
  *
- * This function returns the requested math constants as a #hb_position_t.
- * If the request constant is HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
- * HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
- * HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN then the return value is
- * actually an integer between 0 and 100 representing that percentage.
+ * Fetches the specified math constant. For most constants, the value returned
+ * is an #hb_position_t.
  *
- * Return value: the requested constant or 0
+ * However, if the requested constant is #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
+ * #HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
+ * #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN, then the return value is
+ * an integer between 0 and 100 representing that percentage.
+ *
+ * Return value: the requested constant or zero
  *
  * Since: 1.3.3
  **/
@@ -85,10 +92,13 @@
 
 /**
  * hb_ot_math_get_glyph_italics_correction:
- * @font: #hb_font_t from which to retrieve the value
- * @glyph: glyph index from which to retrieve the value
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph index from which to retrieve the value
  *
- * Return value: the italics correction of the glyph or 0
+ * Fetches an italics-correction value (if one exists) for the specified
+ * glyph index.
+ *
+  * Return value: the italics correction of the glyph or zero
  *
  * Since: 1.3.3
  **/
@@ -101,10 +111,20 @@
 
 /**
  * hb_ot_math_get_glyph_top_accent_attachment:
- * @font: #hb_font_t from which to retrieve the value
- * @glyph: glyph index from which to retrieve the value
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph index from which to retrieve the value
  *
- * Return value: the top accent attachment of the glyph or 0
+ * Fetches a top-accent-attachment value (if one exists) for the specified
+ * glyph index.
+ *
+ * For any glyph that does not have a top-accent-attachment value - that is,
+ * a glyph not covered by the `MathTopAccentAttachment` table (or, when
+ * @font has no `MathTopAccentAttachment` table or no `MATH` table, any
+ * glyph) - the function synthesizes a value, returning the position at
+ * one-half the glyph's advance width.
+ *
+ * Return value: the top accent attachment of the glyph or 0.5 * the advance
+ *               width of @glyph
  *
  * Since: 1.3.3
  **/
@@ -117,8 +137,10 @@
 
 /**
  * hb_ot_math_is_glyph_extended_shape:
- * @face: a #hb_face_t to test
- * @glyph: a glyph index to test
+ * @face: #hb_face_t to work upon
+ * @glyph: The glyph index to test
+ *
+ * Tests whether the given glyph index is an extended shape in the face.
  *
  * Return value: true if the glyph is an extended shape, false otherwise
  *
@@ -133,18 +155,20 @@
 
 /**
  * hb_ot_math_get_glyph_kerning:
- * @font: #hb_font_t from which to retrieve the value
- * @glyph: glyph index from which to retrieve the value
- * @kern: the #hb_ot_math_kern_t from which to retrieve the value
+ * @font: #hb_font_t to work upon
+ * @glyph: The glyph index from which to retrieve the value
+ * @kern: The #hb_ot_math_kern_t from which to retrieve the value
  * @correction_height: the correction height to use to determine the kerning.
  *
- * This function tries to retrieve the MathKern table for the specified font,
- * glyph and #hb_ot_math_kern_t. Then it browses the list of heights from the
- * MathKern table to find one value that is greater or equal to specified
- * correction_height. If one is found the corresponding value from the list of
- * kerns is returned and otherwise the last kern value is returned.
+ * Fetches the math kerning (cut-ins) value for the specified font, glyph index, and
+ * @kern.
  *
- * Return value: requested kerning or 0
+ * If the MathKern table is found, the function examines it to find a height
+ * value that is greater or equal to @correction_height. If such a height
+ * value is found, corresponding kerning value from the table is returned. If
+ * no such height value is found, the last kerning value is returned.
+ *
+ * Return value: requested kerning value or zero
  *
  * Since: 1.3.3
  **/
@@ -162,20 +186,24 @@
 
 /**
  * hb_ot_math_get_glyph_variants:
- * @font: #hb_font_t from which to retrieve the values
- * @glyph: index of the glyph to stretch
- * @direction: direction of the stretching
+ * @font: #hb_font_t to work upon
+ * @glyph: The index of the glyph to stretch
+ * @direction: The direction of the stretching (horizontal or vertical)
  * @start_offset: offset of the first variant to retrieve
- * @variants_count: maximum number of variants to retrieve after start_offset
- * (IN) and actual number of variants retrieved (OUT)
- * @variants: array of size at least @variants_count to store the result
+ * @variants_count: (inout): Input = the maximum number of variants to return;
+ *                           Output = the actual number of variants returned
+ * @variants: (out) (array length=variants_count): array of variants returned
  *
- * This function tries to retrieve the MathGlyphConstruction for the specified
- * font, glyph and direction. Note that only the value of
- * #HB_DIRECTION_IS_HORIZONTAL is considered. It provides the corresponding list
- * of size variants as an array of hb_ot_math_glyph_variant_t structs.
+ * Fetches the MathGlyphConstruction for the specified font, glyph index, and
+ * direction. The corresponding list of size variants is returned as a list of
+ * #hb_ot_math_glyph_variant_t structs.
  *
- * Return value: the total number of size variants available or 0
+ * <note>The @direction parameter is only used to select between horizontal
+ * or vertical directions for the construction. Even though all #hb_direction_t
+ * values are accepted, only the result of #HB_DIRECTION_IS_HORIZONTAL is
+ * considered.</note>
+ *
+ * Return value: the total number of size variants available or zero
  *
  * Since: 1.3.3
  **/
@@ -195,15 +223,19 @@
 
 /**
  * hb_ot_math_get_min_connector_overlap:
- * @font: #hb_font_t from which to retrieve the value
- * @direction: direction of the stretching
+ * @font: #hb_font_t to work upon
+ * @direction: direction of the stretching (horizontal or vertical)
  *
- * This function tries to retrieve the MathVariants table for the specified
- * font and returns the minimum overlap of connecting glyphs to draw a glyph
- * assembly in the specified direction. Note that only the value of
- * #HB_DIRECTION_IS_HORIZONTAL is considered.
+ * Fetches the MathVariants table for the specified font and returns the
+ * minimum overlap of connecting glyphs that are required to draw a glyph
+ * assembly in the specified direction.
  *
- * Return value: requested min connector overlap or 0
+ * <note>The @direction parameter is only used to select between horizontal
+ * or vertical directions for the construction. Even though all #hb_direction_t
+ * values are accepted, only the result of #HB_DIRECTION_IS_HORIZONTAL is
+ * considered.</note>
+ *
+ * Return value: requested minimum connector overlap or zero
  *
  * Since: 1.3.3
  **/
@@ -216,19 +248,24 @@
 
 /**
  * hb_ot_math_get_glyph_assembly:
- * @font: #hb_font_t from which to retrieve the values
- * @glyph: index of the glyph to stretch
- * @direction: direction of the stretching
+ * @font: #hb_font_t to work upon
+ * @glyph: The index of the glyph to stretch
+ * @direction: direction of the stretching (horizontal or vertical)
  * @start_offset: offset of the first glyph part to retrieve
- * @parts_count: maximum number of glyph parts to retrieve after start_offset
- * (IN) and actual number of parts retrieved (OUT)
- * @parts: array of size at least @parts_count to store the result
- * @italics_correction: italic correction of the glyph assembly
+ * @parts_count: (inout): Input = maximum number of glyph parts to return;
+ *               Output = actual number of parts returned
+ * @parts: (out) (array length=parts_count): the glyph parts returned
+ * @italics_correction: (out): italics correction of the glyph assembly
  *
- * This function tries to retrieve the GlyphAssembly for the specified font,
- * glyph and direction. Note that only the value of #HB_DIRECTION_IS_HORIZONTAL
- * is considered. It provides the information necessary to draw the glyph
- * assembly as an array of #hb_ot_math_glyph_part_t.
+ * Fetches the GlyphAssembly for the specified font, glyph index, and direction.
+ * Returned are a list of #hb_ot_math_glyph_part_t glyph parts that can be
+ * used to draw the glyph and an italics-correction value (if one is defined
+ * in the font).
+ *
+ * <note>The @direction parameter is only used to select between horizontal
+ * or vertical directions for the construction. Even though all #hb_direction_t
+ * values are accepted, only the result of #HB_DIRECTION_IS_HORIZONTAL is
+ * considered.</note>
  *
  * Return value: the total number of parts in the glyph assembly
  *
@@ -251,3 +288,6 @@
                                                                  parts,
                                                                  italics_correction);
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.h
index 3cbdb8b..0d92ffb 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.h
@@ -50,6 +50,9 @@
 /**
  * hb_ot_math_constant_t:
  *
+ * The 'MATH' table constants specified at
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/math
+ *
  * Since: 1.3.3
  */
 typedef enum {
@@ -114,6 +117,9 @@
 /**
  * hb_ot_math_kern_t:
  *
+ * The math kerning-table types defined for the four corners
+ * of a glyph.
+ *
  * Since: 1.3.3
  */
 typedef enum {
@@ -125,6 +131,10 @@
 
 /**
  * hb_ot_math_glyph_variant_t:
+ * @glyph: The glyph index of the variant
+ * @advance: The advance width of the variant
+ *
+ * Data type to hold math-variant information for a glyph.
  *
  * Since: 1.3.3
  */
@@ -136,14 +146,25 @@
 /**
  * hb_ot_math_glyph_part_flags_t:
  *
+ * Flags for math glyph parts.
+ *
  * Since: 1.3.3
  */
 typedef enum { /*< flags >*/
-  HB_MATH_GLYPH_PART_FLAG_EXTENDER      = 0x00000001u  /* Extender glyph */
+  HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER   = 0x00000001u  /* Extender glyph */
 } hb_ot_math_glyph_part_flags_t;
 
 /**
  * hb_ot_math_glyph_part_t:
+ * @glyph: The glyph index of the variant part
+ * @start_connector_length: The length of the connector on the starting side of the variant part
+ * @end_connector_length: The length of the connector on the ending side of the variant part
+ * @full_advance: The total advance of the part
+ * @flags: #hb_ot_math_glyph_part_flags_t flags for the part
+ *
+ * Data type to hold information for a "part" component of a math-variant glyph.
+ * Large variants for stretchable math glyphs (such as parentheses) can be constructed
+ * on the fly from parts.
  *
  * Since: 1.3.3
  */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh
index 2940617..0afa53a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh
@@ -77,7 +77,7 @@
 
   void set_num_glyphs (unsigned int count)
   {
-    numGlyphs.set (count);
+    numGlyphs = count;
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -94,46 +94,43 @@
     return_trace (likely (version.major == 0 && version.minor == 0x5000u));
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  bool subset (hb_subset_context_t *c) const
   {
-    hb_blob_t *maxp_blob = hb_sanitize_context_t().reference_table<maxp> (plan->source);
-    hb_blob_t *maxp_prime_blob = hb_blob_copy_writable_or_fail (maxp_blob);
-    hb_blob_destroy (maxp_blob);
+    TRACE_SUBSET (this);
+    maxp *maxp_prime = c->serializer->embed (this);
+    if (unlikely (!maxp_prime)) return_trace (false);
 
-    if (unlikely (!maxp_prime_blob)) {
-      return false;
-    }
-    maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr);
-
-    maxp_prime->set_num_glyphs (plan->glyphs.length);
-    if (plan->drop_hints)
-      drop_hint_fields (plan, maxp_prime);
-
-    bool result = plan->add_table (HB_OT_TAG_maxp, maxp_prime_blob);
-    hb_blob_destroy (maxp_prime_blob);
-    return result;
-  }
-
-  static void drop_hint_fields (hb_subset_plan_t *plan HB_UNUSED, maxp *maxp_prime)
-  {
+    maxp_prime->numGlyphs = c->plan->num_output_glyphs ();
     if (maxp_prime->version.major == 1)
     {
-      maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*maxp_prime);
-      v1.maxZones.set (1);
-      v1.maxTwilightPoints.set (0);
-      v1.maxStorage.set (0);
-      v1.maxFunctionDefs.set (0);
-      v1.maxInstructionDefs.set (0);
-      v1.maxStackElements.set (0);
-      v1.maxSizeOfInstructions.set (0);
+      const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);
+      maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
+      if (unlikely (!dest_v1)) return_trace (false);
+
+      if (c->plan->drop_hints)
+        drop_hint_fields (dest_v1);
     }
+
+    return_trace (true);
+  }
+
+  static void drop_hint_fields (maxpV1Tail* dest_v1)
+  {
+    dest_v1->maxZones = 1;
+    dest_v1->maxTwilightPoints = 0;
+    dest_v1->maxStorage = 0;
+    dest_v1->maxFunctionDefs = 0;
+    dest_v1->maxInstructionDefs = 0;
+    dest_v1->maxStackElements = 0;
+    dest_v1->maxSizeOfInstructions = 0;
   }
 
   protected:
-  FixedVersion<>version;                /* Version of the maxp table (0.5 or 1.0),
-                                         * 0x00005000u or 0x00010000u. */
-  HBUINT16      numGlyphs;              /* The number of glyphs in the font. */
-/*maxpV1Tail    v1Tail[VAR]; */
+  FixedVersion<>version;/* Version of the maxp table (0.5 or 1.0),
+                         * 0x00005000u or 0x00010000u. */
+  HBUINT16      numGlyphs;
+                        /* The number of glyphs in the font. */
+/*maxpV1Tail    v1Tail[HB_VAR_ARRAY]; */
   public:
   DEFINE_SIZE_STATIC (6);
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh
new file mode 100644
index 0000000..2b45f42
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh
@@ -0,0 +1,127 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_OT_META_TABLE_HH
+#define HB_OT_META_TABLE_HH
+
+#include "hb-open-type.hh"
+
+/*
+ * meta -- Metadata Table
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/meta
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6meta.html
+ */
+#define HB_OT_TAG_meta HB_TAG ('m','e','t','a')
+
+
+namespace OT {
+
+
+struct DataMap
+{
+  int cmp (hb_tag_t a) const { return tag.cmp (a); }
+
+  hb_tag_t get_tag () const { return tag; }
+
+  hb_blob_t *reference_entry (hb_blob_t *meta_blob) const
+  { return hb_blob_create_sub_blob (meta_blob, dataZ, dataLength); }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+                          dataZ.sanitize (c, base, dataLength)));
+  }
+
+  protected:
+  Tag           tag;            /* A tag indicating the type of metadata. */
+  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
+                dataZ;          /* Offset in bytes from the beginning of the
+                                 * metadata table to the data for this tag. */
+  HBUINT32      dataLength;     /* Length of the data. The data is not required to
+                                 * be padded to any byte boundary. */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct meta
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_meta;
+
+  struct accelerator_t
+  {
+    void init (hb_face_t *face)
+    { table = hb_sanitize_context_t ().reference_table<meta> (face); }
+    void fini () { table.destroy (); }
+
+    hb_blob_t *reference_entry (hb_tag_t tag) const
+    { return table->dataMaps.lsearch (tag).reference_entry (table.get_blob ()); }
+
+    unsigned int get_entries (unsigned int      start_offset,
+                              unsigned int     *count,
+                              hb_ot_meta_tag_t *entries) const
+    {
+      if (count)
+      {
+        + table->dataMaps.sub_array (start_offset, count)
+        | hb_map (&DataMap::get_tag)
+        | hb_map ([](hb_tag_t tag) { return (hb_ot_meta_tag_t) tag; })
+        | hb_sink (hb_array (entries, *count))
+        ;
+      }
+      return table->dataMaps.len;
+    }
+
+    private:
+    hb_blob_ptr_t<meta> table;
+  };
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+                          version == 1 &&
+                          dataMaps.sanitize (c, this)));
+  }
+
+  protected:
+  HBUINT32      version;        /* Version number of the metadata table — set to 1. */
+  HBUINT32      flags;          /* Flags — currently unused; set to 0. */
+  HBUINT32      dataOffset;
+                                /* Per Apple specification:
+                                 * Offset from the beginning of the table to the data.
+                                 * Per OT specification:
+                                 * Reserved. Not used; should be set to 0. */
+  LArrayOf<DataMap>
+                dataMaps;/* Array of data map records. */
+  public:
+  DEFINE_SIZE_ARRAY (16, dataMaps);
+};
+
+struct meta_accelerator_t : meta::accelerator_t {};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_META_TABLE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc
new file mode 100644
index 0000000..f2d7d33
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_META
+
+#include "hb-ot-meta-table.hh"
+
+/**
+ * SECTION:hb-ot-meta
+ * @title: hb-ot-meta
+ * @short_description: OpenType Metadata
+ * @include: hb-ot.h
+ *
+ * Functions for fetching metadata from fonts.
+ **/
+
+/**
+ * hb_ot_meta_get_entry_tags:
+ * @face: a face object
+ * @start_offset: iteration's start offset
+ * @entries_count:(inout) (allow-none): buffer size as input, filled size as output
+ * @entries: (out caller-allocates) (array length=entries_count): entries tags buffer
+ *
+ * Return value: Number of all available feature types.
+ *
+ * Since: 2.6.0
+ **/
+unsigned int
+hb_ot_meta_get_entry_tags (hb_face_t        *face,
+                           unsigned int      start_offset,
+                           unsigned int     *entries_count, /* IN/OUT.  May be NULL. */
+                           hb_ot_meta_tag_t *entries        /* OUT.     May be NULL. */)
+{
+  return face->table.meta->get_entries (start_offset, entries_count, entries);
+}
+
+/**
+ * hb_ot_meta_reference_entry:
+ * @face: a #hb_face_t object.
+ * @meta_tag: tag of metadata you like to have.
+ *
+ * It fetches metadata entry of a given tag from a font.
+ *
+ * Returns: (transfer full): A blob containing the blob.
+ *
+ * Since: 2.6.0
+ **/
+hb_blob_t *
+hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_tag_t meta_tag)
+{
+  return face->table.meta->reference_entry (meta_tag);
+}
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.h
new file mode 100644
index 0000000..71e1b78
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_META_H
+#define HB_OT_META_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+/**
+ * hb_ot_meta_tag_t:
+ * @HB_OT_META_TAG_DESIGN_LANGUAGES: Design languages. Text, using only
+ * Basic Latin (ASCII) characters. Indicates languages and/or scripts
+ * for the user audiences that the font was primarily designed for.
+ * @HB_OT_META_TAG_SUPPORTED_LANGUAGES: Supported languages. Text, using
+ * only Basic Latin (ASCII) characters. Indicates languages and/or scripts
+ * that the font is declared to be capable of supporting.
+ *
+ * Known metadata tags from https://docs.microsoft.com/en-us/typography/opentype/spec/meta
+ *
+ * Since: 2.6.0
+ **/
+typedef enum {
+/*
+   HB_OT_META_TAG_APPL          = HB_TAG ('a','p','p','l'),
+   HB_OT_META_TAG_BILD          = HB_TAG ('b','i','l','d'),
+*/
+  HB_OT_META_TAG_DESIGN_LANGUAGES       = HB_TAG ('d','l','n','g'),
+  HB_OT_META_TAG_SUPPORTED_LANGUAGES    = HB_TAG ('s','l','n','g'),
+
+  _HB_OT_META_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
+} hb_ot_meta_tag_t;
+
+HB_EXTERN unsigned int
+hb_ot_meta_get_entry_tags (hb_face_t        *face,
+                           unsigned int      start_offset,
+                           unsigned int     *entries_count, /* IN/OUT.  May be NULL. */
+                           hb_ot_meta_tag_t *entries        /* OUT.     May be NULL. */);
+
+HB_EXTERN hb_blob_t *
+hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_tag_t meta_tag);
+
+HB_END_DECLS
+
+#endif /* HB_OT_META_H */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc
new file mode 100644
index 0000000..9c0920a
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc
@@ -0,0 +1,231 @@
+/*
+ * Copyright © 2018-2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#include "hb-ot-var-mvar-table.hh"
+#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-post-table.hh"
+#include "hb-ot-hhea-table.hh"
+#include "hb-ot-metrics.hh"
+#include "hb-ot-face.hh"
+
+
+static float
+_fix_ascender_descender (float value, hb_ot_metrics_tag_t metrics_tag)
+{
+  if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER ||
+      metrics_tag == HB_OT_METRICS_TAG_VERTICAL_ASCENDER)
+    return fabs ((double) value);
+  if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER ||
+      metrics_tag == HB_OT_METRICS_TAG_VERTICAL_DESCENDER)
+    return -fabs ((double) value);
+  return value;
+}
+
+/* The common part of _get_position logic needed on hb-ot-font and here
+   to be able to have slim builds without the not always needed parts */
+bool
+_hb_ot_metrics_get_position_common (hb_font_t           *font,
+                                    hb_ot_metrics_tag_t  metrics_tag,
+                                    hb_position_t       *position     /* OUT.  May be NULL. */)
+{
+  hb_face_t *face = font->face;
+  switch ((unsigned) metrics_tag)
+  {
+#ifndef HB_NO_VAR
+#define GET_VAR face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords)
+#else
+#define GET_VAR .0f
+#endif
+#define GET_METRIC_X(TABLE, ATTR) \
+  (face->table.TABLE->has_data () && \
+    (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
+      face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+#define GET_METRIC_Y(TABLE, ATTR) \
+  (face->table.TABLE->has_data () && \
+    (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
+      face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true))
+  case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
+    return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) ||
+           GET_METRIC_Y (hhea, ascender);
+  case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
+    return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoDescender)) ||
+           GET_METRIC_Y (hhea, descender);
+  case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
+    return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoLineGap)) ||
+           GET_METRIC_Y (hhea, lineGap);
+  case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:  return GET_METRIC_X (vhea, ascender);
+  case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender);
+  case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:  return GET_METRIC_X (vhea, lineGap);
+#undef GET_METRIC_Y
+#undef GET_METRIC_X
+#undef GET_VAR
+  default:                               assert (0); return false;
+  }
+}
+
+#ifndef HB_NO_METRICS
+
+#if 0
+static bool
+_get_gasp (hb_face_t *face, float *result, hb_ot_metrics_tag_t metrics_tag)
+{
+  const OT::GaspRange& range = face->table.gasp->get_gasp_range (metrics_tag - HB_TAG ('g','s','p','0'));
+  if (&range == &Null (OT::GaspRange)) return false;
+  if (result) *result = range.rangeMaxPPEM + font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords);
+  return true;
+}
+#endif
+
+/* Private tags for https://github.com/harfbuzz/harfbuzz/issues/1866 */
+#define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2   HB_TAG ('O','a','s','c')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA  HB_TAG ('H','a','s','c')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2  HB_TAG ('O','d','s','c')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA HB_TAG ('H','d','s','c')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2   HB_TAG ('O','l','g','p')
+#define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA  HB_TAG ('H','l','g','p')
+
+/**
+ * hb_ot_metrics_get_position:
+ * @font: a #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
+ * @position: (out) (optional): result of metrics value from the font.
+ *
+ * It fetches metrics value corresponding to a given tag from a font.
+ *
+ * Returns: Whether found the requested metrics in the font.
+ * Since: 2.6.0
+ **/
+hb_bool_t
+hb_ot_metrics_get_position (hb_font_t           *font,
+                            hb_ot_metrics_tag_t  metrics_tag,
+                            hb_position_t       *position     /* OUT.  May be NULL. */)
+{
+  hb_face_t *face = font->face;
+  switch ((unsigned) metrics_tag)
+  {
+  case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER:
+  case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER:
+  case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP:
+  case HB_OT_METRICS_TAG_VERTICAL_ASCENDER:
+  case HB_OT_METRICS_TAG_VERTICAL_DESCENDER:
+  case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP:           return _hb_ot_metrics_get_position_common (font, metrics_tag, position);
+#ifndef HB_NO_VAR
+#define GET_VAR hb_ot_metrics_get_variation (font, metrics_tag)
+#else
+#define GET_VAR 0
+#endif
+#define GET_METRIC_X(TABLE, ATTR) \
+  (face->table.TABLE->has_data () && \
+    (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR)), true))
+#define GET_METRIC_Y(TABLE, ATTR) \
+  (face->table.TABLE->has_data () && \
+    (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true))
+  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT:  return GET_METRIC_Y (OS2, usWinAscent);
+  case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent);
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE:       return GET_METRIC_Y (hhea, caretSlopeRise);
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN:        return GET_METRIC_X (hhea, caretSlopeRun);
+  case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET:     return GET_METRIC_X (hhea, caretOffset);
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE:         return GET_METRIC_X (vhea, caretSlopeRise);
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN:          return GET_METRIC_Y (vhea, caretSlopeRun);
+  case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET:       return GET_METRIC_Y (vhea, caretOffset);
+  case HB_OT_METRICS_TAG_X_HEIGHT:                    return GET_METRIC_Y (OS2->v2 (), sxHeight);
+  case HB_OT_METRICS_TAG_CAP_HEIGHT:                  return GET_METRIC_Y (OS2->v2 (), sCapHeight);
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE:         return GET_METRIC_X (OS2, ySubscriptXSize);
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE:         return GET_METRIC_Y (OS2, ySubscriptYSize);
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET:       return GET_METRIC_X (OS2, ySubscriptXOffset);
+  case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET:       return GET_METRIC_Y (OS2, ySubscriptYOffset);
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE:       return GET_METRIC_X (OS2, ySuperscriptXSize);
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE:       return GET_METRIC_Y (OS2, ySuperscriptYSize);
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET:     return GET_METRIC_X (OS2, ySuperscriptXOffset);
+  case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET:     return GET_METRIC_Y (OS2, ySuperscriptYOffset);
+  case HB_OT_METRICS_TAG_STRIKEOUT_SIZE:              return GET_METRIC_Y (OS2, yStrikeoutSize);
+  case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET:            return GET_METRIC_Y (OS2, yStrikeoutPosition);
+  case HB_OT_METRICS_TAG_UNDERLINE_SIZE:              return GET_METRIC_Y (post->table, underlineThickness);
+  case HB_OT_METRICS_TAG_UNDERLINE_OFFSET:            return GET_METRIC_Y (post->table, underlinePosition);
+
+  /* Private tags */
+  case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2:    return GET_METRIC_Y (OS2, sTypoAscender);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA:   return GET_METRIC_Y (hhea, ascender);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2:   return GET_METRIC_Y (OS2, sTypoDescender);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA:  return GET_METRIC_Y (hhea, descender);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2:    return GET_METRIC_Y (OS2, sTypoLineGap);
+  case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA:   return GET_METRIC_Y (hhea, lineGap);
+#undef GET_METRIC_Y
+#undef GET_METRIC_X
+#undef GET_VAR
+  default:                                        return false;
+  }
+}
+
+#ifndef HB_NO_VAR
+/**
+ * hb_ot_metrics_get_variation:
+ * @font:
+ * @metrics_tag:
+ *
+ * Returns:
+ *
+ * Since: 2.6.0
+ **/
+float
+hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
+{
+  return font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords);
+}
+
+/**
+ * hb_ot_metrics_get_x_variation:
+ * @font:
+ * @metrics_tag:
+ *
+ * Returns:
+ *
+ * Since: 2.6.0
+ **/
+hb_position_t
+hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
+{
+  return font->em_scalef_x (hb_ot_metrics_get_variation (font, metrics_tag));
+}
+
+/**
+ * hb_ot_metrics_get_y_variation:
+ * @font:
+ * @metrics_tag:
+ *
+ * Returns:
+ *
+ * Since: 2.6.0
+ **/
+hb_position_t
+hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
+{
+  return font->em_scalef_y (hb_ot_metrics_get_variation (font, metrics_tag));
+}
+#endif
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.h
new file mode 100644
index 0000000..c1be1d8
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_METRICS_H
+#define HB_OT_METRICS_H
+
+#include "hb.h"
+#include "hb-ot-name.h"
+
+HB_BEGIN_DECLS
+
+
+/**
+ * hb_ot_metrics_tag_t:
+ * @HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER: horizontal ascender.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER: horizontal descender.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP: horizontal line gap.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: horizontal clipping ascent.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: horizontal clipping descent.
+ * @HB_OT_METRICS_TAG_VERTICAL_ASCENDER: vertical ascender.
+ * @HB_OT_METRICS_TAG_VERTICAL_DESCENDER: vertical descender.
+ * @HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: vertical line gap.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: horizontal caret rise.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: horizontal caret run.
+ * @HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: horizontal caret offset.
+ * @HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: vertical caret rise.
+ * @HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: vertical caret run.
+ * @HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: vertical caret offset.
+ * @HB_OT_METRICS_TAG_X_HEIGHT: x height.
+ * @HB_OT_METRICS_TAG_CAP_HEIGHT: cap height.
+ * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE: subscript em x size.
+ * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE: subscript em y size.
+ * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET: subscript em x offset.
+ * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET: subscript em y offset.
+ * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE: superscript em x size.
+ * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE: superscript em y size.
+ * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET: superscript em x offset.
+ * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET: superscript em y offset.
+ * @HB_OT_METRICS_TAG_STRIKEOUT_SIZE: strikeout size.
+ * @HB_OT_METRICS_TAG_STRIKEOUT_OFFSET: strikeout offset.
+ * @HB_OT_METRICS_TAG_UNDERLINE_SIZE: underline size.
+ * @HB_OT_METRICS_TAG_UNDERLINE_OFFSET: underline offset.
+ *
+ * From https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags
+ *
+ * Since: 2.6.0
+ **/
+typedef enum {
+  HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER         = HB_TAG ('h','a','s','c'),
+  HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER        = HB_TAG ('h','d','s','c'),
+  HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP         = HB_TAG ('h','l','g','p'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT  = HB_TAG ('h','c','l','a'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT = HB_TAG ('h','c','l','d'),
+  HB_OT_METRICS_TAG_VERTICAL_ASCENDER           = HB_TAG ('v','a','s','c'),
+  HB_OT_METRICS_TAG_VERTICAL_DESCENDER          = HB_TAG ('v','d','s','c'),
+  HB_OT_METRICS_TAG_VERTICAL_LINE_GAP           = HB_TAG ('v','l','g','p'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE       = HB_TAG ('h','c','r','s'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN        = HB_TAG ('h','c','r','n'),
+  HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET     = HB_TAG ('h','c','o','f'),
+  HB_OT_METRICS_TAG_VERTICAL_CARET_RISE         = HB_TAG ('v','c','r','s'),
+  HB_OT_METRICS_TAG_VERTICAL_CARET_RUN          = HB_TAG ('v','c','r','n'),
+  HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET       = HB_TAG ('v','c','o','f'),
+  HB_OT_METRICS_TAG_X_HEIGHT                    = HB_TAG ('x','h','g','t'),
+  HB_OT_METRICS_TAG_CAP_HEIGHT                  = HB_TAG ('c','p','h','t'),
+  HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE         = HB_TAG ('s','b','x','s'),
+  HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE         = HB_TAG ('s','b','y','s'),
+  HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET       = HB_TAG ('s','b','x','o'),
+  HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET       = HB_TAG ('s','b','y','o'),
+  HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE       = HB_TAG ('s','p','x','s'),
+  HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE       = HB_TAG ('s','p','y','s'),
+  HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET     = HB_TAG ('s','p','x','o'),
+  HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET     = HB_TAG ('s','p','y','o'),
+  HB_OT_METRICS_TAG_STRIKEOUT_SIZE              = HB_TAG ('s','t','r','s'),
+  HB_OT_METRICS_TAG_STRIKEOUT_OFFSET            = HB_TAG ('s','t','r','o'),
+  HB_OT_METRICS_TAG_UNDERLINE_SIZE              = HB_TAG ('u','n','d','s'),
+  HB_OT_METRICS_TAG_UNDERLINE_OFFSET            = HB_TAG ('u','n','d','o'),
+
+  _HB_OT_METRICS_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
+} hb_ot_metrics_tag_t;
+
+HB_EXTERN hb_bool_t
+hb_ot_metrics_get_position (hb_font_t           *font,
+                            hb_ot_metrics_tag_t  metrics_tag,
+                            hb_position_t       *position     /* OUT.  May be NULL. */);
+
+HB_EXTERN float
+hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);
+
+HB_EXTERN hb_position_t
+hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);
+
+HB_EXTERN hb_position_t
+hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag);
+
+HB_END_DECLS
+
+#endif /* HB_OT_METRICS_H */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.hh
similarity index 70%
rename from src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.hh
rename to src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.hh
index 385a8f9..2c75f32 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2018  Google, Inc.
+ * Copyright © 2018  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -20,21 +20,16 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Garret Rieger
  */
 
-#ifndef HB_SUBSET_GLYF_HH
-#define HB_SUBSET_GLYF_HH
+#ifndef HB_OT_METRICS_HH
+#define HB_OT_METRICS_HH
 
 #include "hb.hh"
 
-#include "hb-subset.hh"
-
 HB_INTERNAL bool
-hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
-                         bool             *use_short_loca, /* OUT */
-                         hb_blob_t       **glyf_prime      /* OUT */,
-                         hb_blob_t       **loca_prime      /* OUT */);
+_hb_ot_metrics_get_position_common (hb_font_t           *font,
+                                    hb_ot_metrics_tag_t  metrics_tag,
+                                    hb_position_t       *position     /* OUT.  May be NULL. */);
 
-#endif /* HB_SUBSET_GLYF_HH */
+#endif /* HB_OT_METRICS_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-name-language.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-name-language-static.hh
similarity index 96%
rename from src/java.desktop/share/native/libharfbuzz/hb-ot-name-language.cc
rename to src/java.desktop/share/native/libharfbuzz/hb-ot-name-language-static.hh
index 1606a13..5312f7b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-name-language.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-name-language-static.hh
@@ -24,6 +24,9 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_OT_NAME_LANGUAGE_STATIC_HH
+#define HB_OT_NAME_LANGUAGE_STATIC_HH
+
 #include "hb-ot-name-language.hh"
 
 /* Following two tables were generated by joining FreeType, FontConfig,
@@ -34,12 +37,8 @@
 
 struct hb_ot_language_map_t
 {
-  static int cmp (const void *key, const void *item)
-  {
-    unsigned int a = * (unsigned int *) key;
-    unsigned int b = ((const hb_ot_language_map_t *) item)->code;
-    return a < b ? -1 : a > b ? +1 : 0;
-  }
+  int cmp (unsigned int key) const
+  { return key < code ? -1 : key > code ? +1 : 0; }
 
   uint16_t      code;
   char          lang[6];
@@ -427,12 +426,10 @@
                           const hb_ot_language_map_t *array,
                           unsigned int len)
 {
-  const hb_ot_language_map_t *entry = (const hb_ot_language_map_t *)
-                                      hb_bsearch (&code,
-                                                  array,
-                                                  len,
-                                                  sizeof (array[0]),
-                                                  hb_ot_language_map_t::cmp);
+#ifdef HB_NO_OT_NAME_LANGUAGE
+  return HB_LANGUAGE_INVALID;
+#endif
+  auto *entry = hb_bsearch (code, array, len);
 
   if (entry)
     return hb_language_from_string (entry->lang, -1);
@@ -455,3 +452,5 @@
                                    hb_mac_language_map,
                                    ARRAY_LENGTH (hb_mac_language_map));
 }
+
+#endif /* HB_OT_NAME_LANGUAGE_STATIC_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-name-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-name-table.hh
index 96600cb..fb2300d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-name-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-name-table.hh
@@ -51,6 +51,7 @@
 {
   hb_language_t language (hb_face_t *face) const
   {
+#ifndef HB_NO_OT_NAME_LANGUAGE
     unsigned int p = platformID;
     unsigned int l = languageID;
 
@@ -60,9 +61,12 @@
     if (p == 1)
       return _hb_ot_name_language_for_mac_code (l);
 
+#ifndef HB_NO_OT_NAME_LANGUAGE_AAT
     if (p == 0)
-      return _hb_aat_language_get (face, l);
+      return face->table.ltag->get_language (l);
+#endif
 
+#endif
     return HB_LANGUAGE_INVALID;
   }
 
@@ -93,11 +97,51 @@
     return UNSUPPORTED;
   }
 
+  NameRecord* copy (hb_serialize_context_t *c, const void *base) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+    out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
+    return_trace (out);
+  }
+
+  bool isUnicode () const
+  {
+    unsigned int p = platformID;
+    unsigned int e = encodingID;
+
+    return (p == 0 ||
+            (p == 3 && (e == 0 || e == 1 || e == 10)));
+  }
+
+  static int cmp (const void *pa, const void *pb)
+  {
+    const NameRecord *a = (const NameRecord *)pa;
+    const NameRecord *b = (const NameRecord *)pb;
+
+    if (a->platformID != b->platformID)
+      return a->platformID - b->platformID;
+
+    if (a->encodingID != b->encodingID)
+      return a->encodingID - b->encodingID;
+
+    if (a->languageID != b->languageID)
+      return a->languageID - b->languageID;
+
+    if (a->nameID != b->nameID)
+      return a->nameID - b->nameID;
+
+    if (a->length != b->length)
+      return a->length - b->length;
+
+    return 0;
+  }
+
   bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
-    /* We can check from base all the way up to the end of string... */
-    return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
+    return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
   }
 
   HBUINT16      platformID;     /* Platform ID. */
@@ -105,7 +149,8 @@
   HBUINT16      languageID;     /* Language ID. */
   HBUINT16      nameID;         /* Name ID. */
   HBUINT16      length;         /* String length (in bytes). */
-  HBUINT16      offset;         /* String offset from start of storage area (in bytes). */
+  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
+                offset;         /* String offset from start of storage area (in bytes). */
   public:
   DEFINE_SIZE_STATIC (12);
 };
@@ -119,7 +164,7 @@
   /* Compare by name_id, then language. */
 
   if (a->name_id != b->name_id)
-    return a->name_id < b->name_id ? -1 : +1;
+    return a->name_id - b->name_id;
 
   if (a->language == b->language) return 0;
   if (!a->language) return -1;
@@ -141,10 +186,10 @@
   const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
 
   if (a->entry_score != b->entry_score)
-    return a->entry_score < b->entry_score ? -1 : +1;
+    return a->entry_score - b->entry_score;
 
   if (a->entry_index != b->entry_index)
-    return a->entry_index < b->entry_index ? -1 : +1;
+    return a->entry_index - b->entry_index;
 
   return 0;
 }
@@ -156,15 +201,65 @@
   unsigned int get_size () const
   { return min_size + count * nameRecordZ.item_size; }
 
+  template <typename Iterator,
+            hb_requires (hb_is_source_of (Iterator, const NameRecord &))>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator it,
+                  const void *src_string_pool)
+  {
+    TRACE_SERIALIZE (this);
+
+    if (unlikely (!c->extend_min ((*this))))  return_trace (false);
+
+    this->format = 0;
+    this->count = it.len ();
+
+    NameRecord *name_records = (NameRecord *) calloc (it.len (), NameRecord::static_size);
+    if (unlikely (!name_records)) return_trace (false);
+
+    hb_array_t<NameRecord> records (name_records, it.len ());
+
+    for (const NameRecord& record : it)
+    {
+      memcpy (name_records, &record, NameRecord::static_size);
+      name_records++;
+    }
+
+    records.qsort ();
+
+    c->copy_all (records, src_string_pool);
+    free (records.arrayZ);
+
+    if (unlikely (c->ran_out_of_room)) return_trace (false);
+
+    this->stringOffset = c->length ();
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    name *name_prime = c->serializer->start_embed<name> ();
+    if (unlikely (!name_prime)) return_trace (false);
+
+    auto it =
+    + nameRecordZ.as_array (count)
+    | hb_filter (c->plan->name_ids, &NameRecord::nameID)
+    | hb_filter (c->plan->name_languages, &NameRecord::languageID)
+    | hb_filter ([&] (const NameRecord& namerecord) { return c->plan->name_legacy || namerecord.isUnicode (); })
+    ;
+
+    name_prime->serialize (c->serializer, it, hb_addressof (this + stringOffset));
+    return_trace (name_prime->count);
+  }
+
   bool sanitize_records (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     const void *string_pool = (this+stringOffset).arrayZ;
-    unsigned int _count = count;
-    /* Move to run-time?! */
-    for (unsigned int i = 0; i < _count; i++)
-      if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false);
-    return_trace (true);
+    return_trace (nameRecordZ.sanitize (c, count, string_pool));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -173,14 +268,15 @@
     return_trace (c->check_struct (this) &&
                   likely (format == 0 || format == 1) &&
                   c->check_array (nameRecordZ.arrayZ, count) &&
-                  c->check_range (this, stringOffset));
+                  c->check_range (this, stringOffset) &&
+                  sanitize_records (c));
   }
 
   struct accelerator_t
   {
     void init (hb_face_t *face)
     {
-      this->table = hb_sanitize_context_t().reference_table<name> (face);
+      this->table = hb_sanitize_context_t ().reference_table<name> (face);
       assert (this->table.get_length () >= this->table->stringOffset);
       this->pool = (const char *) (const void *) (this->table+this->table->stringOffset);
       this->pool_len = this->table.get_length () - this->table->stringOffset;
@@ -224,16 +320,14 @@
       this->table.destroy ();
     }
 
-    int get_index (hb_ot_name_id_t   name_id,
-                          hb_language_t     language,
-                          unsigned int     *width=nullptr) const
+    int get_index (hb_ot_name_id_t  name_id,
+                   hb_language_t    language,
+                   unsigned int    *width=nullptr) const
     {
       const hb_ot_name_entry_t key = {name_id, {0}, language};
-      const hb_ot_name_entry_t *entry = (const hb_ot_name_entry_t *)
-                                        hb_bsearch (&key,
-                                                    (const hb_ot_name_entry_t *) this->names,
+      const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
                                                     this->names.length,
-                                                    sizeof (key),
+                                                    sizeof (hb_ot_name_entry_t),
                                                     _hb_ot_name_entry_cmp_key);
       if (!entry)
         return -1;
@@ -261,16 +355,19 @@
   };
 
   /* We only implement format 0 for now. */
-  HBUINT16      format;                 /* Format selector (=0/1). */
-  HBUINT16      count;                  /* Number of name records. */
-  NNOffsetTo<UnsizedArrayOf<HBUINT8> >
-                stringOffset;           /* Offset to start of string storage (from start of table). */
+  HBUINT16      format;         /* Format selector (=0/1). */
+  HBUINT16      count;          /* Number of name records. */
+  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
+                stringOffset;   /* Offset to start of string storage (from start of table). */
   UnsizedArrayOf<NameRecord>
-                nameRecordZ;            /* The name records where count is the number of records. */
+                nameRecordZ;    /* The name records where count is the number of records. */
   public:
   DEFINE_SIZE_ARRAY (6, nameRecordZ);
 };
 
+#undef entry_index
+#undef entry_score
+
 struct name_accelerator_t : name::accelerator_t {};
 
 } /* namespace OT */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-name.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-name.cc
index 83a332e..56bfd39 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-name.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-name.cc
@@ -26,9 +26,10 @@
 
 #include "hb.hh"
 
+#ifndef HB_NO_NAME
+
 #include "hb-ot-name-table.hh"
 
-#include "hb-ot-face.hh"
 #include "hb-utf.hh"
 
 
@@ -93,7 +94,7 @@
 
       dst = dst_next;
       src = src_next;
-    };
+    }
 
     *text_size = dst - text;
     *dst = 0; /* NUL-terminate. */
@@ -105,7 +106,7 @@
   {
     src = in_utf_t::next (src, src_end, &unicode, replacement);
     dst_len += out_utf_t::encode_len (unicode);
-  };
+  }
   return dst_len;
 }
 
@@ -222,3 +223,6 @@
 {
   return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh
index 6fbffb1..3639a06 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh
@@ -30,6 +30,7 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-os2-unicode-ranges.hh"
+#include "hb-ot-cmap-table.hh"
 
 #include "hb-set.hh"
 
@@ -59,6 +60,10 @@
 
 struct OS2V2Tail
 {
+  bool has_data () const { return sxHeight || sCapHeight; }
+
+  const OS2V2Tail * operator -> () const { return this; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -77,6 +82,23 @@
 
 struct OS2V5Tail
 {
+  inline bool get_optical_size (unsigned int *lower, unsigned int *upper) const
+  {
+    unsigned int lower_optical_size = usLowerOpticalPointSize;
+    unsigned int upper_optical_size = usUpperOpticalPointSize;
+
+    /* Per https://docs.microsoft.com/en-us/typography/opentype/spec/os2#lps */
+    if (lower_optical_size < upper_optical_size &&
+        lower_optical_size >= 1 && lower_optical_size <= 0xFFFE &&
+        upper_optical_size >= 2 && upper_optical_size <= 0xFFFF)
+    {
+      *lower = lower_optical_size;
+      *upper = upper_optical_size;
+      return true;
+    }
+    return false;
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -94,7 +116,7 @@
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_OS2;
 
-  bool has_data () const { return this != &Null (OS2); }
+  bool has_data () const { return usWeightClass || usWidthClass || usFirstCharIndex || usLastCharIndex; }
 
   const OS2V1Tail &v1 () const { return version >= 1 ? v1X : Null (OS2V1Tail); }
   const OS2V2Tail &v2 () const { return version >= 2 ? v2X : Null (OS2V2Tail); }
@@ -113,9 +135,9 @@
     OBLIQUE             = 1u<<9
   };
 
-  bool is_italic () const       { return fsSelection & ITALIC; }
-  bool is_oblique () const      { return fsSelection & OBLIQUE; }
-  bool is_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; }
+  bool        is_italic () const { return fsSelection & ITALIC; }
+  bool       is_oblique () const { return fsSelection & OBLIQUE; }
+  bool use_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; }
 
   enum width_class_t {
     FWIDTH_ULTRA_CONDENSED      = 1, /* 50% */
@@ -145,36 +167,49 @@
     }
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  bool subset (hb_subset_context_t *c) const
   {
-    hb_blob_t *os2_blob = hb_sanitize_context_t ().reference_table<OS2> (plan->source);
-    hb_blob_t *os2_prime_blob = hb_blob_create_sub_blob (os2_blob, 0, -1);
-    // TODO(grieger): move to hb_blob_copy_writable_or_fail
-    hb_blob_destroy (os2_blob);
+    TRACE_SUBSET (this);
+    OS2 *os2_prime = c->serializer->embed (this);
+    if (unlikely (!os2_prime)) return_trace (false);
 
-    OS2 *os2_prime = (OS2 *) hb_blob_get_data_writable (os2_prime_blob, nullptr);
-    if (unlikely (!os2_prime)) {
-      hb_blob_destroy (os2_prime_blob);
-      return false;
+    hb_set_t unicodes;
+    if (!c->plan->glyphs_requested->is_empty ())
+    {
+      hb_map_t unicode_glyphid_map;
+
+      OT::cmap::accelerator_t cmap;
+      cmap.init (c->plan->source);
+      cmap.collect_mapping (&unicodes, &unicode_glyphid_map);
+      cmap.fini ();
+
+      if (c->plan->unicodes->is_empty ()) unicodes.clear ();
+      else hb_set_set (&unicodes, c->plan->unicodes);
+
+      + unicode_glyphid_map.iter ()
+      | hb_filter (c->plan->glyphs_requested, hb_second)
+      | hb_map (hb_first)
+      | hb_sink (unicodes)
+      ;
     }
-
+    /* when --gids option is not used, no need to do collect_mapping that is
+       * iterating all codepoints in each subtable, which is not efficient */
     uint16_t min_cp, max_cp;
-    find_min_and_max_codepoint (plan->unicodes, &min_cp, &max_cp);
-    os2_prime->usFirstCharIndex.set (min_cp);
-    os2_prime->usLastCharIndex.set (max_cp);
+    find_min_and_max_codepoint (unicodes.is_empty () ? c->plan->unicodes : &unicodes, &min_cp, &max_cp);
+    os2_prime->usFirstCharIndex = min_cp;
+    os2_prime->usLastCharIndex = max_cp;
 
-    _update_unicode_ranges (plan->unicodes, os2_prime->ulUnicodeRange);
-    bool result = plan->add_table (HB_OT_TAG_OS2, os2_prime_blob);
+    _update_unicode_ranges (unicodes.is_empty () ? c->plan->unicodes : &unicodes, os2_prime->ulUnicodeRange);
 
-    hb_blob_destroy (os2_prime_blob);
-    return result;
+    return_trace (true);
   }
 
   void _update_unicode_ranges (const hb_set_t *codepoints,
                                HBUINT32 ulUnicodeRange[4]) const
   {
+    HBUINT32    newBits[4];
     for (unsigned int i = 0; i < 4; i++)
-      ulUnicodeRange[i].set (0);
+      newBits[i] = 0;
 
     hb_codepoint_t cp = HB_SET_VALUE_INVALID;
     while (codepoints->next (&cp)) {
@@ -184,40 +219,52 @@
         unsigned int block = bit / 32;
         unsigned int bit_in_block = bit % 32;
         unsigned int mask = 1 << bit_in_block;
-        ulUnicodeRange[block].set (ulUnicodeRange[block] | mask);
+        newBits[block] = newBits[block] | mask;
       }
       if (cp >= 0x10000 && cp <= 0x110000)
       {
         /* the spec says that bit 57 ("Non Plane 0") implies that there's
            at least one codepoint beyond the BMP; so I also include all
            the non-BMP codepoints here */
-        ulUnicodeRange[1].set (ulUnicodeRange[1] | (1 << 25));
+        newBits[1] = newBits[1] | (1 << 25);
       }
     }
+
+    for (unsigned int i = 0; i < 4; i++)
+      ulUnicodeRange[i] = ulUnicodeRange[i] & newBits[i]; // set bits only if set in the original
   }
 
   static void find_min_and_max_codepoint (const hb_set_t *codepoints,
-                                                 uint16_t *min_cp, /* OUT */
-                                                 uint16_t *max_cp  /* OUT */)
+                                          uint16_t *min_cp, /* OUT */
+                                          uint16_t *max_cp  /* OUT */)
   {
-    *min_cp = codepoints->get_min ();
-    *max_cp = codepoints->get_max ();
+    *min_cp = hb_min (0xFFFFu, codepoints->get_min ());
+    *max_cp = hb_min (0xFFFFu, codepoints->get_max ());
   }
 
-  enum font_page_t {
-    HEBREW_FONT_PAGE            = 0xB100, // Hebrew Windows 3.1 font page
-    SIMP_ARABIC_FONT_PAGE       = 0xB200, // Simplified Arabic Windows 3.1 font page
-    TRAD_ARABIC_FONT_PAGE       = 0xB300, // Traditional Arabic Windows 3.1 font page
-    OEM_ARABIC_FONT_PAGE        = 0xB400, // OEM Arabic Windows 3.1 font page
-    SIMP_FARSI_FONT_PAGE        = 0xBA00, // Simplified Farsi Windows 3.1 font page
-    TRAD_FARSI_FONT_PAGE        = 0xBB00, // Traditional Farsi Windows 3.1 font page
-    THAI_FONT_PAGE              = 0xDE00  // Thai Windows 3.1 font page
+  /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 */
+  enum font_page_t
+  {
+    FONT_PAGE_HEBREW            = 0xB100, /* Hebrew Windows 3.1 font page */
+    FONT_PAGE_SIMP_ARABIC       = 0xB200, /* Simplified Arabic Windows 3.1 font page */
+    FONT_PAGE_TRAD_ARABIC       = 0xB300, /* Traditional Arabic Windows 3.1 font page */
+    FONT_PAGE_OEM_ARABIC        = 0xB400, /* OEM Arabic Windows 3.1 font page */
+    FONT_PAGE_SIMP_FARSI        = 0xBA00, /* Simplified Farsi Windows 3.1 font page */
+    FONT_PAGE_TRAD_FARSI        = 0xBB00, /* Traditional Farsi Windows 3.1 font page */
+    FONT_PAGE_THAI              = 0xDE00  /* Thai Windows 3.1 font page */
   };
-
-  // https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681
   font_page_t get_font_page () const
   { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); }
 
+  unsigned get_size () const
+  {
+    unsigned result = min_size;
+    if (version >= 1) result += v1X.get_size ();
+    if (version >= 2) result += v2X.get_size ();
+    if (version >= 5) result += v5X.get_size ();
+    return result;
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-unicode-ranges.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-unicode-ranges.hh
index 7e573b3..9613d2d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-unicode-ranges.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-unicode-ranges.hh
@@ -33,19 +33,8 @@
 
 struct OS2Range
 {
-  static int
-  cmp (const void *_key, const void *_item)
-  {
-    hb_codepoint_t cp = *((hb_codepoint_t *) _key);
-    const OS2Range *range = (OS2Range *) _item;
-
-    if (cp < range->start)
-      return -1;
-    else if (cp <= range->end)
-      return 0;
-    else
-      return +1;
-  }
+  int cmp (hb_codepoint_t key) const
+  { return (key < start) ? -1 : key <= end ? 0 : +1; }
 
   hb_codepoint_t start;
   hb_codepoint_t end;
@@ -233,13 +222,8 @@
 static unsigned int
 _hb_ot_os2_get_unicode_range_bit (hb_codepoint_t cp)
 {
-  OS2Range *range = (OS2Range*) hb_bsearch (&cp, _hb_os2_unicode_ranges,
-                                            ARRAY_LENGTH (_hb_os2_unicode_ranges),
-                                            sizeof (OS2Range),
-                                            OS2Range::cmp);
-  if (range != nullptr)
-    return range->bit;
-  return -1;
+  auto *range = hb_sorted_array (_hb_os2_unicode_ranges).bsearch (cp);
+  return range ? range->bit : -1;
 }
 
 } /* namespace OT */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh
index 40134b4..08449ac 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh
@@ -35,8 +35,6 @@
 #undef HB_STRING_ARRAY_LIST
 #undef HB_STRING_ARRAY_NAME
 
-#define NUM_FORMAT1_NAMES 258
-
 /*
  * post -- PostScript
  * https://docs.microsoft.com/en-us/typography/opentype/spec/post
@@ -73,26 +71,25 @@
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_post;
 
-  bool subset (hb_subset_plan_t *plan) const
+  void serialize (hb_serialize_context_t *c) const
   {
-    unsigned int post_prime_length;
-    hb_blob_t *post_blob = hb_sanitize_context_t ().reference_table<post>(plan->source);
-    hb_blob_t *post_prime_blob = hb_blob_create_sub_blob (post_blob, 0, post::min_size);
-    post *post_prime = (post *) hb_blob_get_data_writable (post_prime_blob, &post_prime_length);
-    hb_blob_destroy (post_blob);
+    post *post_prime = c->allocate_min<post> ();
+    if (unlikely (!post_prime))  return;
 
-    if (unlikely (!post_prime || post_prime_length != post::min_size))
-    {
-      hb_blob_destroy (post_prime_blob);
-      DEBUG_MSG(SUBSET, nullptr, "Invalid source post table with length %d.", post_prime_length);
-      return false;
-    }
+    memcpy (post_prime, this, post::min_size);
+    post_prime->version.major = 3; // Version 3 does not have any glyph names.
+  }
 
-    post_prime->version.major.set (3); // Version 3 does not have any glyph names.
-    bool result = plan->add_table (HB_OT_TAG_post, post_prime_blob);
-    hb_blob_destroy (post_prime_blob);
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    post *post_prime = c->serializer->start_embed<post> ();
+    if (unlikely (!post_prime)) return_trace (false);
 
-    return result;
+    serialize (c->serializer);
+    if (c->serializer->in_error () || c->serializer->ran_out_of_room) return_trace (false);
+
+    return_trace (true);
   }
 
   struct accelerator_t
@@ -131,7 +128,7 @@
       hb_bytes_t s = find_glyph_name (glyph);
       if (!s.length) return false;
       if (!buf_len) return true;
-      unsigned int len = MIN (buf_len - 1, s.length);
+      unsigned int len = hb_min (buf_len - 1, s.length);
       strncpy (buf, s.arrayZ, len);
       buf[len] = '\0';
       return true;
@@ -158,7 +155,7 @@
 
         for (unsigned int i = 0; i < count; i++)
           gids[i] = i;
-        hb_sort_r (gids, count, sizeof (gids[0]), cmp_gids, (void *) this);
+        hb_qsort (gids, count, sizeof (gids[0]), cmp_gids, (void *) this);
 
         if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
         {
@@ -168,8 +165,7 @@
       }
 
       hb_bytes_t st (name, len);
-      const uint16_t *gid = (const uint16_t *) hb_bsearch_r (hb_addressof (st), gids, count,
-                                                             sizeof (gids[0]), cmp_key, (void *) this);
+      auto* gid = hb_bsearch (st, gids, count, sizeof (gids[0]), cmp_key, (void *) this);
       if (gid)
       {
         *glyph = *gid;
@@ -179,12 +175,14 @@
       return false;
     }
 
+    hb_blob_ptr_t<post> table;
+
     protected:
 
     unsigned int get_glyph_count () const
     {
       if (version == 0x00010000)
-        return NUM_FORMAT1_NAMES;
+        return format1_names_length;
 
       if (version == 0x00020000)
         return glyphNameIndex->len;
@@ -212,7 +210,7 @@
     {
       if (version == 0x00010000)
       {
-        if (glyph >= NUM_FORMAT1_NAMES)
+        if (glyph >= format1_names_length)
           return hb_bytes_t ();
 
         return format1_names (glyph);
@@ -222,9 +220,9 @@
         return hb_bytes_t ();
 
       unsigned int index = glyphNameIndex->arrayZ[glyph];
-      if (index < NUM_FORMAT1_NAMES)
+      if (index < format1_names_length)
         return format1_names (index);
-      index -= NUM_FORMAT1_NAMES;
+      index -= format1_names_length;
 
       if (index >= index_to_offset.length)
         return hb_bytes_t ();
@@ -238,7 +236,6 @@
     }
 
     private:
-    hb_blob_ptr_t<post> table;
     uint32_t version;
     const ArrayOf<HBUINT16> *glyphNameIndex;
     hb_vector_t<uint32_t> index_to_offset;
@@ -246,6 +243,8 @@
     hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;
   };
 
+  bool has_data () const { return version.to_int (); }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -260,7 +259,7 @@
                                          * 0x00020000 for version 2.0
                                          * 0x00025000 for version 2.5 (deprecated)
                                          * 0x00030000 for version 3.0 */
-  Fixed         italicAngle;            /* Italic angle in counter-clockwise degrees
+  HBFixed       italicAngle;            /* Italic angle in counter-clockwise degrees
                                          * from the vertical. Zero for upright text,
                                          * negative for text that leans to the right
                                          * (forward). */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh
index f0d104c..8a29d54 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh
@@ -49,8 +49,8 @@
                                           hb_font_t *font,
                                           unsigned int feature_index)
 {
-  OT::GlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
-  OT::GlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  OT::HBGlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  OT::HBGlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
   unsigned int num_glyphs = 0;
 
   /* Populate arrays */
@@ -66,8 +66,8 @@
         u_glyph > 0xFFFFu || s_glyph > 0xFFFFu)
       continue;
 
-    glyphs[num_glyphs].set (u_glyph);
-    substitutes[num_glyphs].set (s_glyph);
+    glyphs[num_glyphs] = u_glyph;
+    substitutes[num_glyphs] = s_glyph;
 
     num_glyphs++;
   }
@@ -77,7 +77,9 @@
 
   /* Bubble-sort or something equally good!
    * May not be good-enough for presidential candidate interviews, but good-enough for us... */
-  hb_stable_sort (&glyphs[0], num_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &substitutes[0]);
+  hb_stable_sort (&glyphs[0], num_glyphs,
+                  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp,
+                  &substitutes[0]);
 
 
   /* Each glyph takes four bytes max, and there's some overhead. */
@@ -86,27 +88,26 @@
   OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
   bool ret = lookup->serialize_single (&c,
                                        OT::LookupFlag::IgnoreMarks,
-                                       hb_array (glyphs, num_glyphs),
+                                       hb_sorted_array (glyphs, num_glyphs),
                                        hb_array (substitutes, num_glyphs));
   c.end_serialize ();
-  /* TODO sanitize the results? */
 
-  return ret ? c.copy<OT::SubstLookup> () : nullptr;
+  return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
 }
 
 static OT::SubstLookup *
 arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
                                             hb_font_t *font)
 {
-  OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
+  OT::HBGlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
   unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
   unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
   unsigned int num_first_glyphs = 0;
 
   /* We know that all our ligatures are 2-component */
-  OT::GlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
+  OT::HBGlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
   unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)];
-  OT::GlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
+  OT::HBGlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
   unsigned int num_ligatures = 0;
 
   /* Populate arrays */
@@ -118,12 +119,14 @@
     hb_codepoint_t first_glyph;
     if (!hb_font_get_glyph (font, first_u, 0, &first_glyph))
       continue;
-    first_glyphs[num_first_glyphs].set (first_glyph);
+    first_glyphs[num_first_glyphs] = first_glyph;
     ligature_per_first_glyph_count_list[num_first_glyphs] = 0;
     first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
     num_first_glyphs++;
   }
-  hb_stable_sort (&first_glyphs[0], num_first_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &first_glyphs_indirection[0]);
+  hb_stable_sort (&first_glyphs[0], num_first_glyphs,
+                  (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp,
+                  &first_glyphs_indirection[0]);
 
   /* Now that the first-glyphs are sorted, walk again, populate ligatures. */
   for (unsigned int i = 0; i < num_first_glyphs; i++)
@@ -142,9 +145,9 @@
 
       ligature_per_first_glyph_count_list[i]++;
 
-      ligature_list[num_ligatures].set (ligature_glyph);
+      ligature_list[num_ligatures] = ligature_glyph;
       component_count_list[num_ligatures] = 2;
-      component_list[num_ligatures].set (second_glyph);
+      component_list[num_ligatures] = second_glyph;
       num_ligatures++;
     }
   }
@@ -159,7 +162,7 @@
   OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
   bool ret = lookup->serialize_ligature (&c,
                                          OT::LookupFlag::IgnoreMarks,
-                                         hb_array (first_glyphs, num_first_glyphs),
+                                         hb_sorted_array (first_glyphs, num_first_glyphs),
                                          hb_array (ligature_per_first_glyph_count_list, num_first_glyphs),
                                          hb_array (ligature_list, num_ligatures),
                                          hb_array (component_count_list, num_ligatures),
@@ -167,7 +170,7 @@
   c.end_serialize ();
   /* TODO sanitize the results? */
 
-  return ret ? c.copy<OT::SubstLookup> () : nullptr;
+  return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr;
 }
 
 static OT::SubstLookup *
@@ -227,8 +230,8 @@
     return false;
 
   const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
-  static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
-                 <= ARABIC_FALLBACK_MAX_LOOKUPS, "");
+  static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) ==
+                 ARABIC_FALLBACK_MAX_LOOKUPS * sizeof (ManifestLookup), "");
   /* TODO sanitize the table? */
 
   unsigned j = 0;
@@ -289,7 +292,7 @@
 {
   arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
   if (unlikely (!fallback_plan))
-    return const_cast<arabic_fallback_plan_t *> (&Null(arabic_fallback_plan_t));
+    return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
 
   fallback_plan->num_lookups = 0;
   fallback_plan->free_lookups = false;
@@ -306,7 +309,7 @@
 
   assert (fallback_plan->num_lookups == 0);
   free (fallback_plan);
-  return const_cast<arabic_fallback_plan_t *> (&Null(arabic_fallback_plan_t));
+  return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
 }
 
 static void
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-joining-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-joining-list.hh
new file mode 100644
index 0000000..c022d4b
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-joining-list.hh
@@ -0,0 +1,46 @@
+/* == Start of generated function == */
+/*
+ * The following function is generated by running:
+ *
+ *   ./gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt
+ *
+ * on files with these headers:
+ *
+ * # ArabicShaping-13.0.0.txt
+ * # Date: 2020-01-31, 23:55:00 GMT [KW, RP]
+ * # Scripts-13.0.0.txt
+ * # Date: 2020-01-22, 00:07:43 GMT
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
+#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
+
+static bool
+has_arabic_joining (hb_script_t script)
+{
+  /* List of scripts that have data in arabic-table. */
+  switch ((int) script)
+  {
+    case HB_SCRIPT_ADLAM:
+    case HB_SCRIPT_ARABIC:
+    case HB_SCRIPT_CHORASMIAN:
+    case HB_SCRIPT_HANIFI_ROHINGYA:
+    case HB_SCRIPT_MANDAIC:
+    case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_MONGOLIAN:
+    case HB_SCRIPT_NKO:
+    case HB_SCRIPT_PHAGS_PA:
+    case HB_SCRIPT_PSALTER_PAHLAVI:
+    case HB_SCRIPT_SOGDIAN:
+    case HB_SCRIPT_SYRIAC:
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */
+
+/* == End of generated function == */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-table.hh
index 7bb0aeb..d47d036 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-table.hh
@@ -6,10 +6,10 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-11.0.0.txt
- * # Date: 2018-02-21, 14:50:00 GMT [KW, RP]
- * # Blocks-11.0.0.txt
- * # Date: 2017-10-16, 24:39:00 GMT [KW]
+ * # ArabicShaping-13.0.0.txt
+ * # Date: 2020-01-31, 23:55:00 GMT [KW, RP]
+ * # Blocks-13.0.0.txt
+ * # Date: 2019-07-10, 19:06:00 GMT [KW]
  * UnicodeData.txt does not have a header.
  */
 
@@ -17,15 +17,15 @@
 #define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
 
 
-#define X       JOINING_TYPE_X
+#define A       JOINING_GROUP_ALAPH
+#define DR      JOINING_GROUP_DALATH_RISH
+#define C       JOINING_TYPE_C
+#define D       JOINING_TYPE_D
+#define L       JOINING_TYPE_L
 #define R       JOINING_TYPE_R
 #define T       JOINING_TYPE_T
 #define U       JOINING_TYPE_U
-#define A       JOINING_GROUP_ALAPH
-#define DR      JOINING_GROUP_DALATH_RISH
-#define L       JOINING_TYPE_L
-#define C       JOINING_TYPE_C
-#define D       JOINING_TYPE_D
+#define X       JOINING_TYPE_X
 
 static const uint8_t joining_table[] =
 {
@@ -71,7 +71,7 @@
 
   /* Mandaic */
 
-  /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,U,U,U,X,X,X,X,X,X,X,
+  /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,R,R,R,X,X,X,X,X,X,X,
 
   /* Syriac Supplement */
 
@@ -80,8 +80,8 @@
 
   /* Arabic Extended-A */
 
-  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,X,D,D,D,R,D,D,D,D,X,X,
-  /* 08C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,X,D,D,D,R,D,D,D,D,D,D,
+  /* 08C0 */ D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
   /* 08E0 */ X,X,U,
 
 #define joining_offset_0x1806u 739
@@ -139,22 +139,29 @@
   /* 10F20 */                                 D,D,D,R,D,D,D,D,D,D,D,D,D,D,D,D,
   /* 10F40 */ D,D,D,D,D,U,X,X,X,X,X,X,X,X,X,X,X,D,D,D,R,
 
-#define joining_offset_0x110bdu 1219
+#define joining_offset_0x10fb0u 1219
+
+  /* Chorasmian */
+
+  /* 10FA0 */                                 D,U,D,D,R,R,R,U,D,R,R,D,D,R,D,D,
+  /* 10FC0 */ U,D,R,R,D,U,U,U,U,R,D,L,
+
+#define joining_offset_0x110bdu 1247
 
   /* Kaithi */
 
   /* 110A0 */                                                           U,X,X,
   /* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U,
 
-#define joining_offset_0x1e900u 1236
+#define joining_offset_0x1e900u 1264
 
   /* Adlam */
 
   /* 1E900 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
   /* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
-  /* 1E940 */ D,D,D,D,
+  /* 1E940 */ D,D,D,D,X,X,X,X,X,X,X,T,
 
-}; /* Table items: 1304; occupancy: 56% */
+}; /* Table items: 1340; occupancy: 57% */
 
 
 static unsigned int
@@ -183,6 +190,7 @@
       if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
       if (hb_in_range<hb_codepoint_t> (u, 0x10D00u, 0x10D23u)) return joining_table[u - 0x10D00u + joining_offset_0x10d00u];
       if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x10F54u)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x10FB0u, 0x10FCBu)) return joining_table[u - 0x10FB0u + joining_offset_0x10fb0u];
       break;
 
     case 0x11u:
@@ -190,7 +198,7 @@
       break;
 
     case 0x1Eu:
-      if (hb_in_range<hb_codepoint_t> (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x1E900u, 0x1E94Bu)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
       break;
 
     default:
@@ -199,15 +207,15 @@
   return X;
 }
 
-#undef X
+#undef A
+#undef DR
+#undef C
+#undef D
+#undef L
 #undef R
 #undef T
 #undef U
-#undef A
-#undef DR
-#undef L
-#undef C
-#undef D
+#undef X
 
 
 static const uint16_t shaping_table[][4] =
@@ -406,16 +414,16 @@
 } ligature_table[] =
 {
   { 0xFEDFu, {
-    { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
     { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
-    { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
     { 0xFE84u, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
+    { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
+    { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
   }},
   { 0xFEE0u, {
-    { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
     { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
-    { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
     { 0xFE84u, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
+    { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
+    { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
   }},
 };
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc
index a25ced1..c8ad501 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc
@@ -25,6 +25,9 @@
  */
 
 #include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-arabic.hh"
 #include "hb-ot-shape.hh"
 
@@ -225,8 +228,6 @@
   map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
   map->add_gsub_pause (nullptr);
 
-  /* And undo here. */
-
   /* The spec includes 'cswh'.  Earlier versions of Windows
    * used to enable this by default, but testing suggests
    * that Windows 8 and later do not enable it by default,
@@ -289,7 +290,7 @@
 {
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
-  unsigned int prev = (unsigned int) -1, state = 0;
+  unsigned int prev = UINT_MAX, state = 0;
 
   /* Check pre-context */
   for (unsigned int i = 0; i < buffer->context_len[0]; i++)
@@ -315,7 +316,7 @@
 
     const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
 
-    if (entry->prev_action != NONE && prev != (unsigned int) -1)
+    if (entry->prev_action != NONE && prev != UINT_MAX)
     {
       info[prev].arabic_shaping_action() = entry->prev_action;
       buffer->unsafe_to_break (prev, i + 1);
@@ -335,7 +336,7 @@
       continue;
 
     const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
-    if (entry->prev_action != NONE && prev != (unsigned int) -1)
+    if (entry->prev_action != NONE && prev != UINT_MAX)
       info[prev].arabic_shaping_action() = entry->prev_action;
     break;
   }
@@ -383,6 +384,10 @@
                        hb_font_t *font,
                        hb_buffer_t *buffer)
 {
+#ifdef HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
+  return;
+#endif
+
   const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
 
   if (!arabic_plan->do_fallback)
@@ -467,7 +472,7 @@
     unsigned int j = new_len;
     for (unsigned int i = count; i; i--)
     {
-      if (!hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+      if (!hb_in_range<uint8_t> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
       {
         if (step == CUT)
         {
@@ -488,7 +493,7 @@
 
       unsigned int end = i;
       while (i &&
-             hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+             hb_in_range<uint8_t> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
       {
         i--;
         hb_position_t width = font->get_glyph_h_advance (info[i].codepoint);
@@ -506,7 +511,7 @@
       unsigned int start = i;
       unsigned int context = i;
       while (context &&
-             !hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
+             !hb_in_range<uint8_t> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
              (_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
               HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
       {
@@ -597,7 +602,7 @@
   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
 
-/* http://www.unicode.org/reports/tr53/ */
+/* https://www.unicode.org/reports/tr53/ */
 
 static hb_codepoint_t
 modifier_combining_marks[] =
@@ -706,3 +711,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-default.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-default.cc
index 97923ec..a755aea 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-default.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-default.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex.hh"
 
 
@@ -44,3 +48,26 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
+
+/* Same as default but no mark advance zeroing / fallback positioning.
+ * Dumbest shaper ever, basically. */
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_dumber =
+{
+  nullptr, /* collect_features */
+  nullptr, /* override_features */
+  nullptr, /* data_create */
+  nullptr, /* data_destroy */
+  nullptr, /* preprocess_text */
+  nullptr, /* postprocess_glyphs */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  nullptr, /* decompose */
+  nullptr, /* compose */
+  nullptr, /* setup_masks */
+  HB_TAG_NONE, /* gpos_tag */
+  nullptr, /* reorder_marks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+  false, /* fallback_position */
+};
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hangul.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hangul.cc
index c77cac1..d7db437 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hangul.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hangul.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex.hh"
 
 
@@ -214,7 +218,8 @@
       else
       {
         /* No valid syllable as base for tone mark; try to insert dotted circle. */
-        if (font->has_glyph (0x25CCu))
+      if (!(buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) &&
+          font->has_glyph (0x25CCu))
         {
           hb_codepoint_t chars[2];
           if (!is_zero_width_char (font, u)) {
@@ -429,3 +434,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hebrew.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hebrew.cc
index 1d80a46..5754080 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hebrew.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hebrew.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex.hh"
 
 
@@ -70,6 +74,10 @@
 
   bool found = (bool) c->unicode->compose (a, b, ab);
 
+#ifdef HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
+  return found;
+#endif
+
   if (!found && !c->plan->has_gpos_mark)
   {
       /* Special-case Hebrew presentation forms that are excluded from
@@ -172,3 +180,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-machine.hh
index 9fc6315..4c04e0c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-machine.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-machine.hh
@@ -34,711 +34,284 @@
 
 #line 36 "hb-ot-shape-complex-indic-machine.hh"
 static const unsigned char _indic_syllable_machine_trans_keys[] = {
-        8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
-        5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u,
-        4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
-        16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u,
-        4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
-        7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u,
-        6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u,
-        4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u,
-        4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u,
-        5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
-        7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
-        6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u,
-        4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 8u, 8u, 4u, 8u, 5u, 7u,
-        7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
-        5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u,
-        4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u,
-        4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 13u,
-        5u, 8u, 8u, 8u, 1u, 19u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u,
-        3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u,
-        3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u,
-        5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u,
-        4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u,
-        3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u,
-        3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u,
-        1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u,
-        3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u,
-        3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u,
-        3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u,
-        10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u,
-        4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u,
-        3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u,
-        1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u,
-        1u, 16u, 1u, 16u, 1u, 16u, 4u, 8u, 3u, 10u, 3u, 10u, 4u, 10u, 1u, 16u,
-        3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u,
-        3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u,
-        5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u,
-        3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u,
-        5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u,
-        3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u,
-        1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 13u,
-        3u, 10u, 4u, 8u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u,
-        4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u,
-        4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u,
-        10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u,
-        5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u,
-        4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u,
-        1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u,
-        3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 1u, 16u, 3u, 13u,
-        1u, 16u, 4u, 13u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u,
-        3u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u,
-        0
+        8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
+        4u, 13u, 4u, 8u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u,
+        4u, 8u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u,
+        6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u,
+        4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 5u, 8u, 8u, 8u, 1u, 19u,
+        3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u,
+        1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u,
+        3u, 10u, 5u, 10u, 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+        3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u,
+        1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u,
+        5u, 10u, 3u, 17u, 3u, 17u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+        3u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u,
+        4u, 10u, 5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u,
+        3u, 17u, 4u, 13u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u,
+        1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u,
+        5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 1u, 17u,
+        3u, 17u, 1u, 17u, 4u, 13u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u,
+        5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 0
 };
 
 static const char _indic_syllable_machine_key_spans[] = {
-        1, 5, 3, 1, 4, 3, 1, 4,
-        3, 1, 4, 3, 1, 5, 1, 1,
-        5, 1, 1, 5, 1, 1, 5, 1,
-        1, 10, 5, 10, 5, 10, 5, 10,
-        5, 10, 1, 5, 3, 1, 4, 3,
-        1, 4, 3, 1, 4, 3, 1, 5,
-        1, 1, 5, 1, 1, 5, 1, 1,
-        5, 1, 1, 10, 5, 10, 5, 10,
-        5, 10, 5, 10, 1, 5, 3, 1,
-        4, 3, 1, 4, 3, 1, 4, 3,
-        1, 5, 1, 1, 5, 1, 1, 5,
-        1, 1, 5, 1, 1, 10, 5, 10,
-        5, 10, 5, 10, 5, 1, 5, 3,
-        1, 4, 3, 1, 4, 3, 1, 4,
-        3, 1, 5, 1, 1, 5, 1, 1,
-        5, 1, 1, 5, 1, 1, 10, 5,
-        10, 5, 10, 5, 10, 5, 10, 10,
-        4, 1, 19, 11, 8, 7, 16, 11,
-        8, 7, 16, 11, 8, 7, 16, 11,
-        8, 7, 16, 11, 8, 7, 6, 6,
-        6, 1, 1, 1, 6, 8, 6, 8,
-        7, 6, 8, 7, 6, 8, 7, 6,
-        8, 7, 8, 11, 16, 16, 16, 8,
-        11, 16, 16, 16, 8, 11, 16, 16,
-        16, 8, 11, 16, 16, 16, 8, 11,
-        11, 8, 7, 16, 11, 8, 7, 16,
-        11, 8, 7, 16, 11, 8, 7, 16,
-        11, 8, 7, 6, 6, 6, 1, 1,
-        1, 6, 8, 6, 8, 7, 6, 8,
-        7, 6, 8, 7, 6, 8, 7, 8,
-        11, 16, 16, 16, 8, 11, 16, 16,
-        16, 8, 11, 16, 16, 16, 8, 11,
-        16, 16, 16, 5, 8, 8, 7, 16,
-        11, 8, 7, 16, 11, 8, 7, 16,
-        11, 8, 7, 16, 11, 8, 7, 6,
-        6, 6, 1, 1, 1, 6, 8, 6,
-        8, 7, 6, 8, 7, 6, 8, 7,
-        6, 8, 7, 8, 11, 16, 16, 16,
-        8, 11, 16, 16, 16, 8, 11, 16,
-        16, 16, 8, 11, 16, 16, 16, 10,
-        8, 5, 11, 8, 7, 16, 11, 8,
-        7, 16, 11, 8, 7, 16, 11, 8,
-        7, 16, 11, 8, 7, 6, 6, 6,
-        1, 1, 1, 6, 8, 6, 8, 7,
-        6, 8, 7, 6, 8, 7, 6, 8,
-        7, 8, 11, 16, 16, 16, 8, 11,
-        16, 16, 16, 8, 11, 16, 16, 16,
-        8, 11, 16, 16, 16, 8, 16, 11,
-        16, 10, 6, 1, 1, 1, 6, 16,
-        8, 6, 6, 1, 1, 1, 6, 16
+        1, 5, 3, 4, 5, 1, 1, 5,
+        10, 5, 1, 3, 4, 5, 1, 1,
+        5, 10, 10, 10, 1, 3, 4, 5,
+        1, 1, 5, 5, 10, 1, 3, 4,
+        5, 1, 1, 5, 5, 4, 1, 19,
+        15, 15, 14, 16, 6, 6, 1, 6,
+        16, 16, 16, 8, 7, 6, 7, 6,
+        8, 6, 15, 15, 15, 15, 14, 16,
+        15, 15, 14, 16, 6, 1, 6, 16,
+        16, 8, 7, 6, 7, 6, 6, 8,
+        6, 15, 15, 5, 15, 15, 14, 16,
+        15, 16, 6, 1, 6, 16, 16, 8,
+        7, 6, 15, 7, 6, 6, 8, 6,
+        15, 10, 5, 15, 15, 14, 16, 15,
+        16, 6, 1, 6, 16, 16, 8, 7,
+        6, 15, 7, 6, 6, 8, 6, 17,
+        15, 17, 10, 6, 1, 6, 16, 8,
+        6, 6, 1, 6, 16
 };
 
 static const short _indic_syllable_machine_index_offsets[] = {
-        0, 2, 8, 12, 14, 19, 23, 25,
-        30, 34, 36, 41, 45, 47, 53, 55,
-        57, 63, 65, 67, 73, 75, 77, 83,
-        85, 87, 98, 104, 115, 121, 132, 138,
-        149, 155, 166, 168, 174, 178, 180, 185,
-        189, 191, 196, 200, 202, 207, 211, 213,
-        219, 221, 223, 229, 231, 233, 239, 241,
-        243, 249, 251, 253, 264, 270, 281, 287,
-        298, 304, 315, 321, 332, 334, 340, 344,
-        346, 351, 355, 357, 362, 366, 368, 373,
-        377, 379, 385, 387, 389, 395, 397, 399,
-        405, 407, 409, 415, 417, 419, 430, 436,
-        447, 453, 464, 470, 481, 487, 489, 495,
-        499, 501, 506, 510, 512, 517, 521, 523,
-        528, 532, 534, 540, 542, 544, 550, 552,
-        554, 560, 562, 564, 570, 572, 574, 585,
-        591, 602, 608, 619, 625, 636, 642, 653,
-        664, 669, 671, 691, 703, 712, 720, 737,
-        749, 758, 766, 783, 795, 804, 812, 829,
-        841, 850, 858, 875, 887, 896, 904, 911,
-        918, 925, 927, 929, 931, 938, 947, 954,
-        963, 971, 978, 987, 995, 1002, 1011, 1019,
-        1026, 1035, 1043, 1052, 1064, 1081, 1098, 1115,
-        1124, 1136, 1153, 1170, 1187, 1196, 1208, 1225,
-        1242, 1259, 1268, 1280, 1297, 1314, 1331, 1340,
-        1352, 1364, 1373, 1381, 1398, 1410, 1419, 1427,
-        1444, 1456, 1465, 1473, 1490, 1502, 1511, 1519,
-        1536, 1548, 1557, 1565, 1572, 1579, 1586, 1588,
-        1590, 1592, 1599, 1608, 1615, 1624, 1632, 1639,
-        1648, 1656, 1663, 1672, 1680, 1687, 1696, 1704,
-        1713, 1725, 1742, 1759, 1776, 1785, 1797, 1814,
-        1831, 1848, 1857, 1869, 1886, 1903, 1920, 1929,
-        1941, 1958, 1975, 1992, 1998, 2007, 2016, 2024,
-        2041, 2053, 2062, 2070, 2087, 2099, 2108, 2116,
-        2133, 2145, 2154, 2162, 2179, 2191, 2200, 2208,
-        2215, 2222, 2229, 2231, 2233, 2235, 2242, 2251,
-        2258, 2267, 2275, 2282, 2291, 2299, 2306, 2315,
-        2323, 2330, 2339, 2347, 2356, 2368, 2385, 2402,
-        2419, 2428, 2440, 2457, 2474, 2491, 2500, 2512,
-        2529, 2546, 2563, 2572, 2584, 2601, 2618, 2635,
-        2646, 2655, 2661, 2673, 2682, 2690, 2707, 2719,
-        2728, 2736, 2753, 2765, 2774, 2782, 2799, 2811,
-        2820, 2828, 2845, 2857, 2866, 2874, 2881, 2888,
-        2895, 2897, 2899, 2901, 2908, 2917, 2924, 2933,
-        2941, 2948, 2957, 2965, 2972, 2981, 2989, 2996,
-        3005, 3013, 3022, 3034, 3051, 3068, 3085, 3094,
-        3106, 3123, 3140, 3157, 3166, 3178, 3195, 3212,
-        3229, 3238, 3250, 3267, 3284, 3301, 3310, 3327,
-        3339, 3356, 3367, 3374, 3376, 3378, 3380, 3387,
-        3404, 3413, 3420, 3427, 3429, 3431, 3433, 3440
+        0, 2, 8, 12, 17, 23, 25, 27,
+        33, 44, 50, 52, 56, 61, 67, 69,
+        71, 77, 88, 99, 110, 112, 116, 121,
+        127, 129, 131, 137, 143, 154, 156, 160,
+        165, 171, 173, 175, 181, 187, 192, 194,
+        214, 230, 246, 261, 278, 285, 292, 294,
+        301, 318, 335, 352, 361, 369, 376, 384,
+        391, 400, 407, 423, 439, 455, 471, 486,
+        503, 519, 535, 550, 567, 574, 576, 583,
+        600, 617, 626, 634, 641, 649, 656, 663,
+        672, 679, 695, 711, 717, 733, 749, 764,
+        781, 797, 814, 821, 823, 830, 847, 864,
+        873, 881, 888, 904, 912, 919, 926, 935,
+        942, 958, 969, 975, 991, 1007, 1022, 1039,
+        1055, 1072, 1079, 1081, 1088, 1105, 1122, 1131,
+        1139, 1146, 1162, 1170, 1177, 1184, 1193, 1200,
+        1218, 1234, 1252, 1263, 1270, 1272, 1279, 1296,
+        1305, 1312, 1319, 1321, 1328
 };
 
-static const short _indic_syllable_machine_indicies[] = {
+static const unsigned char _indic_syllable_machine_indicies[] = {
         1, 0, 2, 3, 3, 4, 1, 0,
-        5, 5, 4, 0, 4, 0, 6, 6,
-        7, 1, 0, 8, 8, 7, 0, 7,
-        0, 9, 9, 10, 1, 0, 11, 11,
-        10, 0, 10, 0, 12, 12, 13, 1,
-        0, 14, 14, 13, 0, 13, 0, 15,
-        0, 0, 0, 1, 0, 16, 0, 17,
-        0, 18, 12, 12, 13, 1, 0, 19,
-        0, 20, 0, 21, 9, 9, 10, 1,
-        0, 22, 0, 23, 0, 24, 6, 6,
-        7, 1, 0, 25, 0, 26, 0, 2,
-        3, 3, 4, 1, 0, 0, 0, 0,
-        27, 0, 28, 3, 3, 4, 1, 0,
-        28, 3, 3, 4, 1, 0, 0, 0,
-        0, 29, 0, 30, 3, 3, 4, 1,
-        0, 30, 3, 3, 4, 1, 0, 0,
-        0, 0, 31, 0, 32, 3, 3, 4,
-        1, 0, 32, 3, 3, 4, 1, 0,
-        0, 0, 0, 33, 0, 34, 3, 3,
-        4, 1, 0, 34, 3, 3, 4, 1,
-        0, 0, 0, 0, 35, 0, 37, 36,
-        38, 39, 39, 40, 37, 36, 41, 41,
-        40, 36, 40, 36, 42, 42, 43, 37,
-        36, 44, 44, 43, 36, 43, 36, 45,
-        45, 46, 37, 36, 47, 47, 46, 36,
-        46, 36, 48, 48, 49, 37, 36, 50,
-        50, 49, 36, 49, 36, 51, 36, 36,
-        36, 37, 36, 52, 36, 53, 36, 54,
-        48, 48, 49, 37, 36, 55, 36, 56,
-        36, 57, 45, 45, 46, 37, 36, 58,
-        36, 59, 36, 60, 42, 42, 43, 37,
-        36, 61, 36, 62, 36, 38, 39, 39,
-        40, 37, 36, 36, 36, 36, 63, 36,
-        64, 39, 39, 40, 37, 36, 64, 39,
-        39, 40, 37, 36, 36, 36, 36, 65,
-        36, 66, 39, 39, 40, 37, 36, 66,
-        39, 39, 40, 37, 36, 36, 36, 36,
-        67, 36, 68, 39, 39, 40, 37, 36,
-        68, 39, 39, 40, 37, 36, 36, 36,
-        36, 69, 36, 70, 39, 39, 40, 37,
-        36, 70, 39, 39, 40, 37, 36, 36,
-        36, 36, 71, 36, 73, 72, 74, 75,
-        75, 76, 73, 72, 78, 78, 76, 77,
-        76, 77, 79, 79, 80, 73, 72, 81,
-        81, 80, 72, 80, 72, 82, 82, 83,
-        73, 72, 84, 84, 83, 72, 83, 72,
-        85, 85, 86, 73, 72, 87, 87, 86,
-        72, 86, 72, 88, 72, 72, 72, 73,
-        72, 89, 72, 90, 72, 91, 85, 85,
-        86, 73, 72, 92, 72, 93, 72, 94,
-        82, 82, 83, 73, 72, 95, 72, 96,
-        72, 97, 79, 79, 80, 73, 72, 98,
-        72, 99, 72, 74, 75, 75, 76, 73,
-        72, 72, 72, 72, 100, 72, 101, 75,
-        75, 76, 73, 72, 101, 75, 75, 76,
-        73, 72, 72, 72, 72, 102, 72, 103,
-        75, 75, 76, 73, 72, 103, 75, 75,
-        76, 73, 72, 72, 72, 72, 104, 72,
-        105, 75, 75, 76, 73, 72, 105, 75,
-        75, 76, 73, 72, 72, 72, 72, 106,
-        72, 107, 75, 75, 76, 73, 72, 109,
-        108, 110, 111, 111, 112, 109, 108, 113,
-        113, 112, 108, 112, 108, 114, 114, 115,
-        109, 108, 116, 116, 115, 108, 115, 108,
-        117, 117, 118, 109, 108, 119, 119, 118,
-        108, 118, 108, 120, 120, 121, 109, 108,
-        122, 122, 121, 108, 121, 108, 123, 108,
-        108, 108, 109, 108, 124, 108, 125, 108,
-        126, 120, 120, 121, 109, 108, 127, 108,
-        128, 108, 129, 117, 117, 118, 109, 108,
-        130, 108, 131, 108, 132, 114, 114, 115,
-        109, 108, 133, 108, 134, 108, 110, 111,
-        111, 112, 109, 108, 108, 108, 108, 135,
-        108, 136, 111, 111, 112, 109, 108, 136,
-        111, 111, 112, 109, 108, 108, 108, 108,
-        137, 108, 138, 111, 111, 112, 109, 108,
-        138, 111, 111, 112, 109, 108, 108, 108,
-        108, 139, 108, 140, 111, 111, 112, 109,
-        108, 140, 111, 111, 112, 109, 108, 108,
-        108, 108, 141, 108, 142, 111, 111, 112,
-        109, 108, 142, 111, 111, 112, 109, 108,
-        108, 108, 108, 143, 108, 107, 75, 75,
-        76, 73, 72, 72, 72, 72, 144, 72,
-        78, 78, 76, 1, 0, 146, 145, 148,
-        149, 150, 151, 152, 153, 76, 73, 147,
-        154, 155, 155, 144, 147, 156, 157, 147,
-        158, 159, 147, 161, 162, 163, 164, 4,
-        1, 160, 165, 160, 160, 35, 160, 166,
-        162, 167, 167, 4, 1, 160, 165, 160,
-        162, 167, 167, 4, 1, 160, 165, 160,
-        168, 160, 160, 160, 17, 169, 160, 1,
-        160, 165, 160, 160, 160, 160, 160, 168,
-        160, 170, 171, 172, 173, 4, 1, 160,
-        165, 160, 160, 33, 160, 174, 171, 175,
-        175, 4, 1, 160, 165, 160, 171, 175,
-        175, 4, 1, 160, 165, 160, 176, 160,
-        160, 160, 17, 177, 160, 1, 160, 165,
-        160, 160, 160, 160, 160, 176, 160, 178,
-        179, 180, 181, 4, 1, 160, 165, 160,
-        160, 31, 160, 182, 179, 183, 183, 4,
-        1, 160, 165, 160, 179, 183, 183, 4,
-        1, 160, 165, 160, 184, 160, 160, 160,
-        17, 185, 160, 1, 160, 165, 160, 160,
-        160, 160, 160, 184, 160, 186, 187, 188,
-        189, 4, 1, 160, 165, 160, 160, 29,
-        160, 190, 187, 191, 191, 4, 1, 160,
-        165, 160, 187, 191, 191, 4, 1, 160,
-        165, 160, 192, 160, 160, 160, 17, 193,
-        160, 1, 160, 165, 160, 160, 160, 160,
-        160, 192, 160, 194, 195, 196, 197, 4,
-        1, 160, 165, 160, 160, 27, 160, 198,
-        195, 199, 199, 4, 1, 160, 165, 160,
-        195, 199, 199, 4, 1, 160, 165, 160,
-        17, 200, 160, 1, 160, 165, 160, 201,
-        201, 160, 1, 160, 165, 160, 202, 160,
-        160, 203, 160, 165, 160, 165, 160, 204,
-        160, 205, 160, 202, 160, 160, 160, 160,
-        165, 160, 17, 160, 201, 201, 160, 1,
-        160, 165, 160, 201, 200, 160, 1, 160,
-        165, 160, 206, 26, 207, 208, 7, 1,
-        160, 165, 160, 26, 207, 208, 7, 1,
-        160, 165, 160, 207, 207, 7, 1, 160,
-        165, 160, 209, 23, 210, 211, 10, 1,
-        160, 165, 160, 23, 210, 211, 10, 1,
-        160, 165, 160, 210, 210, 10, 1, 160,
-        165, 160, 212, 20, 213, 214, 13, 1,
-        160, 165, 160, 20, 213, 214, 13, 1,
-        160, 165, 160, 213, 213, 13, 1, 160,
-        165, 160, 215, 17, 201, 216, 160, 1,
-        160, 165, 160, 17, 201, 216, 160, 1,
-        160, 165, 160, 194, 195, 199, 199, 4,
-        1, 160, 165, 160, 194, 195, 196, 199,
-        4, 1, 160, 165, 160, 160, 27, 160,
-        192, 160, 217, 160, 201, 201, 160, 1,
-        160, 165, 160, 160, 160, 160, 160, 192,
-        160, 192, 160, 160, 160, 201, 201, 160,
-        1, 160, 165, 160, 160, 160, 160, 160,
-        192, 160, 192, 160, 160, 160, 201, 193,
-        160, 1, 160, 165, 160, 160, 160, 160,
-        160, 192, 160, 186, 187, 191, 191, 4,
-        1, 160, 165, 160, 186, 187, 188, 191,
-        4, 1, 160, 165, 160, 160, 29, 160,
-        184, 160, 218, 160, 201, 201, 160, 1,
-        160, 165, 160, 160, 160, 160, 160, 184,
-        160, 184, 160, 160, 160, 201, 201, 160,
-        1, 160, 165, 160, 160, 160, 160, 160,
-        184, 160, 184, 160, 160, 160, 201, 185,
-        160, 1, 160, 165, 160, 160, 160, 160,
-        160, 184, 160, 178, 179, 183, 183, 4,
-        1, 160, 165, 160, 178, 179, 180, 183,
-        4, 1, 160, 165, 160, 160, 31, 160,
-        176, 160, 219, 160, 201, 201, 160, 1,
-        160, 165, 160, 160, 160, 160, 160, 176,
-        160, 176, 160, 160, 160, 201, 201, 160,
-        1, 160, 165, 160, 160, 160, 160, 160,
-        176, 160, 176, 160, 160, 160, 201, 177,
-        160, 1, 160, 165, 160, 160, 160, 160,
-        160, 176, 160, 170, 171, 175, 175, 4,
-        1, 160, 165, 160, 170, 171, 172, 175,
-        4, 1, 160, 165, 160, 160, 33, 160,
-        168, 160, 220, 160, 201, 201, 160, 1,
-        160, 165, 160, 160, 160, 160, 160, 168,
-        160, 168, 160, 160, 160, 201, 201, 160,
-        1, 160, 165, 160, 160, 160, 160, 160,
-        168, 160, 168, 160, 160, 160, 201, 169,
-        160, 1, 160, 165, 160, 160, 160, 160,
-        160, 168, 160, 161, 162, 167, 167, 4,
-        1, 160, 165, 160, 161, 162, 163, 167,
-        4, 1, 160, 165, 160, 160, 35, 160,
-        222, 223, 224, 225, 40, 37, 221, 226,
-        221, 221, 71, 221, 227, 223, 228, 225,
-        40, 37, 221, 226, 221, 223, 228, 225,
-        40, 37, 221, 226, 221, 229, 221, 221,
-        221, 53, 230, 221, 37, 221, 226, 221,
-        221, 221, 221, 221, 229, 221, 231, 232,
-        233, 234, 40, 37, 221, 226, 221, 221,
-        69, 221, 235, 232, 236, 236, 40, 37,
-        221, 226, 221, 232, 236, 236, 40, 37,
-        221, 226, 221, 237, 221, 221, 221, 53,
-        238, 221, 37, 221, 226, 221, 221, 221,
-        221, 221, 237, 221, 239, 240, 241, 242,
-        40, 37, 221, 226, 221, 221, 67, 221,
-        243, 240, 244, 244, 40, 37, 221, 226,
-        221, 240, 244, 244, 40, 37, 221, 226,
-        221, 245, 221, 221, 221, 53, 246, 221,
-        37, 221, 226, 221, 221, 221, 221, 221,
-        245, 221, 247, 248, 249, 250, 40, 37,
-        221, 226, 221, 221, 65, 221, 251, 248,
-        252, 252, 40, 37, 221, 226, 221, 248,
-        252, 252, 40, 37, 221, 226, 221, 253,
-        221, 221, 221, 53, 254, 221, 37, 221,
-        226, 221, 221, 221, 221, 221, 253, 221,
-        255, 256, 257, 258, 40, 37, 221, 226,
-        221, 221, 63, 221, 259, 256, 260, 260,
-        40, 37, 221, 226, 221, 256, 260, 260,
-        40, 37, 221, 226, 221, 53, 261, 221,
-        37, 221, 226, 221, 262, 262, 221, 37,
-        221, 226, 221, 263, 221, 221, 264, 221,
-        226, 221, 226, 221, 265, 221, 266, 221,
-        263, 221, 221, 221, 221, 226, 221, 53,
-        221, 262, 262, 221, 37, 221, 226, 221,
-        262, 261, 221, 37, 221, 226, 221, 267,
-        62, 268, 269, 43, 37, 221, 226, 221,
-        62, 268, 269, 43, 37, 221, 226, 221,
-        268, 268, 43, 37, 221, 226, 221, 270,
-        59, 271, 272, 46, 37, 221, 226, 221,
-        59, 271, 272, 46, 37, 221, 226, 221,
-        271, 271, 46, 37, 221, 226, 221, 273,
-        56, 274, 275, 49, 37, 221, 226, 221,
-        56, 274, 275, 49, 37, 221, 226, 221,
-        274, 274, 49, 37, 221, 226, 221, 276,
-        53, 262, 277, 221, 37, 221, 226, 221,
-        53, 262, 277, 221, 37, 221, 226, 221,
-        255, 256, 260, 260, 40, 37, 221, 226,
-        221, 255, 256, 257, 260, 40, 37, 221,
-        226, 221, 221, 63, 221, 253, 221, 278,
-        221, 262, 262, 221, 37, 221, 226, 221,
-        221, 221, 221, 221, 253, 221, 253, 221,
-        221, 221, 262, 262, 221, 37, 221, 226,
-        221, 221, 221, 221, 221, 253, 221, 253,
-        221, 221, 221, 262, 254, 221, 37, 221,
-        226, 221, 221, 221, 221, 221, 253, 221,
-        247, 248, 252, 252, 40, 37, 221, 226,
-        221, 247, 248, 249, 252, 40, 37, 221,
-        226, 221, 221, 65, 221, 245, 221, 279,
-        221, 262, 262, 221, 37, 221, 226, 221,
-        221, 221, 221, 221, 245, 221, 245, 221,
-        221, 221, 262, 262, 221, 37, 221, 226,
-        221, 221, 221, 221, 221, 245, 221, 245,
-        221, 221, 221, 262, 246, 221, 37, 221,
-        226, 221, 221, 221, 221, 221, 245, 221,
-        239, 240, 244, 244, 40, 37, 221, 226,
-        221, 239, 240, 241, 244, 40, 37, 221,
-        226, 221, 221, 67, 221, 237, 221, 280,
-        221, 262, 262, 221, 37, 221, 226, 221,
-        221, 221, 221, 221, 237, 221, 237, 221,
-        221, 221, 262, 262, 221, 37, 221, 226,
-        221, 221, 221, 221, 221, 237, 221, 237,
-        221, 221, 221, 262, 238, 221, 37, 221,
-        226, 221, 221, 221, 221, 221, 237, 221,
-        231, 232, 236, 236, 40, 37, 221, 226,
-        221, 231, 232, 233, 236, 40, 37, 221,
-        226, 221, 221, 69, 221, 229, 221, 281,
-        221, 262, 262, 221, 37, 221, 226, 221,
-        221, 221, 221, 221, 229, 221, 229, 221,
-        221, 221, 262, 262, 221, 37, 221, 226,
-        221, 221, 221, 221, 221, 229, 221, 229,
-        221, 221, 221, 262, 230, 221, 37, 221,
-        226, 221, 221, 221, 221, 221, 229, 221,
-        70, 39, 39, 40, 37, 221, 222, 223,
-        228, 225, 40, 37, 221, 226, 221, 283,
-        151, 284, 284, 76, 73, 282, 154, 282,
-        151, 284, 284, 76, 73, 282, 154, 282,
-        285, 282, 282, 282, 90, 286, 282, 73,
-        282, 154, 282, 282, 282, 282, 282, 285,
-        282, 287, 288, 289, 290, 76, 73, 282,
-        154, 282, 282, 106, 282, 291, 288, 292,
-        292, 76, 73, 282, 154, 282, 288, 292,
-        292, 76, 73, 282, 154, 282, 293, 282,
-        282, 282, 90, 294, 282, 73, 282, 154,
-        282, 282, 282, 282, 282, 293, 282, 295,
-        296, 297, 298, 76, 73, 282, 154, 282,
-        282, 104, 282, 299, 296, 300, 300, 76,
-        73, 282, 154, 282, 296, 300, 300, 76,
-        73, 282, 154, 282, 301, 282, 282, 282,
-        90, 302, 282, 73, 282, 154, 282, 282,
-        282, 282, 282, 301, 282, 303, 304, 305,
-        306, 76, 73, 282, 154, 282, 282, 102,
-        282, 307, 304, 308, 308, 76, 73, 282,
-        154, 282, 304, 308, 308, 76, 73, 282,
-        154, 282, 309, 282, 282, 282, 90, 310,
-        282, 73, 282, 154, 282, 282, 282, 282,
-        282, 309, 282, 311, 312, 313, 314, 76,
-        73, 282, 154, 282, 282, 100, 282, 315,
-        312, 316, 316, 76, 73, 282, 154, 282,
-        312, 316, 316, 76, 73, 282, 154, 282,
-        90, 317, 282, 73, 282, 154, 282, 318,
-        318, 282, 73, 282, 154, 282, 319, 282,
-        282, 320, 282, 154, 282, 154, 282, 321,
-        282, 322, 282, 319, 282, 282, 282, 282,
-        154, 282, 90, 282, 318, 318, 282, 73,
-        282, 154, 282, 318, 317, 282, 73, 282,
-        154, 282, 323, 99, 324, 325, 80, 73,
-        282, 154, 282, 99, 324, 325, 80, 73,
-        282, 154, 282, 324, 324, 80, 73, 282,
-        154, 282, 326, 96, 327, 328, 83, 73,
-        282, 154, 282, 96, 327, 328, 83, 73,
-        282, 154, 282, 327, 327, 83, 73, 282,
-        154, 282, 329, 93, 330, 331, 86, 73,
-        282, 154, 282, 93, 330, 331, 86, 73,
-        282, 154, 282, 330, 330, 86, 73, 282,
-        154, 282, 332, 90, 318, 333, 282, 73,
-        282, 154, 282, 90, 318, 333, 282, 73,
-        282, 154, 282, 311, 312, 316, 316, 76,
-        73, 282, 154, 282, 311, 312, 313, 316,
-        76, 73, 282, 154, 282, 282, 100, 282,
-        309, 282, 334, 282, 318, 318, 282, 73,
-        282, 154, 282, 282, 282, 282, 282, 309,
-        282, 309, 282, 282, 282, 318, 318, 282,
-        73, 282, 154, 282, 282, 282, 282, 282,
-        309, 282, 309, 282, 282, 282, 318, 310,
-        282, 73, 282, 154, 282, 282, 282, 282,
-        282, 309, 282, 303, 304, 308, 308, 76,
-        73, 282, 154, 282, 303, 304, 305, 308,
-        76, 73, 282, 154, 282, 282, 102, 282,
-        301, 282, 335, 282, 318, 318, 282, 73,
-        282, 154, 282, 282, 282, 282, 282, 301,
-        282, 301, 282, 282, 282, 318, 318, 282,
-        73, 282, 154, 282, 282, 282, 282, 282,
-        301, 282, 301, 282, 282, 282, 318, 302,
-        282, 73, 282, 154, 282, 282, 282, 282,
-        282, 301, 282, 295, 296, 300, 300, 76,
-        73, 282, 154, 282, 295, 296, 297, 300,
-        76, 73, 282, 154, 282, 282, 104, 282,
-        293, 282, 336, 282, 318, 318, 282, 73,
-        282, 154, 282, 282, 282, 282, 282, 293,
-        282, 293, 282, 282, 282, 318, 318, 282,
-        73, 282, 154, 282, 282, 282, 282, 282,
-        293, 282, 293, 282, 282, 282, 318, 294,
-        282, 73, 282, 154, 282, 282, 282, 282,
-        282, 293, 282, 287, 288, 292, 292, 76,
-        73, 282, 154, 282, 287, 288, 289, 292,
-        76, 73, 282, 154, 282, 282, 106, 282,
-        285, 282, 337, 282, 318, 318, 282, 73,
-        282, 154, 282, 282, 282, 282, 282, 285,
-        282, 285, 282, 282, 282, 318, 318, 282,
-        73, 282, 154, 282, 282, 282, 282, 282,
-        285, 282, 285, 282, 282, 282, 318, 286,
-        282, 73, 282, 154, 282, 282, 282, 282,
-        282, 285, 282, 107, 75, 75, 76, 73,
-        338, 338, 338, 338, 144, 338, 150, 151,
-        284, 284, 76, 73, 282, 154, 282, 107,
-        75, 75, 76, 73, 338, 340, 341, 342,
-        343, 112, 109, 339, 344, 339, 339, 143,
-        339, 345, 341, 343, 343, 112, 109, 339,
-        344, 339, 341, 343, 343, 112, 109, 339,
-        344, 339, 346, 339, 339, 339, 125, 347,
-        339, 109, 339, 344, 339, 339, 339, 339,
-        339, 346, 339, 348, 349, 350, 351, 112,
-        109, 339, 344, 339, 339, 141, 339, 352,
-        349, 353, 353, 112, 109, 339, 344, 339,
-        349, 353, 353, 112, 109, 339, 344, 339,
-        354, 339, 339, 339, 125, 355, 339, 109,
-        339, 344, 339, 339, 339, 339, 339, 354,
-        339, 356, 357, 358, 359, 112, 109, 339,
-        344, 339, 339, 139, 339, 360, 357, 361,
-        361, 112, 109, 339, 344, 339, 357, 361,
-        361, 112, 109, 339, 344, 339, 362, 339,
-        339, 339, 125, 363, 339, 109, 339, 344,
-        339, 339, 339, 339, 339, 362, 339, 364,
-        365, 366, 367, 112, 109, 339, 344, 339,
-        339, 137, 339, 368, 365, 369, 369, 112,
-        109, 339, 344, 339, 365, 369, 369, 112,
-        109, 339, 344, 339, 370, 339, 339, 339,
-        125, 371, 339, 109, 339, 344, 339, 339,
-        339, 339, 339, 370, 339, 372, 373, 374,
-        375, 112, 109, 339, 344, 339, 339, 135,
-        339, 376, 373, 377, 377, 112, 109, 339,
-        344, 339, 373, 377, 377, 112, 109, 339,
-        344, 339, 125, 378, 339, 109, 339, 344,
-        339, 379, 379, 339, 109, 339, 344, 339,
-        380, 339, 339, 381, 339, 344, 339, 344,
-        339, 382, 339, 383, 339, 380, 339, 339,
-        339, 339, 344, 339, 125, 339, 379, 379,
-        339, 109, 339, 344, 339, 379, 378, 339,
-        109, 339, 344, 339, 384, 134, 385, 386,
-        115, 109, 339, 344, 339, 134, 385, 386,
-        115, 109, 339, 344, 339, 385, 385, 115,
-        109, 339, 344, 339, 387, 131, 388, 389,
-        118, 109, 339, 344, 339, 131, 388, 389,
-        118, 109, 339, 344, 339, 388, 388, 118,
-        109, 339, 344, 339, 390, 128, 391, 392,
-        121, 109, 339, 344, 339, 128, 391, 392,
-        121, 109, 339, 344, 339, 391, 391, 121,
-        109, 339, 344, 339, 393, 125, 379, 394,
-        339, 109, 339, 344, 339, 125, 379, 394,
-        339, 109, 339, 344, 339, 372, 373, 377,
-        377, 112, 109, 339, 344, 339, 372, 373,
-        374, 377, 112, 109, 339, 344, 339, 339,
-        135, 339, 370, 339, 395, 339, 379, 379,
-        339, 109, 339, 344, 339, 339, 339, 339,
-        339, 370, 339, 370, 339, 339, 339, 379,
-        379, 339, 109, 339, 344, 339, 339, 339,
-        339, 339, 370, 339, 370, 339, 339, 339,
-        379, 371, 339, 109, 339, 344, 339, 339,
-        339, 339, 339, 370, 339, 364, 365, 369,
-        369, 112, 109, 339, 344, 339, 364, 365,
-        366, 369, 112, 109, 339, 344, 339, 339,
-        137, 339, 362, 339, 396, 339, 379, 379,
-        339, 109, 339, 344, 339, 339, 339, 339,
-        339, 362, 339, 362, 339, 339, 339, 379,
-        379, 339, 109, 339, 344, 339, 339, 339,
-        339, 339, 362, 339, 362, 339, 339, 339,
-        379, 363, 339, 109, 339, 344, 339, 339,
-        339, 339, 339, 362, 339, 356, 357, 361,
-        361, 112, 109, 339, 344, 339, 356, 357,
-        358, 361, 112, 109, 339, 344, 339, 339,
-        139, 339, 354, 339, 397, 339, 379, 379,
-        339, 109, 339, 344, 339, 339, 339, 339,
-        339, 354, 339, 354, 339, 339, 339, 379,
-        379, 339, 109, 339, 344, 339, 339, 339,
-        339, 339, 354, 339, 354, 339, 339, 339,
-        379, 355, 339, 109, 339, 344, 339, 339,
-        339, 339, 339, 354, 339, 348, 349, 353,
-        353, 112, 109, 339, 344, 339, 348, 349,
-        350, 353, 112, 109, 339, 344, 339, 339,
-        141, 339, 346, 339, 398, 339, 379, 379,
-        339, 109, 339, 344, 339, 339, 339, 339,
-        339, 346, 339, 346, 339, 339, 339, 379,
-        379, 339, 109, 339, 344, 339, 339, 339,
-        339, 339, 346, 339, 346, 339, 339, 339,
-        379, 347, 339, 109, 339, 344, 339, 339,
-        339, 339, 339, 346, 339, 340, 341, 343,
-        343, 112, 109, 339, 344, 339, 148, 149,
-        150, 151, 399, 284, 76, 73, 282, 154,
-        155, 155, 144, 282, 282, 148, 282, 161,
-        400, 163, 164, 4, 1, 160, 165, 160,
-        160, 35, 160, 168, 149, 150, 151, 401,
-        402, 76, 403, 160, 404, 160, 155, 144,
-        160, 160, 168, 160, 107, 405, 405, 76,
-        403, 160, 165, 160, 160, 144, 160, 406,
-        160, 160, 407, 160, 404, 160, 404, 160,
-        408, 160, 205, 160, 406, 160, 160, 160,
-        160, 404, 160, 168, 160, 220, 107, 405,
-        405, 76, 403, 160, 165, 160, 160, 160,
-        160, 160, 168, 160, 410, 409, 411, 411,
-        409, 146, 409, 412, 409, 411, 411, 409,
-        146, 409, 412, 409, 413, 409, 409, 414,
-        409, 412, 409, 412, 409, 415, 409, 416,
-        409, 413, 409, 409, 409, 409, 412, 409,
-        148, 338, 338, 338, 338, 338, 338, 338,
-        338, 338, 155, 338, 338, 338, 338, 148,
-        338, 0
+        3, 3, 4, 0, 3, 3, 4, 1,
+        0, 5, 3, 3, 4, 1, 0, 6,
+        0, 7, 0, 8, 3, 3, 4, 1,
+        0, 2, 3, 3, 4, 1, 0, 0,
+        0, 0, 9, 0, 11, 12, 12, 13,
+        14, 10, 14, 10, 12, 12, 13, 10,
+        12, 12, 13, 14, 10, 15, 12, 12,
+        13, 14, 10, 16, 10, 17, 10, 18,
+        12, 12, 13, 14, 10, 11, 12, 12,
+        13, 14, 10, 10, 10, 10, 19, 10,
+        11, 12, 12, 13, 14, 10, 10, 10,
+        10, 20, 10, 22, 23, 23, 24, 25,
+        21, 21, 21, 21, 26, 21, 25, 21,
+        23, 23, 24, 27, 23, 23, 24, 25,
+        21, 28, 23, 23, 24, 25, 21, 29,
+        21, 30, 21, 22, 23, 23, 24, 25,
+        21, 31, 23, 23, 24, 25, 21, 33,
+        34, 34, 35, 36, 32, 32, 32, 32,
+        37, 32, 36, 32, 34, 34, 35, 32,
+        34, 34, 35, 36, 32, 38, 34, 34,
+        35, 36, 32, 39, 32, 40, 32, 33,
+        34, 34, 35, 36, 32, 41, 34, 34,
+        35, 36, 32, 23, 23, 24, 1, 0,
+        43, 42, 45, 46, 47, 48, 49, 50,
+        24, 25, 44, 51, 52, 52, 26, 44,
+        53, 54, 55, 56, 57, 44, 59, 60,
+        61, 62, 4, 1, 58, 63, 58, 58,
+        9, 58, 58, 58, 64, 58, 65, 60,
+        66, 66, 4, 1, 58, 63, 58, 58,
+        58, 58, 58, 58, 64, 58, 60, 66,
+        66, 4, 1, 58, 63, 58, 58, 58,
+        58, 58, 58, 64, 58, 45, 58, 58,
+        58, 67, 68, 58, 1, 58, 63, 58,
+        58, 58, 58, 58, 45, 58, 69, 69,
+        58, 1, 58, 63, 58, 63, 58, 58,
+        70, 58, 63, 58, 63, 58, 63, 58,
+        58, 58, 58, 63, 58, 45, 58, 71,
+        58, 69, 69, 58, 1, 58, 63, 58,
+        58, 58, 58, 58, 45, 58, 45, 58,
+        58, 58, 69, 69, 58, 1, 58, 63,
+        58, 58, 58, 58, 58, 45, 58, 45,
+        58, 58, 58, 69, 68, 58, 1, 58,
+        63, 58, 58, 58, 58, 58, 45, 58,
+        72, 7, 73, 74, 4, 1, 58, 63,
+        58, 7, 73, 74, 4, 1, 58, 63,
+        58, 73, 73, 4, 1, 58, 63, 58,
+        75, 76, 76, 4, 1, 58, 63, 58,
+        67, 77, 58, 1, 58, 63, 58, 67,
+        58, 69, 69, 58, 1, 58, 63, 58,
+        69, 77, 58, 1, 58, 63, 58, 59,
+        60, 66, 66, 4, 1, 58, 63, 58,
+        58, 58, 58, 58, 58, 64, 58, 59,
+        60, 61, 66, 4, 1, 58, 63, 58,
+        58, 9, 58, 58, 58, 64, 58, 79,
+        80, 81, 82, 13, 14, 78, 83, 78,
+        78, 20, 78, 78, 78, 84, 78, 85,
+        80, 86, 82, 13, 14, 78, 83, 78,
+        78, 78, 78, 78, 78, 84, 78, 80,
+        86, 82, 13, 14, 78, 83, 78, 78,
+        78, 78, 78, 78, 84, 78, 87, 78,
+        78, 78, 88, 89, 78, 14, 78, 83,
+        78, 78, 78, 78, 78, 87, 78, 90,
+        80, 91, 92, 13, 14, 78, 83, 78,
+        78, 19, 78, 78, 78, 84, 78, 93,
+        80, 86, 86, 13, 14, 78, 83, 78,
+        78, 78, 78, 78, 78, 84, 78, 80,
+        86, 86, 13, 14, 78, 83, 78, 78,
+        78, 78, 78, 78, 84, 78, 87, 78,
+        78, 78, 94, 89, 78, 14, 78, 83,
+        78, 78, 78, 78, 78, 87, 78, 83,
+        78, 78, 95, 78, 83, 78, 83, 78,
+        83, 78, 78, 78, 78, 83, 78, 87,
+        78, 96, 78, 94, 94, 78, 14, 78,
+        83, 78, 78, 78, 78, 78, 87, 78,
+        87, 78, 78, 78, 94, 94, 78, 14,
+        78, 83, 78, 78, 78, 78, 78, 87,
+        78, 97, 17, 98, 99, 13, 14, 78,
+        83, 78, 17, 98, 99, 13, 14, 78,
+        83, 78, 98, 98, 13, 14, 78, 83,
+        78, 100, 101, 101, 13, 14, 78, 83,
+        78, 88, 102, 78, 14, 78, 83, 78,
+        94, 94, 78, 14, 78, 83, 78, 88,
+        78, 94, 94, 78, 14, 78, 83, 78,
+        94, 102, 78, 14, 78, 83, 78, 90,
+        80, 86, 86, 13, 14, 78, 83, 78,
+        78, 78, 78, 78, 78, 84, 78, 90,
+        80, 91, 86, 13, 14, 78, 83, 78,
+        78, 19, 78, 78, 78, 84, 78, 11,
+        12, 12, 13, 14, 78, 79, 80, 86,
+        82, 13, 14, 78, 83, 78, 78, 78,
+        78, 78, 78, 84, 78, 104, 48, 105,
+        105, 24, 25, 103, 51, 103, 103, 103,
+        103, 103, 103, 55, 103, 48, 105, 105,
+        24, 25, 103, 51, 103, 103, 103, 103,
+        103, 103, 55, 103, 106, 103, 103, 103,
+        107, 108, 103, 25, 103, 51, 103, 103,
+        103, 103, 103, 106, 103, 47, 48, 109,
+        110, 24, 25, 103, 51, 103, 103, 26,
+        103, 103, 103, 55, 103, 106, 103, 103,
+        103, 111, 108, 103, 25, 103, 51, 103,
+        103, 103, 103, 103, 106, 103, 51, 103,
+        103, 112, 103, 51, 103, 51, 103, 51,
+        103, 103, 103, 103, 51, 103, 106, 103,
+        113, 103, 111, 111, 103, 25, 103, 51,
+        103, 103, 103, 103, 103, 106, 103, 106,
+        103, 103, 103, 111, 111, 103, 25, 103,
+        51, 103, 103, 103, 103, 103, 106, 103,
+        114, 30, 115, 116, 24, 25, 103, 51,
+        103, 30, 115, 116, 24, 25, 103, 51,
+        103, 115, 115, 24, 25, 103, 51, 103,
+        47, 48, 105, 105, 24, 25, 103, 51,
+        103, 103, 103, 103, 103, 103, 55, 103,
+        117, 118, 118, 24, 25, 103, 51, 103,
+        107, 119, 103, 25, 103, 51, 103, 111,
+        111, 103, 25, 103, 51, 103, 107, 103,
+        111, 111, 103, 25, 103, 51, 103, 111,
+        119, 103, 25, 103, 51, 103, 47, 48,
+        109, 105, 24, 25, 103, 51, 103, 103,
+        26, 103, 103, 103, 55, 103, 22, 23,
+        23, 24, 25, 120, 120, 120, 120, 26,
+        120, 22, 23, 23, 24, 25, 120, 122,
+        123, 124, 125, 35, 36, 121, 126, 121,
+        121, 37, 121, 121, 121, 127, 121, 128,
+        123, 125, 125, 35, 36, 121, 126, 121,
+        121, 121, 121, 121, 121, 127, 121, 123,
+        125, 125, 35, 36, 121, 126, 121, 121,
+        121, 121, 121, 121, 127, 121, 129, 121,
+        121, 121, 130, 131, 121, 36, 121, 126,
+        121, 121, 121, 121, 121, 129, 121, 122,
+        123, 124, 52, 35, 36, 121, 126, 121,
+        121, 37, 121, 121, 121, 127, 121, 129,
+        121, 121, 121, 132, 131, 121, 36, 121,
+        126, 121, 121, 121, 121, 121, 129, 121,
+        126, 121, 121, 133, 121, 126, 121, 126,
+        121, 126, 121, 121, 121, 121, 126, 121,
+        129, 121, 134, 121, 132, 132, 121, 36,
+        121, 126, 121, 121, 121, 121, 121, 129,
+        121, 129, 121, 121, 121, 132, 132, 121,
+        36, 121, 126, 121, 121, 121, 121, 121,
+        129, 121, 135, 40, 136, 137, 35, 36,
+        121, 126, 121, 40, 136, 137, 35, 36,
+        121, 126, 121, 136, 136, 35, 36, 121,
+        126, 121, 122, 123, 125, 125, 35, 36,
+        121, 126, 121, 121, 121, 121, 121, 121,
+        127, 121, 138, 139, 139, 35, 36, 121,
+        126, 121, 130, 140, 121, 36, 121, 126,
+        121, 132, 132, 121, 36, 121, 126, 121,
+        130, 121, 132, 132, 121, 36, 121, 126,
+        121, 132, 140, 121, 36, 121, 126, 121,
+        45, 46, 47, 48, 109, 105, 24, 25,
+        103, 51, 52, 52, 26, 103, 103, 45,
+        55, 103, 59, 141, 61, 62, 4, 1,
+        58, 63, 58, 58, 9, 58, 58, 58,
+        64, 58, 45, 46, 47, 48, 142, 143,
+        24, 144, 58, 145, 58, 52, 26, 58,
+        58, 45, 55, 58, 22, 146, 146, 24,
+        144, 58, 63, 58, 58, 26, 58, 145,
+        58, 58, 147, 58, 145, 58, 145, 58,
+        145, 58, 58, 58, 58, 145, 58, 45,
+        58, 71, 22, 146, 146, 24, 144, 58,
+        63, 58, 58, 58, 58, 58, 45, 58,
+        149, 148, 150, 150, 148, 43, 148, 151,
+        148, 150, 150, 148, 43, 148, 151, 148,
+        151, 148, 148, 152, 148, 151, 148, 151,
+        148, 151, 148, 148, 148, 148, 151, 148,
+        45, 120, 120, 120, 120, 120, 120, 120,
+        120, 120, 52, 120, 120, 120, 120, 45,
+        120, 0
 };
 
-static const short _indic_syllable_machine_trans_targs[] = {
-        138, 160, 166, 2, 167, 3, 5, 170,
-        6, 8, 173, 9, 11, 176, 12, 14,
-        15, 159, 17, 18, 175, 20, 21, 172,
-        23, 24, 169, 178, 182, 183, 187, 188,
-        192, 193, 197, 198, 138, 221, 227, 36,
-        228, 37, 39, 231, 40, 42, 234, 43,
-        45, 237, 46, 48, 49, 220, 51, 52,
-        236, 54, 55, 233, 57, 58, 230, 239,
-        243, 244, 248, 249, 253, 254, 258, 260,
-        138, 281, 287, 70, 288, 138, 71, 73,
-        291, 74, 76, 294, 77, 79, 297, 80,
-        82, 83, 280, 85, 86, 296, 88, 89,
-        293, 91, 92, 290, 299, 303, 304, 308,
-        309, 313, 314, 318, 138, 343, 349, 103,
-        350, 104, 106, 353, 107, 109, 356, 110,
-        112, 359, 113, 115, 116, 342, 118, 119,
-        358, 121, 122, 355, 124, 125, 352, 361,
-        365, 366, 370, 371, 375, 376, 380, 381,
-        320, 138, 394, 138, 139, 200, 261, 263,
-        319, 321, 283, 322, 382, 383, 392, 399,
-        138, 140, 142, 33, 199, 162, 141, 32,
-        143, 195, 144, 146, 31, 194, 145, 30,
-        147, 190, 148, 150, 29, 189, 149, 28,
-        151, 185, 152, 154, 27, 184, 153, 26,
-        155, 180, 156, 158, 25, 179, 157, 1,
-        165, 0, 161, 164, 163, 138, 168, 4,
-        22, 171, 7, 19, 174, 10, 16, 177,
-        13, 181, 186, 191, 196, 138, 201, 203,
-        67, 259, 223, 202, 66, 204, 256, 205,
-        207, 65, 255, 206, 64, 208, 251, 209,
-        211, 63, 250, 210, 62, 212, 246, 213,
-        215, 61, 245, 214, 60, 216, 241, 217,
-        219, 59, 240, 218, 35, 226, 34, 222,
-        225, 224, 138, 229, 38, 56, 232, 41,
-        53, 235, 44, 50, 238, 47, 242, 247,
-        252, 257, 138, 262, 100, 264, 316, 265,
-        267, 99, 315, 266, 98, 268, 311, 269,
-        271, 97, 310, 270, 96, 272, 306, 273,
-        275, 95, 305, 274, 94, 276, 301, 277,
-        279, 93, 300, 278, 69, 286, 68, 282,
-        285, 284, 138, 289, 72, 90, 292, 75,
-        87, 295, 78, 84, 298, 81, 302, 307,
-        312, 317, 138, 138, 323, 325, 134, 133,
-        345, 324, 326, 378, 327, 329, 132, 377,
-        328, 131, 330, 373, 331, 333, 130, 372,
-        332, 129, 334, 368, 335, 337, 128, 367,
-        336, 127, 338, 363, 339, 341, 126, 362,
-        340, 102, 348, 101, 344, 347, 346, 138,
-        351, 105, 123, 354, 108, 120, 357, 111,
-        117, 360, 114, 364, 369, 374, 379, 135,
-        384, 385, 391, 386, 388, 136, 387, 390,
-        389, 138, 393, 137, 396, 395, 398, 397,
-        138
+static const unsigned char _indic_syllable_machine_trans_targs[] = {
+        39, 45, 50, 2, 51, 5, 6, 53,
+        57, 58, 39, 67, 11, 73, 68, 14,
+        15, 75, 80, 81, 84, 39, 89, 21,
+        95, 90, 98, 39, 24, 25, 97, 103,
+        39, 112, 30, 118, 113, 121, 33, 34,
+        120, 126, 39, 137, 39, 40, 60, 85,
+        87, 105, 106, 91, 107, 127, 128, 99,
+        135, 140, 39, 41, 43, 8, 59, 46,
+        54, 42, 1, 44, 48, 0, 47, 49,
+        52, 3, 4, 55, 7, 56, 39, 61,
+        63, 18, 83, 69, 76, 62, 9, 64,
+        78, 71, 65, 17, 82, 66, 10, 70,
+        72, 74, 12, 13, 77, 16, 79, 39,
+        86, 26, 88, 101, 93, 19, 104, 20,
+        92, 94, 96, 22, 23, 100, 27, 102,
+        39, 39, 108, 110, 28, 35, 114, 122,
+        109, 111, 124, 116, 29, 115, 117, 119,
+        31, 32, 123, 36, 125, 129, 130, 134,
+        131, 132, 37, 133, 39, 136, 38, 138,
+        139
 };
 
 static const char _indic_syllable_machine_trans_actions[] = {
         1, 0, 2, 0, 2, 0, 0, 2,
-        0, 0, 2, 0, 0, 2, 0, 0,
-        0, 2, 0, 0, 2, 0, 0, 2,
-        0, 0, 2, 2, 2, 2, 2, 2,
-        2, 2, 2, 2, 3, 0, 2, 0,
-        2, 0, 0, 2, 0, 0, 2, 0,
-        0, 2, 0, 0, 0, 2, 0, 0,
-        2, 0, 0, 2, 0, 0, 2, 2,
-        2, 2, 2, 2, 2, 2, 2, 2,
-        4, 0, 2, 0, 2, 5, 0, 0,
-        2, 0, 0, 2, 0, 0, 2, 0,
-        0, 0, 2, 0, 0, 2, 0, 0,
-        2, 0, 0, 2, 6, 2, 6, 2,
-        6, 2, 6, 2, 7, 0, 2, 0,
-        2, 0, 0, 2, 0, 0, 2, 0,
-        0, 2, 0, 0, 0, 2, 0, 0,
-        2, 0, 0, 2, 0, 0, 2, 2,
-        2, 2, 2, 2, 2, 2, 2, 2,
-        6, 8, 0, 11, 2, 2, 6, 0,
-        12, 12, 0, 2, 6, 2, 2, 0,
-        13, 2, 0, 0, 2, 0, 2, 0,
-        2, 2, 2, 0, 0, 2, 2, 0,
-        2, 2, 2, 0, 0, 2, 2, 0,
-        2, 2, 2, 0, 0, 2, 2, 0,
-        2, 2, 2, 0, 0, 2, 2, 0,
-        2, 0, 0, 0, 0, 14, 2, 0,
-        0, 2, 0, 0, 2, 0, 0, 2,
-        0, 2, 2, 2, 2, 15, 2, 0,
-        0, 2, 0, 2, 0, 2, 2, 2,
-        0, 0, 2, 2, 0, 2, 2, 2,
-        0, 0, 2, 2, 0, 2, 2, 2,
-        0, 0, 2, 2, 0, 2, 2, 2,
-        0, 0, 2, 2, 0, 2, 0, 0,
-        0, 0, 16, 2, 0, 0, 2, 0,
-        0, 2, 0, 0, 2, 0, 2, 2,
-        2, 2, 17, 6, 0, 6, 2, 6,
-        0, 0, 6, 6, 0, 6, 2, 6,
-        0, 0, 6, 6, 0, 6, 2, 6,
-        0, 0, 6, 6, 0, 6, 2, 6,
-        0, 0, 6, 6, 0, 2, 0, 0,
-        0, 0, 18, 2, 0, 0, 2, 0,
-        0, 2, 0, 0, 2, 0, 2, 2,
-        2, 2, 19, 20, 2, 0, 0, 0,
-        0, 2, 2, 2, 2, 0, 0, 2,
-        2, 0, 2, 2, 2, 0, 0, 2,
-        2, 0, 2, 2, 2, 0, 0, 2,
-        2, 0, 2, 2, 2, 0, 0, 2,
-        2, 0, 2, 0, 0, 0, 0, 21,
-        2, 0, 0, 2, 0, 0, 2, 0,
-        0, 2, 0, 2, 2, 2, 2, 0,
-        0, 22, 22, 0, 0, 0, 0, 0,
-        0, 23, 2, 0, 0, 0, 0, 0,
-        24
+        2, 2, 3, 2, 0, 2, 0, 0,
+        0, 2, 2, 2, 2, 4, 2, 0,
+        5, 0, 5, 6, 0, 0, 5, 2,
+        7, 2, 0, 2, 0, 2, 0, 0,
+        2, 2, 8, 0, 11, 2, 2, 5,
+        0, 12, 12, 0, 2, 5, 2, 5,
+        2, 0, 13, 2, 0, 0, 2, 0,
+        2, 2, 0, 2, 2, 0, 0, 2,
+        2, 0, 0, 0, 0, 2, 14, 2,
+        0, 0, 2, 0, 2, 2, 0, 2,
+        2, 2, 2, 0, 2, 2, 0, 0,
+        2, 2, 0, 0, 0, 0, 2, 15,
+        5, 0, 5, 2, 2, 0, 5, 0,
+        0, 2, 5, 0, 0, 0, 0, 2,
+        16, 17, 2, 0, 0, 0, 0, 2,
+        2, 2, 2, 2, 0, 0, 2, 2,
+        0, 0, 0, 0, 2, 0, 18, 18,
+        0, 0, 0, 0, 19, 2, 0, 0,
+        0
 };
 
 static const char _indic_syllable_machine_to_state_actions[] = {
@@ -746,6 +319,7 @@
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 9,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
@@ -758,40 +332,7 @@
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 9, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0
+        0, 0, 0, 0, 0
 };
 
 static const char _indic_syllable_machine_from_state_actions[] = {
@@ -799,6 +340,7 @@
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 10,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
@@ -811,126 +353,61 @@
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 10, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0
+        0, 0, 0, 0, 0
 };
 
 static const short _indic_syllable_machine_eof_trans[] = {
         1, 1, 1, 1, 1, 1, 1, 1,
-        1, 1, 1, 1, 1, 1, 1, 1,
-        1, 1, 1, 1, 1, 1, 1, 1,
-        1, 1, 1, 1, 1, 1, 1, 1,
-        1, 1, 37, 37, 37, 37, 37, 37,
-        37, 37, 37, 37, 37, 37, 37, 37,
-        37, 37, 37, 37, 37, 37, 37, 37,
-        37, 37, 37, 37, 37, 37, 37, 37,
-        37, 37, 37, 37, 73, 73, 78, 78,
-        73, 73, 73, 73, 73, 73, 73, 73,
-        73, 73, 73, 73, 73, 73, 73, 73,
-        73, 73, 73, 73, 73, 73, 73, 73,
-        73, 73, 73, 73, 73, 109, 109, 109,
-        109, 109, 109, 109, 109, 109, 109, 109,
-        109, 109, 109, 109, 109, 109, 109, 109,
-        109, 109, 109, 109, 109, 109, 109, 109,
-        109, 109, 109, 109, 109, 109, 109, 73,
-        1, 146, 0, 161, 161, 161, 161, 161,
-        161, 161, 161, 161, 161, 161, 161, 161,
-        161, 161, 161, 161, 161, 161, 161, 161,
-        161, 161, 161, 161, 161, 161, 161, 161,
-        161, 161, 161, 161, 161, 161, 161, 161,
-        161, 161, 161, 161, 161, 161, 161, 161,
-        161, 161, 161, 161, 161, 161, 161, 161,
-        161, 161, 161, 161, 161, 161, 161, 161,
-        222, 222, 222, 222, 222, 222, 222, 222,
-        222, 222, 222, 222, 222, 222, 222, 222,
-        222, 222, 222, 222, 222, 222, 222, 222,
-        222, 222, 222, 222, 222, 222, 222, 222,
-        222, 222, 222, 222, 222, 222, 222, 222,
-        222, 222, 222, 222, 222, 222, 222, 222,
-        222, 222, 222, 222, 222, 222, 222, 222,
-        222, 222, 222, 222, 222, 283, 283, 283,
-        283, 283, 283, 283, 283, 283, 283, 283,
-        283, 283, 283, 283, 283, 283, 283, 283,
-        283, 283, 283, 283, 283, 283, 283, 283,
-        283, 283, 283, 283, 283, 283, 283, 283,
-        283, 283, 283, 283, 283, 283, 283, 283,
-        283, 283, 283, 283, 283, 283, 283, 283,
-        283, 283, 283, 283, 283, 283, 283, 339,
-        283, 339, 340, 340, 340, 340, 340, 340,
-        340, 340, 340, 340, 340, 340, 340, 340,
-        340, 340, 340, 340, 340, 340, 340, 340,
-        340, 340, 340, 340, 340, 340, 340, 340,
-        340, 340, 340, 340, 340, 340, 340, 340,
-        340, 340, 340, 340, 340, 340, 340, 340,
-        340, 340, 340, 340, 340, 340, 340, 340,
-        340, 340, 340, 340, 340, 340, 283, 161,
-        161, 161, 161, 161, 161, 161, 161, 161,
-        410, 410, 410, 410, 410, 410, 410, 339
+        1, 11, 11, 11, 11, 11, 11, 11,
+        11, 11, 11, 22, 22, 28, 22, 22,
+        22, 22, 22, 22, 33, 33, 33, 33,
+        33, 33, 33, 33, 33, 1, 43, 0,
+        59, 59, 59, 59, 59, 59, 59, 59,
+        59, 59, 59, 59, 59, 59, 59, 59,
+        59, 59, 59, 59, 79, 79, 79, 79,
+        79, 79, 79, 79, 79, 79, 79, 79,
+        79, 79, 79, 79, 79, 79, 79, 79,
+        79, 79, 79, 79, 79, 104, 104, 104,
+        104, 104, 104, 104, 104, 104, 104, 104,
+        104, 104, 104, 104, 104, 104, 104, 104,
+        104, 121, 121, 122, 122, 122, 122, 122,
+        122, 122, 122, 122, 122, 122, 122, 122,
+        122, 122, 122, 122, 122, 122, 122, 104,
+        59, 59, 59, 59, 59, 59, 59, 149,
+        149, 149, 149, 149, 121
 };
 
-static const int indic_syllable_machine_start = 138;
-static const int indic_syllable_machine_first_final = 138;
+static const int indic_syllable_machine_start = 39;
+static const int indic_syllable_machine_first_final = 39;
 static const int indic_syllable_machine_error = -1;
 
-static const int indic_syllable_machine_en_main = 138;
+static const int indic_syllable_machine_en_main = 39;
 
 
 #line 36 "hb-ot-shape-complex-indic-machine.rl"
 
 
 
-#line 92 "hb-ot-shape-complex-indic-machine.rl"
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
 
 
 #define found_syllable(syllable_type) \
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | indic_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_indic (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act;
   int cs;
   hb_glyph_info_t *info = buffer->info;
 
-#line 934 "hb-ot-shape-complex-indic-machine.hh"
+#line 411 "hb-ot-shape-complex-indic-machine.hh"
         {
         cs = indic_syllable_machine_start;
         ts = 0;
@@ -938,7 +415,7 @@
         act = 0;
         }
 
-#line 112 "hb-ot-shape-complex-indic-machine.rl"
+#line 113 "hb-ot-shape-complex-indic-machine.rl"
 
 
   p = 0;
@@ -946,12 +423,12 @@
 
   unsigned int syllable_serial = 1;
 
-#line 950 "hb-ot-shape-complex-indic-machine.hh"
+#line 427 "hb-ot-shape-complex-indic-machine.hh"
         {
         int _slen;
         int _trans;
         const unsigned char *_keys;
-        const short *_inds;
+        const unsigned char *_inds;
         if ( p == pe )
                 goto _test_eof;
 _resume:
@@ -960,7 +437,7 @@
 #line 1 "NONE"
         {ts = p;}
         break;
-#line 964 "hb-ot-shape-complex-indic-machine.hh"
+#line 441 "hb-ot-shape-complex-indic-machine.hh"
         }
 
         _keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -982,75 +459,55 @@
 #line 1 "NONE"
         {te = p+1;}
         break;
-        case 14:
-#line 83 "hb-ot-shape-complex-indic-machine.rl"
-        {te = p+1;{ found_syllable (consonant_syllable); }}
-        break;
-        case 16:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
-        {te = p+1;{ found_syllable (vowel_syllable); }}
-        break;
-        case 21:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
-        {te = p+1;{ found_syllable (standalone_cluster); }}
-        break;
-        case 24:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
-        {te = p+1;{ found_syllable (symbol_cluster); }}
-        break;
-        case 18:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
-        {te = p+1;{ found_syllable (broken_cluster); }}
-        break;
         case 11:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
         {te = p+1;{ found_syllable (non_indic_cluster); }}
         break;
         case 13:
-#line 83 "hb-ot-shape-complex-indic-machine.rl"
+#line 84 "hb-ot-shape-complex-indic-machine.rl"
         {te = p;p--;{ found_syllable (consonant_syllable); }}
         break;
-        case 15:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
+        case 14:
+#line 85 "hb-ot-shape-complex-indic-machine.rl"
         {te = p;p--;{ found_syllable (vowel_syllable); }}
         break;
-        case 20:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
+        case 17:
+#line 86 "hb-ot-shape-complex-indic-machine.rl"
         {te = p;p--;{ found_syllable (standalone_cluster); }}
         break;
-        case 23:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
+        case 19:
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
         {te = p;p--;{ found_syllable (symbol_cluster); }}
         break;
-        case 17:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
+        case 15:
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
         {te = p;p--;{ found_syllable (broken_cluster); }}
         break;
-        case 19:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+        case 16:
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
         {te = p;p--;{ found_syllable (non_indic_cluster); }}
         break;
         case 1:
-#line 83 "hb-ot-shape-complex-indic-machine.rl"
+#line 84 "hb-ot-shape-complex-indic-machine.rl"
         {{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
         break;
         case 3:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
+#line 85 "hb-ot-shape-complex-indic-machine.rl"
         {{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
         break;
         case 7:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
+#line 86 "hb-ot-shape-complex-indic-machine.rl"
         {{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
         break;
         case 8:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
         {{p = ((te))-1;}{ found_syllable (symbol_cluster); }}
         break;
         case 4:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
         {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
         break;
-        case 5:
+        case 6:
 #line 1 "NONE"
         {       switch( act ) {
         case 1:
@@ -1065,25 +522,25 @@
         }
         }
         break;
-        case 22:
+        case 18:
 #line 1 "NONE"
         {te = p+1;}
-#line 83 "hb-ot-shape-complex-indic-machine.rl"
+#line 84 "hb-ot-shape-complex-indic-machine.rl"
         {act = 1;}
         break;
-        case 6:
+        case 5:
 #line 1 "NONE"
         {te = p+1;}
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
         {act = 5;}
         break;
         case 12:
 #line 1 "NONE"
         {te = p+1;}
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
         {act = 6;}
         break;
-#line 1087 "hb-ot-shape-complex-indic-machine.hh"
+#line 544 "hb-ot-shape-complex-indic-machine.hh"
         }
 
 _again:
@@ -1092,7 +549,7 @@
 #line 1 "NONE"
         {ts = 0;}
         break;
-#line 1096 "hb-ot-shape-complex-indic-machine.hh"
+#line 553 "hb-ot-shape-complex-indic-machine.hh"
         }
 
         if ( ++p != pe )
@@ -1108,8 +565,10 @@
 
         }
 
-#line 120 "hb-ot-shape-complex-indic-machine.rl"
+#line 121 "hb-ot-shape-complex-indic-machine.rl"
 
 }
 
+#undef found_syllable
+
 #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-table.cc
index c061ed1..a150fd2 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-table.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-table.cc
@@ -6,71 +6,77 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-11.0.0.txt
- * # Date: 2018-05-21, 18:33:00 GMT [KW, RP]
- * # IndicPositionalCategory-11.0.0.txt
- * # Date: 2018-02-05, 16:21:00 GMT [KW, RP]
- * # Blocks-11.0.0.txt
- * # Date: 2017-10-16, 24:39:00 GMT [KW]
+ * # IndicSyllabicCategory-13.0.0.txt
+ * # Date: 2019-07-22, 19:55:00 GMT [KW, RP]
+ * # IndicPositionalCategory-13.0.0.txt
+ * # Date: 2019-07-23, 00:01:00 GMT [KW, RP]
+ * # Blocks-13.0.0.txt
+ * # Date: 2019-07-10, 19:06:00 GMT [KW]
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-indic.hh"
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-macros"
 
-#define ISC_A   INDIC_SYLLABIC_CATEGORY_AVAGRAHA                /*  16 chars; Avagraha */
-#define ISC_Bi  INDIC_SYLLABIC_CATEGORY_BINDU                   /*  83 chars; Bindu */
-#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER   /*  20 chars; Brahmi_Joining_Number */
-#define ISC_Ca  INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK       /*  58 chars; Cantillation_Mark */
-#define ISC_C   INDIC_SYLLABIC_CATEGORY_CONSONANT               /* 2110 chars; Consonant */
-#define ISC_CD  INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD          /*  10 chars; Consonant_Dead */
-#define ISC_CF  INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL         /*  67 chars; Consonant_Final */
-#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER   /*   5 chars; Consonant_Head_Letter */
-#define ISC_CIP INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED     /*   1 chars; Consonant_Initial_Postfixed */
-#define ISC_CK  INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER        /*   2 chars; Consonant_Killer */
-#define ISC_CM  INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL        /*  28 chars; Consonant_Medial */
-#define ISC_CP  INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER   /*  21 chars; Consonant_Placeholder */
-#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA       /*   2 chars; Consonant_Preceding_Repha */
-#define ISC_CPrf        INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED      /*   7 chars; Consonant_Prefixed */
-#define ISC_CS  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED     /*  95 chars; Consonant_Subjoined */
-#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA      /*   4 chars; Consonant_Succeeding_Repha */
-#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER  /*   6 chars; Consonant_With_Stacker */
-#define ISC_GM  INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK         /*   3 chars; Gemination_Mark */
-#define ISC_IS  INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER       /*  11 chars; Invisible_Stacker */
-#define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER                  /*   1 chars; Joiner */
-#define ISC_ML  INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER        /*   1 chars; Modifying_Letter */
-#define ISC_ZWNJ        INDIC_SYLLABIC_CATEGORY_NON_JOINER              /*   1 chars; Non_Joiner */
-#define ISC_N   INDIC_SYLLABIC_CATEGORY_NUKTA                   /*  30 chars; Nukta */
-#define ISC_Nd  INDIC_SYLLABIC_CATEGORY_NUMBER                  /* 480 chars; Number */
-#define ISC_NJ  INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER           /*   1 chars; Number_Joiner */
-#define ISC_x   INDIC_SYLLABIC_CATEGORY_OTHER                   /*   1 chars; Other */
-#define ISC_PK  INDIC_SYLLABIC_CATEGORY_PURE_KILLER             /*  21 chars; Pure_Killer */
-#define ISC_RS  INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER        /*   2 chars; Register_Shifter */
-#define ISC_SM  INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER       /*  25 chars; Syllable_Modifier */
-#define ISC_TL  INDIC_SYLLABIC_CATEGORY_TONE_LETTER             /*   7 chars; Tone_Letter */
-#define ISC_TM  INDIC_SYLLABIC_CATEGORY_TONE_MARK               /*  42 chars; Tone_Mark */
-#define ISC_V   INDIC_SYLLABIC_CATEGORY_VIRAMA                  /*  25 chars; Virama */
-#define ISC_Vs  INDIC_SYLLABIC_CATEGORY_VISARGA                 /*  36 chars; Visarga */
-#define ISC_Vo  INDIC_SYLLABIC_CATEGORY_VOWEL                   /*  30 chars; Vowel */
-#define ISC_M   INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT         /* 660 chars; Vowel_Dependent */
-#define ISC_VI  INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT       /* 464 chars; Vowel_Independent */
+#define ISC_A    INDIC_SYLLABIC_CATEGORY_AVAGRAHA                    /*   17 chars; Avagraha */
+#define ISC_Bi   INDIC_SYLLABIC_CATEGORY_BINDU                       /*   91 chars; Bindu */
+#define ISC_BJN  INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER       /*   20 chars; Brahmi_Joining_Number */
+#define ISC_Ca   INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK           /*   59 chars; Cantillation_Mark */
+#define ISC_C    INDIC_SYLLABIC_CATEGORY_CONSONANT                   /* 2195 chars; Consonant */
+#define ISC_CD   INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD              /*   12 chars; Consonant_Dead */
+#define ISC_CF   INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL             /*   67 chars; Consonant_Final */
+#define ISC_CHL  INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER       /*    5 chars; Consonant_Head_Letter */
+#define ISC_CIP  INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED /*    1 chars; Consonant_Initial_Postfixed */
+#define ISC_CK   INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER            /*    2 chars; Consonant_Killer */
+#define ISC_CM   INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL            /*   31 chars; Consonant_Medial */
+#define ISC_CP   INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER       /*   22 chars; Consonant_Placeholder */
+#define ISC_CPR  INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA   /*    3 chars; Consonant_Preceding_Repha */
+#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED          /*   10 chars; Consonant_Prefixed */
+#define ISC_CS   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED         /*   94 chars; Consonant_Subjoined */
+#define ISC_CSR  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA  /*    4 chars; Consonant_Succeeding_Repha */
+#define ISC_CWS  INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER      /*    8 chars; Consonant_With_Stacker */
+#define ISC_GM   INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK             /*    3 chars; Gemination_Mark */
+#define ISC_IS   INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER           /*   12 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                       /*   31 chars; Nukta */
+#define ISC_Nd   INDIC_SYLLABIC_CATEGORY_NUMBER                      /*  491 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                 /*   23 chars; Pure_Killer */
+#define ISC_RS   INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER            /*    2 chars; Register_Shifter */
+#define ISC_SM   INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER           /*   25 chars; Syllable_Modifier */
+#define ISC_TL   INDIC_SYLLABIC_CATEGORY_TONE_LETTER                 /*    7 chars; Tone_Letter */
+#define ISC_TM   INDIC_SYLLABIC_CATEGORY_TONE_MARK                   /*   42 chars; Tone_Mark */
+#define ISC_V    INDIC_SYLLABIC_CATEGORY_VIRAMA                      /*   27 chars; Virama */
+#define ISC_Vs   INDIC_SYLLABIC_CATEGORY_VISARGA                     /*   35 chars; Visarga */
+#define ISC_Vo   INDIC_SYLLABIC_CATEGORY_VOWEL                       /*   30 chars; Vowel */
+#define ISC_M    INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT             /*  683 chars; Vowel_Dependent */
+#define ISC_VI   INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT           /*  484 chars; Vowel_Independent */
 
-#define IMC_B   INDIC_MATRA_CATEGORY_BOTTOM                     /* 340 chars; Bottom */
-#define IMC_BL  INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT            /*   1 chars; Bottom_And_Left */
-#define IMC_BR  INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT           /*   2 chars; Bottom_And_Right */
-#define IMC_L   INDIC_MATRA_CATEGORY_LEFT                       /*  59 chars; Left */
-#define IMC_LR  INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT             /*  21 chars; Left_And_Right */
-#define IMC_x   INDIC_MATRA_CATEGORY_NOT_APPLICABLE             /*   1 chars; Not_Applicable */
-#define IMC_O   INDIC_MATRA_CATEGORY_OVERSTRUCK                 /*  10 chars; Overstruck */
-#define IMC_R   INDIC_MATRA_CATEGORY_RIGHT                      /* 276 chars; Right */
-#define IMC_T   INDIC_MATRA_CATEGORY_TOP                        /* 393 chars; Top */
-#define IMC_TB  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM             /*  10 chars; Top_And_Bottom */
-#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT   /*   1 chars; Top_And_Bottom_And_Right */
-#define IMC_TL  INDIC_MATRA_CATEGORY_TOP_AND_LEFT               /*   6 chars; Top_And_Left */
-#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT     /*   4 chars; Top_And_Left_And_Right */
-#define IMC_TR  INDIC_MATRA_CATEGORY_TOP_AND_RIGHT              /*  13 chars; Top_And_Right */
-#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT          /*  19 chars; Visual_Order_Left */
+#define IMC_B    INDIC_MATRA_CATEGORY_BOTTOM                         /*  351 chars; Bottom */
+#define IMC_BL   INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT                /*    1 chars; Bottom_And_Left */
+#define IMC_BR   INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT               /*    4 chars; Bottom_And_Right */
+#define IMC_L    INDIC_MATRA_CATEGORY_LEFT                           /*   64 chars; Left */
+#define IMC_LR   INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT                 /*   22 chars; Left_And_Right */
+#define IMC_x    INDIC_MATRA_CATEGORY_NOT_APPLICABLE                 /*    1 chars; Not_Applicable */
+#define IMC_O    INDIC_MATRA_CATEGORY_OVERSTRUCK                     /*   10 chars; Overstruck */
+#define IMC_R    INDIC_MATRA_CATEGORY_RIGHT                          /*  288 chars; Right */
+#define IMC_T    INDIC_MATRA_CATEGORY_TOP                            /*  415 chars; Top */
+#define IMC_TB   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM                 /*   10 chars; Top_And_Bottom */
+#define IMC_TBL  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT        /*    2 chars; Top_And_Bottom_And_Left */
+#define IMC_TBR  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT       /*    1 chars; Top_And_Bottom_And_Right */
+#define IMC_TL   INDIC_MATRA_CATEGORY_TOP_AND_LEFT                   /*    6 chars; Top_And_Left */
+#define IMC_TLR  INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT         /*    4 chars; Top_And_Left_And_Right */
+#define IMC_TR   INDIC_MATRA_CATEGORY_TOP_AND_RIGHT                  /*   13 chars; Top_And_Right */
+#define IMC_VOL  INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT              /*   19 chars; Visual_Order_Left */
+
 #pragma GCC diagnostic pop
 
 #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
@@ -152,7 +158,7 @@
   /* 0A38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(x,x),  _(M,R),  _(M,L),
   /* 0A40 */  _(M,R),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),
   /* 0A48 */  _(M,T),  _(x,x),  _(x,x),  _(M,T),  _(M,T),  _(V,B),  _(x,x),  _(x,x),
-  /* 0A50 */  _(x,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0A50 */  _(x,x), _(Ca,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 0A58 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),
   /* 0A60 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
@@ -190,7 +196,7 @@
   /* 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),
+  /* 0B50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),  _(M,T), _(M,TR),
   /* 0B58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),
   /* 0B60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0B68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
@@ -237,7 +243,7 @@
 
   /* Kannada */
 
-  /* 0C80 */  _(x,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0C80 */ _(Bi,x), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x),
   /* 0C90 */ _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0C98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -256,7 +262,7 @@
 
   /* Malayalam */
 
-  /* 0D00 */ _(Bi,T), _(Bi,T), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0D00 */ _(Bi,T), _(Bi,T), _(Bi,R), _(Vs,R), _(Bi,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),
@@ -265,7 +271,7 @@
   /* 0D30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0D38 */  _(C,x),  _(C,x),  _(C,x), _(PK,T), _(PK,T),  _(A,x),  _(M,R),  _(M,R),
   /* 0D40 */  _(M,R),  _(M,R),  _(M,R),  _(M,B),  _(M,B),  _(x,x),  _(M,L),  _(M,L),
-  /* 0D48 */  _(M,L),  _(x,x), _(M,LR), _(M,LR), _(M,LR),  _(V,T),_(CPR,x),  _(x,x),
+  /* 0D48 */  _(M,L),  _(x,x), _(M,LR), _(M,LR), _(M,LR),  _(V,T),_(CPR,T),  _(x,x),
   /* 0D50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CD,x), _(CD,x), _(CD,x),  _(M,R),
   /* 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),
@@ -275,7 +281,7 @@
 
   /* Sinhala */
 
-  /* 0D80 */  _(x,x),  _(x,x), _(Bi,R), _(Vs,R),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0D80 */  _(x,x), _(Bi,T), _(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),
@@ -303,7 +309,7 @@
   /* 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,T), _(TM,B),
-  /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R), _(CM,x), _(CM,B), _(CM,B),  _(C,x),
+  /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R),_(CM,TBL), _(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), _(CP,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),
@@ -346,8 +352,8 @@
   /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B),
   /* 1CE0 */ _(Ca,T), _(Ca,R),  _(x,O),  _(x,O),  _(x,O),  _(x,O),  _(x,O),  _(x,O),
   /* 1CE8 */  _(x,O),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,B),  _(x,x),  _(x,x),
-  /* 1CF0 */  _(x,x),  _(x,x), _(Vs,x), _(Vs,x), _(Ca,T),_(CWS,x),_(CWS,x), _(Ca,R),
-  /* 1CF8 */ _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CF0 */  _(x,x),  _(x,x), _(CD,x), _(CD,x), _(Ca,T),_(CWS,x),_(CWS,x), _(Ca,R),
+  /* 1CF8 */ _(Ca,x), _(Ca,x), _(CP,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
 #define indic_offset_0x2008u 1656
 
@@ -435,6 +441,7 @@
 }
 
 #undef _
+
 #undef ISC_A
 #undef ISC_Bi
 #undef ISC_BJN
@@ -471,6 +478,7 @@
 #undef ISC_Vo
 #undef ISC_M
 #undef ISC_VI
+
 #undef IMC_B
 #undef IMC_BL
 #undef IMC_BR
@@ -481,10 +489,13 @@
 #undef IMC_R
 #undef IMC_T
 #undef IMC_TB
+#undef IMC_TBL
 #undef IMC_TBR
 #undef IMC_TL
 #undef IMC_TLR
 #undef IMC_TR
 #undef IMC_VOL
 
+#endif
+
 /* == End of generated table == */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.cc
index 38b47fa..e011f51 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-indic.hh"
 #include "hb-ot-shape-complex-vowel-constraints.hh"
 #include "hb-ot-layout.hh"
@@ -127,62 +131,47 @@
   {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
   {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
   {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS},
-  /*
-   * Positioning features.
-   * We don't care about the types.
-   */
-  {HB_TAG('d','i','s','t'), F_GLOBAL},
-  {HB_TAG('a','b','v','m'), F_GLOBAL},
-  {HB_TAG('b','l','w','m'), F_GLOBAL},
 };
 
 /*
  * Must be in the same order as the indic_features array.
  */
 enum {
-  _NUKT,
-  _AKHN,
-  RPHF,
-  _RKRF,
-  PREF,
-  BLWF,
-  ABVF,
-  HALF,
-  PSTF,
-  _VATU,
-  _CJCT,
+  _INDIC_NUKT,
+  _INDIC_AKHN,
+  INDIC_RPHF,
+  _INDIC_RKRF,
+  INDIC_PREF,
+  INDIC_BLWF,
+  INDIC_ABVF,
+  INDIC_HALF,
+  INDIC_PSTF,
+  _INDIC_VATU,
+  _INDIC_CJCT,
 
-  INIT,
-  _PRES,
-  _ABVS,
-  _BLWS,
-  _PSTS,
-  _HALN,
-
-  _DIST,
-  _ABVM,
-  _BLWM,
+  INDIC_INIT,
+  _INDIC_PRES,
+  _INDIC_ABVS,
+  _INDIC_BLWS,
+  _INDIC_PSTS,
+  _INDIC_HALN,
 
   INDIC_NUM_FEATURES,
-  INDIC_BASIC_FEATURES = INIT, /* Don't forget to update this! */
+  INDIC_BASIC_FEATURES = INDIC_INIT, /* Don't forget to update this! */
 };
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
-                 hb_font_t *font,
-                 hb_buffer_t *buffer);
+setup_syllables_indic (const hb_ot_shape_plan_t *plan,
+                       hb_font_t *font,
+                       hb_buffer_t *buffer);
 static void
-initial_reordering (const hb_ot_shape_plan_t *plan,
-                    hb_font_t *font,
-                    hb_buffer_t *buffer);
+initial_reordering_indic (const hb_ot_shape_plan_t *plan,
+                          hb_font_t *font,
+                          hb_buffer_t *buffer);
 static void
-final_reordering (const hb_ot_shape_plan_t *plan,
-                  hb_font_t *font,
-                  hb_buffer_t *buffer);
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan,
-                 hb_font_t *font,
-                 hb_buffer_t *buffer);
+final_reordering_indic (const hb_ot_shape_plan_t *plan,
+                        hb_font_t *font,
+                        hb_buffer_t *buffer);
 
 static void
 collect_features_indic (hb_ot_shape_planner_t *plan)
@@ -190,7 +179,7 @@
   hb_ot_map_builder_t *map = &plan->map;
 
   /* Do this before any lookups have been applied. */
-  map->add_gsub_pause (setup_syllables);
+  map->add_gsub_pause (setup_syllables_indic);
 
   map->enable_feature (HB_TAG('l','o','c','l'));
   /* The Indic specs do not require ccmp, but we apply it here since if
@@ -199,14 +188,14 @@
 
 
   unsigned int i = 0;
-  map->add_gsub_pause (initial_reordering);
+  map->add_gsub_pause (initial_reordering_indic);
 
   for (; i < INDIC_BASIC_FEATURES; i++) {
     map->add_feature (indic_features[i]);
     map->add_gsub_pause (nullptr);
   }
 
-  map->add_gsub_pause (final_reordering);
+  map->add_gsub_pause (final_reordering_indic);
 
   for (; i < INDIC_NUM_FEATURES; i++)
     map->add_feature (indic_features[i]);
@@ -214,7 +203,7 @@
   map->enable_feature (HB_TAG('c','a','l','t'));
   map->enable_feature (HB_TAG('c','l','i','g'));
 
-  map->add_gsub_pause (clear_syllables);
+  map->add_gsub_pause (_hb_clear_syllables);
 }
 
 static void
@@ -224,32 +213,6 @@
 }
 
 
-struct would_substitute_feature_t
-{
-  void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
-  {
-    zero_context = zero_context_;
-    map->get_stage_lookups (0/*GSUB*/,
-                            map->get_feature_stage (0/*GSUB*/, feature_tag),
-                            &lookups, &count);
-  }
-
-  bool would_substitute (const hb_codepoint_t *glyphs,
-                         unsigned int          glyphs_count,
-                         hb_face_t            *face) const
-  {
-    for (unsigned int i = 0; i < count; i++)
-      if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
-        return true;
-    return false;
-  }
-
-  private:
-  const hb_ot_map_t::lookup_map_t *lookups;
-  unsigned int count;
-  bool zero_context;
-};
-
 struct indic_shape_plan_t
 {
   bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
@@ -274,13 +237,18 @@
   const indic_config_t *config;
 
   bool is_old_spec;
+#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE
   bool uniscribe_bug_compatible;
+#else
+  static constexpr bool uniscribe_bug_compatible = false;
+#endif
   mutable hb_atomic_int_t virama_glyph;
 
-  would_substitute_feature_t rphf;
-  would_substitute_feature_t pref;
-  would_substitute_feature_t blwf;
-  would_substitute_feature_t pstf;
+  hb_indic_would_substitute_feature_t rphf;
+  hb_indic_would_substitute_feature_t pref;
+  hb_indic_would_substitute_feature_t blwf;
+  hb_indic_would_substitute_feature_t pstf;
+  hb_indic_would_substitute_feature_t vatu;
 
   hb_mask_t mask_array[INDIC_NUM_FEATURES];
 };
@@ -300,7 +268,9 @@
     }
 
   indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
+#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE
   indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible;
+#endif
   indic_plan->virama_glyph.set_relaxed (-1);
 
   /* Use zero-context would_substitute() matching for new-spec of the main
@@ -317,6 +287,7 @@
   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);
   indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
+  indic_plan->vatu.init (&plan->map, HB_TAG('v','a','t','u'), zero_context);
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
     indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
@@ -346,10 +317,16 @@
    * base at 0.  The font however, only has lookups matching
    * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
    * table).  As such, we simply match both sequences.  Seems
-   * to work. */
+   * to work.
+   *
+   * Vatu is done as well, for:
+   * https://github.com/harfbuzz/harfbuzz/issues/1587
+   */
   hb_codepoint_t glyphs[3] = {virama, consonant, virama};
   if (indic_plan->blwf.would_substitute (glyphs  , 2, face) ||
-      indic_plan->blwf.would_substitute (glyphs+1, 2, face))
+      indic_plan->blwf.would_substitute (glyphs+1, 2, face) ||
+      indic_plan->vatu.would_substitute (glyphs  , 2, face) ||
+      indic_plan->vatu.would_substitute (glyphs+1, 2, face))
     return POS_BELOW_C;
   if (indic_plan->pstf.would_substitute (glyphs  , 2, face) ||
       indic_plan->pstf.would_substitute (glyphs+1, 2, face))
@@ -361,13 +338,13 @@
 }
 
 
-enum syllable_type_t {
-  consonant_syllable,
-  vowel_syllable,
-  standalone_cluster,
-  symbol_cluster,
-  broken_cluster,
-  non_indic_cluster,
+enum indic_syllable_type_t {
+  indic_consonant_syllable,
+  indic_vowel_syllable,
+  indic_standalone_cluster,
+  indic_symbol_cluster,
+  indic_broken_cluster,
+  indic_non_indic_cluster,
 };
 
 #include "hb-ot-shape-complex-indic-machine.hh"
@@ -391,11 +368,11 @@
 }
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                 hb_font_t *font HB_UNUSED,
-                 hb_buffer_t *buffer)
+setup_syllables_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                       hb_font_t *font HB_UNUSED,
+                       hb_buffer_t *buffer)
 {
-  find_syllables (buffer);
+  find_syllables_indic (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
 }
@@ -412,9 +389,9 @@
 
 
 static void
-update_consonant_positions (const hb_ot_shape_plan_t *plan,
-                            hb_font_t         *font,
-                            hb_buffer_t       *buffer)
+update_consonant_positions_indic (const hb_ot_shape_plan_t *plan,
+                                  hb_font_t         *font,
+                                  hb_buffer_t       *buffer)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
 
@@ -487,7 +464,7 @@
      *    and has more than one consonant, Ra is excluded from candidates for
      *    base consonants. */
     unsigned int limit = start;
-    if (indic_plan->mask_array[RPHF] &&
+    if (indic_plan->mask_array[INDIC_RPHF] &&
         start + 3 <= end &&
         (
          (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
@@ -645,7 +622,7 @@
   /* Reorder characters */
 
   for (unsigned int i = start; i < base; i++)
-    info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position());
+    info[i].indic_position() = hb_min (POS_PRE_C, (indic_position_t) info[i].indic_position());
 
   if (base < end)
     info[base].indic_position() = POS_BASE_C;
@@ -673,7 +650,7 @@
    * is *not* a Halant after last consonant already.  We know that is the
    * case for Kannada, while it reorders unconditionally in other scripts,
    * eg. Malayalam, Bengali, and Devanagari.  We don't currently know about
-   * other scripts, so we blacklist Kannada.
+   * other scripts, so we block Kannada.
    *
    * Kannada test case:
    * U+0C9A,U+0CCD,U+0C9A,U+0CCD
@@ -720,7 +697,7 @@
     indic_position_t last_pos = POS_START;
     for (unsigned int i = start; i < end; i++)
     {
-      if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | FLAG (OT_H))))
+      if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_H))))
       {
         info[i].indic_position() = last_pos;
         if (unlikely (info[i].indic_category() == OT_H &&
@@ -801,7 +778,7 @@
           unsigned int j = start + info[i].syllable();
           while (j != i)
           {
-            max = MAX (max, j);
+            max = hb_max (max, j);
             unsigned int next = start + info[j].syllable();
             info[j].syllable() = 255; /* So we don't process j later again. */
             j = next;
@@ -823,13 +800,13 @@
 
     /* Reph */
     for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++)
-      info[i].mask |= indic_plan->mask_array[RPHF];
+      info[i].mask |= indic_plan->mask_array[INDIC_RPHF];
 
     /* Pre-base */
-    mask = indic_plan->mask_array[HALF];
+    mask = indic_plan->mask_array[INDIC_HALF];
     if (!indic_plan->is_old_spec &&
         indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
-      mask |= indic_plan->mask_array[BLWF];
+      mask |= indic_plan->mask_array[INDIC_BLWF];
     for (unsigned int i = start; i < base; i++)
       info[i].mask  |= mask;
     /* Base */
@@ -837,7 +814,9 @@
     if (base < end)
       info[base].mask |= mask;
     /* Post-base */
-    mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
+    mask = indic_plan->mask_array[INDIC_BLWF] |
+           indic_plan->mask_array[INDIC_ABVF] |
+           indic_plan->mask_array[INDIC_PSTF];
     for (unsigned int i = base + 1; i < end; i++)
       info[i].mask  |= mask;
   }
@@ -869,13 +848,13 @@
           (i + 2 == base ||
            info[i+2].indic_category() != OT_ZWJ))
       {
-        info[i  ].mask |= indic_plan->mask_array[BLWF];
-        info[i+1].mask |= indic_plan->mask_array[BLWF];
+        info[i  ].mask |= indic_plan->mask_array[INDIC_BLWF];
+        info[i+1].mask |= indic_plan->mask_array[INDIC_BLWF];
       }
   }
 
   unsigned int pref_len = 2;
-  if (indic_plan->mask_array[PREF] && base + pref_len < end)
+  if (indic_plan->mask_array[INDIC_PREF] && base + pref_len < end)
   {
     /* Find a Halant,Ra sequence and mark it for pre-base-reordering processing. */
     for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
@@ -885,7 +864,7 @@
       if (indic_plan->pref.would_substitute (glyphs, pref_len, face))
       {
         for (unsigned int j = 0; j < pref_len; j++)
-          info[i++].mask |= indic_plan->mask_array[PREF];
+          info[i++].mask |= indic_plan->mask_array[INDIC_PREF];
         break;
       }
     }
@@ -906,7 +885,7 @@
 
         /* A ZWNJ disables HALF. */
         if (non_joiner)
-          info[j].mask &= ~indic_plan->mask_array[HALF];
+          info[j].mask &= ~indic_plan->mask_array[INDIC_HALF];
 
       } while (j > start && !is_consonant (info[j]));
     }
@@ -918,11 +897,10 @@
                                        hb_buffer_t *buffer,
                                        unsigned int start, unsigned int end)
 {
-  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
-
   /* We treat placeholder/dotted-circle as if they are consonants, so we
    * should just chain.  Only if not in compatibility mode that is... */
 
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   if (indic_plan->uniscribe_bug_compatible)
   {
     /* For dotted-circle, this is what Uniscribe does:
@@ -936,42 +914,45 @@
 }
 
 static void
-initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
-                             hb_face_t *face,
-                             hb_buffer_t *buffer,
-                             unsigned int start, unsigned int end)
+initial_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
+                                   hb_face_t *face,
+                                   hb_buffer_t *buffer,
+                                   unsigned int start, unsigned int end)
 {
-  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  indic_syllable_type_t syllable_type = (indic_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   switch (syllable_type)
   {
-    case vowel_syllable: /* We made the vowels look like consonants.  So let's call the consonant logic! */
-    case consonant_syllable:
+    case indic_vowel_syllable: /* We made the vowels look like consonants.  So let's call the consonant logic! */
+    case indic_consonant_syllable:
      initial_reordering_consonant_syllable (plan, face, buffer, start, end);
      break;
 
-    case broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */
-    case standalone_cluster:
+    case indic_broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */
+    case indic_standalone_cluster:
      initial_reordering_standalone_cluster (plan, face, buffer, start, end);
      break;
 
-    case symbol_cluster:
-    case non_indic_cluster:
+    case indic_symbol_cluster:
+    case indic_non_indic_cluster:
       break;
   }
 }
 
 static inline void
-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                       hb_font_t *font,
-                       hb_buffer_t *buffer)
+insert_dotted_circles_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                             hb_font_t *font,
+                             hb_buffer_t *buffer)
 {
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
   /* Note: This loop is extra overhead, but should not be measurable.
    * TODO Use a buffer scratch flag to remove the loop. */
   bool has_broken_syllables = false;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    if ((info[i].syllable() & 0x0F) == indic_broken_cluster)
     {
       has_broken_syllables = true;
       break;
@@ -996,8 +977,8 @@
   while (buffer->idx < buffer->len && buffer->successful)
   {
     unsigned int syllable = buffer->cur().syllable();
-    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    indic_syllable_type_t syllable_type = (indic_syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == indic_broken_cluster))
     {
       last_syllable = syllable;
 
@@ -1005,7 +986,6 @@
       ginfo.cluster = buffer->cur().cluster;
       ginfo.mask = buffer->cur().mask;
       ginfo.syllable() = buffer->cur().syllable();
-      /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
       while (buffer->idx < buffer->len && buffer->successful &&
@@ -1022,21 +1002,21 @@
 }
 
 static void
-initial_reordering (const hb_ot_shape_plan_t *plan,
-                    hb_font_t *font,
-                    hb_buffer_t *buffer)
+initial_reordering_indic (const hb_ot_shape_plan_t *plan,
+                          hb_font_t *font,
+                          hb_buffer_t *buffer)
 {
-  update_consonant_positions (plan, font, buffer);
-  insert_dotted_circles (plan, font, buffer);
+  update_consonant_positions_indic (plan, font, buffer);
+  insert_dotted_circles_indic (plan, font, buffer);
 
   foreach_syllable (buffer, start, end)
-    initial_reordering_syllable (plan, font->face, buffer, start, end);
+    initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
 }
 
 static void
-final_reordering_syllable (const hb_ot_shape_plan_t *plan,
-                           hb_buffer_t *buffer,
-                           unsigned int start, unsigned int end)
+final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
+                                 hb_buffer_t *buffer,
+                                 unsigned int start, unsigned int end)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   hb_glyph_info_t *info = buffer->info;
@@ -1072,7 +1052,7 @@
    * syllable.
    */
 
-  bool try_pref = !!indic_plan->mask_array[PREF];
+  bool try_pref = !!indic_plan->mask_array[INDIC_PREF];
 
   /* Find base again */
   unsigned int base;
@@ -1082,7 +1062,7 @@
       if (try_pref && base + 1 < end)
       {
         for (unsigned int i = base + 1; i < end; i++)
-          if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+          if ((info[i].mask & indic_plan->mask_array[INDIC_PREF]) != 0)
           {
             if (!(_hb_glyph_info_substituted (&info[i]) &&
                   _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
@@ -1199,9 +1179,14 @@
               goto search;
             }
           }
-          /* -> If ZWNJ follows this halant, position is moved after it. */
-          if (info[new_pos + 1].indic_category() == OT_ZWNJ)
-            new_pos++;
+          /* -> If ZWNJ follows this halant, position is moved after it.
+           *
+           * IMPLEMENTATION NOTES:
+           *
+           * This is taken care of by the state-machine. A Halant,ZWNJ is a terminating
+           * sequence for a consonant syllable; any pre-base matras occurring after it
+           * will belong to the subsequent syllable.
+           */
         }
       }
       else
@@ -1224,14 +1209,14 @@
 
           /* Note: this merge_clusters() is intentionally *after* the reordering.
            * Indic matra reordering is special and tricky... */
-          buffer->merge_clusters (new_pos, MIN (end, base + 1));
+          buffer->merge_clusters (new_pos, hb_min (end, base + 1));
 
           new_pos--;
         }
     } else {
       for (unsigned int i = start; i < base; i++)
         if (info[i].indic_position () == POS_PRE_M) {
-          buffer->merge_clusters (i, MIN (end, base + 1));
+          buffer->merge_clusters (i, hb_min (end, base + 1));
           break;
         }
     }
@@ -1348,6 +1333,7 @@
         goto reph_move;
       }
     }
+    /* See https://github.com/harfbuzz/harfbuzz/issues/2298#issuecomment-615318654 */
 
     /*       6. Otherwise, reorder reph to the end of the syllable.
      */
@@ -1364,13 +1350,15 @@
        * TEST: U+0930,U+094D,U+0915,U+094B,U+094D
        */
       if (!indic_plan->uniscribe_bug_compatible &&
-          unlikely (is_halant (info[new_reph_pos]))) {
+          unlikely (is_halant (info[new_reph_pos])))
+      {
         for (unsigned int i = base + 1; i < new_reph_pos; i++)
           if (info[i].indic_category() == OT_M) {
             /* Ok, got it. */
             new_reph_pos--;
           }
       }
+
       goto reph_move;
     }
 
@@ -1397,7 +1385,7 @@
   if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base-reordering Ra. */
   {
     for (unsigned int i = base + 1; i < end; i++)
-      if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+      if ((info[i].mask & indic_plan->mask_array[INDIC_PREF]) != 0)
       {
         /*       1. Only reorder a glyph produced by substitution during application
          *          of the <pref> feature. (Note that a font may shape a Ra consonant with
@@ -1460,7 +1448,7 @@
     if (!start ||
         !(FLAG_UNSAFE (_hb_glyph_info_get_general_category (&info[start - 1])) &
          FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
-      info[start].mask |= indic_plan->mask_array[INIT];
+      info[start].mask |= indic_plan->mask_array[INDIC_INIT];
     else
       buffer->unsafe_to_break (start - 1, start + 1);
   }
@@ -1490,15 +1478,15 @@
 
 
 static void
-final_reordering (const hb_ot_shape_plan_t *plan,
-                  hb_font_t *font HB_UNUSED,
-                  hb_buffer_t *buffer)
+final_reordering_indic (const hb_ot_shape_plan_t *plan,
+                        hb_font_t *font HB_UNUSED,
+                        hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   if (unlikely (!count)) return;
 
   foreach_syllable (buffer, start, end)
-    final_reordering_syllable (plan, buffer, start, end);
+    final_reordering_syllable_indic (plan, buffer, start, end);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
@@ -1506,18 +1494,6 @@
 
 
 static void
-clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                 hb_font_t *font HB_UNUSED,
-                 hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-}
-
-
-static void
 preprocess_text_indic (const hb_ot_shape_plan_t *plan,
                        hb_buffer_t              *buffer,
                        hb_font_t                *font)
@@ -1583,11 +1559,10 @@
      *   https://docs.microsoft.com/en-us/typography/script-development/sinhala#shaping
      */
 
+
     const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
-
     hb_codepoint_t glyph;
-
-    if (hb_options ().uniscribe_bug_compatible ||
+    if (indic_plan->uniscribe_bug_compatible ||
         (c->font->get_nominal_glyph (ab, &glyph) &&
          indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
     {
@@ -1635,3 +1610,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.hh
index 0aae0d3..5b3347b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.hh
@@ -62,17 +62,26 @@
   OT_Coeng = 14, /* Khmer-style Virama. */
   OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
   OT_Ra = 16,
-  OT_CM = 17,  /* Consonant-Medial; Unused by Indic shaper. */
+  OT_CM = 17,  /* Consonant-Medial. */
   OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
-  OT_CS = 19
+  OT_CS = 19,
+
+  /* The following are used by Khmer & Myanmar shapers.  Defined
+   * here for them to share. */
+  OT_VAbv    = 26,
+  OT_VBlw    = 27,
+  OT_VPre    = 28,
+  OT_VPst    = 29,
 };
 
+#define MEDIAL_FLAGS (FLAG (OT_CM))
+
 /* Note:
  *
  * We treat Vowels and placeholders as if they were consonants.  This is safe because Vowels
  * cannot happen in a consonant syllable.  The plus side however is, we can call the
  * consonant syllable logic from the vowel syllable function and get it all right! */
-#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
+#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
 #define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
 
 
@@ -156,6 +165,7 @@
   INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT                 = INDIC_MATRA_CATEGORY_RIGHT,
   INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT                   = INDIC_MATRA_CATEGORY_RIGHT,
   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM                   = INDIC_MATRA_CATEGORY_BOTTOM,
+  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT          = INDIC_MATRA_CATEGORY_BOTTOM,
   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT         = INDIC_MATRA_CATEGORY_RIGHT,
   INDIC_MATRA_CATEGORY_TOP_AND_LEFT                     = INDIC_MATRA_CATEGORY_TOP,
   INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT           = INDIC_MATRA_CATEGORY_RIGHT,
@@ -276,7 +286,7 @@
     case POS_POST_C:    return MATRA_POS_RIGHT (u);
     case POS_ABOVE_C:   return MATRA_POS_TOP (u);
     case POS_BELOW_C:   return MATRA_POS_BOTTOM (u);
-  };
+  }
   return side;
 }
 
@@ -357,11 +367,12 @@
   /* According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil,
    * so the Indic shaper needs to know their categories. */
   else if (unlikely (u == 0x11301u || u == 0x11303u)) cat = OT_SM;
-  else if (unlikely (u == 0x1133cu)) cat = OT_N;
+  else if (unlikely (u == 0x1133Bu || u == 0x1133Cu)) cat = OT_N;
 
   else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/552 */
 
   else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */
+  else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */
   else if (unlikely (u == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */
   else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u)))
                                     cat = OT_PLACEHOLDER;
@@ -395,5 +406,31 @@
   info.indic_position() = pos;
 }
 
+struct hb_indic_would_substitute_feature_t
+{
+  void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
+  {
+    zero_context = zero_context_;
+    map->get_stage_lookups (0/*GSUB*/,
+                            map->get_feature_stage (0/*GSUB*/, feature_tag),
+                            &lookups, &count);
+  }
+
+  bool would_substitute (const hb_codepoint_t *glyphs,
+                         unsigned int          glyphs_count,
+                         hb_face_t            *face) const
+  {
+    for (unsigned int i = 0; i < count; i++)
+      if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context))
+        return true;
+    return false;
+  }
+
+  private:
+  const hb_ot_map_t::lookup_map_t *lookups;
+  unsigned int count;
+  bool zero_context;
+};
+
 
 #endif /* HB_OT_SHAPE_COMPLEX_INDIC_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer-machine.hh
index 2b59a50..4d737da 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer-machine.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer-machine.hh
@@ -35,29 +35,27 @@
 #line 36 "hb-ot-shape-complex-khmer-machine.hh"
 static const unsigned char _khmer_syllable_machine_trans_keys[] = {
         5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u,
-        5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u,
-        5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 16u, 1u, 29u, 5u, 29u,
-        5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 5u, 26u,
-        5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u,
-        5u, 29u, 0
+        5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u,
+        5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u,
+        22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 26u, 5u, 29u,
+        5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 5u, 29u,
+        0
 };
 
 static const char _khmer_syllable_machine_key_spans[] = {
         22, 17, 22, 17, 16, 17, 22, 17,
-        22, 17, 16, 17, 22, 17, 16, 17,
-        22, 17, 22, 17, 22, 16, 29, 25,
-        25, 25, 1, 18, 25, 25, 25, 22,
-        25, 25, 1, 18, 25, 25, 16, 25,
-        25
+        22, 17, 17, 22, 17, 16, 17, 22,
+        17, 22, 17, 22, 29, 25, 25, 25,
+        1, 18, 25, 25, 25, 16, 22, 25,
+        25, 1, 18, 25, 25, 16, 25, 25
 };
 
 static const short _khmer_syllable_machine_index_offsets[] = {
         0, 23, 41, 64, 82, 99, 117, 140,
-        158, 181, 199, 216, 234, 257, 275, 292,
-        310, 333, 351, 374, 392, 415, 432, 462,
-        488, 514, 540, 542, 561, 587, 613, 639,
-        662, 688, 714, 716, 735, 761, 787, 804,
-        830
+        158, 181, 199, 217, 240, 258, 275, 293,
+        316, 334, 357, 375, 398, 428, 454, 480,
+        506, 508, 527, 553, 579, 605, 622, 645,
+        671, 697, 699, 718, 744, 770, 787, 813
 };
 
 static const char _khmer_syllable_machine_indicies[] = {
@@ -85,142 +83,136 @@
         0, 0, 0, 0, 0, 0, 12, 0,
         0, 0, 0, 4, 0, 11, 11, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 12, 0, 13,
-        13, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 13, 0,
-        15, 15, 14, 14, 14, 14, 14, 14,
-        14, 14, 14, 14, 14, 14, 14, 14,
-        16, 14, 15, 15, 17, 17, 17, 17,
-        17, 17, 17, 17, 17, 17, 17, 17,
-        17, 17, 16, 17, 17, 17, 17, 18,
-        17, 19, 19, 17, 17, 17, 17, 17,
-        17, 17, 17, 17, 17, 17, 17, 17,
-        17, 18, 17, 20, 20, 17, 17, 17,
-        17, 17, 17, 17, 17, 17, 17, 17,
-        17, 17, 20, 17, 21, 21, 17, 17,
-        17, 17, 17, 17, 17, 17, 17, 17,
-        17, 17, 17, 17, 22, 17, 23, 23,
-        17, 17, 17, 17, 17, 17, 17, 17,
-        17, 17, 17, 17, 17, 17, 24, 17,
-        17, 17, 17, 18, 17, 23, 23, 17,
-        17, 17, 17, 17, 17, 17, 17, 17,
-        17, 17, 17, 17, 17, 24, 17, 25,
-        25, 17, 17, 17, 17, 17, 17, 17,
-        17, 17, 17, 17, 17, 17, 17, 26,
-        17, 17, 17, 17, 18, 17, 25, 25,
-        17, 17, 17, 17, 17, 17, 17, 17,
-        17, 17, 17, 17, 17, 17, 26, 17,
-        15, 15, 17, 17, 17, 17, 17, 17,
-        17, 17, 17, 17, 17, 17, 17, 27,
-        16, 17, 17, 17, 17, 18, 17, 28,
-        28, 17, 17, 17, 17, 17, 17, 17,
-        17, 17, 17, 17, 17, 17, 28, 17,
-        13, 13, 29, 29, 30, 30, 29, 29,
-        29, 29, 2, 2, 29, 31, 29, 13,
-        29, 29, 29, 29, 16, 20, 29, 29,
-        29, 18, 24, 26, 22, 29, 33, 33,
-        32, 32, 32, 32, 32, 32, 32, 34,
-        32, 32, 32, 32, 32, 2, 3, 6,
-        32, 32, 32, 4, 10, 12, 8, 32,
-        35, 35, 32, 32, 32, 32, 32, 32,
-        32, 36, 32, 32, 32, 32, 32, 32,
-        3, 6, 32, 32, 32, 4, 10, 12,
-        8, 32, 5, 5, 32, 32, 32, 32,
-        32, 32, 32, 36, 32, 32, 32, 32,
-        32, 32, 4, 6, 32, 32, 32, 32,
-        32, 32, 8, 32, 6, 32, 7, 7,
-        32, 32, 32, 32, 32, 32, 32, 36,
-        32, 32, 32, 32, 32, 32, 8, 6,
-        32, 37, 37, 32, 32, 32, 32, 32,
-        32, 32, 36, 32, 32, 32, 32, 32,
-        32, 10, 6, 32, 32, 32, 4, 32,
-        32, 8, 32, 38, 38, 32, 32, 32,
-        32, 32, 32, 32, 36, 32, 32, 32,
-        32, 32, 32, 12, 6, 32, 32, 32,
-        4, 10, 32, 8, 32, 35, 35, 32,
-        32, 32, 32, 32, 32, 32, 34, 32,
-        32, 32, 32, 32, 32, 3, 6, 32,
-        32, 32, 4, 10, 12, 8, 32, 15,
-        15, 39, 39, 39, 39, 39, 39, 39,
-        39, 39, 39, 39, 39, 39, 39, 16,
-        39, 39, 39, 39, 18, 39, 41, 41,
-        40, 40, 40, 40, 40, 40, 40, 42,
-        40, 40, 40, 40, 40, 40, 16, 20,
-        40, 40, 40, 18, 24, 26, 22, 40,
-        19, 19, 40, 40, 40, 40, 40, 40,
-        40, 42, 40, 40, 40, 40, 40, 40,
-        18, 20, 40, 40, 40, 40, 40, 40,
-        22, 40, 20, 40, 21, 21, 40, 40,
-        40, 40, 40, 40, 40, 42, 40, 40,
-        40, 40, 40, 40, 22, 20, 40, 43,
-        43, 40, 40, 40, 40, 40, 40, 40,
-        42, 40, 40, 40, 40, 40, 40, 24,
-        20, 40, 40, 40, 18, 40, 40, 22,
-        40, 44, 44, 40, 40, 40, 40, 40,
-        40, 40, 42, 40, 40, 40, 40, 40,
-        40, 26, 20, 40, 40, 40, 18, 24,
-        40, 22, 40, 28, 28, 39, 39, 39,
+        0, 0, 0, 0, 0, 12, 0, 14,
+        14, 13, 13, 13, 13, 13, 13, 13,
+        13, 13, 13, 13, 13, 13, 13, 15,
+        13, 14, 14, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 16, 16, 16,
+        16, 15, 16, 16, 16, 16, 17, 16,
+        18, 18, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 16, 16, 16,
+        17, 16, 19, 19, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 16, 16, 16,
+        16, 19, 16, 20, 20, 16, 16, 16,
+        16, 16, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 21, 16, 22, 22, 16,
+        16, 16, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 23, 16, 16,
+        16, 16, 17, 16, 22, 22, 16, 16,
+        16, 16, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 23, 16, 24, 24,
+        16, 16, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 16, 25, 16,
+        16, 16, 16, 17, 16, 24, 24, 16,
+        16, 16, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 25, 16, 14,
+        14, 16, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 16, 26, 15,
+        16, 16, 16, 16, 17, 16, 28, 28,
+        27, 27, 29, 29, 27, 27, 27, 27,
+        2, 2, 27, 30, 27, 28, 27, 27,
+        27, 27, 15, 19, 27, 27, 27, 17,
+        23, 25, 21, 27, 32, 32, 31, 31,
+        31, 31, 31, 31, 31, 33, 31, 31,
+        31, 31, 31, 2, 3, 6, 31, 31,
+        31, 4, 10, 12, 8, 31, 34, 34,
+        31, 31, 31, 31, 31, 31, 31, 35,
+        31, 31, 31, 31, 31, 31, 3, 6,
+        31, 31, 31, 4, 10, 12, 8, 31,
+        5, 5, 31, 31, 31, 31, 31, 31,
+        31, 35, 31, 31, 31, 31, 31, 31,
+        4, 6, 31, 31, 31, 31, 31, 31,
+        8, 31, 6, 31, 7, 7, 31, 31,
+        31, 31, 31, 31, 31, 35, 31, 31,
+        31, 31, 31, 31, 8, 6, 31, 36,
+        36, 31, 31, 31, 31, 31, 31, 31,
+        35, 31, 31, 31, 31, 31, 31, 10,
+        6, 31, 31, 31, 4, 31, 31, 8,
+        31, 37, 37, 31, 31, 31, 31, 31,
+        31, 31, 35, 31, 31, 31, 31, 31,
+        31, 12, 6, 31, 31, 31, 4, 10,
+        31, 8, 31, 34, 34, 31, 31, 31,
+        31, 31, 31, 31, 33, 31, 31, 31,
+        31, 31, 31, 3, 6, 31, 31, 31,
+        4, 10, 12, 8, 31, 28, 28, 31,
+        31, 31, 31, 31, 31, 31, 31, 31,
+        31, 31, 31, 31, 28, 31, 14, 14,
+        38, 38, 38, 38, 38, 38, 38, 38,
+        38, 38, 38, 38, 38, 38, 15, 38,
+        38, 38, 38, 17, 38, 40, 40, 39,
+        39, 39, 39, 39, 39, 39, 41, 39,
+        39, 39, 39, 39, 39, 15, 19, 39,
+        39, 39, 17, 23, 25, 21, 39, 18,
+        18, 39, 39, 39, 39, 39, 39, 39,
+        41, 39, 39, 39, 39, 39, 39, 17,
+        19, 39, 39, 39, 39, 39, 39, 21,
+        39, 19, 39, 20, 20, 39, 39, 39,
+        39, 39, 39, 39, 41, 39, 39, 39,
+        39, 39, 39, 21, 19, 39, 42, 42,
+        39, 39, 39, 39, 39, 39, 39, 41,
+        39, 39, 39, 39, 39, 39, 23, 19,
+        39, 39, 39, 17, 39, 39, 21, 39,
+        43, 43, 39, 39, 39, 39, 39, 39,
+        39, 41, 39, 39, 39, 39, 39, 39,
+        25, 19, 39, 39, 39, 17, 23, 39,
+        21, 39, 44, 44, 39, 39, 39, 39,
         39, 39, 39, 39, 39, 39, 39, 39,
-        39, 39, 28, 39, 45, 45, 40, 40,
-        40, 40, 40, 40, 40, 46, 40, 40,
-        40, 40, 40, 27, 16, 20, 40, 40,
-        40, 18, 24, 26, 22, 40, 41, 41,
-        40, 40, 40, 40, 40, 40, 40, 46,
-        40, 40, 40, 40, 40, 40, 16, 20,
-        40, 40, 40, 18, 24, 26, 22, 40,
-        0
+        39, 44, 39, 45, 45, 39, 39, 39,
+        39, 39, 39, 39, 30, 39, 39, 39,
+        39, 39, 26, 15, 19, 39, 39, 39,
+        17, 23, 25, 21, 39, 40, 40, 39,
+        39, 39, 39, 39, 39, 39, 30, 39,
+        39, 39, 39, 39, 39, 15, 19, 39,
+        39, 39, 17, 23, 25, 21, 39, 0
 };
 
 static const char _khmer_syllable_machine_trans_targs[] = {
-        22, 1, 30, 24, 25, 3, 26, 5,
-        27, 7, 28, 9, 29, 23, 22, 11,
-        32, 22, 33, 13, 34, 15, 35, 17,
-        36, 19, 37, 40, 39, 22, 31, 38,
-        22, 0, 10, 2, 4, 6, 8, 22,
-        22, 12, 14, 16, 18, 20, 21
+        20, 1, 28, 22, 23, 3, 24, 5,
+        25, 7, 26, 9, 27, 20, 10, 31,
+        20, 32, 12, 33, 14, 34, 16, 35,
+        18, 36, 39, 20, 21, 30, 37, 20,
+        0, 29, 2, 4, 6, 8, 20, 20,
+        11, 13, 15, 17, 38, 19
 };
 
 static const char _khmer_syllable_machine_trans_actions[] = {
         1, 0, 2, 2, 2, 0, 0, 0,
-        2, 0, 2, 0, 2, 2, 3, 0,
-        4, 5, 2, 0, 0, 0, 2, 0,
-        2, 0, 2, 4, 4, 8, 9, 0,
-        10, 0, 0, 0, 0, 0, 0, 11,
-        12, 0, 0, 0, 0, 0, 0
+        2, 0, 2, 0, 2, 3, 0, 4,
+        5, 2, 0, 0, 0, 2, 0, 2,
+        0, 2, 4, 8, 2, 9, 0, 10,
+        0, 0, 0, 0, 0, 0, 11, 12,
+        0, 0, 0, 0, 4, 0
 };
 
 static const char _khmer_syllable_machine_to_state_actions[] = {
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 6, 0,
+        0, 0, 0, 0, 6, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0
+        0, 0, 0, 0, 0, 0, 0, 0
 };
 
 static const char _khmer_syllable_machine_from_state_actions[] = {
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 7, 0,
+        0, 0, 0, 0, 7, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0
+        0, 0, 0, 0, 0, 0, 0, 0
 };
 
 static const unsigned char _khmer_syllable_machine_eof_trans[] = {
         1, 1, 1, 1, 1, 1, 1, 1,
-        1, 1, 1, 15, 18, 18, 18, 18,
-        18, 18, 18, 18, 18, 18, 0, 33,
-        33, 33, 33, 33, 33, 33, 33, 40,
-        41, 41, 41, 41, 41, 41, 40, 41,
-        41
+        1, 1, 14, 17, 17, 17, 17, 17,
+        17, 17, 17, 17, 0, 32, 32, 32,
+        32, 32, 32, 32, 32, 32, 39, 40,
+        40, 40, 40, 40, 40, 40, 40, 40
 };
 
-static const int khmer_syllable_machine_start = 22;
-static const int khmer_syllable_machine_first_final = 22;
+static const int khmer_syllable_machine_start = 20;
+static const int khmer_syllable_machine_first_final = 20;
 static const int khmer_syllable_machine_error = -1;
 
-static const int khmer_syllable_machine_en_main = 22;
+static const int khmer_syllable_machine_en_main = 20;
 
 
 #line 36 "hb-ot-shape-complex-khmer-machine.rl"
@@ -234,19 +226,19 @@
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_khmer (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
 
-#line 250 "hb-ot-shape-complex-khmer-machine.hh"
+#line 242 "hb-ot-shape-complex-khmer-machine.hh"
         {
         cs = khmer_syllable_machine_start;
         ts = 0;
@@ -262,7 +254,7 @@
 
   unsigned int syllable_serial = 1;
 
-#line 266 "hb-ot-shape-complex-khmer-machine.hh"
+#line 258 "hb-ot-shape-complex-khmer-machine.hh"
         {
         int _slen;
         int _trans;
@@ -276,7 +268,7 @@
 #line 1 "NONE"
         {ts = p;}
         break;
-#line 280 "hb-ot-shape-complex-khmer-machine.hh"
+#line 272 "hb-ot-shape-complex-khmer-machine.hh"
         }
 
         _keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@@ -346,7 +338,7 @@
 #line 76 "hb-ot-shape-complex-khmer-machine.rl"
         {act = 3;}
         break;
-#line 350 "hb-ot-shape-complex-khmer-machine.hh"
+#line 342 "hb-ot-shape-complex-khmer-machine.hh"
         }
 
 _again:
@@ -355,7 +347,7 @@
 #line 1 "NONE"
         {ts = 0;}
         break;
-#line 359 "hb-ot-shape-complex-khmer-machine.hh"
+#line 351 "hb-ot-shape-complex-khmer-machine.hh"
         }
 
         if ( ++p != pe )
@@ -375,4 +367,6 @@
 
 }
 
+#undef found_syllable
+
 #endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.cc
index f5437b3..6be5d37 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-khmer.hh"
 #include "hb-ot-layout.hh"
 
@@ -52,50 +56,35 @@
   {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS},
   {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
   {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
-  /*
-   * Positioning features.
-   * We don't care about the types.
-   */
-  {HB_TAG('d','i','s','t'), F_GLOBAL},
-  {HB_TAG('a','b','v','m'), F_GLOBAL},
-  {HB_TAG('b','l','w','m'), F_GLOBAL},
 };
 
 /*
  * Must be in the same order as the khmer_features array.
  */
 enum {
-  PREF,
-  BLWF,
-  ABVF,
-  PSTF,
-  CFAR,
+  KHMER_PREF,
+  KHMER_BLWF,
+  KHMER_ABVF,
+  KHMER_PSTF,
+  KHMER_CFAR,
 
-  _PRES,
-  _ABVS,
-  _BLWS,
-  _PSTS,
-
-  _DIST,
-  _ABVM,
-  _BLWM,
+  _KHMER_PRES,
+  _KHMER_ABVS,
+  _KHMER_BLWS,
+  _KHMER_PSTS,
 
   KHMER_NUM_FEATURES,
-  KHMER_BASIC_FEATURES = _PRES, /* Don't forget to update this! */
+  KHMER_BASIC_FEATURES = _KHMER_PRES, /* Don't forget to update this! */
 };
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
-                 hb_font_t *font,
-                 hb_buffer_t *buffer);
+setup_syllables_khmer (const hb_ot_shape_plan_t *plan,
+                       hb_font_t *font,
+                       hb_buffer_t *buffer);
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-         hb_font_t *font,
-         hb_buffer_t *buffer);
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan,
-                 hb_font_t *font,
-                 hb_buffer_t *buffer);
+reorder_khmer (const hb_ot_shape_plan_t *plan,
+               hb_font_t *font,
+               hb_buffer_t *buffer);
 
 static void
 collect_features_khmer (hb_ot_shape_planner_t *plan)
@@ -103,8 +92,8 @@
   hb_ot_map_builder_t *map = &plan->map;
 
   /* Do this before any lookups have been applied. */
-  map->add_gsub_pause (setup_syllables);
-  map->add_gsub_pause (reorder);
+  map->add_gsub_pause (setup_syllables_khmer);
+  map->add_gsub_pause (reorder_khmer);
 
   /* Testing suggests that Uniscribe does NOT pause between basic
    * features.  Test with KhmerUI.ttf and the following three
@@ -123,7 +112,7 @@
   for (; i < KHMER_BASIC_FEATURES; i++)
     map->add_feature (khmer_features[i]);
 
-  map->add_gsub_pause (clear_syllables);
+  map->add_gsub_pause (_hb_clear_syllables);
 
   for (; i < KHMER_NUM_FEATURES; i++)
     map->add_feature (khmer_features[i]);
@@ -149,32 +138,6 @@
 }
 
 
-struct would_substitute_feature_t
-{
-  void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
-  {
-    zero_context = zero_context_;
-    map->get_stage_lookups (0/*GSUB*/,
-                            map->get_feature_stage (0/*GSUB*/, feature_tag),
-                            &lookups, &count);
-  }
-
-  bool would_substitute (const hb_codepoint_t *glyphs,
-                         unsigned int          glyphs_count,
-                         hb_face_t            *face) const
-  {
-    for (unsigned int i = 0; i < count; i++)
-      if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
-        return true;
-    return false;
-  }
-
-  private:
-  const hb_ot_map_t::lookup_map_t *lookups;
-  unsigned int count;
-  bool zero_context;
-};
-
 struct khmer_shape_plan_t
 {
   bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
@@ -198,8 +161,6 @@
 
   mutable hb_codepoint_t virama_glyph;
 
-  would_substitute_feature_t pref;
-
   hb_mask_t mask_array[KHMER_NUM_FEATURES];
 };
 
@@ -212,8 +173,6 @@
 
   khmer_plan->virama_glyph = (hb_codepoint_t) -1;
 
-  khmer_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), true);
-
   for (unsigned int i = 0; i < ARRAY_LENGTH (khmer_plan->mask_array); i++)
     khmer_plan->mask_array[i] = (khmer_features[i].flags & F_GLOBAL) ?
                                  0 : plan->map.get_1_mask (khmer_features[i].tag);
@@ -228,10 +187,10 @@
 }
 
 
-enum syllable_type_t {
-  consonant_syllable,
-  broken_cluster,
-  non_khmer_cluster,
+enum khmer_syllable_type_t {
+  khmer_consonant_syllable,
+  khmer_broken_cluster,
+  khmer_non_khmer_cluster,
 };
 
 #include "hb-ot-shape-complex-khmer-machine.hh"
@@ -253,11 +212,11 @@
 }
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                 hb_font_t *font HB_UNUSED,
-                 hb_buffer_t *buffer)
+setup_syllables_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                       hb_font_t *font HB_UNUSED,
+                       hb_buffer_t *buffer)
 {
-  find_syllables (buffer);
+  find_syllables_khmer (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
 }
@@ -278,7 +237,9 @@
   /* Setup masks. */
   {
     /* Post-base */
-    hb_mask_t mask = khmer_plan->mask_array[BLWF] | khmer_plan->mask_array[ABVF] | khmer_plan->mask_array[PSTF];
+    hb_mask_t mask = khmer_plan->mask_array[KHMER_BLWF] |
+                     khmer_plan->mask_array[KHMER_ABVF] |
+                     khmer_plan->mask_array[KHMER_PSTF];
     for (unsigned int i = start + 1; i < end; i++)
       info[i].mask  |= mask;
   }
@@ -305,7 +266,7 @@
       if (info[i + 1].khmer_category() == OT_Ra)
       {
         for (unsigned int j = 0; j < 2; j++)
-          info[i + j].mask |= khmer_plan->mask_array[PREF];
+          info[i + j].mask |= khmer_plan->mask_array[KHMER_PREF];
 
         /* Move the Coeng,Ro sequence to the start. */
         buffer->merge_clusters (start, i + 2);
@@ -321,9 +282,9 @@
          * U+1784,U+17D2,U+179A,U+17D2,U+1782
          * U+1784,U+17D2,U+1782,U+17D2,U+179A
          */
-        if (khmer_plan->mask_array[CFAR])
+        if (khmer_plan->mask_array[KHMER_CFAR])
           for (unsigned int j = i + 2; j < end; j++)
-            info[j].mask |= khmer_plan->mask_array[CFAR];
+            info[j].mask |= khmer_plan->mask_array[KHMER_CFAR];
 
         num_coengs = 2; /* Done. */
       }
@@ -342,35 +303,39 @@
 }
 
 static void
-initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
-                             hb_face_t *face,
-                             hb_buffer_t *buffer,
-                             unsigned int start, unsigned int end)
+reorder_syllable_khmer (const hb_ot_shape_plan_t *plan,
+                        hb_face_t *face,
+                        hb_buffer_t *buffer,
+                        unsigned int start, unsigned int end)
 {
-  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   switch (syllable_type)
   {
-    case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
-    case consonant_syllable:
+    case khmer_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
+    case khmer_consonant_syllable:
      reorder_consonant_syllable (plan, face, buffer, start, end);
      break;
 
-    case non_khmer_cluster:
+    case khmer_non_khmer_cluster:
       break;
   }
 }
 
 static inline void
-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                       hb_font_t *font,
-                       hb_buffer_t *buffer)
+insert_dotted_circles_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                             hb_font_t *font,
+                             hb_buffer_t *buffer)
 {
-  /* Note: This loop is extra overhead, but should not be measurable. */
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
+  /* Note: This loop is extra overhead, but should not be measurable.
+   * TODO Use a buffer scratch flag to remove the loop. */
   bool has_broken_syllables = false;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    if ((info[i].syllable() & 0x0F) == khmer_broken_cluster)
     {
       has_broken_syllables = true;
       break;
@@ -395,8 +360,8 @@
   while (buffer->idx < buffer->len && buffer->successful)
   {
     unsigned int syllable = buffer->cur().syllable();
-    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == khmer_broken_cluster))
     {
       last_syllable = syllable;
 
@@ -404,7 +369,6 @@
       ginfo.cluster = buffer->cur().cluster;
       ginfo.mask = buffer->cur().mask;
       ginfo.syllable() = buffer->cur().syllable();
-      /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
       while (buffer->idx < buffer->len && buffer->successful &&
@@ -421,29 +385,18 @@
 }
 
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-         hb_font_t *font,
-         hb_buffer_t *buffer)
+reorder_khmer (const hb_ot_shape_plan_t *plan,
+               hb_font_t *font,
+               hb_buffer_t *buffer)
 {
-  insert_dotted_circles (plan, font, buffer);
+  insert_dotted_circles_khmer (plan, font, buffer);
 
   foreach_syllable (buffer, start, end)
-    initial_reordering_syllable (plan, font->face, buffer, start, end);
+    reorder_syllable_khmer (plan, font->face, buffer, start, end);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category);
 }
 
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                 hb_font_t *font HB_UNUSED,
-                 hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-}
-
 
 static bool
 decompose_khmer (const hb_ot_shape_normalize_context_t *c,
@@ -499,3 +452,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.hh
index 4b94cae..b809d8e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.hh
@@ -43,11 +43,10 @@
   OT_Robatic = 20,
   OT_Xgroup  = 21,
   OT_Ygroup  = 22,
-
-  OT_VAbv    = 26,
-  OT_VBlw    = 27,
-  OT_VPre    = 28,
-  OT_VPst    = 29,
+  //OT_VAbv = 26,
+  //OT_VBlw = 27,
+  //OT_VPre = 28,
+  //OT_VPst = 29,
 };
 
 static inline void
@@ -100,12 +99,12 @@
   if (cat == (khmer_category_t) OT_M)
     switch ((int) pos)
     {
-      case POS_PRE_C:   cat = OT_VPre; break;
-      case POS_BELOW_C: cat = OT_VBlw; break;
-      case POS_ABOVE_C: cat = OT_VAbv; break;
-      case POS_POST_C:  cat = OT_VPst; break;
+      case POS_PRE_C:   cat = (khmer_category_t) OT_VPre; break;
+      case POS_BELOW_C: cat = (khmer_category_t) OT_VBlw; break;
+      case POS_ABOVE_C: cat = (khmer_category_t) OT_VAbv; break;
+      case POS_POST_C:  cat = (khmer_category_t) OT_VPst; break;
       default: assert (0);
-    };
+    }
 
   info.khmer_category() = cat;
 }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar-machine.hh
index 7364d6b..c011c9f 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar-machine.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar-machine.hh
@@ -36,29 +36,31 @@
 static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
         1u, 32u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
         3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u,
-        3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 5u, 29u,
-        5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u, 3u, 29u,
-        3u, 29u, 3u, 30u, 3u, 29u, 1u, 32u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u,
-        3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 32u, 8u, 8u,
-        0
+        3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u,
+        5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u,
+        3u, 29u, 3u, 29u, 1u, 16u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u,
+        3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u,
+        3u, 29u, 1u, 32u, 1u, 32u, 8u, 8u, 0
 };
 
 static const char _myanmar_syllable_machine_key_spans[] = {
         32, 28, 25, 4, 25, 23, 21, 21,
         27, 27, 27, 27, 16, 27, 27, 27,
-        27, 27, 28, 27, 27, 27, 27, 25,
-        4, 25, 23, 21, 21, 27, 27, 27,
-        27, 28, 27, 32, 27, 27, 27, 27,
-        27, 28, 27, 27, 27, 27, 32, 1
+        27, 27, 28, 27, 27, 27, 27, 27,
+        25, 4, 25, 23, 21, 21, 27, 27,
+        27, 27, 16, 28, 27, 27, 27, 27,
+        27, 28, 27, 27, 27, 27, 27, 28,
+        27, 32, 32, 1
 };
 
 static const short _myanmar_syllable_machine_index_offsets[] = {
         0, 33, 62, 88, 93, 119, 143, 165,
         187, 215, 243, 271, 299, 316, 344, 372,
         400, 428, 456, 485, 513, 541, 569, 597,
-        623, 628, 654, 678, 700, 722, 750, 778,
-        806, 834, 863, 891, 924, 952, 980, 1008,
-        1036, 1064, 1093, 1121, 1149, 1177, 1205, 1238
+        625, 651, 656, 682, 706, 728, 750, 778,
+        806, 834, 862, 879, 908, 936, 964, 992,
+        1020, 1048, 1077, 1105, 1133, 1161, 1189, 1217,
+        1246, 1274, 1307, 1340
 };
 
 static const char _myanmar_syllable_machine_indicies[] = {
@@ -124,120 +126,134 @@
         21, 21, 21, 21, 21, 21, 32, 33,
         34, 35, 36, 43, 21, 22, 21, 24,
         24, 21, 25, 21, 26, 21, 21, 21,
-        21, 21, 21, 21, 43, 21, 21, 28,
+        21, 21, 21, 21, 21, 21, 21, 28,
         21, 30, 21, 32, 33, 34, 35, 36,
         21, 22, 21, 24, 24, 21, 25, 21,
         26, 21, 21, 21, 21, 21, 21, 21,
         43, 21, 21, 28, 21, 21, 21, 32,
         33, 34, 35, 36, 21, 22, 21, 24,
         24, 21, 25, 21, 26, 21, 21, 21,
-        21, 21, 21, 21, 43, 21, 21, 28,
+        21, 21, 21, 21, 44, 21, 21, 28,
         29, 30, 21, 32, 33, 34, 35, 36,
-        21, 22, 23, 24, 24, 21, 25, 21,
+        21, 22, 21, 24, 24, 21, 25, 21,
         26, 21, 21, 21, 21, 21, 21, 21,
-        27, 21, 21, 28, 29, 30, 31, 32,
-        33, 34, 35, 36, 21, 3, 3, 44,
-        5, 44, 44, 44, 44, 44, 44, 44,
-        44, 44, 45, 44, 44, 44, 44, 44,
-        44, 14, 44, 44, 44, 18, 44, 3,
-        3, 44, 5, 44, 3, 3, 44, 5,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        14, 44, 44, 44, 18, 44, 46, 44,
-        3, 3, 44, 5, 44, 14, 44, 44,
-        44, 44, 44, 44, 44, 47, 44, 44,
-        44, 44, 44, 44, 14, 44, 3, 3,
-        44, 5, 44, 44, 44, 44, 44, 44,
-        44, 44, 44, 47, 44, 44, 44, 44,
-        44, 44, 14, 44, 3, 3, 44, 5,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        14, 44, 2, 44, 3, 3, 44, 5,
-        44, 6, 44, 44, 44, 44, 44, 44,
-        44, 48, 44, 44, 48, 44, 44, 44,
-        14, 49, 44, 44, 18, 44, 2, 44,
-        3, 3, 44, 5, 44, 6, 44, 44,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        44, 44, 44, 44, 14, 44, 44, 44,
-        18, 44, 2, 44, 3, 3, 44, 5,
-        44, 6, 44, 44, 44, 44, 44, 44,
-        44, 48, 44, 44, 44, 44, 44, 44,
-        14, 49, 44, 44, 18, 44, 2, 44,
-        3, 3, 44, 5, 44, 6, 44, 44,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        44, 44, 44, 44, 14, 49, 44, 44,
-        18, 44, 22, 23, 24, 24, 21, 25,
-        21, 26, 21, 21, 21, 21, 21, 21,
-        21, 50, 21, 21, 28, 29, 30, 31,
-        32, 33, 34, 35, 36, 37, 21, 22,
-        51, 24, 24, 21, 25, 21, 26, 21,
-        21, 21, 21, 21, 21, 21, 27, 21,
-        21, 28, 29, 30, 31, 32, 33, 34,
-        35, 36, 21, 1, 1, 2, 3, 3,
-        3, 44, 5, 44, 6, 1, 44, 44,
-        44, 44, 1, 44, 8, 44, 44, 10,
+        21, 21, 21, 28, 29, 30, 21, 32,
+        33, 34, 35, 36, 21, 22, 23, 24,
+        24, 21, 25, 21, 26, 21, 21, 21,
+        21, 21, 21, 21, 27, 21, 21, 28,
+        29, 30, 31, 32, 33, 34, 35, 36,
+        21, 46, 46, 45, 5, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 47, 45,
+        45, 45, 45, 45, 45, 14, 45, 45,
+        45, 18, 45, 46, 46, 45, 5, 45,
+        46, 46, 45, 5, 45, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 45, 45,
+        45, 45, 45, 45, 14, 45, 45, 45,
+        18, 45, 48, 45, 46, 46, 45, 5,
+        45, 14, 45, 45, 45, 45, 45, 45,
+        45, 49, 45, 45, 45, 45, 45, 45,
+        14, 45, 46, 46, 45, 5, 45, 45,
+        45, 45, 45, 45, 45, 45, 45, 49,
+        45, 45, 45, 45, 45, 45, 14, 45,
+        46, 46, 45, 5, 45, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 45, 45,
+        45, 45, 45, 45, 14, 45, 2, 45,
+        46, 46, 45, 5, 45, 6, 45, 45,
+        45, 45, 45, 45, 45, 50, 45, 45,
+        50, 45, 45, 45, 14, 51, 45, 45,
+        18, 45, 2, 45, 46, 46, 45, 5,
+        45, 6, 45, 45, 45, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 45, 45,
+        14, 45, 45, 45, 18, 45, 2, 45,
+        46, 46, 45, 5, 45, 6, 45, 45,
+        45, 45, 45, 45, 45, 50, 45, 45,
+        45, 45, 45, 45, 14, 51, 45, 45,
+        18, 45, 2, 45, 46, 46, 45, 5,
+        45, 6, 45, 45, 45, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 45, 45,
+        14, 51, 45, 45, 18, 45, 52, 52,
+        45, 45, 45, 45, 45, 45, 45, 45,
+        45, 45, 45, 45, 45, 52, 45, 2,
+        3, 46, 46, 45, 5, 45, 6, 45,
+        45, 45, 45, 45, 45, 45, 8, 45,
+        45, 10, 11, 12, 13, 14, 15, 16,
+        17, 18, 19, 45, 2, 45, 46, 46,
+        45, 5, 45, 6, 45, 45, 45, 45,
+        45, 45, 45, 8, 45, 45, 10, 11,
+        12, 13, 14, 15, 16, 17, 18, 45,
+        2, 45, 46, 46, 45, 5, 45, 6,
+        45, 45, 45, 45, 45, 45, 45, 53,
+        45, 45, 45, 45, 45, 45, 14, 15,
+        16, 17, 18, 45, 2, 45, 46, 46,
+        45, 5, 45, 6, 45, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 45, 45,
+        45, 45, 14, 15, 16, 17, 18, 45,
+        2, 45, 46, 46, 45, 5, 45, 6,
+        45, 45, 45, 45, 45, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 14, 15,
+        16, 45, 18, 45, 2, 45, 46, 46,
+        45, 5, 45, 6, 45, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 45, 45,
+        45, 45, 14, 45, 16, 45, 18, 45,
+        2, 45, 46, 46, 45, 5, 45, 6,
+        45, 45, 45, 45, 45, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 14, 15,
+        16, 17, 18, 53, 45, 2, 45, 46,
+        46, 45, 5, 45, 6, 45, 45, 45,
+        45, 45, 45, 45, 45, 45, 45, 10,
+        45, 12, 45, 14, 15, 16, 17, 18,
+        45, 2, 45, 46, 46, 45, 5, 45,
+        6, 45, 45, 45, 45, 45, 45, 45,
+        53, 45, 45, 10, 45, 45, 45, 14,
+        15, 16, 17, 18, 45, 2, 45, 46,
+        46, 45, 5, 45, 6, 45, 45, 45,
+        45, 45, 45, 45, 54, 45, 45, 10,
+        11, 12, 45, 14, 15, 16, 17, 18,
+        45, 2, 45, 46, 46, 45, 5, 45,
+        6, 45, 45, 45, 45, 45, 45, 45,
+        45, 45, 45, 10, 11, 12, 45, 14,
+        15, 16, 17, 18, 45, 2, 3, 46,
+        46, 45, 5, 45, 6, 45, 45, 45,
+        45, 45, 45, 45, 8, 45, 45, 10,
         11, 12, 13, 14, 15, 16, 17, 18,
-        19, 44, 1, 44, 2, 44, 3, 3,
-        44, 5, 44, 6, 44, 44, 44, 44,
-        44, 44, 44, 8, 44, 44, 10, 11,
-        12, 13, 14, 15, 16, 17, 18, 44,
-        2, 44, 3, 3, 44, 5, 44, 6,
-        44, 44, 44, 44, 44, 44, 44, 52,
-        44, 44, 44, 44, 44, 44, 14, 15,
-        16, 17, 18, 44, 2, 44, 3, 3,
-        44, 5, 44, 6, 44, 44, 44, 44,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        44, 44, 14, 15, 16, 17, 18, 44,
-        2, 44, 3, 3, 44, 5, 44, 6,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        44, 44, 44, 44, 44, 44, 14, 15,
-        16, 44, 18, 44, 2, 44, 3, 3,
-        44, 5, 44, 6, 44, 44, 44, 44,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        44, 44, 14, 44, 16, 44, 18, 44,
-        2, 44, 3, 3, 44, 5, 44, 6,
-        44, 44, 44, 44, 44, 44, 44, 44,
-        44, 44, 44, 44, 44, 44, 14, 15,
-        16, 17, 18, 52, 44, 2, 44, 3,
-        3, 44, 5, 44, 6, 44, 44, 44,
-        44, 44, 44, 44, 52, 44, 44, 10,
-        44, 12, 44, 14, 15, 16, 17, 18,
-        44, 2, 44, 3, 3, 44, 5, 44,
-        6, 44, 44, 44, 44, 44, 44, 44,
-        52, 44, 44, 10, 44, 44, 44, 14,
-        15, 16, 17, 18, 44, 2, 44, 3,
-        3, 44, 5, 44, 6, 44, 44, 44,
-        44, 44, 44, 44, 52, 44, 44, 10,
-        11, 12, 44, 14, 15, 16, 17, 18,
-        44, 2, 3, 3, 3, 44, 5, 44,
-        6, 44, 44, 44, 44, 44, 44, 44,
-        8, 44, 44, 10, 11, 12, 13, 14,
-        15, 16, 17, 18, 44, 1, 1, 53,
-        53, 53, 53, 53, 53, 53, 53, 1,
-        53, 53, 53, 53, 1, 53, 53, 53,
-        53, 53, 53, 53, 53, 53, 53, 53,
-        53, 53, 53, 53, 1, 53, 54, 53,
-        0
+        45, 22, 23, 24, 24, 21, 25, 21,
+        26, 21, 21, 21, 21, 21, 21, 21,
+        55, 21, 21, 28, 29, 30, 31, 32,
+        33, 34, 35, 36, 37, 21, 22, 56,
+        24, 24, 21, 25, 21, 26, 21, 21,
+        21, 21, 21, 21, 21, 27, 21, 21,
+        28, 29, 30, 31, 32, 33, 34, 35,
+        36, 21, 1, 1, 2, 3, 46, 46,
+        45, 5, 45, 6, 1, 45, 45, 45,
+        45, 1, 45, 8, 45, 45, 10, 11,
+        12, 13, 14, 15, 16, 17, 18, 19,
+        45, 1, 45, 1, 1, 57, 57, 57,
+        57, 57, 57, 57, 57, 1, 57, 57,
+        57, 57, 1, 57, 57, 57, 57, 57,
+        57, 57, 57, 57, 57, 57, 57, 57,
+        57, 57, 1, 57, 58, 57, 0
 };
 
 static const char _myanmar_syllable_machine_trans_targs[] = {
-        0, 1, 23, 0, 0, 24, 30, 33,
-        36, 46, 37, 42, 43, 44, 26, 39,
-        40, 41, 29, 45, 47, 0, 2, 12,
+        0, 1, 24, 34, 0, 25, 31, 47,
+        36, 50, 37, 42, 43, 44, 27, 39,
+        40, 41, 30, 46, 51, 0, 2, 12,
         0, 3, 9, 13, 14, 19, 20, 21,
-        5, 16, 17, 18, 8, 22, 4, 6,
-        7, 10, 11, 15, 0, 25, 27, 28,
-        31, 32, 34, 35, 38, 0, 0
+        5, 16, 17, 18, 8, 23, 4, 6,
+        7, 10, 11, 15, 22, 0, 0, 26,
+        28, 29, 32, 33, 35, 38, 45, 48,
+        49, 0, 0
 };
 
 static const char _myanmar_syllable_machine_trans_actions[] = {
-        3, 0, 0, 4, 5, 0, 0, 0,
+        3, 0, 0, 0, 4, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 6, 0, 0,
-        7, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 5, 0, 0,
+        6, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 8, 0, 0, 0,
-        0, 0, 0, 0, 0, 9, 10
+        0, 0, 0, 0, 0, 7, 8, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 9, 10
 };
 
 static const char _myanmar_syllable_machine_to_state_actions[] = {
@@ -246,7 +262,8 @@
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0
 };
 
 static const char _myanmar_syllable_machine_from_state_actions[] = {
@@ -255,16 +272,18 @@
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0
 };
 
 static const short _myanmar_syllable_machine_eof_trans[] = {
         0, 22, 22, 22, 22, 22, 22, 22,
         22, 22, 22, 22, 22, 22, 22, 22,
-        22, 22, 22, 22, 22, 22, 22, 45,
-        45, 45, 45, 45, 45, 45, 45, 45,
-        45, 22, 22, 45, 45, 45, 45, 45,
-        45, 45, 45, 45, 45, 45, 54, 54
+        22, 22, 22, 22, 22, 22, 22, 22,
+        46, 46, 46, 46, 46, 46, 46, 46,
+        46, 46, 46, 46, 46, 46, 46, 46,
+        46, 46, 46, 46, 46, 46, 46, 22,
+        22, 46, 58, 58
 };
 
 static const int myanmar_syllable_machine_start = 0;
@@ -285,19 +304,19 @@
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | myanmar_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_myanmar (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
 
-#line 301 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
         {
         cs = myanmar_syllable_machine_start;
         ts = 0;
@@ -313,7 +332,7 @@
 
   unsigned int syllable_serial = 1;
 
-#line 317 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 336 "hb-ot-shape-complex-myanmar-machine.hh"
         {
         int _slen;
         int _trans;
@@ -327,7 +346,7 @@
 #line 1 "NONE"
         {ts = p;}
         break;
-#line 331 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 350 "hb-ot-shape-complex-myanmar-machine.hh"
         }
 
         _keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -345,11 +364,11 @@
                 goto _again;
 
         switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
-        case 7:
+        case 6:
 #line 86 "hb-ot-shape-complex-myanmar-machine.rl"
         {te = p+1;{ found_syllable (consonant_syllable); }}
         break;
-        case 5:
+        case 4:
 #line 87 "hb-ot-shape-complex-myanmar-machine.rl"
         {te = p+1;{ found_syllable (non_myanmar_cluster); }}
         break;
@@ -357,7 +376,7 @@
 #line 88 "hb-ot-shape-complex-myanmar-machine.rl"
         {te = p+1;{ found_syllable (punctuation_cluster); }}
         break;
-        case 4:
+        case 8:
 #line 89 "hb-ot-shape-complex-myanmar-machine.rl"
         {te = p+1;{ found_syllable (broken_cluster); }}
         break;
@@ -365,11 +384,11 @@
 #line 90 "hb-ot-shape-complex-myanmar-machine.rl"
         {te = p+1;{ found_syllable (non_myanmar_cluster); }}
         break;
-        case 6:
+        case 5:
 #line 86 "hb-ot-shape-complex-myanmar-machine.rl"
         {te = p;p--;{ found_syllable (consonant_syllable); }}
         break;
-        case 8:
+        case 7:
 #line 89 "hb-ot-shape-complex-myanmar-machine.rl"
         {te = p;p--;{ found_syllable (broken_cluster); }}
         break;
@@ -377,7 +396,7 @@
 #line 90 "hb-ot-shape-complex-myanmar-machine.rl"
         {te = p;p--;{ found_syllable (non_myanmar_cluster); }}
         break;
-#line 381 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 400 "hb-ot-shape-complex-myanmar-machine.hh"
         }
 
 _again:
@@ -386,7 +405,7 @@
 #line 1 "NONE"
         {ts = 0;}
         break;
-#line 390 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 409 "hb-ot-shape-complex-myanmar-machine.hh"
         }
 
         if ( ++p != pe )
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.cc
index e84c8f4..03b93a6 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-myanmar.hh"
 
 
@@ -32,7 +36,7 @@
  */
 
 static const hb_tag_t
-basic_features[] =
+myanmar_basic_features[] =
 {
   /*
    * Basic features.
@@ -44,7 +48,7 @@
   HB_TAG('p','s','t','f'),
 };
 static const hb_tag_t
-other_features[] =
+myanmar_other_features[] =
 {
   /*
    * Other features.
@@ -55,36 +59,13 @@
   HB_TAG('b','l','w','s'),
   HB_TAG('p','s','t','s'),
 };
-static const hb_tag_t
-positioning_features[] =
-{
-  /*
-   * Positioning features.
-   * We don't care about the types.
-   */
-  HB_TAG('d','i','s','t'),
-  /* Pre-release version of Windows 8 Myanmar font had abvm,blwm
-   * features.  The released Windows 8 version of the font (as well
-   * as the released spec) used 'mark' instead.  The Windows 8
-   * shaper however didn't apply 'mark' but did apply 'mkmk'.
-   * Perhaps it applied abvm/blwm.  This was fixed in a Windows 8
-   * update, so now it applies mark/mkmk.  We are guessing that
-   * it still applies abvm/blwm too.
-   */
-  HB_TAG('a','b','v','m'),
-  HB_TAG('b','l','w','m'),
-};
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
-                 hb_font_t *font,
-                 hb_buffer_t *buffer);
+setup_syllables_myanmar (const hb_ot_shape_plan_t *plan,
+                         hb_font_t *font,
+                         hb_buffer_t *buffer);
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-         hb_font_t *font,
-         hb_buffer_t *buffer);
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan,
+reorder_myanmar (const hb_ot_shape_plan_t *plan,
                  hb_font_t *font,
                  hb_buffer_t *buffer);
 
@@ -94,7 +75,7 @@
   hb_ot_map_builder_t *map = &plan->map;
 
   /* Do this before any lookups have been applied. */
-  map->add_gsub_pause (setup_syllables);
+  map->add_gsub_pause (setup_syllables_myanmar);
 
   map->enable_feature (HB_TAG('l','o','c','l'));
   /* The Indic specs do not require ccmp, but we apply it here since if
@@ -102,21 +83,18 @@
   map->enable_feature (HB_TAG('c','c','m','p'));
 
 
-  map->add_gsub_pause (reorder);
+  map->add_gsub_pause (reorder_myanmar);
 
-  for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
+  for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
   {
-    map->enable_feature (basic_features[i], F_MANUAL_ZWJ);
+    map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ);
     map->add_gsub_pause (nullptr);
   }
 
-  map->add_gsub_pause (clear_syllables);
+  map->add_gsub_pause (_hb_clear_syllables);
 
-  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
-    map->enable_feature (other_features[i], F_MANUAL_ZWJ);
-
-  for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++)
-    map->enable_feature (positioning_features[i]);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
+    map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
 }
 
 static void
@@ -126,11 +104,11 @@
 }
 
 
-enum syllable_type_t {
-  consonant_syllable,
-  punctuation_cluster,
-  broken_cluster,
-  non_myanmar_cluster,
+enum myanmar_syllable_type_t {
+  myanmar_consonant_syllable,
+  myanmar_punctuation_cluster,
+  myanmar_broken_cluster,
+  myanmar_non_myanmar_cluster,
 };
 
 #include "hb-ot-shape-complex-myanmar-machine.hh"
@@ -138,8 +116,8 @@
 
 static void
 setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                   hb_buffer_t              *buffer,
-                   hb_font_t                *font HB_UNUSED)
+                     hb_buffer_t              *buffer,
+                     hb_font_t                *font HB_UNUSED)
 {
   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category);
   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position);
@@ -154,11 +132,11 @@
 }
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                 hb_font_t *font HB_UNUSED,
-                 hb_buffer_t *buffer)
+setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                         hb_font_t *font HB_UNUSED,
+                         hb_buffer_t *buffer)
 {
-  find_syllables (buffer);
+  find_syllables_myanmar (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
 }
@@ -274,36 +252,40 @@
 }
 
 static void
-initial_reordering_syllable (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                             hb_face_t *face HB_UNUSED,
-                             hb_buffer_t *buffer,
-                             unsigned int start, unsigned int end)
+reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                          hb_face_t *face HB_UNUSED,
+                          hb_buffer_t *buffer,
+                          unsigned int start, unsigned int end)
 {
-  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   switch (syllable_type) {
 
-    case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
-    case consonant_syllable:
+    case myanmar_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
+    case myanmar_consonant_syllable:
       initial_reordering_consonant_syllable  (buffer, start, end);
       break;
 
-    case punctuation_cluster:
-    case non_myanmar_cluster:
+    case myanmar_punctuation_cluster:
+    case myanmar_non_myanmar_cluster:
       break;
   }
 }
 
 static inline void
-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                       hb_font_t *font,
-                       hb_buffer_t *buffer)
+insert_dotted_circles_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                               hb_font_t *font,
+                               hb_buffer_t *buffer)
 {
-  /* Note: This loop is extra overhead, but should not be measurable. */
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
+  /* Note: This loop is extra overhead, but should not be measurable.
+   * TODO Use a buffer scratch flag to remove the loop. */
   bool has_broken_syllables = false;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    if ((info[i].syllable() & 0x0F) == myanmar_broken_cluster)
     {
       has_broken_syllables = true;
       break;
@@ -328,8 +310,8 @@
   while (buffer->idx < buffer->len && buffer->successful)
   {
     unsigned int syllable = buffer->cur().syllable();
-    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == myanmar_broken_cluster))
     {
       last_syllable = syllable;
 
@@ -347,30 +329,19 @@
 }
 
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-         hb_font_t *font,
-         hb_buffer_t *buffer)
+reorder_myanmar (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font,
+                 hb_buffer_t *buffer)
 {
-  insert_dotted_circles (plan, font, buffer);
+  insert_dotted_circles_myanmar (plan, font, buffer);
 
   foreach_syllable (buffer, start, end)
-    initial_reordering_syllable (plan, font->face, buffer, start, end);
+    reorder_syllable_myanmar (plan, font->face, buffer, start, end);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
 }
 
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                 hb_font_t *font HB_UNUSED,
-                 hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-}
-
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
 {
@@ -411,3 +382,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.hh
index 86717a9..4adbc5a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.hh
@@ -49,10 +49,10 @@
   OT_MW  = 23, /* Various consonant medial types */
   OT_MY  = 24, /* Various consonant medial types */
   OT_PT  = 25, /* Pwo and other tones */
-  OT_VAbv = 26,
-  OT_VBlw = 27,
-  OT_VPre = 28,
-  OT_VPst = 29,
+  //OT_VAbv = 26,
+  //OT_VBlw = 27,
+  //OT_VPre = 28,
+  //OT_VPst = 29,
   OT_VS   = 30, /* Variation selectors */
   OT_P    = 31, /* Punctuation */
   OT_D    = 32, /* Digits except zero */
@@ -146,7 +146,7 @@
       break;
 
     case 0xAA74u: case 0xAA75u: case 0xAA76u:
-      /* https://github.com/roozbehp/unicode-data/issues/3 */
+      /* https://github.com/harfbuzz/harfbuzz/issues/218 */
       cat = OT_C;
       break;
   }
@@ -155,11 +155,11 @@
   {
     switch ((int) pos)
     {
-      case POS_PRE_C:   cat = OT_VPre;
+      case POS_PRE_C:   cat = (myanmar_category_t) OT_VPre;
                         pos = POS_PRE_M; break;
-      case POS_ABOVE_C: cat = OT_VAbv;   break;
-      case POS_BELOW_C: cat = OT_VBlw;   break;
-      case POS_POST_C:  cat = OT_VPst;   break;
+      case POS_ABOVE_C: cat = (myanmar_category_t) OT_VAbv;   break;
+      case POS_BELOW_C: cat = (myanmar_category_t) OT_VBlw;   break;
+      case POS_POST_C:  cat = (myanmar_category_t) OT_VPst;   break;
     }
   }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-thai.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-thai.cc
index b13697b..e18a06b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-thai.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-thai.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex.hh"
 
 
@@ -218,6 +222,10 @@
                      hb_buffer_t              *buffer,
                      hb_font_t                *font)
 {
+#ifdef HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
+  return;
+#endif
+
   thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT];
   thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT];
   unsigned int base = 0;
@@ -381,3 +389,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   false,/* fallback_position */
 };
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-machine.hh
index 3d0271b..796b611 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-machine.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-machine.hh
@@ -36,36 +36,42 @@
 
 #line 38 "hb-ot-shape-complex-use-machine.hh"
 static const unsigned char _use_syllable_machine_trans_keys[] = {
-        12u, 44u, 1u, 15u, 1u, 1u, 12u, 44u, 0u, 44u, 21u, 21u, 8u, 44u, 8u, 44u,
-        1u, 15u, 1u, 1u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u,
-        8u, 39u, 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u,
-        8u, 44u, 8u, 44u, 8u, 44u, 1u, 39u, 8u, 44u, 13u, 21u, 4u, 4u, 13u, 13u,
-        8u, 44u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u,
-        8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u,
-        8u, 44u, 8u, 44u, 1u, 39u, 1u, 15u, 12u, 44u, 1u, 44u, 8u, 44u, 21u, 42u,
-        41u, 42u, 42u, 42u, 1u, 5u, 0
+        12u, 48u, 1u, 15u, 1u, 1u, 12u, 48u, 1u, 1u, 0u, 48u, 21u, 21u, 11u, 48u,
+        11u, 48u, 1u, 15u, 1u, 1u, 11u, 48u, 22u, 48u, 23u, 48u, 24u, 47u, 25u, 47u,
+        26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u,
+        23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 11u, 48u,
+        1u, 48u, 11u, 48u, 13u, 21u, 4u, 4u, 13u, 13u, 11u, 48u, 11u, 48u, 41u, 42u,
+        42u, 42u, 11u, 48u, 11u, 48u, 22u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u,
+        45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 24u, 48u, 23u, 48u, 23u, 48u,
+        23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 11u, 48u, 1u, 48u, 1u, 15u,
+        4u, 4u, 13u, 21u, 13u, 13u, 12u, 48u, 1u, 48u, 11u, 48u, 41u, 42u, 42u, 42u,
+        21u, 42u, 1u, 5u, 0
 };
 
 static const char _use_syllable_machine_key_spans[] = {
-        33, 15, 1, 33, 45, 1, 37, 37,
-        15, 1, 37, 37, 32, 19, 19, 19,
-        32, 32, 32, 37, 37, 37, 37, 37,
-        37, 37, 37, 39, 37, 9, 1, 1,
-        37, 37, 37, 32, 19, 19, 19, 32,
-        32, 32, 37, 37, 37, 37, 37, 37,
-        37, 37, 39, 15, 33, 44, 37, 22,
-        2, 1, 5
+        37, 15, 1, 37, 1, 49, 1, 38,
+        38, 15, 1, 38, 27, 26, 24, 23,
+        22, 2, 1, 25, 25, 25, 1, 25,
+        26, 26, 26, 27, 27, 27, 27, 38,
+        48, 38, 9, 1, 1, 38, 38, 2,
+        1, 38, 38, 27, 26, 24, 23, 22,
+        2, 1, 25, 25, 25, 25, 26, 26,
+        26, 27, 27, 27, 27, 38, 48, 15,
+        1, 9, 1, 37, 48, 38, 2, 1,
+        22, 5
 };
 
 static const short _use_syllable_machine_index_offsets[] = {
-        0, 34, 50, 52, 86, 132, 134, 172,
-        210, 226, 228, 266, 304, 337, 357, 377,
-        397, 430, 463, 496, 534, 572, 610, 648,
-        686, 724, 762, 800, 840, 878, 888, 890,
-        892, 930, 968, 1006, 1039, 1059, 1079, 1099,
-        1132, 1165, 1198, 1236, 1274, 1312, 1350, 1388,
-        1426, 1464, 1502, 1542, 1558, 1592, 1637, 1675,
-        1698, 1701, 1703
+        0, 38, 54, 56, 94, 96, 146, 148,
+        187, 226, 242, 244, 283, 311, 338, 363,
+        387, 410, 413, 415, 441, 467, 493, 495,
+        521, 548, 575, 602, 630, 658, 686, 714,
+        753, 802, 841, 851, 853, 855, 894, 933,
+        936, 938, 977, 1016, 1044, 1071, 1096, 1120,
+        1143, 1146, 1148, 1174, 1200, 1226, 1252, 1279,
+        1306, 1333, 1361, 1389, 1417, 1445, 1484, 1533,
+        1549, 1551, 1561, 1563, 1601, 1650, 1689, 1692,
+        1694, 1717
 };
 
 static const char _use_syllable_machine_indicies[] = {
@@ -73,308 +79,320 @@
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        1, 0, 3, 2, 2, 2, 2, 2,
+        1, 0, 0, 0, 1, 0, 3, 2,
         2, 2, 2, 2, 2, 2, 2, 2,
-        4, 2, 3, 2, 6, 5, 5, 5,
+        2, 2, 2, 2, 4, 2, 3, 2,
+        6, 5, 5, 5, 5, 5, 5, 5,
         5, 5, 5, 5, 5, 5, 5, 5,
         5, 5, 5, 5, 5, 5, 5, 5,
         5, 5, 5, 5, 5, 5, 5, 5,
-        5, 5, 5, 5, 6, 5, 7, 8,
-        9, 7, 10, 8, 9, 9, 11, 9,
-        9, 3, 12, 9, 9, 13, 7, 7,
-        14, 15, 9, 9, 16, 17, 18, 19,
-        20, 21, 22, 16, 23, 24, 25, 26,
-        27, 28, 9, 29, 30, 31, 9, 9,
-        9, 32, 33, 9, 35, 34, 37, 36,
-        36, 38, 1, 36, 36, 39, 36, 36,
-        36, 36, 36, 40, 41, 42, 43, 44,
-        45, 46, 47, 41, 48, 40, 49, 50,
-        51, 52, 36, 53, 54, 55, 36, 36,
-        36, 36, 56, 36, 37, 36, 36, 38,
-        1, 36, 36, 39, 36, 36, 36, 36,
-        36, 57, 41, 42, 43, 44, 45, 46,
-        47, 41, 48, 49, 49, 50, 51, 52,
-        36, 53, 54, 55, 36, 36, 36, 36,
-        56, 36, 38, 58, 58, 58, 58, 58,
-        58, 58, 58, 58, 58, 58, 58, 58,
-        59, 58, 38, 58, 37, 36, 36, 38,
-        1, 36, 36, 39, 36, 36, 36, 36,
-        36, 36, 41, 42, 43, 44, 45, 46,
-        47, 41, 48, 49, 49, 50, 51, 52,
-        36, 53, 54, 55, 36, 36, 36, 36,
-        56, 36, 37, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        41, 42, 43, 44, 45, 36, 36, 36,
-        36, 36, 36, 50, 51, 52, 36, 53,
-        54, 55, 36, 36, 36, 36, 42, 36,
-        37, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 42,
-        43, 44, 45, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 53, 54, 55,
-        36, 37, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 43, 44, 45, 36, 37, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 44, 45,
-        36, 37, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 45, 36, 37, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 43, 44, 45,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 53, 54, 55, 36, 37, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 43, 44,
-        45, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 54, 55, 36, 37,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 43,
-        44, 45, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 55, 36,
-        37, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 42,
-        43, 44, 45, 36, 36, 36, 36, 36,
-        36, 50, 51, 52, 36, 53, 54, 55,
-        36, 36, 36, 36, 42, 36, 37, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 42, 43, 44,
-        45, 36, 36, 36, 36, 36, 36, 36,
-        51, 52, 36, 53, 54, 55, 36, 36,
-        36, 36, 42, 36, 37, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 42, 43, 44, 45, 36,
-        36, 36, 36, 36, 36, 36, 36, 52,
-        36, 53, 54, 55, 36, 36, 36, 36,
-        42, 36, 37, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        41, 42, 43, 44, 45, 36, 47, 41,
-        36, 36, 36, 50, 51, 52, 36, 53,
-        54, 55, 36, 36, 36, 36, 42, 36,
-        37, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 41, 42,
-        43, 44, 45, 36, 60, 41, 36, 36,
-        36, 50, 51, 52, 36, 53, 54, 55,
-        36, 36, 36, 36, 42, 36, 37, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 36, 36, 41, 42, 43, 44,
-        45, 36, 36, 41, 36, 36, 36, 50,
-        51, 52, 36, 53, 54, 55, 36, 36,
-        36, 36, 42, 36, 37, 36, 36, 36,
-        36, 36, 36, 36, 36, 36, 36, 36,
-        36, 36, 41, 42, 43, 44, 45, 46,
-        47, 41, 36, 36, 36, 50, 51, 52,
-        36, 53, 54, 55, 36, 36, 36, 36,
-        42, 36, 37, 36, 36, 38, 1, 36,
-        36, 39, 36, 36, 36, 36, 36, 36,
-        41, 42, 43, 44, 45, 46, 47, 41,
-        48, 36, 49, 50, 51, 52, 36, 53,
-        54, 55, 36, 36, 36, 36, 56, 36,
-        38, 58, 58, 58, 58, 58, 58, 37,
-        58, 58, 58, 58, 58, 58, 59, 58,
-        58, 58, 58, 58, 58, 58, 42, 43,
-        44, 45, 58, 58, 58, 58, 58, 58,
-        58, 58, 58, 58, 53, 54, 55, 58,
-        37, 36, 36, 38, 1, 36, 36, 39,
-        36, 36, 36, 36, 36, 36, 41, 42,
-        43, 44, 45, 46, 47, 41, 48, 40,
-        49, 50, 51, 52, 36, 53, 54, 55,
-        36, 36, 36, 36, 56, 36, 62, 61,
-        61, 61, 61, 61, 61, 61, 63, 61,
-        10, 64, 62, 61, 11, 65, 65, 3,
-        6, 65, 65, 66, 65, 65, 65, 65,
-        65, 67, 16, 17, 18, 19, 20, 21,
-        22, 16, 23, 25, 25, 26, 27, 28,
-        65, 29, 30, 31, 65, 65, 65, 65,
-        33, 65, 11, 65, 65, 3, 6, 65,
-        65, 66, 65, 65, 65, 65, 65, 65,
-        16, 17, 18, 19, 20, 21, 22, 16,
-        23, 25, 25, 26, 27, 28, 65, 29,
-        30, 31, 65, 65, 65, 65, 33, 65,
-        11, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 16, 17,
-        18, 19, 20, 65, 65, 65, 65, 65,
-        65, 26, 27, 28, 65, 29, 30, 31,
-        65, 65, 65, 65, 17, 65, 11, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 17, 18, 19,
-        20, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 29, 30, 31, 65, 11,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 18,
-        19, 20, 65, 11, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 19, 20, 65, 11,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 20, 65, 11, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 18, 19, 20, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        29, 30, 31, 65, 11, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 18, 19, 20, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 30, 31, 65, 11, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 18, 19, 20,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 31, 65, 11, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 17, 18, 19,
-        20, 65, 65, 65, 65, 65, 65, 26,
-        27, 28, 65, 29, 30, 31, 65, 65,
-        65, 65, 17, 65, 11, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 17, 18, 19, 20, 65,
-        65, 65, 65, 65, 65, 65, 27, 28,
-        65, 29, 30, 31, 65, 65, 65, 65,
-        17, 65, 11, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 17, 18, 19, 20, 65, 65, 65,
-        65, 65, 65, 65, 65, 28, 65, 29,
-        30, 31, 65, 65, 65, 65, 17, 65,
-        11, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 16, 17,
-        18, 19, 20, 65, 22, 16, 65, 65,
-        65, 26, 27, 28, 65, 29, 30, 31,
-        65, 65, 65, 65, 17, 65, 11, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 16, 17, 18, 19,
-        20, 65, 68, 16, 65, 65, 65, 26,
-        27, 28, 65, 29, 30, 31, 65, 65,
-        65, 65, 17, 65, 11, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 16, 17, 18, 19, 20, 65,
-        65, 16, 65, 65, 65, 26, 27, 28,
-        65, 29, 30, 31, 65, 65, 65, 65,
-        17, 65, 11, 65, 65, 65, 65, 65,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        16, 17, 18, 19, 20, 21, 22, 16,
-        65, 65, 65, 26, 27, 28, 65, 29,
-        30, 31, 65, 65, 65, 65, 17, 65,
-        11, 65, 65, 3, 6, 65, 65, 66,
-        65, 65, 65, 65, 65, 65, 16, 17,
-        18, 19, 20, 21, 22, 16, 23, 65,
-        25, 26, 27, 28, 65, 29, 30, 31,
-        65, 65, 65, 65, 33, 65, 3, 65,
-        65, 65, 65, 65, 65, 11, 65, 65,
-        65, 65, 65, 65, 4, 65, 65, 65,
-        65, 65, 65, 65, 17, 18, 19, 20,
-        65, 65, 65, 65, 65, 65, 65, 65,
-        65, 65, 29, 30, 31, 65, 3, 69,
-        69, 69, 69, 69, 69, 69, 69, 69,
-        69, 69, 69, 69, 4, 69, 6, 69,
-        69, 69, 69, 69, 69, 69, 69, 69,
-        69, 69, 69, 69, 69, 69, 69, 69,
-        69, 69, 69, 69, 69, 69, 69, 69,
-        69, 69, 69, 69, 69, 69, 6, 69,
-        8, 65, 65, 65, 8, 65, 65, 11,
-        65, 65, 3, 6, 65, 65, 66, 65,
-        65, 65, 65, 65, 65, 16, 17, 18,
-        19, 20, 21, 22, 16, 23, 24, 25,
-        26, 27, 28, 65, 29, 30, 31, 65,
-        65, 65, 65, 33, 65, 11, 65, 65,
-        3, 6, 65, 65, 66, 65, 65, 65,
-        65, 65, 65, 16, 17, 18, 19, 20,
-        21, 22, 16, 23, 24, 25, 26, 27,
-        28, 65, 29, 30, 31, 65, 65, 65,
-        65, 33, 65, 71, 70, 70, 70, 70,
-        70, 70, 70, 70, 70, 70, 70, 70,
-        70, 70, 70, 70, 70, 70, 70, 71,
-        72, 70, 71, 72, 70, 72, 70, 8,
-        69, 69, 69, 8, 69, 0
+        6, 5, 5, 5, 6, 5, 7, 5,
+        8, 9, 10, 8, 11, 12, 10, 10,
+        10, 10, 10, 3, 13, 14, 10, 15,
+        8, 8, 16, 17, 10, 10, 18, 19,
+        20, 21, 22, 23, 24, 18, 25, 26,
+        27, 28, 29, 30, 10, 31, 32, 33,
+        10, 34, 35, 36, 37, 38, 39, 40,
+        13, 10, 42, 41, 44, 1, 43, 43,
+        45, 43, 43, 43, 43, 43, 46, 47,
+        48, 49, 50, 51, 52, 53, 47, 54,
+        46, 55, 56, 57, 58, 43, 59, 60,
+        61, 43, 43, 43, 43, 62, 63, 64,
+        65, 1, 43, 44, 1, 43, 43, 45,
+        43, 43, 43, 43, 43, 66, 47, 48,
+        49, 50, 51, 52, 53, 47, 54, 55,
+        55, 56, 57, 58, 43, 59, 60, 61,
+        43, 43, 43, 43, 62, 63, 64, 65,
+        1, 43, 44, 67, 67, 67, 67, 67,
+        67, 67, 67, 67, 67, 67, 67, 67,
+        68, 67, 44, 67, 44, 1, 43, 43,
+        45, 43, 43, 43, 43, 43, 43, 47,
+        48, 49, 50, 51, 52, 53, 47, 54,
+        55, 55, 56, 57, 58, 43, 59, 60,
+        61, 43, 43, 43, 43, 62, 63, 64,
+        65, 1, 43, 47, 48, 49, 50, 51,
+        43, 43, 43, 43, 43, 43, 56, 57,
+        58, 43, 59, 60, 61, 43, 43, 43,
+        43, 48, 63, 64, 65, 69, 43, 48,
+        49, 50, 51, 43, 43, 43, 43, 43,
+        43, 43, 43, 43, 43, 59, 60, 61,
+        43, 43, 43, 43, 43, 63, 64, 65,
+        69, 43, 49, 50, 51, 43, 43, 43,
+        43, 43, 43, 43, 43, 43, 43, 43,
+        43, 43, 43, 43, 43, 43, 43, 63,
+        64, 65, 43, 50, 51, 43, 43, 43,
+        43, 43, 43, 43, 43, 43, 43, 43,
+        43, 43, 43, 43, 43, 43, 43, 63,
+        64, 65, 43, 51, 43, 43, 43, 43,
+        43, 43, 43, 43, 43, 43, 43, 43,
+        43, 43, 43, 43, 43, 43, 63, 64,
+        65, 43, 63, 64, 43, 64, 43, 49,
+        50, 51, 43, 43, 43, 43, 43, 43,
+        43, 43, 43, 43, 59, 60, 61, 43,
+        43, 43, 43, 43, 63, 64, 65, 69,
+        43, 49, 50, 51, 43, 43, 43, 43,
+        43, 43, 43, 43, 43, 43, 43, 60,
+        61, 43, 43, 43, 43, 43, 63, 64,
+        65, 69, 43, 49, 50, 51, 43, 43,
+        43, 43, 43, 43, 43, 43, 43, 43,
+        43, 43, 61, 43, 43, 43, 43, 43,
+        63, 64, 65, 69, 43, 71, 70, 49,
+        50, 51, 43, 43, 43, 43, 43, 43,
+        43, 43, 43, 43, 43, 43, 43, 43,
+        43, 43, 43, 43, 63, 64, 65, 69,
+        43, 48, 49, 50, 51, 43, 43, 43,
+        43, 43, 43, 56, 57, 58, 43, 59,
+        60, 61, 43, 43, 43, 43, 48, 63,
+        64, 65, 69, 43, 48, 49, 50, 51,
+        43, 43, 43, 43, 43, 43, 43, 57,
+        58, 43, 59, 60, 61, 43, 43, 43,
+        43, 48, 63, 64, 65, 69, 43, 48,
+        49, 50, 51, 43, 43, 43, 43, 43,
+        43, 43, 43, 58, 43, 59, 60, 61,
+        43, 43, 43, 43, 48, 63, 64, 65,
+        69, 43, 47, 48, 49, 50, 51, 43,
+        53, 47, 43, 43, 43, 56, 57, 58,
+        43, 59, 60, 61, 43, 43, 43, 43,
+        48, 63, 64, 65, 69, 43, 47, 48,
+        49, 50, 51, 43, 72, 47, 43, 43,
+        43, 56, 57, 58, 43, 59, 60, 61,
+        43, 43, 43, 43, 48, 63, 64, 65,
+        69, 43, 47, 48, 49, 50, 51, 43,
+        43, 47, 43, 43, 43, 56, 57, 58,
+        43, 59, 60, 61, 43, 43, 43, 43,
+        48, 63, 64, 65, 69, 43, 47, 48,
+        49, 50, 51, 52, 53, 47, 43, 43,
+        43, 56, 57, 58, 43, 59, 60, 61,
+        43, 43, 43, 43, 48, 63, 64, 65,
+        69, 43, 44, 1, 43, 43, 45, 43,
+        43, 43, 43, 43, 43, 47, 48, 49,
+        50, 51, 52, 53, 47, 54, 43, 55,
+        56, 57, 58, 43, 59, 60, 61, 43,
+        43, 43, 43, 62, 63, 64, 65, 1,
+        43, 44, 67, 67, 67, 67, 67, 67,
+        67, 67, 67, 67, 67, 67, 67, 68,
+        67, 67, 67, 67, 67, 67, 67, 48,
+        49, 50, 51, 67, 67, 67, 67, 67,
+        67, 67, 67, 67, 67, 59, 60, 61,
+        67, 67, 67, 67, 67, 63, 64, 65,
+        69, 67, 44, 1, 43, 43, 45, 43,
+        43, 43, 43, 43, 43, 47, 48, 49,
+        50, 51, 52, 53, 47, 54, 46, 55,
+        56, 57, 58, 43, 59, 60, 61, 43,
+        43, 43, 43, 62, 63, 64, 65, 1,
+        43, 74, 73, 73, 73, 73, 73, 73,
+        73, 75, 73, 11, 76, 74, 73, 44,
+        1, 43, 43, 45, 43, 43, 43, 43,
+        43, 77, 47, 48, 49, 50, 51, 52,
+        53, 47, 54, 46, 55, 56, 57, 58,
+        43, 59, 60, 61, 43, 78, 79, 43,
+        62, 63, 64, 65, 1, 43, 44, 1,
+        43, 43, 45, 43, 43, 43, 43, 43,
+        43, 47, 48, 49, 50, 51, 52, 53,
+        47, 54, 46, 55, 56, 57, 58, 43,
+        59, 60, 61, 43, 78, 79, 43, 62,
+        63, 64, 65, 1, 43, 78, 79, 80,
+        79, 80, 3, 6, 81, 81, 82, 81,
+        81, 81, 81, 81, 83, 18, 19, 20,
+        21, 22, 23, 24, 18, 25, 27, 27,
+        28, 29, 30, 81, 31, 32, 33, 81,
+        81, 81, 81, 37, 38, 39, 40, 6,
+        81, 3, 6, 81, 81, 82, 81, 81,
+        81, 81, 81, 81, 18, 19, 20, 21,
+        22, 23, 24, 18, 25, 27, 27, 28,
+        29, 30, 81, 31, 32, 33, 81, 81,
+        81, 81, 37, 38, 39, 40, 6, 81,
+        18, 19, 20, 21, 22, 81, 81, 81,
+        81, 81, 81, 28, 29, 30, 81, 31,
+        32, 33, 81, 81, 81, 81, 19, 38,
+        39, 40, 84, 81, 19, 20, 21, 22,
+        81, 81, 81, 81, 81, 81, 81, 81,
+        81, 81, 31, 32, 33, 81, 81, 81,
+        81, 81, 38, 39, 40, 84, 81, 20,
+        21, 22, 81, 81, 81, 81, 81, 81,
+        81, 81, 81, 81, 81, 81, 81, 81,
+        81, 81, 81, 81, 38, 39, 40, 81,
+        21, 22, 81, 81, 81, 81, 81, 81,
+        81, 81, 81, 81, 81, 81, 81, 81,
+        81, 81, 81, 81, 38, 39, 40, 81,
+        22, 81, 81, 81, 81, 81, 81, 81,
+        81, 81, 81, 81, 81, 81, 81, 81,
+        81, 81, 81, 38, 39, 40, 81, 38,
+        39, 81, 39, 81, 20, 21, 22, 81,
+        81, 81, 81, 81, 81, 81, 81, 81,
+        81, 31, 32, 33, 81, 81, 81, 81,
+        81, 38, 39, 40, 84, 81, 20, 21,
+        22, 81, 81, 81, 81, 81, 81, 81,
+        81, 81, 81, 81, 32, 33, 81, 81,
+        81, 81, 81, 38, 39, 40, 84, 81,
+        20, 21, 22, 81, 81, 81, 81, 81,
+        81, 81, 81, 81, 81, 81, 81, 33,
+        81, 81, 81, 81, 81, 38, 39, 40,
+        84, 81, 20, 21, 22, 81, 81, 81,
+        81, 81, 81, 81, 81, 81, 81, 81,
+        81, 81, 81, 81, 81, 81, 81, 38,
+        39, 40, 84, 81, 19, 20, 21, 22,
+        81, 81, 81, 81, 81, 81, 28, 29,
+        30, 81, 31, 32, 33, 81, 81, 81,
+        81, 19, 38, 39, 40, 84, 81, 19,
+        20, 21, 22, 81, 81, 81, 81, 81,
+        81, 81, 29, 30, 81, 31, 32, 33,
+        81, 81, 81, 81, 19, 38, 39, 40,
+        84, 81, 19, 20, 21, 22, 81, 81,
+        81, 81, 81, 81, 81, 81, 30, 81,
+        31, 32, 33, 81, 81, 81, 81, 19,
+        38, 39, 40, 84, 81, 18, 19, 20,
+        21, 22, 81, 24, 18, 81, 81, 81,
+        28, 29, 30, 81, 31, 32, 33, 81,
+        81, 81, 81, 19, 38, 39, 40, 84,
+        81, 18, 19, 20, 21, 22, 81, 85,
+        18, 81, 81, 81, 28, 29, 30, 81,
+        31, 32, 33, 81, 81, 81, 81, 19,
+        38, 39, 40, 84, 81, 18, 19, 20,
+        21, 22, 81, 81, 18, 81, 81, 81,
+        28, 29, 30, 81, 31, 32, 33, 81,
+        81, 81, 81, 19, 38, 39, 40, 84,
+        81, 18, 19, 20, 21, 22, 23, 24,
+        18, 81, 81, 81, 28, 29, 30, 81,
+        31, 32, 33, 81, 81, 81, 81, 19,
+        38, 39, 40, 84, 81, 3, 6, 81,
+        81, 82, 81, 81, 81, 81, 81, 81,
+        18, 19, 20, 21, 22, 23, 24, 18,
+        25, 81, 27, 28, 29, 30, 81, 31,
+        32, 33, 81, 81, 81, 81, 37, 38,
+        39, 40, 6, 81, 3, 81, 81, 81,
+        81, 81, 81, 81, 81, 81, 81, 81,
+        81, 81, 4, 81, 81, 81, 81, 81,
+        81, 81, 19, 20, 21, 22, 81, 81,
+        81, 81, 81, 81, 81, 81, 81, 81,
+        31, 32, 33, 81, 81, 81, 81, 81,
+        38, 39, 40, 84, 81, 3, 86, 86,
+        86, 86, 86, 86, 86, 86, 86, 86,
+        86, 86, 86, 4, 86, 87, 81, 14,
+        81, 81, 81, 81, 81, 81, 81, 88,
+        81, 14, 81, 6, 86, 86, 86, 86,
+        86, 86, 86, 86, 86, 86, 86, 86,
+        86, 86, 86, 86, 86, 86, 86, 86,
+        86, 86, 86, 86, 86, 86, 86, 86,
+        86, 86, 86, 6, 86, 86, 86, 6,
+        86, 9, 81, 81, 81, 9, 81, 81,
+        81, 81, 81, 3, 6, 14, 81, 82,
+        81, 81, 81, 81, 81, 81, 18, 19,
+        20, 21, 22, 23, 24, 18, 25, 26,
+        27, 28, 29, 30, 81, 31, 32, 33,
+        81, 34, 35, 81, 37, 38, 39, 40,
+        6, 81, 3, 6, 81, 81, 82, 81,
+        81, 81, 81, 81, 81, 18, 19, 20,
+        21, 22, 23, 24, 18, 25, 26, 27,
+        28, 29, 30, 81, 31, 32, 33, 81,
+        81, 81, 81, 37, 38, 39, 40, 6,
+        81, 34, 35, 81, 35, 81, 78, 80,
+        80, 80, 80, 80, 80, 80, 80, 80,
+        80, 80, 80, 80, 80, 80, 80, 80,
+        80, 80, 78, 79, 80, 9, 86, 86,
+        86, 9, 86, 0
 };
 
 static const char _use_syllable_machine_trans_targs[] = {
-        4, 8, 4, 32, 2, 4, 1, 5,
-        6, 4, 29, 4, 51, 52, 53, 55,
-        34, 35, 36, 37, 38, 45, 46, 48,
-        54, 49, 42, 43, 44, 39, 40, 41,
-        58, 50, 4, 4, 4, 4, 7, 0,
-        28, 11, 12, 13, 14, 15, 22, 23,
-        25, 26, 19, 20, 21, 16, 17, 18,
-        27, 10, 4, 9, 24, 4, 30, 31,
-        4, 4, 3, 33, 47, 4, 4, 56,
-        57
+        5, 9, 5, 41, 2, 5, 1, 53,
+        6, 7, 5, 34, 37, 63, 64, 67,
+        68, 72, 43, 44, 45, 46, 47, 57,
+        58, 60, 69, 61, 54, 55, 56, 50,
+        51, 52, 70, 71, 73, 62, 48, 49,
+        5, 5, 5, 5, 8, 0, 33, 12,
+        13, 14, 15, 16, 27, 28, 30, 31,
+        24, 25, 26, 19, 20, 21, 32, 17,
+        18, 5, 11, 5, 10, 22, 5, 23,
+        29, 5, 35, 36, 5, 38, 39, 40,
+        5, 5, 3, 42, 4, 59, 5, 65,
+        66
 };
 
 static const char _use_syllable_machine_trans_actions[] = {
-        1, 0, 2, 3, 0, 4, 0, 0,
-        7, 8, 0, 9, 10, 10, 3, 0,
+        1, 0, 2, 3, 0, 4, 0, 5,
+        0, 5, 8, 0, 5, 9, 0, 9,
+        3, 0, 5, 5, 0, 0, 0, 5,
+        5, 5, 3, 3, 5, 5, 5, 5,
+        5, 5, 0, 0, 0, 3, 0, 0,
+        10, 11, 12, 13, 5, 0, 5, 0,
+        0, 0, 0, 0, 0, 0, 0, 5,
         0, 0, 0, 0, 0, 0, 0, 0,
-        3, 3, 0, 0, 0, 0, 0, 0,
-        0, 3, 11, 12, 13, 14, 7, 0,
-        7, 0, 0, 0, 0, 0, 0, 0,
-        0, 7, 0, 0, 0, 0, 0, 0,
-        0, 7, 15, 0, 0, 16, 0, 0,
-        17, 18, 0, 3, 0, 19, 20, 0,
+        0, 14, 5, 15, 0, 0, 16, 0,
+        0, 17, 0, 0, 18, 5, 0, 0,
+        19, 20, 0, 3, 0, 5, 21, 0,
         0
 };
 
 static const char _use_syllable_machine_to_state_actions[] = {
-        0, 0, 0, 0, 5, 0, 0, 0,
+        0, 0, 0, 0, 0, 6, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0
 };
 
 static const char _use_syllable_machine_from_state_actions[] = {
-        0, 0, 0, 0, 6, 0, 0, 0,
+        0, 0, 0, 0, 0, 7, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
         0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0
 };
 
 static const short _use_syllable_machine_eof_trans[] = {
-        1, 3, 3, 6, 0, 35, 37, 37,
-        59, 59, 37, 37, 37, 37, 37, 37,
-        37, 37, 37, 37, 37, 37, 37, 37,
-        37, 37, 37, 59, 37, 62, 65, 62,
-        66, 66, 66, 66, 66, 66, 66, 66,
-        66, 66, 66, 66, 66, 66, 66, 66,
-        66, 66, 66, 70, 70, 66, 66, 71,
-        71, 71, 70
+        1, 3, 3, 6, 6, 0, 42, 44,
+        44, 68, 68, 44, 44, 44, 44, 44,
+        44, 44, 44, 44, 44, 44, 71, 44,
+        44, 44, 44, 44, 44, 44, 44, 44,
+        68, 44, 74, 77, 74, 44, 44, 81,
+        81, 82, 82, 82, 82, 82, 82, 82,
+        82, 82, 82, 82, 82, 82, 82, 82,
+        82, 82, 82, 82, 82, 82, 82, 87,
+        82, 82, 82, 87, 82, 82, 82, 82,
+        81, 87
 };
 
-static const int use_syllable_machine_start = 4;
-static const int use_syllable_machine_first_final = 4;
+static const int use_syllable_machine_start = 5;
+static const int use_syllable_machine_first_final = 5;
 static const int use_syllable_machine_error = -1;
 
-static const int use_syllable_machine_en_main = 4;
+static const int use_syllable_machine_en_main = 5;
 
 
 #line 38 "hb-ot-shape-complex-use-machine.rl"
 
 
 
-#line 143 "hb-ot-shape-complex-use-machine.rl"
+#line 162 "hb-ot-shape-complex-use-machine.rl"
 
 
 #define found_syllable(syllable_type) \
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
     for (unsigned int i = ts; i < te; i++) \
-      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+      info[i].syllable() = (syllable_serial << 4) | use_##syllable_type; \
     syllable_serial++; \
     if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (hb_buffer_t *buffer)
+find_syllables_use (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act;
   int cs;
   hb_glyph_info_t *info = buffer->info;
 
-#line 378 "hb-ot-shape-complex-use-machine.hh"
+#line 396 "hb-ot-shape-complex-use-machine.hh"
         {
         cs = use_syllable_machine_start;
         ts = 0;
@@ -382,7 +400,7 @@
         act = 0;
         }
 
-#line 163 "hb-ot-shape-complex-use-machine.rl"
+#line 182 "hb-ot-shape-complex-use-machine.rl"
 
 
   p = 0;
@@ -390,7 +408,7 @@
 
   unsigned int syllable_serial = 1;
 
-#line 394 "hb-ot-shape-complex-use-machine.hh"
+#line 412 "hb-ot-shape-complex-use-machine.hh"
         {
         int _slen;
         int _trans;
@@ -400,11 +418,11 @@
                 goto _test_eof;
 _resume:
         switch ( _use_syllable_machine_from_state_actions[cs] ) {
-        case 6:
+        case 7:
 #line 1 "NONE"
         {ts = p;}
         break;
-#line 408 "hb-ot-shape-complex-use-machine.hh"
+#line 426 "hb-ot-shape-complex-use-machine.hh"
         }
 
         _keys = _use_syllable_machine_trans_keys + (cs<<1);
@@ -422,73 +440,77 @@
                 goto _again;
 
         switch ( _use_syllable_machine_trans_actions[_trans] ) {
-        case 7:
+        case 5:
 #line 1 "NONE"
         {te = p+1;}
         break;
         case 12:
-#line 132 "hb-ot-shape-complex-use-machine.rl"
+#line 150 "hb-ot-shape-complex-use-machine.rl"
         {te = p+1;{ found_syllable (independent_cluster); }}
         break;
         case 14:
-#line 134 "hb-ot-shape-complex-use-machine.rl"
+#line 153 "hb-ot-shape-complex-use-machine.rl"
         {te = p+1;{ found_syllable (standard_cluster); }}
         break;
-        case 9:
-#line 138 "hb-ot-shape-complex-use-machine.rl"
+        case 10:
+#line 157 "hb-ot-shape-complex-use-machine.rl"
         {te = p+1;{ found_syllable (broken_cluster); }}
         break;
         case 8:
-#line 139 "hb-ot-shape-complex-use-machine.rl"
+#line 158 "hb-ot-shape-complex-use-machine.rl"
         {te = p+1;{ found_syllable (non_cluster); }}
         break;
         case 11:
-#line 132 "hb-ot-shape-complex-use-machine.rl"
+#line 150 "hb-ot-shape-complex-use-machine.rl"
         {te = p;p--;{ found_syllable (independent_cluster); }}
         break;
         case 15:
-#line 133 "hb-ot-shape-complex-use-machine.rl"
+#line 151 "hb-ot-shape-complex-use-machine.rl"
         {te = p;p--;{ found_syllable (virama_terminated_cluster); }}
         break;
+        case 16:
+#line 152 "hb-ot-shape-complex-use-machine.rl"
+        {te = p;p--;{ found_syllable (sakot_terminated_cluster); }}
+        break;
         case 13:
-#line 134 "hb-ot-shape-complex-use-machine.rl"
+#line 153 "hb-ot-shape-complex-use-machine.rl"
         {te = p;p--;{ found_syllable (standard_cluster); }}
         break;
-        case 17:
-#line 135 "hb-ot-shape-complex-use-machine.rl"
+        case 18:
+#line 154 "hb-ot-shape-complex-use-machine.rl"
         {te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }}
         break;
-        case 16:
-#line 136 "hb-ot-shape-complex-use-machine.rl"
+        case 17:
+#line 155 "hb-ot-shape-complex-use-machine.rl"
         {te = p;p--;{ found_syllable (numeral_cluster); }}
         break;
-        case 20:
-#line 137 "hb-ot-shape-complex-use-machine.rl"
+        case 19:
+#line 156 "hb-ot-shape-complex-use-machine.rl"
         {te = p;p--;{ found_syllable (symbol_cluster); }}
         break;
-        case 18:
-#line 138 "hb-ot-shape-complex-use-machine.rl"
+        case 20:
+#line 157 "hb-ot-shape-complex-use-machine.rl"
         {te = p;p--;{ found_syllable (broken_cluster); }}
         break;
-        case 19:
-#line 139 "hb-ot-shape-complex-use-machine.rl"
+        case 21:
+#line 158 "hb-ot-shape-complex-use-machine.rl"
         {te = p;p--;{ found_syllable (non_cluster); }}
         break;
         case 1:
-#line 134 "hb-ot-shape-complex-use-machine.rl"
+#line 153 "hb-ot-shape-complex-use-machine.rl"
         {{p = ((te))-1;}{ found_syllable (standard_cluster); }}
         break;
         case 4:
-#line 138 "hb-ot-shape-complex-use-machine.rl"
+#line 157 "hb-ot-shape-complex-use-machine.rl"
         {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
         break;
         case 2:
 #line 1 "NONE"
         {       switch( act ) {
-        case 7:
+        case 8:
         {{p = ((te))-1;} found_syllable (broken_cluster); }
         break;
-        case 8:
+        case 9:
         {{p = ((te))-1;} found_syllable (non_cluster); }
         break;
         }
@@ -497,25 +519,25 @@
         case 3:
 #line 1 "NONE"
         {te = p+1;}
-#line 138 "hb-ot-shape-complex-use-machine.rl"
-        {act = 7;}
-        break;
-        case 10:
-#line 1 "NONE"
-        {te = p+1;}
-#line 139 "hb-ot-shape-complex-use-machine.rl"
+#line 157 "hb-ot-shape-complex-use-machine.rl"
         {act = 8;}
         break;
-#line 510 "hb-ot-shape-complex-use-machine.hh"
+        case 9:
+#line 1 "NONE"
+        {te = p+1;}
+#line 158 "hb-ot-shape-complex-use-machine.rl"
+        {act = 9;}
+        break;
+#line 532 "hb-ot-shape-complex-use-machine.hh"
         }
 
 _again:
         switch ( _use_syllable_machine_to_state_actions[cs] ) {
-        case 5:
+        case 6:
 #line 1 "NONE"
         {ts = 0;}
         break;
-#line 519 "hb-ot-shape-complex-use-machine.hh"
+#line 541 "hb-ot-shape-complex-use-machine.hh"
         }
 
         if ( ++p != pe )
@@ -531,7 +553,7 @@
 
         }
 
-#line 171 "hb-ot-shape-complex-use-machine.rl"
+#line 190 "hb-ot-shape-complex-use-machine.rl"
 
 }
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-table.cc
index 9411e28..910b01a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-table.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-table.cc
@@ -6,15 +6,19 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-11.0.0.txt
- * # Date: 2018-05-21, 18:33:00 GMT [KW, RP]
- * # IndicPositionalCategory-11.0.0.txt
- * # Date: 2018-02-05, 16:21:00 GMT [KW, RP]
- * # Blocks-11.0.0.txt
- * # Date: 2017-10-16, 24:39:00 GMT [KW]
+ * # IndicSyllabicCategory-13.0.0.txt
+ * # Date: 2019-07-22, 19:55:00 GMT [KW, RP]
+ * # IndicPositionalCategory-13.0.0.txt
+ * # Date: 2019-07-23, 00:01:00 GMT [KW, RP]
+ * # Blocks-13.0.0.txt
+ * # Date: 2019-07-10, 19:06:00 GMT [KW]
  * UnicodeData.txt does not have a header.
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-use.hh"
 
 #pragma GCC diagnostic push
@@ -22,7 +26,6 @@
 #define B       USE_B   /* BASE */
 #define CGJ     USE_CGJ /* CGJ */
 #define CS      USE_CS  /* CONS_WITH_STACKER */
-#define FM      USE_FM  /* CONS_FINAL_MOD */
 #define GB      USE_GB  /* BASE_OTHER */
 #define H       USE_H   /* HALANT */
 #define HN      USE_HN  /* HALANT_NUM */
@@ -34,29 +37,33 @@
 #define Rsv     USE_Rsv /* Reserved */
 #define S       USE_S   /* SYM */
 #define SUB     USE_SUB /* CONS_SUB */
+#define Sk      USE_Sk  /* SAKOT */
 #define VS      USE_VS  /* VARIATION_SELECTOR */
 #define WJ      USE_WJ  /* Word_Joiner */
 #define ZWJ     USE_ZWJ /* ZWJ */
 #define ZWNJ    USE_ZWNJ        /* ZWNJ */
-#define CMBlw   USE_CMBlw
 #define CMAbv   USE_CMAbv
+#define CMBlw   USE_CMBlw
+#define FAbv    USE_FAbv
 #define FBlw    USE_FBlw
 #define FPst    USE_FPst
-#define FAbv    USE_FAbv
-#define MPre    USE_MPre
+#define FMAbv   USE_FMAbv
+#define FMBlw   USE_FMBlw
+#define FMPst   USE_FMPst
+#define MAbv    USE_MAbv
 #define MBlw    USE_MBlw
 #define MPst    USE_MPst
-#define MAbv    USE_MAbv
-#define SMBlw   USE_SMBlw
+#define MPre    USE_MPre
 #define SMAbv   USE_SMAbv
-#define VPre    USE_VPre
+#define SMBlw   USE_SMBlw
+#define VAbv    USE_VAbv
 #define VBlw    USE_VBlw
 #define VPst    USE_VPst
-#define VAbv    USE_VAbv
-#define VMPre   USE_VMPre
+#define VPre    USE_VPre
+#define VMAbv   USE_VMAbv
 #define VMBlw   USE_VMBlw
 #define VMPst   USE_VMPst
-#define VMAbv   USE_VMAbv
+#define VMPre   USE_VMPre
 #pragma GCC diagnostic pop
 
 static const USE_TABLE_ELEMENT_TYPE use_table[] = {
@@ -75,7 +82,7 @@
   /* Latin-1 Supplement */
 
   /* 00A0 */    GB,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 00B0 */     O,     O,    FM,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 00B0 */     O,     O, FMPst, FMPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 00C0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 00D0 */     O,     O,     O,     O,     O,     O,     O,    GB,
 
@@ -108,7 +115,7 @@
   /* 09C0 */  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VPre,  VPre,     O,     O,  VPst,  VPst,     H,   IND,     O,
   /* 09D0 */     O,     O,     O,     O,     O,     O,     O,  VPst,     O,     O,     O,     O,     B,     B,     O,     B,
   /* 09E0 */     B,     B,  VBlw,  VBlw,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 09F0 */     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     O,    FM,     O,
+  /* 09F0 */     B,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     B,     O, FMAbv,     O,
 
   /* Gurmukhi */
 
@@ -139,7 +146,7 @@
   /* 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,  VPst,     O,     O,  VPst,  VPst,     H,     O,     O,
-  /* 0B50 */     O,     O,     O,     O,     O,     O,  VAbv,  VAbv,     O,     O,     O,     O,     B,     B,     O,     B,
+  /* 0B50 */     O,     O,     O,     O,     O,  VAbv,  VAbv,  VAbv,     O,     O,     O,     O,     B,     B,     O,     B,
   /* 0B60 */     B,     B,  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,
 
@@ -167,7 +174,7 @@
 
   /* Kannada */
 
-  /* 0C80 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 0C80 */     B, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
   /* 0C90 */     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 0CA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
   /* 0CB0 */     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     O,     O, CMBlw,     B,  VPst,  VAbv,
@@ -178,7 +185,7 @@
 
   /* Malayalam */
 
-  /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
+  /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,
   /* 0D10 */     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 0D20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 0D30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VAbv,  VAbv,     B,  VPst,  VPst,
@@ -189,7 +196,7 @@
 
   /* Sinhala */
 
-  /* 0D80 */     O,     O, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 0D80 */     O, VMAbv, VMPst, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 0D90 */     B,     B,     B,     B,     B,     B,     B,     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,
@@ -204,7 +211,7 @@
   /* Tibetan */
                                                                       VBlw,  VBlw,     O,     O,     O,     O,     O,     O,
   /* 0F20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 0F30 */     B,     B,     B,     B,     O,    FM,     O,    FM,     O, CMAbv,     O,     O,     O,     O,  VPst,  VPre,
+  /* 0F30 */     B,     B,     B,     B,     O, FMBlw,     O, FMBlw,     O, CMAbv,     O,     O,     O,     O,  VPst,  VPre,
   /* 0F40 */     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,
   /* 0F50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 0F60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,
@@ -213,7 +220,7 @@
   /* 0F90 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
   /* 0FA0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
   /* 0FB0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,     O,     O,
-  /* 0FC0 */     O,     O,     O,     O,     O,     O,    FM,     O,
+  /* 0FC0 */     O,     O,     O,     O,     O,     O, FMBlw,     O,
 
 #define use_offset_0x1000u 1536
 
@@ -260,8 +267,8 @@
   /* 1790 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 17A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 17B0 */     B,     B,     B,     B,     O,     O,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VPst,  VPst,
-  /* 17C0 */  VPst,  VPre,  VPre,  VPre,  VPst,  VPst, VMAbv, VMPst,  VPst, VMAbv, VMAbv,    FM,  FAbv, CMAbv,    FM,    FM,
-  /* 17D0 */    FM,  VAbv,     H,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     B,  VAbv,     O,     O,
+  /* 17C0 */  VPst,  VPre,  VPre,  VPre,  VPst,  VPst, VMAbv, VMPst,  VPst, VMAbv, VMAbv, FMAbv,  FAbv, CMAbv, FMAbv, FMAbv,
+  /* 17D0 */ FMAbv,  VAbv,     H, FMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     B, FMAbv,     O,     O,
   /* 17E0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
 #define use_offset_0x1900u 1936
@@ -272,7 +279,7 @@
   /* 1900 */    GB,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1910 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,
   /* 1920 */  VAbv,  VAbv,  VBlw,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,   SUB,   SUB,   SUB,     O,     O,     O,     O,
-  /* 1930 */  FPst,  FPst, VMBlw,  FPst,  FPst,  FPst,  FPst,  FPst,  FPst,  FBlw,  VAbv,    FM,     O,     O,     O,     O,
+  /* 1930 */  FPst,  FPst, VMBlw,  FPst,  FPst,  FPst,  FPst,  FPst,  FPst,  FBlw,  VAbv, FMBlw,     O,     O,     O,     O,
   /* 1940 */     O,     O,     O,     O,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
 
   /* Tai Le */
@@ -288,7 +295,7 @@
   /* 19A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
   /* 19B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 19C0 */     B,     B,     B,     B,     B,     B,     B,     B, VMPst, VMPst,     O,     O,     O,     O,     O,     O,
-  /* 19D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+  /* 19D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,
   /* 19E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 19F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
@@ -302,9 +309,9 @@
   /* 1A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1A30 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1A40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1A50 */     B,     B,     B,     B,     B,  MPre,  MBlw,   SUB,  FAbv,  FAbv,  FAbv,   SUB,   SUB,   SUB,   SUB,     O,
-  /* 1A60 */     H,  VPst,  VAbv,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VAbv,  VBlw,  VPst,  VPre,  VPre,
-  /* 1A70 */  VPre,  VPre,  VPre,  VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,  VAbv,    FM,    FM,     O,     O,  FBlw,
+  /* 1A50 */     B,     B,     B,     B,     B,  MPre,  MBlw,   SUB,  FAbv,  FAbv,  MAbv,   SUB,   SUB,   SUB,   SUB,     O,
+  /* 1A60 */    Sk,  VPst,  VAbv,  VPst,  VPst,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,  VBlw,  VAbv,  VBlw,  VPst,  VPre,  VPre,
+  /* 1A70 */  VPre,  VPre,  VPre,  VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,  VAbv, FMAbv, FMAbv,     O,     O, FMBlw,
   /* 1A80 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
   /* 1A90 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
@@ -318,8 +325,8 @@
   /* 1B20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1B30 */     B,     B,     B,     B, CMAbv,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPre,  VPre,
   /* 1B40 */  VPst,  VPst,  VAbv,  VAbv,     H,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,
-  /* 1B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
-  /* 1B60 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
+  /* 1B50 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,    GB,    GB,     O,     O,    GB,
+  /* 1B60 */     O,     S,    GB,     S,     S,     S,     S,     S,    GB,     S,     S, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
   /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Sundanese */
@@ -340,8 +347,8 @@
 
   /* 1C00 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 1C10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 1C20 */     B,     B,     B,     B,   SUB,   SUB,  VPst,  VPre,  VPre,  VPst,  VPst,  VPst,  VBlw,  FAbv,  FAbv,  FAbv,
-  /* 1C30 */  FAbv,  FAbv,  FAbv,  FAbv, VMPre, VMPre,    FM, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 1C20 */     B,     B,     B,     B,   SUB,   SUB,  VPst,  VPre,  VPre,  VPre,  VPst,  VPst,  VBlw,  FAbv,  FAbv,  FAbv,
+  /* 1C30 */  FAbv,  FAbv,  FAbv,  FAbv, VMPre, VMPre, FMAbv, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 1C40 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     B,     B,     B,
 
 #define use_offset_0x1cd0u 2688
@@ -351,13 +358,13 @@
 
   /* 1CD0 */ VMAbv, VMAbv, VMAbv,     O, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMAbv, VMAbv, VMBlw, VMBlw, VMBlw, VMBlw,
   /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw,     O,     O,     O,     O, VMBlw,     O,     O,
-  /* 1CF0 */     O,     O, VMPst, VMPst, VMAbv,    CS,    CS, VMPst, VMAbv, VMAbv,     O,     O,     O,     O,     O,     O,
+  /* 1CF0 */     O,     O,   IND,   IND, VMAbv,    CS,    CS, VMPst, VMAbv, VMAbv,    GB,     O,     O,     O,     O,     O,
 
 #define use_offset_0x1df8u 2736
 
 
   /* Combining Diacritical Marks Supplement */
-                                                                         O,     O,     O,    FM,     O,     O,     O,     O,
+                                                                         O,     O,     O, FMAbv,     O,     O,     O,     O,
 
 #define use_offset_0x2008u 2744
 
@@ -372,8 +379,8 @@
 
   /* Superscripts and Subscripts */
 
-  /* 2070 */     O,     O,     O,     O,    FM,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 2080 */     O,     O,    FM,    FM,    FM,     O,     O,     O,
+  /* 2070 */     O,     O,     O,     O, FMPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 2080 */     O,     O, FMPst, FMPst, FMPst,     O,     O,     O,
 
 #define use_offset_0x20f0u 2800
 
@@ -393,9 +400,9 @@
 
   /* Syloti Nagri */
 
-  /* A800 */     B,     B,     O,     B,     B,     B,  VAbv,     B,     B,     B,     B, VMAbv,     B,     B,     B,     B,
+  /* A800 */     B,     B,  VAbv,     B,     B,     B,     H,     B,     B,     B,     B, VMAbv,     B,     B,     B,     B,
   /* A810 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A820 */     B,     B,     B,  VPst,  VPst,  VBlw,  VAbv,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* A820 */     B,     B,     B,  VPst,  VPst,  VBlw,  VAbv,  VPst,     O,     O,     O,     O,  VBlw,     O,     O,     O,
   /* A830 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Phags-pa */
@@ -438,7 +445,7 @@
   /* A980 */ VMAbv, VMAbv,  FAbv, VMPst,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A990 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* A9A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* A9B0 */     B,     B,     B, CMAbv,  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VPre,  VAbv,   SUB,  MPst,  MBlw,
+  /* A9B0 */     B,     B,     B, CMAbv,  VPst,  VPst,  VAbv,  VAbv,  VBlw,  VBlw,  VPre,  VPre,  VAbv,  MBlw,  MBlw,  MBlw,
   /* A9C0 */     H,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* A9D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
@@ -533,7 +540,7 @@
   /* 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,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VPre,  VBlw,  VAbv,  VAbv,
   /* 11130 */  VBlw,  VAbv,  VAbv,     H, CMBlw,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11140 */     O,     O,     O,     O,     B,  VPst,  VPst,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11140 */     O,     O,     O,     O,     B,  VPst,  VPst,     B,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Mahajani */
 
@@ -547,7 +554,7 @@
   /* 11190 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 111A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 111B0 */     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,
-  /* 111C0 */     H,     B,     R,     R,     O,     O,     O,     O,    GB,  FBlw, CMBlw,  VAbv,  VBlw,     O,     O,     O,
+  /* 111C0 */     H,     B,     R,     R,     O,     O,     O,     O,    GB, FMBlw, CMBlw,  VAbv,  VBlw,     O,  VPre, VMAbv,
   /* 111D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
   /* Sinhala Archaic Numbers */
@@ -581,7 +588,7 @@
 
   /* Grantha */
 
-  /* 11300 */ VMAbv, VMAbv, VMAbv, VMPst,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,
+  /* 11300 */ VMAbv, VMAbv, VMAbv, VMAbv,     O,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,
   /* 11310 */     B,     O,     O,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11320 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     B,     B,     B,     B,     B,     B,
   /* 11330 */     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     O, CMBlw, CMBlw,     B,  VPst,  VPst,
@@ -600,8 +607,8 @@
   /* 11420 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11430 */     B,     B,     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,
   /* 11440 */  VPst,  VPst,     H, VMAbv, VMAbv, VMPst, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,
-  /* 11450 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,    FM,     O,
-  /* 11460 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11450 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O, FMAbv,     B,
+  /* 11460 */    CS,    CS,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 11470 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Tirhuta */
@@ -610,7 +617,7 @@
   /* 11490 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 114A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 114B0 */  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VBlw,  VPre,  VAbv,  VPst,  VPst,  VPst,  VPst, VMAbv,
-  /* 114C0 */ VMAbv, VMPst,     H, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 114C0 */ VMAbv, VMAbv,     H, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 114D0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
 #define use_offset_0x11580u 4720
@@ -643,7 +650,7 @@
   /* 11680 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11690 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 116A0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B, VMAbv, VMPst,  VAbv,  VPre,  VPst,
-  /* 116B0 */  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,     H, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 116B0 */  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,     H, CMBlw,     B,     O,     O,     O,     O,     O,     O,     O,
   /* 116C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
   /* 116D0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 116E0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
@@ -666,15 +673,36 @@
   /* 11820 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,  VPst,  VPre,  VPst,  VBlw,
   /* 11830 */  VBlw,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv, VMAbv, VMPst,     H, CMBlw,     O,     O,     O,     O,     O,
 
-#define use_offset_0x11a00u 5232
+#define use_offset_0x11900u 5232
 
 
+  /* Dives Akuru */
+
+  /* 11900 */     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,     O,     O,     B,     B,     B,     B,
+  /* 11910 */     B,     B,     B,     B,     O,     B,     B,     O,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11920 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 11930 */  VPst,  VPst,  VPst,  VPst,  VPst,  VPre,     O,  VPre,  VPst,     O,     O, VMAbv, VMAbv,  VPst,     H,     R,
+  /* 11940 */  MPst,     R,  MBlw, CMBlw,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 11950 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
+
+#define use_offset_0x119a0u 5328
+
+
+  /* Nandinagari */
+
+  /* 119A0 */     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     B,     B,     B,     B,     B,     B,
+  /* 119B0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 119C0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
+  /* 119D0 */     B,  VPst,  VPre,  VPst,  VBlw,  VBlw,  VBlw,  VBlw,     O,     O,  VAbv,  VAbv,  VPst,  VPst, VMPst, VMPst,
+  /* 119E0 */     H,     B,     O,     O,  VPre,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+  /* 119F0 */     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,     O,
+
   /* Zanabazar Square */
 
   /* 11A00 */     B,  VAbv,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VAbv,  VBlw,     B,     B,     B,     B,     B,
   /* 11A10 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A20 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11A30 */     B,     B,     B,    FM,  VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst,     R,  MBlw,  MBlw,  MBlw,  MBlw,    GB,
+  /* 11A30 */     B,     B,     B, FMBlw,  VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst,     R,  MBlw,  MBlw,  MBlw,  MBlw,    GB,
   /* 11A40 */     O,     O,     O,     O,     O,    GB,     O,     H,     O,     O,     O,     O,     O,     O,     O,     O,
 
   /* Soyombo */
@@ -682,10 +710,10 @@
   /* 11A50 */     B,  VAbv,  VBlw,  VBlw,  VAbv,  VAbv,  VAbv,  VPst,  VPst,  VBlw,  VBlw,  VBlw,     B,     B,     B,     B,
   /* 11A60 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11A70 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
-  /* 11A80 */     B,     B,     B,     B,     O,     O,     R,     R,     R,     R,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,
+  /* 11A80 */     B,     B,     B,     B,     R,     R,     R,     R,     R,     R,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,
   /* 11A90 */  FBlw,  FBlw,  FBlw,  FBlw,  FBlw,  FBlw, VMAbv, VMPst, CMAbv,     H,     O,     O,     O,     B,     O,     O,
 
-#define use_offset_0x11c00u 5392
+#define use_offset_0x11c00u 5584
 
 
   /* Bhaiksuki */
@@ -706,7 +734,7 @@
   /* 11CA0 */   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,     O,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,   SUB,
   /* 11CB0 */  VBlw,  VPre,  VBlw,  VAbv,  VPst, VMAbv, VMAbv,     O,
 
-#define use_offset_0x11d00u 5576
+#define use_offset_0x11d00u 5768
 
 
   /* Masaram Gondi */
@@ -726,7 +754,7 @@
   /* 11D90 */  VAbv,  VAbv,     O,  VPst,  VPst, VMAbv, VMPst,     H,     O,     O,     O,     O,     O,     O,     O,     O,
   /* 11DA0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     O,     O,     O,     O,     O,     O,
 
-#define use_offset_0x11ee0u 5752
+#define use_offset_0x11ee0u 5944
 
 
   /* Makasar */
@@ -734,7 +762,7 @@
   /* 11EE0 */     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,     B,
   /* 11EF0 */     B,     B,    GB,  VAbv,  VBlw,  VPre,  VPst,     O,
 
-}; /* Table items: 5776; occupancy: 74% */
+}; /* Table items: 5968; occupancy: 74% */
 
 USE_TABLE_ELEMENT_TYPE
 hb_use_get_category (hb_codepoint_t u)
@@ -785,7 +813,8 @@
       if (hb_in_range<hb_codepoint_t> (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11800u, 0x1183Fu)) return use_table[u - 0x11800u + use_offset_0x11800u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x11A00u, 0x11A9Fu)) return use_table[u - 0x11A00u + use_offset_0x11a00u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x11900u, 0x1195Fu)) return use_table[u - 0x11900u + use_offset_0x11900u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x119A0u, 0x11A9Fu)) return use_table[u - 0x119A0u + use_offset_0x119a0u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11D00u, 0x11DAFu)) return use_table[u - 0x11D00u + use_offset_0x11d00u];
       if (hb_in_range<hb_codepoint_t> (u, 0x11EE0u, 0x11EF7u)) return use_table[u - 0x11EE0u + use_offset_0x11ee0u];
@@ -800,7 +829,6 @@
 #undef B
 #undef CGJ
 #undef CS
-#undef FM
 #undef GB
 #undef H
 #undef HN
@@ -812,28 +840,34 @@
 #undef Rsv
 #undef S
 #undef SUB
+#undef Sk
 #undef VS
 #undef WJ
 #undef ZWJ
 #undef ZWNJ
-#undef CMBlw
 #undef CMAbv
+#undef CMBlw
+#undef FAbv
 #undef FBlw
 #undef FPst
-#undef FAbv
-#undef MPre
+#undef FMAbv
+#undef FMBlw
+#undef FMPst
+#undef MAbv
 #undef MBlw
 #undef MPst
-#undef MAbv
-#undef SMBlw
+#undef MPre
 #undef SMAbv
-#undef VPre
+#undef SMBlw
+#undef VAbv
 #undef VBlw
 #undef VPst
-#undef VAbv
-#undef VMPre
+#undef VPre
+#undef VMAbv
 #undef VMBlw
 #undef VMPst
-#undef VMAbv
+#undef VMPre
 
+
+#endif
 /* == End of generated table == */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.cc
index 25b135a..b5cf48a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.cc
@@ -26,12 +26,17 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-use.hh"
 #include "hb-ot-shape-complex-arabic.hh"
+#include "hb-ot-shape-complex-arabic-joining-list.hh"
 #include "hb-ot-shape-complex-vowel-constraints.hh"
 
 /* buffer var allocations */
-#define use_category() complex_var_u8_0()
+#define use_category() complex_var_u8_1()
 
 
 /*
@@ -40,7 +45,7 @@
  */
 
 static const hb_tag_t
-basic_features[] =
+use_basic_features[] =
 {
   /*
    * Basic features.
@@ -55,28 +60,23 @@
   HB_TAG('c','j','c','t'),
 };
 static const hb_tag_t
-arabic_features[] =
+use_topographical_features[] =
 {
   HB_TAG('i','s','o','l'),
   HB_TAG('i','n','i','t'),
   HB_TAG('m','e','d','i'),
   HB_TAG('f','i','n','a'),
-  /* The spec doesn't specify these but we apply anyway, since our Arabic shaper
-   * does.  These are only used in Syriac spec. */
-  HB_TAG('m','e','d','2'),
-  HB_TAG('f','i','n','2'),
-  HB_TAG('f','i','n','3'),
 };
-/* Same order as arabic_features.  Don't need Syriac stuff.*/
+/* Same order as use_topographical_features. */
 enum joining_form_t {
-  ISOL,
-  INIT,
-  MEDI,
-  FINA,
-  _NONE
+  USE_ISOL,
+  USE_INIT,
+  USE_MEDI,
+  USE_FINA,
+  _USE_NONE
 };
 static const hb_tag_t
-other_features[] =
+use_other_features[] =
 {
   /*
    * Other features.
@@ -89,42 +89,23 @@
   HB_TAG('p','r','e','s'),
   HB_TAG('p','s','t','s'),
 };
-static const hb_tag_t
-positioning_features[] =
-{
-  /*
-   * Positioning features.
-   * We don't care about the types.
-   */
-  HB_TAG('d','i','s','t'),
-  HB_TAG('a','b','v','m'),
-  HB_TAG('b','l','w','m'),
-};
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
+setup_syllables_use (const hb_ot_shape_plan_t *plan,
+                     hb_font_t *font,
+                     hb_buffer_t *buffer);
+static void
+record_rphf_use (const hb_ot_shape_plan_t *plan,
                  hb_font_t *font,
                  hb_buffer_t *buffer);
 static void
-clear_substitution_flags (const hb_ot_shape_plan_t *plan,
-                          hb_font_t *font,
-                          hb_buffer_t *buffer);
-static void
-record_rphf (const hb_ot_shape_plan_t *plan,
-             hb_font_t *font,
-             hb_buffer_t *buffer);
-static void
-record_pref (const hb_ot_shape_plan_t *plan,
-             hb_font_t *font,
-             hb_buffer_t *buffer);
-static void
-reorder (const hb_ot_shape_plan_t *plan,
-         hb_font_t *font,
-         hb_buffer_t *buffer);
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan,
+record_pref_use (const hb_ot_shape_plan_t *plan,
                  hb_font_t *font,
                  hb_buffer_t *buffer);
+static void
+reorder_use (const hb_ot_shape_plan_t *plan,
+             hb_font_t *font,
+             hb_buffer_t *buffer);
 
 static void
 collect_features_use (hb_ot_shape_planner_t *plan)
@@ -132,7 +113,7 @@
   hb_ot_map_builder_t *map = &plan->map;
 
   /* Do this before any lookups have been applied. */
-  map->add_gsub_pause (setup_syllables);
+  map->add_gsub_pause (setup_syllables_use);
 
   /* "Default glyph pre-processing group" */
   map->enable_feature (HB_TAG('l','o','c','l'));
@@ -141,32 +122,28 @@
   map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ);
 
   /* "Reordering group" */
-  map->add_gsub_pause (clear_substitution_flags);
+  map->add_gsub_pause (_hb_clear_substitution_flags);
   map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ);
-  map->add_gsub_pause (record_rphf);
-  map->add_gsub_pause (clear_substitution_flags);
+  map->add_gsub_pause (record_rphf_use);
+  map->add_gsub_pause (_hb_clear_substitution_flags);
   map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ);
-  map->add_gsub_pause (record_pref);
+  map->add_gsub_pause (record_pref_use);
 
   /* "Orthographic unit shaping group" */
-  for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
-    map->enable_feature (basic_features[i], F_MANUAL_ZWJ);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++)
+    map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ);
 
-  map->add_gsub_pause (reorder);
-  map->add_gsub_pause (clear_syllables);
+  map->add_gsub_pause (reorder_use);
+  map->add_gsub_pause (_hb_clear_syllables);
 
   /* "Topographical features" */
-  for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++)
-    map->add_feature (arabic_features[i]);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++)
+    map->add_feature (use_topographical_features[i]);
   map->add_gsub_pause (nullptr);
 
   /* "Standard typographic presentation" */
-  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
-    map->enable_feature (other_features[i], F_MANUAL_ZWJ);
-
-  /* "Positional feature application" */
-  for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++)
-    map->enable_feature (positioning_features[i]);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (use_other_features); i++)
+    map->enable_feature (use_other_features[i], F_MANUAL_ZWJ);
 }
 
 struct use_shape_plan_t
@@ -176,40 +153,6 @@
   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:
-
-    /* Unicode-9.0 additions */
-    case HB_SCRIPT_ADLAM:
-
-      return true;
-
-    default:
-      return false;
-  }
-}
-
 static void *
 data_create_use (const hb_ot_shape_plan_t *plan)
 {
@@ -243,15 +186,16 @@
   free (data);
 }
 
-enum syllable_type_t {
-  independent_cluster,
-  virama_terminated_cluster,
-  standard_cluster,
-  number_joiner_terminated_cluster,
-  numeral_cluster,
-  symbol_cluster,
-  broken_cluster,
-  non_cluster,
+enum use_syllable_type_t {
+  use_independent_cluster,
+  use_virama_terminated_cluster,
+  use_sakot_terminated_cluster,
+  use_standard_cluster,
+  use_number_joiner_terminated_cluster,
+  use_numeral_cluster,
+  use_symbol_cluster,
+  use_broken_cluster,
+  use_non_cluster,
 };
 
 #include "hb-ot-shape-complex-use-machine.hh"
@@ -294,7 +238,7 @@
 
   foreach_syllable (buffer, start, end)
   {
-    unsigned int limit = info[start].use_category() == USE_R ? 1 : MIN (3u, end - start);
+    unsigned int limit = info[start].use_category() == USE_R ? 1 : hb_min (3u, end - start);
     for (unsigned int i = start; i < start + limit; i++)
       info[i].mask |= mask;
   }
@@ -308,11 +252,11 @@
   if (use_plan->arabic_plan)
     return;
 
-  static_assert ((INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4), "");
+  static_assert ((USE_INIT < 4 && USE_ISOL < 4 && USE_MEDI < 4 && USE_FINA < 4), "");
   hb_mask_t masks[4], all_masks = 0;
   for (unsigned int i = 0; i < 4; i++)
   {
-    masks[i] = plan->map.get_1_mask (arabic_features[i]);
+    masks[i] = plan->map.get_1_mask (use_topographical_features[i]);
     if (masks[i] == plan->map.get_global_mask ())
       masks[i] = 0;
     all_masks |= masks[i];
@@ -322,38 +266,39 @@
   hb_mask_t other_masks = ~all_masks;
 
   unsigned int last_start = 0;
-  joining_form_t last_form = _NONE;
+  joining_form_t last_form = _USE_NONE;
   hb_glyph_info_t *info = buffer->info;
   foreach_syllable (buffer, start, end)
   {
-    syllable_type_t syllable_type = (syllable_type_t) (info[start].syllable() & 0x0F);
+    use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F);
     switch (syllable_type)
     {
-      case independent_cluster:
-      case symbol_cluster:
-      case non_cluster:
+      case use_independent_cluster:
+      case use_symbol_cluster:
+      case use_non_cluster:
         /* These don't join.  Nothing to do. */
-        last_form = _NONE;
+        last_form = _USE_NONE;
         break;
 
-      case virama_terminated_cluster:
-      case standard_cluster:
-      case number_joiner_terminated_cluster:
-      case numeral_cluster:
-      case broken_cluster:
+      case use_virama_terminated_cluster:
+      case use_sakot_terminated_cluster:
+      case use_standard_cluster:
+      case use_number_joiner_terminated_cluster:
+      case use_numeral_cluster:
+      case use_broken_cluster:
 
-        bool join = last_form == FINA || last_form == ISOL;
+        bool join = last_form == USE_FINA || last_form == USE_ISOL;
 
         if (join)
         {
           /* Fixup previous syllable's form. */
-          last_form = last_form == FINA ? MEDI : INIT;
+          last_form = last_form == USE_FINA ? USE_MEDI : USE_INIT;
           for (unsigned int i = last_start; i < start; i++)
             info[i].mask = (info[i].mask & other_masks) | masks[last_form];
         }
 
         /* Form for this syllable. */
-        last_form = join ? FINA : ISOL;
+        last_form = join ? USE_FINA : USE_ISOL;
         for (unsigned int i = start; i < end; i++)
           info[i].mask = (info[i].mask & other_masks) | masks[last_form];
 
@@ -365,11 +310,11 @@
 }
 
 static void
-setup_syllables (const hb_ot_shape_plan_t *plan,
-                 hb_font_t *font HB_UNUSED,
-                 hb_buffer_t *buffer)
+setup_syllables_use (const hb_ot_shape_plan_t *plan,
+                     hb_font_t *font HB_UNUSED,
+                     hb_buffer_t *buffer)
 {
-  find_syllables (buffer);
+  find_syllables_use (buffer);
   foreach_syllable (buffer, start, end)
     buffer->unsafe_to_break (start, end);
   setup_rphf_mask (plan, buffer);
@@ -377,20 +322,9 @@
 }
 
 static void
-clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                          hb_font_t *font HB_UNUSED,
-                          hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    _hb_glyph_info_clear_substituted (&info[i]);
-}
-
-static void
-record_rphf (const hb_ot_shape_plan_t *plan,
-             hb_font_t *font HB_UNUSED,
-             hb_buffer_t *buffer)
+record_rphf_use (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font HB_UNUSED,
+                 hb_buffer_t *buffer)
 {
   const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
 
@@ -411,9 +345,9 @@
 }
 
 static void
-record_pref (const hb_ot_shape_plan_t *plan HB_UNUSED,
-             hb_font_t *font HB_UNUSED,
-             hb_buffer_t *buffer)
+record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                 hb_font_t *font HB_UNUSED,
+                 hb_buffer_t *buffer)
 {
   hb_glyph_info_t *info = buffer->info;
 
@@ -430,21 +364,22 @@
 }
 
 static inline bool
-is_halant (const hb_glyph_info_t &info)
+is_halant_use (const hb_glyph_info_t &info)
 {
   return (info.use_category() == USE_H || info.use_category() == USE_HVM) &&
          !_hb_glyph_info_ligated (&info);
 }
 
 static void
-reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
+reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
 {
-  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  use_syllable_type_t syllable_type = (use_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   /* Only a few syllable types need reordering. */
   if (unlikely (!(FLAG_UNSAFE (syllable_type) &
-                  (FLAG (virama_terminated_cluster) |
-                   FLAG (standard_cluster) |
-                   FLAG (broken_cluster) |
+                  (FLAG (use_virama_terminated_cluster) |
+                   FLAG (use_sakot_terminated_cluster) |
+                   FLAG (use_standard_cluster) |
+                   FLAG (use_broken_cluster) |
                    0))))
     return;
 
@@ -475,7 +410,7 @@
     for (unsigned int i = start + 1; i < end; i++)
     {
       bool is_post_base_glyph = (FLAG64_UNSAFE (info[i].use_category()) & POST_BASE_FLAGS64) ||
-                                is_halant (info[i]);
+                                is_halant_use (info[i]);
       if (is_post_base_glyph || i == end - 1)
       {
         /* If we hit a post-base glyph, move before it; otherwise move to the
@@ -499,7 +434,7 @@
   for (unsigned int i = start; i < end; i++)
   {
     uint32_t flag = FLAG_UNSAFE (info[i].use_category());
-    if (is_halant (info[i]))
+    if (is_halant_use (info[i]))
     {
       /* If we hit a halant, move after it; otherwise move to the beginning, and
        * shift things in between forward. */
@@ -519,16 +454,20 @@
 }
 
 static inline void
-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                       hb_font_t *font,
-                       hb_buffer_t *buffer)
+insert_dotted_circles_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                           hb_font_t *font,
+                           hb_buffer_t *buffer)
 {
-  /* Note: This loop is extra overhead, but should not be measurable. */
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
+  /* Note: This loop is extra overhead, but should not be measurable.
+   * TODO Use a buffer scratch flag to remove the loop. */
   bool has_broken_syllables = false;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    if ((info[i].syllable() & 0x0F) == broken_cluster)
+    if ((info[i].syllable() & 0x0F) == use_broken_cluster)
     {
       has_broken_syllables = true;
       break;
@@ -548,8 +487,8 @@
   while (buffer->idx < buffer->len && buffer->successful)
   {
     unsigned int syllable = buffer->cur().syllable();
-    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
-    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    use_syllable_type_t syllable_type = (use_syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == use_broken_cluster))
     {
       last_syllable = syllable;
 
@@ -557,7 +496,6 @@
       ginfo.cluster = buffer->cur().cluster;
       ginfo.mask = buffer->cur().mask;
       ginfo.syllable() = buffer->cur().syllable();
-      /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
       while (buffer->idx < buffer->len && buffer->successful &&
@@ -574,29 +512,18 @@
 }
 
 static void
-reorder (const hb_ot_shape_plan_t *plan,
-         hb_font_t *font,
-         hb_buffer_t *buffer)
+reorder_use (const hb_ot_shape_plan_t *plan,
+             hb_font_t *font,
+             hb_buffer_t *buffer)
 {
-  insert_dotted_circles (plan, font, buffer);
+  insert_dotted_circles_use (plan, font, buffer);
 
   foreach_syllable (buffer, start, end)
-    reorder_syllable (buffer, start, end);
+    reorder_syllable_use (buffer, start, end);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
 }
 
-static void
-clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
-                 hb_font_t *font HB_UNUSED,
-                 hb_buffer_t *buffer)
-{
-  hb_glyph_info_t *info = buffer->info;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    info[i].syllable() = 0;
-}
-
 
 static void
 preprocess_text_use (const hb_ot_shape_plan_t *plan,
@@ -637,3 +564,6 @@
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.hh
index d7edef4..6a42d58 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.hh
@@ -68,6 +68,12 @@
   USE_VS        = 21,   /* VARIATION_SELECTOR */
 //  USE_V       = 36,   /* VOWEL */
 //  USE_VM      = 40,   /* VOWEL_MOD */
+  USE_CS        = 43,   /* CONS_WITH_STACKER */
+
+  /* https://github.com/harfbuzz/harfbuzz/issues/1102 */
+  USE_HVM       = 44,   /* HALANT_OR_VOWEL_MODIFIER */
+
+  USE_Sk        = 48,   /* SAKOT */
 
   USE_FAbv      = 24,   /* CONS_FINAL_ABOVE */
   USE_FBlw      = 25,   /* CONS_FINAL_BELOW */
@@ -88,10 +94,9 @@
   USE_VMPre     = 23,   /* VOWEL_MOD_PRE */
   USE_SMAbv     = 41,   /* SYM_MOD_ABOVE */
   USE_SMBlw     = 42,   /* SYM_MOD_BELOW */
-  USE_CS        = 43,   /* CONS_WITH_STACKER */
-
-  /* https://github.com/harfbuzz/harfbuzz/issues/1102 */
-  USE_HVM       = 44,   /* HALANT_OR_VOWEL_MODIFIER */
+  USE_FMAbv     = 45,   /* CONS_FINAL_MOD       UIPC = Top */
+  USE_FMBlw     = 46,   /* CONS_FINAL_MOD       UIPC = Bottom */
+  USE_FMPst     = 47,   /* CONS_FINAL_MOD       UIPC = Not_Applicable */
 };
 
 HB_INTERNAL USE_TABLE_ELEMENT_TYPE
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-vowel-constraints.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-vowel-constraints.cc
index 366751e..adfaa30 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-vowel-constraints.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-vowel-constraints.cc
@@ -2,17 +2,22 @@
 /*
  * The following functions are generated by running:
  *
- *   ./gen-vowel-constraints.py use Scripts.txt
+ *   ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
  *
  * on files with these headers:
  *
- * # Copied from https://docs.microsoft.com/en-us/typography/script-development/use
- * # On October 23, 2018; with documentd dated 02/07/2018.
+ * # IndicShapingInvalidCluster.txt
+ * # Date: 2015-03-12, 21:17:00 GMT [AG]
+ * # Date: 2019-11-08, 23:22:00 GMT [AG]
  *
- * # Scripts-11.0.0.txt
- * # Date: 2018-02-21, 05:34:31 GMT
+ * # Scripts-13.0.0.txt
+ * # Date: 2020-01-22, 00:07:43 GMT
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-complex-vowel-constraints.hh"
 
 static void
@@ -34,6 +39,12 @@
                                        hb_buffer_t              *buffer,
                                        hb_font_t                *font HB_UNUSED)
 {
+#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
+  return;
+#endif
+  if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)
+    return;
+
   /* UGLY UGLY UGLY business of adding dotted-circle in the middle of
    * vowel-sequences that look like another vowel.  Data for each script
    * collected from the USE script development spec.
@@ -87,8 +98,7 @@
                 0x0907u == buffer->cur (2).codepoint)
             {
               buffer->next_glyph ();
-              buffer->next_glyph ();
-              _output_dotted_circle (buffer);
+              matched = true;
             }
             break;
         }
@@ -201,6 +211,21 @@
       processed = true;
       break;
 
+    case HB_SCRIPT_TAMIL:
+      for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+      {
+        bool matched = false;
+        if (0x0B85u == buffer->cur ().codepoint &&
+            0x0BC2u == buffer->cur (1).codepoint)
+        {
+          matched = true;
+        }
+        buffer->next_glyph ();
+        if (matched) _output_with_dotted_circle (buffer);
+      }
+      processed = true;
+      break;
+
     case HB_SCRIPT_TELUGU:
       for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
       {
@@ -434,4 +459,6 @@
   }
 }
 
+
+#endif
 /* == End of generated functions == */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex.hh
index 2756ae1..59165c4 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex.hh
@@ -50,8 +50,9 @@
 
 /* Master OT shaper list */
 #define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
-  HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \
   HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (default) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (dumber) \
   HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
   HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
   HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
@@ -60,7 +61,7 @@
   HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_zawgyi) \
   HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
   HB_COMPLEX_SHAPER_IMPLEMENT (use) \
-  /* ^--- Add new shapers here */
+  /* ^--- Add new shapers here; keep sorted. */
 
 
 struct hb_ot_complex_shaper_t
@@ -377,6 +378,13 @@
     case HB_SCRIPT_MAKASAR:
     //case HB_SCRIPT_SOGDIAN:
 
+    /* Unicode-12.0 additions */
+    case HB_SCRIPT_NANDINAGARI:
+
+    /* Unicode-13.0 additions */
+    case HB_SCRIPT_CHORASMIAN:
+    case HB_SCRIPT_DIVES_AKURU:
+
       /* If the designer designed the font for the 'DFLT' script,
        * (or we ended up arbitrarily pick 'latn'), use the default shaper.
        * Otherwise, use the specific shaper.
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc
index d29bc9b..b6b6f0b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-fallback.hh"
 #include "hb-kern.hh"
 
@@ -166,6 +170,10 @@
                                                         hb_font_t *font HB_UNUSED,
                                                         hb_buffer_t  *buffer)
 {
+#ifdef HB_NO_OT_SHAPE_FALLBACK
+  return;
+#endif
+
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
@@ -414,12 +422,12 @@
   /* Find the base glyph */
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = start; i < end; i++)
-    if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
+    if (!_hb_glyph_info_is_unicode_mark (&info[i]))
     {
       /* Find mark glyphs */
       unsigned int j;
       for (j = i + 1; j < end; j++)
-        if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
+        if (!_hb_glyph_info_is_unicode_mark (&info[j]))
           break;
 
       position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing);
@@ -434,13 +442,17 @@
                                      hb_buffer_t  *buffer,
                                      bool adjust_offsets_when_zeroing)
 {
+#ifdef HB_NO_OT_SHAPE_FALLBACK
+  return;
+#endif
+
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
   unsigned int start = 0;
   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 (likely (!_hb_glyph_info_is_unicode_mark (&info[i]))) {
       position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing);
       start = i;
     }
@@ -448,6 +460,7 @@
 }
 
 
+#ifndef HB_DISABLE_DEPRECATED
 struct hb_ot_shape_fallback_kern_driver_t
 {
   hb_ot_shape_fallback_kern_driver_t (hb_font_t   *font_,
@@ -466,6 +479,7 @@
   hb_font_t *font;
   hb_direction_t direction;
 };
+#endif
 
 /* Performs font-assisted kerning. */
 void
@@ -473,6 +487,11 @@
                             hb_font_t *font,
                             hb_buffer_t *buffer)
 {
+#ifdef HB_NO_OT_SHAPE_FALLBACK
+  return;
+#endif
+
+#ifndef HB_DISABLE_DEPRECATED
   if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
       !font->has_glyph_h_kerning_func () :
       !font->has_glyph_v_kerning_func ())
@@ -489,6 +508,7 @@
 
   if (reverse)
     buffer->reverse ();
+#endif
 }
 
 
@@ -571,3 +591,6 @@
       }
     }
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc
index ed73abb..aa88b26 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc
@@ -24,6 +24,10 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
 #include "hb-ot-shape-normalize.hh"
 #include "hb-ot-shape-complex.hh"
 #include "hb-ot-shape.hh"
@@ -330,7 +334,7 @@
     {
       unsigned int end;
       for (end = buffer->idx + 1; end < count; end++)
-        if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
+        if (unlikely (_hb_glyph_info_is_unicode_mark (&buffer->info[end])))
           break;
 
       if (end < count)
@@ -356,7 +360,7 @@
 
       /* Find all the marks now. */
       for (end = buffer->idx + 1; end < count; end++)
-        if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))
+        if (!_hb_glyph_info_is_unicode_mark(&buffer->info[end]))
           break;
 
       /* idx to end is one non-simple cluster. */
@@ -431,7 +435,7 @@
            * This is both an optimization to avoid trying to compose every two neighboring
            * glyphs in most scripts AND a desired feature for Hangul.  Apparently Hangul
            * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
-          HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())))
+          _hb_glyph_info_is_unicode_mark(&buffer->cur()))
       {
         if (/* If there's anything between the starter and this char, they should have CCC
              * smaller than this character's. */
@@ -469,3 +473,6 @@
     buffer->swap_buffers ();
   }
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc
index e9c8f88..1547255 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc
@@ -26,6 +26,14 @@
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
+#ifdef HB_NO_OT_LAYOUT
+#error "Cannot compile 'ot' shaper with HB_NO_OT_LAYOUT."
+#endif
+
 #include "hb-shaper-impl.hh"
 
 #include "hb-ot-shape.hh"
@@ -40,6 +48,16 @@
 #include "hb-aat-layout.hh"
 
 
+#ifndef HB_NO_AAT_SHAPE
+static inline bool
+_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t *props)
+{
+  /* https://github.com/harfbuzz/harfbuzz/issues/2124 */
+  return hb_aat_layout_has_substitution (face) &&
+         (HB_DIRECTION_IS_HORIZONTAL (props->direction) || !hb_ot_layout_has_substitution (face));
+}
+#endif
+
 /**
  * SECTION:hb-ot-shape
  * @title: hb-ot-shape
@@ -55,36 +73,24 @@
                               const hb_feature_t             *user_features,
                               unsigned int                    num_user_features);
 
-static bool
-_hb_apply_morx (hb_face_t *face)
-{
-  if (hb_options ().aat &&
-      hb_aat_layout_has_substitution (face))
-    return true;
-
-  /* Ignore empty GSUB tables. */
-  return (!hb_ot_layout_has_substitution (face) ||
-          !hb_ot_layout_table_get_script_tags (face,
-                                               HB_OT_TAG_GSUB,
-                                               0, nullptr, nullptr)) &&
-         hb_aat_layout_has_substitution (face);
-}
-
 hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t                     *face,
                                               const hb_segment_properties_t *props) :
                                                 face (face),
                                                 props (*props),
                                                 map (face, props),
-                                                aat_map (face, props),
-                                                apply_morx (_hb_apply_morx (face))
+                                                aat_map (face, props)
+#ifndef HB_NO_AAT_SHAPE
+                                                , apply_morx (_hb_apply_morx (face, props))
+#endif
 {
   shaper = hb_ot_shape_complex_categorize (this);
 
   script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE;
   script_fallback_mark_positioning = shaper->fallback_position;
 
-  if (apply_morx)
-    shaper = &_hb_ot_complex_shaper_default;
+  /* https://github.com/harfbuzz/harfbuzz/issues/1528 */
+  if (apply_morx && shaper != &_hb_ot_complex_shaper_default)
+    shaper = &_hb_ot_complex_shaper_dumber;
 }
 
 void
@@ -94,21 +100,32 @@
   plan.props = props;
   plan.shaper = shaper;
   map.compile (plan.map, key);
+#ifndef HB_NO_AAT_SHAPE
   if (apply_morx)
     aat_map.compile (plan.aat_map);
+#endif
 
+#ifndef HB_NO_OT_SHAPE_FRACTIONS
   plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
   plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
   plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
   plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
+#endif
+
   plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
+  plan.has_vert = !!plan.map.get_1_mask (HB_TAG ('v','e','r','t'));
+
   hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (props.direction) ?
                       HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n');
+#ifndef HB_NO_OT_KERN
   plan.kern_mask = plan.map.get_mask (kern_tag);
-  plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k'));
-
   plan.requested_kerning = !!plan.kern_mask;
+#endif
+#ifndef HB_NO_AAT_SHAPE
+  plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k'));
   plan.requested_tracking = !!plan.trak_mask;
+#endif
+
   bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX;
   bool disable_gpos = plan.shaper->gpos_tag &&
                       plan.shaper->gpos_tag != plan.map.chosen_script[1];
@@ -124,42 +141,61 @@
    * Decide who does substitutions. GSUB, morx, or fallback.
    */
 
+#ifndef HB_NO_AAT_SHAPE
   plan.apply_morx = apply_morx;
+#endif
 
   /*
    * Decide who does positioning. GPOS, kerx, kern, or fallback.
    */
 
-  if (hb_options ().aat && hb_aat_layout_has_positioning (face))
-    plan.apply_kerx = true;
-  else if (!apply_morx && !disable_gpos && hb_ot_layout_has_positioning (face))
-    plan.apply_gpos = true;
+  if (0)
+    ;
+#ifndef HB_NO_AAT_SHAPE
   else if (hb_aat_layout_has_positioning (face))
     plan.apply_kerx = true;
+#endif
+  else if (!apply_morx && !disable_gpos && hb_ot_layout_has_positioning (face))
+    plan.apply_gpos = true;
 
-  if (!plan.apply_kerx && !has_gpos_kern)
+  if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
   {
     /* Apparently Apple applies kerx if GPOS kern was not applied. */
+#ifndef HB_NO_AAT_SHAPE
     if (hb_aat_layout_has_positioning (face))
       plan.apply_kerx = true;
-    else if (hb_ot_layout_has_kerning (face))
+    else
+#endif
+#ifndef HB_NO_OT_KERN
+    if (hb_ot_layout_has_kerning (face))
       plan.apply_kern = true;
+#endif
   }
 
   plan.zero_marks = script_zero_marks &&
                     !plan.apply_kerx &&
-                    (!plan.apply_kern || !hb_ot_layout_has_machine_kerning (face));
+                    (!plan.apply_kern
+#ifndef HB_NO_OT_KERN
+                     || !hb_ot_layout_has_machine_kerning (face)
+#endif
+                    );
   plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
 
   plan.adjust_mark_positioning_when_zeroing = !plan.apply_gpos &&
                                               !plan.apply_kerx &&
-                                              (!plan.apply_kern || !hb_ot_layout_has_cross_kerning (face));
+                                              (!plan.apply_kern
+#ifndef HB_NO_OT_KERN
+                                               || !hb_ot_layout_has_cross_kerning (face)
+#endif
+                                              );
 
   plan.fallback_mark_positioning = plan.adjust_mark_positioning_when_zeroing &&
                                    script_fallback_mark_positioning;
 
+#ifndef HB_NO_AAT_SHAPE
   /* Currently we always apply trak. */
   plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
+#endif
 }
 
 bool
@@ -167,7 +203,9 @@
                            const hb_shape_plan_key_t     *key)
 {
   map.init ();
+#ifndef HB_NO_AAT_SHAPE
   aat_map.init ();
+#endif
 
   hb_ot_shape_planner_t planner (face,
                                  &key->props);
@@ -182,7 +220,13 @@
   {
     data = shaper->data_create (this);
     if (unlikely (!data))
+    {
+      map.fini ();
+#ifndef HB_NO_AAT_SHAPE
+      aat_map.fini ();
+#endif
       return false;
+    }
   }
 
   return true;
@@ -195,16 +239,20 @@
     shaper->data_destroy (const_cast<void *> (data));
 
   map.fini ();
+#ifndef HB_NO_AAT_SHAPE
   aat_map.fini ();
+#endif
 }
 
 void
 hb_ot_shape_plan_t::substitute (hb_font_t   *font,
                                 hb_buffer_t *buffer) const
 {
+#ifndef HB_NO_AAT_SHAPE
   if (unlikely (apply_morx))
     hb_aat_layout_substitute (this, font, buffer);
   else
+#endif
     map.substitute (this, font, buffer);
 }
 
@@ -214,21 +262,29 @@
 {
   if (this->apply_gpos)
     map.position (this, font, buffer);
+#ifndef HB_NO_AAT_SHAPE
   else if (this->apply_kerx)
     hb_aat_layout_position (this, font, buffer);
+#endif
+#ifndef HB_NO_OT_KERN
   else if (this->apply_kern)
     hb_ot_layout_kern (this, font, buffer);
+#endif
   else
     _hb_ot_shape_fallback_kern (this, font, buffer);
 
+#ifndef HB_NO_AAT_SHAPE
   if (this->apply_trak)
     hb_aat_layout_track (this, font, buffer);
+#endif
 }
 
 
 static const hb_ot_map_feature_t
 common_features[] =
 {
+  {HB_TAG('a','b','v','m'), F_GLOBAL},
+  {HB_TAG('b','l','w','m'), F_GLOBAL},
   {HB_TAG('c','c','m','p'), F_GLOBAL},
   {HB_TAG('l','o','c','l'), F_GLOBAL},
   {HB_TAG('m','a','r','k'), F_GLOBAL_MANUAL_JOINERS},
@@ -243,6 +299,7 @@
   {HB_TAG('c','a','l','t'), F_GLOBAL},
   {HB_TAG('c','l','i','g'), F_GLOBAL},
   {HB_TAG('c','u','r','s'), F_GLOBAL},
+  {HB_TAG('d','i','s','t'), F_GLOBAL},
   {HB_TAG('k','e','r','n'), F_GLOBAL_HAS_FALLBACK},
   {HB_TAG('l','i','g','a'), F_GLOBAL},
   {HB_TAG('r','c','l','t'), F_GLOBAL},
@@ -274,18 +331,22 @@
       break;
   }
 
+#ifndef HB_NO_OT_SHAPE_FRACTIONS
   /* Automatic fractions. */
   map->add_feature (HB_TAG ('f','r','a','c'));
   map->add_feature (HB_TAG ('n','u','m','r'));
   map->add_feature (HB_TAG ('d','n','o','m'));
+#endif
 
   /* Random! */
   map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE);
 
+#ifndef HB_NO_AAT_SHAPE
   /* Tracking.  We enable dummy feature here just to allow disabling
    * AAT 'trak' table using features.
    * https://github.com/harfbuzz/harfbuzz/issues/1303 */
   map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK);
+#endif
 
   map->enable_feature (HB_TAG ('H','A','R','F'));
 
@@ -318,6 +379,7 @@
                       feature->value);
   }
 
+#ifndef HB_NO_AAT_SHAPE
   if (planner->apply_morx)
   {
     hb_aat_map_builder_t *aat_map = &planner->aat_map;
@@ -327,6 +389,7 @@
       aat_map->add_feature (feature->tag, feature->value);
     }
   }
+#endif
 
   if (planner->shaper->override_features)
     planner->shaper->override_features (planner);
@@ -417,6 +480,7 @@
     {
         _hb_glyph_info_set_continuation (&info[i]);
     }
+#ifndef HB_NO_EMOJI_SEQUENCES
     else if (unlikely (_hb_glyph_info_is_zwj (&info[i])))
     {
       _hb_glyph_info_set_continuation (&info[i]);
@@ -428,6 +492,7 @@
         _hb_glyph_info_set_continuation (&info[i]);
       }
     }
+#endif
     /* Or part of the Other_Grapheme_Extend that is not marks.
      * As of Unicode 11 that is just:
      *
@@ -448,6 +513,9 @@
 static void
 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
 {
+  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+    return;
+
   if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
       buffer->context_len[0] ||
       !_hb_glyph_info_is_unicode_mark (&buffer->info[0]))
@@ -524,30 +592,95 @@
  * Substitute
  */
 
-static inline void
-hb_ot_mirror_chars (const hb_ot_shape_context_t *c)
+static hb_codepoint_t
+hb_vert_char_for (hb_codepoint_t u)
 {
-  if (HB_DIRECTION_IS_FORWARD (c->target_direction))
-    return;
+  switch (u >> 8)
+  {
+    case 0x20: switch (u) {
+      case 0x2013u: return 0xfe32u; // EN DASH
+      case 0x2014u: return 0xfe31u; // EM DASH
+      case 0x2025u: return 0xfe30u; // TWO DOT LEADER
+      case 0x2026u: return 0xfe19u; // HORIZONTAL ELLIPSIS
+    } break;
+    case 0x30: switch (u) {
+      case 0x3001u: return 0xfe11u; // IDEOGRAPHIC COMMA
+      case 0x3002u: return 0xfe12u; // IDEOGRAPHIC FULL STOP
+      case 0x3008u: return 0xfe3fu; // LEFT ANGLE BRACKET
+      case 0x3009u: return 0xfe40u; // RIGHT ANGLE BRACKET
+      case 0x300au: return 0xfe3du; // LEFT DOUBLE ANGLE BRACKET
+      case 0x300bu: return 0xfe3eu; // RIGHT DOUBLE ANGLE BRACKET
+      case 0x300cu: return 0xfe41u; // LEFT CORNER BRACKET
+      case 0x300du: return 0xfe42u; // RIGHT CORNER BRACKET
+      case 0x300eu: return 0xfe43u; // LEFT WHITE CORNER BRACKET
+      case 0x300fu: return 0xfe44u; // RIGHT WHITE CORNER BRACKET
+      case 0x3010u: return 0xfe3bu; // LEFT BLACK LENTICULAR BRACKET
+      case 0x3011u: return 0xfe3cu; // RIGHT BLACK LENTICULAR BRACKET
+      case 0x3014u: return 0xfe39u; // LEFT TORTOISE SHELL BRACKET
+      case 0x3015u: return 0xfe3au; // RIGHT TORTOISE SHELL BRACKET
+      case 0x3016u: return 0xfe17u; // LEFT WHITE LENTICULAR BRACKET
+      case 0x3017u: return 0xfe18u; // RIGHT WHITE LENTICULAR BRACKET
+    } break;
+    case 0xfe: switch (u) {
+      case 0xfe4fu: return 0xfe34u; // WAVY LOW LINE
+    } break;
+    case 0xff: switch (u) {
+      case 0xff01u: return 0xfe15u; // FULLWIDTH EXCLAMATION MARK
+      case 0xff08u: return 0xfe35u; // FULLWIDTH LEFT PARENTHESIS
+      case 0xff09u: return 0xfe36u; // FULLWIDTH RIGHT PARENTHESIS
+      case 0xff0cu: return 0xfe10u; // FULLWIDTH COMMA
+      case 0xff1au: return 0xfe13u; // FULLWIDTH COLON
+      case 0xff1bu: return 0xfe14u; // FULLWIDTH SEMICOLON
+      case 0xff1fu: return 0xfe16u; // FULLWIDTH QUESTION MARK
+      case 0xff3bu: return 0xfe47u; // FULLWIDTH LEFT SQUARE BRACKET
+      case 0xff3du: return 0xfe48u; // FULLWIDTH RIGHT SQUARE BRACKET
+      case 0xff3fu: return 0xfe33u; // FULLWIDTH LOW LINE
+      case 0xff5bu: return 0xfe37u; // FULLWIDTH LEFT CURLY BRACKET
+      case 0xff5du: return 0xfe38u; // FULLWIDTH RIGHT CURLY BRACKET
+    } break;
+  }
 
+  return u;
+}
+
+static inline void
+hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
+{
   hb_buffer_t *buffer = c->buffer;
-  hb_unicode_funcs_t *unicode = buffer->unicode;
-  hb_mask_t rtlm_mask = c->plan->rtlm_mask;
-
   unsigned int count = buffer->len;
   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 || !c->font->has_glyph (codepoint)))
-      info[i].mask |= rtlm_mask;
-    else
-      info[i].codepoint = codepoint;
+
+  if (HB_DIRECTION_IS_BACKWARD (c->target_direction))
+  {
+    hb_unicode_funcs_t *unicode = buffer->unicode;
+    hb_mask_t rtlm_mask = c->plan->rtlm_mask;
+
+    for (unsigned int i = 0; i < count; i++) {
+      hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
+      if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint)))
+        info[i].codepoint = codepoint;
+      else
+        info[i].mask |= rtlm_mask;
+    }
+  }
+
+  if (HB_DIRECTION_IS_VERTICAL (c->target_direction) && !c->plan->has_vert)
+  {
+    for (unsigned int i = 0; i < count; i++) {
+      hb_codepoint_t codepoint = hb_vert_char_for (info[i].codepoint);
+      if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint)))
+        info[i].codepoint = codepoint;
+    }
   }
 }
 
 static inline void
 hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
 {
+#ifdef HB_NO_OT_SHAPE_FRACTIONS
+  return;
+#endif
+
   if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
       !c->plan->has_frac)
     return;
@@ -619,7 +752,7 @@
   for (unsigned int i = 0; i < c->num_user_features; i++)
   {
     const hb_feature_t *feature = &c->user_features[i];
-    if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
+    if (!(feature->start == HB_FEATURE_GLOBAL_START && feature->end == HB_FEATURE_GLOBAL_END)) {
       unsigned int shift;
       hb_mask_t mask = map->get_mask (feature->tag, &shift);
       buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
@@ -714,7 +847,7 @@
 {
   hb_buffer_t *buffer = c->buffer;
 
-  hb_ot_mirror_chars (c);
+  hb_ot_rotate_chars (c);
 
   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
 
@@ -758,8 +891,10 @@
 hb_ot_substitute_post (const hb_ot_shape_context_t *c)
 {
   hb_ot_hide_default_ignorables (c->buffer, c->font);
+#ifndef HB_NO_AAT_SHAPE
   if (c->plan->apply_morx)
     hb_aat_layout_remove_deleted_glyphs (c->buffer);
+#endif
 
   if (c->plan->shaper->postprocess_glyphs)
     c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
@@ -893,8 +1028,10 @@
   /* Finish off.  Has to follow a certain order. */
   hb_ot_layout_position_finish_advances (c->font, c->buffer);
   hb_ot_zero_width_default_ignorables (c->buffer);
+#ifndef HB_NO_AAT_SHAPE
   if (c->plan->apply_morx)
     hb_aat_layout_zero_width_deleted_glyphs (c->buffer);
+#endif
   hb_ot_layout_position_finish_offsets (c->font, c->buffer);
 
   /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
@@ -959,13 +1096,13 @@
   c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
   if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
   {
-    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
-                              (unsigned) HB_BUFFER_MAX_LEN_MIN);
+    c->buffer->max_len = hb_max (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
+                                 (unsigned) HB_BUFFER_MAX_LEN_MIN);
   }
   if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
   {
-    c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
-                              (unsigned) HB_BUFFER_MAX_OPS_MIN);
+    c->buffer->max_ops = hb_max (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
+                                 (unsigned) HB_BUFFER_MAX_OPS_MIN);
   }
 
   /* Save the original direction, we use it later. */
@@ -1081,3 +1218,6 @@
 
   hb_shape_plan_destroy (shape_plan);
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh
index 5adc058..7823126 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh
@@ -37,9 +37,9 @@
 {
   unsigned int variations_index[2];
 
-  void init (hb_face_t   *face,
-                    const int   *coords,
-                    unsigned int num_coords)
+  void init (hb_face_t *face,
+             const int *coords,
+             unsigned   num_coords)
   {
     for (unsigned int table_index = 0; table_index < 2; table_index++)
       hb_ot_layout_table_find_feature_variations (face,
@@ -65,14 +65,41 @@
   hb_ot_map_t map;
   hb_aat_map_t aat_map;
   const void *data;
+#ifndef HB_NO_OT_SHAPE_FRACTIONS
   hb_mask_t frac_mask, numr_mask, dnom_mask;
+#else
+  static constexpr hb_mask_t frac_mask = 0;
+  static constexpr hb_mask_t numr_mask = 0;
+  static constexpr hb_mask_t dnom_mask = 0;
+#endif
   hb_mask_t rtlm_mask;
+#ifndef HB_NO_OT_KERN
   hb_mask_t kern_mask;
+#else
+  static constexpr hb_mask_t kern_mask = 0;
+#endif
+#ifndef HB_NO_AAT_SHAPE
   hb_mask_t trak_mask;
+#else
+  static constexpr hb_mask_t trak_mask = 0;
+#endif
 
+#ifndef HB_NO_OT_KERN
   bool requested_kerning : 1;
+#else
+  static constexpr bool requested_kerning = false;
+#endif
+#ifndef HB_NO_AAT_SHAPE
   bool requested_tracking : 1;
+#else
+  static constexpr bool requested_tracking = false;
+#endif
+#ifndef HB_NO_OT_SHAPE_FRACTIONS
   bool has_frac : 1;
+#else
+  static constexpr bool has_frac = false;
+#endif
+  bool has_vert : 1;
   bool has_gpos_mark : 1;
   bool zero_marks : 1;
   bool fallback_glyph_classes : 1;
@@ -80,10 +107,20 @@
   bool adjust_mark_positioning_when_zeroing : 1;
 
   bool apply_gpos : 1;
-  bool apply_kerx : 1;
+#ifndef HB_NO_OT_KERN
   bool apply_kern : 1;
+#else
+  static constexpr bool apply_kern = false;
+#endif
+#ifndef HB_NO_AAT_SHAPE
+  bool apply_kerx : 1;
   bool apply_morx : 1;
   bool apply_trak : 1;
+#else
+  static constexpr bool apply_kerx = false;
+  static constexpr bool apply_morx = false;
+  static constexpr bool apply_trak = false;
+#endif
 
   void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
   {
@@ -113,7 +150,11 @@
   hb_segment_properties_t props;
   hb_ot_map_builder_t map;
   hb_aat_map_builder_t aat_map;
+#ifndef HB_NO_AAT_SHAPE
   bool apply_morx : 1;
+#else
+  static constexpr bool apply_morx = false;
+#endif
   bool script_zero_marks : 1;
   bool script_fallback_mark_positioning : 1;
   const struct hb_ot_complex_shaper_t *shaper;
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh
index 63dbfce..ca97aff 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh
@@ -59,6 +59,11 @@
 
 struct AxisValueFormat1
 {
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return value.to_float (); }
+
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -75,13 +80,18 @@
   NameID        valueNameID;    /* The name ID for entries in the 'name' table
                                  * that provide a display string for this
                                  * attribute value. */
-  Fixed         value;          /* A numeric value for this attribute value. */
+  HBFixed       value;          /* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct AxisValueFormat2
 {
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return nominalValue.to_float (); }
+
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -98,10 +108,10 @@
   NameID        valueNameID;    /* The name ID for entries in the 'name' table
                                  * that provide a display string for this
                                  * attribute value. */
-  Fixed         nominalValue;   /* A numeric value for this attribute value. */
-  Fixed         rangeMinValue;  /* The minimum value for a range associated
+  HBFixed       nominalValue;   /* A numeric value for this attribute value. */
+  HBFixed       rangeMinValue;  /* The minimum value for a range associated
                                  * with the specified name ID. */
-  Fixed         rangeMaxValue;  /* The maximum value for a range associated
+  HBFixed       rangeMaxValue;  /* The maximum value for a range associated
                                  * with the specified name ID. */
   public:
   DEFINE_SIZE_STATIC (20);
@@ -109,6 +119,11 @@
 
 struct AxisValueFormat3
 {
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return value.to_float (); }
+
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -125,8 +140,8 @@
   NameID        valueNameID;    /* The name ID for entries in the 'name' table
                                  * that provide a display string for this
                                  * attribute value. */
-  Fixed         value;          /* A numeric value for this attribute value. */
-  Fixed         linkedValue;    /* The numeric value for a style-linked mapping
+  HBFixed       value;          /* A numeric value for this attribute value. */
+  HBFixed       linkedValue;    /* The numeric value for a style-linked mapping
                                  * from this value. */
   public:
   DEFINE_SIZE_STATIC (16);
@@ -134,6 +149,9 @@
 
 struct AxisValueRecord
 {
+  unsigned int get_axis_index () const { return axisIndex; }
+  float get_value ()             const { return value.to_float (); }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -144,13 +162,18 @@
   HBUINT16      axisIndex;      /* Zero-base index into the axis record array
                                  * identifying the axis to which this value
                                  * applies. Must be less than designAxisCount. */
-  Fixed         value;          /* A numeric value for this attribute value. */
+  HBFixed       value;          /* A numeric value for this attribute value. */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct AxisValueFormat4
 {
+  const AxisValueRecord &get_axis_record (unsigned int axis_index) const
+  { return axisValues.as_array (axisCount)[axis_index]; }
+
+  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -175,19 +198,55 @@
 
 struct AxisValue
 {
+  bool get_value (unsigned int axis_index) const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.get_value ();
+    case 2: return u.format2.get_value ();
+    case 3: return u.format3.get_value ();
+    case 4: return u.format4.get_axis_record (axis_index).get_value ();
+    default:return 0;
+    }
+  }
+
+  unsigned int get_axis_index () const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.get_axis_index ();
+    case 2: return u.format2.get_axis_index ();
+    case 3: return u.format3.get_axis_index ();
+    /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */
+    default:return -1;
+    }
+  }
+
+  hb_ot_name_id_t get_value_name_id () const
+  {
+    switch (u.format)
+    {
+    case 1: return u.format1.get_value_name_id ();
+    case 2: return u.format2.get_value_name_id ();
+    case 3: return u.format3.get_value_name_id ();
+    case 4: return u.format4.get_value_name_id ();
+    default:return HB_OT_NAME_ID_INVALID;
+    }
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (unlikely (c->check_struct (this)))
+    if (unlikely (!c->check_struct (this)))
       return_trace (false);
 
     switch (u.format)
     {
-    case 1:  return_trace (likely (u.format1.sanitize (c)));
-    case 2:  return_trace (likely (u.format2.sanitize (c)));
-    case 3:  return_trace (likely (u.format3.sanitize (c)));
-    case 4:  return_trace (likely (u.format4.sanitize (c)));
-    default: return_trace (true);
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 3: return_trace (u.format3.sanitize (c));
+    case 4: return_trace (u.format4.sanitize (c));
+    default:return_trace (true);
     }
   }
 
@@ -206,6 +265,10 @@
 
 struct StatAxisRecord
 {
+  int cmp (hb_tag_t key) const { return tag.cmp (key); }
+
+  hb_ot_name_id_t get_name_id () const { return nameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -227,21 +290,82 @@
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
 
+  bool has_data () const { return version.to_int (); }
+
+  bool get_value (hb_tag_t tag, float *value) const
+  {
+    unsigned int axis_index;
+    if (!get_design_axes ().lfind (tag, &axis_index)) return false;
+
+    hb_array_t<const OffsetTo<AxisValue>> axis_values = get_axis_value_offsets ();
+    for (unsigned int i = 0; i < axis_values.length; i++)
+    {
+      const AxisValue& axis_value = this+axis_values[i];
+      if (axis_value.get_axis_index () == axis_index)
+      {
+        if (value)
+          *value = axis_value.get_value (axis_index);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  unsigned get_design_axis_count () const { return designAxisCount; }
+
+  hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
+  {
+    if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
+    const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
+    return axis_record.get_name_id ();
+  }
+
+  unsigned get_axis_value_count () const { return axisValueCount; }
+
+  hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const
+  {
+    if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
+    const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
+    return axis_value.get_value_name_id ();
+  }
+
+  void collect_name_ids (hb_set_t *nameids_to_retain) const
+  {
+    if (!has_data ()) return;
+
+    + get_design_axes ()
+    | hb_map (&StatAxisRecord::get_name_id)
+    | hb_sink (nameids_to_retain)
+    ;
+
+    + get_axis_value_offsets ()
+    | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
+    | hb_map (&AxisValue::get_value_name_id)
+    | hb_sink (nameids_to_retain)
+    ;
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (likely (c->check_struct (this) &&
-                          majorVersion == 1 &&
-                          minorVersion > 0 &&
+                          version.major == 1 &&
+                          version.minor > 0 &&
                           designAxesOffset.sanitize (c, this, designAxisCount) &&
                           offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
   }
 
   protected:
-  HBUINT16      majorVersion;   /* Major version number of the style attributes
-                                 * table — set to 1. */
-  HBUINT16      minorVersion;   /* Minor version number of the style attributes
-                                 * table — set to 2. */
+  hb_array_t<const StatAxisRecord> const get_design_axes () const
+  { return (this+designAxesOffset).as_array (designAxisCount); }
+
+  hb_array_t<const OffsetTo<AxisValue>> const get_axis_value_offsets () const
+  { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
+
+
+  protected:
+  FixedVersion<>version;        /* Version of the stat table
+                                 * initially set to 0x00010002u */
   HBUINT16      designAxisSize; /* The size in bytes of each axis record. */
   HBUINT16      designAxisCount;/* The number of design axis records. In a
                                  * font with an 'fvar' table, this value must be
@@ -249,7 +373,7 @@
                                  * in the 'fvar' table. In all fonts, must
                                  * be greater than zero if axisValueCount
                                  * is greater than zero. */
-  LNNOffsetTo<UnsizedArrayOf<StatAxisRecord> >
+  LNNOffsetTo<UnsizedArrayOf<StatAxisRecord>>
                 designAxesOffset;
                                 /* Offset in bytes from the beginning of
                                  * the STAT table to the start of the design
@@ -257,7 +381,7 @@
                                  * set to zero; if designAxisCount is greater
                                  * than zero, must be greater than zero. */
   HBUINT16      axisValueCount; /* The number of axis value tables. */
-  LNNOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue> > >
+  LNNOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue>>>
                 offsetToAxisValueOffsets;
                                 /* Offset in bytes from the beginning of
                                  * the STAT table to the start of the design
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh
index 93333bb..9109b48 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh
@@ -6,1055 +6,1058 @@
  *
  * on files with these headers:
  *
- * <meta name="updated_at" content="2018-09-07 07:45 PM" />
- * File-Date: 2018-08-08
+ * <meta name="updated_at" content="2019-05-22 06:05 PM" />
+ * File-Date: 2020-05-12
  */
 
 #ifndef HB_OT_TAG_TABLE_HH
 #define HB_OT_TAG_TABLE_HH
 
 static const LangTag ot_languages[] = {
-  {"aa",        {HB_TAG('A','F','R',' ')}},     /* Afar */
-  {"aae",       {HB_TAG('S','Q','I',' ')}},     /* Arbëreshë Albanian -> Albanian */
-  {"aao",       {HB_TAG('A','R','A',' ')}},     /* Algerian Saharan Arabic -> Arabic */
-  {"aat",       {HB_TAG('S','Q','I',' ')}},     /* Arvanitika Albanian -> Albanian */
-  {"ab",        {HB_TAG('A','B','K',' ')}},     /* Abkhazian */
-  {"abh",       {HB_TAG('A','R','A',' ')}},     /* Tajiki Arabic -> Arabic */
-  {"abq",       {HB_TAG('A','B','A',' ')}},     /* Abaza */
-  {"abv",       {HB_TAG('A','R','A',' ')}},     /* Baharna Arabic -> Arabic */
-  {"acf",       {HB_TAG('F','A','N',' ')}},     /* Saint Lucian Creole French -> French Antillean */
-  {"ach",       {HB_TAG('A','C','H',' ')}},     /* Acoli -> Acholi */
-  {"acm",       {HB_TAG('A','R','A',' ')}},     /* Mesopotamian Arabic -> Arabic */
-  {"acq",       {HB_TAG('A','R','A',' ')}},     /* Ta'izzi-Adeni Arabic -> Arabic */
-  {"acr",       {HB_TAG('A','C','R',' ')}},     /* Achi */
-  {"acw",       {HB_TAG('A','R','A',' ')}},     /* Hijazi Arabic -> Arabic */
-  {"acx",       {HB_TAG('A','R','A',' ')}},     /* Omani Arabic -> Arabic */
-  {"acy",       {HB_TAG('A','R','A',' ')}},     /* Cypriot Arabic -> Arabic */
-  {"ada",       {HB_TAG('D','N','G',' ')}},     /* Adangme -> Dangme */
-  {"adf",       {HB_TAG('A','R','A',' ')}},     /* Dhofari Arabic -> Arabic */
-  {"adp",       {HB_TAG('D','Z','N',' ')}},     /* Adap (retired code) -> Dzongkha */
-  {"ady",       {HB_TAG('A','D','Y',' ')}},     /* Adyghe */
-  {"aeb",       {HB_TAG('A','R','A',' ')}},     /* Tunisian Arabic -> Arabic */
-  {"aec",       {HB_TAG('A','R','A',' ')}},     /* Saidi Arabic -> Arabic */
-  {"af",        {HB_TAG('A','F','K',' ')}},     /* Afrikaans */
-  {"afb",       {HB_TAG('A','R','A',' ')}},     /* Gulf Arabic -> Arabic */
-  {"ahg",       {HB_TAG('A','G','W',' ')}},     /* Qimant -> Agaw */
-  {"aht",       {HB_TAG('A','T','H',' ')}},     /* Ahtena -> Athapaskan */
-  {"aii",       {HB_TAG('S','W','A',' '),       /* Assyrian Neo-Aramaic -> Swadaya Aramaic */
-                 HB_TAG('S','Y','R',' ')}},     /* Assyrian Neo-Aramaic -> Syriac */
-  {"aio",       {HB_TAG('A','I','O',' ')}},     /* Aiton */
-  {"aiw",       {HB_TAG('A','R','I',' ')}},     /* Aari */
-  {"ajp",       {HB_TAG('A','R','A',' ')}},     /* South Levantine Arabic -> Arabic */
-  {"ak",        {HB_TAG('A','K','A',' '),       /* Akan [macrolanguage] */
-                 HB_TAG('T','W','I',' ')}},     /* Akan [macrolanguage] -> Twi */
-  {"aln",       {HB_TAG('S','Q','I',' ')}},     /* Gheg Albanian -> Albanian */
-  {"als",       {HB_TAG('S','Q','I',' ')}},     /* Tosk Albanian -> Albanian */
-  {"alt",       {HB_TAG('A','L','T',' ')}},     /* Southern Altai -> Altai */
-  {"am",        {HB_TAG('A','M','H',' ')}},     /* Amharic */
-  {"amf",       {HB_TAG('H','B','N',' ')}},     /* Hamer-Banna -> Hammer-Banna */
-  {"amw",       {HB_TAG('S','Y','R',' ')}},     /* Western Neo-Aramaic -> Syriac */
-  {"an",        {HB_TAG('A','R','G',' ')}},     /* Aragonese */
-  {"ang",       {HB_TAG('A','N','G',' ')}},     /* Old English (ca. 450-1100) -> Anglo-Saxon */
-  {"apc",       {HB_TAG('A','R','A',' ')}},     /* North Levantine Arabic -> Arabic */
-  {"apd",       {HB_TAG('A','R','A',' ')}},     /* Sudanese Arabic -> Arabic */
-  {"apj",       {HB_TAG('A','T','H',' ')}},     /* Jicarilla Apache -> Athapaskan */
-  {"apk",       {HB_TAG('A','T','H',' ')}},     /* Kiowa Apache -> Athapaskan */
-  {"apl",       {HB_TAG('A','T','H',' ')}},     /* Lipan Apache -> Athapaskan */
-  {"apm",       {HB_TAG('A','T','H',' ')}},     /* Mescalero-Chiricahua Apache -> Athapaskan */
-  {"apw",       {HB_TAG('A','T','H',' ')}},     /* Western Apache -> Athapaskan */
-  {"ar",        {HB_TAG('A','R','A',' ')}},     /* Arabic [macrolanguage] */
-  {"arb",       {HB_TAG('A','R','A',' ')}},     /* Standard Arabic -> Arabic */
-  {"arn",       {HB_TAG('M','A','P',' ')}},     /* Mapudungun */
-  {"arq",       {HB_TAG('A','R','A',' ')}},     /* Algerian Arabic -> Arabic */
-  {"ars",       {HB_TAG('A','R','A',' ')}},     /* Najdi Arabic -> Arabic */
-  {"ary",       {HB_TAG('M','O','R',' ')}},     /* Moroccan Arabic -> Moroccan */
-  {"arz",       {HB_TAG('A','R','A',' ')}},     /* Egyptian Arabic -> Arabic */
-  {"as",        {HB_TAG('A','S','M',' ')}},     /* Assamese */
-  {"ast",       {HB_TAG('A','S','T',' ')}},     /* Asturian */
-  {"ath",       {HB_TAG('A','T','H',' ')}},     /* Athapascan [family] -> Athapaskan */
-  {"atj",       {HB_TAG('R','C','R',' ')}},     /* Atikamekw -> R-Cree */
-  {"atv",       {HB_TAG('A','L','T',' ')}},     /* Northern Altai -> Altai */
-  {"auz",       {HB_TAG('A','R','A',' ')}},     /* Uzbeki Arabic -> Arabic */
-  {"av",        {HB_TAG('A','V','R',' ')}},     /* Avaric -> Avar */
-  {"avl",       {HB_TAG('A','R','A',' ')}},     /* Eastern Egyptian Bedawi Arabic -> Arabic */
-  {"awa",       {HB_TAG('A','W','A',' ')}},     /* Awadhi */
-  {"ay",        {HB_TAG('A','Y','M',' ')}},     /* Aymara [macrolanguage] */
-  {"ayc",       {HB_TAG('A','Y','M',' ')}},     /* Southern Aymara -> Aymara */
-  {"ayh",       {HB_TAG('A','R','A',' ')}},     /* Hadrami Arabic -> Arabic */
-  {"ayl",       {HB_TAG('A','R','A',' ')}},     /* Libyan Arabic -> Arabic */
-  {"ayn",       {HB_TAG('A','R','A',' ')}},     /* Sanaani Arabic -> Arabic */
-  {"ayp",       {HB_TAG('A','R','A',' ')}},     /* North Mesopotamian Arabic -> Arabic */
-  {"ayr",       {HB_TAG('A','Y','M',' ')}},     /* Central Aymara -> Aymara */
-  {"az",        {HB_TAG('A','Z','E',' ')}},     /* Azerbaijani [macrolanguage] */
-  {"azb",       {HB_TAG('A','Z','B',' ')}},     /* South Azerbaijani -> Torki */
-  {"azj",       {HB_TAG('A','Z','E',' ')}},     /* North Azerbaijani -> Azerbaijani */
-  {"ba",        {HB_TAG('B','S','H',' ')}},     /* Bashkir */
-  {"bad",       {HB_TAG('B','A','D','0')}},     /* Banda [family] */
-  {"bai",       {HB_TAG('B','M','L',' ')}},     /* Bamileke [family] */
-  {"bal",       {HB_TAG('B','L','I',' ')}},     /* Baluchi [macrolanguage] */
-  {"ban",       {HB_TAG('B','A','N',' ')}},     /* Balinese */
-  {"bar",       {HB_TAG('B','A','R',' ')}},     /* Bavarian */
-  {"bbc",       {HB_TAG('B','B','C',' ')}},     /* Batak Toba */
-  {"bbz",       {HB_TAG('A','R','A',' ')}},     /* Babalia Creole Arabic -> Arabic */
-  {"bcc",       {HB_TAG('B','L','I',' ')}},     /* Southern Balochi -> Baluchi */
-  {"bci",       {HB_TAG('B','A','U',' ')}},     /* Baoulé -> Baulé */
-  {"bcl",       {HB_TAG('B','I','K',' ')}},     /* Central Bikol -> Bikol */
-  {"bcq",       {HB_TAG('B','C','H',' ')}},     /* Bench */
-  {"bcr",       {HB_TAG('A','T','H',' ')}},     /* Babine -> Athapaskan */
-  {"bdy",       {HB_TAG('B','D','Y',' ')}},     /* Bandjalang */
-  {"be",        {HB_TAG('B','E','L',' ')}},     /* Belarusian -> Belarussian */
-  {"bea",       {HB_TAG('A','T','H',' ')}},     /* Beaver -> Athapaskan */
-  {"beb",       {HB_TAG('B','T','I',' ')}},     /* Bebele -> Beti */
-  {"bem",       {HB_TAG('B','E','M',' ')}},     /* Bemba (Zambia) */
-  {"ber",       {HB_TAG('B','B','R',' ')}},     /* Berber [family] */
-  {"bfq",       {HB_TAG('B','A','D',' ')}},     /* Badaga */
-  {"bft",       {HB_TAG('B','L','T',' ')}},     /* Balti */
-  {"bfu",       {HB_TAG('L','A','H',' ')}},     /* Gahri -> Lahuli */
-  {"bfy",       {HB_TAG('B','A','G',' ')}},     /* Bagheli -> Baghelkhandi */
-  {"bg",        {HB_TAG('B','G','R',' ')}},     /* Bulgarian */
-  {"bgc",       {HB_TAG('B','G','C',' ')}},     /* Haryanvi */
-  {"bgn",       {HB_TAG('B','L','I',' ')}},     /* Western Balochi -> Baluchi */
-  {"bgp",       {HB_TAG('B','L','I',' ')}},     /* Eastern Balochi -> Baluchi */
-  {"bgq",       {HB_TAG('B','G','Q',' ')}},     /* Bagri */
-  {"bgr",       {HB_TAG('Q','I','N',' ')}},     /* Bawm Chin -> Chin */
-  {"bhb",       {HB_TAG('B','H','I',' ')}},     /* Bhili */
-  {"bhi",       {HB_TAG('B','H','I',' ')}},     /* Bhilali -> Bhili */
-  {"bhk",       {HB_TAG('B','I','K',' ')}},     /* Albay Bicolano (retired code) -> Bikol */
-  {"bho",       {HB_TAG('B','H','O',' ')}},     /* Bhojpuri */
-  {"bhr",       {HB_TAG('M','L','G',' ')}},     /* Bara Malagasy -> Malagasy */
-  {"bi",        {HB_TAG('B','I','S',' ')}},     /* Bislama */
-  {"bik",       {HB_TAG('B','I','K',' ')}},     /* Bikol [macrolanguage] */
-  {"bin",       {HB_TAG('E','D','O',' ')}},     /* Edo */
-  {"bjj",       {HB_TAG('B','J','J',' ')}},     /* Kanauji */
-  {"bjn",       {HB_TAG('M','L','Y',' ')}},     /* Banjar -> Malay */
-  {"bjq",       {HB_TAG('M','L','G',' ')}},     /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */
-  {"bjt",       {HB_TAG('B','L','N',' ')}},     /* Balanta-Ganja -> Balante */
-  {"bla",       {HB_TAG('B','K','F',' ')}},     /* Siksika -> Blackfoot */
-  {"ble",       {HB_TAG('B','L','N',' ')}},     /* Balanta-Kentohe -> Balante */
-  {"blk",       {HB_TAG('B','L','K',' ')}},     /* Pa'o Karen */
-  {"bln",       {HB_TAG('B','I','K',' ')}},     /* Southern Catanduanes Bikol -> Bikol */
-  {"bm",        {HB_TAG('B','M','B',' ')}},     /* Bambara (Bamanankan) */
-  {"bmm",       {HB_TAG('M','L','G',' ')}},     /* Northern Betsimisaraka Malagasy -> Malagasy */
-  {"bn",        {HB_TAG('B','E','N',' ')}},     /* Bengali */
-  {"bo",        {HB_TAG('T','I','B',' ')}},     /* Tibetan */
-  {"bpy",       {HB_TAG('B','P','Y',' ')}},     /* Bishnupriya -> Bishnupriya Manipuri */
-  {"bqi",       {HB_TAG('L','R','C',' ')}},     /* Bakhtiari -> Luri */
-  {"br",        {HB_TAG('B','R','E',' ')}},     /* Breton */
-  {"bra",       {HB_TAG('B','R','I',' ')}},     /* Braj -> Braj Bhasha */
-  {"brh",       {HB_TAG('B','R','H',' ')}},     /* Brahui */
-  {"brx",       {HB_TAG('B','R','X',' ')}},     /* Bodo (India) */
-  {"bs",        {HB_TAG('B','O','S',' ')}},     /* Bosnian */
-  {"bsk",       {HB_TAG('B','S','K',' ')}},     /* Burushaski */
-  {"btb",       {HB_TAG('B','T','I',' ')}},     /* Beti (Cameroon) (retired code) */
-  {"btj",       {HB_TAG('M','L','Y',' ')}},     /* Bacanese Malay -> Malay */
-  {"bto",       {HB_TAG('B','I','K',' ')}},     /* Rinconada Bikol -> Bikol */
-  {"bts",       {HB_TAG('B','T','S',' ')}},     /* Batak Simalungun */
-  {"bug",       {HB_TAG('B','U','G',' ')}},     /* Buginese -> Bugis */
-  {"bum",       {HB_TAG('B','T','I',' ')}},     /* Bulu (Cameroon) -> Beti */
-  {"bve",       {HB_TAG('M','L','Y',' ')}},     /* Berau Malay -> Malay */
-  {"bvu",       {HB_TAG('M','L','Y',' ')}},     /* Bukit Malay -> Malay */
-  {"bxk",       {HB_TAG('L','U','H',' ')}},     /* Bukusu -> Luyia */
-  {"bxp",       {HB_TAG('B','T','I',' ')}},     /* Bebil -> Beti */
-  {"bxr",       {HB_TAG('R','B','U',' ')}},     /* Russia Buriat -> Russian Buriat */
-  {"byn",       {HB_TAG('B','I','L',' ')}},     /* Bilin -> Bilen */
-  {"byv",       {HB_TAG('B','Y','V',' ')}},     /* Medumba */
-  {"bzc",       {HB_TAG('M','L','G',' ')}},     /* Southern Betsimisaraka Malagasy -> Malagasy */
-  {"ca",        {HB_TAG('C','A','T',' ')}},     /* Catalan */
-  {"caf",       {HB_TAG('C','R','R',' '),       /* Southern Carrier -> Carrier */
-                 HB_TAG('A','T','H',' ')}},     /* Southern Carrier -> Athapaskan */
-  {"cak",       {HB_TAG('C','A','K',' ')}},     /* Kaqchikel */
-  {"cbk",       {HB_TAG('C','B','K',' ')}},     /* Chavacano -> Zamboanga Chavacano */
-  {"cbl",       {HB_TAG('Q','I','N',' ')}},     /* Bualkhaw Chin -> Chin */
-  {"cco",       {HB_TAG('C','C','H','N')}},     /* Comaltepec Chinantec -> Chinantec */
-  {"ccq",       {HB_TAG('A','R','K',' ')}},     /* Chaungtha (retired code) -> Rakhine */
-  {"cdo",       {HB_TAG('Z','H','S',' ')}},     /* Min Dong Chinese -> Chinese Simplified */
-  {"ce",        {HB_TAG('C','H','E',' ')}},     /* Chechen */
-  {"ceb",       {HB_TAG('C','E','B',' ')}},     /* Cebuano */
-  {"cfm",       {HB_TAG('H','A','L',' ')}},     /* Halam (Falam Chin) */
-  {"cgg",       {HB_TAG('C','G','G',' ')}},     /* Chiga */
-  {"ch",        {HB_TAG('C','H','A',' ')}},     /* Chamorro */
-  {"chj",       {HB_TAG('C','C','H','N')}},     /* Ojitlán Chinantec -> Chinantec */
-  {"chk",       {HB_TAG('C','H','K','0')}},     /* Chuukese */
-  {"cho",       {HB_TAG('C','H','O',' ')}},     /* Choctaw */
-  {"chp",       {HB_TAG('C','H','P',' '),       /* Chipewyan */
-                 HB_TAG('S','A','Y',' '),       /* Chipewyan -> Sayisi */
-                 HB_TAG('A','T','H',' ')}},     /* Chipewyan -> Athapaskan */
-  {"chq",       {HB_TAG('C','C','H','N')}},     /* Quiotepec Chinantec -> Chinantec */
-  {"chr",       {HB_TAG('C','H','R',' ')}},     /* Cherokee */
-  {"chy",       {HB_TAG('C','H','Y',' ')}},     /* Cheyenne */
-  {"chz",       {HB_TAG('C','C','H','N')}},     /* Ozumacín Chinantec -> Chinantec */
-  {"ciw",       {HB_TAG('O','J','B',' ')}},     /* Chippewa -> Ojibway */
-  {"cja",       {HB_TAG('C','J','A',' ')}},     /* Western Cham */
-  {"cjm",       {HB_TAG('C','J','M',' ')}},     /* Eastern Cham */
-  {"cjy",       {HB_TAG('Z','H','S',' ')}},     /* Jinyu Chinese -> Chinese Simplified */
-  {"cka",       {HB_TAG('Q','I','N',' ')}},     /* Khumi Awa Chin (retired code) -> Chin */
-  {"ckb",       {HB_TAG('K','U','R',' ')}},     /* Central Kurdish -> Kurdish */
-  {"ckt",       {HB_TAG('C','H','K',' ')}},     /* Chukot -> Chukchi */
-  {"clc",       {HB_TAG('A','T','H',' ')}},     /* Chilcotin -> Athapaskan */
-  {"cld",       {HB_TAG('S','Y','R',' ')}},     /* Chaldean Neo-Aramaic -> Syriac */
-  {"cle",       {HB_TAG('C','C','H','N')}},     /* Lealao Chinantec -> Chinantec */
-  {"cmn",       {HB_TAG('Z','H','S',' ')}},     /* Mandarin Chinese -> Chinese Simplified */
-  {"cmr",       {HB_TAG('Q','I','N',' ')}},     /* Mro-Khimi Chin -> Chin */
-  {"cnb",       {HB_TAG('Q','I','N',' ')}},     /* Chinbon Chin -> Chin */
-  {"cnh",       {HB_TAG('Q','I','N',' ')}},     /* Hakha Chin -> Chin */
-  {"cnk",       {HB_TAG('Q','I','N',' ')}},     /* Khumi Chin -> Chin */
-  {"cnl",       {HB_TAG('C','C','H','N')}},     /* Lalana Chinantec -> Chinantec */
-  {"cnt",       {HB_TAG('C','C','H','N')}},     /* Tepetotutla Chinantec -> Chinantec */
-  {"cnw",       {HB_TAG('Q','I','N',' ')}},     /* Ngawn Chin -> Chin */
-  {"co",        {HB_TAG('C','O','S',' ')}},     /* Corsican */
-  {"coa",       {HB_TAG('M','L','Y',' ')}},     /* Cocos Islands Malay -> Malay */
-  {"cop",       {HB_TAG('C','O','P',' ')}},     /* Coptic */
-  {"coq",       {HB_TAG('A','T','H',' ')}},     /* Coquille -> Athapaskan */
-  {"cpa",       {HB_TAG('C','C','H','N')}},     /* Palantla Chinantec -> Chinantec */
-  {"cpe",       {HB_TAG('C','P','P',' ')}},     /* English-based creoles and pidgins [family] -> Creoles */
-  {"cpf",       {HB_TAG('C','P','P',' ')}},     /* French-based creoles and pidgins [family] -> Creoles */
-  {"cpp",       {HB_TAG('C','P','P',' ')}},     /* Portuguese-based creoles and pidgins [family] -> Creoles */
-  {"cpx",       {HB_TAG('Z','H','S',' ')}},     /* Pu-Xian Chinese -> Chinese Simplified */
-  {"cqd",       {HB_TAG('H','M','N',' ')}},     /* Chuanqiandian Cluster Miao -> Hmong */
-  {"cqu",       {HB_TAG('Q','U','H',' ')}},     /* Chilean Quechua (retired code) -> Quechua (Bolivia) */
-  {"cr",        {HB_TAG('C','R','E',' '),       /* Cree [macrolanguage] */
-                 HB_TAG('Y','C','R',' ')}},     /* Cree [macrolanguage] -> Y-Cree */
-  {"crh",       {HB_TAG('C','R','T',' ')}},     /* Crimean Tatar */
-  {"crj",       {HB_TAG('E','C','R',' ')}},     /* Southern East Cree -> Eastern Cree */
-  {"crk",       {HB_TAG('W','C','R',' ')}},     /* Plains Cree -> West-Cree */
-  {"crl",       {HB_TAG('E','C','R',' ')}},     /* Northern East Cree -> Eastern Cree */
-  {"crm",       {HB_TAG('M','C','R',' '),       /* Moose Cree */
-                 HB_TAG('L','C','R',' ')}},     /* Moose Cree -> L-Cree */
-  {"crp",       {HB_TAG('C','P','P',' ')}},     /* Creoles and pidgins [family] -> Creoles */
-  {"crx",       {HB_TAG('C','R','R',' '),       /* Carrier */
-                 HB_TAG('A','T','H',' ')}},     /* Carrier -> Athapaskan */
-  {"cs",        {HB_TAG('C','S','Y',' ')}},     /* Czech */
-  {"csa",       {HB_TAG('C','C','H','N')}},     /* Chiltepec Chinantec -> Chinantec */
-  {"csb",       {HB_TAG('C','S','B',' ')}},     /* Kashubian */
-  {"csh",       {HB_TAG('Q','I','N',' ')}},     /* Asho Chin -> Chin */
-  {"cso",       {HB_TAG('C','C','H','N')}},     /* Sochiapam Chinantec -> Chinantec */
-  {"csw",       {HB_TAG('N','C','R',' '),       /* Swampy Cree -> N-Cree */
-                 HB_TAG('N','H','C',' ')}},     /* Swampy Cree -> Norway House Cree */
-  {"csy",       {HB_TAG('Q','I','N',' ')}},     /* Siyin Chin -> Chin */
-  {"ctc",       {HB_TAG('A','T','H',' ')}},     /* Chetco -> Athapaskan */
-  {"ctd",       {HB_TAG('Q','I','N',' ')}},     /* Tedim Chin -> Chin */
-  {"cte",       {HB_TAG('C','C','H','N')}},     /* Tepinapa Chinantec -> Chinantec */
-  {"ctg",       {HB_TAG('C','T','G',' ')}},     /* Chittagonian */
-  {"ctl",       {HB_TAG('C','C','H','N')}},     /* Tlacoatzintepec Chinantec -> Chinantec */
-  {"cts",       {HB_TAG('B','I','K',' ')}},     /* Northern Catanduanes Bikol -> Bikol */
-  {"cu",        {HB_TAG('C','S','L',' ')}},     /* Church Slavonic */
-  {"cuc",       {HB_TAG('C','C','H','N')}},     /* Usila Chinantec -> Chinantec */
-  {"cuk",       {HB_TAG('C','U','K',' ')}},     /* San Blas Kuna */
-  {"cv",        {HB_TAG('C','H','U',' ')}},     /* Chuvash */
-  {"cvn",       {HB_TAG('C','C','H','N')}},     /* Valle Nacional Chinantec -> Chinantec */
-  {"cwd",       {HB_TAG('D','C','R',' '),       /* Woods Cree */
-                 HB_TAG('T','C','R',' ')}},     /* Woods Cree -> TH-Cree */
-  {"cy",        {HB_TAG('W','E','L',' ')}},     /* Welsh */
-  {"czh",       {HB_TAG('Z','H','S',' ')}},     /* Huizhou Chinese -> Chinese Simplified */
-  {"czo",       {HB_TAG('Z','H','S',' ')}},     /* Min Zhong Chinese -> Chinese Simplified */
-  {"czt",       {HB_TAG('Q','I','N',' ')}},     /* Zotung Chin -> Chin */
-  {"da",        {HB_TAG('D','A','N',' ')}},     /* Danish */
-  {"dao",       {HB_TAG('Q','I','N',' ')}},     /* Daai Chin -> Chin */
-  {"dap",       {HB_TAG('N','I','S',' ')}},     /* Nisi (India) (retired code) */
-  {"dar",       {HB_TAG('D','A','R',' ')}},     /* Dargwa */
-  {"dax",       {HB_TAG('D','A','X',' ')}},     /* Dayi */
-  {"de",        {HB_TAG('D','E','U',' ')}},     /* German */
-  {"den",       {HB_TAG('S','L','A',' '),       /* Slave (Athapascan) [macrolanguage] -> Slavey */
-                 HB_TAG('A','T','H',' ')}},     /* Slave (Athapascan) [macrolanguage] -> Athapaskan */
-  {"dgo",       {HB_TAG('D','G','O',' ')}},     /* Dogri */
-  {"dgr",       {HB_TAG('A','T','H',' ')}},     /* Dogrib -> Athapaskan */
-  {"dhd",       {HB_TAG('M','A','W',' ')}},     /* Dhundari -> Marwari */
-  {"dhg",       {HB_TAG('D','H','G',' ')}},     /* Dhangu */
-  {"dib",       {HB_TAG('D','N','K',' ')}},     /* South Central Dinka -> Dinka */
-  {"dik",       {HB_TAG('D','N','K',' ')}},     /* Southwestern Dinka -> Dinka */
-  {"din",       {HB_TAG('D','N','K',' ')}},     /* Dinka [macrolanguage] */
-  {"dip",       {HB_TAG('D','N','K',' ')}},     /* Northeastern Dinka -> Dinka */
-  {"diq",       {HB_TAG('D','I','Q',' ')}},     /* Dimli */
-  {"diw",       {HB_TAG('D','N','K',' ')}},     /* Northwestern Dinka -> Dinka */
-  {"dje",       {HB_TAG('D','J','R',' ')}},     /* Zarma */
-  {"djr",       {HB_TAG('D','J','R','0')}},     /* Djambarrpuyngu */
-  {"dks",       {HB_TAG('D','N','K',' ')}},     /* Southeastern Dinka -> Dinka */
-  {"dng",       {HB_TAG('D','U','N',' ')}},     /* Dungan */
-  {"dnj",       {HB_TAG('D','N','J',' ')}},     /* Dan */
-  {"doi",       {HB_TAG('D','G','R',' ')}},     /* Dogri [macrolanguage] */
-  {"drh",       {HB_TAG('M','N','G',' ')}},     /* Darkhat (retired code) -> Mongolian */
-  {"drw",       {HB_TAG('D','R','I',' ')}},     /* Darwazi (retired code) -> Dari */
-  {"dsb",       {HB_TAG('L','S','B',' ')}},     /* Lower Sorbian */
-  {"dty",       {HB_TAG('N','E','P',' ')}},     /* Dotyali -> Nepali */
-  {"duj",       {HB_TAG('D','U','J',' ')}},     /* Dhuwal (retired code) */
-  {"dup",       {HB_TAG('M','L','Y',' ')}},     /* Duano -> Malay */
-  {"dv",        {HB_TAG('D','I','V',' '),       /* Divehi (Dhivehi, Maldivian) */
-                 HB_TAG('D','H','V',' ')}},     /* Divehi (Dhivehi, Maldivian) (deprecated) */
-  {"dwu",       {HB_TAG('D','U','J',' ')}},     /* Dhuwal */
-  {"dwy",       {HB_TAG('D','U','J',' ')}},     /* Dhuwaya -> Dhuwal */
-  {"dyu",       {HB_TAG('J','U','L',' ')}},     /* Dyula -> Jula */
-  {"dz",        {HB_TAG('D','Z','N',' ')}},     /* Dzongkha */
-  {"ee",        {HB_TAG('E','W','E',' ')}},     /* Ewe */
-  {"efi",       {HB_TAG('E','F','I',' ')}},     /* Efik */
-  {"ekk",       {HB_TAG('E','T','I',' ')}},     /* Standard Estonian -> Estonian */
-  {"el",        {HB_TAG('E','L','L',' ')}},     /* Modern Greek (1453-) -> Greek */
-  {"emk",       {HB_TAG('E','M','K',' '),       /* Eastern Maninkakan */
-                 HB_TAG('M','N','K',' ')}},     /* Eastern Maninkakan -> Maninka */
-  {"en",        {HB_TAG('E','N','G',' ')}},     /* English */
-  {"enb",       {HB_TAG('K','A','L',' ')}},     /* Markweeta -> Kalenjin */
-  {"enf",       {HB_TAG('F','N','E',' ')}},     /* Forest Enets -> Forest Nenets */
-  {"enh",       {HB_TAG('T','N','E',' ')}},     /* Tundra Enets -> Tundra Nenets */
-  {"eo",        {HB_TAG('N','T','O',' ')}},     /* Esperanto */
-  {"es",        {HB_TAG('E','S','P',' ')}},     /* Spanish */
-  {"esg",       {HB_TAG('G','O','N',' ')}},     /* Aheri Gondi -> Gondi */
-  {"esi",       {HB_TAG('I','P','K',' ')}},     /* North Alaskan Inupiatun -> Inupiat */
-  {"esk",       {HB_TAG('I','P','K',' ')}},     /* Northwest Alaska Inupiatun -> Inupiat */
-  {"esu",       {HB_TAG('E','S','U',' ')}},     /* Central Yupik */
-  {"et",        {HB_TAG('E','T','I',' ')}},     /* Estonian [macrolanguage] */
-  {"eto",       {HB_TAG('B','T','I',' ')}},     /* Eton (Cameroon) -> Beti */
-  {"eu",        {HB_TAG('E','U','Q',' ')}},     /* Basque */
-  {"eve",       {HB_TAG('E','V','N',' ')}},     /* Even */
-  {"evn",       {HB_TAG('E','V','K',' ')}},     /* Evenki */
-  {"ewo",       {HB_TAG('B','T','I',' ')}},     /* Ewondo -> Beti */
-  {"eyo",       {HB_TAG('K','A','L',' ')}},     /* Keiyo -> Kalenjin */
-  {"fa",        {HB_TAG('F','A','R',' ')}},     /* Persian [macrolanguage] */
-  {"fan",       {HB_TAG('F','A','N','0')}},     /* Fang (Equatorial Guinea) */
-  {"fat",       {HB_TAG('F','A','T',' ')}},     /* Fanti */
-  {"fbl",       {HB_TAG('B','I','K',' ')}},     /* West Albay Bikol -> Bikol */
-  {"ff",        {HB_TAG('F','U','L',' ')}},     /* Fulah [macrolanguage] */
-  {"ffm",       {HB_TAG('F','U','L',' ')}},     /* Maasina Fulfulde -> Fulah */
-  {"fi",        {HB_TAG('F','I','N',' ')}},     /* Finnish */
-  {"fil",       {HB_TAG('P','I','L',' ')}},     /* Filipino */
-  {"fj",        {HB_TAG('F','J','I',' ')}},     /* Fijian */
-  {"flm",       {HB_TAG('H','A','L',' '),       /* Halam (Falam Chin) (retired code) */
-                 HB_TAG('Q','I','N',' ')}},     /* Falam Chin (retired code) -> Chin */
-  {"fmp",       {HB_TAG('F','M','P',' ')}},     /* Fe'fe' */
-  {"fo",        {HB_TAG('F','O','S',' ')}},     /* Faroese */
-  {"fon",       {HB_TAG('F','O','N',' ')}},     /* Fon */
-  {"fr",        {HB_TAG('F','R','A',' ')}},     /* French */
-  {"frc",       {HB_TAG('F','R','C',' ')}},     /* Cajun French */
-  {"frp",       {HB_TAG('F','R','P',' ')}},     /* Arpitan */
-  {"fub",       {HB_TAG('F','U','L',' ')}},     /* Adamawa Fulfulde -> Fulah */
-  {"fuc",       {HB_TAG('F','U','L',' ')}},     /* Pulaar -> Fulah */
-  {"fue",       {HB_TAG('F','U','L',' ')}},     /* Borgu Fulfulde -> Fulah */
-  {"fuf",       {HB_TAG('F','T','A',' ')}},     /* Pular -> Futa */
-  {"fuh",       {HB_TAG('F','U','L',' ')}},     /* Western Niger Fulfulde -> Fulah */
-  {"fui",       {HB_TAG('F','U','L',' ')}},     /* Bagirmi Fulfulde -> Fulah */
-  {"fuq",       {HB_TAG('F','U','L',' ')}},     /* Central-Eastern Niger Fulfulde -> Fulah */
-  {"fur",       {HB_TAG('F','R','L',' ')}},     /* Friulian */
-  {"fuv",       {HB_TAG('F','U','V',' ')}},     /* Nigerian Fulfulde */
-  {"fy",        {HB_TAG('F','R','I',' ')}},     /* Western Frisian -> Frisian */
-  {"ga",        {HB_TAG('I','R','I',' ')}},     /* Irish */
-  {"gaa",       {HB_TAG('G','A','D',' ')}},     /* Ga */
-  {"gag",       {HB_TAG('G','A','G',' ')}},     /* Gagauz */
-  {"gan",       {HB_TAG('Z','H','S',' ')}},     /* Gan Chinese -> Chinese Simplified */
-  {"gax",       {HB_TAG('O','R','O',' ')}},     /* Borana-Arsi-Guji Oromo -> Oromo */
-  {"gaz",       {HB_TAG('O','R','O',' ')}},     /* West Central Oromo -> Oromo */
-  {"gbm",       {HB_TAG('G','A','W',' ')}},     /* Garhwali */
-  {"gce",       {HB_TAG('A','T','H',' ')}},     /* Galice -> Athapaskan */
-  {"gd",        {HB_TAG('G','A','E',' ')}},     /* Scottish Gaelic (Gaelic) */
-  {"gda",       {HB_TAG('R','A','J',' ')}},     /* Gade Lohar -> Rajasthani */
-  {"gez",       {HB_TAG('G','E','Z',' ')}},     /* Geez */
-  {"ggo",       {HB_TAG('G','O','N',' ')}},     /* Southern Gondi (retired code) -> Gondi */
-  {"gih",       {HB_TAG('G','I','H',' ')}},     /* Githabul */
-  {"gil",       {HB_TAG('G','I','L','0')}},     /* Kiribati (Gilbertese) */
-  {"gju",       {HB_TAG('R','A','J',' ')}},     /* Gujari -> Rajasthani */
-  {"gkp",       {HB_TAG('G','K','P',' ')}},     /* Guinea Kpelle -> Kpelle (Guinea) */
-  {"gl",        {HB_TAG('G','A','L',' ')}},     /* Galician */
-  {"gld",       {HB_TAG('N','A','N',' ')}},     /* Nanai */
-  {"glk",       {HB_TAG('G','L','K',' ')}},     /* Gilaki */
-  {"gn",        {HB_TAG('G','U','A',' ')}},     /* Guarani [macrolanguage] */
-  {"gnn",       {HB_TAG('G','N','N',' ')}},     /* Gumatj */
-  {"gno",       {HB_TAG('G','O','N',' ')}},     /* Northern Gondi -> Gondi */
-  {"gnw",       {HB_TAG('G','U','A',' ')}},     /* Western Bolivian Guaraní -> Guarani */
-  {"gog",       {HB_TAG('G','O','G',' ')}},     /* Gogo */
-  {"gom",       {HB_TAG('K','O','K',' ')}},     /* Goan Konkani -> Konkani */
-  {"gon",       {HB_TAG('G','O','N',' ')}},     /* Gondi [macrolanguage] */
-  {"grt",       {HB_TAG('G','R','O',' ')}},     /* Garo */
-  {"gru",       {HB_TAG('S','O','G',' ')}},     /* Kistane -> Sodo Gurage */
-  {"gsw",       {HB_TAG('A','L','S',' ')}},     /* Alsatian */
-  {"gu",        {HB_TAG('G','U','J',' ')}},     /* Gujarati */
-  {"guc",       {HB_TAG('G','U','C',' ')}},     /* Wayuu */
-  {"guf",       {HB_TAG('G','U','F',' ')}},     /* Gupapuyngu */
-  {"gug",       {HB_TAG('G','U','A',' ')}},     /* Paraguayan Guaraní -> Guarani */
-  {"gui",       {HB_TAG('G','U','A',' ')}},     /* Eastern Bolivian Guaraní -> Guarani */
-  {"guk",       {HB_TAG('G','M','Z',' '),       /* Gumuz */
-                 HB_TAG('G','U','K',' ')}},     /* Gumuz (SIL fonts) */
-  {"gun",       {HB_TAG('G','U','A',' ')}},     /* Mbyá Guaraní -> Guarani */
-  {"guz",       {HB_TAG('G','U','Z',' ')}},     /* Gusii */
-  {"gv",        {HB_TAG('M','N','X',' ')}},     /* Manx */
-  {"gwi",       {HB_TAG('A','T','H',' ')}},     /* Gwichʼin -> Athapaskan */
-  {"ha",        {HB_TAG('H','A','U',' ')}},     /* Hausa */
-  {"haa",       {HB_TAG('A','T','H',' ')}},     /* Han -> Athapaskan */
-  {"hae",       {HB_TAG('O','R','O',' ')}},     /* Eastern Oromo -> Oromo */
-  {"hak",       {HB_TAG('Z','H','S',' ')}},     /* Hakka Chinese -> Chinese Simplified */
-  {"har",       {HB_TAG('H','R','I',' ')}},     /* Harari */
-  {"haw",       {HB_TAG('H','A','W',' ')}},     /* Hawaiian */
-  {"hay",       {HB_TAG('H','A','Y',' ')}},     /* Haya */
-  {"haz",       {HB_TAG('H','A','Z',' ')}},     /* Hazaragi */
-  {"he",        {HB_TAG('I','W','R',' ')}},     /* Hebrew */
-  {"hea",       {HB_TAG('H','M','N',' ')}},     /* Northern Qiandong Miao -> Hmong */
-  {"hi",        {HB_TAG('H','I','N',' ')}},     /* Hindi */
-  {"hil",       {HB_TAG('H','I','L',' ')}},     /* Hiligaynon */
-  {"hji",       {HB_TAG('M','L','Y',' ')}},     /* Haji -> Malay */
-  {"hlt",       {HB_TAG('Q','I','N',' ')}},     /* Matu Chin -> Chin */
-  {"hma",       {HB_TAG('H','M','N',' ')}},     /* Southern Mashan Hmong -> Hmong */
-  {"hmc",       {HB_TAG('H','M','N',' ')}},     /* Central Huishui Hmong -> Hmong */
-  {"hmd",       {HB_TAG('H','M','N',' ')}},     /* Large Flowery Miao -> Hmong */
-  {"hme",       {HB_TAG('H','M','N',' ')}},     /* Eastern Huishui Hmong -> Hmong */
-  {"hmg",       {HB_TAG('H','M','N',' ')}},     /* Southwestern Guiyang Hmong -> Hmong */
-  {"hmh",       {HB_TAG('H','M','N',' ')}},     /* Southwestern Huishui Hmong -> Hmong */
-  {"hmi",       {HB_TAG('H','M','N',' ')}},     /* Northern Huishui Hmong -> Hmong */
-  {"hmj",       {HB_TAG('H','M','N',' ')}},     /* Ge -> Hmong */
-  {"hml",       {HB_TAG('H','M','N',' ')}},     /* Luopohe Hmong -> Hmong */
-  {"hmm",       {HB_TAG('H','M','N',' ')}},     /* Central Mashan Hmong -> Hmong */
-  {"hmn",       {HB_TAG('H','M','N',' ')}},     /* Hmong [macrolanguage] */
-  {"hmp",       {HB_TAG('H','M','N',' ')}},     /* Northern Mashan Hmong -> Hmong */
-  {"hmq",       {HB_TAG('H','M','N',' ')}},     /* Eastern Qiandong Miao -> Hmong */
-  {"hms",       {HB_TAG('H','M','N',' ')}},     /* Southern Qiandong Miao -> Hmong */
-  {"hmw",       {HB_TAG('H','M','N',' ')}},     /* Western Mashan Hmong -> Hmong */
-  {"hmy",       {HB_TAG('H','M','N',' ')}},     /* Southern Guiyang Hmong -> Hmong */
-  {"hmz",       {HB_TAG('H','M','N',' ')}},     /* Hmong Shua -> Hmong */
-  {"hnd",       {HB_TAG('H','N','D',' ')}},     /* Southern Hindko -> Hindko */
-  {"hne",       {HB_TAG('C','H','H',' ')}},     /* Chhattisgarhi -> Chattisgarhi */
-  {"hnj",       {HB_TAG('H','M','N',' ')}},     /* Hmong Njua -> Hmong */
-  {"hno",       {HB_TAG('H','N','D',' ')}},     /* Northern Hindko -> Hindko */
-  {"ho",        {HB_TAG('H','M','O',' ')}},     /* Hiri Motu */
-  {"hoc",       {HB_TAG('H','O',' ',' ')}},     /* Ho */
-  {"hoi",       {HB_TAG('A','T','H',' ')}},     /* Holikachuk -> Athapaskan */
-  {"hoj",       {HB_TAG('H','A','R',' ')}},     /* Hadothi -> Harauti */
-  {"hr",        {HB_TAG('H','R','V',' ')}},     /* Croatian */
-  {"hrm",       {HB_TAG('H','M','N',' ')}},     /* Horned Miao -> Hmong */
-  {"hsb",       {HB_TAG('U','S','B',' ')}},     /* Upper Sorbian */
-  {"hsn",       {HB_TAG('Z','H','S',' ')}},     /* Xiang Chinese -> Chinese Simplified */
-  {"ht",        {HB_TAG('H','A','I',' ')}},     /* Haitian (Haitian Creole) */
-  {"hu",        {HB_TAG('H','U','N',' ')}},     /* Hungarian */
-  {"huj",       {HB_TAG('H','M','N',' ')}},     /* Northern Guiyang Hmong -> Hmong */
-  {"hup",       {HB_TAG('A','T','H',' ')}},     /* Hupa -> Athapaskan */
-  {"hy",        {HB_TAG('H','Y','E','0'),       /* Armenian -> Armenian East */
-                 HB_TAG('H','Y','E',' ')}},     /* Armenian */
-  {"hyw",       {HB_TAG('H','Y','E',' ')}},     /* Western Armenian -> Armenian */
-  {"hz",        {HB_TAG('H','E','R',' ')}},     /* Herero */
-  {"ia",        {HB_TAG('I','N','A',' ')}},     /* Interlingua (International Auxiliary Language Association) */
-  {"iba",       {HB_TAG('I','B','A',' ')}},     /* Iban */
-  {"ibb",       {HB_TAG('I','B','B',' ')}},     /* Ibibio */
-  {"id",        {HB_TAG('I','N','D',' ')}},     /* Indonesian */
-  {"ida",       {HB_TAG('L','U','H',' ')}},     /* Idakho-Isukha-Tiriki -> Luyia */
-  {"ie",        {HB_TAG('I','L','E',' ')}},     /* Interlingue */
-  {"ig",        {HB_TAG('I','B','O',' ')}},     /* Igbo */
-  {"igb",       {HB_TAG('E','B','I',' ')}},     /* Ebira */
-  {"ii",        {HB_TAG('Y','I','M',' ')}},     /* Sichuan Yi -> Yi Modern */
-  {"ijc",       {HB_TAG('I','J','O',' ')}},     /* Izon -> Ijo */
-  {"ijo",       {HB_TAG('I','J','O',' ')}},     /* Ijo [family] */
-  {"ik",        {HB_TAG('I','P','K',' ')}},     /* Inupiaq [macrolanguage] -> Inupiat */
-  {"ike",       {HB_TAG('I','N','U',' ')}},     /* Eastern Canadian Inuktitut -> Inuktitut */
-  {"ikt",       {HB_TAG('I','N','U',' ')}},     /* Inuinnaqtun -> Inuktitut */
-  {"ilo",       {HB_TAG('I','L','O',' ')}},     /* Iloko -> Ilokano */
-  {"in",        {HB_TAG('I','N','D',' ')}},     /* Indonesian (retired code) */
-  {"ing",       {HB_TAG('A','T','H',' ')}},     /* Degexit'an -> Athapaskan */
-  {"inh",       {HB_TAG('I','N','G',' ')}},     /* Ingush */
-  {"io",        {HB_TAG('I','D','O',' ')}},     /* Ido */
-  {"is",        {HB_TAG('I','S','L',' ')}},     /* Icelandic */
-  {"it",        {HB_TAG('I','T','A',' ')}},     /* Italian */
-  {"iu",        {HB_TAG('I','N','U',' ')}},     /* Inuktitut [macrolanguage] */
-  {"iw",        {HB_TAG('I','W','R',' ')}},     /* Hebrew (retired code) */
-  {"ja",        {HB_TAG('J','A','N',' ')}},     /* Japanese */
-  {"jak",       {HB_TAG('M','L','Y',' ')}},     /* Jakun -> Malay */
-  {"jam",       {HB_TAG('J','A','M',' ')}},     /* Jamaican Creole English -> Jamaican Creole */
-  {"jax",       {HB_TAG('M','L','Y',' ')}},     /* Jambi Malay -> Malay */
-  {"jbo",       {HB_TAG('J','B','O',' ')}},     /* Lojban */
-  {"jct",       {HB_TAG('J','C','T',' ')}},     /* Krymchak */
-  {"ji",        {HB_TAG('J','I','I',' ')}},     /* Yiddish (retired code) */
-  {"jv",        {HB_TAG('J','A','V',' ')}},     /* Javanese */
-  {"jw",        {HB_TAG('J','A','V',' ')}},     /* Javanese (retired code) */
-  {"ka",        {HB_TAG('K','A','T',' ')}},     /* Georgian */
-  {"kaa",       {HB_TAG('K','R','K',' ')}},     /* Kara-Kalpak -> Karakalpak */
-  {"kab",       {HB_TAG('K','A','B','0')}},     /* Kabyle */
-  {"kam",       {HB_TAG('K','M','B',' ')}},     /* Kamba (Kenya) */
-  {"kar",       {HB_TAG('K','R','N',' ')}},     /* Karen [family] */
-  {"kbd",       {HB_TAG('K','A','B',' ')}},     /* Kabardian */
-  {"kby",       {HB_TAG('K','N','R',' ')}},     /* Manga Kanuri -> Kanuri */
-  {"kca",       {HB_TAG('K','H','K',' '),       /* Khanty -> Khanty-Kazim */
-                 HB_TAG('K','H','S',' '),       /* Khanty -> Khanty-Shurishkar */
-                 HB_TAG('K','H','V',' ')}},     /* Khanty -> Khanty-Vakhi */
-  {"kde",       {HB_TAG('K','D','E',' ')}},     /* Makonde */
-  {"kdr",       {HB_TAG('K','R','M',' ')}},     /* Karaim */
-  {"kdt",       {HB_TAG('K','U','Y',' ')}},     /* Kuy */
-  {"kea",       {HB_TAG('K','E','A',' ')}},     /* Kabuverdianu (Crioulo) */
-  {"kek",       {HB_TAG('K','E','K',' ')}},     /* Kekchi */
-  {"kex",       {HB_TAG('K','K','N',' ')}},     /* Kukna -> Kokni */
-  {"kfa",       {HB_TAG('K','O','D',' ')}},     /* Kodava -> Kodagu */
-  {"kfr",       {HB_TAG('K','A','C',' ')}},     /* Kachhi -> Kachchi */
-  {"kfx",       {HB_TAG('K','U','L',' ')}},     /* Kullu Pahari -> Kulvi */
-  {"kfy",       {HB_TAG('K','M','N',' ')}},     /* Kumaoni */
-  {"kg",        {HB_TAG('K','O','N','0')}},     /* Kongo [macrolanguage] */
-  {"kha",       {HB_TAG('K','S','I',' ')}},     /* Khasi */
-  {"khb",       {HB_TAG('X','B','D',' ')}},     /* Lü */
-  {"khk",       {HB_TAG('M','N','G',' ')}},     /* Halh Mongolian -> Mongolian */
-  {"kht",       {HB_TAG('K','H','N',' '),       /* Khamti -> Khamti Shan (Microsoft fonts) */
-                 HB_TAG('K','H','T',' ')}},     /* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */
-  {"khw",       {HB_TAG('K','H','W',' ')}},     /* Khowar */
-  {"ki",        {HB_TAG('K','I','K',' ')}},     /* Kikuyu (Gikuyu) */
-  {"kiu",       {HB_TAG('K','I','U',' ')}},     /* Kirmanjki */
-  {"kj",        {HB_TAG('K','U','A',' ')}},     /* Kuanyama */
-  {"kjd",       {HB_TAG('K','J','D',' ')}},     /* Southern Kiwai */
-  {"kjh",       {HB_TAG('K','H','A',' ')}},     /* Khakas -> Khakass */
-  {"kjp",       {HB_TAG('K','J','P',' ')}},     /* Pwo Eastern Karen -> Eastern Pwo Karen */
-  {"kjz",       {HB_TAG('K','J','Z',' ')}},     /* Bumthangkha */
-  {"kk",        {HB_TAG('K','A','Z',' ')}},     /* Kazakh */
-  {"kkz",       {HB_TAG('A','T','H',' ')}},     /* Kaska -> Athapaskan */
-  {"kl",        {HB_TAG('G','R','N',' ')}},     /* Greenlandic */
-  {"kln",       {HB_TAG('K','A','L',' ')}},     /* Kalenjin [macrolanguage] */
-  {"km",        {HB_TAG('K','H','M',' ')}},     /* Khmer */
-  {"kmb",       {HB_TAG('M','B','N',' ')}},     /* Kimbundu -> Mbundu */
-  {"kmr",       {HB_TAG('K','U','R',' ')}},     /* Northern Kurdish -> Kurdish */
-  {"kmw",       {HB_TAG('K','M','O',' ')}},     /* Komo (Democratic Republic of Congo) */
-  {"kmz",       {HB_TAG('K','M','Z',' ')}},     /* Khorasani Turkish -> Khorasani Turkic */
-  {"kn",        {HB_TAG('K','A','N',' ')}},     /* Kannada */
-  {"knc",       {HB_TAG('K','N','R',' ')}},     /* Central Kanuri -> Kanuri */
-  {"kng",       {HB_TAG('K','O','N','0')}},     /* Koongo -> Kongo */
-  {"knn",       {HB_TAG('K','O','K',' ')}},     /* Konkani */
-  {"ko",        {HB_TAG('K','O','R',' ')}},     /* Korean */
-  {"koi",       {HB_TAG('K','O','P',' ')}},     /* Komi-Permyak */
-  {"kok",       {HB_TAG('K','O','K',' ')}},     /* Konkani [macrolanguage] */
-  {"kos",       {HB_TAG('K','O','S',' ')}},     /* Kosraean */
-  {"koy",       {HB_TAG('A','T','H',' ')}},     /* Koyukon -> Athapaskan */
-  {"kpe",       {HB_TAG('K','P','L',' ')}},     /* Kpelle [macrolanguage] */
-  {"kpv",       {HB_TAG('K','O','Z',' ')}},     /* Komi-Zyrian */
-  {"kpy",       {HB_TAG('K','Y','K',' ')}},     /* Koryak */
-  {"kqs",       {HB_TAG('K','I','S',' ')}},     /* Northern Kissi -> Kisii */
-  {"kqy",       {HB_TAG('K','R','T',' ')}},     /* Koorete */
-  {"kr",        {HB_TAG('K','N','R',' ')}},     /* Kanuri [macrolanguage] */
-  {"krc",       {HB_TAG('K','A','R',' '),       /* Karachay-Balkar -> Karachay */
-                 HB_TAG('B','A','L',' ')}},     /* Karachay-Balkar -> Balkar */
-  {"kri",       {HB_TAG('K','R','I',' ')}},     /* Krio */
-  {"krl",       {HB_TAG('K','R','L',' ')}},     /* Karelian */
-  {"krt",       {HB_TAG('K','N','R',' ')}},     /* Tumari Kanuri -> Kanuri */
-  {"kru",       {HB_TAG('K','U','U',' ')}},     /* Kurukh */
-  {"ks",        {HB_TAG('K','S','H',' ')}},     /* Kashmiri */
-  {"ksh",       {HB_TAG('K','S','H','0')}},     /* Kölsch -> Ripuarian */
-  {"kss",       {HB_TAG('K','I','S',' ')}},     /* Southern Kisi -> Kisii */
-  {"ksw",       {HB_TAG('K','S','W',' ')}},     /* S’gaw Karen */
-  {"ktb",       {HB_TAG('K','E','B',' ')}},     /* Kambaata -> Kebena */
-  {"ktu",       {HB_TAG('K','O','N',' ')}},     /* Kituba (Democratic Republic of Congo) -> Kikongo */
-  {"ktw",       {HB_TAG('A','T','H',' ')}},     /* Kato -> Athapaskan */
-  {"ku",        {HB_TAG('K','U','R',' ')}},     /* Kurdish [macrolanguage] */
-  {"kum",       {HB_TAG('K','U','M',' ')}},     /* Kumyk */
-  {"kuu",       {HB_TAG('A','T','H',' ')}},     /* Upper Kuskokwim -> Athapaskan */
-  {"kv",        {HB_TAG('K','O','M',' ')}},     /* Komi [macrolanguage] */
-  {"kvb",       {HB_TAG('M','L','Y',' ')}},     /* Kubu -> Malay */
-  {"kvr",       {HB_TAG('M','L','Y',' ')}},     /* Kerinci -> Malay */
-  {"kw",        {HB_TAG('C','O','R',' ')}},     /* Cornish */
-  {"kwy",       {HB_TAG('K','O','N','0')}},     /* San Salvador Kongo -> Kongo */
-  {"kxc",       {HB_TAG('K','M','S',' ')}},     /* Konso -> Komso */
-  {"kxd",       {HB_TAG('M','L','Y',' ')}},     /* Brunei -> Malay */
-  {"kxu",       {HB_TAG('K','U','I',' ')}},     /* Kui (India) */
-  {"ky",        {HB_TAG('K','I','R',' ')}},     /* Kirghiz (Kyrgyz) */
-  {"kyu",       {HB_TAG('K','Y','U',' ')}},     /* Western Kayah */
-  {"la",        {HB_TAG('L','A','T',' ')}},     /* Latin */
-  {"lad",       {HB_TAG('J','U','D',' ')}},     /* Ladino */
-  {"lb",        {HB_TAG('L','T','Z',' ')}},     /* Luxembourgish */
-  {"lbe",       {HB_TAG('L','A','K',' ')}},     /* Lak */
-  {"lbj",       {HB_TAG('L','D','K',' ')}},     /* Ladakhi */
-  {"lbl",       {HB_TAG('B','I','K',' ')}},     /* Libon Bikol -> Bikol */
-  {"lce",       {HB_TAG('M','L','Y',' ')}},     /* Loncong -> Malay */
-  {"lcf",       {HB_TAG('M','L','Y',' ')}},     /* Lubu -> Malay */
-  {"ldi",       {HB_TAG('K','O','N','0')}},     /* Laari -> Kongo */
-  {"lez",       {HB_TAG('L','E','Z',' ')}},     /* Lezghian -> Lezgi */
-  {"lg",        {HB_TAG('L','U','G',' ')}},     /* Ganda */
-  {"li",        {HB_TAG('L','I','M',' ')}},     /* Limburgish */
-  {"lif",       {HB_TAG('L','M','B',' ')}},     /* Limbu */
-  {"lij",       {HB_TAG('L','I','J',' ')}},     /* Ligurian */
-  {"lis",       {HB_TAG('L','I','S',' ')}},     /* Lisu */
-  {"liw",       {HB_TAG('M','L','Y',' ')}},     /* Col -> Malay */
-  {"ljp",       {HB_TAG('L','J','P',' ')}},     /* Lampung Api -> Lampung */
-  {"lkb",       {HB_TAG('L','U','H',' ')}},     /* Kabras -> Luyia */
-  {"lki",       {HB_TAG('L','K','I',' ')}},     /* Laki */
-  {"lko",       {HB_TAG('L','U','H',' ')}},     /* Khayo -> Luyia */
-  {"lks",       {HB_TAG('L','U','H',' ')}},     /* Kisa -> Luyia */
-  {"lld",       {HB_TAG('L','A','D',' ')}},     /* Ladin */
-  {"lmn",       {HB_TAG('L','A','M',' ')}},     /* Lambadi -> Lambani */
-  {"lmo",       {HB_TAG('L','M','O',' ')}},     /* Lombard */
-  {"ln",        {HB_TAG('L','I','N',' ')}},     /* Lingala */
-  {"lo",        {HB_TAG('L','A','O',' ')}},     /* Lao */
-  {"lom",       {HB_TAG('L','O','M',' ')}},     /* Loma (Liberia) */
-  {"lrc",       {HB_TAG('L','R','C',' ')}},     /* Northern Luri -> Luri */
-  {"lri",       {HB_TAG('L','U','H',' ')}},     /* Marachi -> Luyia */
-  {"lrm",       {HB_TAG('L','U','H',' ')}},     /* Marama -> Luyia */
-  {"lsm",       {HB_TAG('L','U','H',' ')}},     /* Saamia -> Luyia */
-  {"lt",        {HB_TAG('L','T','H',' ')}},     /* Lithuanian */
-  {"ltg",       {HB_TAG('L','V','I',' ')}},     /* Latgalian -> Latvian */
-  {"lto",       {HB_TAG('L','U','H',' ')}},     /* Tsotso -> Luyia */
-  {"lts",       {HB_TAG('L','U','H',' ')}},     /* Tachoni -> Luyia */
-  {"lu",        {HB_TAG('L','U','B',' ')}},     /* Luba-Katanga */
-  {"lua",       {HB_TAG('L','U','A',' ')}},     /* Luba-Lulua */
-  {"luo",       {HB_TAG('L','U','O',' ')}},     /* Luo (Kenya and Tanzania) */
-  {"lus",       {HB_TAG('M','I','Z',' ')}},     /* Lushai -> Mizo */
-  {"luy",       {HB_TAG('L','U','H',' ')}},     /* Luyia [macrolanguage] */
-  {"luz",       {HB_TAG('L','R','C',' ')}},     /* Southern Luri -> Luri */
-  {"lv",        {HB_TAG('L','V','I',' ')}},     /* Latvian [macrolanguage] */
-  {"lvs",       {HB_TAG('L','V','I',' ')}},     /* Standard Latvian -> Latvian */
-  {"lwg",       {HB_TAG('L','U','H',' ')}},     /* Wanga -> Luyia */
-  {"lzh",       {HB_TAG('Z','H','T',' ')}},     /* Literary Chinese -> Chinese Traditional */
-  {"lzz",       {HB_TAG('L','A','Z',' ')}},     /* Laz */
-  {"mad",       {HB_TAG('M','A','D',' ')}},     /* Madurese -> Madura */
-  {"mag",       {HB_TAG('M','A','G',' ')}},     /* Magahi */
-  {"mai",       {HB_TAG('M','T','H',' ')}},     /* Maithili */
-  {"mak",       {HB_TAG('M','K','R',' ')}},     /* Makasar */
-  {"mam",       {HB_TAG('M','A','M',' ')}},     /* Mam */
-  {"man",       {HB_TAG('M','N','K',' ')}},     /* Mandingo [macrolanguage] -> Maninka */
-  {"max",       {HB_TAG('M','L','Y',' ')}},     /* North Moluccan Malay -> Malay */
-  {"mbo",       {HB_TAG('M','B','O',' ')}},     /* Mbo (Cameroon) */
-  {"mct",       {HB_TAG('B','T','I',' ')}},     /* Mengisa -> Beti */
-  {"mdf",       {HB_TAG('M','O','K',' ')}},     /* Moksha */
-  {"mdr",       {HB_TAG('M','D','R',' ')}},     /* Mandar */
-  {"mdy",       {HB_TAG('M','L','E',' ')}},     /* Male (Ethiopia) */
-  {"men",       {HB_TAG('M','D','E',' ')}},     /* Mende (Sierra Leone) */
-  {"meo",       {HB_TAG('M','L','Y',' ')}},     /* Kedah Malay -> Malay */
-  {"mer",       {HB_TAG('M','E','R',' ')}},     /* Meru */
-  {"mfa",       {HB_TAG('M','F','A',' ')}},     /* Pattani Malay */
-  {"mfb",       {HB_TAG('M','L','Y',' ')}},     /* Bangka -> Malay */
-  {"mfe",       {HB_TAG('M','F','E',' ')}},     /* Morisyen */
-  {"mg",        {HB_TAG('M','L','G',' ')}},     /* Malagasy [macrolanguage] */
-  {"mh",        {HB_TAG('M','A','H',' ')}},     /* Marshallese */
-  {"mhr",       {HB_TAG('L','M','A',' ')}},     /* Eastern Mari -> Low Mari */
-  {"mhv",       {HB_TAG('A','R','K',' ')}},     /* Arakanese (retired code) -> Rakhine */
-  {"mi",        {HB_TAG('M','R','I',' ')}},     /* Maori */
-  {"min",       {HB_TAG('M','I','N',' ')}},     /* Minangkabau */
-  {"mk",        {HB_TAG('M','K','D',' ')}},     /* Macedonian */
-  {"mku",       {HB_TAG('M','N','K',' ')}},     /* Konyanka Maninka -> Maninka */
-  {"mkw",       {HB_TAG('M','K','W',' ')}},     /* Kituba (Congo) */
-  {"ml",        {HB_TAG('M','A','L',' '),       /* Malayalam -> Malayalam Traditional */
-                 HB_TAG('M','L','R',' ')}},     /* Malayalam -> Malayalam Reformed */
-  {"mlq",       {HB_TAG('M','L','N',' '),       /* Western Maninkakan -> Malinke */
-                 HB_TAG('M','N','K',' ')}},     /* Western Maninkakan -> Maninka */
-  {"mmr",       {HB_TAG('H','M','N',' ')}},     /* Western Xiangxi Miao -> Hmong */
-  {"mn",        {HB_TAG('M','N','G',' ')}},     /* Mongolian [macrolanguage] */
-  {"mnc",       {HB_TAG('M','C','H',' ')}},     /* Manchu */
-  {"mni",       {HB_TAG('M','N','I',' ')}},     /* Manipuri */
-  {"mnk",       {HB_TAG('M','N','D',' '),       /* Mandinka */
-                 HB_TAG('M','N','K',' ')}},     /* Mandinka -> Maninka */
-  {"mnp",       {HB_TAG('Z','H','S',' ')}},     /* Min Bei Chinese -> Chinese Simplified */
-  {"mns",       {HB_TAG('M','A','N',' ')}},     /* Mansi */
-  {"mnw",       {HB_TAG('M','O','N',' ')}},     /* Mon */
-  {"mo",        {HB_TAG('M','O','L',' ')}},     /* Moldavian (retired code) */
-  {"moh",       {HB_TAG('M','O','H',' ')}},     /* Mohawk */
-  {"mos",       {HB_TAG('M','O','S',' ')}},     /* Mossi */
-  {"mpe",       {HB_TAG('M','A','J',' ')}},     /* Majang */
-  {"mqg",       {HB_TAG('M','L','Y',' ')}},     /* Kota Bangun Kutai Malay -> Malay */
-  {"mr",        {HB_TAG('M','A','R',' ')}},     /* Marathi */
-  {"mrh",       {HB_TAG('Q','I','N',' ')}},     /* Mara Chin -> Chin */
-  {"mrj",       {HB_TAG('H','M','A',' ')}},     /* Western Mari -> High Mari */
-  {"ms",        {HB_TAG('M','L','Y',' ')}},     /* Malay [macrolanguage] */
-  {"msc",       {HB_TAG('M','N','K',' ')}},     /* Sankaran Maninka -> Maninka */
-  {"msh",       {HB_TAG('M','L','G',' ')}},     /* Masikoro Malagasy -> Malagasy */
-  {"msi",       {HB_TAG('M','L','Y',' ')}},     /* Sabah Malay -> Malay */
-  {"mt",        {HB_TAG('M','T','S',' ')}},     /* Maltese */
-  {"mtr",       {HB_TAG('M','A','W',' ')}},     /* Mewari -> Marwari */
-  {"mui",       {HB_TAG('M','L','Y',' ')}},     /* Musi -> Malay */
-  {"mup",       {HB_TAG('R','A','J',' ')}},     /* Malvi -> Rajasthani */
-  {"muq",       {HB_TAG('H','M','N',' ')}},     /* Eastern Xiangxi Miao -> Hmong */
-  {"mus",       {HB_TAG('M','U','S',' ')}},     /* Creek -> Muscogee */
-  {"mvb",       {HB_TAG('A','T','H',' ')}},     /* Mattole -> Athapaskan */
-  {"mve",       {HB_TAG('M','A','W',' ')}},     /* Marwari (Pakistan) */
-  {"mvf",       {HB_TAG('M','N','G',' ')}},     /* Peripheral Mongolian -> Mongolian */
-  {"mwk",       {HB_TAG('M','N','K',' ')}},     /* Kita Maninkakan -> Maninka */
-  {"mwl",       {HB_TAG('M','W','L',' ')}},     /* Mirandese */
-  {"mwr",       {HB_TAG('M','A','W',' ')}},     /* Marwari [macrolanguage] */
-  {"mww",       {HB_TAG('M','W','W',' ')}},     /* Hmong Daw */
-  {"my",        {HB_TAG('B','R','M',' ')}},     /* Burmese */
-  {"mym",       {HB_TAG('M','E','N',' ')}},     /* Me'en */
-  {"myn",       {HB_TAG('M','Y','N',' ')}},     /* Mayan [family] */
-  {"myq",       {HB_TAG('M','N','K',' ')}},     /* Forest Maninka (retired code) -> Maninka */
-  {"myv",       {HB_TAG('E','R','Z',' ')}},     /* Erzya */
-  {"mzn",       {HB_TAG('M','Z','N',' ')}},     /* Mazanderani */
-  {"na",        {HB_TAG('N','A','U',' ')}},     /* Nauru -> Nauruan */
-  {"nag",       {HB_TAG('N','A','G',' ')}},     /* Naga Pidgin -> Naga-Assamese */
-  {"nah",       {HB_TAG('N','A','H',' ')}},     /* Nahuatl [family] */
-  {"nan",       {HB_TAG('Z','H','S',' ')}},     /* Min Nan Chinese -> Chinese Simplified */
-  {"nap",       {HB_TAG('N','A','P',' ')}},     /* Neapolitan */
-  {"nb",        {HB_TAG('N','O','R',' ')}},     /* Norwegian Bokmål -> Norwegian */
-  {"nd",        {HB_TAG('N','D','B',' ')}},     /* North Ndebele -> Ndebele */
-  {"ndc",       {HB_TAG('N','D','C',' ')}},     /* Ndau */
-  {"nds",       {HB_TAG('N','D','S',' ')}},     /* Low Saxon */
-  {"ne",        {HB_TAG('N','E','P',' ')}},     /* Nepali [macrolanguage] */
-  {"new",       {HB_TAG('N','E','W',' ')}},     /* Newari */
-  {"ng",        {HB_TAG('N','D','G',' ')}},     /* Ndonga */
-  {"nga",       {HB_TAG('N','G','A',' ')}},     /* Ngbaka */
-  {"ngl",       {HB_TAG('L','M','W',' ')}},     /* Lomwe */
-  {"ngo",       {HB_TAG('S','X','T',' ')}},     /* Ngoni -> Sutu */
-  {"nhd",       {HB_TAG('G','U','A',' ')}},     /* Chiripá -> Guarani */
-  {"niq",       {HB_TAG('K','A','L',' ')}},     /* Nandi -> Kalenjin */
-  {"niu",       {HB_TAG('N','I','U',' ')}},     /* Niuean */
-  {"niv",       {HB_TAG('G','I','L',' ')}},     /* Gilyak */
-  {"njz",       {HB_TAG('N','I','S',' ')}},     /* Nyishi -> Nisi */
-  {"nl",        {HB_TAG('N','L','D',' ')}},     /* Dutch */
-  {"nle",       {HB_TAG('L','U','H',' ')}},     /* East Nyala -> Luyia */
-  {"nn",        {HB_TAG('N','Y','N',' ')}},     /* Norwegian Nynorsk (Nynorsk, Norwegian) */
-  {"no",        {HB_TAG('N','O','R',' ')}},     /* Norwegian [macrolanguage] */
-  {"nod",       {HB_TAG('N','T','A',' ')}},     /* Northern Thai -> Northern Tai */
-  {"noe",       {HB_TAG('N','O','E',' ')}},     /* Nimadi */
-  {"nog",       {HB_TAG('N','O','G',' ')}},     /* Nogai */
-  {"nov",       {HB_TAG('N','O','V',' ')}},     /* Novial */
-  {"npi",       {HB_TAG('N','E','P',' ')}},     /* Nepali */
-  {"nqo",       {HB_TAG('N','K','O',' ')}},     /* N'Ko */
-  {"nr",        {HB_TAG('N','D','B',' ')}},     /* South Ndebele -> Ndebele */
-  {"nsk",       {HB_TAG('N','A','S',' ')}},     /* Naskapi */
-  {"nso",       {HB_TAG('N','S','O',' ')}},     /* Pedi -> Sotho, Northern */
-  {"nv",        {HB_TAG('N','A','V',' '),       /* Navajo */
-                 HB_TAG('A','T','H',' ')}},     /* Navajo -> Athapaskan */
-  {"ny",        {HB_TAG('C','H','I',' ')}},     /* Chichewa (Chewa, Nyanja) */
-  {"nyd",       {HB_TAG('L','U','H',' ')}},     /* Nyore -> Luyia */
-  {"nym",       {HB_TAG('N','Y','M',' ')}},     /* Nyamwezi */
-  {"nyn",       {HB_TAG('N','K','L',' ')}},     /* Nyankole */
-  {"nza",       {HB_TAG('N','Z','A',' ')}},     /* Tigon Mbembe -> Mbembe Tigon */
-  {"oc",        {HB_TAG('O','C','I',' ')}},     /* Occitan (post 1500) */
-  {"oj",        {HB_TAG('O','J','B',' ')}},     /* Ojibwa [macrolanguage] -> Ojibway */
-  {"ojb",       {HB_TAG('O','J','B',' ')}},     /* Northwestern Ojibwa -> Ojibway */
-  {"ojc",       {HB_TAG('O','J','B',' ')}},     /* Central Ojibwa -> Ojibway */
-  {"ojg",       {HB_TAG('O','J','B',' ')}},     /* Eastern Ojibwa -> Ojibway */
-  {"ojs",       {HB_TAG('O','C','R',' ')}},     /* Severn Ojibwa -> Oji-Cree */
-  {"ojw",       {HB_TAG('O','J','B',' ')}},     /* Western Ojibwa -> Ojibway */
-  {"oki",       {HB_TAG('K','A','L',' ')}},     /* Okiek -> Kalenjin */
-  {"okm",       {HB_TAG('K','O','H',' ')}},     /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
-  {"om",        {HB_TAG('O','R','O',' ')}},     /* Oromo [macrolanguage] */
-  {"or",        {HB_TAG('O','R','I',' ')}},     /* Odia (formerly Oriya) [macrolanguage] */
-  {"orc",       {HB_TAG('O','R','O',' ')}},     /* Orma -> Oromo */
-  {"orn",       {HB_TAG('M','L','Y',' ')}},     /* Orang Kanaq -> Malay */
-  {"ors",       {HB_TAG('M','L','Y',' ')}},     /* Orang Seletar -> Malay */
-  {"ory",       {HB_TAG('O','R','I',' ')}},     /* Odia (formerly Oriya) */
-  {"os",        {HB_TAG('O','S','S',' ')}},     /* Ossetian */
-  {"otw",       {HB_TAG('O','J','B',' ')}},     /* Ottawa -> Ojibway */
-  {"pa",        {HB_TAG('P','A','N',' ')}},     /* Punjabi */
-  {"pag",       {HB_TAG('P','A','G',' ')}},     /* Pangasinan */
-  {"pam",       {HB_TAG('P','A','M',' ')}},     /* Pampanga -> Pampangan */
-  {"pap",       {HB_TAG('P','A','P','0')}},     /* Papiamento -> Papiamentu */
-  {"pau",       {HB_TAG('P','A','U',' ')}},     /* Palauan */
-  {"pbt",       {HB_TAG('P','A','S',' ')}},     /* Southern Pashto -> Pashto */
-  {"pbu",       {HB_TAG('P','A','S',' ')}},     /* Northern Pashto -> Pashto */
-  {"pcc",       {HB_TAG('P','C','C',' ')}},     /* Bouyei */
-  {"pcd",       {HB_TAG('P','C','D',' ')}},     /* Picard */
-  {"pce",       {HB_TAG('P','L','G',' ')}},     /* Ruching Palaung -> Palaung */
-  {"pck",       {HB_TAG('Q','I','N',' ')}},     /* Paite Chin -> Chin */
-  {"pdc",       {HB_TAG('P','D','C',' ')}},     /* Pennsylvania German */
-  {"pel",       {HB_TAG('M','L','Y',' ')}},     /* Pekal -> Malay */
-  {"pes",       {HB_TAG('F','A','R',' ')}},     /* Iranian Persian -> Persian */
-  {"pga",       {HB_TAG('A','R','A',' ')}},     /* Sudanese Creole Arabic -> Arabic */
-  {"phk",       {HB_TAG('P','H','K',' ')}},     /* Phake */
-  {"pi",        {HB_TAG('P','A','L',' ')}},     /* Pali */
-  {"pih",       {HB_TAG('P','I','H',' ')}},     /* Pitcairn-Norfolk -> Norfolk */
-  {"pko",       {HB_TAG('K','A','L',' ')}},     /* Pökoot -> Kalenjin */
-  {"pl",        {HB_TAG('P','L','K',' ')}},     /* Polish */
-  {"pll",       {HB_TAG('P','L','G',' ')}},     /* Shwe Palaung -> Palaung */
-  {"plp",       {HB_TAG('P','A','P',' ')}},     /* Palpa */
-  {"plt",       {HB_TAG('M','L','G',' ')}},     /* Plateau Malagasy -> Malagasy */
-  {"pms",       {HB_TAG('P','M','S',' ')}},     /* Piemontese */
-  {"pnb",       {HB_TAG('P','N','B',' ')}},     /* Western Panjabi */
-  {"poh",       {HB_TAG('P','O','H',' ')}},     /* Poqomchi' -> Pocomchi */
-  {"pon",       {HB_TAG('P','O','N',' ')}},     /* Pohnpeian */
-  {"ppa",       {HB_TAG('B','A','G',' ')}},     /* Pao (retired code) -> Baghelkhandi */
-  {"pro",       {HB_TAG('P','R','O',' ')}},     /* Old Provençal (to 1500) -> Provençal / Old Provençal */
-  {"prs",       {HB_TAG('D','R','I',' ')}},     /* Dari */
-  {"ps",        {HB_TAG('P','A','S',' ')}},     /* Pashto [macrolanguage] */
-  {"pse",       {HB_TAG('M','L','Y',' ')}},     /* Central Malay -> Malay */
-  {"pst",       {HB_TAG('P','A','S',' ')}},     /* Central Pashto -> Pashto */
-  {"pt",        {HB_TAG('P','T','G',' ')}},     /* Portuguese */
-  {"pwo",       {HB_TAG('P','W','O',' ')}},     /* Pwo Western Karen -> Western Pwo Karen */
-  {"qu",        {HB_TAG('Q','U','Z',' ')}},     /* Quechua [macrolanguage] */
-  {"qub",       {HB_TAG('Q','W','H',' ')}},     /* Huallaga Huánuco Quechua -> Quechua (Peru) */
-  {"quc",       {HB_TAG('Q','U','C',' ')}},     /* K’iche’ */
-  {"qud",       {HB_TAG('Q','V','I',' ')}},     /* Calderón Highland Quichua -> Quechua (Ecuador) */
-  {"quf",       {HB_TAG('Q','U','Z',' ')}},     /* Lambayeque Quechua -> Quechua */
-  {"qug",       {HB_TAG('Q','V','I',' ')}},     /* Chimborazo Highland Quichua -> Quechua (Ecuador) */
-  {"quh",       {HB_TAG('Q','U','H',' ')}},     /* South Bolivian Quechua -> Quechua (Bolivia) */
-  {"quk",       {HB_TAG('Q','U','Z',' ')}},     /* Chachapoyas Quechua -> Quechua */
-  {"qul",       {HB_TAG('Q','U','Z',' ')}},     /* North Bolivian Quechua -> Quechua */
-  {"qup",       {HB_TAG('Q','V','I',' ')}},     /* Southern Pastaza Quechua -> Quechua (Ecuador) */
-  {"qur",       {HB_TAG('Q','W','H',' ')}},     /* Yanahuanca Pasco Quechua -> Quechua (Peru) */
-  {"qus",       {HB_TAG('Q','U','H',' ')}},     /* Santiago del Estero Quichua -> Quechua (Bolivia) */
-  {"quw",       {HB_TAG('Q','V','I',' ')}},     /* Tena Lowland Quichua -> Quechua (Ecuador) */
-  {"qux",       {HB_TAG('Q','W','H',' ')}},     /* Yauyos Quechua -> Quechua (Peru) */
-  {"quy",       {HB_TAG('Q','U','Z',' ')}},     /* Ayacucho Quechua -> Quechua */
-  {"quz",       {HB_TAG('Q','U','Z',' ')}},     /* Cusco Quechua -> Quechua */
-  {"qva",       {HB_TAG('Q','W','H',' ')}},     /* Ambo-Pasco Quechua -> Quechua (Peru) */
-  {"qvc",       {HB_TAG('Q','U','Z',' ')}},     /* Cajamarca Quechua -> Quechua */
-  {"qve",       {HB_TAG('Q','U','Z',' ')}},     /* Eastern Apurímac Quechua -> Quechua */
-  {"qvh",       {HB_TAG('Q','W','H',' ')}},     /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */
-  {"qvi",       {HB_TAG('Q','V','I',' ')}},     /* Imbabura Highland Quichua -> Quechua (Ecuador) */
-  {"qvj",       {HB_TAG('Q','V','I',' ')}},     /* Loja Highland Quichua -> Quechua (Ecuador) */
-  {"qvl",       {HB_TAG('Q','W','H',' ')}},     /* Cajatambo North Lima Quechua -> Quechua (Peru) */
-  {"qvm",       {HB_TAG('Q','W','H',' ')}},     /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */
-  {"qvn",       {HB_TAG('Q','W','H',' ')}},     /* North Junín Quechua -> Quechua (Peru) */
-  {"qvo",       {HB_TAG('Q','V','I',' ')}},     /* Napo Lowland Quechua -> Quechua (Ecuador) */
-  {"qvp",       {HB_TAG('Q','W','H',' ')}},     /* Pacaraos Quechua -> Quechua (Peru) */
-  {"qvs",       {HB_TAG('Q','U','Z',' ')}},     /* San Martín Quechua -> Quechua */
-  {"qvw",       {HB_TAG('Q','W','H',' ')}},     /* Huaylla Wanca Quechua -> Quechua (Peru) */
-  {"qvz",       {HB_TAG('Q','V','I',' ')}},     /* Northern Pastaza Quichua -> Quechua (Ecuador) */
-  {"qwa",       {HB_TAG('Q','W','H',' ')}},     /* Corongo Ancash Quechua -> Quechua (Peru) */
-  {"qwc",       {HB_TAG('Q','U','Z',' ')}},     /* Classical Quechua -> Quechua */
-  {"qwh",       {HB_TAG('Q','W','H',' ')}},     /* Huaylas Ancash Quechua -> Quechua (Peru) */
-  {"qws",       {HB_TAG('Q','W','H',' ')}},     /* Sihuas Ancash Quechua -> Quechua (Peru) */
-  {"qxa",       {HB_TAG('Q','W','H',' ')}},     /* Chiquián Ancash Quechua -> Quechua (Peru) */
-  {"qxc",       {HB_TAG('Q','W','H',' ')}},     /* Chincha Quechua -> Quechua (Peru) */
-  {"qxh",       {HB_TAG('Q','W','H',' ')}},     /* Panao Huánuco Quechua -> Quechua (Peru) */
-  {"qxl",       {HB_TAG('Q','V','I',' ')}},     /* Salasaca Highland Quichua -> Quechua (Ecuador) */
-  {"qxn",       {HB_TAG('Q','W','H',' ')}},     /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */
-  {"qxo",       {HB_TAG('Q','W','H',' ')}},     /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */
-  {"qxp",       {HB_TAG('Q','U','Z',' ')}},     /* Puno Quechua -> Quechua */
-  {"qxr",       {HB_TAG('Q','V','I',' ')}},     /* Cañar Highland Quichua -> Quechua (Ecuador) */
-  {"qxt",       {HB_TAG('Q','W','H',' ')}},     /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */
-  {"qxu",       {HB_TAG('Q','U','Z',' ')}},     /* Arequipa-La Unión Quechua -> Quechua */
-  {"qxw",       {HB_TAG('Q','W','H',' ')}},     /* Jauja Wanca Quechua -> Quechua (Peru) */
-  {"rag",       {HB_TAG('L','U','H',' ')}},     /* Logooli -> Luyia */
-  {"raj",       {HB_TAG('R','A','J',' ')}},     /* Rajasthani [macrolanguage] */
-  {"rar",       {HB_TAG('R','A','R',' ')}},     /* Rarotongan */
-  {"rbb",       {HB_TAG('P','L','G',' ')}},     /* Rumai Palaung -> Palaung */
-  {"rbl",       {HB_TAG('B','I','K',' ')}},     /* Miraya Bikol -> Bikol */
-  {"rej",       {HB_TAG('R','E','J',' ')}},     /* Rejang */
-  {"ria",       {HB_TAG('R','I','A',' ')}},     /* Riang (India) */
-  {"rif",       {HB_TAG('R','I','F',' ')}},     /* Tarifit */
-  {"rit",       {HB_TAG('R','I','T',' ')}},     /* Ritarungo */
-  {"rki",       {HB_TAG('A','R','K',' ')}},     /* Rakhine */
-  {"rkw",       {HB_TAG('R','K','W',' ')}},     /* Arakwal */
-  {"rm",        {HB_TAG('R','M','S',' ')}},     /* Romansh */
-  {"rmc",       {HB_TAG('R','O','Y',' ')}},     /* Carpathian Romani -> Romany */
-  {"rmf",       {HB_TAG('R','O','Y',' ')}},     /* Kalo Finnish Romani -> Romany */
-  {"rml",       {HB_TAG('R','O','Y',' ')}},     /* Baltic Romani -> Romany */
-  {"rmn",       {HB_TAG('R','O','Y',' ')}},     /* Balkan Romani -> Romany */
-  {"rmo",       {HB_TAG('R','O','Y',' ')}},     /* Sinte Romani -> Romany */
-  {"rmw",       {HB_TAG('R','O','Y',' ')}},     /* Welsh Romani -> Romany */
-  {"rmy",       {HB_TAG('R','M','Y',' ')}},     /* Vlax Romani */
-  {"rmz",       {HB_TAG('A','R','K',' ')}},     /* Marma -> Rakhine */
-  {"rn",        {HB_TAG('R','U','N',' ')}},     /* Rundi */
-  {"rnl",       {HB_TAG('H','A','L',' ')}},     /* Ranglong -> Halam (Falam Chin) */
-  {"ro",        {HB_TAG('R','O','M',' ')}},     /* Romanian */
-  {"rom",       {HB_TAG('R','O','Y',' ')}},     /* Romany [macrolanguage] */
-  {"rtm",       {HB_TAG('R','T','M',' ')}},     /* Rotuman */
-  {"ru",        {HB_TAG('R','U','S',' ')}},     /* Russian */
-  {"rue",       {HB_TAG('R','S','Y',' ')}},     /* Rusyn */
-  {"rup",       {HB_TAG('R','U','P',' ')}},     /* Aromanian */
-  {"rw",        {HB_TAG('R','U','A',' ')}},     /* Kinyarwanda */
-  {"rwr",       {HB_TAG('M','A','W',' ')}},     /* Marwari (India) */
-  {"sa",        {HB_TAG('S','A','N',' ')}},     /* Sanskrit */
-  {"sah",       {HB_TAG('Y','A','K',' ')}},     /* Yakut -> Sakha */
-  {"sam",       {HB_TAG('P','A','A',' ')}},     /* Samaritan Aramaic -> Palestinian Aramaic */
-  {"sas",       {HB_TAG('S','A','S',' ')}},     /* Sasak */
-  {"sat",       {HB_TAG('S','A','T',' ')}},     /* Santali */
-  {"sc",        {HB_TAG('S','R','D',' ')}},     /* Sardinian [macrolanguage] */
-  {"sck",       {HB_TAG('S','A','D',' ')}},     /* Sadri */
-  {"scn",       {HB_TAG('S','C','N',' ')}},     /* Sicilian */
-  {"sco",       {HB_TAG('S','C','O',' ')}},     /* Scots */
-  {"scs",       {HB_TAG('S','C','S',' '),       /* North Slavey */
-                 HB_TAG('S','L','A',' '),       /* North Slavey -> Slavey */
-                 HB_TAG('A','T','H',' ')}},     /* North Slavey -> Athapaskan */
-  {"sd",        {HB_TAG('S','N','D',' ')}},     /* Sindhi */
-  {"sdc",       {HB_TAG('S','R','D',' ')}},     /* Sassarese Sardinian -> Sardinian */
-  {"sdh",       {HB_TAG('K','U','R',' ')}},     /* Southern Kurdish -> Kurdish */
-  {"sdn",       {HB_TAG('S','R','D',' ')}},     /* Gallurese Sardinian -> Sardinian */
-  {"se",        {HB_TAG('N','S','M',' ')}},     /* Northern Sami */
-  {"seh",       {HB_TAG('S','N','A',' ')}},     /* Sena */
-  {"sek",       {HB_TAG('A','T','H',' ')}},     /* Sekani -> Athapaskan */
-  {"sel",       {HB_TAG('S','E','L',' ')}},     /* Selkup */
-  {"sez",       {HB_TAG('Q','I','N',' ')}},     /* Senthang Chin -> Chin */
-  {"sfm",       {HB_TAG('H','M','N',' ')}},     /* Small Flowery Miao -> Hmong */
-  {"sg",        {HB_TAG('S','G','O',' ')}},     /* Sango */
-  {"sga",       {HB_TAG('S','G','A',' ')}},     /* Old Irish (to 900) */
-  {"sgc",       {HB_TAG('K','A','L',' ')}},     /* Kipsigis -> Kalenjin */
-  {"sgs",       {HB_TAG('S','G','S',' ')}},     /* Samogitian */
-  {"sgw",       {HB_TAG('C','H','G',' '),       /* Sebat Bet Gurage -> Chaha Gurage */
-                 HB_TAG('S','G','W',' ')}},     /* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */
-  {"shi",       {HB_TAG('S','H','I',' ')}},     /* Tachelhit */
-  {"shn",       {HB_TAG('S','H','N',' ')}},     /* Shan */
-  {"shu",       {HB_TAG('A','R','A',' ')}},     /* Chadian Arabic -> Arabic */
-  {"si",        {HB_TAG('S','N','H',' ')}},     /* Sinhala (Sinhalese) */
-  {"sid",       {HB_TAG('S','I','D',' ')}},     /* Sidamo */
-  {"sjd",       {HB_TAG('K','S','M',' ')}},     /* Kildin Sami */
-  {"sjo",       {HB_TAG('S','I','B',' ')}},     /* Xibe -> Sibe */
-  {"sk",        {HB_TAG('S','K','Y',' ')}},     /* Slovak */
-  {"skg",       {HB_TAG('M','L','G',' ')}},     /* Sakalava Malagasy -> Malagasy */
-  {"skr",       {HB_TAG('S','R','K',' ')}},     /* Saraiki */
-  {"sl",        {HB_TAG('S','L','V',' ')}},     /* Slovenian */
-  {"sm",        {HB_TAG('S','M','O',' ')}},     /* Samoan */
-  {"sma",       {HB_TAG('S','S','M',' ')}},     /* Southern Sami */
-  {"smj",       {HB_TAG('L','S','M',' ')}},     /* Lule Sami */
-  {"smn",       {HB_TAG('I','S','M',' ')}},     /* Inari Sami */
-  {"sms",       {HB_TAG('S','K','S',' ')}},     /* Skolt Sami */
-  {"sn",        {HB_TAG('S','N','A','0')}},     /* Shona */
-  {"snk",       {HB_TAG('S','N','K',' ')}},     /* Soninke */
-  {"so",        {HB_TAG('S','M','L',' ')}},     /* Somali */
-  {"sop",       {HB_TAG('S','O','P',' ')}},     /* Songe */
-  {"spv",       {HB_TAG('O','R','I',' ')}},     /* Sambalpuri -> Odia (formerly Oriya) */
-  {"spy",       {HB_TAG('K','A','L',' ')}},     /* Sabaot -> Kalenjin */
-  {"sq",        {HB_TAG('S','Q','I',' ')}},     /* Albanian [macrolanguage] */
-  {"sr",        {HB_TAG('S','R','B',' ')}},     /* Serbian */
-  {"src",       {HB_TAG('S','R','D',' ')}},     /* Logudorese Sardinian -> Sardinian */
-  {"sro",       {HB_TAG('S','R','D',' ')}},     /* Campidanese Sardinian -> Sardinian */
-  {"srr",       {HB_TAG('S','R','R',' ')}},     /* Serer */
-  {"srs",       {HB_TAG('A','T','H',' ')}},     /* Sarsi -> Athapaskan */
-  {"ss",        {HB_TAG('S','W','Z',' ')}},     /* Swati */
-  {"ssh",       {HB_TAG('A','R','A',' ')}},     /* Shihhi Arabic -> Arabic */
-  {"st",        {HB_TAG('S','O','T',' ')}},     /* Southern Sotho -> Sotho, Southern */
-  {"stq",       {HB_TAG('S','T','Q',' ')}},     /* Saterfriesisch -> Saterland Frisian */
-  {"stv",       {HB_TAG('S','I','G',' ')}},     /* Silt'e -> Silte Gurage */
-  {"su",        {HB_TAG('S','U','N',' ')}},     /* Sundanese */
-  {"suk",       {HB_TAG('S','U','K',' ')}},     /* Sukuma */
-  {"suq",       {HB_TAG('S','U','R',' ')}},     /* Suri */
-  {"sv",        {HB_TAG('S','V','E',' ')}},     /* Swedish */
-  {"sva",       {HB_TAG('S','V','A',' ')}},     /* Svan */
-  {"sw",        {HB_TAG('S','W','K',' ')}},     /* Swahili [macrolanguage] */
-  {"swb",       {HB_TAG('C','M','R',' ')}},     /* Maore Comorian -> Comorian */
-  {"swc",       {HB_TAG('S','W','K',' ')}},     /* Congo Swahili -> Swahili */
-  {"swh",       {HB_TAG('S','W','K',' ')}},     /* Swahili */
-  {"swv",       {HB_TAG('M','A','W',' ')}},     /* Shekhawati -> Marwari */
-  {"sxu",       {HB_TAG('S','X','U',' ')}},     /* Upper Saxon */
-  {"syc",       {HB_TAG('S','Y','R',' ')}},     /* Classical Syriac -> Syriac */
-  {"syl",       {HB_TAG('S','Y','L',' ')}},     /* Sylheti */
-  {"syr",       {HB_TAG('S','Y','R',' ')}},     /* Syriac [macrolanguage] */
-  {"szl",       {HB_TAG('S','Z','L',' ')}},     /* Silesian */
-  {"ta",        {HB_TAG('T','A','M',' ')}},     /* Tamil */
-  {"taa",       {HB_TAG('A','T','H',' ')}},     /* Lower Tanana -> Athapaskan */
-  {"tab",       {HB_TAG('T','A','B',' ')}},     /* Tabassaran -> Tabasaran */
-  {"taq",       {HB_TAG('T','M','H',' ')}},     /* Tamasheq -> Tamashek */
-  {"tau",       {HB_TAG('A','T','H',' ')}},     /* Upper Tanana -> Athapaskan */
-  {"tcb",       {HB_TAG('A','T','H',' ')}},     /* Tanacross -> Athapaskan */
-  {"tce",       {HB_TAG('A','T','H',' ')}},     /* Southern Tutchone -> Athapaskan */
-  {"tcp",       {HB_TAG('Q','I','N',' ')}},     /* Tawr Chin -> Chin */
-  {"tcy",       {HB_TAG('T','U','L',' ')}},     /* Tulu -> Tumbuka */
-  {"tcz",       {HB_TAG('Q','I','N',' ')}},     /* Thado Chin -> Chin */
-  {"tdd",       {HB_TAG('T','D','D',' ')}},     /* Tai Nüa -> Dehong Dai */
-  {"tdx",       {HB_TAG('M','L','G',' ')}},     /* Tandroy-Mahafaly Malagasy -> Malagasy */
-  {"te",        {HB_TAG('T','E','L',' ')}},     /* Telugu */
-  {"tec",       {HB_TAG('K','A','L',' ')}},     /* Terik -> Kalenjin */
-  {"tem",       {HB_TAG('T','M','N',' ')}},     /* Timne -> Temne */
-  {"tet",       {HB_TAG('T','E','T',' ')}},     /* Tetum */
-  {"tfn",       {HB_TAG('A','T','H',' ')}},     /* Tanaina -> Athapaskan */
-  {"tg",        {HB_TAG('T','A','J',' ')}},     /* Tajik -> Tajiki */
-  {"tgj",       {HB_TAG('N','I','S',' ')}},     /* Tagin -> Nisi */
-  {"tgx",       {HB_TAG('A','T','H',' ')}},     /* Tagish -> Athapaskan */
-  {"th",        {HB_TAG('T','H','A',' ')}},     /* Thai */
-  {"tht",       {HB_TAG('A','T','H',' ')}},     /* Tahltan -> Athapaskan */
-  {"thv",       {HB_TAG('T','M','H',' ')}},     /* Tahaggart Tamahaq -> Tamashek */
-  {"thz",       {HB_TAG('T','M','H',' ')}},     /* Tayart Tamajeq -> Tamashek */
-  {"ti",        {HB_TAG('T','G','Y',' ')}},     /* Tigrinya */
-  {"tig",       {HB_TAG('T','G','R',' ')}},     /* Tigre */
-  {"tiv",       {HB_TAG('T','I','V',' ')}},     /* Tiv */
-  {"tk",        {HB_TAG('T','K','M',' ')}},     /* Turkmen */
-  {"tkg",       {HB_TAG('M','L','G',' ')}},     /* Tesaka Malagasy -> Malagasy */
-  {"tl",        {HB_TAG('T','G','L',' ')}},     /* Tagalog */
-  {"tmh",       {HB_TAG('T','M','H',' ')}},     /* Tamashek [macrolanguage] */
-  {"tmw",       {HB_TAG('M','L','Y',' ')}},     /* Temuan -> Malay */
-  {"tn",        {HB_TAG('T','N','A',' ')}},     /* Tswana */
-  {"tnf",       {HB_TAG('D','R','I',' ')}},     /* Tangshewi (retired code) -> Dari */
-  {"to",        {HB_TAG('T','G','N',' ')}},     /* Tonga (Tonga Islands) -> Tongan */
-  {"tod",       {HB_TAG('T','O','D','0')}},     /* Toma */
-  {"toi",       {HB_TAG('T','N','G',' ')}},     /* Tonga (Zambia) */
-  {"tol",       {HB_TAG('A','T','H',' ')}},     /* Tolowa -> Athapaskan */
-  {"tpi",       {HB_TAG('T','P','I',' ')}},     /* Tok Pisin */
-  {"tr",        {HB_TAG('T','R','K',' ')}},     /* Turkish */
-  {"tru",       {HB_TAG('T','U','A',' '),       /* Turoyo -> Turoyo Aramaic */
-                 HB_TAG('S','Y','R',' ')}},     /* Turoyo -> Syriac */
-  {"ts",        {HB_TAG('T','S','G',' ')}},     /* Tsonga */
-  {"tsj",       {HB_TAG('T','S','J',' ')}},     /* Tshangla */
-  {"tt",        {HB_TAG('T','A','T',' ')}},     /* Tatar */
-  {"ttm",       {HB_TAG('A','T','H',' ')}},     /* Northern Tutchone -> Athapaskan */
-  {"ttq",       {HB_TAG('T','M','H',' ')}},     /* Tawallammat Tamajaq -> Tamashek */
-  {"tum",       {HB_TAG('T','U','M',' ')}},     /* Tumbuka -> Tulu */
-  {"tuu",       {HB_TAG('A','T','H',' ')}},     /* Tututni -> Athapaskan */
-  {"tuy",       {HB_TAG('K','A','L',' ')}},     /* Tugen -> Kalenjin */
-  {"tvl",       {HB_TAG('T','V','L',' ')}},     /* Tuvalu */
-  {"tw",        {HB_TAG('T','W','I',' '),       /* Twi */
-                 HB_TAG('A','K','A',' ')}},     /* Twi -> Akan */
-  {"txc",       {HB_TAG('A','T','H',' ')}},     /* Tsetsaut -> Athapaskan */
-  {"txy",       {HB_TAG('M','L','G',' ')}},     /* Tanosy Malagasy -> Malagasy */
-  {"ty",        {HB_TAG('T','H','T',' ')}},     /* Tahitian */
-  {"tyv",       {HB_TAG('T','U','V',' ')}},     /* Tuvinian -> Tuvin */
-  {"tyz",       {HB_TAG('T','Y','Z',' ')}},     /* Tày */
-  {"tzm",       {HB_TAG('T','Z','M',' ')}},     /* Central Atlas Tamazight -> Tamazight */
-  {"tzo",       {HB_TAG('T','Z','O',' ')}},     /* Tzotzil */
-  {"ubl",       {HB_TAG('B','I','K',' ')}},     /* Buhi'non Bikol -> Bikol */
-  {"udm",       {HB_TAG('U','D','M',' ')}},     /* Udmurt */
-  {"ug",        {HB_TAG('U','Y','G',' ')}},     /* Uyghur */
-  {"uk",        {HB_TAG('U','K','R',' ')}},     /* Ukrainian */
-  {"umb",       {HB_TAG('U','M','B',' ')}},     /* Umbundu */
-  {"unr",       {HB_TAG('M','U','N',' ')}},     /* Mundari */
-  {"ur",        {HB_TAG('U','R','D',' ')}},     /* Urdu */
-  {"urk",       {HB_TAG('M','L','Y',' ')}},     /* Urak Lawoi' -> Malay */
-  {"uz",        {HB_TAG('U','Z','B',' ')}},     /* Uzbek [macrolanguage] */
-  {"uzn",       {HB_TAG('U','Z','B',' ')}},     /* Northern Uzbek -> Uzbek */
-  {"uzs",       {HB_TAG('U','Z','B',' ')}},     /* Southern Uzbek -> Uzbek */
-  {"ve",        {HB_TAG('V','E','N',' ')}},     /* Venda */
-  {"vec",       {HB_TAG('V','E','C',' ')}},     /* Venetian */
-  {"vi",        {HB_TAG('V','I','T',' ')}},     /* Vietnamese */
-  {"vkk",       {HB_TAG('M','L','Y',' ')}},     /* Kaur -> Malay */
-  {"vkt",       {HB_TAG('M','L','Y',' ')}},     /* Tenggarong Kutai Malay -> Malay */
-  {"vls",       {HB_TAG('F','L','E',' ')}},     /* Vlaams -> Dutch (Flemish) */
-  {"vmw",       {HB_TAG('M','A','K',' ')}},     /* Makhuwa */
-  {"vo",        {HB_TAG('V','O','L',' ')}},     /* Volapük */
-  {"vro",       {HB_TAG('V','R','O',' ')}},     /* Võro */
-  {"wa",        {HB_TAG('W','L','N',' ')}},     /* Walloon */
-  {"war",       {HB_TAG('W','A','R',' ')}},     /* Waray (Philippines) -> Waray-Waray */
-  {"wbm",       {HB_TAG('W','A',' ',' ')}},     /* Wa */
-  {"wbr",       {HB_TAG('W','A','G',' ')}},     /* Wagdi */
-  {"wlc",       {HB_TAG('C','M','R',' ')}},     /* Mwali Comorian -> Comorian */
-  {"wle",       {HB_TAG('S','I','G',' ')}},     /* Wolane -> Silte Gurage */
-  {"wlk",       {HB_TAG('A','T','H',' ')}},     /* Wailaki -> Athapaskan */
-  {"wni",       {HB_TAG('C','M','R',' ')}},     /* Ndzwani Comorian -> Comorian */
-  {"wo",        {HB_TAG('W','L','F',' ')}},     /* Wolof */
-  {"wry",       {HB_TAG('M','A','W',' ')}},     /* Merwari -> Marwari */
-  {"wsg",       {HB_TAG('G','O','N',' ')}},     /* Adilabad Gondi -> Gondi */
-  {"wtm",       {HB_TAG('W','T','M',' ')}},     /* Mewati */
-  {"wuu",       {HB_TAG('Z','H','S',' ')}},     /* Wu Chinese -> Chinese Simplified */
-  {"xal",       {HB_TAG('K','L','M',' '),       /* Kalmyk */
-                 HB_TAG('T','O','D',' ')}},     /* Kalmyk -> Todo */
-  {"xan",       {HB_TAG('S','E','K',' ')}},     /* Xamtanga -> Sekota */
-  {"xh",        {HB_TAG('X','H','S',' ')}},     /* Xhosa */
-  {"xjb",       {HB_TAG('X','J','B',' ')}},     /* Minjungbal -> Minjangbal */
-  {"xkf",       {HB_TAG('X','K','F',' ')}},     /* Khengkha */
-  {"xmm",       {HB_TAG('M','L','Y',' ')}},     /* Manado Malay -> Malay */
-  {"xmv",       {HB_TAG('M','L','G',' ')}},     /* Antankarana Malagasy -> Malagasy */
-  {"xmw",       {HB_TAG('M','L','G',' ')}},     /* Tsimihety Malagasy -> Malagasy */
-  {"xnr",       {HB_TAG('D','G','R',' ')}},     /* Kangri -> Dogri */
-  {"xog",       {HB_TAG('X','O','G',' ')}},     /* Soga */
-  {"xpe",       {HB_TAG('X','P','E',' ')}},     /* Liberia Kpelle -> Kpelle (Liberia) */
-  {"xsl",       {HB_TAG('S','S','L',' '),       /* South Slavey */
-                 HB_TAG('S','L','A',' '),       /* South Slavey -> Slavey */
-                 HB_TAG('A','T','H',' ')}},     /* South Slavey -> Athapaskan */
-  {"xst",       {HB_TAG('S','I','G',' ')}},     /* Silt'e (retired code) -> Silte Gurage */
-  {"xwo",       {HB_TAG('T','O','D',' ')}},     /* Written Oirat -> Todo */
-  {"yao",       {HB_TAG('Y','A','O',' ')}},     /* Yao */
-  {"yap",       {HB_TAG('Y','A','P',' ')}},     /* Yapese */
-  {"ybd",       {HB_TAG('A','R','K',' ')}},     /* Yangbye (retired code) -> Rakhine */
-  {"ydd",       {HB_TAG('J','I','I',' ')}},     /* Eastern Yiddish -> Yiddish */
-  {"yi",        {HB_TAG('J','I','I',' ')}},     /* Yiddish [macrolanguage] */
-  {"yih",       {HB_TAG('J','I','I',' ')}},     /* Western Yiddish -> Yiddish */
-  {"yo",        {HB_TAG('Y','B','A',' ')}},     /* Yoruba */
-  {"yos",       {HB_TAG('Q','I','N',' ')}},     /* Yos (retired code) -> Chin */
-  {"yrk",       {HB_TAG('T','N','E',' '),       /* Nenets -> Tundra Nenets */
-                 HB_TAG('F','N','E',' ')}},     /* Nenets -> Forest Nenets */
-  {"yue",       {HB_TAG('Z','H','H',' ')}},     /* Yue Chinese -> Chinese, Hong Kong SAR */
-  {"za",        {HB_TAG('Z','H','A',' ')}},     /* Zhuang [macrolanguage] */
-  {"zch",       {HB_TAG('Z','H','A',' ')}},     /* Central Hongshuihe Zhuang -> Zhuang */
-  {"zdj",       {HB_TAG('C','M','R',' ')}},     /* Ngazidja Comorian -> Comorian */
-  {"zea",       {HB_TAG('Z','E','A',' ')}},     /* Zeeuws -> Zealandic */
-  {"zeh",       {HB_TAG('Z','H','A',' ')}},     /* Eastern Hongshuihe Zhuang -> Zhuang */
-  {"zgb",       {HB_TAG('Z','H','A',' ')}},     /* Guibei Zhuang -> Zhuang */
-  {"zgh",       {HB_TAG('Z','G','H',' ')}},     /* Standard Moroccan Tamazight */
-  {"zgm",       {HB_TAG('Z','H','A',' ')}},     /* Minz Zhuang -> Zhuang */
-  {"zgn",       {HB_TAG('Z','H','A',' ')}},     /* Guibian Zhuang -> Zhuang */
-  {"zh",        {HB_TAG('Z','H','S',' ')}},     /* Chinese [macrolanguage] -> Chinese Simplified */
-  {"zhd",       {HB_TAG('Z','H','A',' ')}},     /* Dai Zhuang -> Zhuang */
-  {"zhn",       {HB_TAG('Z','H','A',' ')}},     /* Nong Zhuang -> Zhuang */
-  {"zlj",       {HB_TAG('Z','H','A',' ')}},     /* Liujiang Zhuang -> Zhuang */
-  {"zlm",       {HB_TAG('M','L','Y',' ')}},     /* Malay */
-  {"zln",       {HB_TAG('Z','H','A',' ')}},     /* Lianshan Zhuang -> Zhuang */
-  {"zlq",       {HB_TAG('Z','H','A',' ')}},     /* Liuqian Zhuang -> Zhuang */
-  {"zmi",       {HB_TAG('M','L','Y',' ')}},     /* Negeri Sembilan Malay -> Malay */
-  {"zne",       {HB_TAG('Z','N','D',' ')}},     /* Zande */
-  {"zom",       {HB_TAG('Q','I','N',' ')}},     /* Zou -> Chin */
-  {"zqe",       {HB_TAG('Z','H','A',' ')}},     /* Qiubei Zhuang -> Zhuang */
-  {"zsm",       {HB_TAG('M','L','Y',' ')}},     /* Standard Malay -> Malay */
-  {"zu",        {HB_TAG('Z','U','L',' ')}},     /* Zulu */
-  {"zum",       {HB_TAG('L','R','C',' ')}},     /* Kumzari -> Luri */
-  {"zyb",       {HB_TAG('Z','H','A',' ')}},     /* Yongbei Zhuang -> Zhuang */
-  {"zyg",       {HB_TAG('Z','H','A',' ')}},     /* Yang Zhuang -> Zhuang */
-  {"zyj",       {HB_TAG('Z','H','A',' ')}},     /* Youjiang Zhuang -> Zhuang */
-  {"zyn",       {HB_TAG('Z','H','A',' ')}},     /* Yongnan Zhuang -> Zhuang */
-  {"zza",       {HB_TAG('Z','Z','A',' ')}},     /* Zazaki [macrolanguage] */
-  {"zzj",       {HB_TAG('Z','H','A',' ')}},     /* Zuojiang Zhuang -> Zhuang */
+  {"aa",        HB_TAG('A','F','R',' ')},       /* Afar */
+  {"aae",       HB_TAG('S','Q','I',' ')},       /* Arbëreshë Albanian -> Albanian */
+  {"aao",       HB_TAG('A','R','A',' ')},       /* Algerian Saharan Arabic -> Arabic */
+  {"aat",       HB_TAG('S','Q','I',' ')},       /* Arvanitika Albanian -> Albanian */
+  {"ab",        HB_TAG('A','B','K',' ')},       /* Abkhazian */
+  {"abh",       HB_TAG('A','R','A',' ')},       /* Tajiki Arabic -> Arabic */
+  {"abq",       HB_TAG('A','B','A',' ')},       /* Abaza */
+  {"abv",       HB_TAG('A','R','A',' ')},       /* Baharna Arabic -> Arabic */
+  {"acf",       HB_TAG('F','A','N',' ')},       /* Saint Lucian Creole French -> French Antillean */
+/*{"ach",       HB_TAG('A','C','H',' ')},*/     /* Acoli -> Acholi */
+  {"acm",       HB_TAG('A','R','A',' ')},       /* Mesopotamian Arabic -> Arabic */
+  {"acq",       HB_TAG('A','R','A',' ')},       /* Ta'izzi-Adeni Arabic -> Arabic */
+/*{"acr",       HB_TAG('A','C','R',' ')},*/     /* Achi */
+  {"acw",       HB_TAG('A','R','A',' ')},       /* Hijazi Arabic -> Arabic */
+  {"acx",       HB_TAG('A','R','A',' ')},       /* Omani Arabic -> Arabic */
+  {"acy",       HB_TAG('A','R','A',' ')},       /* Cypriot Arabic -> Arabic */
+  {"ada",       HB_TAG('D','N','G',' ')},       /* Adangme -> Dangme */
+  {"adf",       HB_TAG('A','R','A',' ')},       /* Dhofari Arabic -> Arabic */
+  {"adp",       HB_TAG('D','Z','N',' ')},       /* Adap (retired code) -> Dzongkha */
+/*{"ady",       HB_TAG('A','D','Y',' ')},*/     /* Adyghe */
+  {"aeb",       HB_TAG('A','R','A',' ')},       /* Tunisian Arabic -> Arabic */
+  {"aec",       HB_TAG('A','R','A',' ')},       /* Saidi Arabic -> Arabic */
+  {"af",        HB_TAG('A','F','K',' ')},       /* Afrikaans */
+  {"afb",       HB_TAG('A','R','A',' ')},       /* Gulf Arabic -> Arabic */
+  {"ahg",       HB_TAG('A','G','W',' ')},       /* Qimant -> Agaw */
+  {"aht",       HB_TAG('A','T','H',' ')},       /* Ahtena -> Athapaskan */
+  {"aii",       HB_TAG('S','W','A',' ')},       /* Assyrian Neo-Aramaic -> Swadaya Aramaic */
+  {"aii",       HB_TAG('S','Y','R',' ')},       /* Assyrian Neo-Aramaic -> Syriac */
+/*{"aio",       HB_TAG('A','I','O',' ')},*/     /* Aiton */
+  {"aiw",       HB_TAG('A','R','I',' ')},       /* Aari */
+  {"ajp",       HB_TAG('A','R','A',' ')},       /* South Levantine Arabic -> Arabic */
+  {"ak",        HB_TAG('A','K','A',' ')},       /* Akan [macrolanguage] */
+  {"ak",        HB_TAG('T','W','I',' ')},       /* Akan [macrolanguage] -> Twi */
+  {"aln",       HB_TAG('S','Q','I',' ')},       /* Gheg Albanian -> Albanian */
+  {"als",       HB_TAG('S','Q','I',' ')},       /* Tosk Albanian -> Albanian */
+/*{"alt",       HB_TAG('A','L','T',' ')},*/     /* Southern Altai -> Altai */
+  {"am",        HB_TAG('A','M','H',' ')},       /* Amharic */
+  {"amf",       HB_TAG('H','B','N',' ')},       /* Hamer-Banna -> Hammer-Banna */
+  {"amw",       HB_TAG('S','Y','R',' ')},       /* Western Neo-Aramaic -> Syriac */
+  {"an",        HB_TAG('A','R','G',' ')},       /* Aragonese */
+/*{"ang",       HB_TAG('A','N','G',' ')},*/     /* Old English (ca. 450-1100) -> Anglo-Saxon */
+  {"apc",       HB_TAG('A','R','A',' ')},       /* North Levantine Arabic -> Arabic */
+  {"apd",       HB_TAG('A','R','A',' ')},       /* Sudanese Arabic -> Arabic */
+  {"apj",       HB_TAG('A','T','H',' ')},       /* Jicarilla Apache -> Athapaskan */
+  {"apk",       HB_TAG('A','T','H',' ')},       /* Kiowa Apache -> Athapaskan */
+  {"apl",       HB_TAG('A','T','H',' ')},       /* Lipan Apache -> Athapaskan */
+  {"apm",       HB_TAG('A','T','H',' ')},       /* Mescalero-Chiricahua Apache -> Athapaskan */
+  {"apw",       HB_TAG('A','T','H',' ')},       /* Western Apache -> Athapaskan */
+  {"ar",        HB_TAG('A','R','A',' ')},       /* Arabic [macrolanguage] */
+  {"arb",       HB_TAG('A','R','A',' ')},       /* Standard Arabic -> Arabic */
+  {"arn",       HB_TAG('M','A','P',' ')},       /* Mapudungun */
+  {"arq",       HB_TAG('A','R','A',' ')},       /* Algerian Arabic -> Arabic */
+  {"ars",       HB_TAG('A','R','A',' ')},       /* Najdi Arabic -> Arabic */
+  {"ary",       HB_TAG('M','O','R',' ')},       /* Moroccan Arabic -> Moroccan */
+  {"arz",       HB_TAG('A','R','A',' ')},       /* Egyptian Arabic -> Arabic */
+  {"as",        HB_TAG('A','S','M',' ')},       /* Assamese */
+/*{"ast",       HB_TAG('A','S','T',' ')},*/     /* Asturian */
+/*{"ath",       HB_TAG('A','T','H',' ')},*/     /* Athapascan [family] -> Athapaskan */
+  {"atj",       HB_TAG('R','C','R',' ')},       /* Atikamekw -> R-Cree */
+  {"atv",       HB_TAG('A','L','T',' ')},       /* Northern Altai -> Altai */
+  {"auz",       HB_TAG('A','R','A',' ')},       /* Uzbeki Arabic -> Arabic */
+  {"av",        HB_TAG('A','V','R',' ')},       /* Avaric -> Avar */
+  {"avl",       HB_TAG('A','R','A',' ')},       /* Eastern Egyptian Bedawi Arabic -> Arabic */
+/*{"awa",       HB_TAG('A','W','A',' ')},*/     /* Awadhi */
+  {"ay",        HB_TAG('A','Y','M',' ')},       /* Aymara [macrolanguage] */
+  {"ayc",       HB_TAG('A','Y','M',' ')},       /* Southern Aymara -> Aymara */
+  {"ayh",       HB_TAG('A','R','A',' ')},       /* Hadrami Arabic -> Arabic */
+  {"ayl",       HB_TAG('A','R','A',' ')},       /* Libyan Arabic -> Arabic */
+  {"ayn",       HB_TAG('A','R','A',' ')},       /* Sanaani Arabic -> Arabic */
+  {"ayp",       HB_TAG('A','R','A',' ')},       /* North Mesopotamian Arabic -> Arabic */
+  {"ayr",       HB_TAG('A','Y','M',' ')},       /* Central Aymara -> Aymara */
+  {"az",        HB_TAG('A','Z','E',' ')},       /* Azerbaijani [macrolanguage] */
+/*{"azb",       HB_TAG('A','Z','B',' ')},*/     /* South Azerbaijani -> Torki */
+  {"azj",       HB_TAG('A','Z','E',' ')},       /* North Azerbaijani -> Azerbaijani */
+  {"ba",        HB_TAG('B','S','H',' ')},       /* Bashkir */
+  {"bad",       HB_TAG('B','A','D','0')},       /* Banda [family] */
+  {"bai",       HB_TAG('B','M','L',' ')},       /* Bamileke [family] */
+  {"bal",       HB_TAG('B','L','I',' ')},       /* Baluchi [macrolanguage] */
+/*{"ban",       HB_TAG('B','A','N',' ')},*/     /* Balinese */
+/*{"bar",       HB_TAG('B','A','R',' ')},*/     /* Bavarian */
+/*{"bbc",       HB_TAG('B','B','C',' ')},*/     /* Batak Toba */
+  {"bbz",       HB_TAG('A','R','A',' ')},       /* Babalia Creole Arabic (retired code) -> Arabic */
+  {"bcc",       HB_TAG('B','L','I',' ')},       /* Southern Balochi -> Baluchi */
+  {"bci",       HB_TAG('B','A','U',' ')},       /* Baoulé -> Baulé */
+  {"bcl",       HB_TAG('B','I','K',' ')},       /* Central Bikol -> Bikol */
+  {"bcq",       HB_TAG('B','C','H',' ')},       /* Bench */
+  {"bcr",       HB_TAG('A','T','H',' ')},       /* Babine -> Athapaskan */
+/*{"bdy",       HB_TAG('B','D','Y',' ')},*/     /* Bandjalang */
+  {"be",        HB_TAG('B','E','L',' ')},       /* Belarusian -> Belarussian */
+  {"bea",       HB_TAG('A','T','H',' ')},       /* Beaver -> Athapaskan */
+  {"beb",       HB_TAG('B','T','I',' ')},       /* Bebele -> Beti */
+/*{"bem",       HB_TAG('B','E','M',' ')},*/     /* Bemba (Zambia) */
+  {"ber",       HB_TAG('B','B','R',' ')},       /* Berber [family] */
+  {"bfq",       HB_TAG('B','A','D',' ')},       /* Badaga */
+  {"bft",       HB_TAG('B','L','T',' ')},       /* Balti */
+  {"bfu",       HB_TAG('L','A','H',' ')},       /* Gahri -> Lahuli */
+  {"bfy",       HB_TAG('B','A','G',' ')},       /* Bagheli -> Baghelkhandi */
+  {"bg",        HB_TAG('B','G','R',' ')},       /* Bulgarian */
+/*{"bgc",       HB_TAG('B','G','C',' ')},*/     /* Haryanvi */
+  {"bgn",       HB_TAG('B','L','I',' ')},       /* Western Balochi -> Baluchi */
+  {"bgp",       HB_TAG('B','L','I',' ')},       /* Eastern Balochi -> Baluchi */
+/*{"bgq",       HB_TAG('B','G','Q',' ')},*/     /* Bagri */
+  {"bgr",       HB_TAG('Q','I','N',' ')},       /* Bawm Chin -> Chin */
+  {"bhb",       HB_TAG('B','H','I',' ')},       /* Bhili */
+/*{"bhi",       HB_TAG('B','H','I',' ')},*/     /* Bhilali -> Bhili */
+  {"bhk",       HB_TAG('B','I','K',' ')},       /* Albay Bicolano (retired code) -> Bikol */
+/*{"bho",       HB_TAG('B','H','O',' ')},*/     /* Bhojpuri */
+  {"bhr",       HB_TAG('M','L','G',' ')},       /* Bara Malagasy -> Malagasy */
+  {"bi",        HB_TAG('B','I','S',' ')},       /* Bislama */
+/*{"bik",       HB_TAG('B','I','K',' ')},*/     /* Bikol [macrolanguage] */
+  {"bin",       HB_TAG('E','D','O',' ')},       /* Edo */
+/*{"bjj",       HB_TAG('B','J','J',' ')},*/     /* Kanauji */
+  {"bjn",       HB_TAG('M','L','Y',' ')},       /* Banjar -> Malay */
+  {"bjq",       HB_TAG('M','L','G',' ')},       /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */
+  {"bjt",       HB_TAG('B','L','N',' ')},       /* Balanta-Ganja -> Balante */
+  {"bla",       HB_TAG('B','K','F',' ')},       /* Siksika -> Blackfoot */
+  {"ble",       HB_TAG('B','L','N',' ')},       /* Balanta-Kentohe -> Balante */
+/*{"blk",       HB_TAG('B','L','K',' ')},*/     /* Pa’o Karen */
+  {"bln",       HB_TAG('B','I','K',' ')},       /* Southern Catanduanes Bikol -> Bikol */
+  {"bm",        HB_TAG('B','M','B',' ')},       /* Bambara (Bamanankan) */
+  {"bmm",       HB_TAG('M','L','G',' ')},       /* Northern Betsimisaraka Malagasy -> Malagasy */
+  {"bn",        HB_TAG('B','E','N',' ')},       /* Bengali */
+  {"bo",        HB_TAG('T','I','B',' ')},       /* Tibetan */
+/*{"bpy",       HB_TAG('B','P','Y',' ')},*/     /* Bishnupriya -> Bishnupriya Manipuri */
+  {"bqi",       HB_TAG('L','R','C',' ')},       /* Bakhtiari -> Luri */
+  {"br",        HB_TAG('B','R','E',' ')},       /* Breton */
+  {"bra",       HB_TAG('B','R','I',' ')},       /* Braj -> Braj Bhasha */
+/*{"brh",       HB_TAG('B','R','H',' ')},*/     /* Brahui */
+/*{"brx",       HB_TAG('B','R','X',' ')},*/     /* Bodo (India) */
+  {"bs",        HB_TAG('B','O','S',' ')},       /* Bosnian */
+/*{"bsk",       HB_TAG('B','S','K',' ')},*/     /* Burushaski */
+  {"btb",       HB_TAG('B','T','I',' ')},       /* Beti (Cameroon) (retired code) */
+  {"btj",       HB_TAG('M','L','Y',' ')},       /* Bacanese Malay -> Malay */
+  {"bto",       HB_TAG('B','I','K',' ')},       /* Rinconada Bikol -> Bikol */
+/*{"bts",       HB_TAG('B','T','S',' ')},*/     /* Batak Simalungun */
+/*{"bug",       HB_TAG('B','U','G',' ')},*/     /* Buginese -> Bugis */
+  {"bum",       HB_TAG('B','T','I',' ')},       /* Bulu (Cameroon) -> Beti */
+  {"bve",       HB_TAG('M','L','Y',' ')},       /* Berau Malay -> Malay */
+  {"bvu",       HB_TAG('M','L','Y',' ')},       /* Bukit Malay -> Malay */
+  {"bxk",       HB_TAG('L','U','H',' ')},       /* Bukusu -> Luyia */
+  {"bxp",       HB_TAG('B','T','I',' ')},       /* Bebil -> Beti */
+  {"bxr",       HB_TAG('R','B','U',' ')},       /* Russia Buriat -> Russian Buriat */
+  {"byn",       HB_TAG('B','I','L',' ')},       /* Bilin -> Bilen */
+/*{"byv",       HB_TAG('B','Y','V',' ')},*/     /* Medumba */
+  {"bzc",       HB_TAG('M','L','G',' ')},       /* Southern Betsimisaraka Malagasy -> Malagasy */
+  {"ca",        HB_TAG('C','A','T',' ')},       /* Catalan */
+  {"caf",       HB_TAG('C','R','R',' ')},       /* Southern Carrier -> Carrier */
+  {"caf",       HB_TAG('A','T','H',' ')},       /* Southern Carrier -> Athapaskan */
+/*{"cak",       HB_TAG('C','A','K',' ')},*/     /* Kaqchikel */
+/*{"cbk",       HB_TAG('C','B','K',' ')},*/     /* Chavacano -> Zamboanga Chavacano */
+  {"cbl",       HB_TAG('Q','I','N',' ')},       /* Bualkhaw Chin -> Chin */
+  {"cco",       HB_TAG('C','C','H','N')},       /* Comaltepec Chinantec -> Chinantec */
+  {"ccq",       HB_TAG('A','R','K',' ')},       /* Chaungtha (retired code) -> Rakhine */
+  {"cdo",       HB_TAG('Z','H','S',' ')},       /* Min Dong Chinese -> Chinese Simplified */
+  {"ce",        HB_TAG('C','H','E',' ')},       /* Chechen */
+/*{"ceb",       HB_TAG('C','E','B',' ')},*/     /* Cebuano */
+  {"cfm",       HB_TAG('H','A','L',' ')},       /* Halam (Falam Chin) */
+/*{"cgg",       HB_TAG('C','G','G',' ')},*/     /* Chiga */
+  {"ch",        HB_TAG('C','H','A',' ')},       /* Chamorro */
+  {"chj",       HB_TAG('C','C','H','N')},       /* Ojitlán Chinantec -> Chinantec */
+  {"chk",       HB_TAG('C','H','K','0')},       /* Chuukese */
+/*{"cho",       HB_TAG('C','H','O',' ')},*/     /* Choctaw */
+  {"chp",       HB_TAG('C','H','P',' ')},       /* Chipewyan */
+  {"chp",       HB_TAG('S','A','Y',' ')},       /* Chipewyan -> Sayisi */
+  {"chp",       HB_TAG('A','T','H',' ')},       /* Chipewyan -> Athapaskan */
+  {"chq",       HB_TAG('C','C','H','N')},       /* Quiotepec Chinantec -> Chinantec */
+/*{"chr",       HB_TAG('C','H','R',' ')},*/     /* Cherokee */
+/*{"chy",       HB_TAG('C','H','Y',' ')},*/     /* Cheyenne */
+  {"chz",       HB_TAG('C','C','H','N')},       /* Ozumacín Chinantec -> Chinantec */
+  {"ciw",       HB_TAG('O','J','B',' ')},       /* Chippewa -> Ojibway */
+/*{"cja",       HB_TAG('C','J','A',' ')},*/     /* Western Cham */
+/*{"cjm",       HB_TAG('C','J','M',' ')},*/     /* Eastern Cham */
+  {"cjy",       HB_TAG('Z','H','S',' ')},       /* Jinyu Chinese -> Chinese Simplified */
+  {"cka",       HB_TAG('Q','I','N',' ')},       /* Khumi Awa Chin (retired code) -> Chin */
+  {"ckb",       HB_TAG('K','U','R',' ')},       /* Central Kurdish -> Kurdish */
+  {"ckt",       HB_TAG('C','H','K',' ')},       /* Chukot -> Chukchi */
+  {"clc",       HB_TAG('A','T','H',' ')},       /* Chilcotin -> Athapaskan */
+  {"cld",       HB_TAG('S','Y','R',' ')},       /* Chaldean Neo-Aramaic -> Syriac */
+  {"cle",       HB_TAG('C','C','H','N')},       /* Lealao Chinantec -> Chinantec */
+  {"cmn",       HB_TAG('Z','H','S',' ')},       /* Mandarin Chinese -> Chinese Simplified */
+  {"cmr",       HB_TAG('Q','I','N',' ')},       /* Mro-Khimi Chin -> Chin */
+  {"cnb",       HB_TAG('Q','I','N',' ')},       /* Chinbon Chin -> Chin */
+  {"cnh",       HB_TAG('Q','I','N',' ')},       /* Hakha Chin -> Chin */
+  {"cnk",       HB_TAG('Q','I','N',' ')},       /* Khumi Chin -> Chin */
+  {"cnl",       HB_TAG('C','C','H','N')},       /* Lalana Chinantec -> Chinantec */
+  {"cnp",       HB_TAG('Z','H','S',' ')},       /* Northern Ping Chinese -> Chinese Simplified */
+  {"cnt",       HB_TAG('C','C','H','N')},       /* Tepetotutla Chinantec -> Chinantec */
+  {"cnw",       HB_TAG('Q','I','N',' ')},       /* Ngawn Chin -> Chin */
+  {"co",        HB_TAG('C','O','S',' ')},       /* Corsican */
+  {"coa",       HB_TAG('M','L','Y',' ')},       /* Cocos Islands Malay -> Malay */
+/*{"cop",       HB_TAG('C','O','P',' ')},*/     /* Coptic */
+  {"coq",       HB_TAG('A','T','H',' ')},       /* Coquille -> Athapaskan */
+  {"cpa",       HB_TAG('C','C','H','N')},       /* Palantla Chinantec -> Chinantec */
+  {"cpe",       HB_TAG('C','P','P',' ')},       /* English-based creoles and pidgins [family] -> Creoles */
+  {"cpf",       HB_TAG('C','P','P',' ')},       /* French-based creoles and pidgins [family] -> Creoles */
+/*{"cpp",       HB_TAG('C','P','P',' ')},*/     /* Portuguese-based creoles and pidgins [family] -> Creoles */
+  {"cpx",       HB_TAG('Z','H','S',' ')},       /* Pu-Xian Chinese -> Chinese Simplified */
+  {"cqd",       HB_TAG('H','M','N',' ')},       /* Chuanqiandian Cluster Miao -> Hmong */
+  {"cqu",       HB_TAG('Q','U','H',' ')},       /* Chilean Quechua (retired code) -> Quechua (Bolivia) */
+  {"cr",        HB_TAG('C','R','E',' ')},       /* Cree [macrolanguage] */
+  {"cr",        HB_TAG('Y','C','R',' ')},       /* Cree [macrolanguage] -> Y-Cree */
+  {"crh",       HB_TAG('C','R','T',' ')},       /* Crimean Tatar */
+  {"crj",       HB_TAG('E','C','R',' ')},       /* Southern East Cree -> Eastern Cree */
+  {"crk",       HB_TAG('W','C','R',' ')},       /* Plains Cree -> West-Cree */
+  {"crl",       HB_TAG('E','C','R',' ')},       /* Northern East Cree -> Eastern Cree */
+  {"crm",       HB_TAG('M','C','R',' ')},       /* Moose Cree */
+  {"crm",       HB_TAG('L','C','R',' ')},       /* Moose Cree -> L-Cree */
+  {"crp",       HB_TAG('C','P','P',' ')},       /* Creoles and pidgins [family] -> Creoles */
+  {"crx",       HB_TAG('C','R','R',' ')},       /* Carrier */
+  {"crx",       HB_TAG('A','T','H',' ')},       /* Carrier -> Athapaskan */
+  {"cs",        HB_TAG('C','S','Y',' ')},       /* Czech */
+  {"csa",       HB_TAG('C','C','H','N')},       /* Chiltepec Chinantec -> Chinantec */
+/*{"csb",       HB_TAG('C','S','B',' ')},*/     /* Kashubian */
+  {"csh",       HB_TAG('Q','I','N',' ')},       /* Asho Chin -> Chin */
+  {"cso",       HB_TAG('C','C','H','N')},       /* Sochiapam Chinantec -> Chinantec */
+  {"csp",       HB_TAG('Z','H','S',' ')},       /* Southern Ping Chinese -> Chinese Simplified */
+  {"csw",       HB_TAG('N','C','R',' ')},       /* Swampy Cree -> N-Cree */
+  {"csw",       HB_TAG('N','H','C',' ')},       /* Swampy Cree -> Norway House Cree */
+  {"csy",       HB_TAG('Q','I','N',' ')},       /* Siyin Chin -> Chin */
+  {"ctc",       HB_TAG('A','T','H',' ')},       /* Chetco -> Athapaskan */
+  {"ctd",       HB_TAG('Q','I','N',' ')},       /* Tedim Chin -> Chin */
+  {"cte",       HB_TAG('C','C','H','N')},       /* Tepinapa Chinantec -> Chinantec */
+/*{"ctg",       HB_TAG('C','T','G',' ')},*/     /* Chittagonian */
+  {"ctl",       HB_TAG('C','C','H','N')},       /* Tlacoatzintepec Chinantec -> Chinantec */
+  {"cts",       HB_TAG('B','I','K',' ')},       /* Northern Catanduanes Bikol -> Bikol */
+  {"cu",        HB_TAG('C','S','L',' ')},       /* Church Slavonic */
+  {"cuc",       HB_TAG('C','C','H','N')},       /* Usila Chinantec -> Chinantec */
+/*{"cuk",       HB_TAG('C','U','K',' ')},*/     /* San Blas Kuna */
+  {"cv",        HB_TAG('C','H','U',' ')},       /* Chuvash */
+  {"cvn",       HB_TAG('C','C','H','N')},       /* Valle Nacional Chinantec -> Chinantec */
+  {"cwd",       HB_TAG('D','C','R',' ')},       /* Woods Cree */
+  {"cwd",       HB_TAG('T','C','R',' ')},       /* Woods Cree -> TH-Cree */
+  {"cy",        HB_TAG('W','E','L',' ')},       /* Welsh */
+  {"czh",       HB_TAG('Z','H','S',' ')},       /* Huizhou Chinese -> Chinese Simplified */
+  {"czo",       HB_TAG('Z','H','S',' ')},       /* Min Zhong Chinese -> Chinese Simplified */
+  {"czt",       HB_TAG('Q','I','N',' ')},       /* Zotung Chin -> Chin */
+  {"da",        HB_TAG('D','A','N',' ')},       /* Danish */
+  {"dao",       HB_TAG('Q','I','N',' ')},       /* Daai Chin -> Chin */
+  {"dap",       HB_TAG('N','I','S',' ')},       /* Nisi (India) (retired code) */
+/*{"dar",       HB_TAG('D','A','R',' ')},*/     /* Dargwa */
+/*{"dax",       HB_TAG('D','A','X',' ')},*/     /* Dayi */
+  {"de",        HB_TAG('D','E','U',' ')},       /* German */
+  {"den",       HB_TAG('S','L','A',' ')},       /* Slave (Athapascan) [macrolanguage] -> Slavey */
+  {"den",       HB_TAG('A','T','H',' ')},       /* Slave (Athapascan) [macrolanguage] -> Athapaskan */
+/*{"dgo",       HB_TAG('D','G','O',' ')},*/     /* Dogri */
+  {"dgr",       HB_TAG('A','T','H',' ')},       /* Dogrib -> Athapaskan */
+  {"dhd",       HB_TAG('M','A','W',' ')},       /* Dhundari -> Marwari */
+/*{"dhg",       HB_TAG('D','H','G',' ')},*/     /* Dhangu */
+  {"dib",       HB_TAG('D','N','K',' ')},       /* South Central Dinka -> Dinka */
+  {"dik",       HB_TAG('D','N','K',' ')},       /* Southwestern Dinka -> Dinka */
+  {"din",       HB_TAG('D','N','K',' ')},       /* Dinka [macrolanguage] */
+  {"dip",       HB_TAG('D','N','K',' ')},       /* Northeastern Dinka -> Dinka */
+/*{"diq",       HB_TAG('D','I','Q',' ')},*/     /* Dimli */
+  {"diw",       HB_TAG('D','N','K',' ')},       /* Northwestern Dinka -> Dinka */
+  {"dje",       HB_TAG('D','J','R',' ')},       /* Zarma */
+  {"djr",       HB_TAG('D','J','R','0')},       /* Djambarrpuyngu */
+  {"dks",       HB_TAG('D','N','K',' ')},       /* Southeastern Dinka -> Dinka */
+  {"dng",       HB_TAG('D','U','N',' ')},       /* Dungan */
+/*{"dnj",       HB_TAG('D','N','J',' ')},*/     /* Dan */
+  {"doi",       HB_TAG('D','G','R',' ')},       /* Dogri [macrolanguage] */
+  {"drh",       HB_TAG('M','N','G',' ')},       /* Darkhat (retired code) -> Mongolian */
+  {"drw",       HB_TAG('D','R','I',' ')},       /* Darwazi (retired code) -> Dari */
+  {"dsb",       HB_TAG('L','S','B',' ')},       /* Lower Sorbian */
+  {"dty",       HB_TAG('N','E','P',' ')},       /* Dotyali -> Nepali */
+/*{"duj",       HB_TAG('D','U','J',' ')},*/     /* Dhuwal (retired code) */
+  {"dup",       HB_TAG('M','L','Y',' ')},       /* Duano -> Malay */
+  {"dv",        HB_TAG('D','I','V',' ')},       /* Divehi (Dhivehi, Maldivian) */
+  {"dv",        HB_TAG('D','H','V',' ')},       /* Divehi (Dhivehi, Maldivian) (deprecated) */
+  {"dwk",       HB_TAG('K','U','I',' ')},       /* Dawik Kui -> Kui */
+  {"dwu",       HB_TAG('D','U','J',' ')},       /* Dhuwal */
+  {"dwy",       HB_TAG('D','U','J',' ')},       /* Dhuwaya -> Dhuwal */
+  {"dyu",       HB_TAG('J','U','L',' ')},       /* Dyula -> Jula */
+  {"dz",        HB_TAG('D','Z','N',' ')},       /* Dzongkha */
+  {"ee",        HB_TAG('E','W','E',' ')},       /* Ewe */
+/*{"efi",       HB_TAG('E','F','I',' ')},*/     /* Efik */
+  {"ekk",       HB_TAG('E','T','I',' ')},       /* Standard Estonian -> Estonian */
+  {"el",        HB_TAG('E','L','L',' ')},       /* Modern Greek (1453-) -> Greek */
+  {"emk",       HB_TAG('E','M','K',' ')},       /* Eastern Maninkakan */
+  {"emk",       HB_TAG('M','N','K',' ')},       /* Eastern Maninkakan -> Maninka */
+  {"en",        HB_TAG('E','N','G',' ')},       /* English */
+  {"enb",       HB_TAG('K','A','L',' ')},       /* Markweeta -> Kalenjin */
+  {"enf",       HB_TAG('F','N','E',' ')},       /* Forest Enets -> Forest Nenets */
+  {"enh",       HB_TAG('T','N','E',' ')},       /* Tundra Enets -> Tundra Nenets */
+  {"eo",        HB_TAG('N','T','O',' ')},       /* Esperanto */
+  {"es",        HB_TAG('E','S','P',' ')},       /* Spanish */
+  {"esg",       HB_TAG('G','O','N',' ')},       /* Aheri Gondi -> Gondi */
+  {"esi",       HB_TAG('I','P','K',' ')},       /* North Alaskan Inupiatun -> Inupiat */
+  {"esk",       HB_TAG('I','P','K',' ')},       /* Northwest Alaska Inupiatun -> Inupiat */
+/*{"esu",       HB_TAG('E','S','U',' ')},*/     /* Central Yupik */
+  {"et",        HB_TAG('E','T','I',' ')},       /* Estonian [macrolanguage] */
+  {"eto",       HB_TAG('B','T','I',' ')},       /* Eton (Cameroon) -> Beti */
+  {"eu",        HB_TAG('E','U','Q',' ')},       /* Basque */
+  {"eve",       HB_TAG('E','V','N',' ')},       /* Even */
+  {"evn",       HB_TAG('E','V','K',' ')},       /* Evenki */
+  {"ewo",       HB_TAG('B','T','I',' ')},       /* Ewondo -> Beti */
+  {"eyo",       HB_TAG('K','A','L',' ')},       /* Keiyo -> Kalenjin */
+  {"fa",        HB_TAG('F','A','R',' ')},       /* Persian [macrolanguage] */
+  {"fan",       HB_TAG('F','A','N','0')},       /* Fang (Equatorial Guinea) */
+/*{"fat",       HB_TAG('F','A','T',' ')},*/     /* Fanti */
+  {"fbl",       HB_TAG('B','I','K',' ')},       /* West Albay Bikol -> Bikol */
+  {"ff",        HB_TAG('F','U','L',' ')},       /* Fulah [macrolanguage] */
+  {"ffm",       HB_TAG('F','U','L',' ')},       /* Maasina Fulfulde -> Fulah */
+  {"fi",        HB_TAG('F','I','N',' ')},       /* Finnish */
+  {"fil",       HB_TAG('P','I','L',' ')},       /* Filipino */
+  {"fj",        HB_TAG('F','J','I',' ')},       /* Fijian */
+  {"flm",       HB_TAG('H','A','L',' ')},       /* Halam (Falam Chin) (retired code) */
+  {"flm",       HB_TAG('Q','I','N',' ')},       /* Falam Chin (retired code) -> Chin */
+/*{"fmp",       HB_TAG('F','M','P',' ')},*/     /* Fe’fe’ */
+  {"fo",        HB_TAG('F','O','S',' ')},       /* Faroese */
+/*{"fon",       HB_TAG('F','O','N',' ')},*/     /* Fon */
+  {"fr",        HB_TAG('F','R','A',' ')},       /* French */
+/*{"frc",       HB_TAG('F','R','C',' ')},*/     /* Cajun French */
+/*{"frp",       HB_TAG('F','R','P',' ')},*/     /* Arpitan */
+  {"fub",       HB_TAG('F','U','L',' ')},       /* Adamawa Fulfulde -> Fulah */
+  {"fuc",       HB_TAG('F','U','L',' ')},       /* Pulaar -> Fulah */
+  {"fue",       HB_TAG('F','U','L',' ')},       /* Borgu Fulfulde -> Fulah */
+  {"fuf",       HB_TAG('F','T','A',' ')},       /* Pular -> Futa */
+  {"fuh",       HB_TAG('F','U','L',' ')},       /* Western Niger Fulfulde -> Fulah */
+  {"fui",       HB_TAG('F','U','L',' ')},       /* Bagirmi Fulfulde -> Fulah */
+  {"fuq",       HB_TAG('F','U','L',' ')},       /* Central-Eastern Niger Fulfulde -> Fulah */
+  {"fur",       HB_TAG('F','R','L',' ')},       /* Friulian */
+/*{"fuv",       HB_TAG('F','U','V',' ')},*/     /* Nigerian Fulfulde */
+  {"fy",        HB_TAG('F','R','I',' ')},       /* Western Frisian -> Frisian */
+  {"ga",        HB_TAG('I','R','I',' ')},       /* Irish */
+  {"gaa",       HB_TAG('G','A','D',' ')},       /* Ga */
+/*{"gag",       HB_TAG('G','A','G',' ')},*/     /* Gagauz */
+  {"gan",       HB_TAG('Z','H','S',' ')},       /* Gan Chinese -> Chinese Simplified */
+  {"gax",       HB_TAG('O','R','O',' ')},       /* Borana-Arsi-Guji Oromo -> Oromo */
+  {"gaz",       HB_TAG('O','R','O',' ')},       /* West Central Oromo -> Oromo */
+  {"gbm",       HB_TAG('G','A','W',' ')},       /* Garhwali */
+  {"gce",       HB_TAG('A','T','H',' ')},       /* Galice -> Athapaskan */
+  {"gd",        HB_TAG('G','A','E',' ')},       /* Scottish Gaelic (Gaelic) */
+  {"gda",       HB_TAG('R','A','J',' ')},       /* Gade Lohar -> Rajasthani */
+/*{"gez",       HB_TAG('G','E','Z',' ')},*/     /* Geez */
+  {"ggo",       HB_TAG('G','O','N',' ')},       /* Southern Gondi (retired code) -> Gondi */
+/*{"gih",       HB_TAG('G','I','H',' ')},*/     /* Githabul */
+  {"gil",       HB_TAG('G','I','L','0')},       /* Kiribati (Gilbertese) */
+  {"gju",       HB_TAG('R','A','J',' ')},       /* Gujari -> Rajasthani */
+/*{"gkp",       HB_TAG('G','K','P',' ')},*/     /* Guinea Kpelle -> Kpelle (Guinea) */
+  {"gl",        HB_TAG('G','A','L',' ')},       /* Galician */
+  {"gld",       HB_TAG('N','A','N',' ')},       /* Nanai */
+/*{"glk",       HB_TAG('G','L','K',' ')},*/     /* Gilaki */
+  {"gn",        HB_TAG('G','U','A',' ')},       /* Guarani [macrolanguage] */
+/*{"gnn",       HB_TAG('G','N','N',' ')},*/     /* Gumatj */
+  {"gno",       HB_TAG('G','O','N',' ')},       /* Northern Gondi -> Gondi */
+  {"gnw",       HB_TAG('G','U','A',' ')},       /* Western Bolivian Guaraní -> Guarani */
+/*{"gog",       HB_TAG('G','O','G',' ')},*/     /* Gogo */
+  {"gom",       HB_TAG('K','O','K',' ')},       /* Goan Konkani -> Konkani */
+/*{"gon",       HB_TAG('G','O','N',' ')},*/     /* Gondi [macrolanguage] */
+  {"grt",       HB_TAG('G','R','O',' ')},       /* Garo */
+  {"gru",       HB_TAG('S','O','G',' ')},       /* Kistane -> Sodo Gurage */
+  {"gsw",       HB_TAG('A','L','S',' ')},       /* Alsatian */
+  {"gu",        HB_TAG('G','U','J',' ')},       /* Gujarati */
+/*{"guc",       HB_TAG('G','U','C',' ')},*/     /* Wayuu */
+/*{"guf",       HB_TAG('G','U','F',' ')},*/     /* Gupapuyngu */
+  {"gug",       HB_TAG('G','U','A',' ')},       /* Paraguayan Guaraní -> Guarani */
+  {"gui",       HB_TAG('G','U','A',' ')},       /* Eastern Bolivian Guaraní -> Guarani */
+  {"guk",       HB_TAG('G','M','Z',' ')},       /* Gumuz */
+  {"guk",       HB_TAG('G','U','K',' ')},       /* Gumuz (SIL fonts) */
+  {"gun",       HB_TAG('G','U','A',' ')},       /* Mbyá Guaraní -> Guarani */
+/*{"guz",       HB_TAG('G','U','Z',' ')},*/     /* Gusii */
+  {"gv",        HB_TAG('M','N','X',' ')},       /* Manx */
+  {"gwi",       HB_TAG('A','T','H',' ')},       /* Gwichʼin -> Athapaskan */
+  {"ha",        HB_TAG('H','A','U',' ')},       /* Hausa */
+  {"haa",       HB_TAG('A','T','H',' ')},       /* Han -> Athapaskan */
+  {"hae",       HB_TAG('O','R','O',' ')},       /* Eastern Oromo -> Oromo */
+  {"hak",       HB_TAG('Z','H','S',' ')},       /* Hakka Chinese -> Chinese Simplified */
+  {"har",       HB_TAG('H','R','I',' ')},       /* Harari */
+/*{"haw",       HB_TAG('H','A','W',' ')},*/     /* Hawaiian */
+/*{"hay",       HB_TAG('H','A','Y',' ')},*/     /* Haya */
+/*{"haz",       HB_TAG('H','A','Z',' ')},*/     /* Hazaragi */
+  {"he",        HB_TAG('I','W','R',' ')},       /* Hebrew */
+  {"hea",       HB_TAG('H','M','N',' ')},       /* Northern Qiandong Miao -> Hmong */
+  {"hi",        HB_TAG('H','I','N',' ')},       /* Hindi */
+/*{"hil",       HB_TAG('H','I','L',' ')},*/     /* Hiligaynon */
+  {"hji",       HB_TAG('M','L','Y',' ')},       /* Haji -> Malay */
+  {"hlt",       HB_TAG('Q','I','N',' ')},       /* Matu Chin -> Chin */
+  {"hma",       HB_TAG('H','M','N',' ')},       /* Southern Mashan Hmong -> Hmong */
+  {"hmc",       HB_TAG('H','M','N',' ')},       /* Central Huishui Hmong -> Hmong */
+  {"hmd",       HB_TAG('H','M','N',' ')},       /* Large Flowery Miao -> Hmong */
+  {"hme",       HB_TAG('H','M','N',' ')},       /* Eastern Huishui Hmong -> Hmong */
+  {"hmg",       HB_TAG('H','M','N',' ')},       /* Southwestern Guiyang Hmong -> Hmong */
+  {"hmh",       HB_TAG('H','M','N',' ')},       /* Southwestern Huishui Hmong -> Hmong */
+  {"hmi",       HB_TAG('H','M','N',' ')},       /* Northern Huishui Hmong -> Hmong */
+  {"hmj",       HB_TAG('H','M','N',' ')},       /* Ge -> Hmong */
+  {"hml",       HB_TAG('H','M','N',' ')},       /* Luopohe Hmong -> Hmong */
+  {"hmm",       HB_TAG('H','M','N',' ')},       /* Central Mashan Hmong -> Hmong */
+/*{"hmn",       HB_TAG('H','M','N',' ')},*/     /* Hmong [macrolanguage] */
+  {"hmp",       HB_TAG('H','M','N',' ')},       /* Northern Mashan Hmong -> Hmong */
+  {"hmq",       HB_TAG('H','M','N',' ')},       /* Eastern Qiandong Miao -> Hmong */
+  {"hms",       HB_TAG('H','M','N',' ')},       /* Southern Qiandong Miao -> Hmong */
+  {"hmw",       HB_TAG('H','M','N',' ')},       /* Western Mashan Hmong -> Hmong */
+  {"hmy",       HB_TAG('H','M','N',' ')},       /* Southern Guiyang Hmong -> Hmong */
+  {"hmz",       HB_TAG('H','M','N',' ')},       /* Hmong Shua -> Hmong */
+/*{"hnd",       HB_TAG('H','N','D',' ')},*/     /* Southern Hindko -> Hindko */
+  {"hne",       HB_TAG('C','H','H',' ')},       /* Chhattisgarhi -> Chattisgarhi */
+  {"hnj",       HB_TAG('H','M','N',' ')},       /* Hmong Njua -> Hmong */
+  {"hno",       HB_TAG('H','N','D',' ')},       /* Northern Hindko -> Hindko */
+  {"ho",        HB_TAG('H','M','O',' ')},       /* Hiri Motu */
+  {"hoc",       HB_TAG('H','O',' ',' ')},       /* Ho */
+  {"hoi",       HB_TAG('A','T','H',' ')},       /* Holikachuk -> Athapaskan */
+  {"hoj",       HB_TAG('H','A','R',' ')},       /* Hadothi -> Harauti */
+  {"hr",        HB_TAG('H','R','V',' ')},       /* Croatian */
+  {"hrm",       HB_TAG('H','M','N',' ')},       /* Horned Miao -> Hmong */
+  {"hsb",       HB_TAG('U','S','B',' ')},       /* Upper Sorbian */
+  {"hsn",       HB_TAG('Z','H','S',' ')},       /* Xiang Chinese -> Chinese Simplified */
+  {"ht",        HB_TAG('H','A','I',' ')},       /* Haitian (Haitian Creole) */
+  {"hu",        HB_TAG('H','U','N',' ')},       /* Hungarian */
+  {"huj",       HB_TAG('H','M','N',' ')},       /* Northern Guiyang Hmong -> Hmong */
+  {"hup",       HB_TAG('A','T','H',' ')},       /* Hupa -> Athapaskan */
+  {"hy",        HB_TAG('H','Y','E','0')},       /* Armenian -> Armenian East */
+  {"hy",        HB_TAG('H','Y','E',' ')},       /* Armenian */
+  {"hyw",       HB_TAG('H','Y','E',' ')},       /* Western Armenian -> Armenian */
+  {"hz",        HB_TAG('H','E','R',' ')},       /* Herero */
+  {"ia",        HB_TAG('I','N','A',' ')},       /* Interlingua (International Auxiliary Language Association) */
+/*{"iba",       HB_TAG('I','B','A',' ')},*/     /* Iban */
+/*{"ibb",       HB_TAG('I','B','B',' ')},*/     /* Ibibio */
+  {"id",        HB_TAG('I','N','D',' ')},       /* Indonesian */
+  {"ida",       HB_TAG('L','U','H',' ')},       /* Idakho-Isukha-Tiriki -> Luyia */
+  {"ie",        HB_TAG('I','L','E',' ')},       /* Interlingue */
+  {"ig",        HB_TAG('I','B','O',' ')},       /* Igbo */
+  {"igb",       HB_TAG('E','B','I',' ')},       /* Ebira */
+  {"ii",        HB_TAG('Y','I','M',' ')},       /* Sichuan Yi -> Yi Modern */
+  {"ijc",       HB_TAG('I','J','O',' ')},       /* Izon -> Ijo */
+/*{"ijo",       HB_TAG('I','J','O',' ')},*/     /* Ijo [family] */
+  {"ik",        HB_TAG('I','P','K',' ')},       /* Inupiaq [macrolanguage] -> Inupiat */
+  {"ike",       HB_TAG('I','N','U',' ')},       /* Eastern Canadian Inuktitut -> Inuktitut */
+  {"ikt",       HB_TAG('I','N','U',' ')},       /* Inuinnaqtun -> Inuktitut */
+/*{"ilo",       HB_TAG('I','L','O',' ')},*/     /* Iloko -> Ilokano */
+  {"in",        HB_TAG('I','N','D',' ')},       /* Indonesian (retired code) */
+  {"ing",       HB_TAG('A','T','H',' ')},       /* Degexit'an -> Athapaskan */
+  {"inh",       HB_TAG('I','N','G',' ')},       /* Ingush */
+  {"io",        HB_TAG('I','D','O',' ')},       /* Ido */
+  {"is",        HB_TAG('I','S','L',' ')},       /* Icelandic */
+  {"it",        HB_TAG('I','T','A',' ')},       /* Italian */
+  {"iu",        HB_TAG('I','N','U',' ')},       /* Inuktitut [macrolanguage] */
+  {"iw",        HB_TAG('I','W','R',' ')},       /* Hebrew (retired code) */
+  {"ja",        HB_TAG('J','A','N',' ')},       /* Japanese */
+  {"jak",       HB_TAG('M','L','Y',' ')},       /* Jakun -> Malay */
+/*{"jam",       HB_TAG('J','A','M',' ')},*/     /* Jamaican Creole English -> Jamaican Creole */
+  {"jax",       HB_TAG('M','L','Y',' ')},       /* Jambi Malay -> Malay */
+/*{"jbo",       HB_TAG('J','B','O',' ')},*/     /* Lojban */
+/*{"jct",       HB_TAG('J','C','T',' ')},*/     /* Krymchak */
+  {"ji",        HB_TAG('J','I','I',' ')},       /* Yiddish (retired code) */
+  {"jv",        HB_TAG('J','A','V',' ')},       /* Javanese */
+  {"jw",        HB_TAG('J','A','V',' ')},       /* Javanese (retired code) */
+  {"ka",        HB_TAG('K','A','T',' ')},       /* Georgian */
+  {"kaa",       HB_TAG('K','R','K',' ')},       /* Karakalpak */
+  {"kab",       HB_TAG('K','A','B','0')},       /* Kabyle */
+  {"kam",       HB_TAG('K','M','B',' ')},       /* Kamba (Kenya) */
+  {"kar",       HB_TAG('K','R','N',' ')},       /* Karen [family] */
+  {"kbd",       HB_TAG('K','A','B',' ')},       /* Kabardian */
+  {"kby",       HB_TAG('K','N','R',' ')},       /* Manga Kanuri -> Kanuri */
+  {"kca",       HB_TAG('K','H','K',' ')},       /* Khanty -> Khanty-Kazim */
+  {"kca",       HB_TAG('K','H','S',' ')},       /* Khanty -> Khanty-Shurishkar */
+  {"kca",       HB_TAG('K','H','V',' ')},       /* Khanty -> Khanty-Vakhi */
+/*{"kde",       HB_TAG('K','D','E',' ')},*/     /* Makonde */
+  {"kdr",       HB_TAG('K','R','M',' ')},       /* Karaim */
+  {"kdt",       HB_TAG('K','U','Y',' ')},       /* Kuy */
+/*{"kea",       HB_TAG('K','E','A',' ')},*/     /* Kabuverdianu (Crioulo) */
+/*{"kek",       HB_TAG('K','E','K',' ')},*/     /* Kekchi */
+  {"kex",       HB_TAG('K','K','N',' ')},       /* Kukna -> Kokni */
+  {"kfa",       HB_TAG('K','O','D',' ')},       /* Kodava -> Kodagu */
+  {"kfr",       HB_TAG('K','A','C',' ')},       /* Kachhi -> Kachchi */
+  {"kfx",       HB_TAG('K','U','L',' ')},       /* Kullu Pahari -> Kulvi */
+  {"kfy",       HB_TAG('K','M','N',' ')},       /* Kumaoni */
+  {"kg",        HB_TAG('K','O','N','0')},       /* Kongo [macrolanguage] */
+  {"kha",       HB_TAG('K','S','I',' ')},       /* Khasi */
+  {"khb",       HB_TAG('X','B','D',' ')},       /* Lü */
+  {"khk",       HB_TAG('M','N','G',' ')},       /* Halh Mongolian -> Mongolian */
+  {"kht",       HB_TAG('K','H','N',' ')},       /* Khamti -> Khamti Shan (Microsoft fonts) */
+  {"kht",       HB_TAG('K','H','T',' ')},       /* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */
+/*{"khw",       HB_TAG('K','H','W',' ')},*/     /* Khowar */
+  {"ki",        HB_TAG('K','I','K',' ')},       /* Kikuyu (Gikuyu) */
+/*{"kiu",       HB_TAG('K','I','U',' ')},*/     /* Kirmanjki */
+  {"kj",        HB_TAG('K','U','A',' ')},       /* Kuanyama */
+/*{"kjd",       HB_TAG('K','J','D',' ')},*/     /* Southern Kiwai */
+  {"kjh",       HB_TAG('K','H','A',' ')},       /* Khakas -> Khakass */
+/*{"kjp",       HB_TAG('K','J','P',' ')},*/     /* Pwo Eastern Karen -> Eastern Pwo Karen */
+/*{"kjz",       HB_TAG('K','J','Z',' ')},*/     /* Bumthangkha */
+  {"kk",        HB_TAG('K','A','Z',' ')},       /* Kazakh */
+  {"kkz",       HB_TAG('A','T','H',' ')},       /* Kaska -> Athapaskan */
+  {"kl",        HB_TAG('G','R','N',' ')},       /* Greenlandic */
+  {"kln",       HB_TAG('K','A','L',' ')},       /* Kalenjin [macrolanguage] */
+  {"km",        HB_TAG('K','H','M',' ')},       /* Khmer */
+  {"kmb",       HB_TAG('M','B','N',' ')},       /* Kimbundu -> Mbundu */
+  {"kmr",       HB_TAG('K','U','R',' ')},       /* Northern Kurdish -> Kurdish */
+  {"kmw",       HB_TAG('K','M','O',' ')},       /* Komo (Democratic Republic of Congo) */
+/*{"kmz",       HB_TAG('K','M','Z',' ')},*/     /* Khorasani Turkish -> Khorasani Turkic */
+  {"kn",        HB_TAG('K','A','N',' ')},       /* Kannada */
+  {"knc",       HB_TAG('K','N','R',' ')},       /* Central Kanuri -> Kanuri */
+  {"kng",       HB_TAG('K','O','N','0')},       /* Koongo -> Kongo */
+  {"knn",       HB_TAG('K','O','K',' ')},       /* Konkani */
+  {"ko",        HB_TAG('K','O','R',' ')},       /* Korean */
+  {"koi",       HB_TAG('K','O','P',' ')},       /* Komi-Permyak */
+/*{"kok",       HB_TAG('K','O','K',' ')},*/     /* Konkani [macrolanguage] */
+/*{"kos",       HB_TAG('K','O','S',' ')},*/     /* Kosraean */
+  {"koy",       HB_TAG('A','T','H',' ')},       /* Koyukon -> Athapaskan */
+  {"kpe",       HB_TAG('K','P','L',' ')},       /* Kpelle [macrolanguage] */
+  {"kpv",       HB_TAG('K','O','Z',' ')},       /* Komi-Zyrian */
+  {"kpy",       HB_TAG('K','Y','K',' ')},       /* Koryak */
+  {"kqs",       HB_TAG('K','I','S',' ')},       /* Northern Kissi -> Kisii */
+  {"kqy",       HB_TAG('K','R','T',' ')},       /* Koorete */
+  {"kr",        HB_TAG('K','N','R',' ')},       /* Kanuri [macrolanguage] */
+  {"krc",       HB_TAG('K','A','R',' ')},       /* Karachay-Balkar -> Karachay */
+  {"krc",       HB_TAG('B','A','L',' ')},       /* Karachay-Balkar -> Balkar */
+/*{"kri",       HB_TAG('K','R','I',' ')},*/     /* Krio */
+/*{"krl",       HB_TAG('K','R','L',' ')},*/     /* Karelian */
+  {"krt",       HB_TAG('K','N','R',' ')},       /* Tumari Kanuri -> Kanuri */
+  {"kru",       HB_TAG('K','U','U',' ')},       /* Kurukh */
+  {"ks",        HB_TAG('K','S','H',' ')},       /* Kashmiri */
+  {"ksh",       HB_TAG('K','S','H','0')},       /* Kölsch -> Ripuarian */
+  {"kss",       HB_TAG('K','I','S',' ')},       /* Southern Kisi -> Kisii */
+/*{"ksw",       HB_TAG('K','S','W',' ')},*/     /* S’gaw Karen */
+  {"ktb",       HB_TAG('K','E','B',' ')},       /* Kambaata -> Kebena */
+  {"ktu",       HB_TAG('K','O','N',' ')},       /* Kituba (Democratic Republic of Congo) -> Kikongo */
+  {"ktw",       HB_TAG('A','T','H',' ')},       /* Kato -> Athapaskan */
+  {"ku",        HB_TAG('K','U','R',' ')},       /* Kurdish [macrolanguage] */
+/*{"kum",       HB_TAG('K','U','M',' ')},*/     /* Kumyk */
+  {"kuu",       HB_TAG('A','T','H',' ')},       /* Upper Kuskokwim -> Athapaskan */
+  {"kv",        HB_TAG('K','O','M',' ')},       /* Komi [macrolanguage] */
+  {"kvb",       HB_TAG('M','L','Y',' ')},       /* Kubu -> Malay */
+  {"kvr",       HB_TAG('M','L','Y',' ')},       /* Kerinci -> Malay */
+  {"kw",        HB_TAG('C','O','R',' ')},       /* Cornish */
+  {"kwy",       HB_TAG('K','O','N','0')},       /* San Salvador Kongo -> Kongo */
+  {"kxc",       HB_TAG('K','M','S',' ')},       /* Konso -> Komso */
+  {"kxd",       HB_TAG('M','L','Y',' ')},       /* Brunei -> Malay */
+  {"kxl",       HB_TAG('K','U','U',' ')},       /* Nepali Kurux (retired code) -> Kurukh */
+  {"kxu",       HB_TAG('K','U','I',' ')},       /* Kui (India) (retired code) */
+  {"ky",        HB_TAG('K','I','R',' ')},       /* Kirghiz (Kyrgyz) */
+/*{"kyu",       HB_TAG('K','Y','U',' ')},*/     /* Western Kayah */
+  {"la",        HB_TAG('L','A','T',' ')},       /* Latin */
+  {"lad",       HB_TAG('J','U','D',' ')},       /* Ladino */
+  {"lb",        HB_TAG('L','T','Z',' ')},       /* Luxembourgish */
+  {"lbe",       HB_TAG('L','A','K',' ')},       /* Lak */
+  {"lbj",       HB_TAG('L','D','K',' ')},       /* Ladakhi */
+  {"lbl",       HB_TAG('B','I','K',' ')},       /* Libon Bikol -> Bikol */
+  {"lce",       HB_TAG('M','L','Y',' ')},       /* Loncong -> Malay */
+  {"lcf",       HB_TAG('M','L','Y',' ')},       /* Lubu -> Malay */
+  {"ldi",       HB_TAG('K','O','N','0')},       /* Laari -> Kongo */
+/*{"lez",       HB_TAG('L','E','Z',' ')},*/     /* Lezghian -> Lezgi */
+  {"lg",        HB_TAG('L','U','G',' ')},       /* Ganda */
+  {"li",        HB_TAG('L','I','M',' ')},       /* Limburgish */
+  {"lif",       HB_TAG('L','M','B',' ')},       /* Limbu */
+/*{"lij",       HB_TAG('L','I','J',' ')},*/     /* Ligurian */
+/*{"lis",       HB_TAG('L','I','S',' ')},*/     /* Lisu */
+  {"liw",       HB_TAG('M','L','Y',' ')},       /* Col -> Malay */
+/*{"ljp",       HB_TAG('L','J','P',' ')},*/     /* Lampung Api -> Lampung */
+  {"lkb",       HB_TAG('L','U','H',' ')},       /* Kabras -> Luyia */
+/*{"lki",       HB_TAG('L','K','I',' ')},*/     /* Laki */
+  {"lko",       HB_TAG('L','U','H',' ')},       /* Khayo -> Luyia */
+  {"lks",       HB_TAG('L','U','H',' ')},       /* Kisa -> Luyia */
+  {"lld",       HB_TAG('L','A','D',' ')},       /* Ladin */
+  {"lmn",       HB_TAG('L','A','M',' ')},       /* Lambadi -> Lambani */
+/*{"lmo",       HB_TAG('L','M','O',' ')},*/     /* Lombard */
+  {"ln",        HB_TAG('L','I','N',' ')},       /* Lingala */
+  {"lo",        HB_TAG('L','A','O',' ')},       /* Lao */
+/*{"lom",       HB_TAG('L','O','M',' ')},*/     /* Loma (Liberia) */
+/*{"lrc",       HB_TAG('L','R','C',' ')},*/     /* Northern Luri -> Luri */
+  {"lri",       HB_TAG('L','U','H',' ')},       /* Marachi -> Luyia */
+  {"lrm",       HB_TAG('L','U','H',' ')},       /* Marama -> Luyia */
+  {"lsm",       HB_TAG('L','U','H',' ')},       /* Saamia -> Luyia */
+  {"lt",        HB_TAG('L','T','H',' ')},       /* Lithuanian */
+  {"ltg",       HB_TAG('L','V','I',' ')},       /* Latgalian -> Latvian */
+  {"lto",       HB_TAG('L','U','H',' ')},       /* Tsotso -> Luyia */
+  {"lts",       HB_TAG('L','U','H',' ')},       /* Tachoni -> Luyia */
+  {"lu",        HB_TAG('L','U','B',' ')},       /* Luba-Katanga */
+/*{"lua",       HB_TAG('L','U','A',' ')},*/     /* Luba-Lulua */
+/*{"luo",       HB_TAG('L','U','O',' ')},*/     /* Luo (Kenya and Tanzania) */
+  {"lus",       HB_TAG('M','I','Z',' ')},       /* Lushai -> Mizo */
+  {"luy",       HB_TAG('L','U','H',' ')},       /* Luyia [macrolanguage] */
+  {"luz",       HB_TAG('L','R','C',' ')},       /* Southern Luri -> Luri */
+  {"lv",        HB_TAG('L','V','I',' ')},       /* Latvian [macrolanguage] */
+  {"lvs",       HB_TAG('L','V','I',' ')},       /* Standard Latvian -> Latvian */
+  {"lwg",       HB_TAG('L','U','H',' ')},       /* Wanga -> Luyia */
+  {"lzh",       HB_TAG('Z','H','T',' ')},       /* Literary Chinese -> Chinese Traditional */
+  {"lzz",       HB_TAG('L','A','Z',' ')},       /* Laz */
+/*{"mad",       HB_TAG('M','A','D',' ')},*/     /* Madurese -> Madura */
+/*{"mag",       HB_TAG('M','A','G',' ')},*/     /* Magahi */
+  {"mai",       HB_TAG('M','T','H',' ')},       /* Maithili */
+  {"mak",       HB_TAG('M','K','R',' ')},       /* Makasar */
+/*{"mam",       HB_TAG('M','A','M',' ')},*/     /* Mam */
+  {"man",       HB_TAG('M','N','K',' ')},       /* Mandingo [macrolanguage] -> Maninka */
+  {"max",       HB_TAG('M','L','Y',' ')},       /* North Moluccan Malay -> Malay */
+/*{"mbo",       HB_TAG('M','B','O',' ')},*/     /* Mbo (Cameroon) */
+  {"mct",       HB_TAG('B','T','I',' ')},       /* Mengisa -> Beti */
+  {"mdf",       HB_TAG('M','O','K',' ')},       /* Moksha */
+/*{"mdr",       HB_TAG('M','D','R',' ')},*/     /* Mandar */
+  {"mdy",       HB_TAG('M','L','E',' ')},       /* Male (Ethiopia) */
+  {"men",       HB_TAG('M','D','E',' ')},       /* Mende (Sierra Leone) */
+  {"meo",       HB_TAG('M','L','Y',' ')},       /* Kedah Malay -> Malay */
+/*{"mer",       HB_TAG('M','E','R',' ')},*/     /* Meru */
+/*{"mfa",       HB_TAG('M','F','A',' ')},*/     /* Pattani Malay */
+  {"mfb",       HB_TAG('M','L','Y',' ')},       /* Bangka -> Malay */
+/*{"mfe",       HB_TAG('M','F','E',' ')},*/     /* Morisyen */
+  {"mg",        HB_TAG('M','L','G',' ')},       /* Malagasy [macrolanguage] */
+  {"mh",        HB_TAG('M','A','H',' ')},       /* Marshallese */
+  {"mhr",       HB_TAG('L','M','A',' ')},       /* Eastern Mari -> Low Mari */
+  {"mhv",       HB_TAG('A','R','K',' ')},       /* Arakanese (retired code) -> Rakhine */
+  {"mi",        HB_TAG('M','R','I',' ')},       /* Maori */
+/*{"min",       HB_TAG('M','I','N',' ')},*/     /* Minangkabau */
+  {"mk",        HB_TAG('M','K','D',' ')},       /* Macedonian */
+  {"mku",       HB_TAG('M','N','K',' ')},       /* Konyanka Maninka -> Maninka */
+/*{"mkw",       HB_TAG('M','K','W',' ')},*/     /* Kituba (Congo) */
+  {"ml",        HB_TAG('M','A','L',' ')},       /* Malayalam -> Malayalam Traditional */
+  {"ml",        HB_TAG('M','L','R',' ')},       /* Malayalam -> Malayalam Reformed */
+  {"mlq",       HB_TAG('M','L','N',' ')},       /* Western Maninkakan -> Malinke */
+  {"mlq",       HB_TAG('M','N','K',' ')},       /* Western Maninkakan -> Maninka */
+  {"mmr",       HB_TAG('H','M','N',' ')},       /* Western Xiangxi Miao -> Hmong */
+  {"mn",        HB_TAG('M','N','G',' ')},       /* Mongolian [macrolanguage] */
+  {"mnc",       HB_TAG('M','C','H',' ')},       /* Manchu */
+/*{"mni",       HB_TAG('M','N','I',' ')},*/     /* Manipuri */
+  {"mnk",       HB_TAG('M','N','D',' ')},       /* Mandinka */
+  {"mnk",       HB_TAG('M','N','K',' ')},       /* Mandinka -> Maninka */
+  {"mnp",       HB_TAG('Z','H','S',' ')},       /* Min Bei Chinese -> Chinese Simplified */
+  {"mns",       HB_TAG('M','A','N',' ')},       /* Mansi */
+  {"mnw",       HB_TAG('M','O','N',' ')},       /* Mon */
+  {"mo",        HB_TAG('M','O','L',' ')},       /* Moldavian (retired code) */
+/*{"moh",       HB_TAG('M','O','H',' ')},*/     /* Mohawk */
+/*{"mos",       HB_TAG('M','O','S',' ')},*/     /* Mossi */
+  {"mpe",       HB_TAG('M','A','J',' ')},       /* Majang */
+  {"mqg",       HB_TAG('M','L','Y',' ')},       /* Kota Bangun Kutai Malay -> Malay */
+  {"mr",        HB_TAG('M','A','R',' ')},       /* Marathi */
+  {"mrh",       HB_TAG('Q','I','N',' ')},       /* Mara Chin -> Chin */
+  {"mrj",       HB_TAG('H','M','A',' ')},       /* Western Mari -> High Mari */
+  {"ms",        HB_TAG('M','L','Y',' ')},       /* Malay [macrolanguage] */
+  {"msc",       HB_TAG('M','N','K',' ')},       /* Sankaran Maninka -> Maninka */
+  {"msh",       HB_TAG('M','L','G',' ')},       /* Masikoro Malagasy -> Malagasy */
+  {"msi",       HB_TAG('M','L','Y',' ')},       /* Sabah Malay -> Malay */
+  {"mt",        HB_TAG('M','T','S',' ')},       /* Maltese */
+  {"mtr",       HB_TAG('M','A','W',' ')},       /* Mewari -> Marwari */
+  {"mui",       HB_TAG('M','L','Y',' ')},       /* Musi -> Malay */
+  {"mup",       HB_TAG('R','A','J',' ')},       /* Malvi -> Rajasthani */
+  {"muq",       HB_TAG('H','M','N',' ')},       /* Eastern Xiangxi Miao -> Hmong */
+/*{"mus",       HB_TAG('M','U','S',' ')},*/     /* Creek -> Muscogee */
+  {"mvb",       HB_TAG('A','T','H',' ')},       /* Mattole -> Athapaskan */
+  {"mve",       HB_TAG('M','A','W',' ')},       /* Marwari (Pakistan) */
+  {"mvf",       HB_TAG('M','N','G',' ')},       /* Peripheral Mongolian -> Mongolian */
+  {"mwk",       HB_TAG('M','N','K',' ')},       /* Kita Maninkakan -> Maninka */
+/*{"mwl",       HB_TAG('M','W','L',' ')},*/     /* Mirandese */
+  {"mwr",       HB_TAG('M','A','W',' ')},       /* Marwari [macrolanguage] */
+/*{"mww",       HB_TAG('M','W','W',' ')},*/     /* Hmong Daw */
+  {"my",        HB_TAG('B','R','M',' ')},       /* Burmese */
+  {"mym",       HB_TAG('M','E','N',' ')},       /* Me’en */
+/*{"myn",       HB_TAG('M','Y','N',' ')},*/     /* Mayan [family] */
+  {"myq",       HB_TAG('M','N','K',' ')},       /* Forest Maninka (retired code) -> Maninka */
+  {"myv",       HB_TAG('E','R','Z',' ')},       /* Erzya */
+/*{"mzn",       HB_TAG('M','Z','N',' ')},*/     /* Mazanderani */
+  {"na",        HB_TAG('N','A','U',' ')},       /* Nauru -> Nauruan */
+/*{"nag",       HB_TAG('N','A','G',' ')},*/     /* Naga Pidgin -> Naga-Assamese */
+/*{"nah",       HB_TAG('N','A','H',' ')},*/     /* Nahuatl [family] */
+  {"nan",       HB_TAG('Z','H','S',' ')},       /* Min Nan Chinese -> Chinese Simplified */
+/*{"nap",       HB_TAG('N','A','P',' ')},*/     /* Neapolitan */
+  {"nb",        HB_TAG('N','O','R',' ')},       /* Norwegian Bokmål -> Norwegian */
+  {"nd",        HB_TAG('N','D','B',' ')},       /* North Ndebele -> Ndebele */
+/*{"ndc",       HB_TAG('N','D','C',' ')},*/     /* Ndau */
+/*{"nds",       HB_TAG('N','D','S',' ')},*/     /* Low Saxon */
+  {"ne",        HB_TAG('N','E','P',' ')},       /* Nepali [macrolanguage] */
+/*{"new",       HB_TAG('N','E','W',' ')},*/     /* Newari */
+  {"ng",        HB_TAG('N','D','G',' ')},       /* Ndonga */
+/*{"nga",       HB_TAG('N','G','A',' ')},*/     /* Ngbaka */
+  {"ngl",       HB_TAG('L','M','W',' ')},       /* Lomwe */
+  {"ngo",       HB_TAG('S','X','T',' ')},       /* Ngoni -> Sutu */
+  {"nhd",       HB_TAG('G','U','A',' ')},       /* Chiripá -> Guarani */
+  {"niq",       HB_TAG('K','A','L',' ')},       /* Nandi -> Kalenjin */
+/*{"niu",       HB_TAG('N','I','U',' ')},*/     /* Niuean */
+  {"niv",       HB_TAG('G','I','L',' ')},       /* Gilyak */
+  {"njz",       HB_TAG('N','I','S',' ')},       /* Nyishi -> Nisi */
+  {"nl",        HB_TAG('N','L','D',' ')},       /* Dutch */
+  {"nle",       HB_TAG('L','U','H',' ')},       /* East Nyala -> Luyia */
+  {"nn",        HB_TAG('N','Y','N',' ')},       /* Norwegian Nynorsk (Nynorsk, Norwegian) */
+  {"no",        HB_TAG('N','O','R',' ')},       /* Norwegian [macrolanguage] */
+  {"nod",       HB_TAG('N','T','A',' ')},       /* Northern Thai -> Northern Tai */
+/*{"noe",       HB_TAG('N','O','E',' ')},*/     /* Nimadi */
+/*{"nog",       HB_TAG('N','O','G',' ')},*/     /* Nogai */
+/*{"nov",       HB_TAG('N','O','V',' ')},*/     /* Novial */
+  {"npi",       HB_TAG('N','E','P',' ')},       /* Nepali */
+  {"nqo",       HB_TAG('N','K','O',' ')},       /* N’Ko */
+  {"nr",        HB_TAG('N','D','B',' ')},       /* South Ndebele -> Ndebele */
+  {"nsk",       HB_TAG('N','A','S',' ')},       /* Naskapi */
+/*{"nso",       HB_TAG('N','S','O',' ')},*/     /* Pedi -> Sotho, Northern */
+  {"nv",        HB_TAG('N','A','V',' ')},       /* Navajo */
+  {"nv",        HB_TAG('A','T','H',' ')},       /* Navajo -> Athapaskan */
+  {"ny",        HB_TAG('C','H','I',' ')},       /* Chichewa (Chewa, Nyanja) */
+  {"nyd",       HB_TAG('L','U','H',' ')},       /* Nyore -> Luyia */
+/*{"nym",       HB_TAG('N','Y','M',' ')},*/     /* Nyamwezi */
+  {"nyn",       HB_TAG('N','K','L',' ')},       /* Nyankole */
+/*{"nza",       HB_TAG('N','Z','A',' ')},*/     /* Tigon Mbembe -> Mbembe Tigon */
+  {"oc",        HB_TAG('O','C','I',' ')},       /* Occitan (post 1500) */
+  {"oj",        HB_TAG('O','J','B',' ')},       /* Ojibwa [macrolanguage] -> Ojibway */
+/*{"ojb",       HB_TAG('O','J','B',' ')},*/     /* Northwestern Ojibwa -> Ojibway */
+  {"ojc",       HB_TAG('O','J','B',' ')},       /* Central Ojibwa -> Ojibway */
+  {"ojg",       HB_TAG('O','J','B',' ')},       /* Eastern Ojibwa -> Ojibway */
+  {"ojs",       HB_TAG('O','C','R',' ')},       /* Severn Ojibwa -> Oji-Cree */
+  {"ojw",       HB_TAG('O','J','B',' ')},       /* Western Ojibwa -> Ojibway */
+  {"oki",       HB_TAG('K','A','L',' ')},       /* Okiek -> Kalenjin */
+  {"okm",       HB_TAG('K','O','H',' ')},       /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
+  {"om",        HB_TAG('O','R','O',' ')},       /* Oromo [macrolanguage] */
+  {"or",        HB_TAG('O','R','I',' ')},       /* Odia (formerly Oriya) [macrolanguage] */
+  {"orc",       HB_TAG('O','R','O',' ')},       /* Orma -> Oromo */
+  {"orn",       HB_TAG('M','L','Y',' ')},       /* Orang Kanaq -> Malay */
+  {"ors",       HB_TAG('M','L','Y',' ')},       /* Orang Seletar -> Malay */
+  {"ory",       HB_TAG('O','R','I',' ')},       /* Odia (formerly Oriya) */
+  {"os",        HB_TAG('O','S','S',' ')},       /* Ossetian */
+  {"otw",       HB_TAG('O','J','B',' ')},       /* Ottawa -> Ojibway */
+  {"pa",        HB_TAG('P','A','N',' ')},       /* Punjabi */
+/*{"pag",       HB_TAG('P','A','G',' ')},*/     /* Pangasinan */
+/*{"pam",       HB_TAG('P','A','M',' ')},*/     /* Pampanga -> Pampangan */
+  {"pap",       HB_TAG('P','A','P','0')},       /* Papiamento -> Papiamentu */
+/*{"pau",       HB_TAG('P','A','U',' ')},*/     /* Palauan */
+  {"pbt",       HB_TAG('P','A','S',' ')},       /* Southern Pashto -> Pashto */
+  {"pbu",       HB_TAG('P','A','S',' ')},       /* Northern Pashto -> Pashto */
+/*{"pcc",       HB_TAG('P','C','C',' ')},*/     /* Bouyei */
+/*{"pcd",       HB_TAG('P','C','D',' ')},*/     /* Picard */
+  {"pce",       HB_TAG('P','L','G',' ')},       /* Ruching Palaung -> Palaung */
+  {"pck",       HB_TAG('Q','I','N',' ')},       /* Paite Chin -> Chin */
+/*{"pdc",       HB_TAG('P','D','C',' ')},*/     /* Pennsylvania German */
+  {"pel",       HB_TAG('M','L','Y',' ')},       /* Pekal -> Malay */
+  {"pes",       HB_TAG('F','A','R',' ')},       /* Iranian Persian -> Persian */
+  {"pga",       HB_TAG('A','R','A',' ')},       /* Sudanese Creole Arabic -> Arabic */
+/*{"phk",       HB_TAG('P','H','K',' ')},*/     /* Phake */
+  {"pi",        HB_TAG('P','A','L',' ')},       /* Pali */
+/*{"pih",       HB_TAG('P','I','H',' ')},*/     /* Pitcairn-Norfolk -> Norfolk */
+  {"pko",       HB_TAG('K','A','L',' ')},       /* Pökoot -> Kalenjin */
+  {"pl",        HB_TAG('P','L','K',' ')},       /* Polish */
+  {"pll",       HB_TAG('P','L','G',' ')},       /* Shwe Palaung -> Palaung */
+  {"plp",       HB_TAG('P','A','P',' ')},       /* Palpa (retired code) */
+  {"plt",       HB_TAG('M','L','G',' ')},       /* Plateau Malagasy -> Malagasy */
+/*{"pms",       HB_TAG('P','M','S',' ')},*/     /* Piemontese */
+/*{"pnb",       HB_TAG('P','N','B',' ')},*/     /* Western Panjabi */
+/*{"poh",       HB_TAG('P','O','H',' ')},*/     /* Poqomchi' -> Pocomchi */
+/*{"pon",       HB_TAG('P','O','N',' ')},*/     /* Pohnpeian */
+  {"ppa",       HB_TAG('B','A','G',' ')},       /* Pao (retired code) -> Baghelkhandi */
+/*{"pro",       HB_TAG('P','R','O',' ')},*/     /* Old Provençal (to 1500) -> Provençal / Old Provençal */
+  {"prs",       HB_TAG('D','R','I',' ')},       /* Dari */
+  {"ps",        HB_TAG('P','A','S',' ')},       /* Pashto [macrolanguage] */
+  {"pse",       HB_TAG('M','L','Y',' ')},       /* Central Malay -> Malay */
+  {"pst",       HB_TAG('P','A','S',' ')},       /* Central Pashto -> Pashto */
+  {"pt",        HB_TAG('P','T','G',' ')},       /* Portuguese */
+/*{"pwo",       HB_TAG('P','W','O',' ')},*/     /* Pwo Western Karen -> Western Pwo Karen */
+  {"qu",        HB_TAG('Q','U','Z',' ')},       /* Quechua [macrolanguage] */
+  {"qub",       HB_TAG('Q','W','H',' ')},       /* Huallaga Huánuco Quechua -> Quechua (Peru) */
+/*{"quc",       HB_TAG('Q','U','C',' ')},*/     /* K’iche’ */
+  {"qud",       HB_TAG('Q','V','I',' ')},       /* Calderón Highland Quichua -> Quechua (Ecuador) */
+  {"quf",       HB_TAG('Q','U','Z',' ')},       /* Lambayeque Quechua -> Quechua */
+  {"qug",       HB_TAG('Q','V','I',' ')},       /* Chimborazo Highland Quichua -> Quechua (Ecuador) */
+/*{"quh",       HB_TAG('Q','U','H',' ')},*/     /* South Bolivian Quechua -> Quechua (Bolivia) */
+  {"quk",       HB_TAG('Q','U','Z',' ')},       /* Chachapoyas Quechua -> Quechua */
+  {"qul",       HB_TAG('Q','U','Z',' ')},       /* North Bolivian Quechua -> Quechua */
+  {"qup",       HB_TAG('Q','V','I',' ')},       /* Southern Pastaza Quechua -> Quechua (Ecuador) */
+  {"qur",       HB_TAG('Q','W','H',' ')},       /* Yanahuanca Pasco Quechua -> Quechua (Peru) */
+  {"qus",       HB_TAG('Q','U','H',' ')},       /* Santiago del Estero Quichua -> Quechua (Bolivia) */
+  {"quw",       HB_TAG('Q','V','I',' ')},       /* Tena Lowland Quichua -> Quechua (Ecuador) */
+  {"qux",       HB_TAG('Q','W','H',' ')},       /* Yauyos Quechua -> Quechua (Peru) */
+  {"quy",       HB_TAG('Q','U','Z',' ')},       /* Ayacucho Quechua -> Quechua */
+/*{"quz",       HB_TAG('Q','U','Z',' ')},*/     /* Cusco Quechua -> Quechua */
+  {"qva",       HB_TAG('Q','W','H',' ')},       /* Ambo-Pasco Quechua -> Quechua (Peru) */
+  {"qvc",       HB_TAG('Q','U','Z',' ')},       /* Cajamarca Quechua -> Quechua */
+  {"qve",       HB_TAG('Q','U','Z',' ')},       /* Eastern Apurímac Quechua -> Quechua */
+  {"qvh",       HB_TAG('Q','W','H',' ')},       /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */
+/*{"qvi",       HB_TAG('Q','V','I',' ')},*/     /* Imbabura Highland Quichua -> Quechua (Ecuador) */
+  {"qvj",       HB_TAG('Q','V','I',' ')},       /* Loja Highland Quichua -> Quechua (Ecuador) */
+  {"qvl",       HB_TAG('Q','W','H',' ')},       /* Cajatambo North Lima Quechua -> Quechua (Peru) */
+  {"qvm",       HB_TAG('Q','W','H',' ')},       /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */
+  {"qvn",       HB_TAG('Q','W','H',' ')},       /* North Junín Quechua -> Quechua (Peru) */
+  {"qvo",       HB_TAG('Q','V','I',' ')},       /* Napo Lowland Quechua -> Quechua (Ecuador) */
+  {"qvp",       HB_TAG('Q','W','H',' ')},       /* Pacaraos Quechua -> Quechua (Peru) */
+  {"qvs",       HB_TAG('Q','U','Z',' ')},       /* San Martín Quechua -> Quechua */
+  {"qvw",       HB_TAG('Q','W','H',' ')},       /* Huaylla Wanca Quechua -> Quechua (Peru) */
+  {"qvz",       HB_TAG('Q','V','I',' ')},       /* Northern Pastaza Quichua -> Quechua (Ecuador) */
+  {"qwa",       HB_TAG('Q','W','H',' ')},       /* Corongo Ancash Quechua -> Quechua (Peru) */
+  {"qwc",       HB_TAG('Q','U','Z',' ')},       /* Classical Quechua -> Quechua */
+/*{"qwh",       HB_TAG('Q','W','H',' ')},*/     /* Huaylas Ancash Quechua -> Quechua (Peru) */
+  {"qws",       HB_TAG('Q','W','H',' ')},       /* Sihuas Ancash Quechua -> Quechua (Peru) */
+  {"qxa",       HB_TAG('Q','W','H',' ')},       /* Chiquián Ancash Quechua -> Quechua (Peru) */
+  {"qxc",       HB_TAG('Q','W','H',' ')},       /* Chincha Quechua -> Quechua (Peru) */
+  {"qxh",       HB_TAG('Q','W','H',' ')},       /* Panao Huánuco Quechua -> Quechua (Peru) */
+  {"qxl",       HB_TAG('Q','V','I',' ')},       /* Salasaca Highland Quichua -> Quechua (Ecuador) */
+  {"qxn",       HB_TAG('Q','W','H',' ')},       /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */
+  {"qxo",       HB_TAG('Q','W','H',' ')},       /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */
+  {"qxp",       HB_TAG('Q','U','Z',' ')},       /* Puno Quechua -> Quechua */
+  {"qxr",       HB_TAG('Q','V','I',' ')},       /* Cañar Highland Quichua -> Quechua (Ecuador) */
+  {"qxt",       HB_TAG('Q','W','H',' ')},       /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */
+  {"qxu",       HB_TAG('Q','U','Z',' ')},       /* Arequipa-La Unión Quechua -> Quechua */
+  {"qxw",       HB_TAG('Q','W','H',' ')},       /* Jauja Wanca Quechua -> Quechua (Peru) */
+  {"rag",       HB_TAG('L','U','H',' ')},       /* Logooli -> Luyia */
+/*{"raj",       HB_TAG('R','A','J',' ')},*/     /* Rajasthani [macrolanguage] */
+/*{"rar",       HB_TAG('R','A','R',' ')},*/     /* Rarotongan */
+  {"rbb",       HB_TAG('P','L','G',' ')},       /* Rumai Palaung -> Palaung */
+  {"rbl",       HB_TAG('B','I','K',' ')},       /* Miraya Bikol -> Bikol */
+/*{"rej",       HB_TAG('R','E','J',' ')},*/     /* Rejang */
+/*{"ria",       HB_TAG('R','I','A',' ')},*/     /* Riang (India) */
+/*{"rif",       HB_TAG('R','I','F',' ')},*/     /* Tarifit */
+/*{"rit",       HB_TAG('R','I','T',' ')},*/     /* Ritharrngu -> Ritarungo */
+  {"rki",       HB_TAG('A','R','K',' ')},       /* Rakhine */
+/*{"rkw",       HB_TAG('R','K','W',' ')},*/     /* Arakwal */
+  {"rm",        HB_TAG('R','M','S',' ')},       /* Romansh */
+  {"rmc",       HB_TAG('R','O','Y',' ')},       /* Carpathian Romani -> Romany */
+  {"rmf",       HB_TAG('R','O','Y',' ')},       /* Kalo Finnish Romani -> Romany */
+  {"rml",       HB_TAG('R','O','Y',' ')},       /* Baltic Romani -> Romany */
+  {"rmn",       HB_TAG('R','O','Y',' ')},       /* Balkan Romani -> Romany */
+  {"rmo",       HB_TAG('R','O','Y',' ')},       /* Sinte Romani -> Romany */
+  {"rmw",       HB_TAG('R','O','Y',' ')},       /* Welsh Romani -> Romany */
+/*{"rmy",       HB_TAG('R','M','Y',' ')},*/     /* Vlax Romani */
+  {"rmz",       HB_TAG('A','R','K',' ')},       /* Marma -> Rakhine */
+  {"rn",        HB_TAG('R','U','N',' ')},       /* Rundi */
+  {"rnl",       HB_TAG('H','A','L',' ')},       /* Ranglong -> Halam (Falam Chin) */
+  {"ro",        HB_TAG('R','O','M',' ')},       /* Romanian */
+  {"rom",       HB_TAG('R','O','Y',' ')},       /* Romany [macrolanguage] */
+/*{"rtm",       HB_TAG('R','T','M',' ')},*/     /* Rotuman */
+  {"ru",        HB_TAG('R','U','S',' ')},       /* Russian */
+  {"rue",       HB_TAG('R','S','Y',' ')},       /* Rusyn */
+/*{"rup",       HB_TAG('R','U','P',' ')},*/     /* Aromanian */
+  {"rw",        HB_TAG('R','U','A',' ')},       /* Kinyarwanda */
+  {"rwr",       HB_TAG('M','A','W',' ')},       /* Marwari (India) */
+  {"sa",        HB_TAG('S','A','N',' ')},       /* Sanskrit */
+  {"sah",       HB_TAG('Y','A','K',' ')},       /* Yakut -> Sakha */
+  {"sam",       HB_TAG('P','A','A',' ')},       /* Samaritan Aramaic -> Palestinian Aramaic */
+/*{"sas",       HB_TAG('S','A','S',' ')},*/     /* Sasak */
+/*{"sat",       HB_TAG('S','A','T',' ')},*/     /* Santali */
+  {"sc",        HB_TAG('S','R','D',' ')},       /* Sardinian [macrolanguage] */
+  {"sck",       HB_TAG('S','A','D',' ')},       /* Sadri */
+/*{"scn",       HB_TAG('S','C','N',' ')},*/     /* Sicilian */
+/*{"sco",       HB_TAG('S','C','O',' ')},*/     /* Scots */
+  {"scs",       HB_TAG('S','C','S',' ')},       /* North Slavey */
+  {"scs",       HB_TAG('S','L','A',' ')},       /* North Slavey -> Slavey */
+  {"scs",       HB_TAG('A','T','H',' ')},       /* North Slavey -> Athapaskan */
+  {"sd",        HB_TAG('S','N','D',' ')},       /* Sindhi */
+  {"sdc",       HB_TAG('S','R','D',' ')},       /* Sassarese Sardinian -> Sardinian */
+  {"sdh",       HB_TAG('K','U','R',' ')},       /* Southern Kurdish -> Kurdish */
+  {"sdn",       HB_TAG('S','R','D',' ')},       /* Gallurese Sardinian -> Sardinian */
+  {"se",        HB_TAG('N','S','M',' ')},       /* Northern Sami */
+  {"seh",       HB_TAG('S','N','A',' ')},       /* Sena */
+  {"sek",       HB_TAG('A','T','H',' ')},       /* Sekani -> Athapaskan */
+/*{"sel",       HB_TAG('S','E','L',' ')},*/     /* Selkup */
+  {"sez",       HB_TAG('Q','I','N',' ')},       /* Senthang Chin -> Chin */
+  {"sfm",       HB_TAG('H','M','N',' ')},       /* Small Flowery Miao -> Hmong */
+  {"sg",        HB_TAG('S','G','O',' ')},       /* Sango */
+/*{"sga",       HB_TAG('S','G','A',' ')},*/     /* Old Irish (to 900) */
+  {"sgc",       HB_TAG('K','A','L',' ')},       /* Kipsigis -> Kalenjin */
+/*{"sgs",       HB_TAG('S','G','S',' ')},*/     /* Samogitian */
+  {"sgw",       HB_TAG('C','H','G',' ')},       /* Sebat Bet Gurage -> Chaha Gurage */
+  {"sgw",       HB_TAG('S','G','W',' ')},       /* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */
+/*{"shi",       HB_TAG('S','H','I',' ')},*/     /* Tachelhit */
+/*{"shn",       HB_TAG('S','H','N',' ')},*/     /* Shan */
+  {"shu",       HB_TAG('A','R','A',' ')},       /* Chadian Arabic -> Arabic */
+  {"si",        HB_TAG('S','N','H',' ')},       /* Sinhala (Sinhalese) */
+/*{"sid",       HB_TAG('S','I','D',' ')},*/     /* Sidamo */
+  {"sjd",       HB_TAG('K','S','M',' ')},       /* Kildin Sami */
+  {"sjo",       HB_TAG('S','I','B',' ')},       /* Xibe -> Sibe */
+  {"sk",        HB_TAG('S','K','Y',' ')},       /* Slovak */
+  {"skg",       HB_TAG('M','L','G',' ')},       /* Sakalava Malagasy -> Malagasy */
+  {"skr",       HB_TAG('S','R','K',' ')},       /* Saraiki */
+  {"sl",        HB_TAG('S','L','V',' ')},       /* Slovenian */
+  {"sm",        HB_TAG('S','M','O',' ')},       /* Samoan */
+  {"sma",       HB_TAG('S','S','M',' ')},       /* Southern Sami */
+  {"smj",       HB_TAG('L','S','M',' ')},       /* Lule Sami */
+  {"smn",       HB_TAG('I','S','M',' ')},       /* Inari Sami */
+  {"sms",       HB_TAG('S','K','S',' ')},       /* Skolt Sami */
+  {"sn",        HB_TAG('S','N','A','0')},       /* Shona */
+/*{"snk",       HB_TAG('S','N','K',' ')},*/     /* Soninke */
+  {"so",        HB_TAG('S','M','L',' ')},       /* Somali */
+/*{"sop",       HB_TAG('S','O','P',' ')},*/     /* Songe */
+  {"spv",       HB_TAG('O','R','I',' ')},       /* Sambalpuri -> Odia (formerly Oriya) */
+  {"spy",       HB_TAG('K','A','L',' ')},       /* Sabaot -> Kalenjin */
+  {"sq",        HB_TAG('S','Q','I',' ')},       /* Albanian [macrolanguage] */
+  {"sr",        HB_TAG('S','R','B',' ')},       /* Serbian */
+  {"src",       HB_TAG('S','R','D',' ')},       /* Logudorese Sardinian -> Sardinian */
+  {"sro",       HB_TAG('S','R','D',' ')},       /* Campidanese Sardinian -> Sardinian */
+/*{"srr",       HB_TAG('S','R','R',' ')},*/     /* Serer */
+  {"srs",       HB_TAG('A','T','H',' ')},       /* Sarsi -> Athapaskan */
+  {"ss",        HB_TAG('S','W','Z',' ')},       /* Swati */
+  {"ssh",       HB_TAG('A','R','A',' ')},       /* Shihhi Arabic -> Arabic */
+  {"st",        HB_TAG('S','O','T',' ')},       /* Southern Sotho -> Sotho, Southern */
+/*{"stq",       HB_TAG('S','T','Q',' ')},*/     /* Saterfriesisch -> Saterland Frisian */
+  {"stv",       HB_TAG('S','I','G',' ')},       /* Silt'e -> Silte Gurage */
+  {"su",        HB_TAG('S','U','N',' ')},       /* Sundanese */
+/*{"suk",       HB_TAG('S','U','K',' ')},*/     /* Sukuma */
+  {"suq",       HB_TAG('S','U','R',' ')},       /* Suri */
+  {"sv",        HB_TAG('S','V','E',' ')},       /* Swedish */
+/*{"sva",       HB_TAG('S','V','A',' ')},*/     /* Svan */
+  {"sw",        HB_TAG('S','W','K',' ')},       /* Swahili [macrolanguage] */
+  {"swb",       HB_TAG('C','M','R',' ')},       /* Maore Comorian -> Comorian */
+  {"swc",       HB_TAG('S','W','K',' ')},       /* Congo Swahili -> Swahili */
+  {"swh",       HB_TAG('S','W','K',' ')},       /* Swahili */
+  {"swv",       HB_TAG('M','A','W',' ')},       /* Shekhawati -> Marwari */
+/*{"sxu",       HB_TAG('S','X','U',' ')},*/     /* Upper Saxon */
+  {"syc",       HB_TAG('S','Y','R',' ')},       /* Classical Syriac -> Syriac */
+/*{"syl",       HB_TAG('S','Y','L',' ')},*/     /* Sylheti */
+/*{"syr",       HB_TAG('S','Y','R',' ')},*/     /* Syriac [macrolanguage] */
+/*{"szl",       HB_TAG('S','Z','L',' ')},*/     /* Silesian */
+  {"ta",        HB_TAG('T','A','M',' ')},       /* Tamil */
+  {"taa",       HB_TAG('A','T','H',' ')},       /* Lower Tanana -> Athapaskan */
+/*{"tab",       HB_TAG('T','A','B',' ')},*/     /* Tabassaran -> Tabasaran */
+  {"taq",       HB_TAG('T','M','H',' ')},       /* Tamasheq -> Tamashek */
+  {"tau",       HB_TAG('A','T','H',' ')},       /* Upper Tanana -> Athapaskan */
+  {"tcb",       HB_TAG('A','T','H',' ')},       /* Tanacross -> Athapaskan */
+  {"tce",       HB_TAG('A','T','H',' ')},       /* Southern Tutchone -> Athapaskan */
+  {"tcp",       HB_TAG('Q','I','N',' ')},       /* Tawr Chin -> Chin */
+  {"tcy",       HB_TAG('T','U','L',' ')},       /* Tulu -> Tumbuka */
+  {"tcz",       HB_TAG('Q','I','N',' ')},       /* Thado Chin -> Chin */
+/*{"tdd",       HB_TAG('T','D','D',' ')},*/     /* Tai Nüa -> Dehong Dai */
+  {"tdx",       HB_TAG('M','L','G',' ')},       /* Tandroy-Mahafaly Malagasy -> Malagasy */
+  {"te",        HB_TAG('T','E','L',' ')},       /* Telugu */
+  {"tec",       HB_TAG('K','A','L',' ')},       /* Terik -> Kalenjin */
+  {"tem",       HB_TAG('T','M','N',' ')},       /* Timne -> Temne */
+/*{"tet",       HB_TAG('T','E','T',' ')},*/     /* Tetum */
+  {"tfn",       HB_TAG('A','T','H',' ')},       /* Tanaina -> Athapaskan */
+  {"tg",        HB_TAG('T','A','J',' ')},       /* Tajik -> Tajiki */
+  {"tgj",       HB_TAG('N','I','S',' ')},       /* Tagin -> Nisi */
+  {"tgx",       HB_TAG('A','T','H',' ')},       /* Tagish -> Athapaskan */
+  {"th",        HB_TAG('T','H','A',' ')},       /* Thai */
+  {"tht",       HB_TAG('A','T','H',' ')},       /* Tahltan -> Athapaskan */
+  {"thv",       HB_TAG('T','M','H',' ')},       /* Tahaggart Tamahaq -> Tamashek */
+  {"thz",       HB_TAG('T','M','H',' ')},       /* Tayart Tamajeq -> Tamashek */
+  {"ti",        HB_TAG('T','G','Y',' ')},       /* Tigrinya */
+  {"tig",       HB_TAG('T','G','R',' ')},       /* Tigre */
+/*{"tiv",       HB_TAG('T','I','V',' ')},*/     /* Tiv */
+  {"tk",        HB_TAG('T','K','M',' ')},       /* Turkmen */
+  {"tkg",       HB_TAG('M','L','G',' ')},       /* Tesaka Malagasy -> Malagasy */
+  {"tl",        HB_TAG('T','G','L',' ')},       /* Tagalog */
+/*{"tmh",       HB_TAG('T','M','H',' ')},*/     /* Tamashek [macrolanguage] */
+  {"tmw",       HB_TAG('M','L','Y',' ')},       /* Temuan -> Malay */
+  {"tn",        HB_TAG('T','N','A',' ')},       /* Tswana */
+  {"tnf",       HB_TAG('D','R','I',' ')},       /* Tangshewi (retired code) -> Dari */
+  {"to",        HB_TAG('T','G','N',' ')},       /* Tonga (Tonga Islands) -> Tongan */
+  {"tod",       HB_TAG('T','O','D','0')},       /* Toma */
+  {"toi",       HB_TAG('T','N','G',' ')},       /* Tonga (Zambia) */
+  {"tol",       HB_TAG('A','T','H',' ')},       /* Tolowa -> Athapaskan */
+/*{"tpi",       HB_TAG('T','P','I',' ')},*/     /* Tok Pisin */
+  {"tr",        HB_TAG('T','R','K',' ')},       /* Turkish */
+  {"tru",       HB_TAG('T','U','A',' ')},       /* Turoyo -> Turoyo Aramaic */
+  {"tru",       HB_TAG('S','Y','R',' ')},       /* Turoyo -> Syriac */
+  {"ts",        HB_TAG('T','S','G',' ')},       /* Tsonga */
+/*{"tsj",       HB_TAG('T','S','J',' ')},*/     /* Tshangla */
+  {"tt",        HB_TAG('T','A','T',' ')},       /* Tatar */
+  {"ttm",       HB_TAG('A','T','H',' ')},       /* Northern Tutchone -> Athapaskan */
+  {"ttq",       HB_TAG('T','M','H',' ')},       /* Tawallammat Tamajaq -> Tamashek */
+/*{"tum",       HB_TAG('T','U','M',' ')},*/     /* Tumbuka -> Tulu */
+  {"tuu",       HB_TAG('A','T','H',' ')},       /* Tututni -> Athapaskan */
+  {"tuy",       HB_TAG('K','A','L',' ')},       /* Tugen -> Kalenjin */
+/*{"tvl",       HB_TAG('T','V','L',' ')},*/     /* Tuvalu */
+  {"tw",        HB_TAG('T','W','I',' ')},       /* Twi */
+  {"tw",        HB_TAG('A','K','A',' ')},       /* Twi -> Akan */
+  {"txc",       HB_TAG('A','T','H',' ')},       /* Tsetsaut -> Athapaskan */
+  {"txy",       HB_TAG('M','L','G',' ')},       /* Tanosy Malagasy -> Malagasy */
+  {"ty",        HB_TAG('T','H','T',' ')},       /* Tahitian */
+  {"tyv",       HB_TAG('T','U','V',' ')},       /* Tuvinian -> Tuvin */
+/*{"tyz",       HB_TAG('T','Y','Z',' ')},*/     /* Tày */
+/*{"tzm",       HB_TAG('T','Z','M',' ')},*/     /* Central Atlas Tamazight -> Tamazight */
+/*{"tzo",       HB_TAG('T','Z','O',' ')},*/     /* Tzotzil */
+  {"ubl",       HB_TAG('B','I','K',' ')},       /* Buhi'non Bikol -> Bikol */
+/*{"udm",       HB_TAG('U','D','M',' ')},*/     /* Udmurt */
+  {"ug",        HB_TAG('U','Y','G',' ')},       /* Uyghur */
+  {"uk",        HB_TAG('U','K','R',' ')},       /* Ukrainian */
+  {"uki",       HB_TAG('K','U','I',' ')},       /* Kui (India) */
+/*{"umb",       HB_TAG('U','M','B',' ')},*/     /* Umbundu */
+  {"unr",       HB_TAG('M','U','N',' ')},       /* Mundari */
+  {"ur",        HB_TAG('U','R','D',' ')},       /* Urdu */
+  {"urk",       HB_TAG('M','L','Y',' ')},       /* Urak Lawoi' -> Malay */
+  {"uz",        HB_TAG('U','Z','B',' ')},       /* Uzbek [macrolanguage] */
+  {"uzn",       HB_TAG('U','Z','B',' ')},       /* Northern Uzbek -> Uzbek */
+  {"uzs",       HB_TAG('U','Z','B',' ')},       /* Southern Uzbek -> Uzbek */
+  {"ve",        HB_TAG('V','E','N',' ')},       /* Venda */
+/*{"vec",       HB_TAG('V','E','C',' ')},*/     /* Venetian */
+  {"vi",        HB_TAG('V','I','T',' ')},       /* Vietnamese */
+  {"vkk",       HB_TAG('M','L','Y',' ')},       /* Kaur -> Malay */
+  {"vkt",       HB_TAG('M','L','Y',' ')},       /* Tenggarong Kutai Malay -> Malay */
+  {"vls",       HB_TAG('F','L','E',' ')},       /* Vlaams -> Dutch (Flemish) */
+  {"vmw",       HB_TAG('M','A','K',' ')},       /* Makhuwa */
+  {"vo",        HB_TAG('V','O','L',' ')},       /* Volapük */
+/*{"vro",       HB_TAG('V','R','O',' ')},*/     /* Võro */
+  {"wa",        HB_TAG('W','L','N',' ')},       /* Walloon */
+/*{"war",       HB_TAG('W','A','R',' ')},*/     /* Waray (Philippines) -> Waray-Waray */
+  {"wbm",       HB_TAG('W','A',' ',' ')},       /* Wa */
+  {"wbr",       HB_TAG('W','A','G',' ')},       /* Wagdi */
+  {"wlc",       HB_TAG('C','M','R',' ')},       /* Mwali Comorian -> Comorian */
+  {"wle",       HB_TAG('S','I','G',' ')},       /* Wolane -> Silte Gurage */
+  {"wlk",       HB_TAG('A','T','H',' ')},       /* Wailaki -> Athapaskan */
+  {"wni",       HB_TAG('C','M','R',' ')},       /* Ndzwani Comorian -> Comorian */
+  {"wo",        HB_TAG('W','L','F',' ')},       /* Wolof */
+  {"wry",       HB_TAG('M','A','W',' ')},       /* Merwari -> Marwari */
+  {"wsg",       HB_TAG('G','O','N',' ')},       /* Adilabad Gondi -> Gondi */
+/*{"wtm",       HB_TAG('W','T','M',' ')},*/     /* Mewati */
+  {"wuu",       HB_TAG('Z','H','S',' ')},       /* Wu Chinese -> Chinese Simplified */
+  {"xal",       HB_TAG('K','L','M',' ')},       /* Kalmyk */
+  {"xal",       HB_TAG('T','O','D',' ')},       /* Kalmyk -> Todo */
+  {"xan",       HB_TAG('S','E','K',' ')},       /* Xamtanga -> Sekota */
+  {"xh",        HB_TAG('X','H','S',' ')},       /* Xhosa */
+/*{"xjb",       HB_TAG('X','J','B',' ')},*/     /* Minjungbal -> Minjangbal */
+/*{"xkf",       HB_TAG('X','K','F',' ')},*/     /* Khengkha */
+  {"xmm",       HB_TAG('M','L','Y',' ')},       /* Manado Malay -> Malay */
+  {"xmv",       HB_TAG('M','L','G',' ')},       /* Antankarana Malagasy -> Malagasy */
+  {"xmw",       HB_TAG('M','L','G',' ')},       /* Tsimihety Malagasy -> Malagasy */
+  {"xnr",       HB_TAG('D','G','R',' ')},       /* Kangri -> Dogri */
+/*{"xog",       HB_TAG('X','O','G',' ')},*/     /* Soga */
+/*{"xpe",       HB_TAG('X','P','E',' ')},*/     /* Liberia Kpelle -> Kpelle (Liberia) */
+  {"xsl",       HB_TAG('S','S','L',' ')},       /* South Slavey */
+  {"xsl",       HB_TAG('S','L','A',' ')},       /* South Slavey -> Slavey */
+  {"xsl",       HB_TAG('A','T','H',' ')},       /* South Slavey -> Athapaskan */
+  {"xst",       HB_TAG('S','I','G',' ')},       /* Silt'e (retired code) -> Silte Gurage */
+  {"xwo",       HB_TAG('T','O','D',' ')},       /* Written Oirat -> Todo */
+/*{"yao",       HB_TAG('Y','A','O',' ')},*/     /* Yao */
+/*{"yap",       HB_TAG('Y','A','P',' ')},*/     /* Yapese */
+  {"ybd",       HB_TAG('A','R','K',' ')},       /* Yangbye (retired code) -> Rakhine */
+  {"ydd",       HB_TAG('J','I','I',' ')},       /* Eastern Yiddish -> Yiddish */
+  {"yi",        HB_TAG('J','I','I',' ')},       /* Yiddish [macrolanguage] */
+  {"yih",       HB_TAG('J','I','I',' ')},       /* Western Yiddish -> Yiddish */
+  {"yo",        HB_TAG('Y','B','A',' ')},       /* Yoruba */
+  {"yos",       HB_TAG('Q','I','N',' ')},       /* Yos (retired code) -> Chin */
+  {"yrk",       HB_TAG('T','N','E',' ')},       /* Nenets -> Tundra Nenets */
+  {"yrk",       HB_TAG('F','N','E',' ')},       /* Nenets -> Forest Nenets */
+  {"yue",       HB_TAG('Z','H','H',' ')},       /* Yue Chinese -> Chinese, Hong Kong SAR */
+  {"za",        HB_TAG('Z','H','A',' ')},       /* Zhuang [macrolanguage] */
+  {"zch",       HB_TAG('Z','H','A',' ')},       /* Central Hongshuihe Zhuang -> Zhuang */
+  {"zdj",       HB_TAG('C','M','R',' ')},       /* Ngazidja Comorian -> Comorian */
+/*{"zea",       HB_TAG('Z','E','A',' ')},*/     /* Zeeuws -> Zealandic */
+  {"zeh",       HB_TAG('Z','H','A',' ')},       /* Eastern Hongshuihe Zhuang -> Zhuang */
+  {"zgb",       HB_TAG('Z','H','A',' ')},       /* Guibei Zhuang -> Zhuang */
+/*{"zgh",       HB_TAG('Z','G','H',' ')},*/     /* Standard Moroccan Tamazight */
+  {"zgm",       HB_TAG('Z','H','A',' ')},       /* Minz Zhuang -> Zhuang */
+  {"zgn",       HB_TAG('Z','H','A',' ')},       /* Guibian Zhuang -> Zhuang */
+  {"zh",        HB_TAG('Z','H','S',' ')},       /* Chinese [macrolanguage] -> Chinese Simplified */
+  {"zhd",       HB_TAG('Z','H','A',' ')},       /* Dai Zhuang -> Zhuang */
+  {"zhn",       HB_TAG('Z','H','A',' ')},       /* Nong Zhuang -> Zhuang */
+  {"zlj",       HB_TAG('Z','H','A',' ')},       /* Liujiang Zhuang -> Zhuang */
+  {"zlm",       HB_TAG('M','L','Y',' ')},       /* Malay */
+  {"zln",       HB_TAG('Z','H','A',' ')},       /* Lianshan Zhuang -> Zhuang */
+  {"zlq",       HB_TAG('Z','H','A',' ')},       /* Liuqian Zhuang -> Zhuang */
+  {"zmi",       HB_TAG('M','L','Y',' ')},       /* Negeri Sembilan Malay -> Malay */
+  {"zne",       HB_TAG('Z','N','D',' ')},       /* Zande */
+  {"zom",       HB_TAG('Q','I','N',' ')},       /* Zou -> Chin */
+  {"zqe",       HB_TAG('Z','H','A',' ')},       /* Qiubei Zhuang -> Zhuang */
+  {"zsm",       HB_TAG('M','L','Y',' ')},       /* Standard Malay -> Malay */
+  {"zu",        HB_TAG('Z','U','L',' ')},       /* Zulu */
+  {"zum",       HB_TAG('L','R','C',' ')},       /* Kumzari -> Luri */
+  {"zyb",       HB_TAG('Z','H','A',' ')},       /* Yongbei Zhuang -> Zhuang */
+  {"zyg",       HB_TAG('Z','H','A',' ')},       /* Yang Zhuang -> Zhuang */
+  {"zyj",       HB_TAG('Z','H','A',' ')},       /* Youjiang Zhuang -> Zhuang */
+  {"zyn",       HB_TAG('Z','H','A',' ')},       /* Yongnan Zhuang -> Zhuang */
+/*{"zza",       HB_TAG('Z','Z','A',' ')},*/     /* Zazaki [macrolanguage] */
+  {"zzj",       HB_TAG('Z','H','A',' ')},       /* Zuojiang Zhuang -> Zhuang */
 };
 
-static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == 3u, "");
-
 /**
  * hb_ot_tags_from_complex_language:
  * @lang_str: a BCP 47 language tag to convert.
@@ -1185,6 +1188,20 @@
       *count = 1;
       return true;
     }
+    if (lang_matches (&lang_str[1], "np-hant-hk"))
+    {
+      /* Northern Ping Chinese */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
+    if (lang_matches (&lang_str[1], "np-hant-mo"))
+    {
+      /* Northern Ping Chinese */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
     if (lang_matches (&lang_str[1], "px-hant-hk"))
     {
       /* Pu-Xian Chinese */
@@ -1199,6 +1216,20 @@
       *count = 1;
       return true;
     }
+    if (lang_matches (&lang_str[1], "sp-hant-hk"))
+    {
+      /* Southern Ping Chinese */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
+    if (lang_matches (&lang_str[1], "sp-hant-mo"))
+    {
+      /* Southern Ping Chinese */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
     if (lang_matches (&lang_str[1], "zh-hant-hk"))
     {
       /* Huizhou Chinese */
@@ -1269,6 +1300,20 @@
       *count = 1;
       return true;
     }
+    if (lang_matches (&lang_str[1], "np-hans"))
+    {
+      /* Northern Ping Chinese */
+      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      *count = 1;
+      return true;
+    }
+    if (lang_matches (&lang_str[1], "np-hant"))
+    {
+      /* Northern Ping Chinese */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      *count = 1;
+      return true;
+    }
     if (lang_matches (&lang_str[1], "px-hans"))
     {
       /* Pu-Xian Chinese */
@@ -1283,6 +1328,20 @@
       *count = 1;
       return true;
     }
+    if (lang_matches (&lang_str[1], "sp-hans"))
+    {
+      /* Southern Ping Chinese */
+      tags[0] = HB_TAG('Z','H','S',' ');  /* Chinese Simplified */
+      *count = 1;
+      return true;
+    }
+    if (lang_matches (&lang_str[1], "sp-hant"))
+    {
+      /* Southern Ping Chinese */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      *count = 1;
+      return true;
+    }
     if (lang_matches (&lang_str[1], "zh-hans"))
     {
       /* Huizhou Chinese */
@@ -1383,6 +1442,30 @@
       *count = 1;
       return true;
     }
+    if (0 == strncmp (&lang_str[1], "np-", 3)
+        && subtag_matches (lang_str, limit, "-hk"))
+    {
+      /* Northern Ping Chinese; Hong Kong */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "np-", 3)
+        && subtag_matches (lang_str, limit, "-mo"))
+    {
+      /* Northern Ping Chinese; Macao */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "np-", 3)
+        && subtag_matches (lang_str, limit, "-tw"))
+    {
+      /* Northern Ping Chinese; Taiwan, Province of China */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      *count = 1;
+      return true;
+    }
     if (0 == strncmp (&lang_str[1], "px-", 3)
         && subtag_matches (lang_str, limit, "-hk"))
     {
@@ -1407,6 +1490,30 @@
       *count = 1;
       return true;
     }
+    if (0 == strncmp (&lang_str[1], "sp-", 3)
+        && subtag_matches (lang_str, limit, "-hk"))
+    {
+      /* Southern Ping Chinese; Hong Kong */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "sp-", 3)
+        && subtag_matches (lang_str, limit, "-mo"))
+    {
+      /* Southern Ping Chinese; Macao */
+      tags[0] = HB_TAG('Z','H','H',' ');  /* Chinese, Hong Kong SAR */
+      *count = 1;
+      return true;
+    }
+    if (0 == strncmp (&lang_str[1], "sp-", 3)
+        && subtag_matches (lang_str, limit, "-tw"))
+    {
+      /* Southern Ping Chinese; Taiwan, Province of China */
+      tags[0] = HB_TAG('Z','H','T',' ');  /* Chinese Traditional */
+      *count = 1;
+      return true;
+    }
     if (0 == strncmp (&lang_str[1], "zh-", 3)
         && subtag_matches (lang_str, limit, "-hk"))
     {
@@ -1934,7 +2041,8 @@
  *
  * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to
  * many language tags) and the best tag is not the alphabetically first, or if
- * the best tag consists of multiple subtags.
+ * the best tag consists of multiple subtags, or if the best tag does not appear
+ * in #ot_languages.
  *
  * Return value: The #hb_language_t corresponding to the BCP 47 language tag,
  * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.
@@ -1944,6 +2052,8 @@
 {
   switch (tag)
   {
+  case HB_TAG('A','L','T',' '):  /* Altai */
+    return hb_language_from_string ("alt", -1);  /* Southern Altai */
   case HB_TAG('A','P','P','H'):  /* Phonetic transcription—Americanist conventions */
     return hb_language_from_string ("und-fonnapa", -1);  /* Undetermined; North American Phonetic Alphabet */
   case HB_TAG('A','R','A',' '):  /* Arabic */
@@ -1962,8 +2072,6 @@
     return hb_language_from_string ("din", -1);  /* Dinka */
   case HB_TAG('D','R','I',' '):  /* Dari */
     return hb_language_from_string ("prs", -1);  /* Dari */
-  case HB_TAG('D','U','J',' '):  /* Dhuwal */
-    return hb_language_from_string ("dwu", -1);  /* Dhuwal */
   case HB_TAG('D','Z','N',' '):  /* Dzongkha */
     return hb_language_from_string ("dz", -1);  /* Dzongkha */
   case HB_TAG('E','T','I',' '):  /* Estonian */
@@ -1972,6 +2080,8 @@
     return hb_language_from_string ("gon", -1);  /* Gondi */
   case HB_TAG('H','M','N',' '):  /* Hmong */
     return hb_language_from_string ("hmn", -1);  /* Hmong */
+  case HB_TAG('H','N','D',' '):  /* Hindko */
+    return hb_language_from_string ("hnd", -1);  /* Southern Hindko */
   case HB_TAG('I','J','O',' '):  /* Ijo */
     return hb_language_from_string ("ijo", -1);  /* Ijo */
   case HB_TAG('I','N','U',' '):  /* Inuktitut */
@@ -1992,6 +2102,8 @@
     return hb_language_from_string ("kr", -1);  /* Kanuri */
   case HB_TAG('K','O','K',' '):  /* Konkani */
     return hb_language_from_string ("kok", -1);  /* Konkani */
+  case HB_TAG('K','U','I',' '):  /* Kui */
+    return hb_language_from_string ("uki", -1);  /* Kui (India) */
   case HB_TAG('K','U','R',' '):  /* Kurdish */
     return hb_language_from_string ("ku", -1);  /* Kurdish */
   case HB_TAG('L','U','H',' '):  /* Luyia */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc
index 18b5686..36ff854 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc
@@ -28,6 +28,8 @@
 
 #include "hb.hh"
 
+#ifndef HB_NO_OT_TAG
+
 
 /* hb_script_t */
 
@@ -113,6 +115,7 @@
   return HB_SCRIPT_UNKNOWN;
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 void
 hb_ot_tags_from_script (hb_script_t  script,
                         hb_tag_t    *script_tag_1,
@@ -124,6 +127,7 @@
   *script_tag_1 = count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_SCRIPT;
   *script_tag_2 = count > 1 ? tags[1] : HB_OT_TAG_DEFAULT_SCRIPT;
 }
+#endif
 
 /*
  * Complete list at:
@@ -143,7 +147,9 @@
   hb_tag_t new_tag = hb_ot_new_tag_from_script (script);
   if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT))
   {
-    tags[i++] = new_tag | '3';
+    /* HB_SCRIPT_MYANMAR maps to 'mym2', but there is no 'mym3'. */
+    if (new_tag != HB_TAG('m','y','m','2'))
+      tags[i++] = new_tag | '3';
     if (*count > i)
       tags[i++] = new_tag;
   }
@@ -171,24 +177,6 @@
 
 /* hb_language_t */
 
-static int
-lang_compare_first_component (const void *pa,
-                              const void *pb)
-{
-  const char *a = (const char *) pa;
-  const char *b = (const char *) pb;
-  unsigned int da, db;
-  const char *p;
-
-  p = strchr (a, '-');
-  da = p ? (unsigned int) (p - a) : strlen (a);
-
-  p = strchr (b, '-');
-  db = p ? (unsigned int) (p - b) : strlen (b);
-
-  return strncmp (a, b, MAX (da, db));
-}
-
 static bool
 subtag_matches (const char *lang_str,
                 const char *limit,
@@ -213,10 +201,28 @@
          (lang_str[len] == '\0' || lang_str[len] == '-');
 }
 
-typedef struct {
+struct LangTag
+{
   char language[4];
-  hb_tag_t tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
-} LangTag;
+  hb_tag_t tag;
+
+  int cmp (const char *a) const
+  {
+    const char *b = this->language;
+    unsigned int da, db;
+    const char *p;
+
+    p = strchr (a, '-');
+    da = p ? (unsigned int) (p - a) : strlen (a);
+
+    p = strchr (b, '-');
+    db = p ? (unsigned int) (p - b) : strlen (b);
+
+    return strncmp (a, b, hb_max (da, db));
+  }
+  int cmp (const LangTag *that) const
+  { return cmp (that->language); }
+};
 
 #include "hb-ot-tag-table.hh"
 
@@ -230,6 +236,7 @@
 /*{"??",        {HB_TAG('Y','I','C',' ')}},*/   /* Yi Classic */
 /*{"zh?",       {HB_TAG('Z','H','P',' ')}},*/   /* Chinese Phonetic */
 
+#ifndef HB_DISABLE_DEPRECATED
 hb_tag_t
 hb_ot_tag_from_language (hb_language_t language)
 {
@@ -238,6 +245,7 @@
   hb_ot_tags_from_script_and_language (HB_SCRIPT_UNKNOWN, language, nullptr, nullptr, &count, tags);
   return count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_LANGUAGE;
 }
+#endif
 
 static void
 hb_ot_tags_from_language (const char   *lang_str,
@@ -246,6 +254,7 @@
                           hb_tag_t     *tags)
 {
   const char *s;
+  unsigned int tag_idx;
 
   /* Check for matches of multiple subtags. */
   if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags))
@@ -254,7 +263,6 @@
   /* Find a language matching in the first component. */
   s = strchr (lang_str, '-');
   {
-    const LangTag *lang_tag;
     if (s && limit - lang_str >= 6)
     {
       const char *extlang_end = strchr (s + 1, '-');
@@ -263,14 +271,18 @@
           ISALPHA (s[1]))
         lang_str = s + 1;
     }
-    lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
-                                    ARRAY_LENGTH (ot_languages), sizeof (LangTag),
-                                    lang_compare_first_component);
-    if (lang_tag)
+    if (hb_sorted_array (ot_languages).bfind (lang_str, &tag_idx))
     {
       unsigned int i;
-      for (i = 0; i < *count && lang_tag->tags[i] != HB_TAG_NONE; i++)
-        tags[i] = lang_tag->tags[i];
+      while (tag_idx != 0 &&
+             0 == strcmp (ot_languages[tag_idx].language, ot_languages[tag_idx - 1].language))
+        tag_idx--;
+      for (i = 0;
+           i < *count &&
+           tag_idx + i < ARRAY_LENGTH (ot_languages) &&
+           0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language);
+           i++)
+        tags[i] = ot_languages[tag_idx + i].tag;
       *count = i;
       return;
     }
@@ -295,28 +307,42 @@
                           const char     *prefix,
                           unsigned char (*normalize) (unsigned char))
 {
-  if (private_use_subtag && count && tags && *count)
-  {
-    const char *s = strstr (private_use_subtag, prefix);
-    if (s)
+#ifdef HB_NO_LANGUAGE_PRIVATE_SUBTAG
+  return false;
+#endif
+
+  if (!(private_use_subtag && count && tags && *count)) return false;
+
+  const char *s = strstr (private_use_subtag, prefix);
+  if (!s) return false;
+
+  char tag[4];
+  int i;
+  s += strlen (prefix);
+  if (s[0] == '-') {
+    s += 1;
+    char c;
+    for (i = 0; i < 8 && ISHEX (s[i]); i++)
     {
-      char tag[4];
-      int i;
-      s += strlen (prefix);
-      for (i = 0; i < 4 && ISALNUM (s[i]); i++)
-        tag[i] = normalize (s[i]);
-      if (i)
-      {
-        for (; i < 4; i++)
-          tag[i] = ' ';
-        tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]);
-        if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT)
-          tags[0] ^= ~0xDFDFDFDF;
-        *count = 1;
-        return false;
-      }
+      c = FROMHEX (s[i]);
+      if (i % 2 == 0)
+        tag[i / 2] = c << 4;
+      else
+        tag[i / 2] += c;
     }
+    if (i != 8) return false;
+  } else {
+    for (i = 0; i < 4 && ISALNUM (s[i]); i++)
+      tag[i] = normalize (s[i]);
+    if (!i) return false;
+
+    for (; i < 4; i++)
+      tag[i] = ' ';
   }
+  tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]);
+  if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT)
+    tags[0] ^= ~0xDFDFDFDF;
+  *count = 1;
   return true;
 }
 
@@ -384,8 +410,8 @@
         limit = s;
     }
 
-    needs_script = parse_private_use_subtag (private_use_subtag, script_count, script_tags, "-hbsc", TOLOWER);
-    needs_language = parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER);
+    needs_script = !parse_private_use_subtag (private_use_subtag, script_count, script_tags, "-hbsc", TOLOWER);
+    needs_language = !parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER);
 
     if (needs_language && language_count && language_tags && *language_count)
       hb_ot_tags_from_language (lang_str, limit, language_count, language_tags);
@@ -419,20 +445,31 @@
   }
 
   for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
-    if (ot_languages[i].tags[0] == tag)
+    if (ot_languages[i].tag == tag)
       return hb_language_from_string (ot_languages[i].language, -1);
 
-  /* Else return a custom language in the form of "x-hbotABCD" */
+  /* Return a custom language in the form of "x-hbot-AABBCCDD".
+   * If it's three letters long, also guess it's ISO 639-3 and lower-case and
+   * prepend it (if it's not a registered tag, the private use subtags will
+   * ensure that calling hb_ot_tag_from_language on the result will still return
+   * the same tag as the original tag).
+   */
   {
-    unsigned char buf[11] = "x-hbot";
-    buf[6] = tag >> 24;
-    buf[7] = (tag >> 16) & 0xFF;
-    buf[8] = (tag >> 8) & 0xFF;
-    buf[9] = tag & 0xFF;
-    if (buf[9] == 0x20)
-      buf[9] = '\0';
-    buf[10] = '\0';
-    return hb_language_from_string ((char *) buf, -1);
+    char buf[20];
+    char *str = buf;
+    if (ISALPHA (tag >> 24)
+        && ISALPHA ((tag >> 16) & 0xFF)
+        && ISALPHA ((tag >> 8) & 0xFF)
+        && (tag & 0xFF) == ' ')
+    {
+      buf[0] = TOLOWER (tag >> 24);
+      buf[1] = TOLOWER ((tag >> 16) & 0xFF);
+      buf[2] = TOLOWER ((tag >> 8) & 0xFF);
+      buf[3] = '-';
+      str += 4;
+    }
+    snprintf (str, 16, "x-hbot-%08x", tag);
+    return hb_language_from_string (&*buf, -1);
   }
 }
 
@@ -473,13 +510,14 @@
       unsigned char *buf;
       const char *lang_str = hb_language_to_string (*language);
       size_t len = strlen (lang_str);
-      buf = (unsigned char *) malloc (len + 11);
+      buf = (unsigned char *) malloc (len + 16);
       if (unlikely (!buf))
       {
         *language = nullptr;
       }
       else
       {
+        int shift;
         memcpy (buf, lang_str, len);
         if (lang_str[0] != 'x' || lang_str[1] != '-') {
           buf[len++] = '-';
@@ -490,10 +528,9 @@
         buf[len++] = 'b';
         buf[len++] = 's';
         buf[len++] = 'c';
-        buf[len++] = script_tag >> 24;
-        buf[len++] = (script_tag >> 16) & 0xFF;
-        buf[len++] = (script_tag >> 8) & 0xFF;
-        buf[len++] = script_tag & 0xFF;
+        buf[len++] = '-';
+        for (shift = 28; shift >= 0; shift -= 4)
+          buf[len++] = TOHEX (script_tag >> shift);
         *language = hb_language_from_string ((char *) buf, len);
         free (buf);
       }
@@ -507,8 +544,8 @@
 {
   for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++)
   {
-    int c = lang_compare_first_component (ot_languages[i-1].language, ot_languages[i].language);
-    if (c >= 0)
+    int c = ot_languages[i].cmp (&ot_languages[i - 1]);
+    if (c > 0)
     {
       fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
                i, ot_languages[i-1].language, c, ot_languages[i].language);
@@ -525,3 +562,6 @@
 }
 
 #endif
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh
index 5ae0359..2c2934d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh
@@ -49,9 +49,10 @@
   }
 
   public:
-  F2DOT14       fromCoord;      /* A normalized coordinate value obtained using
-                                 * default normalization. */
-  F2DOT14       toCoord;        /* The modified, normalized coordinate value. */
+  F2DOT14       coords[2];
+//   F2DOT14    fromCoord;      /* A normalized coordinate value obtained using
+//                               * default normalization. */
+//   F2DOT14    toCoord;        /* The modified, normalized coordinate value. */
 
   public:
   DEFINE_SIZE_STATIC (4);
@@ -59,12 +60,13 @@
 
 struct SegmentMaps : ArrayOf<AxisValueMap>
 {
-  int map (int value) const
+  int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const
   {
+#define fromCoord coords[from_offset]
+#define toCoord coords[to_offset]
     /* The following special-cases are not part of OpenType, which requires
      * that at least -1, 0, and +1 must be mapped. But we include these as
      * part of a better error recovery scheme. */
-
     if (len < 2)
     {
       if (!len)
@@ -77,7 +79,7 @@
       return value - arrayZ[0].fromCoord + arrayZ[0].toCoord;
 
     unsigned int i;
-    unsigned int count = len;
+    unsigned int count = len - 1;
     for (i = 1; i < count && value > arrayZ[i].fromCoord; i++)
       ;
 
@@ -88,11 +90,14 @@
       return arrayZ[i-1].toCoord;
 
     int denom = arrayZ[i].fromCoord - arrayZ[i-1].fromCoord;
-    return arrayZ[i-1].toCoord +
-           ((arrayZ[i].toCoord - arrayZ[i-1].toCoord) *
-            (value - arrayZ[i-1].fromCoord) + denom/2) / denom;
+    return roundf (arrayZ[i-1].toCoord + ((float) (arrayZ[i].toCoord - arrayZ[i-1].toCoord) *
+                                          (value - arrayZ[i-1].fromCoord)) / denom);
+#undef toCoord
+#undef fromCoord
   }
 
+  int unmap (int value) const { return map (value, 1, 0); }
+
   public:
   DEFINE_SIZE_ARRAY (2, *this);
 };
@@ -123,7 +128,7 @@
 
   void map_coords (int *coords, unsigned int coords_length) const
   {
-    unsigned int count = MIN<unsigned int> (coords_length, axisCount);
+    unsigned int count = hb_min (coords_length, axisCount);
 
     const SegmentMaps *map = &firstAxisSegmentMaps;
     for (unsigned int i = 0; i < count; i++)
@@ -133,6 +138,18 @@
     }
   }
 
+  void unmap_coords (int *coords, unsigned int coords_length) const
+  {
+    unsigned int count = hb_min (coords_length, axisCount);
+
+    const SegmentMaps *map = &firstAxisSegmentMaps;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      coords[i] = map->unmap (coords[i]);
+      map = &StructAfter<SegmentMaps> (*map);
+    }
+  }
+
   protected:
   FixedVersion<>version;        /* Version of the avar table
                                  * initially set to 0x00010000u */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh
index 3785d09..e20cfa4 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh
@@ -44,7 +44,7 @@
 {
   friend struct fvar;
 
-  hb_array_t<const Fixed> get_coordinates (unsigned int axis_count) const
+  hb_array_t<const HBFixed> get_coordinates (unsigned int axis_count) const
   { return coordinatesZ.as_array (axis_count); }
 
   bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
@@ -58,7 +58,7 @@
   NameID        subfamilyNameID;/* The name ID for entries in the 'name' table
                                  * that provide subfamily names for this instance. */
   HBUINT16      flags;          /* Reserved for future use — set to 0. */
-  UnsizedArrayOf<Fixed>
+  UnsizedArrayOf<HBFixed>
                 coordinatesZ;   /* The coordinates array for this instance. */
   //NameID      postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
   //                              * table that provide PostScript names for this
@@ -70,22 +70,83 @@
 
 struct AxisRecord
 {
+  int cmp (hb_tag_t key) const { return axisTag.cmp (key); }
+
   enum
   {
     AXIS_FLAG_HIDDEN    = 0x0001,
   };
 
+#ifndef HB_DISABLE_DEPRECATED
+  void get_axis_deprecated (hb_ot_var_axis_t *info) const
+  {
+    info->tag = axisTag;
+    info->name_id = axisNameID;
+    get_coordinates (info->min_value, info->default_value, info->max_value);
+  }
+#endif
+
+  void get_axis_info (unsigned axis_index, hb_ot_var_axis_info_t *info) const
+  {
+    info->axis_index = axis_index;
+    info->tag = axisTag;
+    info->name_id = axisNameID;
+    info->flags = (hb_ot_var_axis_flags_t) (unsigned int) flags;
+    get_coordinates (info->min_value, info->default_value, info->max_value);
+    info->reserved = 0;
+  }
+
+  int normalize_axis_value (float v) const
+  {
+    float min_value, default_value, max_value;
+    get_coordinates (min_value, default_value, max_value);
+
+    v = hb_clamp (v, min_value, max_value);
+
+    if (v == default_value)
+      return 0;
+    else if (v < default_value)
+      v = (v - default_value) / (default_value - min_value);
+    else
+      v = (v - default_value) / (max_value - default_value);
+    return roundf (v * 16384.f);
+  }
+
+  float unnormalize_axis_value (int v) const
+  {
+    float min_value, default_value, max_value;
+    get_coordinates (min_value, default_value, max_value);
+
+    if (v == 0)
+      return default_value;
+    else if (v < 0)
+      return v * (default_value - min_value) / 16384.f + default_value;
+    else
+      return v * (max_value - default_value) / 16384.f + default_value;
+  }
+
+  hb_ot_name_id_t get_name_id () const { return axisNameID; }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
-  public:
+  protected:
+  void get_coordinates (float &min, float &default_, float &max) const
+  {
+    default_ = defaultValue / 65536.f;
+    /* Ensure order, to simplify client math. */
+    min = hb_min (default_, minValue / 65536.f);
+    max = hb_max (default_, maxValue / 65536.f);
+  }
+
+  protected:
   Tag           axisTag;        /* Tag identifying the design variation for the axis. */
-  Fixed         minValue;       /* The minimum coordinate value for the axis. */
-  Fixed         defaultValue;   /* The default coordinate value for the axis. */
-  Fixed         maxValue;       /* The maximum coordinate value for the axis. */
+  HBFixed       minValue;       /* The minimum coordinate value for the axis. */
+  HBFixed       defaultValue;   /* The default coordinate value for the axis. */
+  HBFixed       maxValue;       /* The maximum coordinate value for the axis. */
   HBUINT16      flags;          /* Axis flags. */
   NameID        axisNameID;     /* The name ID for entries in the 'name' table that
                                  * provide a display name for this axis. */
@@ -114,54 +175,20 @@
 
   unsigned int get_axis_count () const { return axisCount; }
 
-  void get_axis_deprecated (unsigned int axis_index,
-                                   hb_ot_var_axis_t *info) const
-  {
-    const AxisRecord &axis = get_axes ()[axis_index];
-    info->tag = axis.axisTag;
-    info->name_id =  axis.axisNameID;
-    info->default_value = axis.defaultValue / 65536.;
-    /* Ensure order, to simplify client math. */
-    info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.);
-    info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.);
-  }
-
-  void get_axis_info (unsigned int axis_index,
-                      hb_ot_var_axis_info_t *info) const
-  {
-    const AxisRecord &axis = get_axes ()[axis_index];
-    info->axis_index = axis_index;
-    info->tag = axis.axisTag;
-    info->name_id =  axis.axisNameID;
-    info->flags = (hb_ot_var_axis_flags_t) (unsigned int) axis.flags;
-    info->default_value = axis.defaultValue / 65536.;
-    /* Ensure order, to simplify client math. */
-    info->min_value = MIN<float> (info->default_value, axis.minValue / 65536.);
-    info->max_value = MAX<float> (info->default_value, axis.maxValue / 65536.);
-    info->reserved = 0;
-  }
-
+#ifndef HB_DISABLE_DEPRECATED
   unsigned int get_axes_deprecated (unsigned int      start_offset,
                                     unsigned int     *axes_count /* IN/OUT */,
                                     hb_ot_var_axis_t *axes_array /* OUT */) const
   {
     if (axes_count)
     {
-      /* TODO Rewrite as hb_array_t<>::sub-array() */
-      unsigned int count = axisCount;
-      start_offset = MIN (start_offset, count);
-
-      count -= start_offset;
-      axes_array += start_offset;
-
-      count = MIN (count, *axes_count);
-      *axes_count = count;
-
-      for (unsigned int i = 0; i < count; i++)
-        get_axis_deprecated (start_offset + i, axes_array + i);
+      hb_array_t<const AxisRecord> arr = get_axes ().sub_array (start_offset, axes_count);
+      for (unsigned i = 0; i < arr.length; ++i)
+        arr[i].get_axis_deprecated (&axes_array[i]);
     }
     return axisCount;
   }
+#endif
 
   unsigned int get_axis_infos (unsigned int           start_offset,
                                unsigned int          *axes_count /* IN/OUT */,
@@ -169,70 +196,38 @@
   {
     if (axes_count)
     {
-      /* TODO Rewrite as hb_array_t<>::sub-array() */
-      unsigned int count = axisCount;
-      start_offset = MIN (start_offset, count);
-
-      count -= start_offset;
-      axes_array += start_offset;
-
-      count = MIN (count, *axes_count);
-      *axes_count = count;
-
-      for (unsigned int i = 0; i < count; i++)
-        get_axis_info (start_offset + i, axes_array + i);
+      hb_array_t<const AxisRecord> arr = get_axes ().sub_array (start_offset, axes_count);
+      for (unsigned i = 0; i < arr.length; ++i)
+        arr[i].get_axis_info (start_offset + i, &axes_array[i]);
     }
     return axisCount;
   }
 
-  bool find_axis_deprecated (hb_tag_t tag,
-                             unsigned int *axis_index,
-                             hb_ot_var_axis_t *info) const
+#ifndef HB_DISABLE_DEPRECATED
+  bool
+  find_axis_deprecated (hb_tag_t tag, unsigned *axis_index, hb_ot_var_axis_t *info) const
   {
-    const AxisRecord *axes = get_axes ();
-    unsigned int count = get_axis_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (axes[i].axisTag == tag)
-      {
-        if (axis_index)
-          *axis_index = i;
-        get_axis_deprecated (i, info);
-        return true;
-      }
-    if (axis_index)
-      *axis_index = HB_OT_VAR_NO_AXIS_INDEX;
-    return false;
+    unsigned i;
+    if (!axis_index) axis_index = &i;
+    *axis_index = HB_OT_VAR_NO_AXIS_INDEX;
+    auto axes = get_axes ();
+    return axes.lfind (tag, axis_index) && (axes[*axis_index].get_axis_deprecated (info), true);
   }
+#endif
 
-  bool find_axis_info (hb_tag_t tag,
-                       hb_ot_var_axis_info_t *info) const
+  bool
+  find_axis_info (hb_tag_t tag, hb_ot_var_axis_info_t *info) const
   {
-    const AxisRecord *axes = get_axes ();
-    unsigned int count = get_axis_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (axes[i].axisTag == tag)
-      {
-        get_axis_info (i, info);
-        return true;
-      }
-    return false;
+    unsigned i;
+    auto axes = get_axes ();
+    return axes.lfind (tag, &i) && (axes[i].get_axis_info (i, info), true);
   }
 
   int normalize_axis_value (unsigned int axis_index, float v) const
-  {
-    hb_ot_var_axis_info_t axis;
-    get_axis_info (axis_index, &axis);
+  { return get_axes ()[axis_index].normalize_axis_value (v); }
 
-    v = MAX (MIN (v, axis.max_value), axis.min_value); /* Clamp. */
-
-    if (v == axis.default_value)
-      return 0;
-    else if (v < axis.default_value)
-      v = (v - axis.default_value) / (axis.default_value - axis.min_value);
-    else
-      v = (v - axis.default_value) / (axis.max_value - axis.default_value);
-    return (int) (v * 16384.f + (v >= 0.f ? .5f : -.5f));
-  }
+  float unnormalize_axis_value (unsigned int axis_index, int v) const
+  { return get_axes ()[axis_index].unnormalize_axis_value (v); }
 
   unsigned int get_instance_count () const { return instanceCount; }
 
@@ -253,8 +248,8 @@
   }
 
   unsigned int get_instance_coords (unsigned int  instance_index,
-                                           unsigned int *coords_length, /* IN/OUT */
-                                           float        *coords         /* OUT */) const
+                                    unsigned int *coords_length, /* IN/OUT */
+                                    float        *coords         /* OUT */) const
   {
     const InstanceRecord *instance = get_instance (instance_index);
     if (unlikely (!instance))
@@ -266,7 +261,7 @@
 
     if (coords_length && *coords_length)
     {
-      hb_array_t<const Fixed> instanceCoords = instance->get_coordinates (axisCount)
+      hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount)
                                                          .sub_array (0, *coords_length);
       for (unsigned int i = 0; i < instanceCoords.length; i++)
         coords[i] = instanceCoords.arrayZ[i].to_float ();
@@ -274,6 +269,26 @@
     return axisCount;
   }
 
+  void collect_name_ids (hb_set_t *nameids) const
+  {
+    if (!has_data ()) return;
+
+    + get_axes ()
+    | hb_map (&AxisRecord::get_name_id)
+    | hb_sink (nameids)
+    ;
+
+    + hb_range ((unsigned) instanceCount)
+    | hb_map ([this] (const unsigned _) { return get_instance_subfamily_name_id (_); })
+    | hb_sink (nameids)
+    ;
+
+    + hb_range ((unsigned) instanceCount)
+    | hb_map ([this] (const unsigned _) { return get_instance_postscript_name_id (_); })
+    | hb_sink (nameids)
+    ;
+  }
+
   protected:
   hb_array_t<const AxisRecord> get_axes () const
   { return hb_array (&(this+firstAxis), axisCount); }
@@ -299,8 +314,8 @@
   HBUINT16      instanceCount;  /* The number of named instances defined in the font
                                  * (the number of records in the instances array). */
   HBUINT16      instanceSize;   /* The size in bytes of each InstanceRecord — set
-                                 * to either axisCount * sizeof(Fixed) + 4, or to
-                                 * axisCount * sizeof(Fixed) + 6. */
+                                 * to either axisCount * sizeof(HBFixed) + 4, or to
+                                 * axisCount * sizeof(HBFixed) + 6. */
 
   public:
   DEFINE_SIZE_STATIC (16);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh
new file mode 100644
index 0000000..7c99b5d
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh
@@ -0,0 +1,701 @@
+/*
+ * Copyright © 2019  Adobe Inc.
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Adobe Author(s): Michiharu Ariza
+ */
+
+#ifndef HB_OT_VAR_GVAR_TABLE_HH
+#define HB_OT_VAR_GVAR_TABLE_HH
+
+#include "hb-open-type.hh"
+
+/*
+ * gvar -- Glyph Variation Table
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/gvar
+ */
+#define HB_OT_TAG_gvar HB_TAG('g','v','a','r')
+
+namespace OT {
+
+struct contour_point_t
+{
+  void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
+  { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
+
+  void translate (const contour_point_t &p) { x += p.x; y += p.y; }
+
+  uint8_t flag;
+  float x, y;
+  bool is_end_point;
+};
+
+struct contour_point_vector_t : hb_vector_t<contour_point_t>
+{
+  void extend (const hb_array_t<contour_point_t> &a)
+  {
+    unsigned int old_len = length;
+    resize (old_len + a.length);
+    for (unsigned int i = 0; i < a.length; i++)
+      (*this)[old_len + i] = a[i];
+  }
+
+  void transform (const float (&matrix)[4])
+  {
+    for (unsigned int i = 0; i < length; i++)
+    {
+      contour_point_t &p = (*this)[i];
+      float x_ = p.x * matrix[0] + p.y * matrix[2];
+           p.y = p.x * matrix[1] + p.y * matrix[3];
+      p.x = x_;
+    }
+  }
+
+  void translate (const contour_point_t& delta)
+  {
+    for (unsigned int i = 0; i < length; i++)
+      (*this)[i].translate (delta);
+  }
+};
+
+/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
+struct TupleVariationHeader
+{
+  unsigned get_size (unsigned axis_count) const
+  { return min_size + get_all_tuples (axis_count).get_size (); }
+
+  unsigned get_data_size () const { return varDataSize; }
+
+  const TupleVariationHeader &get_next (unsigned axis_count) const
+  { return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
+
+  float calculate_scalar (const int *coords, unsigned int coord_count,
+                          const hb_array_t<const F2DOT14> shared_tuples) const
+  {
+    hb_array_t<const F2DOT14> peak_tuple;
+
+    if (has_peak ())
+      peak_tuple = get_peak_tuple (coord_count);
+    else
+    {
+      unsigned int index = get_index ();
+      if (unlikely (index * coord_count >= shared_tuples.length))
+        return 0.f;
+      peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count);
+    }
+
+    hb_array_t<const F2DOT14> start_tuple;
+    hb_array_t<const F2DOT14> end_tuple;
+    if (has_intermediate ())
+    {
+      start_tuple = get_start_tuple (coord_count);
+      end_tuple = get_end_tuple (coord_count);
+    }
+
+    float scalar = 1.f;
+    for (unsigned int i = 0; i < coord_count; i++)
+    {
+      int v = coords[i];
+      int peak = peak_tuple[i];
+      if (!peak || v == peak) continue;
+
+      if (has_intermediate ())
+      {
+        int start = start_tuple[i];
+        int end = end_tuple[i];
+        if (unlikely (start > peak || peak > end ||
+                      (start < 0 && end > 0 && peak))) continue;
+        if (v < start || v > end) return 0.f;
+        if (v < peak)
+        { if (peak != start) scalar *= (float) (v - start) / (peak - start); }
+        else
+        { if (peak != end) scalar *= (float) (end - v) / (end - peak); }
+      }
+      else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
+      else
+        scalar *= (float) v / peak;
+    }
+    return scalar;
+  }
+
+  bool           has_peak () const { return tupleIndex & TuppleIndex::EmbeddedPeakTuple; }
+  bool   has_intermediate () const { return tupleIndex & TuppleIndex::IntermediateRegion; }
+  bool has_private_points () const { return tupleIndex & TuppleIndex::PrivatePointNumbers; }
+  unsigned      get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; }
+
+  protected:
+  struct TuppleIndex : HBUINT16
+  {
+    enum Flags {
+      EmbeddedPeakTuple   = 0x8000u,
+      IntermediateRegion  = 0x4000u,
+      PrivatePointNumbers = 0x2000u,
+      TupleIndexMask      = 0x0FFFu
+    };
+
+    DEFINE_SIZE_STATIC (2);
+  };
+
+  hb_array_t<const F2DOT14> get_all_tuples (unsigned axis_count) const
+  { return StructAfter<UnsizedArrayOf<F2DOT14>> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); }
+  hb_array_t<const F2DOT14> get_peak_tuple (unsigned axis_count) const
+  { return get_all_tuples (axis_count).sub_array (0, axis_count); }
+  hb_array_t<const F2DOT14> get_start_tuple (unsigned axis_count) const
+  { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count, axis_count); }
+  hb_array_t<const F2DOT14> get_end_tuple (unsigned axis_count) const
+  { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count + axis_count, axis_count); }
+
+  HBUINT16      varDataSize;    /* The size in bytes of the serialized
+                                 * data for this tuple variation table. */
+  TuppleIndex   tupleIndex;     /* A packed field. The high 4 bits are flags (see below).
+                                   The low 12 bits are an index into a shared tuple
+                                   records array. */
+  /* UnsizedArrayOf<F2DOT14> peakTuple - optional */
+                                /* Peak tuple record for this tuple variation table — optional,
+                                 * determined by flags in the tupleIndex value.
+                                 *
+                                 * Note that this must always be included in the 'cvar' table. */
+  /* UnsizedArrayOf<F2DOT14> intermediateStartTuple - optional */
+                                /* Intermediate start tuple record for this tuple variation table — optional,
+                                   determined by flags in the tupleIndex value. */
+  /* UnsizedArrayOf<F2DOT14> intermediateEndTuple - optional */
+                                /* Intermediate end tuple record for this tuple variation table — optional,
+                                 * determined by flags in the tupleIndex value. */
+  public:
+  DEFINE_SIZE_MIN (4);
+};
+
+struct GlyphVariationData
+{
+  const TupleVariationHeader &get_tuple_var_header (void) const
+  { return StructAfter<TupleVariationHeader> (data); }
+
+  struct tuple_iterator_t
+  {
+    void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_)
+    {
+      var_data_bytes = var_data_bytes_;
+      var_data = var_data_bytes_.as<GlyphVariationData> ();
+      index = 0;
+      axis_count = axis_count_;
+      current_tuple = &var_data->get_tuple_var_header ();
+      data_offset = 0;
+    }
+
+    bool get_shared_indices (hb_vector_t<unsigned int> &shared_indices /* OUT */)
+    {
+      if (var_data->has_shared_point_numbers ())
+      {
+        const HBUINT8 *base = &(var_data+var_data->data);
+        const HBUINT8 *p = base;
+        if (!unpack_points (p, shared_indices, var_data_bytes)) return false;
+        data_offset = p - base;
+      }
+      return true;
+    }
+
+    bool is_valid () const
+    {
+      return (index < var_data->tupleVarCount.get_count ()) &&
+             var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) &&
+             var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (), current_tuple->get_size (axis_count))) &&
+             current_tuple->get_size (axis_count);
+    }
+
+    bool move_to_next ()
+    {
+      data_offset += current_tuple->get_data_size ();
+      current_tuple = &current_tuple->get_next (axis_count);
+      index++;
+      return is_valid ();
+    }
+
+    const HBUINT8 *get_serialized_data () const
+    { return &(var_data+var_data->data) + data_offset; }
+
+    private:
+    const GlyphVariationData *var_data;
+    unsigned int index;
+    unsigned int axis_count;
+    unsigned int data_offset;
+
+    public:
+    hb_bytes_t var_data_bytes;
+    const TupleVariationHeader *current_tuple;
+  };
+
+  static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count,
+                                  hb_vector_t<unsigned int> &shared_indices /* OUT */,
+                                  tuple_iterator_t *iterator /* OUT */)
+  {
+    iterator->init (var_data_bytes, axis_count);
+    if (!iterator->get_shared_indices (shared_indices))
+      return false;
+    return iterator->is_valid ();
+  }
+
+  bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
+
+  static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
+                             hb_vector_t<unsigned int> &points /* OUT */,
+                             const hb_bytes_t &bytes)
+  {
+    enum packed_point_flag_t
+    {
+      POINTS_ARE_WORDS     = 0x80,
+      POINT_RUN_COUNT_MASK = 0x7F
+    };
+
+    if (unlikely (!bytes.check_range (p))) return false;
+
+    uint16_t count = *p++;
+    if (count & POINTS_ARE_WORDS)
+    {
+      if (unlikely (!bytes.check_range (p))) return false;
+      count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
+    }
+    points.resize (count);
+
+    unsigned int n = 0;
+    uint16_t i = 0;
+    while (i < count)
+    {
+      if (unlikely (!bytes.check_range (p))) return false;
+      uint16_t j;
+      uint8_t control = *p++;
+      uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1;
+      if (control & POINTS_ARE_WORDS)
+      {
+        for (j = 0; j < run_count && i < count; j++, i++)
+        {
+          if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
+            return false;
+          n += *(const HBUINT16 *)p;
+          points[i] = n;
+          p += HBUINT16::static_size;
+        }
+      }
+      else
+      {
+        for (j = 0; j < run_count && i < count; j++, i++)
+        {
+          if (unlikely (!bytes.check_range (p))) return false;
+          n += *p++;
+          points[i] = n;
+        }
+      }
+      if (j < run_count) return false;
+    }
+    return true;
+  }
+
+  static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
+                             hb_vector_t<int> &deltas /* IN/OUT */,
+                             const hb_bytes_t &bytes)
+  {
+    enum packed_delta_flag_t
+    {
+      DELTAS_ARE_ZERO      = 0x80,
+      DELTAS_ARE_WORDS     = 0x40,
+      DELTA_RUN_COUNT_MASK = 0x3F
+    };
+
+    unsigned int i = 0;
+    unsigned int count = deltas.length;
+    while (i < count)
+    {
+      if (unlikely (!bytes.check_range (p))) return false;
+      uint8_t control = *p++;
+      unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
+      unsigned int j;
+      if (control & DELTAS_ARE_ZERO)
+        for (j = 0; j < run_count && i < count; j++, i++)
+          deltas[i] = 0;
+      else if (control & DELTAS_ARE_WORDS)
+        for (j = 0; j < run_count && i < count; j++, i++)
+        {
+          if (unlikely (!bytes.check_range ((const HBUINT16 *) p)))
+            return false;
+          deltas[i] = *(const HBINT16 *) p;
+          p += HBUINT16::static_size;
+        }
+      else
+        for (j = 0; j < run_count && i < count; j++, i++)
+        {
+          if (unlikely (!bytes.check_range (p)))
+            return false;
+          deltas[i] = *(const HBINT8 *) p++;
+        }
+      if (j < run_count)
+        return false;
+    }
+    return true;
+  }
+
+  bool has_data () const { return tupleVarCount; }
+
+  protected:
+  struct TupleVarCount : HBUINT16
+  {
+    bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
+    unsigned int get_count () const { return (*this) & CountMask; }
+
+    protected:
+    enum Flags
+    {
+      SharedPointNumbers= 0x8000u,
+      CountMask         = 0x0FFFu
+    };
+    public:
+    DEFINE_SIZE_STATIC (2);
+  };
+
+  TupleVarCount tupleVarCount;  /* A packed field. The high 4 bits are flags, and the
+                                 * low 12 bits are the number of tuple variation tables
+                                 * for this glyph. The number of tuple variation tables
+                                 * can be any number between 1 and 4095. */
+  OffsetTo<HBUINT8>
+                data;           /* Offset from the start of the GlyphVariationData table
+                                 * to the serialized data. */
+  /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
+  public:
+  DEFINE_SIZE_MIN (4);
+};
+
+struct gvar
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar;
+
+  bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && (version.major == 1) &&
+                  (glyphCount == c->get_num_glyphs ()) &&
+                  sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) &&
+                  (is_long_offset () ?
+                     c->check_array (get_long_offset_array (), glyphCount+1) :
+                     c->check_array (get_short_offset_array (), glyphCount+1)) &&
+                  c->check_array (((const HBUINT8*)&(this+dataZ)) + get_offset (0),
+                                  get_offset (glyphCount) - get_offset (0)));
+  }
+
+  /* GlyphVariationData not sanitized here; must be checked while accessing each glyph varation data */
+  bool sanitize (hb_sanitize_context_t *c) const
+  { return sanitize_shallow (c); }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    gvar *out = c->serializer->allocate_min<gvar> ();
+    if (unlikely (!out)) return_trace (false);
+
+    out->version.major = 1;
+    out->version.minor = 0;
+    out->axisCount = axisCount;
+    out->sharedTupleCount = sharedTupleCount;
+
+    unsigned int num_glyphs = c->plan->num_output_glyphs ();
+    out->glyphCount = num_glyphs;
+
+    unsigned int subset_data_size = 0;
+    for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+    {
+      hb_codepoint_t old_gid;
+      if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
+      subset_data_size += get_glyph_var_data_bytes (c->source_blob, old_gid).length;
+    }
+
+    bool long_offset = subset_data_size & ~0xFFFFu;
+    out->flags = long_offset ? 1 : 0;
+
+    HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1));
+    if (!subset_offsets) return_trace (false);
+
+    /* shared tuples */
+    if (!sharedTupleCount || !sharedTuples)
+      out->sharedTuples = 0;
+    else
+    {
+      unsigned int shared_tuple_size = F2DOT14::static_size * axisCount * sharedTupleCount;
+      F2DOT14 *tuples = c->serializer->allocate_size<F2DOT14> (shared_tuple_size);
+      if (!tuples) return_trace (false);
+      out->sharedTuples = (char *) tuples - (char *) out;
+      memcpy (tuples, this+sharedTuples, shared_tuple_size);
+    }
+
+    char *subset_data = c->serializer->allocate_size<char> (subset_data_size);
+    if (!subset_data) return_trace (false);
+    out->dataZ = subset_data - (char *) out;
+
+    unsigned int glyph_offset = 0;
+    for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
+    {
+      hb_codepoint_t old_gid;
+      hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid)
+                                ? get_glyph_var_data_bytes (c->source_blob, old_gid)
+                                : hb_bytes_t ();
+
+      if (long_offset)
+        ((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
+      else
+        ((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
+
+      if (var_data_bytes.length > 0)
+        memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
+      subset_data += var_data_bytes.length;
+      glyph_offset += var_data_bytes.length;
+    }
+    if (long_offset)
+      ((HBUINT32 *) subset_offsets)[num_glyphs] = glyph_offset;
+    else
+      ((HBUINT16 *) subset_offsets)[num_glyphs] = glyph_offset / 2;
+
+    return_trace (true);
+  }
+
+  protected:
+  const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const
+  {
+    unsigned start_offset = get_offset (glyph);
+    unsigned length = get_offset (glyph+1) - start_offset;
+    hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length);
+    return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t ();
+  }
+
+  bool is_long_offset () const { return flags & 1; }
+
+  unsigned get_offset (unsigned i) const
+  { return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; }
+
+  const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; }
+  const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; }
+
+  public:
+  struct accelerator_t
+  {
+    void init (hb_face_t *face)
+    { table = hb_sanitize_context_t ().reference_table<gvar> (face); }
+    void fini () { table.destroy (); }
+
+    private:
+    struct x_getter { static float get (const contour_point_t &p) { return p.x; } };
+    struct y_getter { static float get (const contour_point_t &p) { return p.y; } };
+
+    template <typename T>
+    static float infer_delta (const hb_array_t<contour_point_t> points,
+                              const hb_array_t<contour_point_t> deltas,
+                              unsigned int target, unsigned int prev, unsigned int next)
+    {
+      float target_val = T::get (points[target]);
+      float prev_val = T::get (points[prev]);
+      float next_val = T::get (points[next]);
+      float prev_delta = T::get (deltas[prev]);
+      float next_delta = T::get (deltas[next]);
+
+      if (prev_val == next_val)
+        return (prev_delta == next_delta) ? prev_delta : 0.f;
+      else if (target_val <= hb_min (prev_val, next_val))
+        return (prev_val < next_val) ? prev_delta : next_delta;
+      else if (target_val >= hb_max (prev_val, next_val))
+        return (prev_val > next_val) ? prev_delta : next_delta;
+
+      /* linear interpolation */
+      float r = (target_val - prev_val) / (next_val - prev_val);
+      return (1.f - r) * prev_delta + r * next_delta;
+    }
+
+    static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
+    { return (i >= end) ? start : (i + 1); }
+
+    public:
+    bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font,
+                                 const hb_array_t<contour_point_t> points) const
+    {
+      /* num_coords should exactly match gvar's axisCount due to how GlyphVariationData tuples are aligned */
+      if (!font->num_coords || font->num_coords != table->axisCount) return true;
+
+      if (unlikely (glyph >= table->glyphCount)) return true;
+
+      hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyph);
+      if (!var_data_bytes.as<GlyphVariationData> ()->has_data ()) return true;
+      hb_vector_t<unsigned int> shared_indices;
+      GlyphVariationData::tuple_iterator_t iterator;
+      if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
+                                                   shared_indices, &iterator))
+        return true; /* so isn't applied at all */
+
+      /* Save original points for inferred delta calculation */
+      contour_point_vector_t orig_points;
+      orig_points.resize (points.length);
+      for (unsigned int i = 0; i < orig_points.length; i++)
+        orig_points[i] = points[i];
+
+      contour_point_vector_t deltas; /* flag is used to indicate referenced point */
+      deltas.resize (points.length);
+
+      hb_vector_t<unsigned> end_points;
+      for (unsigned i = 0; i < points.length; ++i)
+        if (points[i].is_end_point)
+          end_points.push (i);
+
+      int *coords = font->coords;
+      unsigned num_coords = font->num_coords;
+      hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
+      do
+      {
+        float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples);
+        if (scalar == 0.f) continue;
+        const HBUINT8 *p = iterator.get_serialized_data ();
+        unsigned int length = iterator.current_tuple->get_data_size ();
+        if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
+          return false;
+
+        hb_bytes_t bytes ((const char *) p, length);
+        hb_vector_t<unsigned int> private_indices;
+        if (iterator.current_tuple->has_private_points () &&
+            !GlyphVariationData::unpack_points (p, private_indices, bytes))
+          return false;
+        const hb_array_t<unsigned int> &indices = private_indices.length ? private_indices : shared_indices;
+
+        bool apply_to_all = (indices.length == 0);
+        unsigned int num_deltas = apply_to_all ? points.length : indices.length;
+        hb_vector_t<int> x_deltas;
+        x_deltas.resize (num_deltas);
+        if (!GlyphVariationData::unpack_deltas (p, x_deltas, bytes))
+          return false;
+        hb_vector_t<int> y_deltas;
+        y_deltas.resize (num_deltas);
+        if (!GlyphVariationData::unpack_deltas (p, y_deltas, bytes))
+          return false;
+
+        for (unsigned int i = 0; i < deltas.length; i++)
+          deltas[i].init ();
+        for (unsigned int i = 0; i < num_deltas; i++)
+        {
+          unsigned int pt_index = apply_to_all ? i : indices[i];
+          deltas[pt_index].flag = 1;    /* this point is referenced, i.e., explicit deltas specified */
+          deltas[pt_index].x += x_deltas[i] * scalar;
+          deltas[pt_index].y += y_deltas[i] * scalar;
+        }
+
+        /* infer deltas for unreferenced points */
+        unsigned start_point = 0;
+        for (unsigned c = 0; c < end_points.length; c++)
+        {
+          unsigned end_point = end_points[c];
+
+          /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
+          unsigned unref_count = 0;
+          for (unsigned i = start_point; i <= end_point; i++)
+            if (!deltas[i].flag) unref_count++;
+
+          unsigned j = start_point;
+          if (unref_count == 0 || unref_count > end_point - start_point)
+            goto no_more_gaps;
+
+          for (;;)
+          {
+            /* Locate the next gap of unreferenced points between two referenced points prev and next.
+             * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
+             */
+            unsigned int prev, next, i;
+            for (;;)
+            {
+              i = j;
+              j = next_index (i, start_point, end_point);
+              if (deltas[i].flag && !deltas[j].flag) break;
+            }
+            prev = j = i;
+            for (;;)
+            {
+              i = j;
+              j = next_index (i, start_point, end_point);
+              if (!deltas[i].flag && deltas[j].flag) break;
+            }
+            next = j;
+            /* Infer deltas for all unref points in the gap between prev and next */
+            i = prev;
+            for (;;)
+            {
+              i = next_index (i, start_point, end_point);
+              if (i == next) break;
+              deltas[i].x = infer_delta<x_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
+              deltas[i].y = infer_delta<y_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next);
+              if (--unref_count == 0) goto no_more_gaps;
+            }
+          }
+no_more_gaps:
+          start_point = end_point + 1;
+        }
+
+        /* apply specified / inferred deltas to points */
+        for (unsigned int i = 0; i < points.length; i++)
+        {
+          points[i].x += roundf (deltas[i].x);
+          points[i].y += roundf (deltas[i].y);
+        }
+      } while (iterator.move_to_next ());
+
+      return true;
+    }
+
+    unsigned int get_axis_count () const { return table->axisCount; }
+
+    private:
+    hb_blob_ptr_t<gvar> table;
+  };
+
+  protected:
+  FixedVersion<>version;        /* Version number of the glyph variations table
+                                 * Set to 0x00010000u. */
+  HBUINT16      axisCount;      /* The number of variation axes for this font. This must be
+                                 * the same number as axisCount in the 'fvar' table. */
+  HBUINT16      sharedTupleCount;
+                                /* The number of shared tuple records. Shared tuple records
+                                 * can be referenced within glyph variation data tables for
+                                 * multiple glyphs, as opposed to other tuple records stored
+                                 * directly within a glyph variation data table. */
+  LNNOffsetTo<UnsizedArrayOf<F2DOT14>>
+                sharedTuples;   /* Offset from the start of this table to the shared tuple records.
+                                 * Array of tuple records shared across all glyph variation data tables. */
+  HBUINT16      glyphCount;     /* The number of glyphs in this font. This must match the number of
+                                 * glyphs stored elsewhere in the font. */
+  HBUINT16      flags;          /* Bit-field that gives the format of the offset array that follows.
+                                 * If bit 0 is clear, the offsets are uint16; if bit 0 is set, the
+                                 * offsets are uint32. */
+  LOffsetTo<GlyphVariationData>
+                dataZ;          /* Offset from the start of this table to the array of
+                                 * GlyphVariationData tables. */
+  UnsizedArrayOf<HBUINT8>
+                offsetZ;        /* Offsets from the start of the GlyphVariationData array
+                                 * to each GlyphVariationData table. */
+  public:
+  DEFINE_SIZE_MIN (20);
+};
+
+struct gvar_accelerator_t : gvar::accelerator_t {};
+
+} /* namespace OT */
+
+#endif /* HB_OT_VAR_GVAR_TABLE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh
index 4d030f3..d024147 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh
@@ -44,6 +44,38 @@
                                   get_width ()));
   }
 
+  template <typename T>
+  bool serialize (hb_serialize_context_t *c, const T &plan)
+  {
+    unsigned int width = plan.get_width ();
+    unsigned int inner_bit_count = plan.get_inner_bit_count ();
+    const hb_array_t<const unsigned int> output_map = plan.get_output_map ();
+
+    TRACE_SERIALIZE (this);
+    if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0))))
+      return_trace (false);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+
+    format = ((width-1)<<4)|(inner_bit_count-1);
+    mapCount = output_map.length;
+    HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length);
+    if (unlikely (!p)) return_trace (false);
+    for (unsigned int i = 0; i < output_map.length; i++)
+    {
+      unsigned int v = output_map[i];
+      unsigned int outer = v >> 16;
+      unsigned int inner = v & 0xFFFF;
+      unsigned int u = (outer << inner_bit_count) | inner;
+      for (unsigned int w = width; w > 0;)
+      {
+        p[--w] = u;
+        u >>= 8;
+      }
+      p += width;
+    }
+    return_trace (true);
+  }
+
   unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */
   {
     /* If count is zero, pass value unchanged.  This takes
@@ -63,7 +95,7 @@
     }
 
     { /* Repack it. */
-      unsigned int n = get_inner_bitcount ();
+      unsigned int n = get_inner_bit_count ();
       unsigned int outer = u >> n;
       unsigned int inner = u & ((1 << n) - 1);
       u = (outer<<16) | inner;
@@ -72,10 +104,9 @@
     return u;
   }
 
-  protected:
-  unsigned int get_width () const          { return ((format >> 4) & 3) + 1; }
-
-  unsigned int get_inner_bitcount () const { return (format & 0xF) + 1; }
+  unsigned int get_map_count () const       { return mapCount; }
+  unsigned int get_width () const           { return ((format >> 4) & 3) + 1; }
+  unsigned int get_inner_bit_count () const { return (format & 0xF) + 1; }
 
   protected:
   HBUINT16      format;         /* A packed field that describes the compressed
@@ -88,6 +119,215 @@
   DEFINE_SIZE_ARRAY (4, mapDataZ);
 };
 
+struct index_map_subset_plan_t
+{
+  enum index_map_index_t {
+    ADV_INDEX,
+    LSB_INDEX,  /* dual as TSB */
+    RSB_INDEX,  /* dual as BSB */
+    VORG_INDEX
+  };
+
+  void init (const DeltaSetIndexMap  &index_map,
+             hb_inc_bimap_t          &outer_map,
+             hb_vector_t<hb_set_t *> &inner_sets,
+             const hb_subset_plan_t  *plan)
+  {
+    map_count = 0;
+    outer_bit_count = 0;
+    inner_bit_count = 1;
+    max_inners.init ();
+    output_map.init ();
+
+    if (&index_map == &Null (DeltaSetIndexMap)) return;
+
+    unsigned int        last_val = (unsigned int)-1;
+    hb_codepoint_t      last_gid = (hb_codepoint_t)-1;
+    hb_codepoint_t      gid = (hb_codepoint_t) hb_min (index_map.get_map_count (), plan->num_output_glyphs ());
+
+    outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count ();
+    max_inners.resize (inner_sets.length);
+    for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0;
+
+    /* Search backwards for a map value different from the last map value */
+    for (; gid > 0; gid--)
+    {
+      hb_codepoint_t    old_gid;
+      if (!plan->old_gid_for_new_gid (gid - 1, &old_gid))
+      {
+        if (last_gid == (hb_codepoint_t) -1)
+          continue;
+        else
+          break;
+      }
+
+      unsigned int v = index_map.map (old_gid);
+      if (last_gid == (hb_codepoint_t) -1)
+      {
+        last_val = v;
+        last_gid = gid;
+        continue;
+      }
+      if (v != last_val) break;
+
+      last_gid = gid;
+    }
+
+    if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
+    map_count = last_gid;
+    for (gid = 0; gid < map_count; gid++)
+    {
+      hb_codepoint_t    old_gid;
+      if (plan->old_gid_for_new_gid (gid, &old_gid))
+      {
+        unsigned int v = index_map.map (old_gid);
+        unsigned int outer = v >> 16;
+        unsigned int inner = v & 0xFFFF;
+        outer_map.add (outer);
+        if (inner > max_inners[outer]) max_inners[outer] = inner;
+        if (outer >= inner_sets.length) return;
+        inner_sets[outer]->add (inner);
+      }
+    }
+  }
+
+  void fini ()
+  {
+    max_inners.fini ();
+    output_map.fini ();
+  }
+
+  void remap (const DeltaSetIndexMap *input_map,
+              const hb_inc_bimap_t &outer_map,
+              const hb_vector_t<hb_inc_bimap_t> &inner_maps,
+              const hb_subset_plan_t *plan)
+  {
+    if (input_map == &Null (DeltaSetIndexMap)) return;
+
+    for (unsigned int i = 0; i < max_inners.length; i++)
+    {
+      if (inner_maps[i].get_population () == 0) continue;
+      unsigned int bit_count = (max_inners[i]==0)? 1: hb_bit_storage (inner_maps[i][max_inners[i]]);
+      if (bit_count > inner_bit_count) inner_bit_count = bit_count;
+    }
+
+    output_map.resize (map_count);
+    for (hb_codepoint_t gid = 0; gid < output_map.length; gid++)
+    {
+      hb_codepoint_t    old_gid;
+      if (plan->old_gid_for_new_gid (gid, &old_gid))
+      {
+        unsigned int v = input_map->map (old_gid);
+        unsigned int outer = v >> 16;
+        output_map[gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]);
+      }
+      else
+        output_map[gid] = 0;    /* Map unused glyph to outer/inner=0/0 */
+    }
+  }
+
+  unsigned int get_inner_bit_count () const { return inner_bit_count; }
+  unsigned int get_width ()           const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
+  unsigned int get_map_count ()       const { return map_count; }
+
+  unsigned int get_size () const
+  { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); }
+
+  bool is_identity () const { return get_output_map ().length == 0; }
+  hb_array_t<const unsigned int> get_output_map () const { return output_map.as_array (); }
+
+  protected:
+  unsigned int map_count;
+  hb_vector_t<unsigned int> max_inners;
+  unsigned int outer_bit_count;
+  unsigned int inner_bit_count;
+  hb_vector_t<unsigned int> output_map;
+};
+
+struct hvarvvar_subset_plan_t
+{
+  hvarvvar_subset_plan_t() : inner_maps (), index_map_plans () {}
+  ~hvarvvar_subset_plan_t() { fini (); }
+
+  void init (const hb_array_t<const DeltaSetIndexMap *> &index_maps,
+             const VariationStore &_var_store,
+             const hb_subset_plan_t *plan)
+  {
+    index_map_plans.resize (index_maps.length);
+
+    var_store = &_var_store;
+    inner_sets.resize (var_store->get_sub_table_count ());
+    for (unsigned int i = 0; i < inner_sets.length; i++)
+      inner_sets[i] = hb_set_create ();
+    adv_set = hb_set_create ();
+
+    inner_maps.resize (var_store->get_sub_table_count ());
+
+    for (unsigned int i = 0; i < inner_maps.length; i++)
+      inner_maps[i].init ();
+
+    if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return;
+
+    bool retain_adv_map = false;
+    index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan);
+    if (index_maps[0] == &Null (DeltaSetIndexMap))
+    {
+      retain_adv_map = plan->retain_gids;
+      outer_map.add (0);
+      for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
+      {
+        hb_codepoint_t old_gid;
+        if (plan->old_gid_for_new_gid (gid, &old_gid))
+          inner_sets[0]->add (old_gid);
+      }
+      hb_set_union (adv_set, inner_sets[0]);
+    }
+
+    for (unsigned int i = 1; i < index_maps.length; i++)
+      index_map_plans[i].init (*index_maps[i], outer_map, inner_sets, plan);
+
+    outer_map.sort ();
+
+    if (retain_adv_map)
+    {
+      for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
+        if (inner_sets[0]->has (gid))
+          inner_maps[0].add (gid);
+        else
+          inner_maps[0].skip ();
+    }
+    else
+    {
+      inner_maps[0].add_set (adv_set);
+      hb_set_subtract (inner_sets[0], adv_set);
+      inner_maps[0].add_set (inner_sets[0]);
+    }
+
+    for (unsigned int i = 1; i < inner_maps.length; i++)
+      inner_maps[i].add_set (inner_sets[i]);
+
+    for (unsigned int i = 0; i < index_maps.length; i++)
+      index_map_plans[i].remap (index_maps[i], outer_map, inner_maps, plan);
+  }
+
+  void fini ()
+  {
+    for (unsigned int i = 0; i < inner_sets.length; i++)
+      hb_set_destroy (inner_sets[i]);
+    hb_set_destroy (adv_set);
+    inner_maps.fini_deep ();
+    index_map_plans.fini_deep ();
+  }
+
+  hb_inc_bimap_t outer_map;
+  hb_vector_t<hb_inc_bimap_t> inner_maps;
+  hb_vector_t<index_map_subset_plan_t> index_map_plans;
+  const VariationStore *var_store;
+
+  protected:
+  hb_vector_t<hb_set_t *> inner_sets;
+  hb_set_t *adv_set;
+};
 
 /*
  * HVAR -- Horizontal Metrics Variations
@@ -114,14 +354,73 @@
                   rsbMap.sanitize (c, this));
   }
 
-  float get_advance_var (hb_codepoint_t glyph,
-                         const int *coords, unsigned int coord_count) const
+  void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
+  {
+    index_maps.push (&(this+advMap));
+    index_maps.push (&(this+lsbMap));
+    index_maps.push (&(this+rsbMap));
+  }
+
+  bool serialize_index_maps (hb_serialize_context_t *c,
+                             const hb_array_t<index_map_subset_plan_t> &im_plans)
+  {
+    TRACE_SERIALIZE (this);
+    if (im_plans[index_map_subset_plan_t::ADV_INDEX].is_identity ())
+      advMap = 0;
+    else if (unlikely (!advMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::ADV_INDEX])))
+      return_trace (false);
+    if (im_plans[index_map_subset_plan_t::LSB_INDEX].is_identity ())
+      lsbMap = 0;
+    else if (unlikely (!lsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::LSB_INDEX])))
+      return_trace (false);
+    if (im_plans[index_map_subset_plan_t::RSB_INDEX].is_identity ())
+      rsbMap = 0;
+    else if (unlikely (!rsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::RSB_INDEX])))
+      return_trace (false);
+
+    return_trace (true);
+  }
+
+  template <typename T>
+  bool _subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    hvarvvar_subset_plan_t      hvar_plan;
+    hb_vector_t<const DeltaSetIndexMap *>
+                                index_maps;
+
+    ((T*)this)->listup_index_maps (index_maps);
+    hvar_plan.init (index_maps.as_array (), this+varStore, c->plan);
+
+    T *out = c->serializer->allocate_min<T> ();
+    if (unlikely (!out)) return_trace (false);
+
+    out->version.major = 1;
+    out->version.minor = 0;
+
+    if (unlikely (!out->varStore.serialize (c->serializer, out)
+                     .serialize (c->serializer, hvar_plan.var_store, hvar_plan.inner_maps.as_array ())))
+      return_trace (false);
+
+    return_trace (out->T::serialize_index_maps (c->serializer,
+                                                hvar_plan.index_map_plans.as_array ()));
+  }
+
+  float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const
   {
     unsigned int varidx = (this+advMap).map (glyph);
+    return (this+varStore).get_delta (varidx, font->coords, font->num_coords);
+  }
+
+  float get_side_bearing_var (hb_codepoint_t glyph,
+                              const int *coords, unsigned int coord_count) const
+  {
+    if (!has_side_bearing_deltas ()) return 0.f;
+    unsigned int varidx = (this+lsbMap).map (glyph);
     return (this+varStore).get_delta (varidx, coords, coord_count);
   }
 
-  bool has_sidebearing_deltas () const { return lsbMap && rsbMap; }
+  bool has_side_bearing_deltas () const { return lsbMap && rsbMap; }
 
   protected:
   FixedVersion<>version;        /* Version of the metrics variation table
@@ -141,6 +440,7 @@
 
 struct HVAR : HVARVVAR {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR;
+  bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<HVAR> (c); }
 };
 struct VVAR : HVARVVAR {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR;
@@ -152,6 +452,28 @@
                   vorgMap.sanitize (c, this));
   }
 
+  void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
+  {
+    HVARVVAR::listup_index_maps (index_maps);
+    index_maps.push (&(this+vorgMap));
+  }
+
+  bool serialize_index_maps (hb_serialize_context_t *c,
+                             const hb_array_t<index_map_subset_plan_t> &im_plans)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!HVARVVAR::serialize_index_maps (c, im_plans)))
+      return_trace (false);
+    if (!im_plans[index_map_subset_plan_t::VORG_INDEX].get_map_count ())
+      vorgMap = 0;
+    else if (unlikely (!vorgMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::VORG_INDEX])))
+      return_trace (false);
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<VVAR> (c); }
+
   protected:
   LOffsetTo<DeltaSetIndexMap>
                 vorgMap;        /* Offset to vertical-origin var-idx mapping. */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-mvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-mvar-table.hh
index 374ce66..37a47ff 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-mvar-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-mvar-table.hh
@@ -77,9 +77,11 @@
                  const int *coords, unsigned int coord_count) const
   {
     const VariationValueRecord *record;
-    record = (VariationValueRecord *) bsearch (&tag, valuesZ.arrayZ,
-                                               valueRecordCount, valueRecordSize,
-                                               tag_compare);
+    record = (VariationValueRecord *) hb_bsearch (tag,
+                                                  (const VariationValueRecord *)
+                                                    (const HBUINT8 *) valuesZ,
+                                                  valueRecordCount, valueRecordSize,
+                                                  tag_compare);
     if (!record)
       return 0.;
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc
index ed36012..1c12d56 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc
@@ -24,13 +24,15 @@
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-open-type.hh"
+#include "hb.hh"
 
-#include "hb-ot-face.hh"
+#ifndef HB_NO_VAR
+
+#include "hb-ot-var.h"
+
 #include "hb-ot-var-avar-table.hh"
 #include "hb-ot-var-fvar-table.hh"
 #include "hb-ot-var-mvar-table.hh"
-#include "hb-ot-var.h"
 
 
 /**
@@ -75,6 +77,7 @@
   return face->table.fvar->get_axis_count ();
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_ot_var_get_axes:
  *
@@ -104,6 +107,7 @@
 {
   return face->table.fvar->find_axis_deprecated (axis_tag, axis_index, axis_info);
 }
+#endif
 
 /**
  * hb_ot_var_get_axis_infos:
@@ -211,3 +215,6 @@
 
   face->table.avar->map_coords (normalized_coords, coords_length);
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.h
index 5b02824..92494c2 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.h
@@ -68,7 +68,7 @@
 typedef enum { /*< flags >*/
   HB_OT_VAR_AXIS_FLAG_HIDDEN    = 0x00000001u,
 
-  _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= 0x7FFFFFFFu /*< skip >*/
+  _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/
 } hb_ot_var_axis_flags_t;
 
 /**
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh
index c2dc77b..4dd8dfd 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh
@@ -48,7 +48,7 @@
   }
 
   public:
-  GlyphID       glyph;
+  HBGlyphID     glyph;
   FWORD         vertOriginY;
 
   public:
@@ -69,94 +69,48 @@
     return vertYOrigins[i].vertOriginY;
   }
 
-  bool _subset (const hb_subset_plan_t *plan HB_UNUSED,
-                const VORG *vorg_table,
-                const hb_vector_t<VertOriginMetric> &subset_metrics,
-                unsigned int dest_sz,
-                void *dest) const
+  template <typename Iterator,
+            hb_requires (hb_is_iterator (Iterator))>
+  void serialize (hb_serialize_context_t *c,
+                  Iterator it,
+                  FWORD defaultVertOriginY)
   {
-    hb_serialize_context_t c (dest, dest_sz);
 
-    VORG *subset_table = c.start_serialize<VORG> ();
-    if (unlikely (!c.extend_min (*subset_table)))
-      return false;
+    if (unlikely (!c->extend_min ((*this))))  return;
 
-    subset_table->version.major.set (1);
-    subset_table->version.minor.set (0);
+    this->version.major = 1;
+    this->version.minor = 0;
 
-    subset_table->defaultVertOriginY.set (vorg_table->defaultVertOriginY);
-    subset_table->vertYOrigins.len.set (subset_metrics.length);
+    this->defaultVertOriginY = defaultVertOriginY;
+    this->vertYOrigins.len = it.len ();
 
-    bool success = true;
-    if (subset_metrics.length > 0)
-    {
-      unsigned int  size = VertOriginMetric::static_size * subset_metrics.length;
-      VertOriginMetric  *metrics = c.allocate_size<VertOriginMetric> (size);
-      if (likely (metrics != nullptr))
-        memcpy (metrics, &subset_metrics[0], size);
-      else
-        success = false;
-    }
-    c.end_serialize ();
-
-    return success;
+    c->copy_all (it);
   }
 
-  bool subset (hb_subset_plan_t *plan) const
+  bool subset (hb_subset_context_t *c) const
   {
-    hb_blob_t *vorg_blob = hb_sanitize_context_t().reference_table<VORG> (plan->source);
-    const VORG *vorg_table = vorg_blob->as<VORG> ();
+    TRACE_SUBSET (this);
+    VORG *vorg_prime = c->serializer->start_embed<VORG> ();
+    if (unlikely (!c->serializer->check_success (vorg_prime))) return_trace (false);
 
-    /* count the number of glyphs to be included in the subset table */
-    hb_vector_t<VertOriginMetric> subset_metrics;
-    subset_metrics.init ();
-    unsigned int glyph = 0;
-    unsigned int i = 0;
-    while ((glyph < plan->glyphs.length) && (i < vertYOrigins.len))
-    {
-      if (plan->glyphs[glyph] > vertYOrigins[i].glyph)
-        i++;
-      else if (plan->glyphs[glyph] < vertYOrigins[i].glyph)
-        glyph++;
-      else
-      {
-        VertOriginMetric *metrics = subset_metrics.push ();
-        metrics->glyph.set (glyph);
-        metrics->vertOriginY.set (vertYOrigins[i].vertOriginY);
-        glyph++;
-        i++;
-      }
-    }
+    auto it =
+    + vertYOrigins.as_array ()
+    | hb_filter (c->plan->glyphset (), &VertOriginMetric::glyph)
+    | hb_map ([&] (const VertOriginMetric& _)
+              {
+                hb_codepoint_t new_glyph = HB_SET_VALUE_INVALID;
+                c->plan->new_gid_for_old_gid (_.glyph, &new_glyph);
 
-    /* alloc the new table */
-    unsigned int dest_sz = VORG::min_size + VertOriginMetric::static_size * subset_metrics.length;
-    void *dest = (void *) malloc (dest_sz);
-    if (unlikely (!dest))
-    {
-      subset_metrics.fini ();
-      hb_blob_destroy (vorg_blob);
-      return false;
-    }
+                VertOriginMetric metric;
+                metric.glyph = new_glyph;
+                metric.vertOriginY = _.vertOriginY;
+                return metric;
+              })
+    ;
 
     /* serialize the new table */
-    if (!_subset (plan, vorg_table, subset_metrics, dest_sz, dest))
-    {
-      subset_metrics.fini ();
-      free (dest);
-      hb_blob_destroy (vorg_blob);
-      return false;
-    }
-
-    hb_blob_t *result = hb_blob_create ((const char *)dest,
-                                        dest_sz,
-                                        HB_MEMORY_MODE_READONLY,
-                                        dest,
-                                        free);
-    bool success = plan->add_table (HB_OT_TAG_VORG, result);
-    hb_blob_destroy (result);
-    subset_metrics.fini ();
-    hb_blob_destroy (vorg_blob);
-    return success;
+    vorg_prime->serialize (c->serializer, it, defaultVertOriginY);
+    return_trace (true);
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -168,10 +122,11 @@
   }
 
   protected:
-  FixedVersion<>        version;                /* Version of VORG table. Set to 0x00010000u. */
-  FWORD                 defaultVertOriginY;     /* The default vertical origin. */
+  FixedVersion<>version;        /* Version of VORG table. Set to 0x00010000u. */
+  FWORD         defaultVertOriginY;
+                                /* The default vertical origin. */
   SortedArrayOf<VertOriginMetric>
-                        vertYOrigins;           /* The array of vertical origins. */
+                vertYOrigins;   /* The array of vertical origins. */
 
   public:
   DEFINE_SIZE_ARRAY(8, vertYOrigins);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot.h b/src/java.desktop/share/native/libharfbuzz/hb-ot.h
index db78469..f2dbaa1 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-ot.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ot.h
@@ -35,6 +35,8 @@
 #include "hb-ot-font.h"
 #include "hb-ot-layout.h"
 #include "hb-ot-math.h"
+#include "hb-ot-meta.h"
+#include "hb-ot-metrics.h"
 #include "hb-ot-name.h"
 #include "hb-ot-shape.h"
 #include "hb-ot-var.h"
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-pool.hh b/src/java.desktop/share/native/libharfbuzz/hb-pool.hh
new file mode 100644
index 0000000..a2266a3
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-pool.hh
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_POOL_HH
+#define HB_POOL_HH
+
+#include "hb.hh"
+
+/* Memory pool for persistent allocation of small objects. */
+
+template <typename T, unsigned ChunkLen = 16>
+struct hb_pool_t
+{
+  hb_pool_t () : next (nullptr) {}
+  ~hb_pool_t () { fini (); }
+
+  void fini ()
+  {
+    next = nullptr;
+
+    for (chunk_t *_ : chunks) ::free (_);
+
+    chunks.fini ();
+  }
+
+  T* alloc ()
+  {
+    if (unlikely (!next))
+    {
+      if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
+      chunk_t *chunk = (chunk_t *) calloc (1, sizeof (chunk_t));
+      if (unlikely (!chunk)) return nullptr;
+      chunks.push (chunk);
+      next = chunk->thread ();
+    }
+
+    T* obj = next;
+    next = * ((T**) next);
+
+    memset (obj, 0, sizeof (T));
+
+    return obj;
+  }
+
+  void free (T* obj)
+  {
+    * (T**) obj = next;
+    next = obj;
+  }
+
+  private:
+
+  static_assert (ChunkLen > 1, "");
+  static_assert (sizeof (T) >= sizeof (void *), "");
+  static_assert (alignof (T) % alignof (void *) == 0, "");
+
+  struct chunk_t
+  {
+    T* thread ()
+    {
+      for (unsigned i = 0; i < ARRAY_LENGTH (arrayZ) - 1; i++)
+        * (T**) &arrayZ[i] = &arrayZ[i + 1];
+
+      * (T**) &arrayZ[ARRAY_LENGTH (arrayZ) - 1] = nullptr;
+
+      return arrayZ;
+    }
+
+    T arrayZ[ChunkLen];
+  };
+
+  T* next;
+  hb_vector_t<chunk_t *> chunks;
+};
+
+
+#endif /* HB_POOL_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh b/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh
new file mode 100644
index 0000000..0e293e9
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh
@@ -0,0 +1,412 @@
+/*
+ * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright © 2012,2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SANITIZE_HH
+#define HB_SANITIZE_HH
+
+#include "hb.hh"
+#include "hb-blob.hh"
+#include "hb-dispatch.hh"
+
+
+/*
+ * Sanitize
+ *
+ *
+ * === Introduction ===
+ *
+ * The sanitize machinery is at the core of our zero-cost font loading.  We
+ * mmap() font file into memory and create a blob out of it.  Font subtables
+ * are returned as a readonly sub-blob of the main font blob.  These table
+ * blobs are then sanitized before use, to ensure invalid memory access does
+ * not happen.  The toplevel sanitize API use is like, eg. to load the 'head'
+ * table:
+ *
+ *   hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face);
+ *
+ * The blob then can be converted to a head table struct with:
+ *
+ *   const head *head_table = head_blob->as<head> ();
+ *
+ * What the reference_table does is, to call hb_face_reference_table() to load
+ * the table blob, sanitize it and return either the sanitized blob, or empty
+ * blob if sanitization failed.  The blob->as() function returns the null
+ * object of its template type argument if the blob is empty.  Otherwise, it
+ * just casts the blob contents to the desired type.
+ *
+ * Sanitizing a blob of data with a type T works as follows (with minor
+ * simplification):
+ *
+ *   - Cast blob content to T*, call sanitize() method of it,
+ *   - If sanitize succeeded, return blob.
+ *   - Otherwise, if blob is not writable, try making it writable,
+ *     or copy if cannot be made writable in-place,
+ *   - Call sanitize() again.  Return blob if sanitize succeeded.
+ *   - Return empty blob otherwise.
+ *
+ *
+ * === The sanitize() contract ===
+ *
+ * The sanitize() method of each object type shall return true if it's safe to
+ * call other methods of the object, and false otherwise.
+ *
+ * Note that what sanitize() checks for might align with what the specification
+ * describes as valid table data, but does not have to be.  In particular, we
+ * do NOT want to be pedantic and concern ourselves with validity checks that
+ * are irrelevant to our use of the table.  On the contrary, we want to be
+ * lenient with error handling and accept invalid data to the extent that it
+ * does not impose extra burden on us.
+ *
+ * Based on the sanitize contract, one can see that what we check for depends
+ * on how we use the data in other table methods.  Ie. if other table methods
+ * assume that offsets do NOT point out of the table data block, then that's
+ * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way).  On
+ * the other hand, if other methods do such checks themselves, then sanitize()
+ * does not have to bother with them (glyf/local work this way).  The choice
+ * depends on the table structure and sanitize() performance.  For example, to
+ * check glyf/loca offsets in sanitize() would cost O(num-glyphs).  We try hard
+ * to avoid such costs during font loading.  By postponing such checks to the
+ * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime
+ * cost to O(used-glyphs).  As such, this is preferred.
+ *
+ * The same argument can be made re GSUB/GPOS/GDEF, but there, the table
+ * structure is so complicated that by checking all offsets at sanitize() time,
+ * we make the code much simpler in other methods, as offsets and referenced
+ * objects do not need to be validated at each use site.
+ */
+
+/* This limits sanitizing time on really broken fonts. */
+#ifndef HB_SANITIZE_MAX_EDITS
+#define HB_SANITIZE_MAX_EDITS 32
+#endif
+#ifndef HB_SANITIZE_MAX_OPS_FACTOR
+#define HB_SANITIZE_MAX_OPS_FACTOR 8
+#endif
+#ifndef HB_SANITIZE_MAX_OPS_MIN
+#define HB_SANITIZE_MAX_OPS_MIN 16384
+#endif
+#ifndef HB_SANITIZE_MAX_OPS_MAX
+#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF
+#endif
+#ifndef HB_SANITIZE_MAX_SUTABLES
+#define HB_SANITIZE_MAX_SUTABLES 0x4000
+#endif
+
+struct hb_sanitize_context_t :
+       hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
+{
+  hb_sanitize_context_t () :
+        start (nullptr), end (nullptr),
+        max_ops (0), max_subtables (0),
+        writable (false), edit_count (0),
+        blob (nullptr),
+        num_glyphs (65536),
+        num_glyphs_set (false) {}
+
+  const char *get_name () { return "SANITIZE"; }
+  template <typename T, typename F>
+  bool may_dispatch (const T *obj HB_UNUSED, const F *format)
+  { return format->sanitize (this); }
+  static return_t default_return_value () { return true; }
+  static return_t no_dispatch_return_value () { return false; }
+  bool stop_sublookup_iteration (const return_t r) const { return !r; }
+
+  bool visit_subtables (unsigned count)
+  {
+    max_subtables += count;
+    return max_subtables < HB_SANITIZE_MAX_SUTABLES;
+  }
+
+  private:
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.sanitize (this, hb_forward<Ts> (ds)...) )
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.dispatch (this, hb_forward<Ts> (ds)...) )
+  public:
+  template <typename T, typename ...Ts> auto
+  dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
+  ( _dispatch (obj, hb_prioritize, hb_forward<Ts> (ds)...) )
+
+
+  void init (hb_blob_t *b)
+  {
+    this->blob = hb_blob_reference (b);
+    this->writable = false;
+  }
+
+  void set_num_glyphs (unsigned int num_glyphs_)
+  {
+    num_glyphs = num_glyphs_;
+    num_glyphs_set = true;
+  }
+  unsigned int get_num_glyphs () { return num_glyphs; }
+
+  void set_max_ops (int max_ops_) { max_ops = max_ops_; }
+
+  template <typename T>
+  void set_object (const T *obj)
+  {
+    reset_object ();
+
+    if (!obj) return;
+
+    const char *obj_start = (const char *) obj;
+    if (unlikely (obj_start < this->start || this->end <= obj_start))
+      this->start = this->end = nullptr;
+    else
+    {
+      this->start = obj_start;
+      this->end   = obj_start + hb_min (size_t (this->end - obj_start), obj->get_size ());
+    }
+  }
+
+  void reset_object ()
+  {
+    this->start = this->blob->data;
+    this->end = this->start + this->blob->length;
+    assert (this->start <= this->end); /* Must not overflow. */
+  }
+
+  void start_processing ()
+  {
+    reset_object ();
+    if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR)))
+      this->max_ops = HB_SANITIZE_MAX_OPS_MAX;
+    else
+      this->max_ops = hb_clamp ((unsigned) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
+                                (unsigned) HB_SANITIZE_MAX_OPS_MIN,
+                                (unsigned) HB_SANITIZE_MAX_OPS_MAX);
+    this->edit_count = 0;
+    this->debug_depth = 0;
+
+    DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
+                     "start [%p..%p] (%lu bytes)",
+                     this->start, this->end,
+                     (unsigned long) (this->end - this->start));
+  }
+
+  void end_processing ()
+  {
+    DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
+                     "end [%p..%p] %u edit requests",
+                     this->start, this->end, this->edit_count);
+
+    hb_blob_destroy (this->blob);
+    this->blob = nullptr;
+    this->start = this->end = nullptr;
+  }
+
+  unsigned get_edit_count () { return edit_count; }
+
+  bool check_range (const void *base,
+                    unsigned int len) const
+  {
+    const char *p = (const char *) base;
+    bool ok = !len ||
+              (this->start <= p &&
+               p <= this->end &&
+               (unsigned int) (this->end - p) >= len &&
+               this->max_ops-- > 0);
+
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+                     "check_range [%p..%p]"
+                     " (%d bytes) in [%p..%p] -> %s",
+                     p, p + len, len,
+                     this->start, this->end,
+                     ok ? "OK" : "OUT-OF-RANGE");
+
+    return likely (ok);
+  }
+
+  template <typename T>
+  bool check_range (const T *base,
+                    unsigned int a,
+                    unsigned int b) const
+  {
+    return !hb_unsigned_mul_overflows (a, b) &&
+           this->check_range (base, a * b);
+  }
+
+  template <typename T>
+  bool check_range (const T *base,
+                    unsigned int a,
+                    unsigned int b,
+                    unsigned int c) const
+  {
+    return !hb_unsigned_mul_overflows (a, b) &&
+           this->check_range (base, a * b, c);
+  }
+
+  template <typename T>
+  bool check_array (const T *base, unsigned int len) const
+  {
+    return this->check_range (base, len, hb_static_size (T));
+  }
+
+  template <typename T>
+  bool check_array (const T *base,
+                    unsigned int a,
+                    unsigned int b) const
+  {
+    return this->check_range (base, a, b, hb_static_size (T));
+  }
+
+  template <typename Type>
+  bool check_struct (const Type *obj) const
+  { return likely (this->check_range (obj, obj->min_size)); }
+
+  bool may_edit (const void *base, unsigned int len)
+  {
+    if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
+      return false;
+
+    const char *p = (const char *) base;
+    this->edit_count++;
+
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
+       this->edit_count,
+       p, p + len, len,
+       this->start, this->end,
+       this->writable ? "GRANTED" : "DENIED");
+
+    return this->writable;
+  }
+
+  template <typename Type, typename ValueType>
+  bool try_set (const Type *obj, const ValueType &v)
+  {
+    if (this->may_edit (obj, hb_static_size (Type)))
+    {
+      * const_cast<Type *> (obj) = v;
+      return true;
+    }
+    return false;
+  }
+
+  template <typename Type>
+  hb_blob_t *sanitize_blob (hb_blob_t *blob)
+  {
+    bool sane;
+
+    init (blob);
+
+  retry:
+    DEBUG_MSG_FUNC (SANITIZE, start, "start");
+
+    start_processing ();
+
+    if (unlikely (!start))
+    {
+      end_processing ();
+      return blob;
+    }
+
+    Type *t = reinterpret_cast<Type *> (const_cast<char *> (start));
+
+    sane = t->sanitize (this);
+    if (sane)
+    {
+      if (edit_count)
+      {
+        DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count);
+
+        /* sanitize again to ensure no toe-stepping */
+        edit_count = 0;
+        sane = t->sanitize (this);
+        if (edit_count) {
+          DEBUG_MSG_FUNC (SANITIZE, start, "requested %d edits in second round; FAILLING", edit_count);
+          sane = false;
+        }
+      }
+    }
+    else
+    {
+      if (edit_count && !writable) {
+        start = hb_blob_get_data_writable (blob, nullptr);
+        end = start + blob->length;
+
+        if (start)
+        {
+          writable = true;
+          /* ok, we made it writable by relocating.  try again */
+          DEBUG_MSG_FUNC (SANITIZE, start, "retry");
+          goto retry;
+        }
+      }
+    }
+
+    end_processing ();
+
+    DEBUG_MSG_FUNC (SANITIZE, start, sane ? "PASSED" : "FAILED");
+    if (sane)
+    {
+      hb_blob_make_immutable (blob);
+      return blob;
+    }
+    else
+    {
+      hb_blob_destroy (blob);
+      return hb_blob_get_empty ();
+    }
+  }
+
+  template <typename Type>
+  hb_blob_t *reference_table (const hb_face_t *face, hb_tag_t tableTag = Type::tableTag)
+  {
+    if (!num_glyphs_set)
+      set_num_glyphs (hb_face_get_glyph_count (face));
+    return sanitize_blob<Type> (hb_face_reference_table (face, tableTag));
+  }
+
+  const char *start, *end;
+  mutable int max_ops, max_subtables;
+  private:
+  bool writable;
+  unsigned int edit_count;
+  hb_blob_t *blob;
+  unsigned int num_glyphs;
+  bool  num_glyphs_set;
+};
+
+struct hb_sanitize_with_object_t
+{
+  template <typename T>
+  hb_sanitize_with_object_t (hb_sanitize_context_t *c, const T& obj) : c (c)
+  { c->set_object (obj); }
+  ~hb_sanitize_with_object_t ()
+  { c->reset_object (); }
+
+  private:
+  hb_sanitize_context_t *c;
+};
+
+
+#endif /* HB_SANITIZE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh
new file mode 100644
index 0000000..e0ceae2
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh
@@ -0,0 +1,553 @@
+/*
+ * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright © 2012,2018  Google, Inc.
+ * Copyright © 2019  Facebook, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ * Facebook Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SERIALIZE_HH
+#define HB_SERIALIZE_HH
+
+#include "hb.hh"
+#include "hb-blob.hh"
+#include "hb-map.hh"
+#include "hb-pool.hh"
+
+
+/*
+ * Serialize
+ */
+
+struct hb_serialize_context_t
+{
+  typedef unsigned objidx_t;
+
+  enum whence_t {
+     Head,      /* Relative to the current object head (default). */
+     Tail,      /* Relative to the current object tail after packed. */
+     Absolute   /* Absolute: from the start of the serialize buffer. */
+   };
+
+  struct object_t
+  {
+    void fini () { links.fini (); }
+
+    bool operator == (const object_t &o) const
+    {
+      return (tail - head == o.tail - o.head)
+          && (links.length == o.links.length)
+          && 0 == hb_memcmp (head, o.head, tail - head)
+          && links.as_bytes () == o.links.as_bytes ();
+    }
+    uint32_t hash () const
+    {
+      return hb_bytes_t (head, tail - head).hash () ^
+             links.as_bytes ().hash ();
+    }
+
+    struct link_t
+    {
+      bool is_wide: 1;
+      bool is_signed: 1;
+      unsigned whence: 2;
+      unsigned position: 28;
+      unsigned bias;
+      objidx_t objidx;
+    };
+
+    char *head;
+    char *tail;
+    hb_vector_t<link_t> links;
+    object_t *next;
+  };
+
+  struct snapshot_t
+  {
+    char *head;
+    char *tail;
+    object_t *current; // Just for sanity check
+    unsigned num_links;
+  };
+
+  snapshot_t snapshot ()
+  { return snapshot_t { head, tail, current, current->links.length }; }
+
+  hb_serialize_context_t (void *start_, unsigned int size) :
+    start ((char *) start_),
+    end (start + size),
+    current (nullptr)
+  { reset (); }
+  ~hb_serialize_context_t () { fini (); }
+
+  void fini ()
+  {
+    for (object_t *_ : ++hb_iter (packed)) _->fini ();
+    packed.fini ();
+    this->packed_map.fini ();
+
+    while (current)
+    {
+      auto *_ = current;
+      current = current->next;
+      _->fini ();
+    }
+    object_pool.fini ();
+  }
+
+  bool in_error () const { return !this->successful; }
+
+  void reset ()
+  {
+    this->successful = true;
+    this->ran_out_of_room = false;
+    this->head = this->start;
+    this->tail = this->end;
+    this->debug_depth = 0;
+
+    fini ();
+    this->packed.push (nullptr);
+  }
+
+  bool check_success (bool success)
+  { return this->successful && (success || (err_other_error (), false)); }
+
+  template <typename T1, typename T2>
+  bool check_equal (T1 &&v1, T2 &&v2)
+  { return check_success ((long long) v1 == (long long) v2); }
+
+  template <typename T1, typename T2>
+  bool check_assign (T1 &v1, T2 &&v2)
+  { return check_equal (v1 = v2, v2); }
+
+  template <typename T> bool propagate_error (T &&obj)
+  { return check_success (!hb_deref (obj).in_error ()); }
+
+  template <typename T1, typename... Ts> bool propagate_error (T1 &&o1, Ts&&... os)
+  { return propagate_error (hb_forward<T1> (o1)) &&
+           propagate_error (hb_forward<Ts> (os)...); }
+
+  /* To be called around main operation. */
+  template <typename Type>
+  Type *start_serialize ()
+  {
+    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
+                     "start [%p..%p] (%lu bytes)",
+                     this->start, this->end,
+                     (unsigned long) (this->end - this->start));
+
+    assert (!current);
+    return push<Type> ();
+  }
+  void end_serialize ()
+  {
+    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
+                     "end [%p..%p] serialized %u bytes; %s",
+                     this->start, this->end,
+                     (unsigned) (this->head - this->start),
+                     this->successful ? "successful" : "UNSUCCESSFUL");
+
+    propagate_error (packed, packed_map);
+
+    if (unlikely (!current)) return;
+    if (unlikely (in_error())) return;
+
+    assert (!current->next);
+
+    /* Only "pack" if there exist other objects... Otherwise, don't bother.
+     * Saves a move. */
+    if (packed.length <= 1)
+      return;
+
+    pop_pack (false);
+
+    resolve_links ();
+  }
+
+  template <typename Type = void>
+  Type *push ()
+  {
+    if (unlikely (in_error ())) return start_embed<Type> ();
+
+    object_t *obj = object_pool.alloc ();
+    if (unlikely (!obj))
+      check_success (false);
+    else
+    {
+      obj->head = head;
+      obj->tail = tail;
+      obj->next = current;
+      current = obj;
+    }
+    return start_embed<Type> ();
+  }
+  void pop_discard ()
+  {
+    object_t *obj = current;
+    if (unlikely (!obj)) return;
+    if (unlikely (in_error())) return;
+
+    current = current->next;
+    revert (obj->head, obj->tail);
+    obj->fini ();
+    object_pool.free (obj);
+  }
+
+  /* Set share to false when an object is unlikely sharable with others
+   * so not worth an attempt, or a contiguous table is serialized as
+   * multiple consecutive objects in the reverse order so can't be shared.
+   */
+  objidx_t pop_pack (bool share=true)
+  {
+    object_t *obj = current;
+    if (unlikely (!obj)) return 0;
+    if (unlikely (in_error())) return 0;
+
+    current = current->next;
+    obj->tail = head;
+    obj->next = nullptr;
+    unsigned len = obj->tail - obj->head;
+    head = obj->head; /* Rewind head. */
+
+    if (!len)
+    {
+      assert (!obj->links.length);
+      return 0;
+    }
+
+    objidx_t objidx;
+    if (share)
+    {
+      objidx = packed_map.get (obj);
+      if (objidx)
+      {
+        obj->fini ();
+        return objidx;
+      }
+    }
+
+    tail -= len;
+    memmove (tail, obj->head, len);
+
+    obj->head = tail;
+    obj->tail = tail + len;
+
+    packed.push (obj);
+
+    if (unlikely (packed.in_error ())) {
+      // obj wasn't successfully added to packed, so clean it up otherwise it's
+      // links will be leaked.
+      propagate_error (packed);
+      obj->fini ();
+      return 0;
+    }
+
+    objidx = packed.length - 1;
+
+    if (share) packed_map.set (obj, objidx);
+    propagate_error (packed_map);
+
+    return objidx;
+  }
+
+  void revert (snapshot_t snap)
+  {
+    if (unlikely (in_error ())) return;
+    assert (snap.current == current);
+    current->links.shrink (snap.num_links);
+    revert (snap.head, snap.tail);
+  }
+
+  void revert (char *snap_head,
+               char *snap_tail)
+  {
+    if (unlikely (in_error ())) return;
+    assert (snap_head <= head);
+    assert (tail <= snap_tail);
+    head = snap_head;
+    tail = snap_tail;
+    discard_stale_objects ();
+  }
+
+  void discard_stale_objects ()
+  {
+    if (unlikely (in_error ())) return;
+    while (packed.length > 1 &&
+           packed.tail ()->head < tail)
+    {
+      packed_map.del (packed.tail ());
+      assert (!packed.tail ()->next);
+      packed.tail ()->fini ();
+      packed.pop ();
+    }
+    if (packed.length > 1)
+      assert (packed.tail ()->head == tail);
+  }
+
+  template <typename T>
+  void add_link (T &ofs, objidx_t objidx,
+                 whence_t whence = Head,
+                 unsigned bias = 0)
+  {
+    static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");
+    if (unlikely (in_error ())) return;
+
+    if (!objidx)
+      return;
+
+    assert (current);
+    assert (current->head <= (const char *) &ofs);
+
+    auto& link = *current->links.push ();
+
+    link.is_wide = sizeof (T) == 4;
+    link.is_signed = hb_is_signed (hb_unwrap_type (T));
+    link.whence = (unsigned) whence;
+    link.position = (const char *) &ofs - current->head;
+    link.bias = bias;
+    link.objidx = objidx;
+  }
+
+  unsigned to_bias (const void *base) const
+  {
+    if (unlikely (in_error ())) return 0;
+    if (!base) return 0;
+    assert (current);
+    assert (current->head <= (const char *) base);
+    return (const char *) base - current->head;
+  }
+
+  void resolve_links ()
+  {
+    if (unlikely (in_error ())) return;
+
+    assert (!current);
+    assert (packed.length > 1);
+
+    for (const object_t* parent : ++hb_iter (packed))
+      for (const object_t::link_t &link : parent->links)
+      {
+        const object_t* child = packed[link.objidx];
+        if (unlikely (!child)) { err_other_error(); return; }
+        unsigned offset = 0;
+        switch ((whence_t) link.whence) {
+        case Head:     offset = child->head - parent->head; break;
+        case Tail:     offset = child->head - parent->tail; break;
+        case Absolute: offset = (head - start) + (child->head - tail); break;
+        }
+
+        assert (offset >= link.bias);
+        offset -= link.bias;
+        if (link.is_signed)
+        {
+          if (link.is_wide)
+            assign_offset<int32_t> (parent, link, offset);
+          else
+            assign_offset<int16_t> (parent, link, offset);
+        }
+        else
+        {
+          if (link.is_wide)
+            assign_offset<uint32_t> (parent, link, offset);
+          else
+            assign_offset<uint16_t> (parent, link, offset);
+        }
+      }
+  }
+
+  unsigned int length () const
+  {
+    if (unlikely (!current)) return 0;
+    return this->head - current->head;
+  }
+
+  void align (unsigned int alignment)
+  {
+    unsigned int l = length () % alignment;
+    if (l)
+      allocate_size<void> (alignment - l);
+  }
+
+  template <typename Type = void>
+  Type *start_embed (const Type *obj HB_UNUSED = nullptr) const
+  { return reinterpret_cast<Type *> (this->head); }
+  template <typename Type>
+  Type *start_embed (const Type &obj) const
+  { return start_embed (hb_addressof (obj)); }
+
+  /* Following two functions exist to allow setting breakpoint on. */
+  void err_ran_out_of_room () { this->ran_out_of_room = true; }
+  void err_other_error () { this->successful = false; }
+
+  template <typename Type>
+  Type *allocate_size (unsigned int size)
+  {
+    if (unlikely (!this->successful)) return nullptr;
+
+    if (this->tail - this->head < ptrdiff_t (size))
+    {
+      err_ran_out_of_room ();
+      this->successful = false;
+      return nullptr;
+    }
+    memset (this->head, 0, size);
+    char *ret = this->head;
+    this->head += size;
+    return reinterpret_cast<Type *> (ret);
+  }
+
+  template <typename Type>
+  Type *allocate_min ()
+  { return this->allocate_size<Type> (Type::min_size); }
+
+  template <typename Type>
+  Type *embed (const Type *obj)
+  {
+    unsigned int size = obj->get_size ();
+    Type *ret = this->allocate_size<Type> (size);
+    if (unlikely (!ret)) return nullptr;
+    memcpy (ret, obj, size);
+    return ret;
+  }
+  template <typename Type>
+  Type *embed (const Type &obj)
+  { return embed (hb_addressof (obj)); }
+
+  template <typename Type, typename ...Ts> auto
+  _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN
+  (Type *, src.copy (this, hb_forward<Ts> (ds)...))
+
+  template <typename Type> auto
+  _copy (const Type &src, hb_priority<0>) -> decltype (&(hb_declval<Type> () = src))
+  {
+    Type *ret = this->allocate_size<Type> (sizeof (Type));
+    if (unlikely (!ret)) return nullptr;
+    *ret = src;
+    return ret;
+  }
+
+  /* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data
+   * instead of memcpy(). */
+  template <typename Type, typename ...Ts>
+  Type *copy (const Type &src, Ts&&... ds)
+  { return _copy (src, hb_prioritize, hb_forward<Ts> (ds)...); }
+  template <typename Type, typename ...Ts>
+  Type *copy (const Type *src, Ts&&... ds)
+  { return copy (*src, hb_forward<Ts> (ds)...); }
+
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator)),
+           typename ...Ts>
+  void copy_all (Iterator it, Ts&&... ds)
+  { for (decltype (*it) _ : it) copy (_, hb_forward<Ts> (ds)...); }
+
+  template <typename Type>
+  hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
+
+  template <typename Type>
+  Type *extend_size (Type *obj, unsigned int size)
+  {
+    if (unlikely (in_error ())) return nullptr;
+
+    assert (this->start <= (char *) obj);
+    assert ((char *) obj <= this->head);
+    assert ((char *) obj + size >= this->head);
+    if (unlikely (!this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
+    return reinterpret_cast<Type *> (obj);
+  }
+  template <typename Type>
+  Type *extend_size (Type &obj, unsigned int size)
+  { return extend_size (hb_addressof (obj), size); }
+
+  template <typename Type>
+  Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); }
+  template <typename Type>
+  Type *extend_min (Type &obj) { return extend_min (hb_addressof (obj)); }
+
+  template <typename Type, typename ...Ts>
+  Type *extend (Type *obj, Ts&&... ds)
+  { return extend_size (obj, obj->get_size (hb_forward<Ts> (ds)...)); }
+  template <typename Type, typename ...Ts>
+  Type *extend (Type &obj, Ts&&... ds)
+  { return extend (hb_addressof (obj), hb_forward<Ts> (ds)...); }
+
+  /* Output routines. */
+  hb_bytes_t copy_bytes () const
+  {
+    assert (this->successful);
+    /* Copy both items from head side and tail side... */
+    unsigned int len = (this->head - this->start)
+                     + (this->end  - this->tail);
+
+    char *p = (char *) malloc (len);
+    if (unlikely (!p)) return hb_bytes_t ();
+
+    memcpy (p, this->start, this->head - this->start);
+    memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
+    return hb_bytes_t (p, len);
+  }
+  template <typename Type>
+  Type *copy () const
+  { return reinterpret_cast<Type *> ((char *) copy_bytes ().arrayZ); }
+  hb_blob_t *copy_blob () const
+  {
+    hb_bytes_t b = copy_bytes ();
+    return hb_blob_create (b.arrayZ, b.length,
+                           HB_MEMORY_MODE_WRITABLE,
+                           (char *) b.arrayZ, free);
+  }
+
+  private:
+  template <typename T>
+  void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
+  {
+    auto &off = * ((BEInt<T, sizeof (T)> *) (parent->head + link.position));
+    assert (0 == off);
+    check_assign (off, offset);
+  }
+
+  public: /* TODO Make private. */
+  char *start, *head, *tail, *end;
+  unsigned int debug_depth;
+  bool successful;
+  bool ran_out_of_room;
+
+  private:
+
+  /* Object memory pool. */
+  hb_pool_t<object_t> object_pool;
+
+  /* Stack of currently under construction objects. */
+  object_t *current;
+
+  /* Stack of packed objects.  Object 0 is always nil object. */
+  hb_vector_t<object_t *> packed;
+
+  /* Map view of packed objects. */
+  hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
+};
+
+
+#endif /* HB_SERIALIZE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-set.cc b/src/java.desktop/share/native/libharfbuzz/hb-set.cc
index 7dff331..fb40368 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-set.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-set.cc
@@ -69,7 +69,7 @@
 hb_set_t *
 hb_set_get_empty ()
 {
-  return const_cast<hb_set_t *> (&Null(hb_set_t));
+  return const_cast<hb_set_t *> (&Null (hb_set_t));
 }
 
 /**
@@ -389,6 +389,7 @@
   set->symmetric_difference (other);
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_set_invert:
  * @set: a set.
@@ -403,6 +404,7 @@
 hb_set_invert (hb_set_t *set HB_UNUSED)
 {
 }
+#endif
 
 /**
  * hb_set_get_population:
@@ -477,7 +479,7 @@
  * @set: a set.
  * @codepoint: (inout):
  *
- * Gets the previous number in @set that is slower than current value of @codepoint.
+ * Gets the previous number in @set that is lower than current value of @codepoint.
  *
  * Set @codepoint to %HB_SET_VALUE_INVALID to get started.
  *
@@ -522,7 +524,7 @@
  * @last: (out): output last codepoint in the range.
  *
  * Gets the previous consecutive range of numbers in @set that
- * are greater than current value of @last.
+ * are less than current value of @first.
  *
  * Set @first to %HB_SET_VALUE_INVALID to get started.
  *
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-set.hh b/src/java.desktop/share/native/libharfbuzz/hb-set.hh
index 6b42694..93ba0d0 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-set.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-set.hh
@@ -28,6 +28,7 @@
 #define HB_SET_HH
 
 #include "hb.hh"
+#include "hb-machinery.hh"
 
 
 /*
@@ -39,7 +40,7 @@
 
 struct hb_set_t
 {
-  HB_NO_COPY_ASSIGN (hb_set_t);
+  HB_DELETE_COPY_ASSIGN (hb_set_t);
   hb_set_t ()  { init (); }
   ~hb_set_t () { fini (); }
 
@@ -69,7 +70,7 @@
 
     void add (hb_codepoint_t g) { elt (g) |= mask (g); }
     void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
-    bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); }
+    bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
 
     void add_range (hb_codepoint_t a, hb_codepoint_t b)
     {
@@ -88,6 +89,23 @@
       }
     }
 
+    void del_range (hb_codepoint_t a, hb_codepoint_t b)
+    {
+      elt_t *la = &elt (a);
+      elt_t *lb = &elt (b);
+      if (la == lb)
+        *la &= ~((mask (b) << 1) - mask(a));
+      else
+      {
+        *la &= mask (a) - 1;
+        la++;
+
+        memset (la, 0, (char *) lb - (char *) la);
+
+        *lb &= ~((mask (b) << 1) - 1);
+      }
+    }
+
     bool is_equal (const page_t *other) const
     {
       return 0 == hb_memcmp (&v, &other->v, sizeof (v));
@@ -134,13 +152,22 @@
       unsigned int i = m / ELT_BITS;
       unsigned int j = m & ELT_MASK;
 
-      const elt_t vv = v[i] & ((elt_t (1) << (j + 1)) - 1);
-      for (const elt_t *p = &vv; (int) i >= 0; p = &v[--i])
+      /* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */
+      const elt_t mask = j < 8 * sizeof (elt_t) - 1 ?
+                         ((elt_t (1) << (j + 1)) - 1) :
+                         (elt_t) -1;
+      const elt_t vv = v[i] & mask;
+      const elt_t *p = &vv;
+      while (true)
+      {
         if (*p)
         {
           *codepoint = i * ELT_BITS + elt_get_max (*p);
           return true;
         }
+        if ((int) i <= 0) break;
+        p = &v[--i];
+      }
 
       *codepoint = INVALID;
       return false;
@@ -186,7 +213,7 @@
   hb_object_header_t header;
   bool successful; /* Allocations successful */
   mutable unsigned int population;
-  hb_vector_t<page_map_t> page_map;
+  hb_sorted_vector_t<page_map_t> page_map;
   hb_vector_t<page_t> pages;
 
   void init_shallow ()
@@ -227,11 +254,18 @@
     return true;
   }
 
+  void reset ()
+  {
+    if (unlikely (hb_object_is_immutable (this)))
+      return;
+    clear ();
+    successful = true;
+  }
+
   void clear ()
   {
     if (unlikely (hb_object_is_immutable (this)))
       return;
-    successful = true;
     population = 0;
     page_map.resize (0);
     pages.resize (0);
@@ -245,7 +279,7 @@
     return true;
   }
 
-  void dirty () { population = (unsigned int) -1; }
+  void dirty () { population = UINT_MAX; }
 
   void add (hb_codepoint_t g)
   {
@@ -301,7 +335,7 @@
       {
         page->add (g);
 
-        array = (const T *) ((const char *) array + stride);
+        array = &StructAtOffsetUnaligned<T> (array, stride);
         count--;
       }
       while (count && (g = *array, start <= g && g < end));
@@ -349,23 +383,79 @@
     dirty ();
     page->del (g);
   }
+
+  private:
+  void del_pages (int ds, int de)
+  {
+    if (ds <= de)
+    {
+      unsigned int write_index = 0;
+      for (unsigned int i = 0; i < page_map.length; i++)
+      {
+        int m = (int) page_map[i].major;
+        if (m < ds || de < m)
+          page_map[write_index++] = page_map[i];
+      }
+      compact (write_index);
+      resize (write_index);
+    }
+  }
+
+  public:
   void del_range (hb_codepoint_t a, hb_codepoint_t b)
   {
     /* TODO perform op even if !successful. */
-    /* TODO Optimize, like add_range(). */
     if (unlikely (!successful)) return;
-    for (unsigned int i = a; i < b + 1; i++)
-      del (i);
+    if (unlikely (a > b || a == INVALID || b == INVALID)) return;
+    dirty ();
+    unsigned int ma = get_major (a);
+    unsigned int mb = get_major (b);
+    /* Delete pages from ds through de if ds <= de. */
+    int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
+    int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
+    if (ds > de || (int) ma < ds)
+    {
+      page_t *page = page_for (a);
+      if (page)
+      {
+        if (ma == mb)
+          page->del_range (a, b);
+        else
+          page->del_range (a, major_start (ma + 1) - 1);
+      }
+    }
+    if (de < (int) mb && ma != mb)
+    {
+      page_t *page = page_for (b);
+      if (page)
+        page->del_range (major_start (mb), b);
+    }
+    del_pages (ds, de);
   }
-  bool has (hb_codepoint_t g) const
+
+  bool get (hb_codepoint_t g) const
   {
     const page_t *page = page_for (g);
     if (!page)
       return false;
-    return page->has (g);
+    return page->get (g);
   }
-  bool intersects (hb_codepoint_t first,
-                          hb_codepoint_t last) const
+
+  /* Has interface. */
+  static constexpr bool SENTINEL = false;
+  typedef bool value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Predicate. */
+  bool operator () (hb_codepoint_t k) const { return has (k); }
+
+  /* Sink interface. */
+  hb_set_t& operator << (hb_codepoint_t v)
+  { add (v); return *this; }
+  hb_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+  { add_range (range.first, range.second); return *this; }
+
+  bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
   {
     hb_codepoint_t c = first - 1;
     return next (&c) && c <= last;
@@ -422,8 +512,36 @@
     return true;
   }
 
-  template <class Op>
-  void process (const hb_set_t *other)
+  void compact (unsigned int length)
+  {
+    hb_vector_t<uint32_t> old_index_to_page_map_index;
+    old_index_to_page_map_index.resize(pages.length);
+    for (uint32_t i = 0; i < old_index_to_page_map_index.length; i++)
+      old_index_to_page_map_index[i] = 0xFFFFFFFF;
+
+    for (uint32_t i = 0; i < length; i++)
+      old_index_to_page_map_index[page_map[i].index] =  i;
+
+    compact_pages (old_index_to_page_map_index);
+  }
+
+  void compact_pages (const hb_vector_t<uint32_t>& old_index_to_page_map_index)
+  {
+    unsigned int write_index = 0;
+    for (unsigned int i = 0; i < pages.length; i++)
+    {
+      if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
+
+      if (write_index < i)
+        pages[write_index] = pages[i];
+
+      page_map[old_index_to_page_map_index[i]].index = write_index;
+      write_index++;
+    }
+  }
+
+  template <typename Op>
+  void process (const Op& op, const hb_set_t *other)
   {
     if (unlikely (!successful)) return;
 
@@ -435,10 +553,22 @@
 
     unsigned int count = 0, newCount = 0;
     unsigned int a = 0, b = 0;
+    unsigned int write_index = 0;
     for (; a < na && b < nb; )
     {
       if (page_map[a].major == other->page_map[b].major)
       {
+        if (!Op::passthru_left)
+        {
+          // Move page_map entries that we're keeping from the left side set
+          // to the front of the page_map vector. This isn't necessary if
+          // passthru_left is set since no left side pages will be removed
+          // in that case.
+          if (write_index < a)
+            page_map[write_index] = page_map[a];
+          write_index++;
+        }
+
         count++;
         a++;
         b++;
@@ -461,9 +591,16 @@
     if (Op::passthru_right)
       count += nb - b;
 
-    if (count > pages.length)
-      if (!resize (count))
-        return;
+    if (!Op::passthru_left)
+    {
+      na  = write_index;
+      next_page = write_index;
+      compact (write_index);
+    }
+
+    if (!resize (count))
+      return;
+
     newCount = count;
 
     /* Process in-place backward. */
@@ -477,7 +614,7 @@
         b--;
         count--;
         page_map[count] = page_map[a];
-        Op::process (page_at (count).v, page_at (a).v, other->page_at (b).v);
+        page_at (count).v = op (page_at (a).v, other->page_at (b).v);
       }
       else if (page_map[a - 1].major > other->page_map[b - 1].major)
       {
@@ -523,19 +660,19 @@
 
   void union_ (const hb_set_t *other)
   {
-    process<HbOpOr> (other);
+    process (hb_bitwise_or, other);
   }
   void intersect (const hb_set_t *other)
   {
-    process<HbOpAnd> (other);
+    process (hb_bitwise_and, other);
   }
   void subtract (const hb_set_t *other)
   {
-    process<HbOpMinus> (other);
+    process (hb_bitwise_sub, other);
   }
   void symmetric_difference (const hb_set_t *other)
   {
-    process<HbOpXor> (other);
+    process (hb_bitwise_xor, other);
   }
   bool next (hb_codepoint_t *codepoint) const
   {
@@ -638,7 +775,7 @@
 
   unsigned int get_population () const
   {
-    if (population != (unsigned int) -1)
+    if (population != UINT_MAX)
       return population;
 
     unsigned int pop = 0;
@@ -671,27 +808,36 @@
   /*
    * Iterator implementation.
    */
-  struct const_iter_t : hb_sorted_iter_t<const_iter_t, const hb_codepoint_t>
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
   {
-    const_iter_t (const hb_set_t &s_) :
-      s (s_), v (INVALID), l (s.get_population () + 1) { __next__ (); }
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const hb_set_t &s_ = Null (hb_set_t),
+            bool init = true) : s (&s_), v (INVALID), l(0)
+    {
+      if (init)
+      {
+        l = s->get_population () + 1;
+        __next__ ();
+      }
+    }
 
-    typedef hb_codepoint_t __item_type__;
+    typedef hb_codepoint_t __item_t__;
     hb_codepoint_t __item__ () const { return v; }
     bool __more__ () const { return v != INVALID; }
-    void __next__ () { s.next (&v); if (l) l--; }
-    void __prev__ () { s.previous (&v); }
-    unsigned __len__ () { return l; }
+    void __next__ () { s->next (&v); if (l) l--; }
+    void __prev__ () { s->previous (&v); }
+    unsigned __len__ () const { return l; }
+    iter_t end () const { return iter_t (*s, false); }
+    bool operator != (const iter_t& o) const
+    { return s != o.s || v != o.v; }
 
     protected:
-    const hb_set_t &s;
+    const hb_set_t *s;
     hb_codepoint_t v;
     unsigned l;
   };
-  const_iter_t const_iter () const { return const_iter_t (*this); }
-  operator const_iter_t () const { return const_iter (); }
-  typedef const_iter_t iter_t;
-  iter_t iter () const { return const_iter (); }
+  iter_t iter () const { return iter_t (*this); }
+  operator iter_t () const { return iter (); }
 
   protected:
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc
index 800cf0a..3243eff 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc
@@ -79,7 +79,9 @@
   }
   this->shaper_func = nullptr;
   this->shaper_name = nullptr;
+#ifndef HB_NO_OT_SHAPE
   this->ot.init (face, coords, num_coords);
+#endif
 
   /*
    * Choose shaper.
@@ -148,7 +150,9 @@
 {
   return hb_segment_properties_equal (&this->props, &other->props) &&
          this->user_features_match (other) &&
+#ifndef HB_NO_OT_SHAPE
          this->ot.equal (&other->ot) &&
+#endif
          this->shaper_func == other->shaper_func;
 }
 
@@ -224,12 +228,16 @@
                                        num_coords,
                                        shaper_list)))
     goto bail2;
+#ifndef HB_NO_OT_SHAPE
   if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key)))
     goto bail3;
+#endif
 
   return shape_plan;
 
+#ifndef HB_NO_OT_SHAPE
 bail3:
+#endif
   shape_plan->key.free ();
 bail2:
   free (shape_plan);
@@ -249,7 +257,7 @@
 hb_shape_plan_t *
 hb_shape_plan_get_empty ()
 {
-  return const_cast<hb_shape_plan_t *> (&Null(hb_shape_plan_t));
+  return const_cast<hb_shape_plan_t *> (&Null (hb_shape_plan_t));
 }
 
 /**
@@ -281,7 +289,9 @@
 {
   if (!hb_object_destroy (shape_plan)) return;
 
+#ifndef HB_NO_OT_SHAPE
   shape_plan->ot.fini ();
+#endif
   shape_plan->key.free ();
   free (shape_plan);
 }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh
index a99cfc3..debe659 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh
@@ -39,21 +39,23 @@
   const hb_feature_t      *user_features;
   unsigned int             num_user_features;
 
+#ifndef HB_NO_OT_SHAPE
   hb_ot_shape_plan_key_t   ot;
+#endif
 
   hb_shape_func_t         *shaper_func;
   const char              *shaper_name;
 
-  HB_INTERNAL inline bool init (bool                           copy,
-                                hb_face_t                     *face,
-                                const hb_segment_properties_t *props,
-                                const hb_feature_t            *user_features,
-                                unsigned int                   num_user_features,
-                                const int                     *coords,
-                                unsigned int                   num_coords,
-                                const char * const            *shaper_list);
+  HB_INTERNAL bool init (bool                           copy,
+                         hb_face_t                     *face,
+                         const hb_segment_properties_t *props,
+                         const hb_feature_t            *user_features,
+                         unsigned int                   num_user_features,
+                         const int                     *coords,
+                         unsigned int                   num_coords,
+                         const char * const            *shaper_list);
 
-  HB_INTERNAL inline void free () { ::free ((void *) user_features); }
+  HB_INTERNAL void free () { ::free ((void *) user_features); }
 
   HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other);
 
@@ -65,7 +67,9 @@
   hb_object_header_t header;
   hb_face_t *face_unsafe; /* We don't carry a reference to face. */
   hb_shape_plan_key_t key;
+#ifndef HB_NO_OT_SHAPE
   hb_ot_shape_plan_t ot;
+#endif
 };
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc
index 90876d6..5dc55fe 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc
@@ -132,6 +132,8 @@
                unsigned int        num_features,
                const char * const *shaper_list)
 {
+  if (unlikely (hb_object_is_immutable (buffer))) return false;
+
   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props,
                                                               features, num_features,
                                                               font->coords, font->num_coords,
@@ -154,7 +156,9 @@
  *
  * Shapes @buffer using @font turning its Unicode characters content to
  * positioned glyphs. If @features is not %NULL, it will be used to control the
- * features applied during shaping.
+ * features applied during shaping. If two @features have the same tag but
+ * overlapping ranges the value of the feature with the higher index takes
+ * precedence.
  *
  * Since: 0.9.2
  **/
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh
index 36d8fc7..0d63933 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh
@@ -28,6 +28,9 @@
 #define HB_SHAPER_LIST_HH
 #endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */
 
+#ifndef HB_NO_SHAPER
+
+
 /* v--- Add new shapers in the right place here. */
 
 #ifdef HAVE_GRAPHITE2
@@ -35,7 +38,9 @@
 HB_SHAPER_IMPLEMENT (graphite2)
 #endif
 
+#ifndef HB_NO_OT_SHAPE
 HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
+#endif
 
 #ifdef HAVE_UNISCRIBE
 HB_SHAPER_IMPLEMENT (uniscribe)
@@ -45,12 +50,11 @@
 #endif
 #ifdef HAVE_CORETEXT
 HB_SHAPER_IMPLEMENT (coretext)
-
-/* Only picks up fonts that have a "mort" or "morx" table.
-   Probably going to be removed https://github.com/harfbuzz/harfbuzz/issues/1478 */
-HB_SHAPER_IMPLEMENT (coretext_aat)
 #endif
 
-#ifdef HAVE_FALLBACK
+#ifndef HB_NO_FALLBACK_SHAPE
 HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
 #endif
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shaper.cc b/src/java.desktop/share/native/libharfbuzz/hb-shaper.cc
index 158b454..b1d76dc 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-shaper.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-shaper.cc
@@ -34,6 +34,9 @@
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 };
+#ifndef HB_NO_SHAPER
+static_assert (0 != ARRAY_LENGTH_CONST (all_shapers), "No shaper enabled.");
+#endif
 
 #if HB_USE_ATEXIT
 static void free_static_shapers ();
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shaper.hh b/src/java.desktop/share/native/libharfbuzz/hb-shaper.hh
index 37ca9ff..0c9b681 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-shaper.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-shaper.hh
@@ -102,7 +102,7 @@
           static void destroy (Type *p) { HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (p); } \
         }; \
         \
-        static_assert (true, "") /* Require semicolon. */
+        static_assert (true, "") /* Require semicolon after. */
 
 
 template <typename Object>
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-static.cc b/src/java.desktop/share/native/libharfbuzz/hb-static.cc
index 4c51588..b213c57 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-static.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-static.cc
@@ -37,9 +37,10 @@
 #include "hb-ot-maxp-table.hh"
 
 #ifndef HB_NO_VISIBILITY
+#include "hb-ot-name-language-static.hh"
 
-hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {};
-/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {};
+uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
+/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
 
 DEFINE_NULL_NAMESPACE_BYTES (OT, Index) =  {0xFF,0xFF};
 DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00};
@@ -50,6 +51,9 @@
 const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
 
 
+
+/* hb_face_t */
+
 unsigned int
 hb_face_t::load_num_glyphs () const
 {
@@ -72,4 +76,37 @@
   return ret;
 }
 
+
+/* hb_user_data_array_t */
+
+bool
+hb_user_data_array_t::set (hb_user_data_key_t *key,
+                           void *              data,
+                           hb_destroy_func_t   destroy,
+                           hb_bool_t           replace)
+{
+  if (!key)
+    return false;
+
+  if (replace) {
+    if (!data && !destroy) {
+      items.remove (key, lock);
+      return true;
+    }
+  }
+  hb_user_data_item_t item = {key, data, destroy};
+  bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
+
+  return ret;
+}
+
+void *
+hb_user_data_array_t::get (hb_user_data_key_t *key)
+{
+  hb_user_data_item_t item = {nullptr, nullptr, nullptr};
+
+  return items.find (key, &item, lock) ? item.data : nullptr;
+}
+
+
 #endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh
index dffa9f3..9d00cae 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh
@@ -37,6 +37,7 @@
 #define HB_STRING_ARRAY_TYPE_NAME       HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr_t)
 #define HB_STRING_ARRAY_POOL_NAME       HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr)
 #define HB_STRING_ARRAY_OFFS_NAME       HB_PASTE(HB_STRING_ARRAY_NAME, _msgidx)
+#define HB_STRING_ARRAY_LENG_NAME       HB_PASTE(HB_STRING_ARRAY_NAME, _length)
 
 static const union HB_STRING_ARRAY_TYPE_NAME {
   struct {
@@ -48,7 +49,7 @@
 #include HB_STRING_ARRAY_LIST
 #undef _S
   } st;
-  char str[VAR];
+  char str[HB_VAR_ARRAY];
 }
 HB_STRING_ARRAY_POOL_NAME =
 {
@@ -66,6 +67,8 @@
   sizeof (HB_STRING_ARRAY_TYPE_NAME)
 };
 
+static const unsigned int HB_STRING_ARRAY_LENG_NAME = ARRAY_LENGTH_CONST (HB_STRING_ARRAY_OFFS_NAME) - 1;
+
 static inline hb_bytes_t
 HB_STRING_ARRAY_NAME (unsigned int i)
 {
@@ -77,5 +80,6 @@
 #undef HB_STRING_ARRAY_TYPE_NAME
 #undef HB_STRING_ARRAY_POOL_NAME
 #undef HB_STRING_ARRAY_OFFS_NAME
+#undef HB_STRING_ARRAY_LENG_NAME
 
 #endif /* HB_STRING_ARRAY_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-style.cc b/src/java.desktop/share/native/libharfbuzz/hb-style.cc
new file mode 100644
index 0000000..50f9df9
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-style.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright © 2019  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_STYLE
+#ifdef HB_EXPERIMENTAL_API
+
+#include "hb-ot-var-avar-table.hh"
+#include "hb-ot-var-fvar-table.hh"
+#include "hb-ot-stat-table.hh"
+#include "hb-ot-os2-table.hh"
+#include "hb-ot-head-table.hh"
+#include "hb-ot-post-table.hh"
+#include "hb-ot-face.hh"
+
+/**
+ * hb_style_tag_t:
+ * @HB_STYLE_TAG_ITALIC: Used to vary between non-italic and italic.
+ * A value of 0 can be interpreted as "Roman" (non-italic); a value of 1 can
+ * be interpreted as (fully) italic.
+ * @HB_STYLE_TAG_OPTICAL_SIZE: Used to vary design to suit different text sizes.
+ * Non-zero. Values can be interpreted as text size, in points.
+ * @HB_STYLE_TAG_SLANT: Used to vary between upright and slanted text. Values
+ * must be greater than -90 and less than +90. Values can be interpreted as
+ * the angle, in counter-clockwise degrees, of oblique slant from whatever the
+ * designer considers to be upright for that font design.
+ * @HB_STYLE_TAG_WIDTH: Used to vary width of text from narrower to wider.
+ * Non-zero. Values can be interpreted as a percentage of whatever the font
+ * designer considers “normal width” for that font design.
+ * @HB_STYLE_TAG_WEIGHT: Used to vary stroke thicknesses or other design details
+ * to give variation from lighter to blacker. Values can be interpreted in direct
+ * comparison to values for usWeightClass in the OS/2 table,
+ * or the CSS font-weight property.
+ *
+ * Defined by https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg
+ *
+ * Since: EXPERIMENTAL
+ **/
+typedef enum {
+  HB_STYLE_TAG_ITALIC           = HB_TAG ('i','t','a','l'),
+  HB_STYLE_TAG_OPTICAL_SIZE     = HB_TAG ('o','p','s','z'),
+  HB_STYLE_TAG_SLANT            = HB_TAG ('s','l','n','t'),
+  HB_STYLE_TAG_WIDTH            = HB_TAG ('w','d','t','h'),
+  HB_STYLE_TAG_WEIGHT           = HB_TAG ('w','g','h','t'),
+
+  _HB_STYLE_TAG_MAX_VALUE       = HB_TAG_MAX_SIGNED /*< skip >*/
+} hb_style_tag_t;
+
+/**
+ * hb_style_get_value:
+ * @font: a #hb_font_t object.
+ * @style_tag: a style tag.
+ *
+ * Searches variation axes of a hb_font_t object for a specific axis first,
+ * if not set, then tries to get default style values from different
+ * tables of the font.
+ *
+ * Returns: Corresponding axis or default value to a style tag.
+ *
+ * Since: EXPERIMENTAL
+ **/
+float
+hb_style_get_value (hb_font_t *font, hb_tag_t tag)
+{
+  hb_style_tag_t style_tag = (hb_style_tag_t) tag;
+  hb_face_t *face = font->face;
+
+#ifndef HB_NO_VAR
+  hb_ot_var_axis_info_t axis;
+  if (hb_ot_var_find_axis_info (face, style_tag, &axis))
+  {
+    if (axis.axis_index < font->num_coords) return font->design_coords[axis.axis_index];
+    /* If a face is variable, fvar's default_value is better than STAT records */
+    return axis.default_value;
+  }
+#endif
+
+  if (style_tag == HB_STYLE_TAG_OPTICAL_SIZE && font->ptem)
+    return font->ptem;
+
+  /* STAT */
+  float value;
+  if (face->table.STAT->get_value (style_tag, &value))
+    return value;
+
+  switch ((unsigned) style_tag)
+  {
+  case HB_STYLE_TAG_ITALIC:
+    return face->table.OS2->is_italic () || face->table.head->is_italic () ? 1 : 0;
+  case HB_STYLE_TAG_OPTICAL_SIZE:
+  {
+    unsigned int lower, upper;
+    return face->table.OS2->v5 ().get_optical_size (&lower, &upper)
+           ? (float) (lower + upper) / 2.f
+           : 12.f;
+  }
+  case HB_STYLE_TAG_SLANT:
+    return face->table.post->table->italicAngle.to_float ();
+  case HB_STYLE_TAG_WIDTH:
+    return face->table.OS2->has_data ()
+           ? face->table.OS2->get_width ()
+           : (face->table.head->is_condensed () ? 75 : 100);
+  case HB_STYLE_TAG_WEIGHT:
+    return face->table.OS2->has_data ()
+           ? face->table.OS2->usWeightClass
+           : (face->table.head->is_bold () ? 700 : 400);
+  default:
+    return 0;
+  }
+}
+
+#endif
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-warning.cc b/src/java.desktop/share/native/libharfbuzz/hb-style.h
similarity index 69%
rename from src/java.desktop/share/native/libharfbuzz/hb-warning.cc
rename to src/java.desktop/share/native/libharfbuzz/hb-style.h
index 9fb4100..1209c79 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-warning.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-style.h
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2012  Google, Inc.
+ * Copyright © 2019  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -20,18 +20,24 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb.hh"
-
-#if defined(HB_ATOMIC_INT_NIL)
-#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe"
-#error "Check hb-atomic.hh for possible resolutions."
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
 #endif
 
-#if defined(HB_MUTEX_IMPL_NIL)
-#error "Could not find any system to define mutex macros, library WILL NOT be thread-safe"
-#error "Check hb-mutex.hh for possible resolutions."
+#ifndef HB_STYLE_H
+#define HB_STYLE_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+#ifdef HB_EXPERIMENTAL_API
+HB_EXTERN float
+hb_style_get_value (hb_font_t *font, hb_tag_t style_tag);
 #endif
+
+HB_END_DECLS
+
+#endif /* HB_STYLE_H */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc
index 75004fe..e174331 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc
@@ -24,6 +24,10 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_SUBSET_CFF
+
 #include "hb-ot-cff-common.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-subset-cff-common.hh"
@@ -43,33 +47,39 @@
  **/
 
 bool
-hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
-                            unsigned int fdCount,
-                            const FDSelect &src, /* IN */
-                            unsigned int &subset_fd_count /* OUT */,
-                            unsigned int &subset_fdselect_size /* OUT */,
-                            unsigned int &subset_fdselect_format /* OUT */,
-                            hb_vector_t<code_pair_t> &fdselect_ranges /* OUT */,
-                            remap_t &fdmap /* OUT */)
+hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
+                             unsigned int fdCount,
+                             const FDSelect &src, /* IN */
+                             unsigned int &subset_fd_count /* OUT */,
+                             unsigned int &subset_fdselect_size /* OUT */,
+                             unsigned int &subset_fdselect_format /* OUT */,
+                             hb_vector_t<code_pair_t> &fdselect_ranges /* OUT */,
+                             hb_inc_bimap_t &fdmap /* OUT */)
 {
   subset_fd_count = 0;
   subset_fdselect_size = 0;
   subset_fdselect_format = 0;
-  unsigned int  num_ranges = 0;
+  unsigned int num_ranges = 0;
 
-  unsigned int subset_num_glyphs = glyphs.length;
+  unsigned int subset_num_glyphs = plan->num_output_glyphs ();
   if (subset_num_glyphs == 0)
     return true;
 
   {
     /* use hb_set to determine the subset of font dicts */
-    hb_set_t  *set = hb_set_create ();
-    if (set == &Null (hb_set_t))
-      return false;
-    hb_codepoint_t  prev_fd = CFF_UNDEF_CODE;
+    hb_set_t *set = hb_set_create ();
+    if (unlikely (set == &Null (hb_set_t))) return false;
+    hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
     for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
     {
-      hb_codepoint_t  fd = src.get_fd (glyphs[i]);
+      hb_codepoint_t glyph;
+      hb_codepoint_t fd;
+      if (!plan->old_gid_for_new_gid (i, &glyph))
+      {
+        /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */
+        glyph = i;
+      }
+      fd = src.get_fd (glyph);
       set->add (fd);
 
       if (fd != prev_fd)
@@ -91,17 +101,13 @@
     else
     {
       /* create a fdmap */
-      if (!fdmap.reset (fdCount))
-      {
-        hb_set_destroy (set);
-        return false;
-      }
+      fdmap.reset ();
 
-      hb_codepoint_t  fd = CFF_UNDEF_CODE;
+      hb_codepoint_t fd = CFF_UNDEF_CODE;
       while (set->next (&fd))
         fdmap.add (fd);
       hb_set_destroy (set);
-      if (unlikely (fdmap.get_count () != subset_fd_count))
+      if (unlikely (fdmap.get_population () != subset_fd_count))
         return false;
     }
 
@@ -145,21 +151,21 @@
 template <typename FDSELECT3_4>
 static inline bool
 serialize_fdselect_3_4 (hb_serialize_context_t *c,
-                          const unsigned int num_glyphs,
-                          const FDSelect &src,
-                          unsigned int size,
-                          const hb_vector_t<code_pair_t> &fdselect_ranges)
+                        const unsigned int num_glyphs,
+                        const FDSelect &src,
+                        unsigned int size,
+                        const hb_vector_t<code_pair_t> &fdselect_ranges)
 {
   TRACE_SERIALIZE (this);
   FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size);
-  if (unlikely (p == nullptr)) return_trace (false);
-  p->nRanges ().set (fdselect_ranges.length);
+  if (unlikely (!p)) return_trace (false);
+  p->nRanges () = fdselect_ranges.length;
   for (unsigned int i = 0; i < fdselect_ranges.length; i++)
   {
-    p->ranges[i].first.set (fdselect_ranges[i].glyph);
-    p->ranges[i].fd.set (fdselect_ranges[i].code);
+    p->ranges[i].first = fdselect_ranges[i].glyph;
+    p->ranges[i].fd = fdselect_ranges[i].code;
   }
-  p->sentinel().set (num_glyphs);
+  p->sentinel () = num_glyphs;
   return_trace (true);
 }
 
@@ -169,58 +175,53 @@
  **/
 bool
 hb_serialize_cff_fdselect (hb_serialize_context_t *c,
-                          const unsigned int num_glyphs,
-                          const FDSelect &src,
-                          unsigned int fd_count,
-                          unsigned int fdselect_format,
-                          unsigned int size,
-                          const hb_vector_t<code_pair_t> &fdselect_ranges)
+                           const unsigned int num_glyphs,
+                           const FDSelect &src,
+                           unsigned int fd_count,
+                           unsigned int fdselect_format,
+                           unsigned int size,
+                           const hb_vector_t<code_pair_t> &fdselect_ranges)
 {
   TRACE_SERIALIZE (this);
-  FDSelect  *p = c->allocate_min<FDSelect> ();
-  if (unlikely (p == nullptr)) return_trace (false);
-  p->format.set (fdselect_format);
+  FDSelect *p = c->allocate_min<FDSelect> ();
+  if (unlikely (!p)) return_trace (false);
+  p->format = fdselect_format;
   size -= FDSelect::min_size;
 
   switch (fdselect_format)
   {
 #if CFF_SERIALIZE_FDSELECT_0
-    case 0:
+  case 0:
+  {
+    FDSelect0 *p = c->allocate_size<FDSelect0> (size);
+    if (unlikely (!p)) return_trace (false);
+    unsigned int range_index = 0;
+    unsigned int fd = fdselect_ranges[range_index++].code;
+    for (unsigned int i = 0; i < num_glyphs; i++)
     {
-      FDSelect0 *p = c->allocate_size<FDSelect0> (size);
-      if (unlikely (p == nullptr)) return_trace (false);
-      unsigned int range_index = 0;
-      unsigned int  fd = fdselect_ranges[range_index++].code;
-      for (unsigned int i = 0; i < num_glyphs; i++)
+      if ((range_index < fdselect_ranges.len) &&
+          (i >= fdselect_ranges[range_index].glyph))
       {
-        if ((range_index < fdselect_ranges.len) &&
-            (i >= fdselect_ranges[range_index].glyph))
-        {
-          fd = fdselect_ranges[range_index++].code;
-        }
-        p->fds[i].set (fd);
+        fd = fdselect_ranges[range_index++].code;
       }
-      break;
+      p->fds[i] = fd;
     }
+    return_trace (true);
+  }
 #endif /* CFF_SERIALIZE_FDSELECT_0 */
 
-    case 3:
-      return serialize_fdselect_3_4<FDSelect3> (c,
-                                                num_glyphs,
-                                                src,
-                                                size,
-                                                fdselect_ranges);
+  case 3:
+    return serialize_fdselect_3_4<FDSelect3> (c, num_glyphs, src,
+                                              size, fdselect_ranges);
 
-    case 4:
-      return serialize_fdselect_3_4<FDSelect4> (c,
-                                                num_glyphs,
-                                                src,
-                                                size,
-                                                fdselect_ranges);
+  case 4:
+    return serialize_fdselect_3_4<FDSelect4> (c, num_glyphs, src,
+                                              size, fdselect_ranges);
 
-    default:
-      assert(false);
+  default:
+    return_trace (false);
   }
-
-  return_trace (true);
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh
index a349254..b818641 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh
@@ -44,7 +44,7 @@
 
   void encode_byte (unsigned char b)
   {
-    if (unlikely (buff.push (b) == &Crap(unsigned char)))
+    if (unlikely (buff.push (b) == &Crap (unsigned char)))
       set_error ();
   }
 
@@ -110,7 +110,11 @@
   void copy_str (const byte_str_t &str)
   {
     unsigned int  offset = buff.length;
-    buff.resize (offset + str.length);
+    if (unlikely (!buff.resize (offset + str.length)))
+    {
+      set_error ();
+      return;
+    }
     if (unlikely (buff.length < offset + str.length))
     {
       set_error ();
@@ -128,26 +132,17 @@
   bool    error;
 };
 
-struct cff_sub_table_offsets_t {
-  cff_sub_table_offsets_t () : privateDictsOffset (0)
+struct cff_sub_table_info_t {
+  cff_sub_table_info_t ()
+    : fd_array_link (0),
+      char_strings_link (0)
   {
-    topDictInfo.init ();
-    FDSelectInfo.init ();
-    FDArrayInfo.init ();
-    charStringsInfo.init ();
-    globalSubrsInfo.init ();
-    localSubrsInfos.init ();
+    fd_select.init ();
   }
 
-  ~cff_sub_table_offsets_t () { localSubrsInfos.fini (); }
-
-  table_info_t     topDictInfo;
-  table_info_t     FDSelectInfo;
-  table_info_t     FDArrayInfo;
-  table_info_t     charStringsInfo;
-  unsigned int  privateDictsOffset;
-  table_info_t     globalSubrsInfo;
-  hb_vector_t<table_info_t>  localSubrsInfos;
+  table_info_t     fd_select;
+  objidx_t         fd_array_link;
+  objidx_t         char_strings_link;
 };
 
 template <typename OPSTR=op_str_t>
@@ -155,40 +150,26 @@
 {
   bool serialize (hb_serialize_context_t *c,
                   const OPSTR &opstr,
-                  const cff_sub_table_offsets_t &offsets) const
+                  const cff_sub_table_info_t &info) const
   {
     TRACE_SERIALIZE (this);
 
     switch (opstr.op)
     {
       case OpCode_CharStrings:
-        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset));
+        return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute));
 
       case OpCode_FDArray:
-        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset));
+        return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute));
 
       case OpCode_FDSelect:
-        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
+        return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute));
 
       default:
         return_trace (copy_opstr (c, opstr));
     }
     return_trace (true);
   }
-
-  unsigned int calculate_serialized_size (const OPSTR &opstr) const
-  {
-    switch (opstr.op)
-    {
-      case OpCode_CharStrings:
-      case OpCode_FDArray:
-      case OpCode_FDSelect:
-        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
-
-      default:
-        return opstr.str.length;
-    }
-  }
 };
 
 struct cff_font_dict_op_serializer_t : op_serializer_t
@@ -202,33 +183,17 @@
     if (opstr.op == OpCode_Private)
     {
       /* serialize the private dict size & offset as 2-byte & 4-byte integers */
-      if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) ||
-                    !UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
-        return_trace (false);
-
-      /* serialize the opcode */
-      HBUINT8 *p = c->allocate_size<HBUINT8> (1);
-      if (unlikely (p == nullptr)) return_trace (false);
-      p->set (OpCode_Private);
-
-      return_trace (true);
+      return_trace (UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) &&
+                    Dict::serialize_link4_op (c, opstr.op, privateDictInfo.link, whence_t::Absolute));
     }
     else
     {
       HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
-      if (unlikely (d == nullptr)) return_trace (false);
+      if (unlikely (!d)) return_trace (false);
       memcpy (d, &opstr.str[0], opstr.str.length);
     }
     return_trace (true);
   }
-
-  unsigned int calculate_serialized_size (const op_str_t &opstr) const
-  {
-    if (opstr.op == OpCode_Private)
-      return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
-    else
-      return opstr.str.length;
-  }
 };
 
 struct cff_private_dict_op_serializer_t : op_serializer_t
@@ -238,7 +203,7 @@
 
   bool serialize (hb_serialize_context_t *c,
                   const op_str_t &opstr,
-                  const unsigned int subrsOffset) const
+                  objidx_t subrs_link) const
   {
     TRACE_SERIALIZE (this);
 
@@ -246,31 +211,15 @@
       return true;
     if (opstr.op == OpCode_Subrs)
     {
-      if (desubroutinize || (subrsOffset == 0))
+      if (desubroutinize || !subrs_link)
         return_trace (true);
       else
-        return_trace (FontDict::serialize_offset2_op (c, opstr.op, subrsOffset));
+        return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link));
     }
     else
       return_trace (copy_opstr (c, opstr));
   }
 
-  unsigned int calculate_serialized_size (const op_str_t &opstr,
-                                          bool has_localsubr=true) const
-  {
-    if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
-      return 0;
-    if (opstr.op == OpCode_Subrs)
-    {
-      if (desubroutinize || !has_localsubr)
-        return 0;
-      else
-        return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (opstr.op);
-    }
-    else
-      return opstr.str.length;
-  }
-
   protected:
   const bool  desubroutinize;
   const bool  drop_hints;
@@ -282,30 +231,35 @@
   bool  drop_hints;
 };
 
-template <typename ACC, typename ENV, typename OPSET>
+template <typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
 struct subr_flattener_t
 {
   subr_flattener_t (const ACC &acc_,
-                    const hb_vector_t<hb_codepoint_t> &glyphs_,
-                    bool drop_hints_) : acc (acc_), glyphs (glyphs_),
-                                        drop_hints (drop_hints_) {}
+                    const hb_subset_plan_t *plan_)
+                   : acc (acc_), plan (plan_) {}
 
   bool flatten (str_buff_vec_t &flat_charstrings)
   {
-    if (!flat_charstrings.resize (glyphs.length))
+    if (!flat_charstrings.resize (plan->num_output_glyphs ()))
       return false;
-    for (unsigned int i = 0; i < glyphs.length; i++)
+    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
       flat_charstrings[i].init ();
-    for (unsigned int i = 0; i < glyphs.length; i++)
+    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
     {
-      hb_codepoint_t  glyph = glyphs[i];
+      hb_codepoint_t  glyph;
+      if (!plan->old_gid_for_new_gid (i, &glyph))
+      {
+        /* add an endchar only charstring for a missing glyph if CFF1 */
+        if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
+        continue;
+      }
       const byte_str_t str = (*acc.charStrings)[glyph];
       unsigned int fd = acc.fdSelect->get_fd (glyph);
       if (unlikely (fd >= acc.fdCount))
         return false;
       cs_interpreter_t<ENV, OPSET, flatten_param_t> interp;
       interp.env.init (str, acc, fd);
-      flatten_param_t  param = { flat_charstrings[i], drop_hints };
+      flatten_param_t  param = { flat_charstrings[i], plan->drop_hints };
       if (unlikely (!interp.interpret (param)))
         return false;
     }
@@ -313,8 +267,7 @@
   }
 
   const ACC &acc;
-  const hb_vector_t<hb_codepoint_t> &glyphs;
-  bool  drop_hints;
+  const hb_subset_plan_t *plan;
 };
 
 struct subr_closures_t
@@ -463,7 +416,8 @@
   void init (unsigned int len_ = 0)
   {
     SUPER::init ();
-    resize (len_);
+    if (unlikely (!resize (len_)))
+      return;
     for (unsigned int i = 0; i < length; i++)
       (*this)[i].init ();
   }
@@ -512,19 +466,19 @@
   template <typename ENV>
   void set_current_str (ENV &env, bool calling)
   {
-    parsed_cs_str_t  *parsed_str = get_parsed_str_for_context (env.context);
-    if (likely (parsed_str != nullptr))
+    parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context);
+    if (unlikely (!parsed_str))
     {
-      /* If the called subroutine is parsed partially but not completely yet,
-       * it must be because we are calling it recursively.
-       * Handle it as an error. */
-      if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
-        env.set_error ();
-      else
-        current_parsed_str = parsed_str;
-    }
-    else
       env.set_error ();
+      return;
+    }
+    /* If the called subroutine is parsed partially but not completely yet,
+     * it must be because we are calling it recursively.
+     * Handle it as an error. */
+    if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
+      env.set_error ();
+    else
+      current_parsed_str = parsed_str;
   }
 
   parsed_cs_str_t       *current_parsed_str;
@@ -537,39 +491,29 @@
   bool    drop_hints;
 };
 
-struct subr_remap_t : remap_t
+struct subr_remap_t : hb_inc_bimap_t
 {
   void create (hb_set_t *closure)
   {
     /* create a remapping of subroutine numbers from old to new.
      * no optimization based on usage counts. fonttools doesn't appear doing that either.
      */
-    reset (closure->get_max () + 1);
-    for (hb_codepoint_t old_num = 0; old_num < length; old_num++)
-    {
-      if (hb_set_has (closure, old_num))
-        add (old_num);
-    }
 
-    if (get_count () < 1240)
+    hb_codepoint_t old_num = HB_SET_VALUE_INVALID;
+    while (hb_set_next (closure, &old_num))
+      add (old_num);
+
+    if (get_population () < 1240)
       bias = 107;
-    else if (get_count () < 33900)
+    else if (get_population () < 33900)
       bias = 1131;
     else
       bias = 32768;
   }
 
-  hb_codepoint_t operator[] (unsigned int old_num) const
-  {
-    if (old_num >= length)
-      return CFF_UNDEF_CODE;
-    else
-      return remap_t::operator[] (old_num);
-  }
-
   int biased_num (unsigned int old_num) const
   {
-    hb_codepoint_t new_num = (*this)[old_num];
+    hb_codepoint_t new_num = get (old_num);
     return (int)new_num - bias;
   }
 
@@ -577,23 +521,28 @@
   int bias;
 };
 
-struct subr_remap_ts
+struct subr_remaps_t
 {
-  subr_remap_ts ()
+  subr_remaps_t ()
   {
     global_remap.init ();
     local_remaps.init ();
   }
 
-  ~subr_remap_ts () { fini (); }
+  ~subr_remaps_t () { fini (); }
 
   void init (unsigned int fdCount)
   {
-    local_remaps.resize (fdCount);
+    if (unlikely (!local_remaps.resize (fdCount))) return;
     for (unsigned int i = 0; i < fdCount; i++)
       local_remaps[i].init ();
   }
 
+  bool in_error()
+  {
+    return local_remaps.in_error ();
+  }
+
   void create (subr_closures_t& closures)
   {
     global_remap.create (closures.global_closure);
@@ -611,10 +560,11 @@
   hb_vector_t<subr_remap_t>  local_remaps;
 };
 
-template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET>
+template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
 struct subr_subsetter_t
 {
-  subr_subsetter_t ()
+  subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_)
+    : acc (acc_), plan (plan_)
   {
     parsed_charstrings.init ();
     parsed_global_subrs.init ();
@@ -644,25 +594,36 @@
    * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number
    * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine.
    */
-  bool subset (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, bool drop_hints)
+  bool subset (void)
   {
     closures.init (acc.fdCount);
     remaps.init (acc.fdCount);
 
-    parsed_charstrings.init (glyphs.length);
+    parsed_charstrings.init (plan->num_output_glyphs ());
     parsed_global_subrs.init (acc.globalSubrs->count);
-    parsed_local_subrs.resize (acc.fdCount);
+
+    if (unlikely (remaps.in_error()
+                  || parsed_charstrings.in_error ()
+                  || parsed_global_subrs.in_error ())) {
+      return false;
+    }
+
+    if (unlikely (!parsed_local_subrs.resize (acc.fdCount))) return false;
+
     for (unsigned int i = 0; i < acc.fdCount; i++)
     {
       parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count);
+      if (unlikely (parsed_local_subrs[i].in_error ())) return false;
     }
     if (unlikely (!closures.valid))
       return false;
 
     /* phase 1 & 2 */
-    for (unsigned int i = 0; i < glyphs.length; i++)
+    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
     {
-      hb_codepoint_t  glyph = glyphs[i];
+      hb_codepoint_t  glyph;
+      if (!plan->old_gid_for_new_gid (i, &glyph))
+        continue;
       const byte_str_t str = (*acc.charStrings)[glyph];
       unsigned int fd = acc.fdSelect->get_fd (glyph);
       if (unlikely (fd >= acc.fdCount))
@@ -675,28 +636,31 @@
       param.init (&parsed_charstrings[i],
                   &parsed_global_subrs,  &parsed_local_subrs[fd],
                   closures.global_closure, closures.local_closures[fd],
-                  drop_hints);
+                  plan->drop_hints);
 
       if (unlikely (!interp.interpret (param)))
         return false;
 
-      /* finalize parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
-      SUBSETTER::finalize_parsed_str (interp.env, param, parsed_charstrings[i]);
+      /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
+      SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
     }
 
-    if (drop_hints)
+    if (plan->drop_hints)
     {
       /* mark hint ops and arguments for drop */
-      for (unsigned int i = 0; i < glyphs.length; i++)
+      for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
       {
-        unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
+        hb_codepoint_t  glyph;
+        if (!plan->old_gid_for_new_gid (i, &glyph))
+          continue;
+        unsigned int fd = acc.fdSelect->get_fd (glyph);
         if (unlikely (fd >= acc.fdCount))
           return false;
         subr_subset_param_t  param;
         param.init (&parsed_charstrings[i],
                     &parsed_global_subrs,  &parsed_local_subrs[fd],
                     closures.global_closure, closures.local_closures[fd],
-                    drop_hints);
+                    plan->drop_hints);
 
         drop_hints_param_t  drop;
         if (drop_hints_in_str (parsed_charstrings[i], param, drop))
@@ -709,16 +673,19 @@
 
       /* after dropping hints recreate closures of actually used subrs */
       closures.reset ();
-      for (unsigned int i = 0; i < glyphs.length; i++)
+      for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
       {
-        unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
+        hb_codepoint_t  glyph;
+        if (!plan->old_gid_for_new_gid (i, &glyph))
+          continue;
+        unsigned int fd = acc.fdSelect->get_fd (glyph);
         if (unlikely (fd >= acc.fdCount))
           return false;
         subr_subset_param_t  param;
         param.init (&parsed_charstrings[i],
                     &parsed_global_subrs,  &parsed_local_subrs[fd],
                     closures.global_closure, closures.local_closures[fd],
-                    drop_hints);
+                    plan->drop_hints);
         collect_subr_refs_in_str (parsed_charstrings[i], param);
       }
     }
@@ -728,13 +695,20 @@
     return true;
   }
 
-  bool encode_charstrings (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, str_buff_vec_t &buffArray) const
+  bool encode_charstrings (str_buff_vec_t &buffArray) const
   {
-    if (unlikely (!buffArray.resize (glyphs.length)))
+    if (unlikely (!buffArray.resize (plan->num_output_glyphs ())))
       return false;
-    for (unsigned int i = 0; i < glyphs.length; i++)
+    for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
     {
-      unsigned int  fd = acc.fdSelect->get_fd (glyphs[i]);
+      hb_codepoint_t  glyph;
+      if (!plan->old_gid_for_new_gid (i, &glyph))
+      {
+        /* add an endchar only charstring for a missing glyph if CFF1 */
+        if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op);
+        continue;
+      }
+      unsigned int  fd = acc.fdSelect->get_fd (glyph);
       if (unlikely (fd >= acc.fdCount))
         return false;
       if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
@@ -745,7 +719,7 @@
 
   bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const
   {
-    unsigned int  count = remap.get_count ();
+    unsigned int  count = remap.get_population ();
 
     if (unlikely (!buffArray.resize (count)))
       return false;
@@ -777,10 +751,12 @@
     drop_hints_param_t ()
       : seen_moveto (false),
         ends_in_hint (false),
+        all_dropped (false),
         vsindex_dropped (false) {}
 
     bool  seen_moveto;
     bool  ends_in_hint;
+    bool  all_dropped;
     bool  vsindex_dropped;
   };
 
@@ -791,7 +767,7 @@
     drop.ends_in_hint = false;
     bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop);
 
-    /* if this subr ends with a stem hint (i.e., not a number a potential argument for moveto),
+    /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto),
      * then this entire subroutine must be a hint. drop its call. */
     if (drop.ends_in_hint)
     {
@@ -801,6 +777,10 @@
       if (!str.at_end (pos))
         drop.ends_in_hint = false;
     }
+    else if (drop.all_dropped)
+    {
+      str.values[pos].set_drop ();
+    }
 
     return has_hint;
   }
@@ -819,7 +799,6 @@
           has_hint = drop_hints_in_subr (str, pos,
                                         *param.parsed_local_subrs, str.values[pos].subr_num,
                                         param, drop);
-
           break;
 
         case OpCode_callgsubr:
@@ -876,6 +855,23 @@
       }
     }
 
+    /* Raise all_dropped flag if all operators except return are dropped from a subr.
+     * It may happen even after seeing the first moveto if a subr contains
+     * only (usually one) hintmask operator, then calls to this subr can be dropped.
+     */
+    drop.all_dropped = true;
+    for (unsigned int pos = 0; pos < str.values.length; pos++)
+    {
+      parsed_cs_op_t  &csop = str.values[pos];
+      if (csop.op == OpCode_return)
+        break;
+      if (!csop.for_drop ())
+      {
+        drop.all_dropped = false;
+        break;
+      }
+    }
+
     return seen_hint;
   }
 
@@ -884,7 +880,7 @@
                                   hb_set_t *closure,
                                   const subr_subset_param_t &param)
   {
-    hb_set_add (closure, subr_num);
+    closure->add (subr_num);
     collect_subr_refs_in_str (subrs[subr_num], param);
   }
 
@@ -954,13 +950,16 @@
   }
 
   protected:
-  subr_closures_t             closures;
+  const ACC                     &acc;
+  const hb_subset_plan_t        *plan;
 
-  parsed_cs_str_vec_t          parsed_charstrings;
-  parsed_cs_str_vec_t          parsed_global_subrs;
+  subr_closures_t               closures;
+
+  parsed_cs_str_vec_t           parsed_charstrings;
+  parsed_cs_str_vec_t           parsed_global_subrs;
   hb_vector_t<parsed_cs_str_vec_t>  parsed_local_subrs;
 
-  subr_remap_ts         remaps;
+  subr_remaps_t                 remaps;
 
   private:
   typedef typename SUBRS::count_type subr_count_type;
@@ -969,14 +968,14 @@
 } /* namespace CFF */
 
 HB_INTERNAL bool
-hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
+hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
                             unsigned int fdCount,
                             const CFF::FDSelect &src, /* IN */
                             unsigned int &subset_fd_count /* OUT */,
                             unsigned int &subset_fdselect_size /* OUT */,
                             unsigned int &subset_fdselect_format /* OUT */,
                             hb_vector_t<CFF::code_pair_t> &fdselect_ranges /* OUT */,
-                            CFF::remap_t &fdmap /* OUT */);
+                            hb_inc_bimap_t &fdmap /* OUT */);
 
 HB_INTERNAL bool
 hb_serialize_cff_fdselect (hb_serialize_context_t *c,
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc
index 7f35e5e..650c3ae 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc
@@ -24,9 +24,14 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_SUBSET_CFF
+
 #include "hb-open-type.hh"
 #include "hb-ot-cff1-table.hh"
 #include "hb-set.h"
+#include "hb-bimap.hh"
 #include "hb-subset-cff1.hh"
 #include "hb-subset-plan.hh"
 #include "hb-subset-cff-common.hh"
@@ -34,12 +39,12 @@
 
 using namespace CFF;
 
-struct remap_sid_t : remap_t
+struct remap_sid_t : hb_inc_bimap_t
 {
   unsigned int add (unsigned int sid)
   {
     if ((sid != CFF_UNDEF_SID) && !is_std_std (sid))
-      return offset_sid (remap_t::add (unoffset_sid (sid)));
+      return offset_sid (hb_inc_bimap_t::add (unoffset_sid (sid)));
     else
       return sid;
   }
@@ -49,7 +54,7 @@
     if (is_std_std (sid) || (sid == CFF_UNDEF_SID))
       return sid;
     else
-      return offset_sid (remap_t::operator [] (unoffset_sid (sid)));
+      return offset_sid (get (unoffset_sid (sid)));
   }
 
   static const unsigned int num_std_strings = 391;
@@ -59,29 +64,25 @@
   static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
 };
 
-struct cff1_sub_table_offsets_t : cff_sub_table_offsets_t
+struct cff1_sub_table_info_t : cff_sub_table_info_t
 {
-  cff1_sub_table_offsets_t ()
-    : cff_sub_table_offsets_t (),
-      nameIndexOffset (0),
-      encodingOffset (0)
-  {
-    stringIndexInfo.init ();
-    charsetInfo.init ();
+  cff1_sub_table_info_t ()
+    : cff_sub_table_info_t (),
+      encoding_link (0),
+      charset_link (0)
+   {
     privateDictInfo.init ();
   }
 
-  unsigned int  nameIndexOffset;
-  table_info_t  stringIndexInfo;
-  unsigned int  encodingOffset;
-  table_info_t  charsetInfo;
+  objidx_t      encoding_link;
+  objidx_t      charset_link;
   table_info_t  privateDictInfo;
 };
 
 /* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */
 struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t
 {
-  void init (const cff1_top_dict_values_t *base_= &Null(cff1_top_dict_values_t))
+  void init (const cff1_top_dict_values_t *base_= &Null (cff1_top_dict_values_t))
   {
     SUPER::init ();
     base = base_;
@@ -112,13 +113,13 @@
 
 struct top_dict_modifiers_t
 {
-  top_dict_modifiers_t (const cff1_sub_table_offsets_t &offsets_,
-                           const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount])
-    : offsets (offsets_),
+  top_dict_modifiers_t (const cff1_sub_table_info_t &info_,
+                        const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount])
+    : info (info_),
       nameSIDs (nameSIDs_)
   {}
 
-  const cff1_sub_table_offsets_t &offsets;
+  const cff1_sub_table_info_t &info;
   const unsigned int    (&nameSIDs)[name_dict_values_t::ValCount];
 };
 
@@ -134,22 +135,20 @@
     switch (op)
     {
       case OpCode_charset:
-        return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.charsetInfo.offset));
+        if (mod.info.charset_link)
+          return_trace (FontDict::serialize_link4_op(c, op, mod.info.charset_link, whence_t::Absolute));
+        else
+          goto fall_back;
 
       case OpCode_Encoding:
-        return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.encodingOffset));
+        if (mod.info.encoding_link)
+          return_trace (FontDict::serialize_link4_op(c, op, mod.info.encoding_link, whence_t::Absolute));
+        else
+          goto fall_back;
 
       case OpCode_Private:
-        {
-          if (unlikely (!UnsizedByteStr::serialize_int2 (c, mod.offsets.privateDictInfo.size)))
-            return_trace (false);
-          if (unlikely (!UnsizedByteStr::serialize_int4 (c, mod.offsets.privateDictInfo.offset)))
-            return_trace (false);
-          HBUINT8 *p = c->allocate_size<HBUINT8> (1);
-          if (unlikely (p == nullptr)) return_trace (false);
-          p->set (OpCode_Private);
-        }
-        break;
+        return_trace (UnsizedByteStr::serialize_int2 (c, mod.info.privateDictInfo.size) &&
+                      Dict::serialize_link4_op (c, op, mod.info.privateDictInfo.link, whence_t::Absolute));
 
       case OpCode_version:
       case OpCode_Notice:
@@ -160,7 +159,7 @@
       case OpCode_PostScript:
       case OpCode_BaseFontName:
       case OpCode_FontName:
-        return_trace (FontDict::serialize_offset2_op(c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)]));
+        return_trace (FontDict::serialize_int2_op (c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)]));
 
       case OpCode_ROS:
         {
@@ -175,86 +174,29 @@
                         UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) &&
                         copy_opstr (c, supp_op));
         }
+      fall_back:
       default:
-        return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.offsets));
+        return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.info));
     }
     return_trace (true);
   }
 
-  unsigned int calculate_serialized_size (const cff1_top_dict_val_t &opstr) const
-  {
-    op_code_t op = opstr.op;
-    switch (op)
-    {
-      case OpCode_charset:
-      case OpCode_Encoding:
-        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
-
-      case OpCode_Private:
-        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
-
-      case OpCode_version:
-      case OpCode_Notice:
-      case OpCode_Copyright:
-      case OpCode_FullName:
-      case OpCode_FamilyName:
-      case OpCode_Weight:
-      case OpCode_PostScript:
-      case OpCode_BaseFontName:
-      case OpCode_FontName:
-        return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op);
-
-      case OpCode_ROS:
-        return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.length - opstr.last_arg_offset)/* supplement + op */;
-
-      default:
-        return cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::calculate_serialized_size (opstr);
-    }
-  }
-};
-
-struct font_dict_values_mod_t
-{
-  void init (const cff1_font_dict_values_t *base_,
-             unsigned int fontName_,
-             const table_info_t &privateDictInfo_)
-  {
-    base = base_;
-    fontName = fontName_;
-    privateDictInfo = privateDictInfo_;
-  }
-
-  unsigned get_count () const { return base->get_count (); }
-
-  const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; }
-
-  const cff1_font_dict_values_t    *base;
-  table_info_t             privateDictInfo;
-  unsigned int          fontName;
 };
 
 struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t
 {
   bool serialize (hb_serialize_context_t *c,
                   const op_str_t &opstr,
-                  const font_dict_values_mod_t &mod) const
+                  const cff1_font_dict_values_mod_t &mod) const
   {
     TRACE_SERIALIZE (this);
 
     if (opstr.op == OpCode_FontName)
-      return_trace (FontDict::serialize_uint2_op (c, opstr.op, mod.fontName));
+      return_trace (FontDict::serialize_int2_op (c, opstr.op, mod.fontName));
     else
       return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo));
   }
 
-  unsigned int calculate_serialized_size (const op_str_t &opstr) const
-  {
-    if (opstr.op == OpCode_FontName)
-      return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName);
-    else
-      return SUPER::calculate_serialized_size (opstr);
-  }
-
   private:
   typedef cff_font_dict_op_serializer_t SUPER;
 };
@@ -326,7 +268,7 @@
 struct range_list_t : hb_vector_t<code_pair_t>
 {
   /* replace the first glyph ID in the "glyph" field each range with a nLeft value */
-  bool finalize (unsigned int last_glyph)
+  bool complete (unsigned int last_glyph)
   {
     bool  two_byte = false;
     for (unsigned int i = (*this).length; i > 0; i--)
@@ -351,7 +293,7 @@
       case OpCode_return:
         param.current_parsed_str->add_op (op, env.str_ref);
         param.current_parsed_str->set_parsed ();
-        env.returnFromSubr ();
+        env.return_from_subr ();
         param.set_current_str (env, false);
         break;
 
@@ -382,9 +324,9 @@
                                  cff1_biased_subrs_t& subrs, hb_set_t *closure)
   {
     byte_str_ref_t    str_ref = env.str_ref;
-    env.callSubr (subrs, type);
+    env.call_subr (subrs, type);
     param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num);
-    hb_set_add (closure, env.context.subr_num);
+    closure->add (env.context.subr_num);
     param.set_current_str (env, true);
   }
 
@@ -392,9 +334,12 @@
   typedef cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
 };
 
-struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs, const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t>
+struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs, const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, OpCode_endchar>
 {
-  static void finalize_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
+  cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
+    : subr_subsetter_t (acc_, plan_) {}
+
+  static void complete_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
   {
     /* insert width at the beginning of the charstring as necessary */
     if (env.has_width)
@@ -406,8 +351,8 @@
     param.current_parsed_str->set_parsed ();
     for (unsigned int i = 0; i < env.callStack.get_count (); i++)
     {
-      parsed_cs_str_t  *parsed_str = param.get_parsed_str_for_context (env.callStack[i]);
-      if (likely (parsed_str != nullptr))
+      parsed_cs_str_t *parsed_str = param.get_parsed_str_for_context (env.callStack[i]);
+      if (likely (parsed_str))
         parsed_str->set_parsed ();
       else
         env.set_error ();
@@ -417,16 +362,13 @@
 
 struct cff_subset_plan {
   cff_subset_plan ()
-    : final_size (0),
-      offsets (),
+    : info (),
       orig_fdcount (0),
       subset_fdcount (1),
       subset_fdselect_format (0),
       drop_hints (false),
       desubroutinize(false)
   {
-    topdict_sizes.init ();
-    topdict_sizes.resize (1);
     topdict_mod.init ();
     subset_fdselect_ranges.init ();
     fdmap.init ();
@@ -444,7 +386,6 @@
 
   ~cff_subset_plan ()
   {
-    topdict_sizes.fini ();
     topdict_mod.fini ();
     subset_fdselect_ranges.fini ();
     fdmap.fini ();
@@ -458,39 +399,49 @@
     sidmap.fini ();
   }
 
-  unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
+  void plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
   {
     const Encoding *encoding = acc.encoding;
     unsigned int  size0, size1, supp_size;
     hb_codepoint_t  code, last_code = CFF_UNDEF_CODE;
     hb_vector_t<hb_codepoint_t> supp_codes;
 
-    subset_enc_code_ranges.resize (0);
+    if (unlikely (!subset_enc_code_ranges.resize (0)))
+    {
+      plan->check_success (false);
+      return;
+    }
+
     supp_size = 0;
     supp_codes.init ();
 
-    subset_enc_num_codes = plan->glyphs.length - 1;
+    subset_enc_num_codes = plan->num_output_glyphs () - 1;
     unsigned int glyph;
-    for (glyph = 1; glyph < plan->glyphs.length; glyph++)
+    for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
     {
-      hb_codepoint_t  orig_glyph = plan->glyphs[glyph];
-      code = acc.glyph_to_code (orig_glyph);
+      hb_codepoint_t  old_glyph;
+      if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+      {
+        /* Retain the code for the old missing glyph ID */
+        old_glyph = glyph;
+      }
+      code = acc.glyph_to_code (old_glyph);
       if (code == CFF_UNDEF_CODE)
       {
         subset_enc_num_codes = glyph - 1;
         break;
       }
 
-      if (code != last_code + 1)
+      if ((last_code == CFF_UNDEF_CODE) || (code != last_code + 1))
       {
         code_pair_t pair = { code, glyph };
         subset_enc_code_ranges.push (pair);
       }
       last_code = code;
 
-      if (encoding != &Null(Encoding))
+      if (encoding != &Null (Encoding))
       {
-        hb_codepoint_t  sid = acc.glyph_to_sid (orig_glyph);
+        hb_codepoint_t  sid = acc.glyph_to_sid (old_glyph);
         encoding->get_supplement_codes (sid, supp_codes);
         for (unsigned int i = 0; i < supp_codes.length; i++)
         {
@@ -502,7 +453,7 @@
     }
     supp_codes.fini ();
 
-    subset_enc_code_ranges.finalize (glyph);
+    subset_enc_code_ranges.complete (glyph);
 
     assert (subset_enc_num_codes <= 0xFF);
     size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
@@ -512,29 +463,34 @@
       subset_enc_format = 0;
     else
       subset_enc_format = 1;
-
-    return Encoding::calculate_serialized_size (
-                        subset_enc_format,
-                        subset_enc_format? subset_enc_code_ranges.length: subset_enc_num_codes,
-                        subset_enc_supp_codes.length);
   }
 
-  unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
+  void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
   {
     unsigned int  size0, size_ranges;
     hb_codepoint_t  sid, last_sid = CFF_UNDEF_CODE;
 
-    subset_charset_ranges.resize (0);
-    unsigned int glyph;
-    for (glyph = 1; glyph < plan->glyphs.length; glyph++)
+    if (unlikely (!subset_charset_ranges.resize (0)))
     {
-      hb_codepoint_t  orig_glyph = plan->glyphs[glyph];
-      sid = acc.glyph_to_sid (orig_glyph);
+      plan->check_success (false);
+      return;
+    }
+
+    unsigned int glyph;
+    for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
+    {
+      hb_codepoint_t  old_glyph;
+      if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+      {
+        /* Retain the SID for the old missing glyph ID */
+        old_glyph = glyph;
+      }
+      sid = acc.glyph_to_sid (old_glyph);
 
       if (!acc.is_CID ())
         sid = sidmap.add (sid);
 
-      if (sid != last_sid + 1)
+      if ((last_sid == CFF_UNDEF_CODE) || (sid != last_sid + 1))
       {
         code_pair_t pair = { sid, glyph };
         subset_charset_ranges.push (pair);
@@ -542,9 +498,9 @@
       last_sid = sid;
     }
 
-    bool two_byte = subset_charset_ranges.finalize (glyph);
+    bool two_byte = subset_charset_ranges.complete (glyph);
 
-    size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.length - 1);
+    size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1);
     if (!two_byte)
       size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
     else
@@ -556,16 +512,11 @@
       subset_charset_format = 1;
     else
       subset_charset_format = 2;
-
-    return Charset::calculate_serialized_size (
-                        subset_charset_format,
-                        subset_charset_format? subset_charset_ranges.length: plan->glyphs.length);
   }
 
   bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
   {
-    if (unlikely (!sidmap.reset (acc.stringIndex->count)))
-      return false;
+    sidmap.reset ();
 
     for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
     {
@@ -577,31 +528,33 @@
       }
     }
 
-    if (acc.fdArray != &Null(CFF1FDArray))
+    if (acc.fdArray != &Null (CFF1FDArray))
       for (unsigned int i = 0; i < orig_fdcount; i++)
-        if (fdmap.includes (i))
+        if (fdmap.has (i))
           (void)sidmap.add (acc.fontDicts[i].fontName);
 
     return true;
   }
 
   bool create (const OT::cff1::accelerator_subset_t &acc,
-                      hb_subset_plan_t *plan)
+               hb_subset_plan_t *plan)
   {
-     /* make sure notdef is first */
-    if ((plan->glyphs.length == 0) || (plan->glyphs[0] != 0)) return false;
+    /* make sure notdef is first */
+    hb_codepoint_t old_glyph;
+    if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
 
-    final_size = 0;
-    num_glyphs = plan->glyphs.length;
+    num_glyphs = plan->num_output_glyphs ();
     orig_fdcount = acc.fdCount;
     drop_hints = plan->drop_hints;
     desubroutinize = plan->desubroutinize;
 
     /* check whether the subset renumbers any glyph IDs */
     gid_renum = false;
-    for (unsigned int glyph = 0; glyph < plan->glyphs.length; glyph++)
+    for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++)
     {
-      if (plan->glyphs[glyph] != glyph) {
+      if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph))
+        continue;
+      if (new_glyph != old_glyph) {
         gid_renum = true;
         break;
       }
@@ -610,13 +563,6 @@
     subset_charset = gid_renum || !acc.is_predef_charset ();
     subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
 
-    /* CFF header */
-    final_size += OT::cff1::static_size;
-
-    /* Name INDEX */
-    offsets.nameIndexOffset = final_size;
-    final_size += acc.nameIndex->get_size ();
-
     /* top dict INDEX */
     {
       /* Add encoding/charset to a (copy of) top dict as necessary */
@@ -630,25 +576,16 @@
         if (need_to_add_set)
           topdict_mod.add_op (OpCode_charset);
       }
-      offsets.topDictInfo.offset = final_size;
-      cff1_top_dict_op_serializer_t topSzr;
-      unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr);
-      offsets.topDictInfo.offSize = calcOffSize(topDictSize);
-      if (unlikely (offsets.topDictInfo.offSize > 4))
-        return false;
-      final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<cff1_top_dict_values_mod_t>
-                                                (offsets.topDictInfo.offSize,
-                                                 &topdict_mod, 1, topdict_sizes, topSzr);
     }
 
     /* Determine re-mapping of font index as fdmap among other info */
-    if (acc.fdSelect != &Null(CFF1FDSelect))
+    if (acc.fdSelect != &Null (CFF1FDSelect))
     {
-        if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
+        if (unlikely (!hb_plan_subset_cff_fdselect (plan,
                                   orig_fdcount,
                                   *acc.fdSelect,
                                   subset_fdcount,
-                                  offsets.FDSelectInfo.size,
+                                  info.fd_select.size,
                                   subset_fdselect_format,
                                   subset_fdselect_ranges,
                                   fdmap)))
@@ -662,170 +599,79 @@
       /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */
       if (unlikely (!collect_sids_in_dicts (acc)))
         return false;
-      if (unlikely (sidmap.get_count () > 0x8000))      /* assumption: a dict won't reference that many strings */
+      if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */
         return false;
-      if (subset_charset)
-        offsets.charsetInfo.size = plan_subset_charset (acc, plan);
+
+      if (subset_charset) plan_subset_charset (acc, plan);
 
       topdict_mod.reassignSIDs (sidmap);
     }
 
-    /* String INDEX */
-    {
-      offsets.stringIndexInfo.offset = final_size;
-      offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap);
-      final_size += offsets.stringIndexInfo.size;
-    }
-
     if (desubroutinize)
     {
       /* Flatten global & local subrs */
-      subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t>
-                    flattener(acc, plan->glyphs, plan->drop_hints);
+      subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, OpCode_endchar>
+                    flattener(acc, plan);
       if (!flattener.flatten (subset_charstrings))
         return false;
-
-      /* no global/local subroutines */
-      offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0);
     }
     else
     {
+      cff1_subr_subsetter_t       subr_subsetter (acc, plan);
+
       /* Subset subrs: collect used subroutines, leaving all unused ones behind */
-      if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints))
+      if (!subr_subsetter.subset ())
         return false;
 
       /* encode charstrings, global subrs, local subrs with new subroutine numbers */
-      if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings))
+      if (!subr_subsetter.encode_charstrings (subset_charstrings))
         return false;
 
       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
         return false;
 
-      /* global subrs */
-      unsigned int dataSize = subset_globalsubrs.total_size ();
-      offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
-      if (unlikely (offsets.globalSubrsInfo.offSize > 4))
-        return false;
-      offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize);
-
       /* local subrs */
-      if (!offsets.localSubrsInfos.resize (orig_fdcount))
-        return false;
       if (!subset_localsubrs.resize (orig_fdcount))
         return false;
       for (unsigned int fd = 0; fd < orig_fdcount; fd++)
       {
         subset_localsubrs[fd].init ();
-        offsets.localSubrsInfos[fd].init ();
-        if (fdmap.includes (fd))
+        if (fdmap.has (fd))
         {
           if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
             return false;
-
-          unsigned int dataSize = subset_localsubrs[fd].total_size ();
-          if (dataSize > 0)
-          {
-            offsets.localSubrsInfos[fd].offset = final_size;
-            offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
-            if (unlikely (offsets.localSubrsInfos[fd].offSize > 4))
-              return false;
-            offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize);
-          }
         }
       }
     }
 
-    /* global subrs */
-    offsets.globalSubrsInfo.offset = final_size;
-    final_size += offsets.globalSubrsInfo.size;
-
     /* Encoding */
-    if (!subset_encoding)
-      offsets.encodingOffset = acc.topDict.EncodingOffset;
-    else
-    {
-      offsets.encodingOffset = final_size;
-      final_size += plan_subset_encoding (acc, plan);
-    }
-
-    /* Charset */
-    if (!subset_charset && acc.is_predef_charset ())
-      offsets.charsetInfo.offset = acc.topDict.CharsetOffset;
-    else
-      offsets.charsetInfo.offset = final_size;
-    final_size += offsets.charsetInfo.size;
-
-    /* FDSelect */
-    if (acc.fdSelect != &Null(CFF1FDSelect))
-    {
-      offsets.FDSelectInfo.offset = final_size;
-      final_size += offsets.FDSelectInfo.size;
-    }
-
-    /* FDArray (FDIndex) */
-    if (acc.fdArray != &Null(CFF1FDArray)) {
-      offsets.FDArrayInfo.offset = final_size;
-      cff1_font_dict_op_serializer_t fontSzr;
-      unsigned int dictsSize = 0;
-      for (unsigned int i = 0; i < acc.fontDicts.length; i++)
-        if (fdmap.includes (i))
-          dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
-
-      offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
-      if (unlikely (offsets.FDArrayInfo.offSize > 4))
-        return false;
-      final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
-    }
-
-    /* CharStrings */
-    {
-      offsets.charStringsInfo.offset = final_size;
-      unsigned int dataSize = subset_charstrings.total_size ();
-      offsets.charStringsInfo.offSize = calcOffSize (dataSize);
-      if (unlikely (offsets.charStringsInfo.offSize > 4))
-        return false;
-      final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize);
-    }
+    if (subset_encoding)
+      plan_subset_encoding (acc, plan);
 
     /* private dicts & local subrs */
-    offsets.privateDictInfo.offset = final_size;
-    for (unsigned int i = 0; i < orig_fdcount; i++)
+    if (!acc.is_CID ())
+      fontdicts_mod.push (cff1_font_dict_values_mod_t ());
+    else
     {
-      if (fdmap.includes (i))
-      {
-        bool  has_localsubrs = offsets.localSubrsInfos[i].size > 0;
-        cff_private_dict_op_serializer_t privSzr (desubroutinize, plan->drop_hints);
-        unsigned int  priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
-        table_info_t  privInfo = { final_size, priv_size, 0 };
-        font_dict_values_mod_t fontdict_mod;
-        if (!acc.is_CID ())
-          fontdict_mod.init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID, privInfo );
-        else
-          fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo );
-        fontdicts_mod.push (fontdict_mod);
-        final_size += privInfo.size;
-
-        if (!plan->desubroutinize && has_localsubrs)
+      + hb_iter (acc.fontDicts)
+      | hb_filter ([&] (const cff1_font_dict_values_t &_)
+        { return fdmap.has (&_ - &acc.fontDicts[0]); } )
+      | hb_map ([&] (const cff1_font_dict_values_t &_)
         {
-          offsets.localSubrsInfos[i].offset = final_size;
-          final_size += offsets.localSubrsInfos[i].size;
-        }
-      }
+          cff1_font_dict_values_mod_t mod;
+          mod.init (&_, sidmap[_.fontName]);
+          return mod;
+        })
+      | hb_sink (fontdicts_mod)
+      ;
     }
 
-    if (!acc.is_CID ())
-      offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
-
-    return ((subset_charstrings.length == plan->glyphs.length)
+    return ((subset_charstrings.length == plan->num_output_glyphs ())
            && (fontdicts_mod.length == subset_fdcount));
   }
 
-  unsigned int get_final_size () const  { return final_size; }
-
-  unsigned int        final_size;
-  hb_vector_t<unsigned int>     topdict_sizes;
   cff1_top_dict_values_mod_t    topdict_mod;
-  cff1_sub_table_offsets_t      offsets;
+  cff1_sub_table_info_t         info;
 
   unsigned int    num_glyphs;
   unsigned int    orig_fdcount;
@@ -835,12 +681,12 @@
 
   /* font dict index remap table from fullset FDArray to subset FDArray.
    * set to CFF_UNDEF_CODE if excluded from subset */
-  remap_t   fdmap;
+  hb_inc_bimap_t   fdmap;
 
   str_buff_vec_t                subset_charstrings;
   str_buff_vec_t                subset_globalsubrs;
   hb_vector_t<str_buff_vec_t>   subset_localsubrs;
-  hb_vector_t<font_dict_values_mod_t>  fontdicts_mod;
+  hb_vector_t<cff1_font_dict_values_mod_t>  fontdicts_mod;
 
   bool          drop_hints;
 
@@ -859,94 +705,97 @@
   unsigned int  topDictModSIDs[name_dict_values_t::ValCount];
 
   bool          desubroutinize;
-  cff1_subr_subsetter_t       subr_subsetter;
 };
 
-static inline bool _write_cff1 (const cff_subset_plan &plan,
-                                const OT::cff1::accelerator_subset_t  &acc,
-                                const hb_vector_t<hb_codepoint_t>& glyphs,
-                                unsigned int dest_sz,
-                                void *dest)
+static bool _serialize_cff1 (hb_serialize_context_t *c,
+                             cff_subset_plan &plan,
+                             const OT::cff1::accelerator_subset_t  &acc,
+                             unsigned int num_glyphs)
 {
-  hb_serialize_context_t c (dest, dest_sz);
-
-  OT::cff1 *cff = c.start_serialize<OT::cff1> ();
-  if (unlikely (!c.extend_min (*cff)))
-    return false;
-
-  /* header */
-  cff->version.major.set (0x01);
-  cff->version.minor.set (0x00);
-  cff->nameIndex.set (cff->min_size);
-  cff->offSize.set (4); /* unused? */
-
-  /* name INDEX */
+  /* private dicts & local subrs */
+  for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
   {
-    assert (cff->nameIndex == (unsigned) (c.head - c.start));
-    CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
+    if (plan.fdmap.has (i))
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX");
+      objidx_t  subrs_link = 0;
+      if (plan.subset_localsubrs[i].length > 0)
+      {
+        CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
+        if (unlikely (!dest)) return false;
+        c->push ();
+        if (likely (dest && dest->serialize (c, plan.subset_localsubrs[i])))
+          subrs_link = c->pop_pack ();
+        else
+        {
+          c->pop_discard ();
+          return false;
+        }
+      }
+
+      PrivateDict *pd = c->start_embed<PrivateDict> ();
+      if (unlikely (!pd)) return false;
+      c->push ();
+      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
+      /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
+      if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link)))
+      {
+        unsigned fd = plan.fdmap[i];
+        plan.fontdicts_mod[fd].privateDictInfo.size = c->length ();
+        plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack ();
+      }
+      else
+      {
+        c->pop_discard ();
+        return false;
+      }
+    }
+  }
+
+  if (!acc.is_CID ())
+    plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo;
+
+  /* CharStrings */
+  {
+    CFF1CharStrings  *cs = c->start_embed<CFF1CharStrings> ();
+    if (unlikely (!cs)) return false;
+    c->push ();
+    if (likely (cs->serialize (c, plan.subset_charstrings)))
+      plan.info.char_strings_link = c->pop_pack ();
+    else
+    {
+      c->pop_discard ();
       return false;
     }
   }
 
-  /* top dict INDEX */
+  /* FDArray (FD Index) */
+  if (acc.fdArray != &Null (CFF1FDArray))
   {
-    assert (plan.offsets.topDictInfo.offset == (unsigned) (c.head - c.start));
-    CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
-    if (dest == nullptr) return false;
-    cff1_top_dict_op_serializer_t topSzr;
-    top_dict_modifiers_t  modifier (plan.offsets, plan.topDictModSIDs);
-    if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize,
-                                    &plan.topdict_mod, 1,
-                                    plan.topdict_sizes, topSzr, modifier)))
+    CFF1FDArray *fda = c->start_embed<CFF1FDArray> ();
+    if (unlikely (!fda)) return false;
+    c->push ();
+    cff1_font_dict_op_serializer_t  fontSzr;
+    auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod));
+    if (likely (fda->serialize (c, it, fontSzr)))
+      plan.info.fd_array_link = c->pop_pack (false);
+    else
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
+      c->pop_discard ();
       return false;
     }
   }
 
-  /* String INDEX */
+  /* FDSelect */
+  if (acc.fdSelect != &Null (CFF1FDSelect))
   {
-    assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c.head - c.start));
-    CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap)))
+    c->push ();
+    if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount,
+                                           plan.subset_fdselect_format, plan.info.fd_select.size,
+                                           plan.subset_fdselect_ranges)))
+      plan.info.fd_select.link = c->pop_pack ();
+    else
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
-      return false;
-    }
-  }
-
-  /* global subrs */
-  {
-    assert (plan.offsets.globalSubrsInfo.offset != 0);
-    assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c.head - c.start));
-
-    CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
-      return false;
-    }
-  }
-
-  /* Encoding */
-  if (plan.subset_encoding)
-  {
-    assert (plan.offsets.encodingOffset == (unsigned) (c.head - c.start));
-    Encoding *dest = c.start_embed<Encoding> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c,
-                                    plan.subset_enc_format,
-                                    plan.subset_enc_num_codes,
-                                    plan.subset_enc_code_ranges,
-                                    plan.subset_enc_supp_codes)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding");
+      c->pop_discard ();
       return false;
     }
   }
@@ -954,129 +803,120 @@
   /* Charset */
   if (plan.subset_charset)
   {
-    assert (plan.offsets.charsetInfo.offset == (unsigned) (c.head - c.start));
-    Charset *dest = c.start_embed<Charset> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c,
-                                    plan.subset_charset_format,
-                                    plan.num_glyphs,
-                                    plan.subset_charset_ranges)))
+    Charset *dest = c->start_embed<Charset> ();
+    if (unlikely (!dest)) return false;
+    c->push ();
+    if (likely (dest->serialize (c,
+                                 plan.subset_charset_format,
+                                 plan.num_glyphs,
+                                 plan.subset_charset_ranges)))
+      plan.info.charset_link = c->pop_pack ();
+    else
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset");
+      c->pop_discard ();
       return false;
     }
   }
 
-  /* FDSelect */
-  if (acc.fdSelect != &Null(CFF1FDSelect))
+  /* Encoding */
+  if (plan.subset_encoding)
   {
-    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
-
-    if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *acc.fdSelect, acc.fdCount,
-                                              plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
-                                              plan.subset_fdselect_ranges)))
+    Encoding *dest = c->start_embed<Encoding> ();
+    if (unlikely (!dest)) return false;
+    c->push ();
+    if (likely (dest->serialize (c,
+                                 plan.subset_enc_format,
+                                 plan.subset_enc_num_codes,
+                                 plan.subset_enc_code_ranges,
+                                 plan.subset_enc_supp_codes)))
+      plan.info.encoding_link = c->pop_pack ();
+    else
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect");
+      c->pop_discard ();
       return false;
     }
   }
 
-  /* FDArray (FD Index) */
-  if (acc.fdArray != &Null(CFF1FDArray))
+  /* global subrs */
   {
-    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
-    CFF1FDArray  *fda = c.start_embed<CFF1FDArray> ();
-    if (unlikely (fda == nullptr)) return false;
-    cff1_font_dict_op_serializer_t  fontSzr;
-    if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
-                                   plan.fontdicts_mod,
-                                   fontSzr)))
+    c->push ();
+    CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
+    if (unlikely (!dest)) return false;
+    if (likely (dest->serialize (c, plan.subset_globalsubrs)))
+      c->pop_pack ();
+    else
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
+      c->pop_discard ();
       return false;
     }
   }
 
-  /* CharStrings */
+  /* String INDEX */
   {
-    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
-    CFF1CharStrings  *cs = c.start_embed<CFF1CharStrings> ();
-    if (unlikely (cs == nullptr)) return false;
-    if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
+    CFF1StringIndex *dest = c->start_embed<CFF1StringIndex> ();
+    if (unlikely (!dest)) return false;
+    c->push ();
+    if (likely (dest->serialize (c, *acc.stringIndex, plan.sidmap)))
+      c->pop_pack ();
+    else
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings");
+      c->pop_discard ();
       return false;
     }
   }
 
-  /* private dicts & local subrs */
-  assert (plan.offsets.privateDictInfo.offset == (unsigned) (c.head - c.start));
-  for (unsigned int i = 0; i < acc.privateDicts.length; i++)
+  OT::cff1 *cff = c->allocate_min<OT::cff1> ();
+  if (unlikely (!cff))
+    return false;
+
+  /* header */
+  cff->version.major = 0x01;
+  cff->version.minor = 0x00;
+  cff->nameIndex = cff->min_size;
+  cff->offSize = 4; /* unused? */
+
+  /* name INDEX */
+  if (unlikely (!(*acc.nameIndex).copy (c))) return false;
+
+  /* top dict INDEX */
   {
-    if (plan.fdmap.includes (i))
+    /* serialize singleton TopDict */
+    TopDict *top = c->start_embed<TopDict> ();
+    if (!top) return false;
+    c->push ();
+    cff1_top_dict_op_serializer_t topSzr;
+    unsigned top_size = 0;
+    top_dict_modifiers_t  modifier (plan.info, plan.topDictModSIDs);
+    if (likely (top->serialize (c, plan.topdict_mod, topSzr, modifier)))
     {
-      PrivateDict  *pd = c.start_embed<PrivateDict> ();
-      if (unlikely (pd == nullptr)) return false;
-      unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size;
-      bool result;
-      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
-      /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
-      unsigned int  subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0;
-      result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
-      if (unlikely (!result))
-      {
-        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
-        return false;
-      }
-      if (plan.offsets.localSubrsInfos[i].size > 0)
-      {
-        CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
-        if (unlikely (dest == nullptr)) return false;
-        if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i])))
-        {
-          DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines");
-          return false;
-        }
-      }
+      top_size = c->length ();
+      c->pop_pack (false);
     }
+    else
+    {
+      c->pop_discard ();
+      return false;
+    }
+    /* serialize INDEX header for above */
+    CFF1Index *dest = c->start_embed<CFF1Index> ();
+    if (!dest) return false;
+    return dest->serialize_header (c, hb_iter (hb_array_t<unsigned> (&top_size, 1)));
   }
-
-  assert (c.head == c.end);
-  c.end_serialize ();
-
-  return true;
 }
 
 static bool
 _hb_subset_cff1 (const OT::cff1::accelerator_subset_t  &acc,
-                const char              *data,
-                hb_subset_plan_t        *plan,
-                hb_blob_t               **prime /* OUT */)
+                hb_subset_context_t     *c)
 {
   cff_subset_plan cff_plan;
 
-  if (unlikely (!cff_plan.create (acc, plan)))
+  if (unlikely (!cff_plan.create (acc, c->plan)))
   {
     DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
     return false;
   }
 
-  unsigned int  cff_prime_size = cff_plan.get_final_size ();
-  char *cff_prime_data = (char *) calloc (1, cff_prime_size);
-
-  if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs,
-                              cff_prime_size, cff_prime_data))) {
-    DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
-    free (cff_prime_data);
-    return false;
-  }
-
-  *prime = hb_blob_create (cff_prime_data,
-                           cff_prime_size,
-                           HB_MEMORY_MODE_READONLY,
-                           cff_prime_data,
-                           free);
-  return true;
+  return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ());
 }
 
 /**
@@ -1086,18 +926,15 @@
  * Return value: subsetted cff table.
  **/
 bool
-hb_subset_cff1 (hb_subset_plan_t *plan,
-                hb_blob_t       **prime /* OUT */)
+hb_subset_cff1 (hb_subset_context_t *c)
 {
-  hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff1> (plan->source);
-  const char *data = hb_blob_get_data(cff_blob, nullptr);
-
   OT::cff1::accelerator_subset_t acc;
-  acc.init(plan->source);
-  bool result = likely (acc.is_valid ()) &&
-                        _hb_subset_cff1 (acc, data, plan, prime);
-  hb_blob_destroy (cff_blob);
+  acc.init (c->plan->source);
+  bool result = likely (acc.is_valid ()) && _hb_subset_cff1 (acc, c);
   acc.fini ();
 
   return result;
 }
+
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.hh
index 33a6638..aaf5def 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.hh
@@ -32,7 +32,6 @@
 #include "hb-subset-plan.hh"
 
 HB_INTERNAL bool
-hb_subset_cff1 (hb_subset_plan_t *plan,
-               hb_blob_t        **cff_prime /* OUT */);
+hb_subset_cff1 (hb_subset_context_t *c);
 
 #endif /* HB_SUBSET_CFF1_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc
index ec69ed6..6f1b4a7 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc
@@ -24,6 +24,10 @@
  * Adobe Author(s): Michiharu Ariza
  */
 
+#include "hb.hh"
+
+#ifndef HB_NO_SUBSET_CFF
+
 #include "hb-open-type.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-set.h"
@@ -34,43 +38,31 @@
 
 using namespace CFF;
 
-struct cff2_sub_table_offsets_t : cff_sub_table_offsets_t
+struct cff2_sub_table_info_t : cff_sub_table_info_t
 {
-  cff2_sub_table_offsets_t ()
-    : cff_sub_table_offsets_t (),
-      varStoreOffset (0)
+  cff2_sub_table_info_t ()
+    : cff_sub_table_info_t (),
+      var_store_link (0)
   {}
 
-  unsigned int  varStoreOffset;
+  objidx_t  var_store_link;
 };
 
 struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<>
 {
   bool serialize (hb_serialize_context_t *c,
                   const op_str_t &opstr,
-                  const cff2_sub_table_offsets_t &offsets) const
+                  const cff2_sub_table_info_t &info) const
   {
     TRACE_SERIALIZE (this);
 
     switch (opstr.op)
     {
       case OpCode_vstore:
-        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset));
+        return_trace (FontDict::serialize_link4_op(c, opstr.op, info.var_store_link));
 
       default:
-        return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, offsets));
-    }
-  }
-
-  unsigned int calculate_serialized_size (const op_str_t &opstr) const
-  {
-    switch (opstr.op)
-    {
-      case OpCode_vstore:
-        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
-
-      default:
-        return cff_top_dict_op_serializer_t<>::calculate_serialized_size (opstr);
+        return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, info));
     }
   }
 };
@@ -183,7 +175,7 @@
 
       case OpCode_return:
         param.current_parsed_str->set_parsed ();
-        env.returnFromSubr ();
+        env.return_from_subr ();
         param.set_current_str (env, false);
         break;
 
@@ -213,9 +205,9 @@
                                  cff2_biased_subrs_t& subrs, hb_set_t *closure)
   {
     byte_str_ref_t    str_ref = env.str_ref;
-    env.callSubr (subrs, type);
+    env.call_subr (subrs, type);
     param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num);
-    hb_set_add (closure, env.context.subr_num);
+    closure->add (env.context.subr_num);
     param.set_current_str (env, true);
   }
 
@@ -225,7 +217,10 @@
 
 struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t>
 {
-  static void finalize_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
+  cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
+    : subr_subsetter_t (acc_, plan_) {}
+
+  static void complete_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
   {
     /* vsindex is inserted at the beginning of the charstring as necessary */
     if (env.seen_vsindex ())
@@ -239,9 +234,9 @@
 
 struct cff2_subset_plan {
   cff2_subset_plan ()
-    : final_size (0),
-      orig_fdcount (0),
+    : orig_fdcount (0),
       subset_fdcount(1),
+      subset_fdselect_size (0),
       subset_fdselect_format (0),
       drop_hints (false),
       desubroutinize (false)
@@ -251,7 +246,6 @@
     subset_charstrings.init ();
     subset_globalsubrs.init ();
     subset_localsubrs.init ();
-    privateDictInfos.init ();
   }
 
   ~cff2_subset_plan ()
@@ -261,364 +255,234 @@
     subset_charstrings.fini_deep ();
     subset_globalsubrs.fini_deep ();
     subset_localsubrs.fini_deep ();
-    privateDictInfos.fini ();
   }
 
   bool create (const OT::cff2::accelerator_subset_t &acc,
               hb_subset_plan_t *plan)
   {
-    final_size = 0;
     orig_fdcount = acc.fdArray->count;
 
     drop_hints = plan->drop_hints;
     desubroutinize = plan->desubroutinize;
 
-    /* CFF2 header */
-    final_size += OT::cff2::static_size;
-
-    /* top dict */
-    {
-      cff2_top_dict_op_serializer_t topSzr;
-      offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr);
-      final_size += offsets.topDictInfo.size;
-    }
-
     if (desubroutinize)
     {
       /* Flatten global & local subrs */
       subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t>
-                    flattener(acc, plan->glyphs, plan->drop_hints);
+                    flattener(acc, plan);
       if (!flattener.flatten (subset_charstrings))
         return false;
-
-      /* no global/local subroutines */
-      offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (1, 0, 0);
     }
     else
     {
+      cff2_subr_subsetter_t     subr_subsetter (acc, plan);
+
       /* Subset subrs: collect used subroutines, leaving all unused ones behind */
-      if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints))
+      if (!subr_subsetter.subset ())
         return false;
 
       /* encode charstrings, global subrs, local subrs with new subroutine numbers */
-      if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings))
+      if (!subr_subsetter.encode_charstrings (subset_charstrings))
         return false;
 
       if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
         return false;
 
-      /* global subrs */
-      unsigned int dataSize = subset_globalsubrs.total_size ();
-      offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
-      offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize);
-
       /* local subrs */
-      if (!offsets.localSubrsInfos.resize (orig_fdcount))
-        return false;
       if (!subset_localsubrs.resize (orig_fdcount))
         return false;
       for (unsigned int fd = 0; fd < orig_fdcount; fd++)
       {
         subset_localsubrs[fd].init ();
-        offsets.localSubrsInfos[fd].init ();
-        if (fdmap.includes (fd))
-        {
-          if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
-            return false;
-
-          unsigned int dataSize = subset_localsubrs[fd].total_size ();
-          if (dataSize > 0)
-          {
-            offsets.localSubrsInfos[fd].offset = final_size;
-            offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
-            offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize);
-          }
-        }
+        if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
+          return false;
       }
     }
 
-    /* global subrs */
-    offsets.globalSubrsInfo.offset = final_size;
-    final_size += offsets.globalSubrsInfo.size;
-
-    /* variation store */
-    if (acc.varStore != &Null(CFF2VariationStore))
-    {
-      offsets.varStoreOffset = final_size;
-      final_size += acc.varStore->get_size ();
-    }
-
     /* FDSelect */
-    if (acc.fdSelect != &Null(CFF2FDSelect))
+    if (acc.fdSelect != &Null (CFF2FDSelect))
     {
-      offsets.FDSelectInfo.offset = final_size;
-      if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
-                                  orig_fdcount,
-                                  *(const FDSelect *)acc.fdSelect,
-                                  subset_fdcount,
-                                  offsets.FDSelectInfo.size,
-                                  subset_fdselect_format,
-                                  subset_fdselect_ranges,
-                                  fdmap)))
+      if (unlikely (!hb_plan_subset_cff_fdselect (plan,
+                                                  orig_fdcount,
+                                                  *(const FDSelect *)acc.fdSelect,
+                                                  subset_fdcount,
+                                                  subset_fdselect_size,
+                                                  subset_fdselect_format,
+                                                  subset_fdselect_ranges,
+                                                  fdmap)))
         return false;
-
-      final_size += offsets.FDSelectInfo.size;
     }
     else
       fdmap.identity (1);
 
-    /* FDArray (FDIndex) */
-    {
-      offsets.FDArrayInfo.offset = final_size;
-      cff_font_dict_op_serializer_t fontSzr;
-      unsigned int dictsSize = 0;
-      for (unsigned int i = 0; i < acc.fontDicts.length; i++)
-        if (fdmap.includes (i))
-          dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
-
-      offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
-      final_size += CFF2Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
-    }
-
-    /* CharStrings */
-    {
-      offsets.charStringsInfo.offset = final_size;
-      unsigned int dataSize = subset_charstrings.total_size ();
-      offsets.charStringsInfo.offSize = calcOffSize (dataSize);
-      final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize);
-    }
-
-    /* private dicts & local subrs */
-    offsets.privateDictsOffset = final_size;
-    for (unsigned int i = 0; i < orig_fdcount; i++)
-    {
-      if (fdmap.includes (i))
-      {
-        bool  has_localsubrs = offsets.localSubrsInfos[i].size > 0;
-        cff_private_dict_op_serializer_t privSzr (desubroutinize, drop_hints);
-        unsigned int  priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
-        table_info_t  privInfo = { final_size, priv_size, 0 };
-        privateDictInfos.push (privInfo);
-        final_size += privInfo.size;
-
-        if (!plan->desubroutinize && has_localsubrs)
-        {
-          offsets.localSubrsInfos[i].offset = final_size;
-          final_size += offsets.localSubrsInfos[i].size;
-        }
-      }
-    }
-
     return true;
   }
 
-  unsigned int get_final_size () const  { return final_size; }
-
-  unsigned int  final_size;
-  cff2_sub_table_offsets_t offsets;
+  cff2_sub_table_info_t info;
 
   unsigned int    orig_fdcount;
   unsigned int    subset_fdcount;
+  unsigned int    subset_fdselect_size;
   unsigned int    subset_fdselect_format;
   hb_vector_t<code_pair_t>   subset_fdselect_ranges;
 
-  remap_t   fdmap;
+  hb_inc_bimap_t   fdmap;
 
   str_buff_vec_t            subset_charstrings;
   str_buff_vec_t            subset_globalsubrs;
   hb_vector_t<str_buff_vec_t> subset_localsubrs;
-  hb_vector_t<table_info_t>  privateDictInfos;
 
   bool      drop_hints;
   bool      desubroutinize;
-  cff2_subr_subsetter_t       subr_subsetter;
 };
 
-static inline bool _write_cff2 (const cff2_subset_plan &plan,
-                                const OT::cff2::accelerator_subset_t  &acc,
-                                const hb_vector_t<hb_codepoint_t>& glyphs,
-                                unsigned int dest_sz,
-                                void *dest)
+static bool _serialize_cff2 (hb_serialize_context_t *c,
+                             cff2_subset_plan &plan,
+                             const OT::cff2::accelerator_subset_t  &acc,
+                             unsigned int num_glyphs)
 {
-  hb_serialize_context_t c (dest, dest_sz);
+  /* private dicts & local subrs */
+  hb_vector_t<table_info_t>  private_dict_infos;
+  if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) return false;
 
-  OT::cff2 *cff2 = c.start_serialize<OT::cff2> ();
-  if (unlikely (!c.extend_min (*cff2)))
-    return false;
-
-  /* header */
-  cff2->version.major.set (0x02);
-  cff2->version.minor.set (0x00);
-  cff2->topDict.set (OT::cff2::static_size);
-
-  /* top dict */
+  for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
   {
-    assert (cff2->topDict == (unsigned) (c.head - c.start));
-    cff2->topDictSize.set (plan.offsets.topDictInfo.size);
-    TopDict &dict = cff2 + cff2->topDict;
-    cff2_top_dict_op_serializer_t topSzr;
-    if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets)))
+    if (plan.fdmap.has (i))
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict");
-      return false;
+      objidx_t  subrs_link = 0;
+
+      if (plan.subset_localsubrs[i].length > 0)
+      {
+        CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
+        if (unlikely (!dest)) return false;
+        c->push ();
+        if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
+          subrs_link = c->pop_pack ();
+        else
+        {
+          c->pop_discard ();
+          return false;
+        }
+      }
+      PrivateDict *pd = c->start_embed<PrivateDict> ();
+      if (unlikely (!pd)) return false;
+      c->push ();
+      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
+      if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link)))
+      {
+        unsigned fd = plan.fdmap[i];
+        private_dict_infos[fd].size = c->length ();
+        private_dict_infos[fd].link = c->pop_pack ();
+      }
+      else
+      {
+        c->pop_discard ();
+        return false;
+      }
     }
   }
 
-  /* global subrs */
+  /* CharStrings */
   {
-    assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start));
-    CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
-    if (unlikely (dest == nullptr)) return false;
-    if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
+    CFF2CharStrings  *cs = c->start_embed<CFF2CharStrings> ();
+    if (unlikely (!cs)) return false;
+    c->push ();
+    if (likely (cs->serialize (c, plan.subset_charstrings)))
+      plan.info.char_strings_link = c->pop_pack ();
+    else
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
-      return false;
-    }
-  }
-
-  /* variation store */
-  if (acc.varStore != &Null(CFF2VariationStore))
-  {
-    assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start));
-    CFF2VariationStore *dest = c.start_embed<CFF2VariationStore> ();
-    if (unlikely (!dest->serialize (&c, acc.varStore)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Variation Store");
+      c->pop_discard ();
       return false;
     }
   }
 
   /* FDSelect */
-  if (acc.fdSelect != &Null(CFF2FDSelect))
+  if (acc.fdSelect != &Null (CFF2FDSelect))
   {
-    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
-
-    if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
-                                              plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
-                                              plan.subset_fdselect_ranges)))
+    c->push ();
+    if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect,                                            plan.orig_fdcount,
+                                            plan.subset_fdselect_format, plan.subset_fdselect_size,
+                                            plan.subset_fdselect_ranges)))
+      plan.info.fd_select.link = c->pop_pack ();
+    else
     {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect");
+      c->pop_discard ();
       return false;
     }
   }
 
   /* FDArray (FD Index) */
   {
-    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
-    CFF2FDArray  *fda = c.start_embed<CFF2FDArray> ();
-    if (unlikely (fda == nullptr)) return false;
-    cff_font_dict_op_serializer_t  fontSzr;
-    if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
-                                   acc.fontDicts, plan.subset_fdcount, plan.fdmap,
-                                   fontSzr, plan.privateDictInfos)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray");
-      return false;
-    }
+    c->push ();
+    CFF2FDArray *fda = c->start_embed<CFF2FDArray> ();
+    if (unlikely (!fda)) return false;
+    cff_font_dict_op_serializer_t fontSzr;
+    auto it =
+    + hb_zip (+ hb_iter (acc.fontDicts)
+              | hb_filter ([&] (const cff2_font_dict_values_t &_)
+                { return plan.fdmap.has (&_ - &acc.fontDicts[0]); }),
+              hb_iter (private_dict_infos))
+    ;
+    if (unlikely (!fda->serialize (c, it, fontSzr))) return false;
+    plan.info.fd_array_link = c->pop_pack ();
   }
 
-  /* CharStrings */
+  /* variation store */
+  if (acc.varStore != &Null (CFF2VariationStore))
   {
-    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
-    CFF2CharStrings  *cs = c.start_embed<CFF2CharStrings> ();
-    if (unlikely (cs == nullptr)) return false;
-    if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
-    {
-      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings");
-      return false;
-    }
+    c->push ();
+    CFF2VariationStore *dest = c->start_embed<CFF2VariationStore> ();
+    if (unlikely (!dest || !dest->serialize (c, acc.varStore))) return false;
+    plan.info.var_store_link = c->pop_pack ();
   }
 
-  /* private dicts & local subrs */
-  assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start));
-  for (unsigned int i = 0; i < acc.privateDicts.length; i++)
+  OT::cff2 *cff2 = c->allocate_min<OT::cff2> ();
+  if (unlikely (!cff2)) return false;
+
+  /* header */
+  cff2->version.major = 0x02;
+  cff2->version.minor = 0x00;
+  cff2->topDict = OT::cff2::static_size;
+
+  /* top dict */
   {
-    if (plan.fdmap.includes (i))
-    {
-      PrivateDict  *pd = c.start_embed<PrivateDict> ();
-      if (unlikely (pd == nullptr)) return false;
-      unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
-      bool result;
-      cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
-      /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
-      unsigned int  subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0;
-      result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
-      if (unlikely (!result))
-      {
-        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
-        return false;
-      }
-      if (plan.offsets.localSubrsInfos[i].size > 0)
-      {
-        CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
-        if (unlikely (dest == nullptr)) return false;
-        if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i])))
-        {
-          DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines");
-          return false;
-        }
-      }
-    }
+    TopDict &dict = cff2 + cff2->topDict;
+    cff2_top_dict_op_serializer_t topSzr;
+    if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.info))) return false;
+    cff2->topDictSize = c->head - (const char *)&dict;
   }
 
-  assert (c.head == c.end);
-  c.end_serialize ();
-
-  return true;
+  /* global subrs */
+  {
+    CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
+    if (unlikely (!dest)) return false;
+    return dest->serialize (c, plan.subset_globalsubrs);
+  }
 }
 
 static bool
 _hb_subset_cff2 (const OT::cff2::accelerator_subset_t  &acc,
-                const char                    *data,
-                hb_subset_plan_t                *plan,
-                hb_blob_t                      **prime /* OUT */)
+                 hb_subset_context_t    *c)
 {
   cff2_subset_plan cff2_plan;
 
-  if (unlikely (!cff2_plan.create (acc, plan)))
-  {
-    DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan.");
-    return false;
-  }
-
-  unsigned int  cff2_prime_size = cff2_plan.get_final_size ();
-  char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
-
-  if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs,
-                              cff2_prime_size, cff2_prime_data))) {
-    DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
-    free (cff2_prime_data);
-    return false;
-  }
-
-  *prime = hb_blob_create (cff2_prime_data,
-                                cff2_prime_size,
-                                HB_MEMORY_MODE_READONLY,
-                                cff2_prime_data,
-                                free);
-  return true;
+  if (unlikely (!cff2_plan.create (acc, c->plan))) return false;
+  return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs ());
 }
 
 /**
  * hb_subset_cff2:
- * Subsets the CFF2 table according to a provided plan.
- *
- * Return value: subsetted cff2 table.
+ * Subsets the CFF2 table according to a provided subset context.
  **/
 bool
-hb_subset_cff2 (hb_subset_plan_t *plan,
-                hb_blob_t       **prime /* OUT */)
+hb_subset_cff2 (hb_subset_context_t *c)
 {
-  hb_blob_t *cff2_blob = hb_sanitize_context_t().reference_table<CFF::cff2> (plan->source);
-  const char *data = hb_blob_get_data(cff2_blob, nullptr);
-
   OT::cff2::accelerator_subset_t acc;
-  acc.init(plan->source);
-  bool result = likely (acc.is_valid ()) &&
-                _hb_subset_cff2 (acc, data, plan, prime);
-
-  hb_blob_destroy (cff2_blob);
+  acc.init (c->plan->source);
+  bool result = likely (acc.is_valid ()) && _hb_subset_cff2 (acc, c);
   acc.fini ();
 
   return result;
 }
+
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.hh
index baac1a9..f10556d 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.hh
@@ -32,7 +32,6 @@
 #include "hb-subset-plan.hh"
 
 HB_INTERNAL bool
-hb_subset_cff2 (hb_subset_plan_t *plan,
-               hb_blob_t       **cff2_prime /* OUT */);
+hb_subset_cff2 (hb_subset_context_t *c);
 
 #endif /* HB_SUBSET_CFF2_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.cc
deleted file mode 100644
index 03c39a6..0000000
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.cc
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright © 2018  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Garret Rieger, Roderick Sheeter
- */
-
-#include "hb-open-type.hh"
-#include "hb-ot-glyf-table.hh"
-#include "hb-set.h"
-#include "hb-subset-glyf.hh"
-
-static bool
-_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
-                                     hb_vector_t<hb_codepoint_t> &glyph_ids,
-                                     hb_bool_t drop_hints,
-                                     bool *use_short_loca /* OUT */,
-                                     unsigned int *glyf_size /* OUT */,
-                                     unsigned int *loca_size /* OUT */,
-                                     hb_vector_t<unsigned int> *instruction_ranges /* OUT */)
-{
-  unsigned int total = 0;
-  for (unsigned int i = 0; i < glyph_ids.length; i++)
-  {
-    hb_codepoint_t next_glyph = glyph_ids[i];
-    if (!instruction_ranges->resize (instruction_ranges->length + 2))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges.");
-      return false;
-    }
-    unsigned int *instruction_start = &(*instruction_ranges)[instruction_ranges->length - 2];
-    *instruction_start = 0;
-    unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->length - 1];
-    *instruction_end = 0;
-
-    unsigned int start_offset, end_offset;
-    if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) &&
-                    glyf.remove_padding (start_offset, &end_offset))))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph);
-      continue;
-    }
-    if (end_offset - start_offset < OT::glyf::GlyphHeader::static_size)
-      continue; /* 0-length glyph */
-
-    if (drop_hints)
-    {
-      if (unlikely (!glyf.get_instruction_offsets (start_offset, end_offset,
-                                                   instruction_start, instruction_end)))
-      {
-        DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", next_glyph);
-        return false;
-      }
-    }
-
-    total += end_offset - start_offset - (*instruction_end - *instruction_start);
-    /* round2 so short loca will work */
-    total += total % 2;
-  }
-
-  *glyf_size = total;
-  *use_short_loca = (total <= 131070);
-  *loca_size = (glyph_ids.length + 1)
-      * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32));
-
-  DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca",
-            total,
-            *loca_size,
-            *use_short_loca ? "short" : "long");
-  return true;
-}
-
-static bool
-_write_loca_entry (unsigned int  id,
-                   unsigned int  offset,
-                   bool          is_short,
-                   void         *loca_prime,
-                   unsigned int  loca_size)
-{
-  unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32);
-  if ((id + 1) * entry_size <= loca_size)
-  {
-    if (is_short) {
-      ((OT::HBUINT16*) loca_prime) [id].set (offset / 2);
-    } else {
-      ((OT::HBUINT32*) loca_prime) [id].set (offset);
-    }
-    return true;
-  }
-
-  // Offset was not written because the write is out of bounds.
-  DEBUG_MSG(SUBSET,
-            nullptr,
-            "WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d.",
-            id,
-            loca_size);
-  return false;
-}
-
-static void
-_update_components (hb_subset_plan_t * plan,
-                    char * glyph_start,
-                    unsigned int length)
-{
-  OT::glyf::CompositeGlyphHeader::Iterator iterator;
-  if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start,
-                                                    length,
-                                                    &iterator))
-  {
-    do
-    {
-      hb_codepoint_t new_gid;
-      if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex,
-                                      &new_gid))
-        continue;
-
-      ((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex.set (new_gid);
-    } while (iterator.move_to_next ());
-  }
-}
-
-static bool _remove_composite_instruction_flag (char *glyf_prime, unsigned int length)
-{
-  /* remove WE_HAVE_INSTRUCTIONS from flags in dest */
-  OT::glyf::CompositeGlyphHeader::Iterator composite_it;
-  if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (glyf_prime, length, &composite_it))) return false;
-  const OT::glyf::CompositeGlyphHeader *glyph;
-  do {
-    glyph = composite_it.current;
-    OT::HBUINT16 *flags = const_cast<OT::HBUINT16 *> (&glyph->flags);
-    flags->set ( (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS);
-  } while (composite_it.move_to_next ());
-  return true;
-}
-
-static bool
-_write_glyf_and_loca_prime (hb_subset_plan_t              *plan,
-                            const OT::glyf::accelerator_t &glyf,
-                            const char                    *glyf_data,
-                            bool                           use_short_loca,
-                            hb_vector_t<unsigned int> &instruction_ranges,
-                            unsigned int                   glyf_prime_size,
-                            char                          *glyf_prime_data /* OUT */,
-                            unsigned int                   loca_prime_size,
-                            char                          *loca_prime_data /* OUT */)
-{
-  hb_vector_t<hb_codepoint_t> &glyph_ids = plan->glyphs;
-  char *glyf_prime_data_next = glyf_prime_data;
-
-  bool success = true;
-  for (unsigned int i = 0; i < glyph_ids.length; i++)
-  {
-    unsigned int start_offset, end_offset;
-    if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) &&
-                    glyf.remove_padding (start_offset, &end_offset))))
-      end_offset = start_offset = 0;
-
-    unsigned int instruction_start = instruction_ranges[i * 2];
-    unsigned int instruction_end = instruction_ranges[i * 2 + 1];
-
-    int length = end_offset - start_offset - (instruction_end - instruction_start);
-
-    if (glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size)
-    {
-      DEBUG_MSG(SUBSET,
-                 nullptr,
-                 "WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)",
-                 i, length);
-      return false;
-    }
-
-    if (instruction_start == instruction_end)
-      memcpy (glyf_prime_data_next, glyf_data + start_offset, length);
-    else
-    {
-      memcpy (glyf_prime_data_next, glyf_data + start_offset, instruction_start - start_offset);
-      memcpy (glyf_prime_data_next + instruction_start - start_offset, glyf_data + instruction_end, end_offset - instruction_end);
-      /* if the instructions end at the end this was a composite glyph, else simple */
-      if (instruction_end == end_offset)
-      {
-        if (unlikely (!_remove_composite_instruction_flag (glyf_prime_data_next, length))) return false;
-      }
-      else
-        /* zero instruction length, which is just before instruction_start */
-        memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2);
-    }
-
-    success = success && _write_loca_entry (i,
-                                            glyf_prime_data_next - glyf_prime_data,
-                                            use_short_loca,
-                                            loca_prime_data,
-                                            loca_prime_size);
-    _update_components (plan, glyf_prime_data_next, length);
-
-    // TODO: don't align to two bytes if using long loca.
-    glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca.
-  }
-
-  success = success && _write_loca_entry (glyph_ids.length,
-                                          glyf_prime_data_next - glyf_prime_data,
-                                          use_short_loca,
-                                          loca_prime_data,
-                                          loca_prime_size);
-  return success;
-}
-
-static bool
-_hb_subset_glyf_and_loca (const OT::glyf::accelerator_t  &glyf,
-                          const char                     *glyf_data,
-                          hb_subset_plan_t               *plan,
-                          bool                           *use_short_loca,
-                          hb_blob_t                     **glyf_prime /* OUT */,
-                          hb_blob_t                     **loca_prime /* OUT */)
-{
-  // TODO(grieger): Sanity check allocation size for the new table.
-  hb_vector_t<hb_codepoint_t> &glyphs_to_retain = plan->glyphs;
-
-  unsigned int glyf_prime_size;
-  unsigned int loca_prime_size;
-  hb_vector_t<unsigned int> instruction_ranges;
-  instruction_ranges.init ();
-
-  if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
-                                                      glyphs_to_retain,
-                                                      plan->drop_hints,
-                                                      use_short_loca,
-                                                      &glyf_prime_size,
-                                                      &loca_prime_size,
-                                                      &instruction_ranges))) {
-    instruction_ranges.fini ();
-    return false;
-  }
-
-  char *glyf_prime_data = (char *) calloc (1, glyf_prime_size);
-  char *loca_prime_data = (char *) calloc (1, loca_prime_size);
-  if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data,
-                                             *use_short_loca,
-                                             instruction_ranges,
-                                             glyf_prime_size, glyf_prime_data,
-                                             loca_prime_size, loca_prime_data))) {
-    free (glyf_prime_data);
-    free (loca_prime_data);
-    instruction_ranges.fini ();
-    return false;
-  }
-  instruction_ranges.fini ();
-
-  *glyf_prime = hb_blob_create (glyf_prime_data,
-                                glyf_prime_size,
-                                HB_MEMORY_MODE_READONLY,
-                                glyf_prime_data,
-                                free);
-  *loca_prime = hb_blob_create (loca_prime_data,
-                                loca_prime_size,
-                                HB_MEMORY_MODE_READONLY,
-                                loca_prime_data,
-                                free);
-  return true;
-}
-
-/**
- * hb_subset_glyf:
- * Subsets the glyph table according to a provided plan.
- *
- * Return value: subsetted glyf table.
- *
- * Since: 1.7.5
- **/
-bool
-hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
-                         bool             *use_short_loca, /* OUT */
-                         hb_blob_t       **glyf_prime, /* OUT */
-                         hb_blob_t       **loca_prime /* OUT */)
-{
-  hb_blob_t *glyf_blob = hb_sanitize_context_t ().reference_table<OT::glyf> (plan->source);
-  const char *glyf_data = hb_blob_get_data (glyf_blob, nullptr);
-
-  OT::glyf::accelerator_t glyf;
-  glyf.init (plan->source);
-  bool result = _hb_subset_glyf_and_loca (glyf,
-                                          glyf_data,
-                                          plan,
-                                          use_short_loca,
-                                          glyf_prime,
-                                          loca_prime);
-
-  hb_blob_destroy (glyf_blob);
-  glyf.fini ();
-
-  return result;
-}
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc
index 3feeb5c..087981b 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc
@@ -44,7 +44,45 @@
 
   input->unicodes = hb_set_create ();
   input->glyphs = hb_set_create ();
-  input->drop_layout = true;
+  input->name_ids = hb_set_create ();
+  hb_set_add_range (input->name_ids, 0, 6);
+  input->name_languages = hb_set_create ();
+  hb_set_add (input->name_languages, 0x0409);
+  input->drop_tables = hb_set_create ();
+  input->drop_hints = false;
+  input->desubroutinize = false;
+  input->retain_gids = false;
+  input->name_legacy = false;
+
+  hb_tag_t default_drop_tables[] = {
+    // Layout disabled by default
+    HB_TAG ('G', 'S', 'U', 'B'),
+    HB_TAG ('G', 'P', 'O', 'S'),
+    HB_TAG ('G', 'D', 'E', 'F'),
+    HB_TAG ('m', 'o', 'r', 'x'),
+    HB_TAG ('m', 'o', 'r', 't'),
+    HB_TAG ('k', 'e', 'r', 'x'),
+    HB_TAG ('k', 'e', 'r', 'n'),
+
+    // Copied from fontTools:
+    HB_TAG ('B', 'A', 'S', 'E'),
+    HB_TAG ('J', 'S', 'T', 'F'),
+    HB_TAG ('D', 'S', 'I', 'G'),
+    HB_TAG ('E', 'B', 'D', 'T'),
+    HB_TAG ('E', 'B', 'L', 'C'),
+    HB_TAG ('E', 'B', 'S', 'C'),
+    HB_TAG ('S', 'V', 'G', ' '),
+    HB_TAG ('P', 'C', 'L', 'T'),
+    HB_TAG ('L', 'T', 'S', 'H'),
+    // Graphite tables
+    HB_TAG ('F', 'e', 'a', 't'),
+    HB_TAG ('G', 'l', 'a', 't'),
+    HB_TAG ('G', 'l', 'o', 'c'),
+    HB_TAG ('S', 'i', 'l', 'f'),
+    HB_TAG ('S', 'i', 'l', 'l'),
+  };
+
+  input->drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
 
   return input;
 }
@@ -78,6 +116,9 @@
 
   hb_set_destroy (subset_input->unicodes);
   hb_set_destroy (subset_input->glyphs);
+  hb_set_destroy (subset_input->name_ids);
+  hb_set_destroy (subset_input->name_languages);
+  hb_set_destroy (subset_input->drop_tables);
 
   free (subset_input);
 }
@@ -106,6 +147,24 @@
   return subset_input->glyphs;
 }
 
+HB_EXTERN hb_set_t *
+hb_subset_input_nameid_set (hb_subset_input_t *subset_input)
+{
+  return subset_input->name_ids;
+}
+
+HB_EXTERN hb_set_t *
+hb_subset_input_namelangid_set (hb_subset_input_t *subset_input)
+{
+  return subset_input->name_languages;
+}
+
+HB_EXTERN hb_set_t *
+hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input)
+{
+  return subset_input->drop_tables;
+}
+
 HB_EXTERN void
 hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
                                 hb_bool_t drop_hints)
@@ -120,21 +179,8 @@
 }
 
 HB_EXTERN void
-hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
-                                 hb_bool_t drop_layout)
-{
-  subset_input->drop_layout = drop_layout;
-}
-
-HB_EXTERN hb_bool_t
-hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input)
-{
-  return subset_input->drop_layout;
-}
-
-HB_EXTERN void
 hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
-        hb_bool_t desubroutinize)
+                                    hb_bool_t desubroutinize)
 {
   subset_input->desubroutinize = desubroutinize;
 }
@@ -144,3 +190,40 @@
 {
   return subset_input->desubroutinize;
 }
+
+/**
+ * hb_subset_input_set_retain_gids:
+ * @subset_input: a subset_input.
+ * @retain_gids: If true the subsetter will not renumber glyph ids.
+ * Since: 2.4.0
+ **/
+HB_EXTERN void
+hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
+                                 hb_bool_t retain_gids)
+{
+  subset_input->retain_gids = retain_gids;
+}
+
+/**
+ * hb_subset_input_get_retain_gids:
+ * Returns: value of retain_gids.
+ * Since: 2.4.0
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input)
+{
+  return subset_input->retain_gids;
+}
+
+HB_EXTERN void
+hb_subset_input_set_name_legacy (hb_subset_input_t *subset_input,
+                                 hb_bool_t name_legacy)
+{
+  subset_input->name_legacy = name_legacy;
+}
+
+HB_EXTERN hb_bool_t
+hb_subset_input_get_name_legacy (hb_subset_input_t *subset_input)
+{
+  return subset_input->name_legacy;
+}
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.hh
index 8dad94f..0aeb966 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.hh
@@ -40,15 +40,19 @@
 
   hb_set_t *unicodes;
   hb_set_t *glyphs;
+  hb_set_t *name_ids;
+  hb_set_t *name_languages;
+  hb_set_t *drop_tables;
 
-  bool drop_hints : 1;
-  bool drop_layout : 1;
-  bool desubroutinize : 1;
+  bool drop_hints;
+  bool desubroutinize;
+  bool retain_gids;
+  bool name_legacy;
   /* TODO
    *
    * features
    * lookups
-   * nameIDs
+   * name_ids
    * ...
    */
 };
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc
index 69b4328..2f2f343 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc
@@ -30,44 +30,47 @@
 
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-glyf-table.hh"
+#include "hb-ot-layout-gdef-table.hh"
+#include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-cff1-table.hh"
+#include "hb-ot-color-colr-table.hh"
+#include "hb-ot-var-fvar-table.hh"
+#include "hb-ot-stat-table.hh"
 
-static void
-_add_gid_and_children (const OT::glyf::accelerator_t &glyf,
-                       hb_codepoint_t gid,
-                       hb_set_t *gids_to_retain)
-{
-  if (hb_set_has (gids_to_retain, gid))
-    // Already visited this gid, ignore.
-    return;
 
-  hb_set_add (gids_to_retain, gid);
-
-  OT::glyf::CompositeGlyphHeader::Iterator composite;
-  if (glyf.get_composite (gid, &composite))
-  {
-    do
-    {
-      _add_gid_and_children (glyf, (hb_codepoint_t) composite.current->glyphIndex, gids_to_retain);
-    } while (composite.move_to_next());
-  }
-}
-
-static void
+#ifndef HB_NO_SUBSET_CFF
+static inline void
 _add_cff_seac_components (const OT::cff1::accelerator_t &cff,
-           hb_codepoint_t gid,
-           hb_set_t *gids_to_retain)
+                          hb_codepoint_t gid,
+                          hb_set_t *gids_to_retain)
 {
   hb_codepoint_t base_gid, accent_gid;
   if (cff.get_seac_components (gid, &base_gid, &accent_gid))
   {
-    hb_set_add (gids_to_retain, base_gid);
-    hb_set_add (gids_to_retain, accent_gid);
+    gids_to_retain->add (base_gid);
+    gids_to_retain->add (accent_gid);
   }
 }
+#endif
 
+#ifndef HB_NO_SUBSET_LAYOUT
 static void
-_gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
+_remap_indexes (const hb_set_t *indexes,
+                hb_map_t       *mapping /* OUT */)
+{
+  unsigned count = indexes->get_population ();
+
+  for (auto _ : + hb_zip (indexes->iter (), hb_range (count)))
+    mapping->set (_.first, _.second);
+
+}
+
+static inline void
+_gsub_closure_glyphs_lookups_features (hb_face_t *face,
+                                       hb_set_t *gids_to_retain,
+                                       hb_map_t *gsub_lookups,
+                                       hb_map_t *gsub_features)
 {
   hb_set_t lookup_indices;
   hb_ot_layout_collect_lookups (face,
@@ -79,9 +82,88 @@
   hb_ot_layout_lookups_substitute_closure (face,
                                            &lookup_indices,
                                            gids_to_retain);
+  hb_blob_ptr_t<OT::GSUB> gsub = hb_sanitize_context_t ().reference_table<OT::GSUB> (face);
+  gsub->closure_lookups (face,
+                         gids_to_retain,
+                         &lookup_indices);
+  _remap_indexes (&lookup_indices, gsub_lookups);
+
+  //closure features
+  hb_set_t feature_indices;
+  gsub->closure_features (gsub_lookups, &feature_indices);
+  _remap_indexes (&feature_indices, gsub_features);
+  gsub.destroy ();
 }
 
-static void
+static inline void
+_gpos_closure_lookups_features (hb_face_t      *face,
+                                const hb_set_t *gids_to_retain,
+                                hb_map_t       *gpos_lookups,
+                                hb_map_t       *gpos_features)
+{
+  hb_set_t lookup_indices;
+  hb_ot_layout_collect_lookups (face,
+                                HB_OT_TAG_GPOS,
+                                nullptr,
+                                nullptr,
+                                nullptr,
+                                &lookup_indices);
+  hb_blob_ptr_t<OT::GPOS> gpos = hb_sanitize_context_t ().reference_table<OT::GPOS> (face);
+  gpos->closure_lookups (face,
+                         gids_to_retain,
+                         &lookup_indices);
+  _remap_indexes (&lookup_indices, gpos_lookups);
+
+  //closure features
+  hb_set_t feature_indices;
+  gpos->closure_features (gpos_lookups, &feature_indices);
+  _remap_indexes (&feature_indices, gpos_features);
+  gpos.destroy ();
+}
+#endif
+
+#ifndef HB_NO_VAR
+static inline void
+  _collect_layout_variation_indices (hb_face_t *face,
+                                     const hb_set_t *glyphset,
+                                     const hb_map_t *gpos_lookups,
+                                     hb_set_t  *layout_variation_indices,
+                                     hb_map_t  *layout_variation_idx_map)
+{
+  hb_blob_ptr_t<OT::GDEF> gdef = hb_sanitize_context_t ().reference_table<OT::GDEF> (face);
+  hb_blob_ptr_t<OT::GPOS> gpos = hb_sanitize_context_t ().reference_table<OT::GPOS> (face);
+
+  if (!gdef->has_data ())
+  {
+    gdef.destroy ();
+    gpos.destroy ();
+    return;
+  }
+  OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups);
+  gdef->collect_variation_indices (&c);
+
+  if (hb_ot_layout_has_positioning (face))
+    gpos->collect_variation_indices (&c);
+
+  gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map);
+
+  gdef.destroy ();
+  gpos.destroy ();
+}
+#endif
+
+static inline void
+_cmap_closure (hb_face_t           *face,
+               const hb_set_t      *unicodes,
+               hb_set_t            *glyphset)
+{
+  OT::cmap::accelerator_t cmap;
+  cmap.init (face);
+  cmap.table->closure_glyphs (unicodes, glyphset);
+  cmap.fini ();
+}
+
+static inline void
 _remove_invalid_gids (hb_set_t *glyphs,
                       unsigned int num_glyphs)
 {
@@ -93,23 +175,29 @@
   }
 }
 
-static hb_set_t *
-_populate_gids_to_retain (hb_face_t *face,
+static void
+_populate_gids_to_retain (hb_subset_plan_t* plan,
                           const hb_set_t *unicodes,
+                          const hb_set_t *input_glyphs_to_retain,
                           bool close_over_gsub,
-                          hb_set_t *unicodes_to_retain,
-                          hb_map_t *codepoint_to_glyph,
-                          hb_vector_t<hb_codepoint_t> *glyphs)
+                          bool close_over_gpos,
+                          bool close_over_gdef)
 {
   OT::cmap::accelerator_t cmap;
   OT::glyf::accelerator_t glyf;
+#ifndef HB_NO_SUBSET_CFF
   OT::cff1::accelerator_t cff;
-  cmap.init (face);
-  glyf.init (face);
-  cff.init (face);
+#endif
+  OT::COLR::accelerator_t colr;
+  cmap.init (plan->source);
+  glyf.init (plan->source);
+#ifndef HB_NO_SUBSET_CFF
+  cff.init (plan->source);
+#endif
+  colr.init (plan->source);
 
-  hb_set_t *initial_gids_to_retain = hb_set_create ();
-  initial_gids_to_retain->add (0); // Not-def
+  plan->_glyphset_gsub->add (0); // Not-def
+  hb_set_union (plan->_glyphset_gsub, input_glyphs_to_retain);
 
   hb_codepoint_t cp = HB_SET_VALUE_INVALID;
   while (unicodes->next (&cp))
@@ -120,48 +208,96 @@
       DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
       continue;
     }
-    unicodes_to_retain->add (cp);
-    codepoint_to_glyph->set (cp, gid);
-    initial_gids_to_retain->add (gid);
+    plan->unicodes->add (cp);
+    plan->codepoint_to_glyph->set (cp, gid);
+    plan->_glyphset_gsub->add (gid);
   }
 
+  _cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
+
+#ifndef HB_NO_SUBSET_LAYOUT
   if (close_over_gsub)
-    // Add all glyphs needed for GSUB substitutions.
-    _gsub_closure (face, initial_gids_to_retain);
+    // closure all glyphs/lookups/features needed for GSUB substitutions.
+    _gsub_closure_glyphs_lookups_features (plan->source, plan->_glyphset_gsub, plan->gsub_lookups, plan->gsub_features);
+
+  if (close_over_gpos)
+    _gpos_closure_lookups_features (plan->source, plan->_glyphset_gsub, plan->gpos_lookups, plan->gpos_features);
+#endif
+  _remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
 
   // Populate a full set of glyphs to retain by adding all referenced
   // composite glyphs.
   hb_codepoint_t gid = HB_SET_VALUE_INVALID;
-  hb_set_t *all_gids_to_retain = hb_set_create ();
-  while (initial_gids_to_retain->next (&gid))
+  while (plan->_glyphset_gsub->next (&gid))
   {
-    _add_gid_and_children (glyf, gid, all_gids_to_retain);
+    glyf.add_gid_and_children (gid, plan->_glyphset);
+#ifndef HB_NO_SUBSET_CFF
     if (cff.is_valid ())
-      _add_cff_seac_components (cff, gid, all_gids_to_retain);
+      _add_cff_seac_components (cff, gid, plan->_glyphset);
+#endif
+    if (colr.is_valid ())
+      colr.closure_glyphs (gid, plan->_glyphset);
   }
-  hb_set_destroy (initial_gids_to_retain);
 
-  _remove_invalid_gids (all_gids_to_retain, face->get_num_glyphs ());
+  _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ());
 
-  glyphs->alloc (all_gids_to_retain->get_population ());
-  gid = HB_SET_VALUE_INVALID;
-  while (all_gids_to_retain->next (&gid))
-    glyphs->push (gid);
+#ifndef HB_NO_VAR
+  if (close_over_gdef)
+    _collect_layout_variation_indices (plan->source, plan->_glyphset, plan->gpos_lookups, plan->layout_variation_indices, plan->layout_variation_idx_map);
+#endif
 
+#ifndef HB_NO_SUBSET_CFF
   cff.fini ();
+#endif
   glyf.fini ();
   cmap.fini ();
-
-  return all_gids_to_retain;
 }
 
 static void
-_create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
-                                hb_map_t *glyph_map)
+_create_old_gid_to_new_gid_map (const hb_face_t *face,
+                                bool             retain_gids,
+                                const hb_set_t  *all_gids_to_retain,
+                                hb_map_t        *glyph_map, /* OUT */
+                                hb_map_t        *reverse_glyph_map, /* OUT */
+                                unsigned int    *num_glyphs /* OUT */)
 {
-  for (unsigned int i = 0; i < glyphs.length; i++) {
-    glyph_map->set (glyphs[i], i);
+  if (!retain_gids)
+  {
+    + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0)
+    | hb_sink (reverse_glyph_map)
+    ;
+    *num_glyphs = reverse_glyph_map->get_population ();
+  } else {
+    + hb_iter (all_gids_to_retain)
+    | hb_map ([] (hb_codepoint_t _) {
+                return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, _);
+              })
+    | hb_sink (reverse_glyph_map)
+    ;
+
+    unsigned max_glyph =
+    + hb_iter (all_gids_to_retain)
+    | hb_reduce (hb_max, 0u)
+    ;
+    *num_glyphs = max_glyph + 1;
   }
+
+  + reverse_glyph_map->iter ()
+  | hb_map (&hb_pair_t<hb_codepoint_t, hb_codepoint_t>::reverse)
+  | hb_sink (glyph_map)
+  ;
+}
+
+static void
+_nameid_closure (hb_face_t *face,
+                 hb_set_t  *nameids)
+{
+#ifndef HB_NO_STYLE
+  face->table.STAT->collect_name_ids (nameids);
+#endif
+#ifndef HB_NO_VAR
+  face->table.fvar->collect_name_ids (nameids);
+#endif
 }
 
 /**
@@ -175,28 +311,52 @@
  * Since: 1.7.5
  **/
 hb_subset_plan_t *
-hb_subset_plan_create (hb_face_t           *face,
-                       hb_subset_input_t   *input)
+hb_subset_plan_create (hb_face_t         *face,
+                       hb_subset_input_t *input)
 {
-  hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
+  hb_subset_plan_t *plan;
+  if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> ())))
+    return const_cast<hb_subset_plan_t *> (&Null (hb_subset_plan_t));
 
+  plan->successful = true;
   plan->drop_hints = input->drop_hints;
-  plan->drop_layout = input->drop_layout;
   plan->desubroutinize = input->desubroutinize;
-  plan->unicodes = hb_set_create();
-  plan->glyphs.init();
+  plan->retain_gids = input->retain_gids;
+  plan->name_legacy = input->name_legacy;
+  plan->unicodes = hb_set_create ();
+  plan->name_ids = hb_set_reference (input->name_ids);
+  _nameid_closure (face, plan->name_ids);
+  plan->name_languages = hb_set_reference (input->name_languages);
+  plan->glyphs_requested = hb_set_reference (input->glyphs);
+  plan->drop_tables = hb_set_reference (input->drop_tables);
   plan->source = hb_face_reference (face);
   plan->dest = hb_face_builder_create ();
-  plan->codepoint_to_glyph = hb_map_create();
-  plan->glyph_map = hb_map_create();
-  plan->glyphset = _populate_gids_to_retain (face,
-                                             input->unicodes,
-                                             !plan->drop_layout,
-                                             plan->unicodes,
-                                             plan->codepoint_to_glyph,
-                                             &plan->glyphs);
-  _create_old_gid_to_new_gid_map (plan->glyphs,
-                                  plan->glyph_map);
+
+  plan->_glyphset = hb_set_create ();
+  plan->_glyphset_gsub = hb_set_create ();
+  plan->codepoint_to_glyph = hb_map_create ();
+  plan->glyph_map = hb_map_create ();
+  plan->reverse_glyph_map = hb_map_create ();
+  plan->gsub_lookups = hb_map_create ();
+  plan->gpos_lookups = hb_map_create ();
+  plan->gsub_features = hb_map_create ();
+  plan->gpos_features = hb_map_create ();
+  plan->layout_variation_indices = hb_set_create ();
+  plan->layout_variation_idx_map = hb_map_create ();
+
+  _populate_gids_to_retain (plan,
+                            input->unicodes,
+                            input->glyphs,
+                            !input->drop_tables->has (HB_OT_TAG_GSUB),
+                            !input->drop_tables->has (HB_OT_TAG_GPOS),
+                            !input->drop_tables->has (HB_OT_TAG_GDEF));
+
+  _create_old_gid_to_new_gid_map (face,
+                                  input->retain_gids,
+                                  plan->_glyphset,
+                                  plan->glyph_map,
+                                  plan->reverse_glyph_map,
+                                  &plan->_num_output_glyphs);
 
   return plan;
 }
@@ -212,12 +372,24 @@
   if (!hb_object_destroy (plan)) return;
 
   hb_set_destroy (plan->unicodes);
-  plan->glyphs.fini ();
+  hb_set_destroy (plan->name_ids);
+  hb_set_destroy (plan->name_languages);
+  hb_set_destroy (plan->glyphs_requested);
+  hb_set_destroy (plan->drop_tables);
   hb_face_destroy (plan->source);
   hb_face_destroy (plan->dest);
   hb_map_destroy (plan->codepoint_to_glyph);
   hb_map_destroy (plan->glyph_map);
-  hb_set_destroy (plan->glyphset);
+  hb_map_destroy (plan->reverse_glyph_map);
+  hb_set_destroy (plan->_glyphset);
+  hb_set_destroy (plan->_glyphset_gsub);
+  hb_map_destroy (plan->gsub_lookups);
+  hb_map_destroy (plan->gpos_lookups);
+  hb_map_destroy (plan->gsub_features);
+  hb_map_destroy (plan->gpos_features);
+  hb_set_destroy (plan->layout_variation_indices);
+  hb_map_destroy (plan->layout_variation_idx_map);
+
 
   free (plan);
 }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh
index 83dd370..b029548 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh
@@ -33,30 +33,111 @@
 #include "hb-subset-input.hh"
 
 #include "hb-map.hh"
+#include "hb-set.hh"
 
 struct hb_subset_plan_t
 {
   hb_object_header_t header;
 
+  bool successful : 1;
   bool drop_hints : 1;
-  bool drop_layout : 1;
   bool desubroutinize : 1;
+  bool retain_gids : 1;
+  bool name_legacy : 1;
 
   // For each cp that we'd like to retain maps to the corresponding gid.
   hb_set_t *unicodes;
 
-  hb_vector_t<hb_codepoint_t> glyphs;
-  hb_set_t *glyphset;
+  // name_ids we would like to retain
+  hb_set_t *name_ids;
 
+  // name_languages we would like to retain
+  hb_set_t *name_languages;
+
+  //glyph ids requested to retain
+  hb_set_t *glyphs_requested;
+
+  // Tables which should be dropped.
+  hb_set_t *drop_tables;
+
+  // The glyph subset
   hb_map_t *codepoint_to_glyph;
+
+  // Old -> New glyph id mapping
   hb_map_t *glyph_map;
+  hb_map_t *reverse_glyph_map;
 
   // Plan is only good for a specific source/dest so keep them with it
   hb_face_t *source;
   hb_face_t *dest;
 
-  bool new_gid_for_codepoint (hb_codepoint_t codepoint,
-                              hb_codepoint_t *new_gid) const
+  unsigned int _num_output_glyphs;
+  hb_set_t *_glyphset;
+  hb_set_t *_glyphset_gsub;
+
+  //active lookups we'd like to retain
+  hb_map_t *gsub_lookups;
+  hb_map_t *gpos_lookups;
+
+  //active features we'd like to retain
+  hb_map_t *gsub_features;
+  hb_map_t *gpos_features;
+
+  //The set of layout item variation store delta set indices to be retained
+  hb_set_t *layout_variation_indices;
+  //Old -> New layout item variation store delta set index mapping
+  hb_map_t *layout_variation_idx_map;
+
+ public:
+
+  bool in_error () const { return !successful; }
+
+  bool check_success(bool success)
+  {
+    successful = (successful && success);
+    return successful;
+  }
+
+  /*
+   * The set of input glyph ids which will be retained in the subset.
+   * Does NOT include ids kept due to retain_gids. You probably want to use
+   * glyph_map/reverse_glyph_map.
+   */
+  inline const hb_set_t *
+  glyphset () const
+  {
+    return _glyphset;
+  }
+
+  /*
+   * The set of input glyph ids which will be retained in the subset.
+   */
+  inline const hb_set_t *
+  glyphset_gsub () const
+  {
+    return _glyphset_gsub;
+  }
+
+  /*
+   * The total number of output glyphs in the final subset.
+   */
+  inline unsigned int
+  num_output_glyphs () const
+  {
+    return _num_output_glyphs;
+  }
+
+  /*
+   * Given an output gid , returns true if that glyph id is an empty
+   * glyph (ie. it's a gid that we are dropping all data for).
+   */
+  inline bool is_empty_glyph (hb_codepoint_t gid) const
+  {
+    return !_glyphset->has (gid);
+  }
+
+  inline bool new_gid_for_codepoint (hb_codepoint_t codepoint,
+                                     hb_codepoint_t *new_gid) const
   {
     hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint);
     if (old_gid == HB_MAP_VALUE_INVALID)
@@ -65,8 +146,8 @@
     return new_gid_for_old_gid (old_gid, new_gid);
   }
 
-  bool new_gid_for_old_gid (hb_codepoint_t old_gid,
-                            hb_codepoint_t *new_gid) const
+  inline bool new_gid_for_old_gid (hb_codepoint_t old_gid,
+                                   hb_codepoint_t *new_gid) const
   {
     hb_codepoint_t gid = glyph_map->get (old_gid);
     if (gid == HB_MAP_VALUE_INVALID)
@@ -76,7 +157,18 @@
     return true;
   }
 
-  bool
+  inline bool old_gid_for_new_gid (hb_codepoint_t  new_gid,
+                                   hb_codepoint_t *old_gid) const
+  {
+    hb_codepoint_t gid = reverse_glyph_map->get (new_gid);
+    if (gid == HB_MAP_VALUE_INVALID)
+      return false;
+
+    *old_gid = gid;
+    return true;
+  }
+
+  inline bool
   add_table (hb_tag_t tag,
              hb_blob_t *contents)
   {
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc
index 6584167..43afc30 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc
@@ -28,7 +28,6 @@
 #include "hb-open-type.hh"
 
 #include "hb-subset.hh"
-#include "hb-subset-glyf.hh"
 
 #include "hb-open-file.hh"
 #include "hb-ot-cmap-table.hh"
@@ -38,218 +37,194 @@
 #include "hb-ot-hhea-table.hh"
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-maxp-table.hh"
+#include "hb-ot-color-sbix-table.hh"
+#include "hb-ot-color-colr-table.hh"
 #include "hb-ot-os2-table.hh"
 #include "hb-ot-post-table.hh"
 #include "hb-ot-cff1-table.hh"
 #include "hb-ot-cff2-table.hh"
 #include "hb-ot-vorg-table.hh"
+#include "hb-ot-name-table.hh"
+#include "hb-ot-color-cbdt-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-var-gvar-table.hh"
+#include "hb-ot-var-hvar-table.hh"
 
 
-static unsigned int
-_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
-                                  unsigned int table_len)
+static unsigned
+_plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len)
 {
-  unsigned int src_glyphs = plan->source->get_num_glyphs ();
-  unsigned int dst_glyphs = plan->glyphset->get_population ();
+  unsigned src_glyphs = plan->source->get_num_glyphs ();
+  unsigned dst_glyphs = plan->glyphset ()->get_population ();
 
   if (unlikely (!src_glyphs))
     return 512 + table_len;
 
-  return 512 + (unsigned int) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
-}
-
-template<typename TableType>
-static bool
-_subset2 (hb_subset_plan_t *plan)
-{
-  hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
-  const TableType *table = source_blob->as<TableType> ();
-
-  hb_tag_t tag = TableType::tableTag;
-  hb_bool_t result = false;
-  if (source_blob->data)
-  {
-    hb_vector_t<char> buf;
-    unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
-    DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
-    if (unlikely (!buf.alloc (buf_size)))
-    {
-      DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
-      return false;
-    }
-  retry:
-    hb_serialize_context_t serializer ((void *) buf, buf_size);
-    hb_subset_context_t c (plan, &serializer);
-    result = table->subset (&c);
-    if (serializer.in_error ())
-    {
-      buf_size += (buf_size >> 1) + 32;
-      DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size);
-      if (unlikely (!buf.alloc (buf_size)))
-      {
-        DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size);
-        return false;
-      }
-      goto retry;
-    }
-    if (result)
-    {
-      hb_blob_t *dest_blob = serializer.copy_blob ();
-      DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length);
-      result = c.plan->add_table (tag, dest_blob);
-      hb_blob_destroy (dest_blob);
-    }
-    else
-    {
-      DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
-      result = true;
-    }
-  }
-  else
-    DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
-
-  hb_blob_destroy (source_blob);
-  DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!");
-  return result;
+  return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
 }
 
 template<typename TableType>
 static bool
 _subset (hb_subset_plan_t *plan)
 {
+  bool result = false;
   hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
   const TableType *table = source_blob->as<TableType> ();
 
   hb_tag_t tag = TableType::tableTag;
-  hb_bool_t result = false;
   if (source_blob->data)
-    result = table->subset (plan);
+  {
+    hb_vector_t<char> buf;
+    /* TODO Not all tables are glyph-related.  'name' table size for example should not be
+     * affected by number of glyphs.  Accommodate that. */
+    unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
+    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
+    if (unlikely (!buf.alloc (buf_size)))
+    {
+      DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
+      hb_blob_destroy (source_blob);
+      return false;
+    }
+  retry:
+    hb_serialize_context_t serializer ((void *) buf, buf_size);
+    serializer.start_serialize<TableType> ();
+    hb_subset_context_t c (source_blob, plan, &serializer, tag);
+    bool needed = table->subset (&c);
+    if (serializer.ran_out_of_room)
+    {
+      buf_size += (buf_size >> 1) + 32;
+      DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size);
+      if (unlikely (!buf.alloc (buf_size)))
+      {
+        DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size);
+        hb_blob_destroy (source_blob);
+        return false;
+      }
+      goto retry;
+    }
+    serializer.end_serialize ();
+
+    result = !serializer.in_error ();
+
+    if (result)
+    {
+      if (needed)
+      {
+        hb_blob_t *dest_blob = serializer.copy_blob ();
+        DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length);
+        result = c.plan->add_table (tag, dest_blob);
+        hb_blob_destroy (dest_blob);
+      }
+      else
+      {
+        DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
+      }
+    }
+  }
   else
-    DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
+    DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
 
   hb_blob_destroy (source_blob);
-  DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!");
+  DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!");
   return result;
 }
 
-
 static bool
-_subset_table (hb_subset_plan_t *plan,
-               hb_tag_t          tag)
+_is_table_present (hb_face_t *source, hb_tag_t tag)
 {
-  DEBUG_MSG(SUBSET, nullptr, "begin subset %c%c%c%c", HB_UNTAG (tag));
-  bool result = true;
-  switch (tag) {
-    case HB_OT_TAG_glyf:
-      result = _subset<const OT::glyf> (plan);
-      break;
-    case HB_OT_TAG_hdmx:
-      result = _subset<const OT::hdmx> (plan);
-      break;
-    case HB_OT_TAG_head:
-      // TODO that won't work well if there is no glyf
-      DEBUG_MSG(SUBSET, nullptr, "skip head, handled by glyf");
-      result = true;
-      break;
-    case HB_OT_TAG_hhea:
-      DEBUG_MSG(SUBSET, nullptr, "skip hhea handled by hmtx");
-      return true;
-    case HB_OT_TAG_hmtx:
-      result = _subset<const OT::hmtx> (plan);
-      break;
-    case HB_OT_TAG_vhea:
-      DEBUG_MSG(SUBSET, nullptr, "skip vhea handled by vmtx");
-      return true;
-    case HB_OT_TAG_vmtx:
-      result = _subset<const OT::vmtx> (plan);
-      break;
-    case HB_OT_TAG_maxp:
-      result = _subset<const OT::maxp> (plan);
-      break;
-    case HB_OT_TAG_loca:
-      DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf");
-      return true;
-    case HB_OT_TAG_cmap:
-      result = _subset<const OT::cmap> (plan);
-      break;
-    case HB_OT_TAG_OS2:
-      result = _subset<const OT::OS2> (plan);
-      break;
-    case HB_OT_TAG_post:
-      result = _subset<const OT::post> (plan);
-      break;
-    case HB_OT_TAG_cff1:
-      result = _subset<const OT::cff1> (plan);
-      break;
-    case HB_OT_TAG_cff2:
-      result = _subset<const OT::cff2> (plan);
-      break;
-    case HB_OT_TAG_VORG:
-      result = _subset<const OT::VORG> (plan);
-      break;
-    case HB_OT_TAG_GDEF:
-      result = _subset2<const OT::GDEF> (plan);
-      break;
-    case HB_OT_TAG_GSUB:
-      result = _subset2<const OT::GSUB> (plan);
-      break;
-    case HB_OT_TAG_GPOS:
-      result = _subset2<const OT::GPOS> (plan);
-      break;
-
-    default:
-      hb_blob_t *source_table = hb_face_reference_table (plan->source, tag);
-      if (likely (source_table))
-        result = plan->add_table (tag, source_table);
-      else
-        result = false;
-      hb_blob_destroy (source_table);
-      break;
+  hb_tag_t table_tags[32];
+  unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
+  while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
+  {
+    for (unsigned i = 0; i < num_tables; ++i)
+      if (table_tags[i] == tag)
+        return true;
+    offset += num_tables;
   }
-  DEBUG_MSG(SUBSET, nullptr, "subset %c%c%c%c %s", HB_UNTAG (tag), result ? "ok" : "FAILED");
-  return result;
+  return false;
 }
 
 static bool
 _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
 {
-  switch (tag) {
-    case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */
-    case HB_TAG ('c', 'v', 't', ' '): /* hint table, fallthrough */
-    case HB_TAG ('f', 'p', 'g', 'm'): /* hint table, fallthrough */
-    case HB_TAG ('p', 'r', 'e', 'p'): /* hint table, fallthrough */
-    case HB_TAG ('h', 'd', 'm', 'x'): /* hint table, fallthrough */
-    case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */
-      return plan->drop_hints;
+  if (plan->drop_tables->has (tag))
+    return true;
+
+  switch (tag)
+  {
+  case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */
+  case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */
+  case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */
+  case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */
+  case HB_TAG ('h','d','m','x'): /* hint table, fallthrough */
+  case HB_TAG ('V','D','M','X'): /* hint table, fallthrough */
+    return plan->drop_hints;
+
+#ifdef HB_NO_SUBSET_LAYOUT
     // Drop Layout Tables if requested.
-    case HB_OT_TAG_GDEF:
-    case HB_OT_TAG_GPOS:
-    case HB_OT_TAG_GSUB:
-      return plan->drop_layout;
-    // Drop these tables below by default, list pulled
-    // from fontTools:
-    case HB_TAG ('B', 'A', 'S', 'E'):
-    case HB_TAG ('J', 'S', 'T', 'F'):
-    case HB_TAG ('D', 'S', 'I', 'G'):
-    case HB_TAG ('E', 'B', 'D', 'T'):
-    case HB_TAG ('E', 'B', 'L', 'C'):
-    case HB_TAG ('E', 'B', 'S', 'C'):
-    case HB_TAG ('S', 'V', 'G', ' '):
-    case HB_TAG ('P', 'C', 'L', 'T'):
-    case HB_TAG ('L', 'T', 'S', 'H'):
-    // Graphite tables:
-    case HB_TAG ('F', 'e', 'a', 't'):
-    case HB_TAG ('G', 'l', 'a', 't'):
-    case HB_TAG ('G', 'l', 'o', 'c'):
-    case HB_TAG ('S', 'i', 'l', 'f'):
-    case HB_TAG ('S', 'i', 'l', 'l'):
-    // Colour
-    case HB_TAG ('s', 'b', 'i', 'x'):
-      return true;
-    default:
-      return false;
+  case HB_OT_TAG_GDEF:
+  case HB_OT_TAG_GPOS:
+  case HB_OT_TAG_GSUB:
+  case HB_TAG ('m','o','r','x'):
+  case HB_TAG ('m','o','r','t'):
+  case HB_TAG ('k','e','r','x'):
+  case HB_TAG ('k','e','r','n'):
+    return true;
+#endif
+
+  default:
+    return false;
+  }
+}
+
+static bool
+_subset_table (hb_subset_plan_t *plan, hb_tag_t tag)
+{
+  DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag));
+  switch (tag)
+  {
+  case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan);
+  case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan);
+  case HB_OT_TAG_name: return _subset<const OT::name> (plan);
+  case HB_OT_TAG_head:
+    if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf))
+      return true; /* skip head, handled by glyf */
+    return _subset<const OT::head> (plan);
+  case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */
+  case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan);
+  case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */
+  case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan);
+  case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan);
+  case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan);
+  case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */
+  case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan);
+  case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan);
+  case HB_OT_TAG_post: return _subset<const OT::post> (plan);
+  case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan);
+  case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan);
+  case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */
+
+#ifndef HB_NO_SUBSET_CFF
+  case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan);
+  case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan);
+  case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan);
+#endif
+
+#ifndef HB_NO_SUBSET_LAYOUT
+  case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan);
+  case HB_OT_TAG_GSUB: return _subset<const OT::GSUB> (plan);
+  case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan);
+  case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan);
+  case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan);
+  case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan);
+#endif
+
+  default:
+    hb_blob_t *source_table = hb_face_reference_table (plan->source, tag);
+    bool result = plan->add_table (tag, source_table);
+    hb_blob_destroy (source_table);
+    return result;
   }
 }
 
@@ -261,33 +236,34 @@
  * Subsets a font according to provided input.
  **/
 hb_face_t *
-hb_subset (hb_face_t *source,
-           hb_subset_input_t *input)
+hb_subset (hb_face_t *source, hb_subset_input_t *input)
 {
   if (unlikely (!input || !source)) return hb_face_get_empty ();
 
   hb_subset_plan_t *plan = hb_subset_plan_create (source, input);
+  if (unlikely (plan->in_error ()))
+    return hb_face_get_empty ();
 
-  hb_tag_t table_tags[32];
-  unsigned int offset = 0, count;
+  hb_set_t tags_set;
   bool success = true;
-  do {
-    count = ARRAY_LENGTH (table_tags);
-    hb_face_get_table_tags (source, offset, &count, table_tags);
-    for (unsigned int i = 0; i < count; i++)
+  hb_tag_t table_tags[32];
+  unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags);
+  while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables))
+  {
+    for (unsigned i = 0; i < num_tables; ++i)
     {
       hb_tag_t tag = table_tags[i];
-      if (_should_drop_table (plan, tag))
-      {
-        DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG (tag));
-        continue;
-      }
-      success = success && _subset_table (plan, tag);
+      if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue;
+      tags_set.add (tag);
+      success = _subset_table (plan, tag);
+      if (unlikely (!success)) goto end;
     }
-    offset += count;
-  } while (success && count == ARRAY_LENGTH (table_tags));
+    offset += num_tables;
+  }
+end:
 
   hb_face_t *result = success ? hb_face_reference (plan->dest) : hb_face_get_empty ();
+
   hb_subset_plan_destroy (plan);
   return result;
 }
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.h b/src/java.desktop/share/native/libharfbuzz/hb-subset.h
index 75cc00a..3deab75 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.h
@@ -54,6 +54,15 @@
 HB_EXTERN hb_set_t *
 hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
 
+HB_EXTERN hb_set_t *
+hb_subset_input_nameid_set (hb_subset_input_t *subset_input);
+
+HB_EXTERN hb_set_t *
+hb_subset_input_namelangid_set (hb_subset_input_t *subset_input);
+
+HB_EXTERN hb_set_t *
+hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input);
+
 HB_EXTERN void
 hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
                                 hb_bool_t drop_hints);
@@ -61,17 +70,23 @@
 hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input);
 
 HB_EXTERN void
-hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
-                                 hb_bool_t drop_layout);
-HB_EXTERN hb_bool_t
-hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input);
-
-HB_EXTERN void
 hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input,
-        hb_bool_t desubroutinize);
+                                    hb_bool_t desubroutinize);
 HB_EXTERN hb_bool_t
 hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input);
 
+HB_EXTERN void
+hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input,
+                                 hb_bool_t retain_gids);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input);
+
+HB_EXTERN void
+hb_subset_input_set_name_legacy (hb_subset_input_t *subset_input,
+                                 hb_bool_t name_legacy);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_name_legacy (hb_subset_input_t *subset_input);
+
 /* hb_subset () */
 HB_EXTERN hb_face_t *
 hb_subset (hb_face_t *source, hb_subset_input_t *input);
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset.hh
index d4d7209..dbbe451 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-subset.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.hh
@@ -40,19 +40,33 @@
        hb_dispatch_context_t<hb_subset_context_t, bool, HB_DEBUG_SUBSET>
 {
   const char *get_name () { return "SUBSET"; }
-  template <typename T>
-  bool dispatch (const T &obj) { return obj.subset (this); }
-  static bool default_return_value () { return true; }
+  static return_t default_return_value () { return true; }
 
+  private:
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.subset (this, hb_forward<Ts> (ds)...) )
+  template <typename T, typename ...Ts> auto
+  _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
+  ( obj.dispatch (this, hb_forward<Ts> (ds)...) )
+  public:
+  template <typename T, typename ...Ts> auto
+  dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
+  ( _dispatch (obj, hb_prioritize, hb_forward<Ts> (ds)...) )
+
+  hb_blob_t *source_blob;
   hb_subset_plan_t *plan;
   hb_serialize_context_t *serializer;
-  unsigned int debug_depth;
+  hb_tag_t table_tag;
 
-  hb_subset_context_t (hb_subset_plan_t *plan_,
-                       hb_serialize_context_t *serializer_) :
+  hb_subset_context_t (hb_blob_t *source_blob_,
+                       hb_subset_plan_t *plan_,
+                       hb_serialize_context_t *serializer_,
+                       hb_tag_t table_tag_) :
+                        source_blob (source_blob_),
                         plan (plan_),
                         serializer (serializer_),
-                        debug_depth (0) {}
+                        table_tag (table_tag_) {}
 };
 
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh
new file mode 100644
index 0000000..88623db
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh
@@ -0,0 +1,6780 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-ucd-table.py ucd.nounihan.grouped.xml
+ *
+ * on file with this description: Unicode 13.0.0
+ */
+
+#ifndef HB_UCD_TABLE_HH
+#define HB_UCD_TABLE_HH
+
+#include "hb.hh"
+
+static const hb_script_t
+_hb_ucd_sc_map[157] =
+{
+                   HB_SCRIPT_COMMON,              HB_SCRIPT_INHERITED,
+                  HB_SCRIPT_UNKNOWN,                 HB_SCRIPT_ARABIC,
+                 HB_SCRIPT_ARMENIAN,                HB_SCRIPT_BENGALI,
+                 HB_SCRIPT_CYRILLIC,             HB_SCRIPT_DEVANAGARI,
+                 HB_SCRIPT_GEORGIAN,                  HB_SCRIPT_GREEK,
+                 HB_SCRIPT_GUJARATI,               HB_SCRIPT_GURMUKHI,
+                   HB_SCRIPT_HANGUL,                    HB_SCRIPT_HAN,
+                   HB_SCRIPT_HEBREW,               HB_SCRIPT_HIRAGANA,
+                  HB_SCRIPT_KANNADA,               HB_SCRIPT_KATAKANA,
+                      HB_SCRIPT_LAO,                  HB_SCRIPT_LATIN,
+                HB_SCRIPT_MALAYALAM,                  HB_SCRIPT_ORIYA,
+                    HB_SCRIPT_TAMIL,                 HB_SCRIPT_TELUGU,
+                     HB_SCRIPT_THAI,                HB_SCRIPT_TIBETAN,
+                 HB_SCRIPT_BOPOMOFO,                HB_SCRIPT_BRAILLE,
+       HB_SCRIPT_CANADIAN_SYLLABICS,               HB_SCRIPT_CHEROKEE,
+                 HB_SCRIPT_ETHIOPIC,                  HB_SCRIPT_KHMER,
+                HB_SCRIPT_MONGOLIAN,                HB_SCRIPT_MYANMAR,
+                    HB_SCRIPT_OGHAM,                  HB_SCRIPT_RUNIC,
+                  HB_SCRIPT_SINHALA,                 HB_SCRIPT_SYRIAC,
+                   HB_SCRIPT_THAANA,                     HB_SCRIPT_YI,
+                  HB_SCRIPT_DESERET,                 HB_SCRIPT_GOTHIC,
+               HB_SCRIPT_OLD_ITALIC,                  HB_SCRIPT_BUHID,
+                  HB_SCRIPT_HANUNOO,                HB_SCRIPT_TAGALOG,
+                 HB_SCRIPT_TAGBANWA,                HB_SCRIPT_CYPRIOT,
+                    HB_SCRIPT_LIMBU,               HB_SCRIPT_LINEAR_B,
+                  HB_SCRIPT_OSMANYA,                HB_SCRIPT_SHAVIAN,
+                   HB_SCRIPT_TAI_LE,               HB_SCRIPT_UGARITIC,
+                 HB_SCRIPT_BUGINESE,                 HB_SCRIPT_COPTIC,
+               HB_SCRIPT_GLAGOLITIC,             HB_SCRIPT_KHAROSHTHI,
+              HB_SCRIPT_NEW_TAI_LUE,            HB_SCRIPT_OLD_PERSIAN,
+             HB_SCRIPT_SYLOTI_NAGRI,               HB_SCRIPT_TIFINAGH,
+                 HB_SCRIPT_BALINESE,              HB_SCRIPT_CUNEIFORM,
+                      HB_SCRIPT_NKO,               HB_SCRIPT_PHAGS_PA,
+               HB_SCRIPT_PHOENICIAN,                 HB_SCRIPT_CARIAN,
+                     HB_SCRIPT_CHAM,               HB_SCRIPT_KAYAH_LI,
+                   HB_SCRIPT_LEPCHA,                 HB_SCRIPT_LYCIAN,
+                   HB_SCRIPT_LYDIAN,               HB_SCRIPT_OL_CHIKI,
+                   HB_SCRIPT_REJANG,             HB_SCRIPT_SAURASHTRA,
+                HB_SCRIPT_SUNDANESE,                    HB_SCRIPT_VAI,
+                  HB_SCRIPT_AVESTAN,                  HB_SCRIPT_BAMUM,
+     HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,       HB_SCRIPT_IMPERIAL_ARAMAIC,
+    HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
+                 HB_SCRIPT_JAVANESE,                 HB_SCRIPT_KAITHI,
+                     HB_SCRIPT_LISU,           HB_SCRIPT_MEETEI_MAYEK,
+        HB_SCRIPT_OLD_SOUTH_ARABIAN,             HB_SCRIPT_OLD_TURKIC,
+                HB_SCRIPT_SAMARITAN,               HB_SCRIPT_TAI_THAM,
+                 HB_SCRIPT_TAI_VIET,                  HB_SCRIPT_BATAK,
+                   HB_SCRIPT_BRAHMI,                HB_SCRIPT_MANDAIC,
+                   HB_SCRIPT_CHAKMA,       HB_SCRIPT_MEROITIC_CURSIVE,
+     HB_SCRIPT_MEROITIC_HIEROGLYPHS,                   HB_SCRIPT_MIAO,
+                  HB_SCRIPT_SHARADA,           HB_SCRIPT_SORA_SOMPENG,
+                    HB_SCRIPT_TAKRI,              HB_SCRIPT_BASSA_VAH,
+       HB_SCRIPT_CAUCASIAN_ALBANIAN,               HB_SCRIPT_DUPLOYAN,
+                  HB_SCRIPT_ELBASAN,                HB_SCRIPT_GRANTHA,
+                   HB_SCRIPT_KHOJKI,              HB_SCRIPT_KHUDAWADI,
+                 HB_SCRIPT_LINEAR_A,               HB_SCRIPT_MAHAJANI,
+               HB_SCRIPT_MANICHAEAN,          HB_SCRIPT_MENDE_KIKAKUI,
+                     HB_SCRIPT_MODI,                    HB_SCRIPT_MRO,
+                HB_SCRIPT_NABATAEAN,      HB_SCRIPT_OLD_NORTH_ARABIAN,
+               HB_SCRIPT_OLD_PERMIC,           HB_SCRIPT_PAHAWH_HMONG,
+                HB_SCRIPT_PALMYRENE,            HB_SCRIPT_PAU_CIN_HAU,
+          HB_SCRIPT_PSALTER_PAHLAVI,                HB_SCRIPT_SIDDHAM,
+                  HB_SCRIPT_TIRHUTA,            HB_SCRIPT_WARANG_CITI,
+                     HB_SCRIPT_AHOM,  HB_SCRIPT_ANATOLIAN_HIEROGLYPHS,
+                   HB_SCRIPT_HATRAN,                HB_SCRIPT_MULTANI,
+            HB_SCRIPT_OLD_HUNGARIAN,            HB_SCRIPT_SIGNWRITING,
+                    HB_SCRIPT_ADLAM,              HB_SCRIPT_BHAIKSUKI,
+                  HB_SCRIPT_MARCHEN,                  HB_SCRIPT_OSAGE,
+                   HB_SCRIPT_TANGUT,                   HB_SCRIPT_NEWA,
+            HB_SCRIPT_MASARAM_GONDI,                  HB_SCRIPT_NUSHU,
+                  HB_SCRIPT_SOYOMBO,       HB_SCRIPT_ZANABAZAR_SQUARE,
+                    HB_SCRIPT_DOGRA,          HB_SCRIPT_GUNJALA_GONDI,
+          HB_SCRIPT_HANIFI_ROHINGYA,                HB_SCRIPT_MAKASAR,
+              HB_SCRIPT_MEDEFAIDRIN,            HB_SCRIPT_OLD_SOGDIAN,
+                  HB_SCRIPT_SOGDIAN,                HB_SCRIPT_ELYMAIC,
+              HB_SCRIPT_NANDINAGARI, HB_SCRIPT_NYIAKENG_PUACHUE_HMONG,
+                   HB_SCRIPT_WANCHO,             HB_SCRIPT_CHORASMIAN,
+              HB_SCRIPT_DIVES_AKURU,    HB_SCRIPT_KHITAN_SMALL_SCRIPT,
+                   HB_SCRIPT_YEZIDI,
+};
+static const uint16_t
+_hb_ucd_dm1_p0_map[825] =
+{
+   0x003Bu, 0x004Bu, 0x0060u, 0x00B4u, 0x00B7u, 0x00C5u, 0x02B9u, 0x0300u,
+   0x0301u, 0x0313u, 0x0385u, 0x0386u, 0x0388u, 0x0389u, 0x038Au, 0x038Cu,
+   0x038Eu, 0x038Fu, 0x0390u, 0x03A9u, 0x03ACu, 0x03ADu, 0x03AEu, 0x03AFu,
+   0x03B0u, 0x03B9u, 0x03CCu, 0x03CDu, 0x03CEu, 0x2002u, 0x2003u, 0x3008u,
+   0x3009u, 0x349Eu, 0x34B9u, 0x34BBu, 0x34DFu, 0x3515u, 0x36EEu, 0x36FCu,
+   0x3781u, 0x382Fu, 0x3862u, 0x387Cu, 0x38C7u, 0x38E3u, 0x391Cu, 0x393Au,
+   0x3A2Eu, 0x3A6Cu, 0x3AE4u, 0x3B08u, 0x3B19u, 0x3B49u, 0x3B9Du, 0x3C18u,
+   0x3C4Eu, 0x3D33u, 0x3D96u, 0x3EACu, 0x3EB8u, 0x3F1Bu, 0x3FFCu, 0x4008u,
+   0x4018u, 0x4039u, 0x4046u, 0x4096u, 0x40E3u, 0x412Fu, 0x4202u, 0x4227u,
+   0x42A0u, 0x4301u, 0x4334u, 0x4359u, 0x43D5u, 0x43D9u, 0x440Bu, 0x446Bu,
+   0x452Bu, 0x455Du, 0x4561u, 0x456Bu, 0x45D7u, 0x45F9u, 0x4635u, 0x46BEu,
+   0x46C7u, 0x4995u, 0x49E6u, 0x4A6Eu, 0x4A76u, 0x4AB2u, 0x4B33u, 0x4BCEu,
+   0x4CCEu, 0x4CEDu, 0x4CF8u, 0x4D56u, 0x4E0Du, 0x4E26u, 0x4E32u, 0x4E38u,
+   0x4E39u, 0x4E3Du, 0x4E41u, 0x4E82u, 0x4E86u, 0x4EAEu, 0x4EC0u, 0x4ECCu,
+   0x4EE4u, 0x4F60u, 0x4F80u, 0x4F86u, 0x4F8Bu, 0x4FAEu, 0x4FBBu, 0x4FBFu,
+   0x5002u, 0x502Bu, 0x507Au, 0x5099u, 0x50CFu, 0x50DAu, 0x50E7u, 0x5140u,
+   0x5145u, 0x514Du, 0x5154u, 0x5164u, 0x5167u, 0x5168u, 0x5169u, 0x516Du,
+   0x5177u, 0x5180u, 0x518Du, 0x5192u, 0x5195u, 0x5197u, 0x51A4u, 0x51ACu,
+   0x51B5u, 0x51B7u, 0x51C9u, 0x51CCu, 0x51DCu, 0x51DEu, 0x51F5u, 0x5203u,
+   0x5207u, 0x5217u, 0x5229u, 0x523Au, 0x523Bu, 0x5246u, 0x5272u, 0x5277u,
+   0x5289u, 0x529Bu, 0x52A3u, 0x52B3u, 0x52C7u, 0x52C9u, 0x52D2u, 0x52DEu,
+   0x52E4u, 0x52F5u, 0x52FAu, 0x5305u, 0x5306u, 0x5317u, 0x533Fu, 0x5349u,
+   0x5351u, 0x535Au, 0x5373u, 0x5375u, 0x537Du, 0x537Fu, 0x53C3u, 0x53CAu,
+   0x53DFu, 0x53E5u, 0x53EBu, 0x53F1u, 0x5406u, 0x540Fu, 0x541Du, 0x5438u,
+   0x5442u, 0x5448u, 0x5468u, 0x549Eu, 0x54A2u, 0x54BDu, 0x54F6u, 0x5510u,
+   0x5553u, 0x5555u, 0x5563u, 0x5584u, 0x5587u, 0x5599u, 0x559Du, 0x55ABu,
+   0x55B3u, 0x55C0u, 0x55C2u, 0x55E2u, 0x5606u, 0x5651u, 0x5668u, 0x5674u,
+   0x56F9u, 0x5716u, 0x5717u, 0x578Bu, 0x57CEu, 0x57F4u, 0x580Du, 0x5831u,
+   0x5832u, 0x5840u, 0x585Au, 0x585Eu, 0x58A8u, 0x58ACu, 0x58B3u, 0x58D8u,
+   0x58DFu, 0x58EEu, 0x58F2u, 0x58F7u, 0x5906u, 0x591Au, 0x5922u, 0x5944u,
+   0x5948u, 0x5951u, 0x5954u, 0x5962u, 0x5973u, 0x59D8u, 0x59ECu, 0x5A1Bu,
+   0x5A27u, 0x5A62u, 0x5A66u, 0x5AB5u, 0x5B08u, 0x5B28u, 0x5B3Eu, 0x5B85u,
+   0x5BC3u, 0x5BD8u, 0x5BE7u, 0x5BEEu, 0x5BF3u, 0x5BFFu, 0x5C06u, 0x5C22u,
+   0x5C3Fu, 0x5C60u, 0x5C62u, 0x5C64u, 0x5C65u, 0x5C6Eu, 0x5C8Du, 0x5CC0u,
+   0x5D19u, 0x5D43u, 0x5D50u, 0x5D6Bu, 0x5D6Eu, 0x5D7Cu, 0x5DB2u, 0x5DBAu,
+   0x5DE1u, 0x5DE2u, 0x5DFDu, 0x5E28u, 0x5E3Du, 0x5E69u, 0x5E74u, 0x5EA6u,
+   0x5EB0u, 0x5EB3u, 0x5EB6u, 0x5EC9u, 0x5ECAu, 0x5ED2u, 0x5ED3u, 0x5ED9u,
+   0x5EECu, 0x5EFEu, 0x5F04u, 0x5F22u, 0x5F53u, 0x5F62u, 0x5F69u, 0x5F6Bu,
+   0x5F8Bu, 0x5F9Au, 0x5FA9u, 0x5FADu, 0x5FCDu, 0x5FD7u, 0x5FF5u, 0x5FF9u,
+   0x6012u, 0x601Cu, 0x6075u, 0x6081u, 0x6094u, 0x60C7u, 0x60D8u, 0x60E1u,
+   0x6108u, 0x6144u, 0x6148u, 0x614Cu, 0x614Eu, 0x6160u, 0x6168u, 0x617Au,
+   0x618Eu, 0x6190u, 0x61A4u, 0x61AFu, 0x61B2u, 0x61DEu, 0x61F2u, 0x61F6u,
+   0x6200u, 0x6210u, 0x621Bu, 0x622Eu, 0x6234u, 0x625Du, 0x62B1u, 0x62C9u,
+   0x62CFu, 0x62D3u, 0x62D4u, 0x62FCu, 0x62FEu, 0x633Du, 0x6350u, 0x6368u,
+   0x637Bu, 0x6383u, 0x63A0u, 0x63A9u, 0x63C4u, 0x63C5u, 0x63E4u, 0x641Cu,
+   0x6422u, 0x6452u, 0x6469u, 0x6477u, 0x647Eu, 0x649Au, 0x649Du, 0x64C4u,
+   0x654Fu, 0x6556u, 0x656Cu, 0x6578u, 0x6599u, 0x65C5u, 0x65E2u, 0x65E3u,
+   0x6613u, 0x6649u, 0x6674u, 0x6688u, 0x6691u, 0x669Cu, 0x66B4u, 0x66C6u,
+   0x66F4u, 0x66F8u, 0x6700u, 0x6717u, 0x671Bu, 0x6721u, 0x674Eu, 0x6753u,
+   0x6756u, 0x675Eu, 0x677Bu, 0x6785u, 0x6797u, 0x67F3u, 0x67FAu, 0x6817u,
+   0x681Fu, 0x6852u, 0x6881u, 0x6885u, 0x688Eu, 0x68A8u, 0x6914u, 0x6942u,
+   0x69A3u, 0x69EAu, 0x6A02u, 0x6A13u, 0x6AA8u, 0x6AD3u, 0x6ADBu, 0x6B04u,
+   0x6B21u, 0x6B54u, 0x6B72u, 0x6B77u, 0x6B79u, 0x6B9Fu, 0x6BAEu, 0x6BBAu,
+   0x6BBBu, 0x6C4Eu, 0x6C67u, 0x6C88u, 0x6CBFu, 0x6CCCu, 0x6CCDu, 0x6CE5u,
+   0x6D16u, 0x6D1Bu, 0x6D1Eu, 0x6D34u, 0x6D3Eu, 0x6D41u, 0x6D69u, 0x6D6Au,
+   0x6D77u, 0x6D78u, 0x6D85u, 0x6DCBu, 0x6DDAu, 0x6DEAu, 0x6DF9u, 0x6E1Au,
+   0x6E2Fu, 0x6E6Eu, 0x6E9Cu, 0x6EBAu, 0x6EC7u, 0x6ECBu, 0x6ED1u, 0x6EDBu,
+   0x6F0Fu, 0x6F22u, 0x6F23u, 0x6F6Eu, 0x6FC6u, 0x6FEBu, 0x6FFEu, 0x701Bu,
+   0x701Eu, 0x7039u, 0x704Au, 0x7070u, 0x7077u, 0x707Du, 0x7099u, 0x70ADu,
+   0x70C8u, 0x70D9u, 0x7145u, 0x7149u, 0x716Eu, 0x719Cu, 0x71CEu, 0x71D0u,
+   0x7210u, 0x721Bu, 0x7228u, 0x722Bu, 0x7235u, 0x7250u, 0x7262u, 0x7280u,
+   0x7295u, 0x72AFu, 0x72C0u, 0x72FCu, 0x732Au, 0x7375u, 0x737Au, 0x7387u,
+   0x738Bu, 0x73A5u, 0x73B2u, 0x73DEu, 0x7406u, 0x7409u, 0x7422u, 0x7447u,
+   0x745Cu, 0x7469u, 0x7471u, 0x7485u, 0x7489u, 0x7498u, 0x74CAu, 0x7506u,
+   0x7524u, 0x753Bu, 0x753Eu, 0x7559u, 0x7565u, 0x7570u, 0x75E2u, 0x7610u,
+   0x761Du, 0x761Fu, 0x7642u, 0x7669u, 0x76CAu, 0x76DBu, 0x76E7u, 0x76F4u,
+   0x7701u, 0x771Eu, 0x771Fu, 0x7740u, 0x774Au, 0x778Bu, 0x77A7u, 0x784Eu,
+   0x786Bu, 0x788Cu, 0x7891u, 0x78CAu, 0x78CCu, 0x78FBu, 0x792Au, 0x793Cu,
+   0x793Eu, 0x7948u, 0x7949u, 0x7950u, 0x7956u, 0x795Du, 0x795Eu, 0x7965u,
+   0x797Fu, 0x798Du, 0x798Eu, 0x798Fu, 0x79AEu, 0x79CAu, 0x79EBu, 0x7A1Cu,
+   0x7A40u, 0x7A4Au, 0x7A4Fu, 0x7A81u, 0x7AB1u, 0x7ACBu, 0x7AEEu, 0x7B20u,
+   0x7BC0u, 0x7BC6u, 0x7BC9u, 0x7C3Eu, 0x7C60u, 0x7C7Bu, 0x7C92u, 0x7CBEu,
+   0x7CD2u, 0x7CD6u, 0x7CE3u, 0x7CE7u, 0x7CE8u, 0x7D00u, 0x7D10u, 0x7D22u,
+   0x7D2Fu, 0x7D5Bu, 0x7D63u, 0x7DA0u, 0x7DBEu, 0x7DC7u, 0x7DF4u, 0x7E02u,
+   0x7E09u, 0x7E37u, 0x7E41u, 0x7E45u, 0x7F3Eu, 0x7F72u, 0x7F79u, 0x7F7Au,
+   0x7F85u, 0x7F95u, 0x7F9Au, 0x7FBDu, 0x7FFAu, 0x8001u, 0x8005u, 0x8046u,
+   0x8060u, 0x806Fu, 0x8070u, 0x807Eu, 0x808Bu, 0x80ADu, 0x80B2u, 0x8103u,
+   0x813Eu, 0x81D8u, 0x81E8u, 0x81EDu, 0x8201u, 0x8204u, 0x8218u, 0x826Fu,
+   0x8279u, 0x828Bu, 0x8291u, 0x829Du, 0x82B1u, 0x82B3u, 0x82BDu, 0x82E5u,
+   0x82E6u, 0x831Du, 0x8323u, 0x8336u, 0x8352u, 0x8353u, 0x8363u, 0x83ADu,
+   0x83BDu, 0x83C9u, 0x83CAu, 0x83CCu, 0x83DCu, 0x83E7u, 0x83EFu, 0x83F1u,
+   0x843Du, 0x8449u, 0x8457u, 0x84EEu, 0x84F1u, 0x84F3u, 0x84FCu, 0x8516u,
+   0x8564u, 0x85CDu, 0x85FAu, 0x8606u, 0x8612u, 0x862Du, 0x863Fu, 0x8650u,
+   0x865Cu, 0x8667u, 0x8669u, 0x8688u, 0x86A9u, 0x86E2u, 0x870Eu, 0x8728u,
+   0x876Bu, 0x8779u, 0x8786u, 0x87BAu, 0x87E1u, 0x8801u, 0x881Fu, 0x884Cu,
+   0x8860u, 0x8863u, 0x88C2u, 0x88CFu, 0x88D7u, 0x88DEu, 0x88E1u, 0x88F8u,
+   0x88FAu, 0x8910u, 0x8941u, 0x8964u, 0x8986u, 0x898Bu, 0x8996u, 0x8AA0u,
+   0x8AAAu, 0x8ABFu, 0x8ACBu, 0x8AD2u, 0x8AD6u, 0x8AEDu, 0x8AF8u, 0x8AFEu,
+   0x8B01u, 0x8B39u, 0x8B58u, 0x8B80u, 0x8B8Au, 0x8C48u, 0x8C55u, 0x8CABu,
+   0x8CC1u, 0x8CC2u, 0x8CC8u, 0x8CD3u, 0x8D08u, 0x8D1Bu, 0x8D77u, 0x8DBCu,
+   0x8DCBu, 0x8DEFu, 0x8DF0u, 0x8ECAu, 0x8ED4u, 0x8F26u, 0x8F2Au, 0x8F38u,
+   0x8F3Bu, 0x8F62u, 0x8F9Eu, 0x8FB0u, 0x8FB6u, 0x9023u, 0x9038u, 0x9072u,
+   0x907Cu, 0x908Fu, 0x9094u, 0x90CEu, 0x90DEu, 0x90F1u, 0x90FDu, 0x9111u,
+   0x911Bu, 0x916Au, 0x9199u, 0x91B4u, 0x91CCu, 0x91CFu, 0x91D1u, 0x9234u,
+   0x9238u, 0x9276u, 0x927Cu, 0x92D7u, 0x92D8u, 0x9304u, 0x934Au, 0x93F9u,
+   0x9415u, 0x958Bu, 0x95ADu, 0x95B7u, 0x962Eu, 0x964Bu, 0x964Du, 0x9675u,
+   0x9678u, 0x967Cu, 0x9686u, 0x96A3u, 0x96B7u, 0x96B8u, 0x96C3u, 0x96E2u,
+   0x96E3u, 0x96F6u, 0x96F7u, 0x9723u, 0x9732u, 0x9748u, 0x9756u, 0x97DBu,
+   0x97E0u, 0x97FFu, 0x980Bu, 0x9818u, 0x9829u, 0x983Bu, 0x985Eu, 0x98E2u,
+   0x98EFu, 0x98FCu, 0x9928u, 0x9929u, 0x99A7u, 0x99C2u, 0x99F1u, 0x99FEu,
+   0x9A6Au, 0x9B12u, 0x9B6Fu, 0x9C40u, 0x9C57u, 0x9CFDu, 0x9D67u, 0x9DB4u,
+   0x9DFAu, 0x9E1Eu, 0x9E7Fu, 0x9E97u, 0x9E9Fu, 0x9EBBu, 0x9ECEu, 0x9EF9u,
+   0x9EFEu, 0x9F05u, 0x9F0Fu, 0x9F16u, 0x9F3Bu, 0x9F43u, 0x9F8Du, 0x9F8Eu,
+   0x9F9Cu,
+};
+static const uint16_t
+_hb_ucd_dm1_p2_map[110] =
+{
+   0x0122u, 0x051Cu, 0x0525u, 0x054Bu, 0x063Au, 0x0804u, 0x08DEu, 0x0A2Cu,
+   0x0B63u, 0x14E4u, 0x16A8u, 0x16EAu, 0x19C8u, 0x1B18u, 0x1D0Bu, 0x1DE4u,
+   0x1DE6u, 0x2183u, 0x219Fu, 0x2331u, 0x26D4u, 0x2844u, 0x284Au, 0x2B0Cu,
+   0x2BF1u, 0x300Au, 0x32B8u, 0x335Fu, 0x3393u, 0x339Cu, 0x33C3u, 0x33D5u,
+   0x346Du, 0x36A3u, 0x38A7u, 0x3A8Du, 0x3AFAu, 0x3CBCu, 0x3D1Eu, 0x3ED1u,
+   0x3F5Eu, 0x3F8Eu, 0x4263u, 0x42EEu, 0x43ABu, 0x4608u, 0x4735u, 0x4814u,
+   0x4C36u, 0x4C92u, 0x4FA1u, 0x4FB8u, 0x5044u, 0x50F2u, 0x50F3u, 0x5119u,
+   0x5133u, 0x5249u, 0x541Du, 0x5626u, 0x569Au, 0x56C5u, 0x597Cu, 0x5AA7u,
+   0x5BABu, 0x5C80u, 0x5CD0u, 0x5F86u, 0x61DAu, 0x6228u, 0x6247u, 0x62D9u,
+   0x633Eu, 0x64DAu, 0x6523u, 0x65A8u, 0x67A7u, 0x67B5u, 0x6B3Cu, 0x6C36u,
+   0x6CD5u, 0x6D6Bu, 0x6F2Cu, 0x6FB1u, 0x70D2u, 0x73CAu, 0x7667u, 0x78AEu,
+   0x7966u, 0x7CA8u, 0x7ED3u, 0x7F2Fu, 0x85D2u, 0x85EDu, 0x872Eu, 0x8BFAu,
+   0x8D77u, 0x9145u, 0x91DFu, 0x921Au, 0x940Au, 0x9496u, 0x95B6u, 0x9B30u,
+   0xA0CEu, 0xA105u, 0xA20Eu, 0xA291u, 0xA392u, 0xA600u,
+};
+static const uint32_t
+_hb_ucd_dm2_u32_map[638] =
+{
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x003Cu, 0x0338u, 0x226Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x003Du, 0x0338u, 0x2260u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x003Eu, 0x0338u, 0x226Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0300u, 0x00C0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0301u, 0x00C1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0302u, 0x00C2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0303u, 0x00C3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0304u, 0x0100u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0306u, 0x0102u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0307u, 0x0226u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0308u, 0x00C4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0309u, 0x1EA2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Au, 0x00C5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Cu, 0x01CDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Fu, 0x0200u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0311u, 0x0202u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0323u, 0x1EA0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0325u, 0x1E00u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0328u, 0x0104u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0307u, 0x1E02u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0323u, 0x1E04u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0331u, 0x1E06u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0301u, 0x0106u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0302u, 0x0108u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0307u, 0x010Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x030Cu, 0x010Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0327u, 0x00C7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0307u, 0x1E0Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x030Cu, 0x010Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0323u, 0x1E0Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0327u, 0x1E10u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x032Du, 0x1E12u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0331u, 0x1E0Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0300u, 0x00C8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0301u, 0x00C9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0302u, 0x00CAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0303u, 0x1EBCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0304u, 0x0112u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0306u, 0x0114u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0307u, 0x0116u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0308u, 0x00CBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0309u, 0x1EBAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x030Cu, 0x011Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x030Fu, 0x0204u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0311u, 0x0206u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0323u, 0x1EB8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0327u, 0x0228u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0328u, 0x0118u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x032Du, 0x1E18u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0330u, 0x1E1Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0046u, 0x0307u, 0x1E1Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0301u, 0x01F4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0302u, 0x011Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0304u, 0x1E20u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0306u, 0x011Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0307u, 0x0120u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x030Cu, 0x01E6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0327u, 0x0122u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0302u, 0x0124u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0307u, 0x1E22u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0308u, 0x1E26u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x030Cu, 0x021Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0323u, 0x1E24u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0327u, 0x1E28u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x032Eu, 0x1E2Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0300u, 0x00CCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0301u, 0x00CDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0302u, 0x00CEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0303u, 0x0128u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0304u, 0x012Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0306u, 0x012Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0307u, 0x0130u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0308u, 0x00CFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0309u, 0x1EC8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x030Cu, 0x01CFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x030Fu, 0x0208u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0311u, 0x020Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0323u, 0x1ECAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0328u, 0x012Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0330u, 0x1E2Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Au, 0x0302u, 0x0134u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0301u, 0x1E30u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x030Cu, 0x01E8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0323u, 0x1E32u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0327u, 0x0136u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0331u, 0x1E34u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0301u, 0x0139u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x030Cu, 0x013Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0323u, 0x1E36u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0327u, 0x013Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x032Du, 0x1E3Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0331u, 0x1E3Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0301u, 0x1E3Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0307u, 0x1E40u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0323u, 0x1E42u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0300u, 0x01F8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0301u, 0x0143u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0303u, 0x00D1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0307u, 0x1E44u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x030Cu, 0x0147u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0323u, 0x1E46u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0327u, 0x0145u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x032Du, 0x1E4Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0331u, 0x1E48u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0300u, 0x00D2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0301u, 0x00D3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0302u, 0x00D4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0303u, 0x00D5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0304u, 0x014Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0306u, 0x014Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0307u, 0x022Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0308u, 0x00D6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0309u, 0x1ECEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Bu, 0x0150u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Cu, 0x01D1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Fu, 0x020Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0311u, 0x020Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x031Bu, 0x01A0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0323u, 0x1ECCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0328u, 0x01EAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0050u, 0x0301u, 0x1E54u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0050u, 0x0307u, 0x1E56u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0301u, 0x0154u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0307u, 0x1E58u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x030Cu, 0x0158u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x030Fu, 0x0210u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0311u, 0x0212u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0323u, 0x1E5Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0327u, 0x0156u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0331u, 0x1E5Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0301u, 0x015Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0302u, 0x015Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0307u, 0x1E60u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x030Cu, 0x0160u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0323u, 0x1E62u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0326u, 0x0218u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0327u, 0x015Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0307u, 0x1E6Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x030Cu, 0x0164u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0323u, 0x1E6Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0326u, 0x021Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0327u, 0x0162u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x032Du, 0x1E70u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0331u, 0x1E6Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0300u, 0x00D9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0301u, 0x00DAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0302u, 0x00DBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0303u, 0x0168u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0304u, 0x016Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0306u, 0x016Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0308u, 0x00DCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0309u, 0x1EE6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Au, 0x016Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Bu, 0x0170u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Cu, 0x01D3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Fu, 0x0214u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0311u, 0x0216u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x031Bu, 0x01AFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0323u, 0x1EE4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0324u, 0x1E72u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0328u, 0x0172u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x032Du, 0x1E76u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0330u, 0x1E74u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0056u, 0x0303u, 0x1E7Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0056u, 0x0323u, 0x1E7Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0300u, 0x1E80u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0301u, 0x1E82u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0302u, 0x0174u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0307u, 0x1E86u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0308u, 0x1E84u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0323u, 0x1E88u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0058u, 0x0307u, 0x1E8Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0058u, 0x0308u, 0x1E8Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0300u, 0x1EF2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0301u, 0x00DDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0302u, 0x0176u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0303u, 0x1EF8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0304u, 0x0232u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0307u, 0x1E8Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0308u, 0x0178u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0309u, 0x1EF6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0323u, 0x1EF4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0301u, 0x0179u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0302u, 0x1E90u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0307u, 0x017Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x030Cu, 0x017Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0323u, 0x1E92u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0331u, 0x1E94u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0300u, 0x00E0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0301u, 0x00E1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0302u, 0x00E2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0303u, 0x00E3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0304u, 0x0101u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0306u, 0x0103u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0307u, 0x0227u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0308u, 0x00E4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0309u, 0x1EA3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Au, 0x00E5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Cu, 0x01CEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Fu, 0x0201u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0311u, 0x0203u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0323u, 0x1EA1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0325u, 0x1E01u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0328u, 0x0105u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0307u, 0x1E03u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0323u, 0x1E05u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0331u, 0x1E07u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0301u, 0x0107u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0302u, 0x0109u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0307u, 0x010Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x030Cu, 0x010Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0327u, 0x00E7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0307u, 0x1E0Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x030Cu, 0x010Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0323u, 0x1E0Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0327u, 0x1E11u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x032Du, 0x1E13u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0331u, 0x1E0Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0300u, 0x00E8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0301u, 0x00E9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0302u, 0x00EAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0303u, 0x1EBDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0304u, 0x0113u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0306u, 0x0115u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0307u, 0x0117u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0308u, 0x00EBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0309u, 0x1EBBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x030Cu, 0x011Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x030Fu, 0x0205u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0311u, 0x0207u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0323u, 0x1EB9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0327u, 0x0229u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0328u, 0x0119u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x032Du, 0x1E19u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0330u, 0x1E1Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0066u, 0x0307u, 0x1E1Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0301u, 0x01F5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0302u, 0x011Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0304u, 0x1E21u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0306u, 0x011Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0307u, 0x0121u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x030Cu, 0x01E7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0327u, 0x0123u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0302u, 0x0125u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0307u, 0x1E23u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0308u, 0x1E27u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x030Cu, 0x021Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0323u, 0x1E25u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0327u, 0x1E29u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x032Eu, 0x1E2Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0331u, 0x1E96u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0300u, 0x00ECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0301u, 0x00EDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0302u, 0x00EEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0303u, 0x0129u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0304u, 0x012Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0306u, 0x012Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0308u, 0x00EFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0309u, 0x1EC9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x030Cu, 0x01D0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x030Fu, 0x0209u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0311u, 0x020Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0323u, 0x1ECBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0328u, 0x012Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0330u, 0x1E2Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Au, 0x0302u, 0x0135u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Au, 0x030Cu, 0x01F0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0301u, 0x1E31u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x030Cu, 0x01E9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0323u, 0x1E33u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0327u, 0x0137u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0331u, 0x1E35u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0301u, 0x013Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x030Cu, 0x013Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0323u, 0x1E37u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0327u, 0x013Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x032Du, 0x1E3Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0331u, 0x1E3Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0301u, 0x1E3Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0307u, 0x1E41u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0323u, 0x1E43u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0300u, 0x01F9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0301u, 0x0144u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0303u, 0x00F1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0307u, 0x1E45u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x030Cu, 0x0148u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0323u, 0x1E47u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0327u, 0x0146u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x032Du, 0x1E4Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0331u, 0x1E49u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0300u, 0x00F2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0301u, 0x00F3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0302u, 0x00F4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0303u, 0x00F5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0304u, 0x014Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0306u, 0x014Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0307u, 0x022Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0308u, 0x00F6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0309u, 0x1ECFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Bu, 0x0151u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Cu, 0x01D2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Fu, 0x020Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0311u, 0x020Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x031Bu, 0x01A1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0323u, 0x1ECDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0328u, 0x01EBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0070u, 0x0301u, 0x1E55u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0070u, 0x0307u, 0x1E57u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0301u, 0x0155u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0307u, 0x1E59u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x030Cu, 0x0159u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x030Fu, 0x0211u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0311u, 0x0213u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0323u, 0x1E5Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0327u, 0x0157u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0331u, 0x1E5Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0301u, 0x015Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0302u, 0x015Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0307u, 0x1E61u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x030Cu, 0x0161u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0323u, 0x1E63u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0326u, 0x0219u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0327u, 0x015Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0307u, 0x1E6Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0308u, 0x1E97u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x030Cu, 0x0165u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0323u, 0x1E6Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0326u, 0x021Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0327u, 0x0163u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x032Du, 0x1E71u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0331u, 0x1E6Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0300u, 0x00F9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0301u, 0x00FAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0302u, 0x00FBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0303u, 0x0169u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0304u, 0x016Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0306u, 0x016Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0308u, 0x00FCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0309u, 0x1EE7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Au, 0x016Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Bu, 0x0171u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Cu, 0x01D4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Fu, 0x0215u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0311u, 0x0217u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x031Bu, 0x01B0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0323u, 0x1EE5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0324u, 0x1E73u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0328u, 0x0173u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x032Du, 0x1E77u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0330u, 0x1E75u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0076u, 0x0303u, 0x1E7Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0076u, 0x0323u, 0x1E7Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0300u, 0x1E81u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0301u, 0x1E83u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0302u, 0x0175u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0307u, 0x1E87u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0308u, 0x1E85u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x030Au, 0x1E98u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0323u, 0x1E89u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0078u, 0x0307u, 0x1E8Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0078u, 0x0308u, 0x1E8Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0300u, 0x1EF3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0301u, 0x00FDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0302u, 0x0177u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0303u, 0x1EF9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0304u, 0x0233u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0307u, 0x1E8Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0308u, 0x00FFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0309u, 0x1EF7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x030Au, 0x1E99u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0323u, 0x1EF5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0301u, 0x017Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0302u, 0x1E91u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0307u, 0x017Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x030Cu, 0x017Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0323u, 0x1E93u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0331u, 0x1E95u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0300u, 0x1FEDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0301u, 0x0385u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0342u, 0x1FC1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0300u, 0x1EA6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0301u, 0x1EA4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0303u, 0x1EAAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0309u, 0x1EA8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C4u, 0x0304u, 0x01DEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C5u, 0x0301u, 0x01FAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6u, 0x0301u, 0x01FCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6u, 0x0304u, 0x01E2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00C7u, 0x0301u, 0x1E08u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0300u, 0x1EC0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0301u, 0x1EBEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0303u, 0x1EC4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0309u, 0x1EC2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00CFu, 0x0301u, 0x1E2Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0300u, 0x1ED2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0301u, 0x1ED0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0303u, 0x1ED6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0309u, 0x1ED4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0301u, 0x1E4Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0304u, 0x022Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0308u, 0x1E4Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D6u, 0x0304u, 0x022Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00D8u, 0x0301u, 0x01FEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0300u, 0x01DBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0301u, 0x01D7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0304u, 0x01D5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x030Cu, 0x01D9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0300u, 0x1EA7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0301u, 0x1EA5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0303u, 0x1EABu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0309u, 0x1EA9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E4u, 0x0304u, 0x01DFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E5u, 0x0301u, 0x01FBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6u, 0x0301u, 0x01FDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6u, 0x0304u, 0x01E3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00E7u, 0x0301u, 0x1E09u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0300u, 0x1EC1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0301u, 0x1EBFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0303u, 0x1EC5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0309u, 0x1EC3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00EFu, 0x0301u, 0x1E2Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0300u, 0x1ED3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0301u, 0x1ED1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0303u, 0x1ED7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0309u, 0x1ED5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0301u, 0x1E4Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0304u, 0x022Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0308u, 0x1E4Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F6u, 0x0304u, 0x022Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00F8u, 0x0301u, 0x01FFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0300u, 0x01DCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0301u, 0x01D8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0304u, 0x01D6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x030Cu, 0x01DAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0300u, 0x1EB0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0301u, 0x1EAEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0303u, 0x1EB4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0309u, 0x1EB2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0300u, 0x1EB1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0301u, 0x1EAFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0303u, 0x1EB5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0309u, 0x1EB3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0112u, 0x0300u, 0x1E14u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0112u, 0x0301u, 0x1E16u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0113u, 0x0300u, 0x1E15u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0113u, 0x0301u, 0x1E17u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x014Cu, 0x0300u, 0x1E50u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x014Cu, 0x0301u, 0x1E52u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x014Du, 0x0300u, 0x1E51u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x014Du, 0x0301u, 0x1E53u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x015Au, 0x0307u, 0x1E64u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x015Bu, 0x0307u, 0x1E65u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0160u, 0x0307u, 0x1E66u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0161u, 0x0307u, 0x1E67u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0168u, 0x0301u, 0x1E78u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0169u, 0x0301u, 0x1E79u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x016Au, 0x0308u, 0x1E7Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x016Bu, 0x0308u, 0x1E7Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x017Fu, 0x0307u, 0x1E9Bu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0300u, 0x1EDCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0301u, 0x1EDAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0303u, 0x1EE0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0309u, 0x1EDEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0323u, 0x1EE2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0300u, 0x1EDDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0301u, 0x1EDBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0303u, 0x1EE1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0309u, 0x1EDFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0323u, 0x1EE3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0300u, 0x1EEAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0301u, 0x1EE8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0303u, 0x1EEEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0309u, 0x1EECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0323u, 0x1EF0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0300u, 0x1EEBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0301u, 0x1EE9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0303u, 0x1EEFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0309u, 0x1EEDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0323u, 0x1EF1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01B7u, 0x030Cu, 0x01EEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01EAu, 0x0304u, 0x01ECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x01EBu, 0x0304u, 0x01EDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0226u, 0x0304u, 0x01E0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0227u, 0x0304u, 0x01E1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0228u, 0x0306u, 0x1E1Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0229u, 0x0306u, 0x1E1Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x022Eu, 0x0304u, 0x0230u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x022Fu, 0x0304u, 0x0231u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0292u, 0x030Cu, 0x01EFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0308u, 0x0301u, 0x0000u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0300u, 0x1FBAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0301u, 0x0386u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0304u, 0x1FB9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0306u, 0x1FB8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0313u, 0x1F08u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0314u, 0x1F09u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0345u, 0x1FBCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0300u, 0x1FC8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0301u, 0x0388u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0313u, 0x1F18u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0314u, 0x1F19u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0300u, 0x1FCAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0301u, 0x0389u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0313u, 0x1F28u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0314u, 0x1F29u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0345u, 0x1FCCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0300u, 0x1FDAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0301u, 0x038Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0304u, 0x1FD9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0306u, 0x1FD8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0308u, 0x03AAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0313u, 0x1F38u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0314u, 0x1F39u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0300u, 0x1FF8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0301u, 0x038Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0313u, 0x1F48u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0314u, 0x1F49u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A1u, 0x0314u, 0x1FECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0300u, 0x1FEAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0301u, 0x038Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0304u, 0x1FE9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0306u, 0x1FE8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0308u, 0x03ABu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0314u, 0x1F59u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0300u, 0x1FFAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0301u, 0x038Fu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0313u, 0x1F68u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0314u, 0x1F69u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0345u, 0x1FFCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03ACu, 0x0345u, 0x1FB4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03AEu, 0x0345u, 0x1FC4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0300u, 0x1F70u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0301u, 0x03ACu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0304u, 0x1FB1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0306u, 0x1FB0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0313u, 0x1F00u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0314u, 0x1F01u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0342u, 0x1FB6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0345u, 0x1FB3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0300u, 0x1F72u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0301u, 0x03ADu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0313u, 0x1F10u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0314u, 0x1F11u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0300u, 0x1F74u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0301u, 0x03AEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0313u, 0x1F20u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0314u, 0x1F21u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0342u, 0x1FC6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0345u, 0x1FC3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0300u, 0x1F76u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0301u, 0x03AFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0304u, 0x1FD1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0306u, 0x1FD0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0308u, 0x03CAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0313u, 0x1F30u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0314u, 0x1F31u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0342u, 0x1FD6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0300u, 0x1F78u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0301u, 0x03CCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0313u, 0x1F40u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0314u, 0x1F41u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1u, 0x0313u, 0x1FE4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1u, 0x0314u, 0x1FE5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0300u, 0x1F7Au),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0301u, 0x03CDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0304u, 0x1FE1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0306u, 0x1FE0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0308u, 0x03CBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0313u, 0x1F50u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0314u, 0x1F51u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0342u, 0x1FE6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0300u, 0x1F7Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0301u, 0x03CEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0313u, 0x1F60u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0314u, 0x1F61u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0342u, 0x1FF6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0345u, 0x1FF3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0300u, 0x1FD2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0301u, 0x0390u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0342u, 0x1FD7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0300u, 0x1FE2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0301u, 0x03B0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0342u, 0x1FE7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03CEu, 0x0345u, 0x1FF4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2u, 0x0301u, 0x03D3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2u, 0x0308u, 0x03D4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0406u, 0x0308u, 0x0407u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0410u, 0x0306u, 0x04D0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0410u, 0x0308u, 0x04D2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0413u, 0x0301u, 0x0403u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0300u, 0x0400u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0306u, 0x04D6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0308u, 0x0401u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0416u, 0x0306u, 0x04C1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0416u, 0x0308u, 0x04DCu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0417u, 0x0308u, 0x04DEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0300u, 0x040Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0304u, 0x04E2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0306u, 0x0419u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0308u, 0x04E4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x041Au, 0x0301u, 0x040Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x041Eu, 0x0308u, 0x04E6u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0304u, 0x04EEu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0306u, 0x040Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0308u, 0x04F0u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x030Bu, 0x04F2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0427u, 0x0308u, 0x04F4u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x042Bu, 0x0308u, 0x04F8u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x042Du, 0x0308u, 0x04ECu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0430u, 0x0306u, 0x04D1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0430u, 0x0308u, 0x04D3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0433u, 0x0301u, 0x0453u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0300u, 0x0450u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0306u, 0x04D7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0308u, 0x0451u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0436u, 0x0306u, 0x04C2u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0436u, 0x0308u, 0x04DDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0437u, 0x0308u, 0x04DFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0300u, 0x045Du),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0304u, 0x04E3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0306u, 0x0439u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0308u, 0x04E5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x043Au, 0x0301u, 0x045Cu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x043Eu, 0x0308u, 0x04E7u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0304u, 0x04EFu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0306u, 0x045Eu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0308u, 0x04F1u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x030Bu, 0x04F3u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0447u, 0x0308u, 0x04F5u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x044Bu, 0x0308u, 0x04F9u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x044Du, 0x0308u, 0x04EDu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0456u, 0x0308u, 0x0457u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0474u, 0x030Fu, 0x0476u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x0475u, 0x030Fu, 0x0477u),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x04D8u, 0x0308u, 0x04DAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x04D9u, 0x0308u, 0x04DBu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x04E8u, 0x0308u, 0x04EAu),
+   HB_CODEPOINT_ENCODE3_11_7_14 (0x04E9u, 0x0308u, 0x04EBu),
+};
+static const uint64_t
+_hb_ucd_dm2_u64_map[388] =
+{
+     HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B8u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BFu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D2u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D3u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D4u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D5u, 0x05B9u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D5u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D6u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D8u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05D9u, 0x05B4u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05D9u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05DAu, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05DBu, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05DBu, 0x05BFu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05DCu, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05DEu, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E0u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E1u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E3u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E4u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E4u, 0x05BFu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E6u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E7u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E8u, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05C1u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05C2u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x05EAu, 0x05BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x05F2u, 0x05B7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0627u, 0x0653u, 0x0622u),   HB_CODEPOINT_ENCODE3 (0x0627u, 0x0654u, 0x0623u),
+     HB_CODEPOINT_ENCODE3 (0x0627u, 0x0655u, 0x0625u),   HB_CODEPOINT_ENCODE3 (0x0648u, 0x0654u, 0x0624u),
+     HB_CODEPOINT_ENCODE3 (0x064Au, 0x0654u, 0x0626u),   HB_CODEPOINT_ENCODE3 (0x06C1u, 0x0654u, 0x06C2u),
+     HB_CODEPOINT_ENCODE3 (0x06D2u, 0x0654u, 0x06D3u),   HB_CODEPOINT_ENCODE3 (0x06D5u, 0x0654u, 0x06C0u),
+     HB_CODEPOINT_ENCODE3 (0x0915u, 0x093Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0916u, 0x093Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0917u, 0x093Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x091Cu, 0x093Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0921u, 0x093Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0922u, 0x093Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0928u, 0x093Cu, 0x0929u),   HB_CODEPOINT_ENCODE3 (0x092Bu, 0x093Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x092Fu, 0x093Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0930u, 0x093Cu, 0x0931u),
+     HB_CODEPOINT_ENCODE3 (0x0933u, 0x093Cu, 0x0934u),   HB_CODEPOINT_ENCODE3 (0x09A1u, 0x09BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x09A2u, 0x09BCu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x09AFu, 0x09BCu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x09C7u, 0x09BEu, 0x09CBu),   HB_CODEPOINT_ENCODE3 (0x09C7u, 0x09D7u, 0x09CCu),
+     HB_CODEPOINT_ENCODE3 (0x0A16u, 0x0A3Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0A17u, 0x0A3Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0A1Cu, 0x0A3Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0A2Bu, 0x0A3Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0A32u, 0x0A3Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0A38u, 0x0A3Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0B21u, 0x0B3Cu, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0B22u, 0x0B3Cu, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B3Eu, 0x0B4Bu),   HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B56u, 0x0B48u),
+     HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B57u, 0x0B4Cu),   HB_CODEPOINT_ENCODE3 (0x0B92u, 0x0BD7u, 0x0B94u),
+     HB_CODEPOINT_ENCODE3 (0x0BC6u, 0x0BBEu, 0x0BCAu),   HB_CODEPOINT_ENCODE3 (0x0BC6u, 0x0BD7u, 0x0BCCu),
+     HB_CODEPOINT_ENCODE3 (0x0BC7u, 0x0BBEu, 0x0BCBu),   HB_CODEPOINT_ENCODE3 (0x0C46u, 0x0C56u, 0x0C48u),
+     HB_CODEPOINT_ENCODE3 (0x0CBFu, 0x0CD5u, 0x0CC0u),   HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CC2u, 0x0CCAu),
+     HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CD5u, 0x0CC7u),   HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CD6u, 0x0CC8u),
+     HB_CODEPOINT_ENCODE3 (0x0CCAu, 0x0CD5u, 0x0CCBu),   HB_CODEPOINT_ENCODE3 (0x0D46u, 0x0D3Eu, 0x0D4Au),
+     HB_CODEPOINT_ENCODE3 (0x0D46u, 0x0D57u, 0x0D4Cu),   HB_CODEPOINT_ENCODE3 (0x0D47u, 0x0D3Eu, 0x0D4Bu),
+     HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DCAu, 0x0DDAu),   HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DCFu, 0x0DDCu),
+     HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DDFu, 0x0DDEu),   HB_CODEPOINT_ENCODE3 (0x0DDCu, 0x0DCAu, 0x0DDDu),
+     HB_CODEPOINT_ENCODE3 (0x0F40u, 0x0FB5u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F42u, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F4Cu, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F51u, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F56u, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F5Bu, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F72u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F74u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F80u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F90u, 0x0FB5u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0F92u, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0F9Cu, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0FA1u, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0FA6u, 0x0FB7u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0FABu, 0x0FB7u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x0FB2u, 0x0F80u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x0FB3u, 0x0F80u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0x1025u, 0x102Eu, 0x1026u),
+     HB_CODEPOINT_ENCODE3 (0x1B05u, 0x1B35u, 0x1B06u),   HB_CODEPOINT_ENCODE3 (0x1B07u, 0x1B35u, 0x1B08u),
+     HB_CODEPOINT_ENCODE3 (0x1B09u, 0x1B35u, 0x1B0Au),   HB_CODEPOINT_ENCODE3 (0x1B0Bu, 0x1B35u, 0x1B0Cu),
+     HB_CODEPOINT_ENCODE3 (0x1B0Du, 0x1B35u, 0x1B0Eu),   HB_CODEPOINT_ENCODE3 (0x1B11u, 0x1B35u, 0x1B12u),
+     HB_CODEPOINT_ENCODE3 (0x1B3Au, 0x1B35u, 0x1B3Bu),   HB_CODEPOINT_ENCODE3 (0x1B3Cu, 0x1B35u, 0x1B3Du),
+     HB_CODEPOINT_ENCODE3 (0x1B3Eu, 0x1B35u, 0x1B40u),   HB_CODEPOINT_ENCODE3 (0x1B3Fu, 0x1B35u, 0x1B41u),
+     HB_CODEPOINT_ENCODE3 (0x1B42u, 0x1B35u, 0x1B43u),   HB_CODEPOINT_ENCODE3 (0x1E36u, 0x0304u, 0x1E38u),
+     HB_CODEPOINT_ENCODE3 (0x1E37u, 0x0304u, 0x1E39u),   HB_CODEPOINT_ENCODE3 (0x1E5Au, 0x0304u, 0x1E5Cu),
+     HB_CODEPOINT_ENCODE3 (0x1E5Bu, 0x0304u, 0x1E5Du),   HB_CODEPOINT_ENCODE3 (0x1E62u, 0x0307u, 0x1E68u),
+     HB_CODEPOINT_ENCODE3 (0x1E63u, 0x0307u, 0x1E69u),   HB_CODEPOINT_ENCODE3 (0x1EA0u, 0x0302u, 0x1EACu),
+     HB_CODEPOINT_ENCODE3 (0x1EA0u, 0x0306u, 0x1EB6u),   HB_CODEPOINT_ENCODE3 (0x1EA1u, 0x0302u, 0x1EADu),
+     HB_CODEPOINT_ENCODE3 (0x1EA1u, 0x0306u, 0x1EB7u),   HB_CODEPOINT_ENCODE3 (0x1EB8u, 0x0302u, 0x1EC6u),
+     HB_CODEPOINT_ENCODE3 (0x1EB9u, 0x0302u, 0x1EC7u),   HB_CODEPOINT_ENCODE3 (0x1ECCu, 0x0302u, 0x1ED8u),
+     HB_CODEPOINT_ENCODE3 (0x1ECDu, 0x0302u, 0x1ED9u),   HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0300u, 0x1F02u),
+     HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0301u, 0x1F04u),   HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0342u, 0x1F06u),
+     HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0345u, 0x1F80u),   HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0300u, 0x1F03u),
+     HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0301u, 0x1F05u),   HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0342u, 0x1F07u),
+     HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0345u, 0x1F81u),   HB_CODEPOINT_ENCODE3 (0x1F02u, 0x0345u, 0x1F82u),
+     HB_CODEPOINT_ENCODE3 (0x1F03u, 0x0345u, 0x1F83u),   HB_CODEPOINT_ENCODE3 (0x1F04u, 0x0345u, 0x1F84u),
+     HB_CODEPOINT_ENCODE3 (0x1F05u, 0x0345u, 0x1F85u),   HB_CODEPOINT_ENCODE3 (0x1F06u, 0x0345u, 0x1F86u),
+     HB_CODEPOINT_ENCODE3 (0x1F07u, 0x0345u, 0x1F87u),   HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0300u, 0x1F0Au),
+     HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0301u, 0x1F0Cu),   HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0342u, 0x1F0Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0345u, 0x1F88u),   HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0300u, 0x1F0Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0301u, 0x1F0Du),   HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0342u, 0x1F0Fu),
+     HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0345u, 0x1F89u),   HB_CODEPOINT_ENCODE3 (0x1F0Au, 0x0345u, 0x1F8Au),
+     HB_CODEPOINT_ENCODE3 (0x1F0Bu, 0x0345u, 0x1F8Bu),   HB_CODEPOINT_ENCODE3 (0x1F0Cu, 0x0345u, 0x1F8Cu),
+     HB_CODEPOINT_ENCODE3 (0x1F0Du, 0x0345u, 0x1F8Du),   HB_CODEPOINT_ENCODE3 (0x1F0Eu, 0x0345u, 0x1F8Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F0Fu, 0x0345u, 0x1F8Fu),   HB_CODEPOINT_ENCODE3 (0x1F10u, 0x0300u, 0x1F12u),
+     HB_CODEPOINT_ENCODE3 (0x1F10u, 0x0301u, 0x1F14u),   HB_CODEPOINT_ENCODE3 (0x1F11u, 0x0300u, 0x1F13u),
+     HB_CODEPOINT_ENCODE3 (0x1F11u, 0x0301u, 0x1F15u),   HB_CODEPOINT_ENCODE3 (0x1F18u, 0x0300u, 0x1F1Au),
+     HB_CODEPOINT_ENCODE3 (0x1F18u, 0x0301u, 0x1F1Cu),   HB_CODEPOINT_ENCODE3 (0x1F19u, 0x0300u, 0x1F1Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F19u, 0x0301u, 0x1F1Du),   HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0300u, 0x1F22u),
+     HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0301u, 0x1F24u),   HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0342u, 0x1F26u),
+     HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0345u, 0x1F90u),   HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0300u, 0x1F23u),
+     HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0301u, 0x1F25u),   HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0342u, 0x1F27u),
+     HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0345u, 0x1F91u),   HB_CODEPOINT_ENCODE3 (0x1F22u, 0x0345u, 0x1F92u),
+     HB_CODEPOINT_ENCODE3 (0x1F23u, 0x0345u, 0x1F93u),   HB_CODEPOINT_ENCODE3 (0x1F24u, 0x0345u, 0x1F94u),
+     HB_CODEPOINT_ENCODE3 (0x1F25u, 0x0345u, 0x1F95u),   HB_CODEPOINT_ENCODE3 (0x1F26u, 0x0345u, 0x1F96u),
+     HB_CODEPOINT_ENCODE3 (0x1F27u, 0x0345u, 0x1F97u),   HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0300u, 0x1F2Au),
+     HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0301u, 0x1F2Cu),   HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0342u, 0x1F2Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0345u, 0x1F98u),   HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0300u, 0x1F2Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0301u, 0x1F2Du),   HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0342u, 0x1F2Fu),
+     HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0345u, 0x1F99u),   HB_CODEPOINT_ENCODE3 (0x1F2Au, 0x0345u, 0x1F9Au),
+     HB_CODEPOINT_ENCODE3 (0x1F2Bu, 0x0345u, 0x1F9Bu),   HB_CODEPOINT_ENCODE3 (0x1F2Cu, 0x0345u, 0x1F9Cu),
+     HB_CODEPOINT_ENCODE3 (0x1F2Du, 0x0345u, 0x1F9Du),   HB_CODEPOINT_ENCODE3 (0x1F2Eu, 0x0345u, 0x1F9Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F2Fu, 0x0345u, 0x1F9Fu),   HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0300u, 0x1F32u),
+     HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0301u, 0x1F34u),   HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0342u, 0x1F36u),
+     HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0300u, 0x1F33u),   HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0301u, 0x1F35u),
+     HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0342u, 0x1F37u),   HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0300u, 0x1F3Au),
+     HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0301u, 0x1F3Cu),   HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0342u, 0x1F3Eu),
+     HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0300u, 0x1F3Bu),   HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0301u, 0x1F3Du),
+     HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0342u, 0x1F3Fu),   HB_CODEPOINT_ENCODE3 (0x1F40u, 0x0300u, 0x1F42u),
+     HB_CODEPOINT_ENCODE3 (0x1F40u, 0x0301u, 0x1F44u),   HB_CODEPOINT_ENCODE3 (0x1F41u, 0x0300u, 0x1F43u),
+     HB_CODEPOINT_ENCODE3 (0x1F41u, 0x0301u, 0x1F45u),   HB_CODEPOINT_ENCODE3 (0x1F48u, 0x0300u, 0x1F4Au),
+     HB_CODEPOINT_ENCODE3 (0x1F48u, 0x0301u, 0x1F4Cu),   HB_CODEPOINT_ENCODE3 (0x1F49u, 0x0300u, 0x1F4Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F49u, 0x0301u, 0x1F4Du),   HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0300u, 0x1F52u),
+     HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0301u, 0x1F54u),   HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0342u, 0x1F56u),
+     HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0300u, 0x1F53u),   HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0301u, 0x1F55u),
+     HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0342u, 0x1F57u),   HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0300u, 0x1F5Bu),
+     HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0301u, 0x1F5Du),   HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0342u, 0x1F5Fu),
+     HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0300u, 0x1F62u),   HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0301u, 0x1F64u),
+     HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0342u, 0x1F66u),   HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0345u, 0x1FA0u),
+     HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0300u, 0x1F63u),   HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0301u, 0x1F65u),
+     HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0342u, 0x1F67u),   HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0345u, 0x1FA1u),
+     HB_CODEPOINT_ENCODE3 (0x1F62u, 0x0345u, 0x1FA2u),   HB_CODEPOINT_ENCODE3 (0x1F63u, 0x0345u, 0x1FA3u),
+     HB_CODEPOINT_ENCODE3 (0x1F64u, 0x0345u, 0x1FA4u),   HB_CODEPOINT_ENCODE3 (0x1F65u, 0x0345u, 0x1FA5u),
+     HB_CODEPOINT_ENCODE3 (0x1F66u, 0x0345u, 0x1FA6u),   HB_CODEPOINT_ENCODE3 (0x1F67u, 0x0345u, 0x1FA7u),
+     HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0300u, 0x1F6Au),   HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0301u, 0x1F6Cu),
+     HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0342u, 0x1F6Eu),   HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0345u, 0x1FA8u),
+     HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0300u, 0x1F6Bu),   HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0301u, 0x1F6Du),
+     HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0342u, 0x1F6Fu),   HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0345u, 0x1FA9u),
+     HB_CODEPOINT_ENCODE3 (0x1F6Au, 0x0345u, 0x1FAAu),   HB_CODEPOINT_ENCODE3 (0x1F6Bu, 0x0345u, 0x1FABu),
+     HB_CODEPOINT_ENCODE3 (0x1F6Cu, 0x0345u, 0x1FACu),   HB_CODEPOINT_ENCODE3 (0x1F6Du, 0x0345u, 0x1FADu),
+     HB_CODEPOINT_ENCODE3 (0x1F6Eu, 0x0345u, 0x1FAEu),   HB_CODEPOINT_ENCODE3 (0x1F6Fu, 0x0345u, 0x1FAFu),
+     HB_CODEPOINT_ENCODE3 (0x1F70u, 0x0345u, 0x1FB2u),   HB_CODEPOINT_ENCODE3 (0x1F74u, 0x0345u, 0x1FC2u),
+     HB_CODEPOINT_ENCODE3 (0x1F7Cu, 0x0345u, 0x1FF2u),   HB_CODEPOINT_ENCODE3 (0x1FB6u, 0x0345u, 0x1FB7u),
+     HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0300u, 0x1FCDu),   HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0301u, 0x1FCEu),
+     HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0342u, 0x1FCFu),   HB_CODEPOINT_ENCODE3 (0x1FC6u, 0x0345u, 0x1FC7u),
+     HB_CODEPOINT_ENCODE3 (0x1FF6u, 0x0345u, 0x1FF7u),   HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0300u, 0x1FDDu),
+     HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0301u, 0x1FDEu),   HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0342u, 0x1FDFu),
+     HB_CODEPOINT_ENCODE3 (0x2190u, 0x0338u, 0x219Au),   HB_CODEPOINT_ENCODE3 (0x2192u, 0x0338u, 0x219Bu),
+     HB_CODEPOINT_ENCODE3 (0x2194u, 0x0338u, 0x21AEu),   HB_CODEPOINT_ENCODE3 (0x21D0u, 0x0338u, 0x21CDu),
+     HB_CODEPOINT_ENCODE3 (0x21D2u, 0x0338u, 0x21CFu),   HB_CODEPOINT_ENCODE3 (0x21D4u, 0x0338u, 0x21CEu),
+     HB_CODEPOINT_ENCODE3 (0x2203u, 0x0338u, 0x2204u),   HB_CODEPOINT_ENCODE3 (0x2208u, 0x0338u, 0x2209u),
+     HB_CODEPOINT_ENCODE3 (0x220Bu, 0x0338u, 0x220Cu),   HB_CODEPOINT_ENCODE3 (0x2223u, 0x0338u, 0x2224u),
+     HB_CODEPOINT_ENCODE3 (0x2225u, 0x0338u, 0x2226u),   HB_CODEPOINT_ENCODE3 (0x223Cu, 0x0338u, 0x2241u),
+     HB_CODEPOINT_ENCODE3 (0x2243u, 0x0338u, 0x2244u),   HB_CODEPOINT_ENCODE3 (0x2245u, 0x0338u, 0x2247u),
+     HB_CODEPOINT_ENCODE3 (0x2248u, 0x0338u, 0x2249u),   HB_CODEPOINT_ENCODE3 (0x224Du, 0x0338u, 0x226Du),
+     HB_CODEPOINT_ENCODE3 (0x2261u, 0x0338u, 0x2262u),   HB_CODEPOINT_ENCODE3 (0x2264u, 0x0338u, 0x2270u),
+     HB_CODEPOINT_ENCODE3 (0x2265u, 0x0338u, 0x2271u),   HB_CODEPOINT_ENCODE3 (0x2272u, 0x0338u, 0x2274u),
+     HB_CODEPOINT_ENCODE3 (0x2273u, 0x0338u, 0x2275u),   HB_CODEPOINT_ENCODE3 (0x2276u, 0x0338u, 0x2278u),
+     HB_CODEPOINT_ENCODE3 (0x2277u, 0x0338u, 0x2279u),   HB_CODEPOINT_ENCODE3 (0x227Au, 0x0338u, 0x2280u),
+     HB_CODEPOINT_ENCODE3 (0x227Bu, 0x0338u, 0x2281u),   HB_CODEPOINT_ENCODE3 (0x227Cu, 0x0338u, 0x22E0u),
+     HB_CODEPOINT_ENCODE3 (0x227Du, 0x0338u, 0x22E1u),   HB_CODEPOINT_ENCODE3 (0x2282u, 0x0338u, 0x2284u),
+     HB_CODEPOINT_ENCODE3 (0x2283u, 0x0338u, 0x2285u),   HB_CODEPOINT_ENCODE3 (0x2286u, 0x0338u, 0x2288u),
+     HB_CODEPOINT_ENCODE3 (0x2287u, 0x0338u, 0x2289u),   HB_CODEPOINT_ENCODE3 (0x2291u, 0x0338u, 0x22E2u),
+     HB_CODEPOINT_ENCODE3 (0x2292u, 0x0338u, 0x22E3u),   HB_CODEPOINT_ENCODE3 (0x22A2u, 0x0338u, 0x22ACu),
+     HB_CODEPOINT_ENCODE3 (0x22A8u, 0x0338u, 0x22ADu),   HB_CODEPOINT_ENCODE3 (0x22A9u, 0x0338u, 0x22AEu),
+     HB_CODEPOINT_ENCODE3 (0x22ABu, 0x0338u, 0x22AFu),   HB_CODEPOINT_ENCODE3 (0x22B2u, 0x0338u, 0x22EAu),
+     HB_CODEPOINT_ENCODE3 (0x22B3u, 0x0338u, 0x22EBu),   HB_CODEPOINT_ENCODE3 (0x22B4u, 0x0338u, 0x22ECu),
+     HB_CODEPOINT_ENCODE3 (0x22B5u, 0x0338u, 0x22EDu),   HB_CODEPOINT_ENCODE3 (0x2ADDu, 0x0338u, 0x0000u),
+     HB_CODEPOINT_ENCODE3 (0x3046u, 0x3099u, 0x3094u),   HB_CODEPOINT_ENCODE3 (0x304Bu, 0x3099u, 0x304Cu),
+     HB_CODEPOINT_ENCODE3 (0x304Du, 0x3099u, 0x304Eu),   HB_CODEPOINT_ENCODE3 (0x304Fu, 0x3099u, 0x3050u),
+     HB_CODEPOINT_ENCODE3 (0x3051u, 0x3099u, 0x3052u),   HB_CODEPOINT_ENCODE3 (0x3053u, 0x3099u, 0x3054u),
+     HB_CODEPOINT_ENCODE3 (0x3055u, 0x3099u, 0x3056u),   HB_CODEPOINT_ENCODE3 (0x3057u, 0x3099u, 0x3058u),
+     HB_CODEPOINT_ENCODE3 (0x3059u, 0x3099u, 0x305Au),   HB_CODEPOINT_ENCODE3 (0x305Bu, 0x3099u, 0x305Cu),
+     HB_CODEPOINT_ENCODE3 (0x305Du, 0x3099u, 0x305Eu),   HB_CODEPOINT_ENCODE3 (0x305Fu, 0x3099u, 0x3060u),
+     HB_CODEPOINT_ENCODE3 (0x3061u, 0x3099u, 0x3062u),   HB_CODEPOINT_ENCODE3 (0x3064u, 0x3099u, 0x3065u),
+     HB_CODEPOINT_ENCODE3 (0x3066u, 0x3099u, 0x3067u),   HB_CODEPOINT_ENCODE3 (0x3068u, 0x3099u, 0x3069u),
+     HB_CODEPOINT_ENCODE3 (0x306Fu, 0x3099u, 0x3070u),   HB_CODEPOINT_ENCODE3 (0x306Fu, 0x309Au, 0x3071u),
+     HB_CODEPOINT_ENCODE3 (0x3072u, 0x3099u, 0x3073u),   HB_CODEPOINT_ENCODE3 (0x3072u, 0x309Au, 0x3074u),
+     HB_CODEPOINT_ENCODE3 (0x3075u, 0x3099u, 0x3076u),   HB_CODEPOINT_ENCODE3 (0x3075u, 0x309Au, 0x3077u),
+     HB_CODEPOINT_ENCODE3 (0x3078u, 0x3099u, 0x3079u),   HB_CODEPOINT_ENCODE3 (0x3078u, 0x309Au, 0x307Au),
+     HB_CODEPOINT_ENCODE3 (0x307Bu, 0x3099u, 0x307Cu),   HB_CODEPOINT_ENCODE3 (0x307Bu, 0x309Au, 0x307Du),
+     HB_CODEPOINT_ENCODE3 (0x309Du, 0x3099u, 0x309Eu),   HB_CODEPOINT_ENCODE3 (0x30A6u, 0x3099u, 0x30F4u),
+     HB_CODEPOINT_ENCODE3 (0x30ABu, 0x3099u, 0x30ACu),   HB_CODEPOINT_ENCODE3 (0x30ADu, 0x3099u, 0x30AEu),
+     HB_CODEPOINT_ENCODE3 (0x30AFu, 0x3099u, 0x30B0u),   HB_CODEPOINT_ENCODE3 (0x30B1u, 0x3099u, 0x30B2u),
+     HB_CODEPOINT_ENCODE3 (0x30B3u, 0x3099u, 0x30B4u),   HB_CODEPOINT_ENCODE3 (0x30B5u, 0x3099u, 0x30B6u),
+     HB_CODEPOINT_ENCODE3 (0x30B7u, 0x3099u, 0x30B8u),   HB_CODEPOINT_ENCODE3 (0x30B9u, 0x3099u, 0x30BAu),
+     HB_CODEPOINT_ENCODE3 (0x30BBu, 0x3099u, 0x30BCu),   HB_CODEPOINT_ENCODE3 (0x30BDu, 0x3099u, 0x30BEu),
+     HB_CODEPOINT_ENCODE3 (0x30BFu, 0x3099u, 0x30C0u),   HB_CODEPOINT_ENCODE3 (0x30C1u, 0x3099u, 0x30C2u),
+     HB_CODEPOINT_ENCODE3 (0x30C4u, 0x3099u, 0x30C5u),   HB_CODEPOINT_ENCODE3 (0x30C6u, 0x3099u, 0x30C7u),
+     HB_CODEPOINT_ENCODE3 (0x30C8u, 0x3099u, 0x30C9u),   HB_CODEPOINT_ENCODE3 (0x30CFu, 0x3099u, 0x30D0u),
+     HB_CODEPOINT_ENCODE3 (0x30CFu, 0x309Au, 0x30D1u),   HB_CODEPOINT_ENCODE3 (0x30D2u, 0x3099u, 0x30D3u),
+     HB_CODEPOINT_ENCODE3 (0x30D2u, 0x309Au, 0x30D4u),   HB_CODEPOINT_ENCODE3 (0x30D5u, 0x3099u, 0x30D6u),
+     HB_CODEPOINT_ENCODE3 (0x30D5u, 0x309Au, 0x30D7u),   HB_CODEPOINT_ENCODE3 (0x30D8u, 0x3099u, 0x30D9u),
+     HB_CODEPOINT_ENCODE3 (0x30D8u, 0x309Au, 0x30DAu),   HB_CODEPOINT_ENCODE3 (0x30DBu, 0x3099u, 0x30DCu),
+     HB_CODEPOINT_ENCODE3 (0x30DBu, 0x309Au, 0x30DDu),   HB_CODEPOINT_ENCODE3 (0x30EFu, 0x3099u, 0x30F7u),
+     HB_CODEPOINT_ENCODE3 (0x30F0u, 0x3099u, 0x30F8u),   HB_CODEPOINT_ENCODE3 (0x30F1u, 0x3099u, 0x30F9u),
+     HB_CODEPOINT_ENCODE3 (0x30F2u, 0x3099u, 0x30FAu),   HB_CODEPOINT_ENCODE3 (0x30FDu, 0x3099u, 0x30FEu),
+     HB_CODEPOINT_ENCODE3 (0xFB49u, 0x05C1u, 0x0000u),   HB_CODEPOINT_ENCODE3 (0xFB49u, 0x05C2u, 0x0000u),
+  HB_CODEPOINT_ENCODE3 (0x11099u, 0x110BAu, 0x1109Au),HB_CODEPOINT_ENCODE3 (0x1109Bu, 0x110BAu, 0x1109Cu),
+  HB_CODEPOINT_ENCODE3 (0x110A5u, 0x110BAu, 0x110ABu),HB_CODEPOINT_ENCODE3 (0x11131u, 0x11127u, 0x1112Eu),
+  HB_CODEPOINT_ENCODE3 (0x11132u, 0x11127u, 0x1112Fu),HB_CODEPOINT_ENCODE3 (0x11347u, 0x1133Eu, 0x1134Bu),
+  HB_CODEPOINT_ENCODE3 (0x11347u, 0x11357u, 0x1134Cu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114B0u, 0x114BCu),
+  HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BAu, 0x114BBu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BDu, 0x114BEu),
+  HB_CODEPOINT_ENCODE3 (0x115B8u, 0x115AFu, 0x115BAu),HB_CODEPOINT_ENCODE3 (0x115B9u, 0x115AFu, 0x115BBu),
+  HB_CODEPOINT_ENCODE3 (0x11935u, 0x11930u, 0x11938u), HB_CODEPOINT_ENCODE3 (0x1D157u, 0x1D165u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D158u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Eu, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Fu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D170u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D171u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D172u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D1B9u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BAu, 0x1D165u, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Fu, 0x0000u),
+   HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Fu, 0x0000u),
+};
+
+#ifndef HB_OPTIMIZE_SIZE
+
+static const uint8_t
+_hb_ucd_u8[32480] =
+{
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 28,
+   29, 26, 30, 31, 32, 33, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 34, 35, 35, 35, 35,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 38, 39, 40,
+   41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+   26, 57, 58, 59, 59, 59, 59, 59, 26, 26, 60, 59, 59, 59, 59, 59,
+   59, 59, 26, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 26, 62, 59, 63, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 64, 26, 26, 65, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 66, 67, 59, 59, 59, 59, 68, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 69, 70, 71, 72, 73, 74, 59, 59,
+   75, 76, 59, 59, 77, 59, 78, 79, 80, 81, 73, 82, 83, 84, 59, 59,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 85, 26, 26, 26, 26, 26, 26, 26, 86, 87, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 88, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 89, 59, 59, 59, 59, 59, 59, 26, 90, 59, 59,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 91, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   92, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 93,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 94,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   29, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 25, 25, 25, 21,
+   21,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 22, 21, 18, 24, 16,
+   24,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22, 25, 18, 25,  0,
+   29, 21, 23, 23, 23, 23, 26, 21, 24, 26,  7, 20, 25,  1, 26, 24,
+   26, 25, 15, 15, 24,  5, 21, 21, 24, 15,  7, 19, 15, 15, 15, 21,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9, 25,  9,  9,  9,  9,  9,  9,  9,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5, 25,  5,  5,  5,  5,  5,  5,  5,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  5,  9,  5,  9,  5,  9,  5,  9,
+    5,  9,  5,  9,  5,  9,  5,  9,  5,  5,  9,  5,  9,  5,  9,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  9,  5,  9,  5,  9,  5,  5,
+    5,  9,  9,  5,  9,  5,  9,  9,  5,  9,  9,  9,  5,  5,  9,  9,
+    9,  9,  5,  9,  9,  5,  9,  9,  9,  5,  5,  5,  9,  9,  5,  9,
+    9,  5,  9,  5,  9,  5,  9,  9,  5,  9,  5,  5,  9,  5,  9,  9,
+    5,  9,  9,  9,  5,  9,  5,  9,  9,  5,  5,  7,  9,  5,  5,  5,
+    7,  7,  7,  7,  9,  8,  5,  9,  8,  5,  9,  8,  5,  9,  5,  9,
+    5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  5,  9,  5,
+    5,  9,  8,  5,  9,  5,  9,  9,  9,  5,  9,  5,  9,  5,  9,  5,
+    9,  5,  9,  5,  5,  5,  5,  5,  5,  5,  9,  9,  5,  9,  9,  5,
+    5,  9,  5,  9,  9,  9,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    5,  5,  5,  5,  7,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+    6,  6, 24, 24, 24, 24,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+    6,  6, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+    6,  6,  6,  6,  6, 24, 24, 24, 24, 24, 24, 24,  6, 24,  6, 24,
+   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+    9,  5,  9,  5,  6, 24,  9,  5,  2,  2,  6,  5,  5,  5, 21,  9,
+    2,  2,  2,  2, 24, 24,  9, 21,  9,  9,  9,  2,  9,  2,  9,  9,
+    5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,
+    5,  5,  9,  9,  9,  5,  5,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    5,  5,  5,  5,  9,  5, 25,  9,  5,  9,  9,  5,  5,  9,  9,  9,
+    9,  5, 26, 12, 12, 12, 12, 12, 11, 11,  9,  5,  9,  5,  9,  5,
+    9,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  5,
+    2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  2,  2,  6, 21, 21, 21, 21, 21, 21,
+    5,  5,  5,  5,  5,  5,  5,  5,  5, 21, 17,  2,  2, 26, 26, 23,
+    2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12,
+   21, 12, 12, 21, 12, 12, 21, 12,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  7,
+    7,  7,  7, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    1,  1,  1,  1,  1,  1, 25, 25, 25, 21, 21, 23, 21, 21, 26, 26,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21,  1,  2, 21, 21,
+    6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21,  7,  7,
+   12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7, 21,  7, 12, 12, 12, 12, 12, 12, 12,  1, 26, 12,
+   12, 12, 12, 12, 12,  6,  6, 12, 12, 26, 12, 12, 12, 12,  7,  7,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  7, 26, 26,  7,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  1,
+    7, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2,  7,  7,  7,
+    7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12,
+   12, 12, 12, 12,  6,  6, 26, 21, 21, 21,  6,  2,  2, 12, 23, 23,
+    7,  7,  7,  7,  7,  7, 12, 12, 12, 12,  6, 12, 12, 12, 12, 12,
+   12, 12, 12, 12,  6, 12, 12, 12,  6, 12, 12, 12, 12, 12,  2,  2,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12,  2,  2, 21,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12,  1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 10, 12,  7, 10, 10,
+   10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, 10, 12, 10, 10,
+    7, 12, 12, 12, 12, 12, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7, 12, 12, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   21,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,
+    7,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,
+    7,  2,  7,  2,  2,  2,  7,  7,  7,  7,  2,  2, 12,  7, 10, 10,
+   10, 12, 12, 12, 12,  2,  2, 10, 10,  2,  2, 10, 10, 12,  7,  2,
+    2,  2,  2,  2,  2,  2,  2, 10,  2,  2,  2,  2,  7,  7,  2,  7,
+    7,  7, 12, 12,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    7,  7, 23, 23, 15, 15, 15, 15, 15, 15, 26, 23,  7, 21, 12,  2,
+    2, 12, 12, 10,  2,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  7,
+    7,  2,  7,  7,  2,  7,  7,  2,  7,  7,  2,  2, 12,  2, 10, 10,
+   10, 12, 12,  2,  2,  2,  2, 12, 12,  2,  2, 12, 12, 12,  2,  2,
+    2, 12,  2,  2,  2,  2,  2,  2,  2,  7,  7,  7,  7,  2,  7,  2,
+    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   12, 12,  7,  7,  7, 12, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2, 12, 12, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,
+    7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  2,  2, 12,  7, 10, 10,
+   10, 12, 12, 12, 12, 12,  2, 12, 12, 10,  2, 10, 10, 12,  2,  2,
+    7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   21, 23,  2,  2,  2,  2,  2,  2,  2,  7, 12, 12, 12, 12, 12, 12,
+    2, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,
+    7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  2,  2, 12,  7, 10, 12,
+   10, 12, 12, 12, 12,  2,  2, 10, 10,  2,  2, 10, 10, 12,  2,  2,
+    2,  2,  2,  2,  2, 12, 12, 10,  2,  2,  2,  2,  7,  7,  2,  7,
+   26,  7, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2, 12,  7,  2,  7,  7,  7,  7,  7,  7,  2,  2,  2,  7,  7,
+    7,  2,  7,  7,  7,  7,  2,  2,  2,  7,  7,  2,  7,  2,  7,  7,
+    2,  2,  2,  7,  7,  2,  2,  2,  7,  7,  7,  2,  2,  2,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2, 10, 10,
+   12, 10, 10,  2,  2,  2, 10, 10, 10,  2, 10, 10, 10, 12,  2,  2,
+    7,  2,  2,  2,  2,  2,  2, 10,  2,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 26, 26, 26, 26, 26, 26, 23, 26,  2,  2,  2,  2,  2,
+   12, 10, 10, 10, 12,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
+    7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  7, 12, 12,
+   12, 10, 10, 10, 10,  2, 12, 12, 12,  2, 12, 12, 12, 12,  2,  2,
+    2,  2,  2,  2,  2, 12, 12,  2,  7,  7,  7,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2, 21, 15, 15, 15, 15, 15, 15, 15, 26,
+    7, 12, 10, 10, 21,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
+    7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  2,  2, 12,  7, 10, 12,
+   10, 10, 10, 10, 10,  2, 12, 10, 10,  2, 10, 10, 12, 12,  2,  2,
+    2,  2,  2,  2,  2, 10, 10,  2,  2,  2,  2,  2,  2,  2,  7,  2,
+    2,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 10, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12,  7, 10, 10,
+   10, 12, 12, 12, 12,  2, 10, 10, 10,  2, 10, 10, 10, 12,  7, 26,
+    2,  2,  2,  2,  7,  7,  7, 10, 15, 15, 15, 15, 15, 15, 15,  7,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 26,  7,  7,  7,  7,  7,  7,
+    2, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  7,  7,  7,  7,  7,  7,
+    7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  2,  2, 12,  2,  2,  2,  2, 10,
+   10, 10, 12, 12, 12,  2, 12,  2, 10, 10, 10, 10, 10, 10, 10, 10,
+    2,  2, 10, 10, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7, 12,  7,  7, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2, 23,
+    7,  7,  7,  7,  7,  7,  6, 12, 12, 12, 12, 12, 12, 12, 12, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21,  2,  2,  2,  2,
+    2,  7,  7,  2,  7,  2,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,
+    7,  7,  7,  7,  2,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7, 12,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 12,  7,  2,  2,
+    7,  7,  7,  7,  7,  2,  6,  2, 12, 12, 12, 12, 12, 12,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  7,  7,  7,  7,
+    7, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 26, 21, 26, 26, 26, 12, 12, 26, 26, 26, 26, 26, 26,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 26, 12, 26, 12, 26, 12, 22, 18, 22, 18, 10, 10,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,
+    2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
+   12, 12, 12, 12, 12, 21, 12, 12,  7,  7,  7,  7,  7, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2, 26, 26,
+   26, 26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26,  2, 26, 26,
+   21, 21, 21, 21, 21, 26, 26, 26, 26, 21, 21,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 10, 12, 12, 12,
+   12, 10, 12, 12, 12, 12, 12, 12, 10, 12, 12, 10, 10, 12, 12,  7,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21,
+    7,  7,  7,  7,  7,  7, 10, 10, 12, 12,  7,  7,  7,  7, 12, 12,
+   12,  7, 10, 10, 10,  7,  7, 10, 10, 10, 10, 10, 10, 10,  7,  7,
+    7, 12, 12, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7, 12, 10, 10, 12, 12, 10, 10, 10, 10, 10, 10, 12,  7, 10,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 10, 10, 10, 12, 26, 26,
+    9,  9,  9,  9,  9,  9,  2,  9,  2,  2,  2,  2,  2,  9,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 21,  6,  5,  5,  5,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  2,  7,  7,  7,  7,  2,  2,
+    7,  2,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,  7,  2,
+    7,  2,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2, 12, 12, 12,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,
+    9,  9,  9,  9,  9,  9,  2,  2,  5,  5,  5,  5,  5,  5,  2,  2,
+   17,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 26, 21,  7,
+   29,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 22, 18,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 21, 21, 21, 14, 14,
+   14,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,
+    7,  7, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7, 12, 12, 12, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  2, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, 10, 10,
+   10, 10, 10, 10, 10, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 21, 21, 21,  6, 21, 21, 21, 23,  7, 12,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,
+   21, 21, 21, 21, 21, 21, 17, 21, 21, 21, 21, 12, 12, 12,  1,  2,
+    7,  7,  7,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 12,  7,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,
+   12, 12, 12, 10, 10, 10, 10, 12, 12, 10, 10, 10,  2,  2,  2,  2,
+   10, 10, 12, 10, 10, 10, 10, 10, 10, 12, 12, 12,  2,  2,  2,  2,
+   26,  2,  2,  2, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,
+    7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15,  2,  2,  2, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+    7,  7,  7,  7,  7,  7,  7, 12, 12, 10, 10, 12,  2,  2, 21, 21,
+    7,  7,  7,  7,  7, 10, 12, 10, 12, 12, 12, 12, 12, 12, 12,  2,
+   12, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10,
+   10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2, 12,
+   21, 21, 21, 21, 21, 21, 21,  6, 21, 21, 21, 21, 21, 21,  2,  2,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 12,
+   12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 12, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7, 12, 10, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10,
+   10, 10, 12, 10, 10,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,
+   21, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,
+   12, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 12, 12, 12,  7,  7,
+    7,  7,  7,  7,  7,  7, 12, 10, 12, 12, 10, 10, 10, 12, 10, 12,
+   12, 12, 10, 10,  2,  2,  2,  2,  2,  2,  2,  2, 21, 21, 21, 21,
+    7,  7,  7,  7, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12,
+   12, 12, 12, 12, 10, 10, 12, 12,  2,  2,  2, 21, 21, 21, 21, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  6,  6,  6,  6,  6,  6, 21, 21,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  2,  2,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,  9,
+   21, 21, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 10, 12, 12, 12, 12, 12, 12, 12,  7,  7,  7,  7, 12,  7,  7,
+    7,  7,  7,  7, 12,  7,  7, 10, 12, 12,  7,  2,  2,  2,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  6,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12,
+    9,  5,  9,  5,  9,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,  9,  9,  9,  9,
+    5,  5,  5,  5,  5,  5,  2,  2,  9,  9,  9,  9,  9,  9,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  2,  9,  2,  9,  2,  9,  2,  9,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  8,  8,  8,  8,  8,  8,  8,  8,
+    5,  5,  5,  5,  5,  2,  5,  5,  9,  9,  9,  9,  8, 24,  5, 24,
+   24, 24,  5,  5,  5,  2,  5,  5,  9,  9,  9,  9,  8, 24, 24, 24,
+    5,  5,  5,  5,  2,  2,  5,  5,  9,  9,  9,  9,  2, 24, 24, 24,
+    5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,  9, 24, 24, 24,
+    2,  2,  5,  5,  5,  2,  5,  5,  9,  9,  9,  9,  8, 24, 24,  2,
+   29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,  1,  1,  1,  1,  1,
+   17, 17, 17, 17, 17, 17, 21, 21, 20, 19, 22, 20, 20, 19, 22, 20,
+   21, 21, 21, 21, 21, 21, 21, 21, 27, 28,  1,  1,  1,  1,  1, 29,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 19, 21, 21, 21, 21, 16,
+   16, 21, 21, 21, 25, 22, 18, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 25, 21, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 29,
+    1,  1,  1,  1,  1,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+   15,  6,  2,  2, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18,  6,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18,  2,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  2,  2,  2,
+   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
+   11, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   26, 26,  9, 26, 26, 26, 26,  9, 26, 26,  5,  9,  9,  9,  5,  5,
+    9,  9,  9,  5, 26,  9, 26, 26, 25,  9,  9,  9,  9,  9, 26, 26,
+   26, 26, 26, 26,  9, 26,  9, 26,  9, 26,  9,  9,  9,  9, 26,  5,
+    9,  9,  9,  9,  5,  7,  7,  7,  7,  5, 26, 26,  5,  5,  9,  9,
+   25, 25, 25, 25, 25,  9,  5,  5,  5,  5, 26, 25, 26, 26,  5, 26,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14,  9,  5, 14, 14, 14, 14, 15, 26, 26,  2,  2,  2,  2,
+   25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 25, 25, 26, 26, 26, 26,
+   25, 26, 26, 25, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 25, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25,
+   26, 26, 25, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 26, 26, 26, 26,
+   25, 25, 26, 26, 26, 26, 26, 26, 26, 22, 18, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25,
+   25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15,
+   26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25,
+   26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18,
+   22, 18, 22, 18, 22, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   25, 25, 25, 25, 25, 22, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18,
+   25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
+   18, 22, 18, 22, 18, 22, 18, 22, 18, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 25, 25,
+   25, 25, 25, 25, 25, 26, 26, 25, 25, 25, 25, 25, 25, 26, 26, 26,
+   26, 26, 26, 26,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,
+    9,  5,  9,  9,  9,  5,  5,  9,  5,  9,  5,  9,  5,  9,  9,  9,
+    9,  5,  9,  5,  5,  9,  5,  5,  5,  5,  5,  5,  6,  6,  9,  9,
+    9,  5,  9,  5,  5, 26, 26, 26, 26, 26, 26,  9,  5,  9,  5, 12,
+   12, 12,  9,  5,  2,  2,  2,  2,  2, 21, 21, 21, 21, 15, 21, 21,
+    5,  5,  5,  5,  5,  5,  2,  5,  2,  2,  2,  2,  2,  5,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  6,
+   21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12,
+    7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  2,
+   21, 21, 20, 19, 20, 19, 21, 21, 21, 20, 19, 21, 20, 19, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 17, 21, 21, 17, 21, 20, 19, 21, 21,
+   20, 19, 22, 18, 22, 18, 22, 18, 22, 18, 21, 21, 21, 21, 21,  6,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 21, 21, 21, 21,
+   17, 21, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   26, 26, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2, 26, 26, 26, 26, 26,
+   26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,
+   29, 21, 21, 21, 26,  6,  7, 14, 22, 18, 22, 18, 22, 18, 22, 18,
+   22, 18, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18, 17, 22, 18, 18,
+   26, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 10, 10,
+   17,  6,  6,  6,  6,  6, 26, 26, 14, 14, 14,  6,  7, 21, 26, 26,
+    7,  7,  7,  7,  7,  7,  7,  2,  2, 12, 12, 24, 24,  6,  6,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 21,  6,  6,  6,  7,
+    2,  2,  2,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+   26, 26, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15, 15, 15,
+   26, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  7,  7,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  6, 21, 21, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  2,  2,  2,  2,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  7, 12,
+   11, 11, 11, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21,  6,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  6,  6, 12, 12,
+    7,  7,  7,  7,  7,  7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   12, 12, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,
+   24, 24, 24, 24, 24, 24, 24,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+   24, 24,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    5,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    6,  5,  5,  5,  5,  5,  5,  5,  5,  9,  5,  9,  5,  9,  9,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  6, 24, 24,  9,  5,  9,  5,  7,
+    9,  5,  9,  5,  5,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  9,  9,  9,  9,  5,
+    9,  9,  9,  9,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,  9,  5,
+    2,  2,  9,  5,  9,  9,  9,  9,  5,  9,  5,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  9,  5,  7,  6,  6,  5,  7,  7,  7,  7,  7,
+    7,  7, 12,  7,  7,  7, 12,  7,  7,  7,  7, 12,  7,  7,  7,  7,
+    7,  7,  7, 10, 10, 12, 12, 10, 26, 26, 26, 26, 12,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 26, 26, 23, 26,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,
+   10, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2, 21, 21,
+   12, 12,  7,  7,  7,  7,  7,  7, 21, 21, 21,  7, 21,  7,  7, 12,
+    7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21,
+    7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 10, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 21,
+    7,  7,  7, 12, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 10,
+   10, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  6,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2, 21, 21,
+    7,  7,  7,  7,  7, 12,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7,  7,  7,  7,  7,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 10,
+   10, 12, 12, 10, 10, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7, 12,  7,  7,  7,  7,  7,  7,  7,  7, 12, 10,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2, 21, 21, 21, 21,
+    6,  7,  7,  7,  7,  7,  7, 26, 26, 26,  7, 10, 12, 10,  7,  7,
+   12,  7, 12, 12, 12,  7,  7, 12, 12,  7,  7,  7,  7,  7, 12, 12,
+    7, 12,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,  7,  6, 21, 21,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 12, 12, 10, 10,
+   21, 21,  7,  6,  6, 10, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,  2,
+    2,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 24,  6,  6,  6,  6,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  6, 24, 24,  2,  2,  2,  2,
+    7,  7,  7, 10, 10, 12, 10, 10, 12, 10, 10, 21, 10, 12,  2,  2,
+    7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  7,  7,  7,  7,  7,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  5,  5,  5,  5,  5,  2,  2,  2,  2,  2,  7, 12,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 25,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  2,  7,  2,
+    7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24, 24,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 18, 22,
+    2,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 23, 26,  2,  2,
+   21, 21, 21, 21, 21, 21, 21, 22, 18, 21,  2,  2,  2,  2,  2,  2,
+   21, 17, 17, 16, 16, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
+   18, 22, 18, 22, 18, 21, 21, 22, 18, 21, 21, 21, 21, 16, 16, 16,
+   21, 21, 21,  2, 21, 21, 21, 21, 17, 22, 18, 22, 18, 22, 18, 21,
+   21, 21, 25, 17, 25, 25, 25,  2, 21, 23, 21, 21,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  1,
+    2, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22, 25, 18, 25, 22,
+   18, 21, 22, 18, 21, 21,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  6,  6,
+    2,  2,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,
+    2,  2,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  2,  2,  2,
+   23, 23, 25, 24, 26, 23, 23,  2, 26, 25, 25, 25, 25, 26, 26,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  1,  1, 26, 26,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  7,
+   21, 21, 21,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15,  2,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   14, 14, 14, 14, 14, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 26, 26, 26,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,
+   26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12,  2,  2,
+   12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,
+   15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,  7,  7,
+    7, 14,  7,  7,  7,  7,  7,  7,  7,  7, 14,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2, 21,
+    7,  7,  7,  7,  2,  2,  2,  2,  7,  7,  7,  7,  7,  7,  7,  7,
+   21, 14, 14, 14, 14, 14,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    9,  9,  9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  5,  5,  5,  5,
+    9,  9,  9,  9,  2,  2,  2,  2,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  2,  2,
+    7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 21,
+    7,  7,  7,  7,  7,  7,  2,  2,  7,  2,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  2,  2,  7,  2,  2,  7,
+    7,  7,  7,  7,  7,  7,  2, 21, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  7,  7,  7,  7, 26, 26, 15, 15, 15, 15, 15, 15, 15,
+    2,  2,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  2,  7,  7,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15,
+    7,  7,  7,  7,  7,  7, 15, 15, 15, 15, 15, 15,  2,  2,  2, 21,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2, 21,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2, 15, 15,  7,  7,
+    2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    7, 12, 12, 12,  2, 12, 12,  2,  2,  2,  2,  2, 12, 12, 12, 12,
+    7,  7,  7,  7,  2,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  2,  2, 12, 12, 12,  2,  2,  2,  2, 12,
+   15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,
+   21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 15, 15, 21,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 15, 15, 15,
+    7,  7,  7,  7,  7,  7,  7,  7, 26,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7, 12, 12,  2,  2,  2,  2, 15, 15, 15, 15, 15,
+   21, 21, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  2,  2,  2, 21, 21, 21, 21, 21, 21, 21,
+    7,  7,  7,  7,  7,  7,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15,
+    7,  7,  2,  2,  2,  2,  2,  2,  2, 21, 21, 21, 21,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15, 15,
+    9,  9,  9,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    5,  5,  5,  2,  2,  2,  2,  2,  2,  2, 15, 15, 15, 15, 15, 15,
+    7,  7,  7,  7, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2, 12, 12, 17,  2,  2,
+    7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15,  7,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 15, 15, 15, 15, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,
+   10, 12, 10,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21,  2,  2,
+   15, 15, 15, 15, 15, 15, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12,
+   10, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 21, 21,  1, 21, 21,
+   21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  1,  2,  2,
+   12, 12, 12,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 10, 12, 12, 12,
+   12, 12, 12, 12, 12,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   21, 21, 21, 21,  7, 10, 10,  7,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7, 12, 21, 21,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
+   10,  7,  7,  7,  7, 21, 21, 21, 21, 12, 12, 12, 12, 21, 10, 12,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  7, 21,  7, 21, 21, 21,
+    2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 10, 10, 12,
+   12, 12, 10, 10, 12, 10, 12, 12, 21, 21, 21, 21, 21, 21, 12,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  2,  7,  7,  7,  7,  2,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7, 21,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12,
+   10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,
+   12, 12, 10, 10,  2,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,
+    7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  2, 12, 12,  7, 10, 10,
+   12, 10, 10, 10, 10,  2,  2, 10, 10,  2,  2, 10, 10, 10,  2,  2,
+    7,  2,  2,  2,  2,  2,  2, 10,  2,  2,  2,  2,  2,  7,  7,  7,
+    7,  7, 10, 10,  2,  2, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,
+   12, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12,
+   10, 10, 12, 12, 12, 10, 12,  7,  7,  7,  7, 21, 21, 21, 21, 21,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21,  2, 21, 12,  7,
+   10, 10, 10, 12, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10, 10, 12,
+   12, 10, 12, 12,  7,  7, 21,  7,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10,
+   10, 10, 12, 12, 12, 12,  2,  2, 10, 10, 10, 10, 12, 12, 10, 12,
+   12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21,  7,  7,  7,  7, 12, 12,  2,  2,
+   10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, 10, 12,
+   12, 21, 21, 21,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 10, 12, 10, 10,
+   12, 12, 12, 12, 12, 12, 10, 12,  7,  2,  2,  2,  2,  2,  2,  2,
+   10, 10, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12,  2,  2,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 21, 21, 21, 26,
+   12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21,  2,  2,  2,  2,
+   15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  7,
+    7,  7,  7,  7,  7,  7,  7,  2,  2,  7,  2,  2,  7,  7,  7,  7,
+    7,  7,  7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,
+   10, 10, 10, 10, 10, 10,  2, 10, 10,  2,  2, 12, 12, 10, 12,  7,
+   10,  7, 10, 12, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  7,  7,  7,  7,  7,  7,
+    7, 10, 10, 10, 12, 12, 12, 12,  2,  2, 12, 12, 10, 10, 10, 10,
+   12,  7, 21,  7, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  7,  7,  7,  7,  7,
+    7,  7,  7, 12, 12, 12, 12, 12, 12, 10,  7, 12, 12, 12, 12, 21,
+   21, 21, 21, 21, 21, 21, 21, 12,  2,  2,  2,  2,  2,  2,  2,  2,
+    7, 12, 12, 12, 12, 12, 12, 10, 10, 12, 12, 12,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 21, 21,  7, 21, 21,
+   21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 10, 12,
+    7, 21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   21, 21,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    2,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12,  2, 10, 12, 12, 12, 12, 12, 12,
+   12, 10, 12, 12, 10, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,
+    7, 12, 12, 12, 12, 12, 12,  2,  2,  2, 12,  2, 12, 12,  2, 12,
+   12, 12, 12, 12, 12, 12,  7, 12,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  2,  7,  7,  2,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 10, 10, 10, 10, 10,  2,
+   12, 12,  2, 10, 10, 12, 10, 12,  7,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7, 12, 12, 10, 10, 21, 21,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 23, 23, 23,
+   23, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 21,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2,
+   21, 21, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 12, 12, 12, 21,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 26, 26, 26, 26,
+    6,  6,  6,  6, 21, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2, 15, 15, 15, 15, 15,
+   15, 15,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2,  2,  7,  7,  7,
+   15, 15, 15, 15, 15, 15, 15, 21, 21, 21, 21,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2,  2,  2, 12,
+    7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 10, 10, 10, 10,  2,  2,  2,  2,  2,  2,  2, 12,
+   12, 12, 12,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+    6,  6, 21,  6, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   10, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  7,  7,  7,  7,  2,  2,  2,  2,  2,  2,  2,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  2, 26, 12, 12, 21,
+    1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26,  2,  2, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 10, 10, 12, 12, 12, 26, 26, 26, 10, 10, 10,
+   10, 10, 10,  1,  1,  1,  1,  1,  1,  1,  1, 12, 12, 12, 12, 12,
+   12, 12, 12, 26, 26, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 12, 12, 12, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  5,  5,
+    5,  5,  5,  5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    9,  9,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,  2,  9,  9,
+    2,  2,  9,  2,  2,  9,  9,  2,  2,  9,  9,  9,  9,  2,  9,  9,
+    9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  2,  5,  2,  5,  5,  5,
+    5,  5,  5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  9,  9,  2,  9,  9,  9,  9,  2,  2,  9,  9,  9,
+    9,  9,  9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  9,  2,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  2,  9,  9,  9,  9,  2,
+    9,  9,  9,  9,  9,  2,  9,  2,  2,  2,  9,  9,  9,  9,  9,  9,
+    9,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  2,  2,  9,  9,  9,  9,  9,  9,  9,  9,
+    9, 25,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 25,  5,  5,  5,  5,
+    5,  5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 25,  5,  5,  5,  5,
+    5,  5,  5,  5,  5, 25,  5,  5,  5,  5,  5,  5,  9,  9,  9,  9,
+    9,  9,  9,  9,  9, 25,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 25,
+    5,  5,  5,  5,  5,  5,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 25,
+    5,  5,  5,  5,  5,  5,  5,  5,  5, 25,  5,  5,  5,  5,  5,  5,
+    9,  9,  9,  9,  9,  9,  9,  9,  9, 25,  5,  5,  5,  5,  5,  5,
+    5,  5,  5, 25,  5,  5,  5,  5,  5,  5,  9,  5,  2,  2, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26,
+   26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 12, 26, 26, 21, 21, 21, 21, 21,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12,  2,  2, 12, 12, 12, 12, 12,
+   12, 12,  2, 12, 12,  2, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,
+   12, 12, 12, 12, 12, 12, 12,  6,  6,  6,  6,  6,  6,  6,  2,  2,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  7, 26,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 12, 12, 12, 12,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2, 23,
+    7,  7,  7,  7,  7,  2,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   12, 12, 12, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    5,  5,  5,  5, 12, 12, 12, 12, 12, 12, 12,  6,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15, 15, 15,
+   23, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,
+    7,  7,  7,  7,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    2,  7,  7,  2,  7,  2,  2,  7,  2,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  2,  7,  2,  2,  2,  2,
+    2,  2,  7,  2,  2,  2,  2,  7,  2,  7,  2,  7,  2,  7,  7,  7,
+    2,  7,  7,  2,  7,  2,  2,  7,  2,  7,  2,  7,  2,  7,  2,  7,
+    2,  7,  7,  2,  7,  2,  2,  7,  7,  7,  7,  2,  7,  7,  7,  7,
+    7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  7,  7,  7,  2,  7,  2,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,
+    2,  7,  7,  7,  2,  7,  7,  7,  7,  7,  2,  7,  7,  7,  7,  7,
+   25, 25,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2,  2,
+    2,  2,  2,  2,  2,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 24, 24, 24, 24, 24,
+   26, 26, 26, 26, 26, 26, 26, 26,  2,  2,  2,  2,  2,  2,  2,  2,
+   26, 26, 26, 26, 26, 26, 26, 26, 26,  2, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,  2, 26, 26, 26,
+   26, 26, 26, 26, 26,  2,  2,  2, 26, 26, 26,  2,  2,  2,  2,  2,
+   26, 26, 26,  2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+    2,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  0,  0,
+    0,  0,  0,  0,  0,  0,  1,  0,  0,  2,  0,  3,  4,  5,  6,  7,
+    8,  9, 10, 11, 12, 12, 12, 13, 14, 12, 15, 16, 17, 18, 19, 20,
+   21, 22,  0,  0,  0,  0, 23,  0,  0,  0,  0,  0,  0,  0, 24, 25,
+    0, 26, 27,  0, 28, 29, 30, 31, 32, 33,  0, 34,  0,  0,  0,  0,
+    0, 35,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 36, 37, 38,  0,  0,  0,  0,
+   39, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41, 42,  0,  0,
+   43, 44, 45, 46,  0, 47,  0, 48,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 49,  0,  0,  0,  0,  0, 50,  0,  0,  0,
+    0,  0,  0, 51,  0, 52, 53,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 54, 55,  0,  0,  0,  0, 56,  0,  0, 57, 58,  0,
+   59, 60, 61, 62, 63, 64, 65,  0, 66, 67,  0, 68, 69, 70, 71,  0,
+   60,  0, 72, 73, 74, 75,  0,  0, 69,  0, 76, 77,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 78, 79,  0,  0,  0,  0,  0,  0,  0,  0, 80,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 81,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 82, 83, 84,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   85,  0, 79,  0,  0, 86,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 87, 88,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  1,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
+   12,  1,  0,  0, 13,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 14, 15, 16, 17, 18, 19, 20,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  1, 21,  0,  0,  0,  0,  0, 22, 23, 24,
+    0,  0, 25,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 26, 27,
+   28, 29,  0,  0,  0,  0, 30,  0,  0,  0, 31, 32, 33, 34,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 13, 35, 36,  0,  0, 26, 37, 38, 39,  0,  0,  0,  0,  0, 40,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41,  1,
+   42, 43, 44, 45,  0,  0,  0,  0,  0,  0,  0, 46,  0, 47, 48,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 46,  0, 47,  0,  0,
+    0,  0,  0, 49,  0,  0,  0,  0,  0,  0,  0, 46,  0, 47,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 47,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 47, 50,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 51,  0, 47,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 52,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 53,  0, 54,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 55,  0, 56,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 57,  0,  0, 58, 59,  0,  0,  0,  0,
+    0,  0, 60, 61, 62,  0,  0,  0,  0,  0,  0,  0, 63,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 64, 65,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 66,
+    0,  0,  0,  0,  0,  0, 67,  0,  0,  0, 67,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 52, 68,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 69,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 70,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 71, 72,  0,  0,  0,  0,  0,  0,  0,  0,
+   73,  0, 66, 74,  0,  0,  0,  0,  0,  0, 75, 76, 72,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 46,  0, 67,  0,  0,  0,
+    0, 77, 78,  0,  0,  0,  0,  0,  0, 79,  0,  0,  0,  0,  0,  0,
+   80,  0, 79,  0,  0,  0,  0,  0,  0,  0, 64,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 81, 82,
+   83, 84, 85, 86,  0,  0,  0,  0,  0,  0,  0,  0, 87, 88, 89,  1,
+    1,  1, 90, 91,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 92, 93,
+   94, 95, 96,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 71, 86,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 97,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    1,  1,  1,  1,  0,  0,  0,  0,  0, 98,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 99,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 71,100,101,  0,  0,  0, 26,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 86,  0,102,  0,  0,  0,  0, 67,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 67,  0,  0,  0,
+    1,  1, 86,  0,  0,  0,  0,  0,  0,103,  0,  0,  0,  0,104,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,  0, 73,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,106,107,108,  0,  0,  0,
+    0,  0,102,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 47,  0,  0,  0,  0,  0,109,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,110,111,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 36,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   72,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 26,112,  0,113,  0,  0,  0,  0,  0,114,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  115,  0,  0,  0,  0,  0,  0,  0,100,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,116,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,117,118, 72,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,102,  0,  0,  0,
+    0,  0,  0, 97,  0,  0,  0,  0,  0,  0,  0,119,  0,  0,  0,  0,
+    0,  0,  0,  0,112,  0,  0,  0,  0,  0, 51,  0,  0,  0,  0,  0,
+    0,  0,105,  0,  0,  0,  0,  0,  0,  0,  0,  0, 73,120,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,121,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,122,  0,  0,  0,  0,  0,  0,  0,  0,  0,123,  0, 47,  0,  0,
+   26,124,124,  0,  0,  0,  0,  0,  0,  0,  0,  0,125,  0,  0, 49,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,126,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 97,127,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 97,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,128,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,104,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,129,105,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   73,  0,  0,  0,  0,  0,  0,  0,  0,  0, 67,  0, 97,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,130,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,131,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 97,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,132,  0,  0,  0,  0,  0,  0,  0,133,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,134,  0,  0,  0,  0,135,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  136,137,138,139,140,141,  0,  0,  0,142,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,143,  0,  0,  0,
+    0,  0,  0,  0,133,  1,  1,144,145,112,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,100,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,146,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,100,147,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,
+  230,230,230,230,230,230,230,230,230,232,220,220,220,220,232,216,
+  220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
+  220,220,220,220,220,220,220,220,  1,  1,  1,  1,  1,220,220,220,
+  220,230,230,230,230,230,230,230,230,240,230,220,220,220,230,230,
+  230,220,220,  0,230,230,230,220,220,220,220,230,232,220,220,230,
+  233,234,234,233,234,234,233,230,230,230,230,230,  0,  0,  0,230,
+  230,230,230,230,  0,220,230,230,230,230,220,230,230,230,222,220,
+  230,230,230,230,230,230,220,220,220,220,220,220,230,230,220,230,
+  230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
+   21, 22,  0, 23,  0, 24, 25,  0,230,220,  0, 18, 30, 31, 32,  0,
+    0,  0,  0,  0,  0,  0,  0, 27, 28, 29, 30, 31, 32, 33, 34,230,
+  230,220,220,230,230,230,230,230,220,230,230,220, 35,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,
+  230,  0,  0,230,230,230,230,220,230,  0,  0,230,230,  0,220,230,
+  230,220,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0,230,220,230,230,
+  220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230,
+  220,230,220,230,220,230,230,  0,  0,  0,  0,  0,230,230,220,230,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,220,  0,  0,230,230,  0,230,
+  230,230,230,230,230,230,230,230,  0,230,230,230,  0,230,230,230,
+  230,230,  0,  0,  0,220,220,220,  0,  0,  0,  0,  0,  0,  0,220,
+  230,230,230,230,230,230,  0,220,230,230,220,230,230,220,230,230,
+  230,220,220,220, 27, 28, 29,230,230,230,220,230,230,220,220,230,
+  230,230,230,230,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,
+    0,  9,  0,  0,  0,230,220,230,230,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,230,  0,  0,  0,  0,  0,  0, 84, 91,  0,  0,  0,  0,  9,
+    9,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,103,103,  9,  0,
+    0,  0,  0,  0,107,107,107,107,  0,  0,  0,  0,118,118,  9,  0,
+    0,  0,  0,  0,122,122,122,122,  0,  0,  0,  0,220,220,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,220,  0,220,  0,216,  0,  0,
+    0,  0,  0,  0,  0,129,130,  0,132,  0,  0,  0,  0,  0,130,130,
+  130,130,  0,  0,130,  0,230,230,  9,  0,230,230,  0,  0,  0,  0,
+    0,  0,220,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,  9,  9,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,230,230,230,  0,  0,  0,  0,
+    9,  0,  0,  0,  0,  0,  0,  0,  0,230,  0,  0,  0,228,  0,  0,
+    0,  0,  0,  0,  0,222,230,220,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,230,220,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,
+    0,  0,  0,  0,230,230,230,230,230,  0,  0,220,230,230,230,230,
+  230,220,220,220,220,220,220,230,230,220,  0,220,  0,  0,  0,230,
+  220,230,230,230,230,230,230,230,  0,  0,  0,  0,  0,  0,  9,  9,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,230,230,230,  0,
+    1,220,220,220,220,220,230,230,220,220,220,220,230,  0,  1,  1,
+    1,  1,  1,  1,  1,  0,  0,  0,  0,220,  0,  0,  0,  0,  0,  0,
+  230,  0,  0,  0,230,230,  0,  0,  0,  0,  0,  0,230,230,220,230,
+  230,230,230,230,230,230,220,230,230,234,214,220,202,230,230,230,
+  230,230,230,230,230,230,230,230,230,230,232,228,228,220,  0,230,
+  233,220,230,220,230,230,  1,  1,230,230,230,230,  1,  1,  1,230,
+  230,  0,  0,  0,  0,230,  0,  0,  0,  1,  1,230,220,230,  1,  1,
+  220,220,220,220,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  9,  0,  0,218,228,232,222,224,224,  0,  8,  8,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,230,230,230,230,230,230,230,230,
+  230,230,  0,  0,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,220,
+  220,220,  0,  0,  0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  7,
+    0,  0,  0,  0,230,  0,230,230,220,  0,  0,230,230,  0,  0,  0,
+    0,  0,230,230,  0,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 26,  0,230,230,230,230,230,230,230,220,220,220,220,220,
+  220,220,230,230,230,230,230,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,220,  0,230,230,  1,220,  0,  0,  0,  0,  9,  0,  0,  0,  0,
+    0,230,220,  0,  0,  0,  0,230,230,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,220,220,230,230,230,220,230,220,220,220,  0,  9,  7,  0,
+    0,  0,  0,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  9,  7,  0,  0,  7,  9,  0,  0,  0,  0,  0,  0,  0,  0,  7,
+    7,  0,  0,  0,230,230,230,230,230,  0,  0,  0,  0,  0,  9,  0,
+    0,  0,  7,  0,  0,  0,  9,  7,  0,  0,  0,  0,  7,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9,  7,  0,  0,  0,  0,
+    0,  9,  9,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  7,  0,
+    9,  9,  0,  0,  1,  1,  1,  1,  1,  0,  0,  0,230,230,230,230,
+  230,230,230,  0,  6,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  1,  0,  0,  0,  0,  0,  0,216,216,  1,  1,  1,  0,  0,
+    0,226,216,216,216,216,216,  0,  0,  0,  0,  0,  0,  0,  0,220,
+  220,220,220,220,220,220,220,  0,  0,230,230,230,230,230,220,220,
+    0,  0,  0,  0,  0,  0,230,230,230,230,  0,  0,  0,  0,230,230,
+  230,  0,  0,  0,230,  0,  0,230,230,230,230,230,230,230,  0,230,
+  230,  0,230,230,220,220,220,220,220,220,220,  0,230,230,  7,  0,
+    0,  0,  0,  0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
+   17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17,237,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,
+    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  0,  0,
+    0,  0,  3,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  0,
+    0,  0,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  7,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  9,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 10,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 10,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 11, 12,  0, 13,  0, 14, 15, 16,  0,  0,
+    0,  0,  0,  1, 17, 18,  0, 19,  7,  1,  0,  0,  0, 20, 20,  7,
+   20, 20, 20, 20, 20, 20, 20,  8, 21,  0, 22,  0,  7, 23, 24,  0,
+   20, 20, 25,  0,  0,  0, 26, 27,  1,  7, 20, 20, 20, 20, 20,  1,
+   28, 29, 30, 31,  0,  0, 20,  0,  0,  0,  0,  0,  0,  0, 10,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20, 20,
+   20,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  8, 21, 32,  4,  0, 10,  0, 33,  7, 20, 20, 20,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  8, 34, 34, 35, 36, 34, 37,  0, 38,  1, 20, 20,
+    0,  0, 39,  0,  1,  1,  0,  8, 21,  1, 20,  0,  0,  0,  1,  0,
+    0, 40,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 21,
+    0,  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,
+    0,  0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21,  7, 20, 41,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 21,  0, 42, 43, 44,  0, 45,
+    0,  8, 21,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 46,  7,  1, 10,  1,  0,  0,  0,  1, 20, 20,  1,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 20, 20,  1, 20, 20,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 26, 21,  0,  1,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  2,  0,  0,  0,  0,
+    0,  0,  3,  4,  0,  0,  0,  0,  0,  0,  3, 47, 48,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,
+    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  0,  0,
+    0,  0,  3,  4,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
+   12, 13, 14, 15, 16, 17, 18, 17, 19, 20, 21, 22, 23, 24, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 27, 28, 28, 29, 30, 31, 32, 33, 33, 33, 33, 33, 33,
+   33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+   52, 53, 54, 55, 56, 57, 58, 35, 35, 35, 35, 35, 59, 59, 60, 35,
+   35, 35, 35, 35, 35, 35, 61, 62, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 63, 64, 35, 65, 66, 66, 66, 66,
+   66, 66, 66, 66, 66, 66, 66, 67, 66, 68, 69, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 70, 71, 35, 35,
+   35, 35, 72, 35, 35, 35, 35, 35, 35, 35, 35, 35, 73, 74, 75, 76,
+   77, 78, 35, 35, 79, 80, 35, 35, 81, 35, 82, 83, 84, 85, 17, 86,
+   87, 88, 35, 35, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 89, 25, 25, 25, 25, 25, 25, 25, 90,
+   91, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 92, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 93, 35, 35, 35, 35, 35, 35,
+   25, 94, 35, 35, 25, 25, 25, 25, 25, 25, 25, 25, 25, 95, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 96,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   19,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0,
+    0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19,  0,  0,  0,  0,  0,
+   26, 26,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1,  1,  1,  1,  1,  1,  9,  9,  9,  9,  0,  9,  9,  9,  2,  2,
+    9,  9,  9,  9,  0,  9,  2,  2,  2,  2,  9,  0,  9,  0,  9,  9,
+    9,  2,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9, 55, 55, 55, 55, 55, 55, 55, 55,
+   55, 55, 55, 55, 55, 55,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  1,  1,  6,  6,  6,
+    6,  6,  6,  6,  6,  6,  2,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  2,  2,  4,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    4,  2,  2,  4,  4,  4,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2,  2,
+    2,  2,  2,  2,  2,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14,  2,  2,  2,  2, 14, 14, 14, 14, 14, 14,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,
+    3,  3,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  0,  3,  2,  3,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  1,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  0,  3,  3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+   37, 37, 37, 37,  2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+   37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+   37,  2,  2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+   38, 38, 38, 38, 38, 38, 38, 38,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+   64,  2,  2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+   90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+   90, 90, 90, 90,  2,  2, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+   90, 90, 90, 90, 90,  2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95,  2,  2, 95,  2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+   37,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  1,  1,  1,  1,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  0,  0,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  5,  5,  5,  5,  2,  5,  5,  5,  5,  5,
+    5,  5,  5,  2,  2,  5,  5,  2,  2,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,
+    5,  5,  5,  5,  5,  5,  5,  2,  5,  2,  2,  2,  5,  5,  5,  5,
+    2,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  5,  5,  2,
+    2,  5,  5,  5,  5,  2,  2,  2,  2,  2,  2,  2,  2,  5,  2,  2,
+    2,  2,  5,  5,  2,  5,  5,  5,  5,  5,  2,  2,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+    5,  5,  5,  5,  5,  2,  2, 11, 11, 11,  2, 11, 11, 11, 11, 11,
+   11,  2,  2,  2,  2, 11, 11,  2,  2, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,
+   11, 11, 11, 11, 11, 11, 11,  2, 11, 11,  2, 11, 11,  2, 11, 11,
+    2,  2, 11,  2, 11, 11, 11, 11, 11,  2,  2,  2,  2, 11, 11,  2,
+    2, 11, 11, 11,  2,  2,  2, 11,  2,  2,  2,  2,  2,  2,  2, 11,
+   11, 11, 11,  2, 11,  2,  2,  2,  2,  2,  2,  2, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2, 10, 10, 10,  2, 10, 10, 10, 10, 10,
+   10, 10, 10, 10,  2, 10, 10, 10,  2, 10, 10, 10, 10, 10, 10, 10,
+   10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2,
+   10, 10, 10, 10, 10, 10, 10,  2, 10, 10,  2, 10, 10, 10, 10, 10,
+    2,  2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,
+    2, 10, 10, 10,  2,  2, 10,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 10, 10, 10, 10,  2,  2, 10, 10, 10, 10,
+   10, 10, 10, 10, 10, 10, 10, 10,  2,  2,  2,  2,  2,  2,  2, 10,
+   10, 10, 10, 10, 10, 10,  2, 21, 21, 21,  2, 21, 21, 21, 21, 21,
+   21, 21, 21,  2,  2, 21, 21,  2,  2, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,
+   21, 21, 21, 21, 21, 21, 21,  2, 21, 21,  2, 21, 21, 21, 21, 21,
+    2,  2, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2, 21, 21,  2,
+    2, 21, 21, 21,  2,  2,  2,  2,  2,  2,  2, 21, 21, 21,  2,  2,
+    2,  2, 21, 21,  2, 21, 21, 21, 21, 21,  2,  2, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2, 22, 22,  2, 22, 22, 22, 22, 22,
+   22,  2,  2,  2, 22, 22, 22,  2, 22, 22, 22, 22,  2,  2,  2, 22,
+   22,  2, 22,  2, 22, 22,  2,  2,  2, 22, 22,  2,  2,  2, 22, 22,
+   22,  2,  2,  2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+    2,  2,  2,  2, 22, 22, 22, 22, 22,  2,  2,  2, 22, 22, 22,  2,
+   22, 22, 22, 22,  2,  2, 22,  2,  2,  2,  2,  2,  2, 22,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22,  2,  2,  2,  2,  2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+   23, 23, 23,  2, 23, 23, 23,  2, 23, 23, 23, 23, 23, 23, 23, 23,
+   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,  2,
+   23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+    2,  2,  2, 23, 23, 23, 23, 23, 23, 23, 23,  2, 23, 23, 23,  2,
+   23, 23, 23, 23,  2,  2,  2,  2,  2,  2,  2, 23, 23,  2, 23, 23,
+   23,  2,  2,  2,  2,  2, 23, 23, 23, 23,  2,  2, 23, 23, 23, 23,
+   23, 23, 23, 23, 23, 23,  2,  2,  2,  2,  2,  2,  2, 23, 23, 23,
+   23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16,  2, 16, 16, 16,  2, 16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2,
+   16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16, 16, 16,
+    2,  2, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16,  2,
+   16, 16, 16, 16,  2,  2,  2,  2,  2,  2,  2, 16, 16,  2,  2,  2,
+    2,  2,  2,  2, 16,  2, 16, 16, 16, 16,  2,  2, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16,  2, 16, 16,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+   20, 20, 20,  2, 20, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  2, 20, 20, 20,  2,
+   20, 20, 20, 20, 20, 20,  2,  2,  2,  2, 20, 20, 20, 20, 20, 20,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  2,  2, 20, 20, 20, 20,
+   20, 20, 20, 20, 20, 20,  2, 36, 36, 36,  2, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36,  2, 36, 36, 36, 36, 36, 36, 36,
+   36, 36,  2, 36,  2,  2, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,
+   36,  2,  2,  2,  2, 36, 36, 36, 36, 36, 36,  2, 36,  2, 36, 36,
+   36, 36, 36, 36, 36, 36,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36,  2,  2, 36, 36, 36,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24,  2,  2,  2,  2,  0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24, 24,  2,  2,  2,  2,  2, 18, 18,  2, 18,  2, 18, 18, 18, 18,
+   18,  2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+   18, 18, 18, 18, 18, 18, 18, 18, 18, 18,  2, 18,  2, 18, 18, 18,
+   18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+   18, 18, 18, 18,  2,  2, 18, 18, 18, 18, 18,  2, 18,  2, 18, 18,
+   18, 18, 18, 18,  2,  2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+    2,  2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,  2, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25,  2,  2,  2,  2, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25,  2, 25, 25, 25, 25, 25, 25, 25,  0,  0,  0,  0, 25,
+   25,  2,  2,  2,  2,  2, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+   33, 33, 33, 33, 33, 33,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  2,  8,  2,  2,
+    2,  2,  2,  8,  2,  2,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    8,  0,  8,  8,  8,  8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+   30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,  2,
+   30, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30, 30, 30,  2, 30,  2,
+   30, 30, 30, 30,  2,  2, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30,
+   30, 30, 30, 30, 30,  2, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30,
+   30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,  2, 30, 30,
+   30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+   30,  2,  2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+   30, 30, 30,  2,  2,  2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+    2,  2,  2,  2,  2,  2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+   29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,  2,  2, 29, 29,
+   29, 29, 29, 29,  2,  2, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+   28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34,  2,  2,  2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35,  0,  0,  0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,  2,
+    2,  2,  2,  2,  2,  2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+   45, 45, 45,  2, 45, 45, 45, 45, 45, 45, 45,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+   44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,  0,  0,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 43, 43, 43,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+   46, 46, 46,  2, 46, 46, 46,  2, 46, 46,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+   31, 31, 31, 31,  2,  2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+    2,  2,  2,  2,  2,  2, 32, 32,  0,  0, 32,  0, 32, 32, 32, 32,
+   32, 32, 32, 32, 32,  2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+    2,  2,  2,  2,  2,  2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,  2,
+    2,  2,  2,  2,  2,  2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32,  2,  2,  2,  2,  2, 28, 28, 28, 28, 28, 28,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+   48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+   48, 48, 48, 48, 48,  2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+   48, 48,  2,  2,  2,  2, 48,  2,  2,  2, 48, 48, 48, 48, 48, 48,
+   48, 48, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+   52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+   52, 52, 52, 52,  2,  2, 52, 52, 52, 52, 52,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+   58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+   58, 58,  2,  2,  2,  2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+    2,  2,  2,  2,  2,  2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+   58,  2,  2,  2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+   54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+   54, 54,  2,  2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+   91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+   91, 91, 91, 91, 91,  2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+   91, 91, 91,  2,  2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+    2,  2,  2,  2,  2,  2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+   91, 91, 91, 91,  2,  2,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+   62, 62,  2,  2,  2,  2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+   62, 62, 62,  2,  2,  2, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+   76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+   93, 93, 93, 93, 93, 93, 93, 93, 93, 93,  2,  2,  2,  2,  2,  2,
+    2,  2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,  2,  2,
+    2, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+    2,  2,  2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+   73, 73, 73, 73, 73, 73,  6,  6,  6,  6,  6,  6,  6,  6,  6,  2,
+    2,  2,  2,  2,  2,  2,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    8,  2,  2,  8,  8,  8, 76, 76, 76, 76, 76, 76, 76, 76,  2,  2,
+    2,  2,  2,  2,  2,  2,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,
+    1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  0,
+    0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,
+    0,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19,  9,  9,  9,  9,
+    9,  6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19,  9,  9,  9,  9,  9, 19, 19, 19, 19,  9,  9,  9,  9,
+    9, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  6, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19,  9,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    2,  1,  1,  1,  1,  1,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,
+    9,  9,  9,  9,  2,  2,  9,  9,  9,  9,  9,  9,  9,  9,  2,  9,
+    2,  9,  2,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  2,  2,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  2,  9,  9,  9,  9,
+    9,  9,  2,  9,  9,  9,  2,  2,  9,  9,  9,  2,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 19,  2,  2,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19,  2,  2,  2,  0,  0,  0,  0,  0,  0,  9,  0,  0,  0,
+   19, 19,  0,  0,  0,  0,  0,  0, 19,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 19,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0,
+    0,  0,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  2,  2,  2,  2,  2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27,  0,  0,  0,  0,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+   56, 56, 56, 56, 56,  2, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+   55, 55, 55, 55, 55, 55, 55, 55, 55, 55,  2,  2,  2,  2,  2, 55,
+   55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+   61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,  2,  2,
+    2,  2,  2,  2,  2, 61, 61,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2, 61, 30, 30, 30, 30, 30, 30, 30,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 30, 30, 30, 30, 30, 30, 30,  2, 30, 30,
+   30, 30, 30, 30, 30,  2,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    2, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  2,  2,  2,  2,  0,  0,  0,  0,  0, 13,  0, 13,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    1,  1,  1,  1, 12, 12,  0,  0,  0,  0,  0,  0,  0,  0, 13, 13,
+   13, 13,  0,  0,  0,  0,  2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  1,
+    1,  0,  0, 15, 15, 15,  0, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17,  0,  0, 17, 17, 17,  2,  2,  2,  2,  2, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12,  2,  0,  0,  0,  0,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12,  0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17,  0, 17, 17, 17, 17, 17, 17, 17, 17,  0,  0,
+    0,  0,  0,  0,  0,  0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13,  2,  2,  2, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+   39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+   39, 39, 39,  2,  2,  2, 39, 39, 39, 39, 39, 39, 39,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+   86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+   77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+   77, 77,  2,  2,  2,  2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
+   79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  0,  0,
+    0, 19, 19, 19, 19, 19,  2,  2, 19, 19, 19, 19, 19, 19, 19, 19,
+   19,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+   60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+   60, 60, 60,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    2,  2,  2,  2,  2,  2, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+   65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,  2,  2,
+    2,  2,  2,  2,  2,  2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+   75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,  2,  2,  2,  2,
+    2,  2,  2,  2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+    2,  2,  2,  2,  2,  2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+   69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+   69, 69, 69, 69,  0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+   74, 74, 74, 74, 74, 74, 74, 74, 74, 74,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2, 74, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12,  2,  2,  2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+   84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+   84, 84, 84, 84,  2,  0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+    2,  2,  2,  2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+   33, 33, 33, 33, 33,  2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+   68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+   68, 68, 68, 68,  2,  2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+    2,  2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+   92, 92, 92, 92, 92, 92, 92, 92, 92,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2, 30, 30, 30, 30, 30, 30,  2,  2, 30,
+   30, 30, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30, 30,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19,  9, 19, 19, 19, 19,
+    0,  0,  2,  2,  2,  2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87,  2,  2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+    2,  2,  2,  2,  2,  2, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 12, 12, 12, 12, 12, 12, 12,  2,  2,  2,
+    2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13, 13, 13, 13,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    2,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19, 19,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  4,  4,  4,  4,  4,  2,  2,
+    2,  2,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2, 14, 14,
+   14, 14, 14,  2, 14,  2, 14, 14,  2, 14, 14,  2, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14,  3,  3,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  0,  0,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  2,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1,  1,  1,  1,  6,  6,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,
+    0,  0,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  2,  2,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17,  0,  0,  2,  2, 12, 12, 12, 12, 12, 12,  2,  2,
+   12, 12, 12, 12, 12, 12,  2,  2, 12, 12, 12, 12, 12, 12,  2,  2,
+   12, 12, 12,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,
+    0,  0,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  0,
+    0,  0,  0,  0,  2,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+   49, 49,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+   49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,  2, 49, 49,
+   49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+   49,  2, 49, 49,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+   49, 49, 49, 49,  2,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+   49,  2,  2,  2,  2,  2,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  2,  2,  2,  9,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  1,  2,  2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+   71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+   71, 71, 71,  2,  2,  2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+   67, 67, 67, 67, 67, 67, 67,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+   42, 42, 42, 42, 42, 42, 42, 42, 42, 42,  2,  2,  2,  2,  2,  2,
+    2,  2,  2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+   41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+   41,  2,  2,  2,  2,  2,118,118,118,118,118,118,118,118,118,118,
+  118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,
+  118,  2,  2,  2,  2,  2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+   53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+   53, 53, 53, 53,  2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59,  2,  2,  2,  2, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+   40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+   51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+   50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+   50, 50, 50, 50,  2,  2, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+    2,  2,  2,  2,  2,  2,135,135,135,135,135,135,135,135,135,135,
+  135,135,135,135,135,135,135,135,135,135,  2,  2,  2,  2,135,135,
+  135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
+  135,135,  2,  2,  2,  2,106,106,106,106,106,106,106,106,106,106,
+  106,106,106,106,106,106,106,106,106,106,106,106,106,106,  2,  2,
+    2,  2,  2,  2,  2,  2,104,104,104,104,104,104,104,104,104,104,
+  104,104,104,104,104,104,104,104,104,104,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,104,110,110,110,110,110,110,110,110,110,110,
+  110,110,110,110,110,110,110,110,110,110,110,110,110,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,110,110,110,110,110,110,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,110,110,110,110,110,110,110,110,  2,  2,
+    2,  2,  2,  2,  2,  2, 47, 47, 47, 47, 47, 47,  2,  2, 47,  2,
+   47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+   47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,  2, 47, 47,  2,
+    2,  2, 47,  2,  2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+   81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,  2, 81, 81, 81,
+   81, 81, 81, 81, 81, 81,120,120,120,120,120,120,120,120,120,120,
+  120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
+  116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+  116,116,116,116,116,  2,  2,  2,  2,  2,  2,  2,  2,116,116,116,
+  116,116,116,116,116,116,128,128,128,128,128,128,128,128,128,128,
+  128,128,128,128,128,128,128,128,128,  2,128,128,  2,  2,  2,  2,
+    2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+   66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+   66, 66,  2,  2,  2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+   72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+    2,  2,  2,  2,  2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
+   98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,  2,  2,
+    2,  2, 97, 97, 97, 97,  2,  2, 97, 97, 97, 97, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97, 57, 57, 57, 57,  2, 57, 57,  2,  2,  2,
+    2,  2, 57, 57, 57, 57, 57, 57, 57, 57,  2, 57, 57, 57,  2, 57,
+   57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+   57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,  2,  2, 57, 57,
+   57,  2,  2,  2,  2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,  2,
+    2,  2,  2,  2,  2,  2, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+   88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,117,117,
+  117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
+  112,112,112,112,112,112,112,112,112,112,112,112,112,  2,  2,  2,
+    2,112,112,112,112,112,112,112,112,112,112,112,112,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+   78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,  2,  2,  2, 78,
+   78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+   83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,  2,  2, 83, 83,
+   83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+   82, 82, 82, 82, 82, 82, 82, 82, 82,  2,  2,  2,  2,  2, 82, 82,
+   82, 82, 82, 82, 82, 82,122,122,122,122,122,122,122,122,122,122,
+  122,122,122,122,122,122,122,122,  2,  2,  2,  2,  2,  2,  2,122,
+  122,122,122,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,122,
+  122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+   89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,  2,
+    2,  2,  2,  2,  2,  2,130,130,130,130,130,130,130,130,130,130,
+  130,130,130,130,130,130,130,130,130,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,130,130,130,  2,  2,  2,  2,  2,  2,  2,
+  130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144,
+  144,144,144,144,144,144,144,144,144,144,144,144,144,144,  2,  2,
+    2,  2,  2,  2,  2,  2,144,144,144,144,144,144,144,144,144,144,
+    2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  2,156,156,156,156,156,156,156,156,156,156,
+  156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
+    2,156,156,156,  2,  2,156,156,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,147,147,147,147,147,147,147,147,147,147,
+  147,147,147,147,147,147,147,147,147,147,147,147,147,147,  2,  2,
+    2,  2,  2,  2,  2,  2,148,148,148,148,148,148,148,148,148,148,
+  148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
+    2,  2,  2,  2,  2,  2,153,153,153,153,153,153,153,153,153,153,
+  153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
+  153,153,  2,  2,  2,  2,149,149,149,149,149,149,149,149,149,149,
+  149,149,149,149,149,149,149,149,149,149,149,149,149,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+   94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+   94, 94, 94, 94,  2,  2,  2,  2, 94, 94, 94, 94, 94, 94, 94, 94,
+   94, 94, 94, 94, 94, 94,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+   85, 85, 85, 85, 85, 85, 85, 85,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2, 85,  2,  2,101,101,101,101,101,101,101,101,101,101,
+  101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,  2,
+    2,  2,  2,  2,  2,  2,101,101,101,101,101,101,101,101,101,101,
+    2,  2,  2,  2,  2,  2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  2, 96, 96, 96, 96,
+   96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,  2,  2,
+    2,  2,  2,  2,  2,  2,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,100,100,100,100,100,100,100,100,100,100,
+  100,100,100,100,100,100,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,108,108,108,108,108,108,108,108,108,108,
+  108,108,108,108,108,108,108,108,  2,108,108,108,108,108,108,108,
+  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
+  108,108,108,108,108,  2,129,129,129,129,129,129,129,  2,129,  2,
+  129,129,129,129,  2,129,129,129,129,129,129,129,129,129,129,129,
+  129,129,129,129,  2,129,129,129,129,129,129,129,129,129,129,129,
+    2,  2,  2,  2,  2,  2,109,109,109,109,109,109,109,109,109,109,
+  109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
+  109,  2,  2,  2,  2,  2,109,109,109,109,109,109,109,109,109,109,
+    2,  2,  2,  2,  2,  2,107,107,107,107,  2,107,107,107,107,107,
+  107,107,107,  2,  2,107,107,  2,  2,107,107,107,107,107,107,107,
+  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,  2,
+  107,107,107,107,107,107,107,  2,107,107,  2,107,107,107,107,107,
+    2,  1,107,107,107,107,107,107,107,107,107,  2,  2,107,107,  2,
+    2,107,107,107,  2,  2,107,  2,  2,  2,  2,  2,  2,107,  2,  2,
+    2,  2,  2,107,107,107,107,107,107,107,  2,  2,107,107,107,107,
+  107,107,107,  2,  2,  2,107,107,107,107,107,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,137,137,137,137,137,137,137,137,137,137,
+  137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
+  137,137,  2,137,137,137,137,137,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,124,124,124,124,124,124,124,124,124,124,
+  124,124,124,124,124,124,124,124,124,124,124,124,124,124,  2,  2,
+    2,  2,  2,  2,  2,  2,124,124,124,124,124,124,124,124,124,124,
+    2,  2,  2,  2,  2,  2,123,123,123,123,123,123,123,123,123,123,
+  123,123,123,123,123,123,123,123,123,123,123,123,  2,  2,123,123,
+  123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,
+  123,123,123,123,  2,  2,114,114,114,114,114,114,114,114,114,114,
+  114,114,114,114,114,114,114,114,114,114,114,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,114,114,114,114,114,114,114,114,114,114,
+    2,  2,  2,  2,  2,  2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32,  2,  2,  2,102,102,102,102,102,102,102,102,102,102,
+  102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,  2,
+    2,  2,  2,  2,  2,  2,102,102,102,102,102,102,102,102,102,102,
+    2,  2,  2,  2,  2,  2,126,126,126,126,126,126,126,126,126,126,
+  126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,
+  126,  2,  2,126,126,126,126,126,126,126,126,126,126,126,126,126,
+  126,126,  2,  2,  2,  2,142,142,142,142,142,142,142,142,142,142,
+  142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
+  142,142,  2,  2,  2,  2,125,125,125,125,125,125,125,125,125,125,
+  125,125,125,125,125,125,125,125,125,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,125,154,154,154,154,154,154,154,  2,  2,154,
+    2,  2,154,154,154,154,154,154,154,154,  2,154,154,  2,154,154,
+  154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
+  154,154,154,154,154,154,154,154,154,154,154,154,  2,154,154,  2,
+    2,154,154,154,154,154,154,154,154,154,154,154,154,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,154,154,154,154,154,154,154,154,154,154,
+    2,  2,  2,  2,  2,  2,150,150,150,150,150,150,150,150,  2,  2,
+  150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,
+  150,150,150,150,150,150,150,150,150,150,150,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,141,141,141,141,141,141,141,141,141,141,
+  141,141,141,141,141,141,141,141,141,141,141,141,141,141,  2,  2,
+    2,  2,  2,  2,  2,  2,140,140,140,140,140,140,140,140,140,140,
+  140,140,140,140,140,140,140,140,140,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,121,121,121,121,121,121,121,121,121,121,
+  121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,  2,
+    2,  2,  2,  2,  2,  2,133,133,133,133,133,133,133,133,133,  2,
+  133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
+  133,133,133,133,133,133,133,133,133,133,133,133,133,  2,133,133,
+  133,133,133,133,133,133,133,133,133,133,133,133,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,133,133,133,133,133,133,133,133,133,133,
+  133,133,133,  2,  2,  2,134,134,134,134,134,134,134,134,134,134,
+  134,134,134,134,134,134,  2,  2,134,134,134,134,134,134,134,134,
+  134,134,134,134,134,134,134,134,134,134,134,134,134,134,  2,134,
+  134,134,134,134,134,134,134,134,134,134,134,134,134,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,138,138,138,138,138,138,138,  2,138,138,
+    2,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
+  138,138,138,138,138,138,138,138,138,138,138,138,138,  2,  2,  2,
+  138,  2,138,138,  2,138,138,138,138,138,138,138,138,138,  2,  2,
+    2,  2,  2,  2,  2,  2,138,138,138,138,138,138,138,138,138,138,
+    2,  2,  2,  2,  2,  2,143,143,143,143,143,143,  2,143,143,  2,
+  143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
+  143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
+  143,143,143,143,143,  2,143,143,  2,143,143,143,143,143,143,  2,
+    2,  2,  2,  2,  2,  2,143,143,143,143,143,143,143,143,143,143,
+    2,  2,  2,  2,  2,  2,145,145,145,145,145,145,145,145,145,145,
+  145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,  2,
+    2,  2,  2,  2,  2,  2, 86,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+    2,  2,  2,  2,  2,  2, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+   63, 63, 63, 63, 63,  2, 63, 63, 63, 63, 63,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 63, 63, 63, 63,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+   80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+   80, 80, 80, 80, 80,  2, 80, 80, 80, 80, 80, 80, 80, 80, 80,  2,
+    2,  2,  2,  2,  2,  2,127,127,127,127,127,127,127,127,127,127,
+  127,127,127,127,127,127,127,127,127,127,127,127,127,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 79, 79, 79, 79, 79, 79, 79, 79, 79,  2,
+    2,  2,  2,  2,  2,  2,115,115,115,115,115,115,115,115,115,115,
+  115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+  115,115,115,115,115,  2,115,115,115,115,115,115,115,115,115,115,
+    2,  2,  2,  2,115,115,103,103,103,103,103,103,103,103,103,103,
+  103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,
+  103,103,103,103,  2,  2,103,103,103,103,103,103,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,119,119,119,119,119,119,119,119,119,119,
+  119,119,119,119,119,119,119,119,119,119,119,119,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,119,119,119,119,119,119,119,119,119,119,
+    2,119,119,119,119,119,119,119,  2,119,119,119,119,119,119,119,
+  119,119,119,119,119,119,119,119,119,119,119,119,119,119,  2,  2,
+    2,  2,  2,119,119,119,146,146,146,146,146,146,146,146,146,146,
+  146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
+  146,  2,  2,  2,  2,  2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+   99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+   99,  2,  2,  2,  2, 99, 99, 99, 99, 99, 99, 99, 99, 99,  2,  2,
+    2,  2,  2,  2,  2, 99,136,139,  0,  0,155,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 13, 13,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,136,136,136,136,136,136,136,136,136,136,
+  136,136,136,136,136,136,136,136,136,136,136,136,136,136,  2,  2,
+    2,  2,  2,  2,  2,  2,155,155,155,155,155,155,155,155,155,155,
+  155,155,155,155,155,155,155,155,155,155,155,155,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,136,136,136,136,136,136,136,136,136,  2,
+    2,  2,  2,  2,  2,  2, 17, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15,  2, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 17, 17, 17, 17,  2,  2,
+    2,  2,  2,  2,  2,  2,139,139,139,139,139,139,139,139,139,139,
+  139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
+  139,139,  2,  2,  2,  2,105,105,105,105,105,105,105,105,105,105,
+  105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
+  105,  2,  2,  2,  2,  2,105,105,105,105,105,105,105,105,105,105,
+  105,105,105,  2,  2,  2,105,105,105,105,105,105,105,105,105,  2,
+    2,  2,  2,  2,  2,  2,105,105,105,105,105,105,105,105,105,105,
+    2,  2,105,105,105,105,  0,  0,  0,  0,  0,  0,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,  2,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,
+    1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,
+    2,  2,  2,  2,  2,  2,  9,  9,  9,  9,  9,  9,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  2,  0,  0,  2,  2,  0,  2,  2,  0,  0,  2,  2,  0,
+    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    2,  0,  2,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,
+    0,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,
+    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    2,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  2,  0,  2,  2,  2,
+    0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  2,  2,  0,  0,131,131,131,131,131,131,131,131,131,131,
+  131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
+  131,131,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,131,131,131,131,131,  2,131,131,131,131,131,131,131,131,131,
+  131,131,131,131,131,131, 56, 56, 56, 56, 56, 56, 56,  2, 56, 56,
+   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,  2,
+    2, 56, 56, 56, 56, 56, 56, 56,  2, 56, 56,  2, 56, 56, 56, 56,
+   56,  2,  2,  2,  2,  2,151,151,151,151,151,151,151,151,151,151,
+  151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,
+  151,151,151,  2,  2,  2,151,151,151,151,151,151,151,151,151,151,
+  151,151,151,151,  2,  2,151,151,151,151,151,151,151,151,151,151,
+    2,  2,  2,  2,151,151,152,152,152,152,152,152,152,152,152,152,
+  152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
+    2,  2,  2,  2,  2,152,113,113,113,113,113,113,113,113,113,113,
+  113,113,113,113,113,113,113,113,113,113,113,  2,  2,113,113,113,
+  113,113,113,113,113,113,113,113,113,113,113,113,113,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,132,132,132,132,132,132,132,132,132,132,
+  132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
+  132,132,  2,  2,  2,  2,132,132,132,132,132,132,132,132,132,132,
+    2,  2,  2,  2,132,132,  0,  0,  0,  0,  0,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  2,  2,  3,  3,  3,  3,  2,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  2,  3,  3,  2,  3,  2,  2,  3,  2,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,  2,  3,
+    2,  3,  2,  2,  2,  2,  2,  2,  3,  2,  2,  2,  2,  3,  2,  3,
+    2,  3,  2,  3,  3,  3,  2,  3,  3,  2,  3,  2,  2,  3,  2,  3,
+    2,  3,  2,  3,  2,  3,  2,  3,  3,  2,  3,  2,  2,  3,  3,  3,
+    3,  2,  3,  3,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,  2,  3,
+    3,  3,  3,  2,  3,  2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    2,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  2,  2,  2,  2,  2,  3,  3,  3,  2,  3,  3,  3,  3,  3,
+    2,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  2,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 15,  0,  0,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  2,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  2,  0,  0,
+    0,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 13,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+   13,  2,  2,  2,  2,  2,  2,  0,  2,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  1,  2,  3,  4,  5,  6,  0,
+    0,  0,  0,  7,  8,  9, 10, 11,  0, 12,  0,  0,  0,  0, 13,  0,
+    0, 14,  0,  0,  0,  0,  0,  0,  0,  0, 15, 16,  0, 17, 18, 19,
+    0,  0,  0, 20, 21, 22,  0, 23,  0, 24,  0, 25,  0, 26,  0,  0,
+    0,  0,  0, 27, 28,  0, 29,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 30, 31,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 32, 33,
+   34, 35, 36, 37, 38, 39, 40,  0,  0,  0, 41,  0, 42, 43, 44, 45,
+   46, 47, 48,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 49,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 50, 51, 52,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 53, 54, 55, 56, 57, 58,
+   59, 60, 61, 62,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 63,  0, 64,  0,  0,  0,  0,  0,
+    0,  0,  0, 65,  0,  0,  0,  0, 66,  0,  0,  0, 67,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 68,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 69, 70, 71,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 72, 73, 74, 75, 76, 77, 78, 79, 80,  0,
+};
+static const uint16_t
+_hb_ucd_u16[11328] =
+{
+     0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
+    13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
+    13,  13,  13,  24,  25,  11,  11,  11,  11,  26,  11,  27,  28,  29,  30,  31,
+    32,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  11,  37,  38,  13,  39,
+     9,   9,   9,  11,  11,  11,  13,  13,  40,  13,  13,  13,  41,  13,  13,  13,
+    13,  13,  13,  42,   9,  43,  11,  11,  44,  45,  32,  46,  47,  48,  49,  50,
+    51,  52,  48,  48,  53,  32,  54,  55,  48,  48,  48,  48,  48,  56,  57,  58,
+    59,  60,  48,  32,  61,  48,  48,  48,  48,  48,  62,  63,  64,  48,  65,  66,
+    48,  67,  68,  69,  48,  70,  71,  72,  72,  72,  48,  73,  74,  75,  76,  32,
+    77,  48,  48,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,
+    91,  84,  85,  92,  93,  94,  95,  96,  97,  98,  85,  99, 100, 101,  89, 102,
+   103,  84,  85, 104, 105, 106,  89, 107, 108, 109, 110, 111, 112, 113,  95, 114,
+   115, 116,  85, 117, 118, 119,  89, 120, 121, 116,  85, 122, 123, 124,  89, 125,
+   126, 116,  48, 127, 128, 129,  89, 130, 131, 132,  48, 133, 134, 135,  95, 136,
+   137,  48,  48, 138, 139, 140,  72,  72, 141,  48, 142, 143, 144, 145,  72,  72,
+   146, 147, 148, 149, 150,  48, 151, 152, 153, 154,  32, 155, 156, 157,  72,  72,
+    48,  48, 158, 159, 160, 161, 162, 163, 164, 165,   9,   9, 166,  11,  11, 167,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48, 168, 169,  48,  48, 168,  48,  48, 170, 171, 172,  48,  48,
+    48, 171,  48,  48,  48, 173, 174, 175,  48, 176,   9,   9,   9,   9,   9, 177,
+   178,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48, 179,  48, 180, 181,  48,  48,  48,  48, 182, 183,
+   184, 185,  48, 186,  48, 187, 184, 188,  48,  48,  48, 189, 190, 191, 192, 193,
+   194, 192,  48,  48, 195,  48,  48, 196, 197,  48, 198,  48,  48,  48,  48, 199,
+    48, 200, 201, 202, 203,  48, 204, 205,  48,  48, 206,  48, 207, 208, 209, 209,
+    48, 210,  48,  48,  48, 211, 212, 213, 192, 192, 214, 215, 216,  72,  72,  72,
+   217,  48,  48, 218, 219, 160, 220, 221, 222,  48, 223,  64,  48,  48, 224, 225,
+    48,  48, 226, 227, 228,  64,  48, 229, 230,   9,   9, 231, 232, 233, 234, 235,
+    11,  11, 236,  27,  27,  27, 237, 238,  11, 239,  27,  27,  32,  32,  32, 240,
+    13,  13,  13,  13,  13,  13,  13,  13,  13, 241,  13,  13,  13,  13,  13,  13,
+   242, 243, 242, 242, 243, 244, 242, 245, 246, 246, 246, 247, 248, 249, 250, 251,
+   252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 262,  72, 263, 264, 216,
+   265, 266, 267, 268, 269, 270, 271, 271, 272, 273, 274, 209, 275, 276, 209, 277,
+   278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+   279, 209, 280, 209, 209, 209, 209, 281, 209, 282, 278, 283, 209, 284, 285, 209,
+   209, 209, 286,  72, 287,  72, 270, 270, 270, 288, 209, 209, 209, 209, 289, 270,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 290, 291, 209, 209, 292,
+   209, 209, 209, 209, 209, 209, 293, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+   209, 209, 209, 209, 209, 209, 294, 295, 270, 296, 209, 209, 297, 278, 298, 278,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+   278, 278, 278, 278, 278, 278, 278, 278, 299, 300, 278, 278, 278, 301, 278, 302,
+   278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+   209, 209, 209, 278, 303, 209, 209, 304, 209, 305, 209, 209, 209, 209, 209, 209,
+     9,   9, 306,  11,  11, 307, 308, 309,  13,  13,  13,  13,  13,  13, 310, 311,
+    11,  11, 312,  48,  48,  48, 313, 314,  48, 315, 316, 316, 316, 316,  32,  32,
+   317, 318, 319, 320, 321, 322,  72,  72, 209, 323, 209, 209, 209, 209, 209, 324,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 325,  72, 326,
+   327, 328, 329, 330, 137,  48,  48,  48,  48, 331, 178,  48,  48,  48,  48, 332,
+   333,  48,  48, 137,  48,  48,  48,  48, 200, 334,  48,  48, 209, 209, 324,  48,
+   209, 335, 336, 209, 337, 338, 209, 209, 336, 209, 209, 338, 209, 209, 209, 209,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 209, 209, 209, 209,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 151,
+    48, 339,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48, 151, 209, 209, 209, 286,  48,  48, 229,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+   340,  48, 341,  72,  13,  13, 342, 343,  13, 344,  48,  48,  48,  48, 345, 346,
+    31, 347, 348, 349,  13,  13,  13, 350, 351, 352, 353, 354, 355,  72,  72, 356,
+   357,  48, 358, 359,  48,  48,  48, 360, 361,  48,  48, 362, 363, 192,  32, 364,
+    64,  48, 365,  48, 366, 367,  48, 151,  77,  48,  48, 368, 369, 370, 371, 372,
+    48,  48, 373, 374, 375, 376,  48, 377,  48,  48,  48, 378, 379, 380, 381, 382,
+   383, 384, 316,  11,  11, 385, 386,  11,  11,  11,  11,  11,  48,  48, 387, 192,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 388,  48, 389,  48,  48, 206,
+   390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
+   390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
+   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
+   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
+   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48, 204,  48,  48,  48,  48,  48,  48, 207,  72,  72,
+   392, 393, 394, 395, 396,  48,  48,  48,  48,  48,  48, 397, 398, 399,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48, 400,  72,  48,  48,  48,  48, 401,  48,  48,  74,  72,  72, 402,
+    32, 403,  32, 404, 405, 406, 407,  73,  48,  48,  48,  48,  48,  48,  48, 408,
+   409,   2,   3,   4,   5, 410, 411, 412,  48, 413,  48, 200, 414, 415, 416, 417,
+   418,  48, 172, 419, 204, 204,  72,  72,  48,  48,  48,  48,  48,  48,  48,  71,
+   420, 270, 270, 421, 271, 271, 271, 422, 423, 424, 425,  72,  72, 209, 209, 426,
+    72,  72,  72,  72,  72,  72,  72,  72,  48, 151,  48,  48,  48, 101, 427, 428,
+    48,  48, 429,  48, 430,  48,  48, 431,  48, 432,  48,  48, 433, 434,  72,  72,
+     9,   9, 435,  11,  11,  48,  48,  48,  48, 204, 192,   9,   9, 436,  11, 437,
+    48,  48,  74,  48,  48,  48, 438,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48, 315,  48, 199,  74,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   439,  48,  48, 440,  48, 441,  48, 442,  48, 200, 443,  72,  72,  72,  48, 444,
+    48, 445,  48, 446,  72,  72,  72,  72,  48,  48,  48, 447, 270, 448, 270, 270,
+   449, 450,  48, 451, 452, 453,  48, 454,  48, 455,  72,  72, 456,  48, 457, 458,
+    48,  48,  48, 459,  48, 460,  48, 461,  48, 462, 463,  72,  72,  72,  72,  72,
+    48,  48,  48,  48, 196,  72,  72,  72,   9,   9,   9, 464,  11,  11,  11, 465,
+    48,  48, 466, 192,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72, 270, 467,  48,  48, 468, 469,  72,  72,  72,  72,
+    48, 455, 470,  48,  62, 471,  72,  72,  72,  72,  72,  48, 472,  72,  48, 315,
+   473,  48,  48, 474, 475, 448, 476, 477, 222,  48,  48, 478, 479,  48, 196, 192,
+   480,  48, 481, 482, 483,  48,  48, 484, 222,  48,  48, 485, 486, 487, 488, 489,
+    48,  98, 490, 491,  72,  72,  72,  72, 492, 493, 494,  48,  48, 495, 496, 192,
+   497,  84,  85, 498, 499, 500, 501, 502,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48, 503, 504, 505, 469,  72,  48,  48,  48, 506, 507, 192,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  48,  48, 508, 509, 510, 511,  72,  72,
+    48,  48,  48, 512, 513, 192, 514,  72,  48,  48, 515, 516, 192,  72,  72,  72,
+    48, 173, 517, 518,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48, 490, 519,  72,  72,  72,  72,  72,  72,   9,   9,  11,  11, 148, 520,
+   521, 522,  48, 523, 524, 192,  72,  72,  72,  72, 525,  48,  48, 526, 527,  72,
+   528,  48,  48, 529, 530, 531,  48,  48, 532, 533, 534,  72,  48,  48,  48, 196,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    85,  48, 508, 535, 536, 148, 175, 537,  48, 538, 539, 540,  72,  72,  72,  72,
+   541,  48,  48, 542, 543, 192, 544,  48, 545, 546, 192,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  48, 547,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72, 101, 270, 548, 549, 550,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48, 207,  72,  72,  72,  72,  72,  72,
+   271, 271, 271, 271, 271, 271, 551, 552,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48, 388,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48, 200, 553,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48, 315,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48, 196,  48, 200, 370,  72,  72,  72,  72,  72,  72,  48, 204, 554,
+    48,  48,  48, 555, 556, 557, 558, 559,  48,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,   9,   9,  11,  11, 270, 560,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48, 561, 562, 563, 563, 564, 565,  72,  72,  72,  72, 566, 567,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  74,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 199,  72,  72,
+   196,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48, 200,  72,  72,  72, 568, 569,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 206,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  71, 151, 196, 570, 571,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 325,
+   209, 209, 572, 209, 209, 209, 573, 574, 575, 209, 576, 209, 209, 209, 577,  72,
+   209, 209, 209, 209, 578,  72,  72,  72,  72,  72,  72,  72,  72,  72, 270, 579,
+   209, 209, 209, 209, 209, 286, 270, 452,  72,  72,  72,  72,  72,  72,  72,  72,
+     9, 580,  11, 581, 582, 583, 242,   9, 584, 585, 586, 587, 588,   9, 580,  11,
+   589, 590,  11, 591, 592, 593, 594,   9, 595,  11,   9, 580,  11, 581, 582,  11,
+   242,   9, 584, 594,   9, 595,  11,   9, 580,  11, 596,   9, 597, 598, 599, 600,
+    11, 601,   9, 602, 603, 604, 605,  11, 606,   9, 607,  11, 608, 609, 609, 609,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+    32,  32,  32, 610,  32,  32, 611, 612, 613, 614,  45,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   615, 616, 617,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48, 151, 618, 619,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  48,  48, 620, 621,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 622, 623,  72,  72,
+     9,   9, 584,  11, 624, 370,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72, 488, 270, 270, 625, 626,  72,  72,  72,  72,
+   488, 270, 627, 628,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   629,  48, 630, 631, 632, 633, 634, 635, 636, 206, 637, 206,  72,  72,  72, 638,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   209, 209, 326, 209, 209, 209, 209, 209, 209, 324, 335, 639, 639, 639, 209, 325,
+   640, 209, 209, 209, 209, 209, 209, 209, 209, 209, 641,  72,  72,  72, 642, 209,
+   643, 209, 209, 326, 577, 644, 325,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 645,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 646, 424, 424,
+   209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 209, 209, 209, 577, 326,  72,
+   326, 209, 209, 209, 646, 176, 209, 209, 646, 209, 641, 644,  72,  72,  72,  72,
+   209, 209, 209, 209, 209, 209, 209, 647, 209, 209, 209, 209, 648, 209, 209, 209,
+   209, 209, 209, 209, 209, 324, 641, 649, 286, 209, 577, 286, 643, 286,  72,  72,
+   209, 209, 209, 209, 209, 209, 209, 209, 209, 650, 209, 209, 287,  72,  72, 192,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 204,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48, 205,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48, 204,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 469,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 101,  72,
+    48, 204,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  71,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,
+   651,  72, 652, 652, 652, 652, 652, 652,  72,  72,  72,  72,  72,  72,  72,  72,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  72,
+   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
+   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 653,
+   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
+   391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 654,
+     0,   0,   0,   0,   1,   2,   1,   2,   0,   0,   3,   3,   4,   5,   4,   5,
+     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,
+     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   6,   0,   0,   7,   0,
+     8,   8,   8,   8,   8,   8,   8,   9,  10,  11,  12,  11,  11,  11,  13,  11,
+    14,  14,  14,  14,  14,  14,  14,  14,  15,  14,  14,  14,  14,  14,  14,  14,
+    14,  14,  14,  16,  17,  18,  17,  17,  19,  20,  21,  21,  22,  21,  23,  24,
+    25,  26,  27,  27,  28,  29,  27,  30,  27,  27,  27,  27,  27,  31,  27,  27,
+    32,  33,  33,  33,  34,  27,  27,  27,  35,  35,  35,  36,  37,  37,  37,  38,
+    39,  39,  40,  41,  42,  43,  44,  45,  45,  45,  27,  46,  47,  48,  49,  27,
+    50,  50,  50,  50,  50,  51,  52,  50,  53,  54,  55,  56,  57,  58,  59,  60,
+    61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,
+    77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,
+    93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+   109, 110, 111, 111, 112, 113, 114, 111, 115, 116, 117, 118, 119, 120, 121, 122,
+   123, 124, 124, 125, 124, 126,  45,  45, 127, 128, 129, 130, 131, 132,  45,  45,
+   133, 133, 133, 133, 134, 133, 135, 136, 133, 134, 133, 137, 137, 138,  45,  45,
+   139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 140, 140, 141, 140, 140, 142,
+   143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+   144, 144, 144, 144, 145, 146, 144, 144, 145, 144, 144, 147, 148, 149, 144, 144,
+   144, 148, 144, 144, 144, 150, 144, 151, 144, 152, 153, 153, 153, 153, 153, 154,
+   155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+   155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+   155, 155, 155, 155, 155, 155, 155, 155, 156, 157, 158, 158, 158, 158, 159, 160,
+   161, 162, 163, 164, 165, 166, 167, 168, 169, 169, 169, 169, 169, 170, 171, 171,
+   172, 173, 174, 174, 174, 174, 174, 175, 174, 174, 176, 155, 155, 155, 155, 177,
+   178, 179, 180, 180, 181, 182, 183, 184, 185, 185, 186, 185, 187, 188, 169, 169,
+   189, 190, 191, 191, 191, 192, 191, 193, 194, 194, 195,   8, 196,  45,  45,  45,
+   197, 197, 197, 197, 198, 197, 197, 199, 200, 200, 200, 200, 201, 201, 201, 202,
+   203, 203, 203, 204, 205, 206, 206, 206, 207, 140, 140, 208, 209, 210, 211, 212,
+     4,   4, 213,   4,   4, 214, 215, 216,   4,   4,   4, 217,   8,   8,   8, 218,
+     4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,
+    11, 219,  11,  11, 219, 220,  11, 221,  11,  11,  11, 222, 222, 223,  11, 224,
+   225,   0,   0,   0,   0,   0, 226, 227, 228, 229,   0,   0,  45,   8,   8, 196,
+     0,   0, 230, 231, 232,   0,   4,   4, 233,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 234,  45, 235,  45,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0, 237,   0, 238,   0,   0,   0,   0,   0,   0,
+   239, 239, 240, 239, 239, 240,   4,   4, 241, 241, 241, 241, 241, 241, 241, 242,
+   140, 140, 141, 243, 243, 243, 244, 245, 144, 246, 247, 247, 247, 247,  14,  14,
+     0,   0,   0,   0,   0, 248,  45,  45, 249, 250, 249, 249, 249, 249, 249, 251,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 252,  45, 253,
+   254,   0, 255, 256, 257, 258, 258, 258, 258, 259, 260, 261, 261, 261, 261, 262,
+   263, 264, 264, 265, 143, 143, 143, 143, 266,   0, 264, 264,   0,   0, 267, 261,
+   143, 266,   0,   0,   0,   0, 143, 268,   0,   0,   0,   0,   0, 261, 261, 269,
+   261, 261, 261, 261, 261, 270,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,   0,   0,   0,   0,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 271,
+   272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272,
+   272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272,
+   272, 272, 272, 272, 272, 272, 272, 272, 273, 272, 272, 272, 274, 275, 275, 275,
+   276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+   276, 276, 277,  45,  14,  14,  14,  14,  14,  14, 278, 278, 278, 278, 278, 279,
+     0,   0, 280,   4,   4,   4,   4,   4, 281,   4,   4,   4, 282,  45,  45, 283,
+   284, 284, 285, 286, 287, 287, 287, 288, 289, 289, 289, 289, 290, 291,  50,  50,
+   292, 292, 293, 294, 294, 295, 143, 296, 297, 297, 297, 297, 298, 299, 139, 300,
+   301, 301, 301, 302, 303, 304, 139, 139, 305, 305, 305, 305, 306, 307, 308, 309,
+   310, 311, 247,   4,   4, 312, 313, 153, 153, 153, 153, 153, 308, 308, 314, 315,
+   143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+   143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+   143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+   143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 316, 143, 317, 143, 143, 318,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 319, 249, 249, 249, 249, 249, 249, 320,  45,  45,
+   321, 322,  21, 323, 324,  27,  27,  27,  27,  27,  27,  27, 325,  48,  27,  27,
+    27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,  27,
+    27,  27,  27, 326,  45,  27,  27,  27,  27, 327,  27,  27,  47,  45,  45, 328,
+     8, 286, 329,   0,   0, 330, 331,  46,  27,  27,  27,  27,  27,  27,  27, 332,
+   333,   0,   1,   2,   1,   2, 334, 260, 261, 335, 143, 266, 336, 337, 338, 339,
+   340, 341, 342, 343, 344, 344,  45,  45, 341, 341, 341, 341, 341, 341, 341, 345,
+   346,   0,   0, 347,  11,  11,  11,  11, 348, 349, 350,  45,  45,   0,   0, 351,
+    45,  45,  45,  45,  45,  45,  45,  45, 352, 353, 354, 354, 354, 355, 356, 253,
+   357, 357, 358, 359, 360, 361, 361, 362, 363, 364, 365, 365, 366, 367,  45,  45,
+   368, 368, 368, 368, 368, 369, 369, 369, 370, 371, 372, 373, 373, 374, 373, 375,
+   376, 376, 377, 378, 378, 378, 379,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380,
+   380, 380, 380, 381, 380, 382, 383,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   384, 385, 385, 386, 387, 388, 389, 389, 390, 391, 392,  45,  45,  45, 393, 394,
+   395, 396, 397, 398,  45,  45,  45,  45, 399, 399, 400, 401, 400, 402, 400, 400,
+   403, 404, 405, 406, 407, 407, 408, 408, 409, 409,  45,  45, 410, 410, 411, 412,
+   413, 413, 413, 414, 415, 416, 417, 418, 419, 420, 421,  45,  45,  45,  45,  45,
+   422, 422, 422, 422, 423,  45,  45,  45, 424, 424, 424, 425, 424, 424, 424, 426,
+   427, 427, 428, 429,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  27, 430, 431, 431, 432, 433,  45,  45,  45,  45,
+   434, 434, 435, 436, 436, 437,  45,  45,  45,  45,  45, 438, 439,  45, 440, 441,
+   442, 442, 442, 442, 443, 444, 442, 445, 446, 446, 446, 446, 447, 448, 449, 450,
+   451, 451, 451, 452, 453, 454, 454, 455, 456, 456, 456, 456, 456, 456, 457, 458,
+   459, 460, 459, 461,  45,  45,  45,  45, 462, 463, 464, 465, 465, 465, 466, 467,
+   468, 469, 470, 471, 472, 473, 474, 475,  45,  45,  45,  45,  45,  45,  45,  45,
+   476, 476, 476, 476, 476, 477, 478,  45, 479, 479, 479, 479, 480, 481,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45, 482, 482, 482, 483, 482, 484,  45,  45,
+   485, 485, 485, 485, 486, 487, 488,  45, 489, 489, 489, 490, 491,  45,  45,  45,
+   492, 493, 494, 492,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   495, 495, 495, 496,  45,  45,  45,  45,  45,  45, 497, 497, 497, 497, 497, 498,
+   499, 500, 501, 502, 503, 504,  45,  45,  45,  45, 505, 506, 506, 505, 507,  45,
+   508, 508, 508, 508, 509, 510, 510, 510, 510, 510, 511,  45, 512, 512, 512, 513,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   514, 515, 515, 516, 517, 515, 518, 519, 519, 520, 521, 522,  45,  45,  45,  45,
+   523, 524, 524, 525, 526, 527, 528, 529, 530, 531, 532,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 533, 534,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 535, 536, 536, 536, 537,
+   538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538,
+   538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538,
+   538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538,
+   538, 538, 538, 538, 538, 538, 538, 538, 538, 539,  45,  45,  45,  45,  45,  45,
+   538, 538, 538, 538, 538, 538, 540, 541, 538, 538, 538, 538, 538, 538, 538, 538,
+   538, 538, 538, 538, 542,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543,
+   543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543,
+   543, 543, 544, 545,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
+   546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
+   546, 546, 546, 546, 547,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   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, 548, 549, 550, 551,  45,  45,  45,  45,  45,  45, 552, 553, 554,
+   555, 555, 555, 555, 556, 557, 558, 559, 555,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45, 560, 560, 560, 560, 560, 561,  45,  45,  45,  45,  45,  45,
+   562, 562, 562, 562, 563, 562, 562, 562, 564, 562,  45,  45,  45,  45, 565, 566,
+   567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
+   567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
+   567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
+   567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 568,
+   567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567,
+   569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569,
+   569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 570,  45,  45,
+   571,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   572, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258,
+   258, 573,  45,  45,  45, 574, 575, 576, 576, 576, 576, 576, 576, 576, 576, 576,
+   576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 577,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   578, 578, 578, 578, 578, 578, 579, 580, 581, 582, 267,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 583,
+     0,   0, 584,   0,   0,   0, 585, 586, 587,   0, 588,   0,   0,   0, 589,  45,
+    11,  11,  11,  11, 590,  45,  45,  45,  45,  45,  45,  45,  45,  45,   0, 267,
+     0,   0,   0,   0,   0, 234,   0, 589,  45,  45,  45,  45,  45,  45,  45,  45,
+     0,   0,   0,   0,   0, 226,   0,   0,   0, 591, 592, 593, 594,   0,   0,   0,
+   595, 596,   0, 597, 598, 599,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 600,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 601,   0,   0,   0,
+   602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602,
+   602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602,
+   602, 602, 602, 602, 602, 602, 602, 602, 603, 604, 605,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   606, 607, 608,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   609, 609, 610, 611, 612,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45, 613, 613, 613, 614,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 616, 617,  45,  45,
+   618, 618, 618, 618, 619, 620,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45, 333,   0,   0,   0, 621,  45,  45,  45,  45,
+   333,   0,   0, 622,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   623,  27, 624, 625, 626, 627, 628, 629, 630, 631, 632, 631,  45,  45,  45, 325,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+     0,   0, 253,   0,   0,   0,   0,   0,   0, 267, 228, 333, 333, 333,   0, 583,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 622,  45,  45,  45, 633,   0,
+   634,   0,   0, 253, 589, 635, 583,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 636, 349, 349,
+     0,   0,   0,   0,   0,   0,   0, 267,   0,   0,   0,   0,   0, 589, 253,  45,
+   253,   0,   0,   0, 636, 286,   0,   0, 636,   0, 622, 635,  45,  45,  45,  45,
+     0,   0,   0,   0,   0,   0,   0, 637,   0,   0,   0,   0, 638,   0,   0,   0,
+     0,   0,   0,   0,   0, 267, 622, 639, 234,   0, 589, 234, 248, 234,  45,  45,
+     0,   0,   0,   0,   0,   0,   0,   0,   0, 330,   0,   0, 235,  45,  45, 286,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 319,  45,  45,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 640, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 319, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 566, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 641,  45,
+   249, 319,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+    45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
+   249, 249, 249, 249, 642,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,  45,
+   643,  45,   0,   0,   0,   0,   0,   0,  45,  45,  45,  45,  45,  45,  45,  45,
+     8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   8,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   939, 940, 941, 942, 946, 948,   0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
+     0,1033,1040,1041,1042,1043,1047,   0,   0,1080,1081,1082,1086,1110,   0,   0,
+  1124,1125,1126,1127,1131,1133,   0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
+     0,1219,1226,1227,1228,1229,1233,   0,   0,1267,1268,1269,1273,1298,   0,1303,
+   943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
+     0,   0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
+   991,1176, 993,1178, 994,1179,   0,   0,1004,1190,1005,1191,1006,1192,1014,1199,
+  1007,   0,   0,   0,1016,1201,1020,1206,   0,1022,1208,1025,1211,1023,1209,   0,
+     0,   0,   0,1032,1218,1037,1223,1035,1221,   0,   0,   0,1044,1230,1045,1231,
+  1049,1235,   0,   0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
+  1069,1255,1077,1264,1074,1261,   0,   0,1083,1270,1084,1271,1085,1272,1088,1275,
+  1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1053,1239,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1093,
+  1280,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 949,1134,1010,
+  1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366,   0,1320,1347,
+  1418,1419,1323,1350,   0,   0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
+  1202,   0,   0,   0, 987,1172,   0,   0,1031,1217,1321,1348,1322,1349,1338,1365,
+   950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
+  1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263,   0,   0, 997,1182,
+     0,   0,   0,   0,   0,   0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
+  1422,1423,1113,1301,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     8,   9,   0,  10,1425,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,
+     0,   0,   0,   0,   0,1314,1427,   5,1434,1438,1443,   0,1450,   0,1455,1461,
+  1514,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1446,1458,1468,1476,1480,1486,
+  1517,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1489,1503,1494,1500,1508,   0,
+     0,   0,   0,1520,1521,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1526,1528,   0,1525,   0,   0,   0,1522,   0,   0,   0,   0,1536,1532,1539,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1534,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1556,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1548,1550,   0,1547,   0,   0,   0,1567,   0,   0,   0,   0,1558,1554,1561,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1568,1569,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1529,1551,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1523,1545,1524,1546,   0,   0,1527,1549,   0,   0,1570,1571,1530,1552,1531,1553,
+     0,   0,1533,1555,1535,1557,1537,1559,   0,   0,1572,1573,1544,1566,1538,1560,
+  1540,1562,1541,1563,1542,1564,   0,   0,1543,1565,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1606,1607,1609,1608,1610,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1613,   0,1611,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1612,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1620,   0,   0,   0,   0,   0,   0,
+     0,1623,   0,   0,1624,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1614,1615,1616,1617,1618,1619,1621,1622,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1628,1629,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1625,1626,   0,1627,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1634,   0,   0,1635,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1630,1631,1632,   0,   0,1633,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1639,   0,   0,1638,1640,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1636,1637,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1641,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1642,1644,1643,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1645,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1646,   0,   0,   0,   0,   0,   0,1648,1649,   0,1647,1650,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1651,1653,1652,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1654,   0,1655,1657,1656,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1659,   0,   0,   0,   0,   0,   0,   0,   0,   0,1660,   0,   0,
+     0,   0,1661,   0,   0,   0,   0,1662,   0,   0,   0,   0,1663,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1658,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1664,   0,1665,1673,   0,1674,   0,   0,   0,   0,   0,   0,   0,
+     0,1666,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1668,   0,   0,   0,   0,   0,   0,   0,   0,   0,1669,   0,   0,
+     0,   0,1670,   0,   0,   0,   0,1671,   0,   0,   0,   0,1672,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1667,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1675,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1676,   0,1677,   0,1678,   0,1679,   0,1680,   0,
+     0,   0,1681,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1682,   0,1683,   0,   0,
+  1684,1685,   0,1686,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
+   966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
+   989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
+  1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
+  1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
+  1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
+  1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
+  1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
+  1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
+  1119,1308,1122,1311,1123,1312,1186,1260,1293,1305,   0,1394,   0,   0,   0,   0,
+   952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
+  1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
+  1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
+  1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
+  1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
+  1409,1414,1109,1297,1117,1306,1116,1304,1112,1300,   0,   0,   0,   0,   0,   0,
+  1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
+  1477,1478,1729,1731,1730,1732,   0,   0,1435,1436,1733,1735,1734,1736,   0,   0,
+  1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
+  1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
+  1495,1496,1777,1779,1778,1780,   0,   0,1451,1452,1781,1783,1782,1784,   0,   0,
+  1504,1505,1785,1788,1786,1789,1787,1790,   0,1459,   0,1791,   0,1792,   0,1793,
+  1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
+  1467,  21,1475,  22,1479,  23,1485,  24,1493,  27,1499,  28,1507,  29,   0,   0,
+  1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
+  1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
+  1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
+  1470,1469,1822,1474,1465,   0,1473,1825,1429,1428,1426,  12,1432,   0,  26,   0,
+     0,1315,1823,1484,1466,   0,1483,1829,1433,  13,1437,  14,1441,1826,1827,1828,
+  1488,1487,1513,  19,   0,   0,1492,1515,1445,1444,1442,  15,   0,1831,1832,1833,
+  1502,1501,1516,  25,1497,1498,1506,1518,1457,1456,1454,  17,1453,1313,  11,   3,
+     0,   0,1824,1512,1519,   0,1511,1830,1449,  16,1460,  18,1464,   4,   0,   0,
+    30,  31,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,  20,   0,   0,   0,   2,   6,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1834,1835,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1836,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1837,1839,1838,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1840,   0,   0,   0,   0,1841,   0,   0,1842,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1843,   0,1844,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1845,   0,   0,1846,   0,   0,1847,   0,1848,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   937,   0,1850,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1849, 936, 938,
+  1851,1852,   0,   0,1853,1854,   0,   0,1855,1856,   0,   0,   0,   0,   0,   0,
+  1857,1858,   0,   0,1861,1862,   0,   0,1863,1864,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1867,1868,1869,1870,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1859,1860,1865,1866,   0,   0,   0,   0,   0,   0,1871,1872,1873,1874,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,  32,  33,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1875,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1877,   0,1878,   0,
+  1879,   0,1880,   0,1881,   0,1882,   0,1883,   0,1884,   0,1885,   0,1886,   0,
+  1887,   0,1888,   0,   0,1889,   0,1890,   0,1891,   0,   0,   0,   0,   0,   0,
+  1892,1893,   0,1894,1895,   0,1896,1897,   0,1898,1899,   0,1900,1901,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1876,   0,   0,   0,   0,   0,   0,   0,   0,   0,1902,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1904,   0,1905,   0,
+  1906,   0,1907,   0,1908,   0,1909,   0,1910,   0,1911,   0,1912,   0,1913,   0,
+  1914,   0,1915,   0,   0,1916,   0,1917,   0,1918,   0,   0,   0,   0,   0,   0,
+  1919,1920,   0,1921,1922,   0,1923,1924,   0,1925,1926,   0,1927,1928,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1903,   0,   0,1929,1930,1931,1932,   0,   0,   0,1933,   0,
+   710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
+   663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
+   810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
+   368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
+   811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
+   594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
+   313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
+   424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
+   193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
+   337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
+   683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
+   608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
+   479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
+   791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
+   377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
+   659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
+   153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210,   0,   0,
+   227,   0, 379,   0,   0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604,   0,
+   661,   0, 703,   0,   0, 735, 743,   0,   0,   0, 793, 794, 795, 808, 741, 773,
+   118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
+   335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
+   549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
+   690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623,   0,   0,
+   102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
+   250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
+   370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
+   493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
+   591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
+   709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
+   847, 857,  55,  65,  66, 883, 892, 916, 822, 824,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1586,   0,1605,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1602,1603,1934,1935,1574,1575,
+  1576,1577,1579,1580,1581,1583,1584,   0,1585,1587,1588,1589,1591,   0,1592,   0,
+  1593,1594,   0,1595,1596,   0,1598,1599,1600,1601,1604,1582,1578,1590,1597,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1936,   0,1937,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1938,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1939,1940,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1941,1942,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1944,1943,   0,1945,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1946,1947,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1948,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1949,1950,
+  1951,1952,1953,1954,1955,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1956,1957,1958,1960,1959,
+  1961,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125,  34, 830, 130, 131,
+   132, 137, 827,  35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152,  37,
+   157, 158, 159, 160,  38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
+   181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
+   197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
+   153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
+   836, 837, 247, 248, 249, 246, 251,  39,  40, 253, 255, 255, 838, 257, 258, 259,
+   261, 839, 262, 263, 301, 264,  41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
+   278, 281, 282,  42, 283, 284, 285, 286,  43, 843,  44, 289, 290, 291, 293, 934,
+   298, 845, 845, 621, 300, 300,  45, 852, 894, 302, 304,  46, 306, 309, 310, 312,
+   316,  48,  47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
+   335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
+   358, 356,  49, 363, 365, 367, 364,  50, 369, 371, 851, 376, 386, 378,  53, 381,
+    52,  51, 140, 141, 387, 382, 614,  78, 388, 389, 390, 394, 392, 856,  54, 399,
+   396, 402, 404, 858, 405, 401, 407,  55, 408, 409, 410, 413, 859, 415,  56, 417,
+   860, 418,  57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
+   437, 441, 438, 439, 442, 443, 864, 436, 449, 450,  58, 454, 453, 865, 447, 460,
+   866, 867, 461, 466, 465, 464,  59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
+   483, 485, 486, 871, 488, 489, 872, 873, 495, 497,  60, 498,  61,  61, 504, 505,
+   507, 508, 511,  62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878,  63,  64,
+   528, 880, 879, 881, 882, 530, 531, 531, 533,  66, 534,  67,  68, 884, 536, 538,
+   541,  69, 885, 549, 886, 887, 556, 559,  70, 561, 562, 563, 888, 889, 889, 567,
+    71, 890, 570, 571,  72, 891, 577,  73, 581, 579, 582, 893, 587,  74, 590, 592,
+   596,  75, 895, 896,  76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
+   853,  77, 615, 616,  79, 617, 252, 902, 903, 854, 855, 621, 622, 731,  80, 627,
+   626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
+   638, 643, 644, 645, 905, 907, 906,  81, 653, 654, 656, 911, 657, 908,  82,  83,
+   909, 910,  84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675,  85,
+   677, 678,  86, 681, 682, 912, 685, 686,  87, 689,  36, 913, 914,  88,  89, 696,
+   702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
+   918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762,  90,
+   764, 922,  91, 775, 279, 780, 923, 925,  92,  93, 785, 926,  94, 927, 787, 787,
+   789, 928, 792,  95, 796, 797, 798, 800,  96, 929, 802, 804, 806,  97,  98, 807,
+   930,  99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+static const int16_t
+_hb_ucd_i16[196] =
+{
+      0,    0,    0,    0,    1,   -1,    0,    0,    2,    0,   -2,    0,    0,    0,    0,    2,
+      0,   -2,    0,    0,    0,    0,    0,   16,    0,    0,    0,  -16,    0,    0,    1,   -1,
+      0,    0,    0,    1,   -1,    0,    0,    0,    0,    1,   -1,    0,    3,    3,    3,   -3,
+     -3,   -3,    0,    0,    0, 2016,    0,    0,    0,    0,    0, 2527, 1923, 1914, 1918,    0,
+   2250,    0,    0,    0,    0,    0,    0,  138,    0,    7,    0,    0,   -7,    0,    0,    0,
+      1,   -1,    1,   -1,   -1,    1,   -1,    0, 1824,    0,    0,    0,    0,    0, 2104,    0,
+   2108, 2106,    0, 2106, 1316,    0,    0,    0,    0,    1,   -1,    1,   -1, -138,    0,    0,
+      1,   -1,    8,    8,    8,    0,    7,    7,    0,    0,   -8,   -8,   -8,   -7,   -7,    0,
+      1,   -1,    0,    2,-1316,    1,   -1,    0,   -1,    1,   -1,    1,   -1,    3,    1,   -1,
+     -3,    1,   -1,    1,   -1,    0,    0,-1914,-1918,    0,    0,-1923,-1824,    0,    0,    0,
+      0,-2016,    0,    0,    1,   -1,    0,    1,    0,    0,-2104,    0,    0,    0,    0,-2106,
+  -2108,-2106,    0,    0,    1,   -1,-2250,    0,    0,    0,-2527,    0,    0,   -2,    0,    1,
+     -1,    0,    1,   -1,
+};
+
+static inline uint_fast8_t
+_hb_ucd_gc (unsigned u)
+{
+  return u<1114110u?_hb_ucd_u8[2176+(((_hb_ucd_u16[((_hb_ucd_u8[u>>4>>5])<<5)+((u>>4)&31u)])<<4)+((u)&15u))]:2;
+}
+static inline uint_fast8_t
+_hb_ucd_ccc (unsigned u)
+{
+  return u<125259u?_hb_ucd_u8[15060+(((_hb_ucd_u8[13636+(((_hb_ucd_u8[12656+(u>>3>>4)])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:0;
+}
+static inline unsigned
+_hb_ucd_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline int_fast16_t
+_hb_ucd_bmg (unsigned u)
+{
+  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[16372+(((_hb_ucd_b4(16244+_hb_ucd_u8,u>>2>>6))<<6)+((u>>2)&63u))])<<2)+((u)&3u)]:0;
+}
+static inline uint_fast8_t
+_hb_ucd_sc (unsigned u)
+{
+  return u<918000u?_hb_ucd_u8[19126+(((_hb_ucd_u16[3040+(((_hb_ucd_u8[17332+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:2;
+}
+static inline uint_fast16_t
+_hb_ucd_dm (unsigned u)
+{
+  return u<195102u?_hb_ucd_u16[6144+(((_hb_ucd_u8[29430+(u>>6)])<<6)+((u)&63u))]:0;
+}
+
+
+#elif !defined(HB_NO_UCD_UNASSIGNED)
+
+static const uint8_t
+_hb_ucd_u8[17508] =
+{
+    0,  1,  2,  3,  4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  9, 10, 11,  7,  7,  7,  7, 12, 13, 14, 14, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 21, 23, 21, 21, 21, 21, 24,  7,  7,
+   25, 26, 21, 21, 21, 21, 27, 28, 21, 21, 29, 30, 31, 32, 33, 34,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7, 35,  7, 36, 37,  7, 38,  7,  7,  7, 39, 21, 40,
+    7,  7, 41, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   42, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 43,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 44,
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+   32, 33, 34, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43,
+   44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+   60, 61, 62, 63, 64, 64, 65, 66, 67, 68, 69, 70, 71, 69, 72, 73,
+   69, 69, 64, 74, 64, 64, 75, 76, 77, 78, 79, 80, 81, 82, 69, 83,
+   84, 85, 86, 87, 88, 89, 69, 69, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91,
+   92, 34, 34, 34, 34, 34, 34, 34, 34, 93, 34, 34, 94, 95, 96, 97,
+   98, 99,100,101,102,103,104,105, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,106,
+  107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
+  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
+  108,108, 34, 34,109,110,111,112, 34, 34,113,114,115,116,117,118,
+  119,120,121,122,123,124,125,126,127,128,129,123, 34, 34,130,123,
+  131,132,133,134,135,136,137,138,139,140,141,123,142,143,144,145,
+  146,147,148,149,150,151,152,123,153,154,123,155,156,157,158,123,
+  159,160,161,162,163,164,123,123,165,166,167,168,123,169,123,170,
+   34, 34, 34, 34, 34, 34, 34,171,172, 34,173,123,123,123,123,123,
+  123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,
+   34, 34, 34, 34, 34, 34, 34, 34,174,123,123,123,123,123,123,123,
+  123,123,123,123,123,123,123,123, 34, 34, 34, 34,175,123,123,123,
+   34, 34, 34, 34,176,177,178,179,123,123,123,123,180,181,182,183,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,184,
+   34, 34, 34, 34, 34, 34, 34, 34, 34,185,186,123,123,123,123,123,
+   34, 34,187, 34, 34,188,123,123,123,123,123,123,123,123,123,123,
+  123,123,123,123,123,123,123,123,189,190,123,123,123,123,123,123,
+   69,191,192,193,194,195,196,123,197,198,199,200,201,202,203,204,
+   69, 69, 69, 69,205,206,123,123,123,123,123,123,123,123,123,123,
+  207,123,208,123,123,209,123,123,123,123,123,123,123,123,123,123,
+   34,210,211,123,123,123,123,123,212,213,214,123,215,216,123,123,
+  217,218,219,220,221,123, 69,222, 69, 69, 69, 69, 69,223,224,225,
+  226,227,228,229,230,231, 69,232,123,123,123,123,123,123,123,123,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,233, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,234, 34,
+  235, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,236, 34, 34,
+   34, 34, 34, 34, 34, 34, 34,237,123,123,123,123,123,123,123,123,
+   34, 34, 34, 34,238,123,123,123,123,123,123,123,123,123,123,123,
+   34, 34, 34, 34, 34, 34,239,123,123,123,123,123,123,123,123,123,
+  240,123,241,242,123,123,123,123,123,123,123,123,123,123,123,123,
+  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,243,
+  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,244,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  2,  4,  5,  6,  2,
+    7,  7,  7,  7,  7,  2,  8,  9, 10, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 17, 18, 19,  1, 20, 20, 21, 22, 23, 24, 25,
+   26, 27, 15,  2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32,
+   32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11,
+   11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11,
+   34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34,
+   34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32,
+   32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32,
+   16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40,
+   40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41,
+   40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41,
+   43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 44, 45, 16, 10,
+   44, 44, 41, 46, 11, 47, 47, 11, 34, 11, 11, 11, 11, 11, 11, 11,
+   11, 48, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34,
+   16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 49, 34, 32, 34, 11,
+   32, 50, 43, 43, 51, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+   48, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 47, 52,  2,  2,  2,
+   16, 16, 16, 16, 53, 54, 55, 56, 57, 43, 43, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 43, 43, 43, 58, 59, 60, 43, 59, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 62,
+   36, 63, 64, 44, 44, 44, 44, 44, 65, 65, 65,  8,  9, 66,  2, 67,
+   43, 43, 43, 43, 43, 60, 68,  2, 69, 36, 36, 36, 36, 70, 43, 43,
+    7,  7,  7,  7,  7,  2,  2, 36, 71, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 72, 43, 43, 43, 73, 50, 43, 43, 74, 75, 76, 43, 43, 36,
+    7,  7,  7,  7,  7, 36, 77, 78,  2,  2,  2,  2,  2,  2,  2, 79,
+   70, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 80, 62, 36,
+   36, 36, 36, 43, 43, 43, 43, 43, 71, 44, 44, 44, 44, 44, 44, 44,
+    7,  7,  7,  7,  7, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43,
+   43, 43, 40, 21,  2, 81, 57, 20, 36, 36, 36, 43, 43, 75, 43, 43,
+   43, 43, 75, 43, 75, 43, 43, 44,  2,  2,  2,  2,  2,  2,  2, 64,
+   36, 36, 36, 36, 70, 43, 44, 64, 36, 36, 36, 36, 36, 61, 44, 44,
+   44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 44, 44, 44, 44, 44, 57, 43, 43, 43, 43, 43, 43,
+   43, 82, 43, 43, 43, 43, 43, 43, 43, 83, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 83, 71, 84, 85, 43, 43, 43, 83, 84, 85, 84,
+   70, 43, 43, 43, 36, 36, 36, 36, 36, 43,  2,  7,  7,  7,  7,  7,
+   86, 36, 36, 36, 36, 36, 36, 36, 70, 84, 62, 36, 36, 36, 61, 62,
+   61, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36,
+   61, 61, 44, 36, 36, 44, 71, 84, 85, 43, 80, 87, 88, 87, 85, 61,
+   44, 44, 44, 87, 44, 44, 36, 62, 36, 43, 44,  7,  7,  7,  7,  7,
+   36, 20, 27, 27, 27, 56, 63, 80, 57, 83, 62, 36, 36, 61, 44, 62,
+   61, 36, 62, 61, 36, 44, 80, 84, 85, 80, 44, 57, 80, 57, 43, 44,
+   57, 44, 44, 44, 62, 36, 61, 61, 44, 44, 44,  7,  7,  7,  7,  7,
+   43, 36, 70, 64, 44, 44, 44, 44, 57, 83, 62, 36, 36, 36, 36, 62,
+   36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62, 36, 36, 44, 71, 84,
+   85, 43, 43, 57, 83, 87, 85, 44, 61, 44, 44, 44, 44, 44, 44, 44,
+   66, 44, 44, 44, 62, 43, 43, 43, 57, 84, 62, 36, 36, 36, 61, 62,
+   61, 36, 62, 36, 36, 44, 71, 85, 85, 43, 80, 87, 88, 87, 85, 44,
+   44, 44, 57, 83, 44, 44, 36, 62, 78, 27, 27, 27, 44, 44, 44, 44,
+   44, 71, 62, 36, 36, 61, 44, 36, 61, 36, 36, 44, 62, 61, 61, 36,
+   44, 62, 61, 44, 36, 61, 44, 36, 36, 36, 36, 36, 36, 44, 44, 84,
+   83, 88, 44, 84, 88, 84, 85, 44, 61, 44, 44, 87, 44, 44, 44, 44,
+   27, 89, 67, 67, 56, 90, 44, 44, 83, 84, 71, 36, 36, 36, 61, 36,
+   61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 62, 43,
+   83, 84, 88, 43, 80, 43, 43, 44, 44, 44, 57, 80, 36, 61, 44, 44,
+   44, 44, 44, 91, 27, 27, 27, 89, 70, 84, 72, 36, 36, 36, 61, 36,
+   36, 36, 62, 36, 36, 44, 71, 85, 84, 84, 88, 83, 88, 84, 43, 44,
+   44, 44, 87, 88, 44, 44, 44, 61, 62, 61, 44, 44, 44, 44, 44, 44,
+   43, 84, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 70, 71, 84,
+   85, 43, 80, 84, 88, 84, 85, 77, 44, 44, 36, 92, 27, 27, 27, 93,
+   27, 27, 27, 27, 89, 36, 36, 36, 57, 84, 62, 36, 36, 36, 36, 36,
+   36, 36, 36, 61, 44, 36, 36, 36, 36, 62, 36, 36, 36, 36, 62, 44,
+   36, 36, 36, 61, 44, 80, 44, 87, 84, 43, 80, 80, 84, 84, 84, 84,
+   44, 84, 64, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36, 36,
+   70, 36, 43, 43, 43, 80, 44, 94, 36, 36, 36, 75, 43, 43, 43, 60,
+    7,  7,  7,  7,  7,  2, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36,
+   36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44,
+   36, 36, 61, 81, 43, 43, 43, 44,  7,  7,  7,  7,  7, 44, 36, 36,
+   77, 67,  2,  2,  2,  2,  2,  2,  2, 95, 95, 67, 43, 67, 67, 67,
+    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 50, 50, 50,  4,  4, 84,
+   36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
+   57, 43, 43, 43, 43, 43, 43, 83, 43, 43, 60, 43, 36, 36, 70, 43,
+   43, 43, 43, 43, 57, 43, 43, 43, 43, 43, 43, 43, 43, 43, 80, 67,
+   67, 67, 67, 76, 67, 67, 90, 67,  2,  2, 95, 67, 21, 64, 44, 44,
+   36, 36, 36, 36, 36, 92, 85, 43, 83, 43, 43, 43, 85, 83, 85, 71,
+    7,  7,  7,  7,  7,  2,  2,  2, 36, 36, 36, 84, 43, 36, 36, 43,
+   71, 84, 96, 92, 84, 84, 84, 36, 70, 43, 71, 36, 36, 36, 36, 36,
+   36, 83, 85, 83, 84, 84, 85, 92,  7,  7,  7,  7,  7, 84, 85, 67,
+   11, 11, 11, 48, 44, 44, 48, 44, 16, 16, 16, 16, 16, 53, 45, 16,
+   36, 36, 36, 36, 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44,
+   61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, 36, 36, 36, 36,
+   36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 57, 43,
+    2,  2,  2,  2, 97, 27, 27, 27, 27, 27, 27, 27, 27, 27, 98, 44,
+   67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44,
+   99, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72,
+  100, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,101,102, 44,
+   36, 36, 36, 36, 36, 63,  2,103,104, 36, 36, 36, 61, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 61, 36, 36, 43, 80, 44, 44, 44, 44, 44,
+   36, 43, 60, 64, 44, 44, 44, 44, 36, 43, 44, 44, 44, 44, 44, 44,
+   61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 85, 43, 43, 43, 84,
+   84, 84, 84, 83, 85, 43, 43, 43, 43, 43,  2, 86,  2, 66, 70, 44,
+    7,  7,  7,  7,  7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44,
+    2,  2,  2,105,  2, 59, 43, 68, 36,106, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 61, 44, 44, 44, 36, 36, 70, 71, 36, 36, 36, 36,
+   36, 36, 36, 36, 70, 61, 44, 44, 36, 36, 36, 44, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 61, 43, 83, 84, 85, 83, 84, 44, 44,
+   84, 83, 84, 84, 85, 43, 44, 44, 90, 44,  2,  7,  7,  7,  7,  7,
+   36, 36, 36, 36, 36, 36, 36, 44, 36, 36, 61, 44, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 44, 44, 36, 36, 36, 36, 36, 44, 44, 44,
+    7,  7,  7,  7,  7, 98, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+   36, 36, 36, 70, 83, 85, 44,  2, 36, 36, 92, 83, 43, 43, 43, 80,
+   83, 83, 85, 43, 43, 43, 83, 84, 84, 85, 43, 43, 43, 43, 80, 57,
+    2,  2,  2, 86,  2,  2,  2, 44, 43, 43, 43, 43, 43, 43, 43,107,
+   80, 44, 44, 44, 44, 44, 44, 44, 43, 43, 96, 36, 36, 36, 36, 36,
+   36, 36, 83, 43, 43, 83, 83, 84, 84, 83, 96, 36, 36, 36, 44, 44,
+   95, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 90, 44,
+   43, 96, 36, 36, 36, 36, 36, 36, 92, 43, 43, 84, 43, 85, 43, 36,
+   36, 36, 36, 83, 43, 84, 85, 85, 43, 84, 44, 44, 44, 44,  2,  2,
+   36, 36, 84, 84, 84, 84, 43, 43, 43, 43, 84, 43, 44, 91,  2,  2,
+    7,  7,  7,  7,  7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40,  2,
+   16, 16, 16, 16,108, 44, 44, 44, 11, 11, 11, 11, 11, 47, 48, 11,
+    2,  2,  2,  2, 44, 44, 44, 44, 43, 60, 43, 43, 43, 43, 43, 43,
+   83, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 92, 43, 61, 44, 44,
+   16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 45, 16, 16,
+   16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16,109, 40, 40,
+   43, 43, 43, 43, 43, 57, 43, 43, 32, 32, 32, 16, 16, 16, 16, 32,
+   16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 44, 11, 11, 11, 44,
+   16, 16, 16, 16, 48, 48, 48, 48, 16, 16, 16, 16, 16, 16, 16, 44,
+   16, 16, 16, 16,110,110,110,110, 16, 16,108, 16, 11, 11,111,112,
+   41, 16,108, 16, 11, 11,111, 41, 16, 16, 44, 16, 11, 11,113, 41,
+   16, 16, 16, 16, 11, 11,114, 41, 44, 16,108, 16, 11, 11,111,115,
+  116,116,116,116,116,117, 65, 65,118,118,118,  2,119,120,119,120,
+    2,  2,  2,  2,121, 65, 65,122,  2,  2,  2,  2,123,124,  2,125,
+  126,  2,127,128,  2,  2,  2,  2,  2,  9,126,  2,  2,  2,  2,129,
+   65, 65, 68, 65, 65, 65, 65, 65,130, 44, 27, 27, 27,  8,127,131,
+   27, 27, 27, 27, 27,  8,127,102, 40, 40, 40, 40, 40, 40, 81, 44,
+   20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,132, 51,
+  107, 51,107, 43, 43, 43, 43, 43, 67,133, 67,134, 67, 34, 11, 16,
+   11, 32,134, 67, 49, 11, 11, 67, 67, 67,133,133,133, 11, 11,135,
+   11, 11, 35, 36, 39, 67, 16, 11,  8,  8, 49, 16, 16, 26, 67,136,
+   27, 27, 27, 27, 27, 27, 27, 27,103,103,103,103,103,103,103,103,
+  103,137,138,103,139, 67, 44, 44,  8,  8,140, 67, 67,  8, 67, 67,
+  140, 26, 67,140, 67, 67, 67,140, 67, 67, 67, 67, 67, 67, 67,  8,
+   67,140,140, 67, 67, 67, 67, 67, 67, 67,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8, 67, 67, 67, 67,  4,  4, 67, 67,
+    8, 67, 67, 67,141,142, 67, 67, 67, 67, 67, 67, 67, 67,140, 67,
+   67, 67, 67, 67, 67, 26,  8,  8,  8,  8, 67, 67, 67, 67, 67, 67,
+   67, 67, 67, 67, 67, 67,  8,  8,  8, 67, 67, 67, 67, 67, 67, 67,
+   67, 67, 67, 90, 44, 44, 44, 44, 67, 67, 67, 67, 67, 90, 44, 44,
+   27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27,
+   67, 67, 67, 26, 67, 67, 67, 67, 26, 67, 67, 67, 67, 67, 67, 67,
+   67, 67, 67, 67,  8,  8,  8,  8, 67, 67, 67, 67, 67, 67, 67, 26,
+   67, 67, 67, 67,  4,  4,  4,  4,  4,  4,  4, 27, 27, 27, 27, 27,
+   27, 27, 67, 67, 67, 67, 67, 67,  8,  8,127,143,  8,  8,  8,  8,
+    8,  8,  8,  4,  4,  4,  4,  4,  8,127,144,144,144,144,144,144,
+  144,144,144,144,143,  8,  8,  8,  8,  8,  8,  8,  4,  4,  8,  8,
+    8,  8,  8,  8,  8,  8,  4,  8,  8,  8,140, 26,  8,  8,140, 67,
+   67, 67, 44, 67, 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 67,
+   11, 11, 11, 11, 11, 11, 11, 47, 16, 16, 16, 16, 16, 16, 16,108,
+   32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11,
+   32, 32,136, 67, 67,134, 34,145, 43, 32, 44, 44, 91,  2, 97,  2,
+   16, 16, 16,146, 44, 44,146, 44, 36, 36, 36, 36, 44, 44, 44, 52,
+   64, 44, 44, 44, 44, 44, 44, 57, 36, 36, 36, 61, 44, 44, 44, 44,
+   36, 36, 36, 61, 36, 36, 36, 61,  2,119,119,  2,123,124,119,  2,
+    2,  2,  2,  6,  2,105,119,  2,119,  4,  4,  4,  4,  2,  2, 86,
+    2,  2,  2,  2,  2,118,  2,  2,105,147,  2,  2,  2,  2,  2,  2,
+   67, 64, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 55, 67, 67,
+   67, 67, 44, 44, 44, 44, 44, 44, 67, 67, 67, 44, 44, 44, 44, 44,
+   67, 67, 67, 67, 67, 67, 44, 44,  1,  2,148,149,  4,  4,  4,  4,
+    4, 67,  4,  4,  4,  4,150,151,152,103,103,103,103, 43, 43, 84,
+  153, 40, 40, 67,103,154, 63, 67, 36, 36, 36, 61, 57,155,156, 69,
+   36, 36, 36, 36, 36, 63, 40, 69, 44, 44, 62, 36, 36, 36, 36, 36,
+   67, 27, 27, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90,
+   27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27,
+  157, 27, 27, 27, 27, 27, 27, 27, 36, 36,106, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36,158,  2,  7,  7,  7,  7,  7, 36, 44, 44,
+   32, 32, 32, 32, 32, 32, 32, 70, 51,159, 43, 43, 43, 43, 43, 86,
+   32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36,103,103,103,103,103,
+   43,  2,  2,  2, 44, 44, 44, 44, 41, 41, 41,156, 40, 40, 40, 40,
+   41, 32, 32, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32,
+   45, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,160, 34, 35,
+   32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32,
+   11, 11, 32, 32, 32, 32, 32, 32, 44, 32, 11, 11, 34,108, 44, 44,
+   44, 44, 48, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36,
+   36, 92, 85, 83, 67, 67, 80, 44, 27, 27, 27, 67,161, 44, 44, 44,
+   36, 36,  2,  2, 44, 44, 44, 44, 84, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 84, 84, 84, 84, 84, 84, 84, 84, 43, 44, 44, 44, 44,  2,
+   43, 36, 36, 36,  2, 72, 72, 70, 36, 36, 36, 43, 43, 43, 43,  2,
+   36, 36, 36, 70, 43, 43, 43, 43, 43, 84, 44, 44, 44, 44, 44, 91,
+   36, 70, 84, 43, 43, 84, 43, 84,162,  2,  2,  2,  2,  2,  2, 52,
+    7,  7,  7,  7,  7, 44, 44,  2, 36, 36, 70, 69, 36, 36, 36, 36,
+    7,  7,  7,  7,  7, 36, 36, 61, 36, 36, 36, 36, 70, 43, 43, 83,
+   85, 83, 85, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 83, 44,
+    7,  7,  7,  7,  7, 44,  2,  2, 69, 36, 36, 77, 67, 92, 83, 36,
+   71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44,
+   44, 44, 44, 44, 44, 62,106,  2, 36, 36, 36, 36, 36, 92, 43, 84,
+    2,106,163, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61,
+   62, 36, 36, 61, 44, 44, 44, 44, 16, 16, 16, 16, 16,112, 40, 40,
+   16, 16, 16, 16,109, 41, 44, 44, 36, 92, 85, 84, 83,162, 85, 44,
+   36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36,
+  164,164,164,164,164,164,164,164,165,165,165,165,165,165,165,165,
+   16, 16, 16,108, 44, 44, 44, 44, 44,146, 16, 16, 44, 44, 62, 71,
+   36, 36, 36, 36,166, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61,
+   36, 62, 61, 36, 36, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41,
+   41, 44, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36,144, 44, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36,161, 44,  2,  2,  2,167,128, 44, 44, 44,
+    6,168,169,144,144,144,144,144,144,144,128,167,128,  2,125,170,
+    2, 64,  2,  2,150,144,144,128,  2,171,  8,172, 66,  2, 44, 44,
+   36, 36, 36, 36, 36, 36, 61, 79, 91,  2,  3,  2,  4,  5,  6,  2,
+   16, 16, 16, 16, 16, 17, 18,127,128,  4,  2, 36, 36, 36, 36, 36,
+   69, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40,
+   44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 61, 44,
+   20,173, 56,174, 26,  8,140, 90, 44, 44, 44, 44, 79, 65, 67, 44,
+   36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62,
+    2, 64, 44,175, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67,
+  103,103,139, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 90,
+   67, 67, 67, 67, 67, 67, 90, 44, 90, 44, 44, 44, 44, 44, 44, 44,
+   67, 67, 67, 67, 67, 67, 50, 44,176, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36,
+  149, 36, 36, 36, 36,177, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 91, 36, 36, 44, 44, 36, 36, 36, 36,
+  178,103,103, 44, 44, 44, 44, 44, 11, 11, 11, 11, 16, 16, 16, 16,
+   11, 11, 44, 44, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 44, 44,
+   36, 36, 44, 44, 44, 44, 44, 91, 36, 36, 36, 44, 61, 36, 36, 36,
+   36, 36, 36, 62, 61, 44, 61, 62, 36, 36, 36, 91, 27, 27, 27, 27,
+   36, 36, 36, 77,157, 27, 27, 27, 44, 44, 44,175, 27, 27, 27, 27,
+   36, 61, 36, 44, 44,175, 27, 27, 36, 36, 36, 27, 27, 27, 44, 91,
+   36, 36, 36, 36, 36, 44, 44, 91, 36, 36, 36, 36, 44, 44, 27, 36,
+   44, 27, 27, 27, 27, 27, 27, 27, 70, 43, 57, 80, 44, 44, 43, 43,
+   36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36, 44, 43, 80, 44, 57,
+   27, 27, 27, 27, 98, 44, 44, 44,  2,  2,  2,  2, 64, 44, 44, 44,
+   36, 36, 36, 36, 36, 36,179, 30, 36, 36, 36, 36, 36, 36,179, 27,
+   36, 36, 36, 36, 78, 36, 36, 36, 36, 36, 70, 80, 44,175, 27, 27,
+    2,  2,  2, 64, 44, 44, 44, 44, 36, 36, 36, 44, 91,  2,  2,  2,
+   36, 36, 36, 44, 27, 27, 27, 27, 36, 61, 44, 44, 27, 27, 27, 27,
+   36, 44, 44, 44, 91,  2, 64, 44, 44, 44, 44, 44,175, 27, 27, 27,
+   11, 47, 44, 44, 44, 44, 44, 44, 16,108, 44, 44, 44, 27, 27, 27,
+   36, 36, 43, 43, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27, 98,
+   36, 36, 36, 36, 36, 57,180, 44, 36, 44, 44, 44, 44, 44, 44, 44,
+   27, 27, 27, 93, 44, 44, 44, 44,176, 27, 30,  2,  2, 44, 44, 44,
+   36, 36,179, 27, 27, 27, 44, 44, 85, 96, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60,  2,  2,  2, 44,
+   27, 27, 27,  7,  7,  7,  7,  7, 44, 44, 44, 44, 44, 44, 44, 57,
+   84, 85, 43, 83, 85, 60,181,  2,  2, 44, 44, 44, 44, 44, 79, 44,
+   43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 85, 43,
+   43, 43, 80,  7,  7,  7,  7,  7,  2,  2, 92, 96, 44, 44, 44, 44,
+   36, 70,  2, 61, 44, 44, 44, 44, 36, 92, 84, 43, 43, 43, 43, 83,
+   96, 36, 63,  2, 59, 43, 60, 85,  7,  7,  7,  7,  7, 63, 63,  2,
+  175, 27, 27, 27, 27, 27, 27, 27, 27, 27, 98, 44, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 84, 85, 43, 84, 83, 43,  2,  2,  2, 80,
+   36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62,
+   36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70,
+   84, 85, 43, 43, 43, 80, 44, 44, 43, 84, 62, 36, 36, 36, 61, 62,
+   61, 36, 62, 36, 36, 57, 71, 84, 83, 84, 88, 87, 88, 87, 84, 44,
+   61, 44, 44, 87, 44, 44, 62, 36, 36, 84, 44, 43, 43, 43, 80, 44,
+   43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 92, 84, 43, 43, 43, 43,
+   84, 43, 83, 71, 36, 63,  2,  2,  7,  7,  7,  7,  7,  2, 91, 71,
+   84, 85, 43, 43, 83, 83, 84, 85, 83, 43, 36, 72, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 36, 36, 92, 84, 43, 43, 44, 84, 84, 43, 85,
+   60,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 43, 44,
+   84, 85, 43, 43, 43, 83, 85, 85, 60,  2, 61, 44, 44, 44, 44, 44,
+    2,  2,  2,  2,  2,  2, 64, 44, 36, 36, 36, 36, 36, 70, 85, 84,
+   43, 43, 43, 85, 61, 44, 44, 44, 84, 43, 43, 85, 43, 43, 44, 44,
+    7,  7,  7,  7,  7, 27,  2, 95, 43, 43, 43, 43, 85, 60, 44, 44,
+   27, 98, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36,
+   36, 36, 62, 61, 36, 36, 36, 36, 84, 84, 84, 87, 88, 57, 83, 71,
+   96, 85,  2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36,
+   92, 84, 43, 43, 44, 43, 84, 84, 71, 72, 88, 44, 44, 44, 44, 44,
+   70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 83, 70, 43, 60,
+    2,  2,  2, 59, 44, 44, 44, 44, 70, 43, 43, 83, 85, 43, 36, 36,
+   36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 83, 43,  2, 72,  2,
+    2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 85,
+   63,  2,  2, 44, 44, 44, 44, 44,  2, 36, 36, 36, 36, 36, 36, 36,
+   44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 87, 43, 43, 43,
+   83, 43, 85, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36,
+   70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44,
+   36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 84, 84, 88,
+   43, 87, 85, 85, 61, 44, 44, 44, 36, 70, 83,162, 64, 44, 44, 44,
+   27, 27, 89, 67, 67, 67, 56, 20,161, 67, 67, 67, 67, 67, 67, 67,
+   67, 44, 44, 44, 44, 44, 44, 91,103,103,103,103,103,103,103,177,
+    2,  2, 64, 44, 44, 44, 44, 44, 65, 65, 65, 65, 68, 44, 44, 44,
+   43, 43, 60, 44, 44, 44, 44, 44, 43, 43, 43, 60,  2,  2, 67, 67,
+   40, 40, 95, 44, 44, 44, 44, 44,  7,  7,  7,  7,  7,175, 27, 27,
+   27, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 44, 62, 36,
+   27, 27, 27, 30,  2, 64, 44, 44, 36, 36, 36, 36, 36, 61, 44, 57,
+   92, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+   84, 84, 84, 84, 44, 44, 44, 57, 43, 74, 40, 40, 40, 40, 40, 40,
+   40, 86, 80, 44, 44, 44, 44, 44, 84, 44, 44, 44, 44, 44, 44, 44,
+   36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
+   36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44,
+   67, 67, 67, 90, 55, 67, 67, 67, 67, 67,182, 85, 43, 67,182, 84,
+   84,183, 65, 65, 65, 82, 43, 43, 43, 76, 50, 43, 43, 43, 67, 67,
+   67, 67, 67, 67, 67, 43, 43, 67, 67, 67, 67, 67, 90, 44, 44, 44,
+   67, 43, 76, 44, 44, 44, 44, 44, 27, 27, 44, 44, 44, 44, 44, 44,
+   11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 11, 11, 16, 16, 16,108, 16, 16, 16, 16, 16,
+   11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 47, 11,
+   44, 47, 48, 47, 48, 11, 47, 11, 11, 11, 11, 16, 16,146,146, 16,
+   16, 16,146, 16, 16, 16, 16, 16, 16, 16, 11, 48, 11, 47, 48, 11,
+   11, 11, 47, 11, 11, 11, 47, 16, 16, 16, 16, 16, 11, 48, 11, 47,
+   11, 11, 47, 47, 44, 11, 11, 11, 47, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16,
+   16, 16, 16, 44, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11,
+   11, 11, 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33,
+   16, 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31,
+   16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16,
+   16, 33, 16, 16, 16, 32, 44,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+   43, 43, 43, 76, 67, 50, 43, 43, 43, 43, 43, 43, 43, 43, 76, 67,
+   67, 67, 50, 67, 67, 67, 67, 67, 67, 67, 76, 21,  2,  2, 44, 44,
+   44, 44, 44, 44, 44, 57, 43, 43, 43, 43, 43, 80, 43, 43, 43, 43,
+   43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44,
+   43, 43, 43, 74, 40, 40, 40, 44,  7,  7,  7,  7,  7, 44, 44, 77,
+   36, 36, 36, 36, 36, 36, 43, 43,  7,  7,  7,  7,  7, 44, 44, 94,
+   36, 36, 61,175, 27, 27, 27, 27, 43, 43, 43, 80, 44, 44, 44, 44,
+   16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,157, 27,
+  184, 27, 98, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,157,
+   27, 27, 27, 27, 27, 27, 27, 44, 36, 36, 62, 36, 36, 36, 36, 36,
+   62, 61, 61, 62, 62, 36, 36, 36, 36, 61, 36, 36, 62, 62, 44, 44,
+   44, 61, 44, 62, 62, 62, 62, 36, 62, 61, 61, 62, 62, 62, 62, 62,
+   62, 61, 61, 62, 36, 61, 36, 36, 36, 61, 36, 36, 62, 36, 61, 61,
+   36, 36, 36, 36, 36, 62, 36, 36, 62, 36, 62, 36, 36, 62, 36, 36,
+    8, 44, 44, 44, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67,
+   27, 27, 27, 27, 27, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 44,
+   44, 44, 44, 67, 67, 67, 67, 67, 67, 90, 44, 44, 44, 44, 44, 44,
+   67, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 25, 41, 41,
+   67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 90, 67, 67, 67,
+   67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 90, 44, 67, 90, 44, 44,
+   67, 90, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44,
+   65, 65, 65, 65, 65, 65, 65, 65,165,165,165,165,165,165,165, 44,
+  165,165,165,165,165,165,165,  0,  0,  0, 29, 21, 21, 21, 23, 21,
+   22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21,  9,  9,  9,
+    9, 22, 21, 18, 24, 16, 24,  5,  5,  5,  5, 22, 25, 18, 25,  0,
+   23, 23, 26, 21, 24, 26,  7, 20, 25,  1, 26, 24, 26, 25, 15, 15,
+   24, 15,  7, 19, 15, 21,  9, 25,  9,  5,  5, 25,  5,  9,  5,  7,
+    7,  7,  9,  8,  8,  5,  7,  5,  6,  6, 24, 24,  6, 24, 12, 12,
+    2,  2,  6,  5,  9, 21,  9,  2,  2,  9, 25,  9, 26, 12, 11, 11,
+    2,  6,  5, 21, 17,  2,  2, 26, 26, 23,  2, 12, 17, 12, 21, 12,
+   12, 21,  7,  2,  2,  7,  7, 21, 21,  2,  1,  1, 21, 23, 26, 26,
+    1,  2,  6,  7,  7, 12, 12,  7, 21,  7, 12,  1, 12,  6,  6, 12,
+   12, 26,  7, 26, 26,  7,  2,  1, 12,  2,  6,  2,  1, 12, 12, 10,
+   10, 10, 10, 12, 21,  6,  2, 10, 10,  2, 15, 26, 26,  2,  2, 21,
+    7, 10, 15,  7,  2, 23, 21, 26, 10,  7, 21, 15, 15,  2, 17,  7,
+   29,  7,  7, 22, 18,  2, 14, 14, 14,  7, 17, 21,  7,  6, 11, 12,
+    5,  2,  5,  6,  8,  8,  8, 24,  5, 24,  2, 24,  9, 24, 24,  2,
+   29, 29, 29,  1, 17, 17, 20, 19, 22, 20, 27, 28,  1, 29, 21, 20,
+   19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15,  6, 18,  6,
+   12, 11,  9, 26, 26,  9, 26,  5,  5, 26, 14,  9,  5, 14, 14, 15,
+   25, 26, 26, 22, 18, 26, 18, 25, 18, 22,  5, 12,  2,  5, 22, 21,
+   26,  6,  7, 14, 17, 22, 18, 18, 26, 14, 17,  6, 14,  6, 12, 24,
+   24,  6, 26, 15,  6, 21, 11, 21, 24,  9, 23, 26, 10, 21,  6, 10,
+    4,  4,  3,  3,  7, 25, 21, 22, 17, 16, 16, 22, 16, 16, 25, 17,
+   25,  2, 25, 24, 23,  2,  2, 15, 12, 15, 14,  2, 21, 14,  7, 15,
+   12, 17, 21,  1, 26, 10, 10,  1, 23, 15,  0,  1,  2,  3,  4,  5,
+    6,  7,  8,  9,  0, 10, 11, 12, 13,  0, 14,  0,  0,  0,  0,  0,
+   15,  0, 16,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 17, 18, 19,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 20,  0, 21, 22, 23,  0,  0,  0, 24,
+   25, 26, 27, 28, 29, 30, 31, 32, 33,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 34,
+    0, 35,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 36,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 37, 38,  0,  0,  0,  0,  0,  0, 39, 40,  0,  0, 41,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  0,  0,  0,  0,
+    0,  0,  0,  0,  5,  0,  0,  0,  0,  0,  0,  0,  6,  7,  8,  0,
+    9,  0, 10, 11,  0,  0, 12, 13, 14, 15, 16,  0,  0,  0,  0, 17,
+   18, 19, 20,  0,  0,  0, 21, 22,  0, 23, 24,  0,  0, 23, 25, 26,
+    0, 23, 25,  0,  0, 23, 25,  0,  0, 23, 25,  0,  0,  0, 25,  0,
+    0,  0, 27,  0,  0, 23, 25,  0,  0, 28, 25,  0,  0,  0, 29,  0,
+    0, 30, 31,  0,  0, 32, 33,  0, 34, 35,  0, 36, 37,  0, 38,  0,
+    0, 39,  0,  0, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 42, 42,  0,  0,  0,  0, 43,  0,
+    0,  0,  0,  0,  0, 44,  0,  0,  0, 45,  0,  0,  0,  0,  0,  0,
+   46,  0,  0, 47,  0, 48, 49,  0,  0, 50, 51, 52,  0, 53,  0, 54,
+    0, 55,  0,  0,  0,  0, 56, 57,  0,  0,  0,  0,  0,  0, 58, 59,
+    0,  0,  0,  0,  0,  0, 60, 61,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0, 63,  0,  0,  0, 64,
+    0, 65,  0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 67, 68,  0,  0, 69,  0,  0,  0,  0,  0,  0,  0,  0,
+   70, 71,  0,  0,  0,  0, 51, 72,  0, 73, 74,  0,  0, 75, 76,  0,
+    0,  0,  0,  0,  0, 77, 78, 79,  0,  0,  0,  0,  0,  0,  0, 25,
+    0,  0,  0,  0,  0,  0,  0,  0, 80,  0,  0,  0,  0,  0,  0,  0,
+    0, 81,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 82,
+    0,  0,  0,  0,  0,  0,  0, 49,  0,  0,  0, 83,  0,  0,  0,  0,
+   84, 85,  0,  0,  0,  0,  0, 86,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0, 87,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 88,  0,  0,  0,  0, 89,  0,  0,  0,  0,  0,
+    0,  0, 70, 63,  0, 90,  0,  0, 91, 92,  0, 75,  0,  0, 93,  0,
+    0, 94,  0,  0,  0,  0,  0, 95,  0, 96, 25, 97,  0,  0,  0,  0,
+    0,  0, 98,  0,  0,  0, 99,  0,  0,  0,  0,  0,  0, 63,100,  0,
+    0, 63,  0,  0,  0,101,  0,  0,  0,102,  0,  0,  0,  0,  0,  0,
+    0, 90,  0,  0,  0,  0,  0,  0,  0,103,104,  0,  0,  0,  0, 76,
+    0, 42,105,  0,106,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 63,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,108,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,109,  0,110,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,111,
+    0,  0,  0,  0,112,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,113,114,115,  0,  0,
+    0,  0,116,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  117,118,  0,  0,  0,  0,  0,  0,  0,110,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,119,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,120,  0,  0,  0,121,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  3,  4,
+    5,  6,  7,  4,  4,  8,  9, 10,  1, 11, 12, 13, 14, 15, 16, 17,
+   18,  1,  1,  1,  0,  0,  0,  0, 19,  1,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 20, 21, 22,  1, 23,  4, 21, 24, 25, 26, 27, 28,
+   29, 30,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1, 31,  0,
+    0,  0, 32, 33, 34, 35,  1, 36,  0,  0,  0,  0, 37,  0,  0,  0,
+    0,  0,  0,  0,  0, 38,  1, 39, 14, 39, 40, 41,  0,  0,  0,  0,
+    0,  0,  0,  0, 42,  0,  0,  0,  0,  0,  0,  0, 43, 36, 44, 45,
+   21, 45, 46,  0,  0,  0,  0,  0,  0,  0, 19,  1, 21,  0,  0, 47,
+    0,  0,  0,  0,  0, 38, 48,  1,  1, 49, 49, 50,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 51,  0,  0,  0,  0,  0, 52,  1,  1,  1,
+   53, 21, 43, 54, 55, 21, 35,  1,  0,  0,  0,  0,  0,  0,  0, 56,
+    0,  0,  0, 57, 58, 59,  0,  0,  0,  0,  0, 57,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 60,  0,  0,  0, 57,  0, 61,  0,  0,
+    0,  0,  0,  0,  0,  0, 62, 63,  0,  0, 64,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 65,  0,  0,  0, 66,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 67,  0,  0,  0, 68,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 69,  0,  0,  0,  0,  0,  0, 70, 71,  0,
+    0,  0,  0,  0, 72, 73, 74, 75, 76, 77,  0,  0,  0,  0,  0,  0,
+    0, 78,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 79, 80,  0,
+    0,  0,  0, 47,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 49,
+    0,  0,  0,  0,  0, 63,  0,  0,  0,  0,  0,  0, 64,  0,  0, 81,
+    0,  0, 82,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 83,  0,
+    0,  0,  0,  0,  0, 19, 84,  0, 63,  0,  0,  0,  0, 49,  1, 85,
+    0,  0,  0,  0,  1, 54, 15, 86, 84,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 56,  0,  0,  0, 63,  0,  0,  0,  0,  0,  0,
+    0,  0, 19, 10,  1,  0,  0,  0,  0,  0, 87,  0,  0,  0,  0,  0,
+    0, 88,  0,  0, 87,  0,  0,  0,  0,  0,  0,  0,  0, 79,  0,  0,
+    0,  0,  0,  0, 89,  9, 12,  4, 90,  8, 91, 47,  0, 59, 50,  0,
+   21,  1, 21, 92, 93,  1,  1,  1,  1,  1,  1,  1,  1, 94, 95, 96,
+    0,  0,  0,  0, 97,  1, 98, 59, 81, 99,100,  4, 59,  0,  0,  0,
+    0,  0,  0, 19, 50,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,
+    1,  1,  1,  1,  1,  1,  1,  1,  0,  0,101,102,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,103,  0,  0,  0,  0, 19,  0,  1,  1, 50,
+    0,  0,  0,  0,  0,  0,  0, 38,  0,  0,  0,  0, 50,  0,  0,  0,
+    0, 64,  0,  0,  0,  0,  0,  0,  0,  0,  0, 63,  0,  0,  0,  0,
+    1,  1,  1,  1, 50,  0,  0,  0,  0,  0, 52, 69,  0,  0,  0,  0,
+    0,  0,  0,  0, 62,  0,  0,  0,  0,  0,  0,  0, 79,  0,  0,  0,
+   63,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,104,105, 59, 38,
+   81,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 64,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,106,  1, 14,  4, 12,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 47,  0,  0,  0,  0,  0, 38, 89,  0,
+    0,  0,  0,107,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,108, 62,
+    0,109,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,
+    0,  0, 19, 59,  0,  0,  0,  0,  0,110, 14, 54, 84,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,111,  0, 89,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 62, 63,  0,  0, 63,  0, 88,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,111,  0,  0,  0,  0,112,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 79, 56,  0, 38,  1, 59,  1, 59,  0,  0,
+   64, 88,  0,  0,  0,  0,  0, 60,113,  0,  0,  0,  0,  0,  0,  0,
+   56,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,113,  0,  0,
+    0,  0, 62,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 80,
+   79,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 57,  0, 88,114,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0, 62,  0,  0,  0,  0,  0,  0,  8, 91,  0,  0,
+    0,  0,  0,  0,  1, 89,  0,  0,  0,  0,  0,  0,115,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,116,  0,117,118,119,120,  0, 52,  4,
+  121, 49, 23,  0,  0,  0,  0,  0,  0,  0, 38, 50,  0,  0,  0,  0,
+   38, 59,  0,  0,  0,  0,  0,  0,  1, 89,  1,  1,  1,  1, 39,  1,
+   48,104, 89,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,
+    0,  0,  0,  0,  4,121,  0,  0,  0,  1,122,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,230,230,230,230,230,232,220,220,220,220,232,216,
+  220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
+    1,  1,  1,  1,  1,220,220,220,220,230,230,230,230,240,230,220,
+  220,220,230,230,230,220,220,  0,230,230,230,220,220,220,220,230,
+  232,220,220,230,233,234,234,233,234,234,233,230,  0,  0,  0,230,
+    0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220,
+  230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
+   21, 22,  0, 23,  0, 24, 25,  0,230,220,  0, 18, 30, 31, 32,  0,
+    0,  0,  0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,
+  220,230,230,220, 35,  0,  0,  0,  0,  0,230,230,230,  0,  0,230,
+  230,  0,220,230,230,220,  0,  0,  0, 36,  0,  0,230,220,230,230,
+  220,220,230,220,220,230,220,230,220,230,230,  0,  0,220,  0,  0,
+  230,230,  0,230,  0,230,230,230,230,230,  0,  0,  0,220,220,220,
+    0,  0,  0,220,230,230,  0,220,230,220,220,220, 27, 28, 29,230,
+    7,  0,  0,  0,  0,  9,  0,  0,  0,230,220,230,230,  0,  0,  0,
+    0,  0,230,  0,  0, 84, 91,  0,  0,  0,  0,  9,  9,  0,  0,  0,
+    0,  0,  9,  0,103,103,  9,  0,107,107,107,107,118,118,  9,  0,
+  122,122,122,122,220,220,  0,  0,  0,220,  0,220,  0,216,  0,  0,
+    0,129,130,  0,132,  0,  0,  0,  0,  0,130,130,130,130,  0,  0,
+  130,  0,230,230,  9,  0,230,230,  0,  0,220,  0,  0,  0,  0,  7,
+    0,  9,  9,  0,  0,230,  0,  0,  0,228,  0,  0,  0,222,230,220,
+  220,  0,  0,  0,230,  0,  0,220,230,220,  0,220,  0,  0,  9,  9,
+    0,  0,  7,  0,230,230,230,  0,230,  0,  1,  1,  1,  0,  0,  0,
+  230,234,214,220,202,230,230,230,230,230,232,228,228,220,  0,230,
+  233,220,230,220,230,230,  1,  1,  1,  1,  1,230,  0,  1,  1,230,
+  220,230,  1,  1,  0,  0,218,228,232,222,224,224,  0,  8,  8,  0,
+  230,  0,230,230,220,  0,  0,230,  0,  0, 26,  0,  0,220,  0,230,
+  230,  1,220,  0,  0,230,220,  0,  0,  0,220,220,  0,  9,  7,  0,
+    0,  7,  9,  0,  0,  0,  9,  7,  9,  9,  0,  0,  6,  6,  0,  0,
+    0,  0,  1,  0,  0,216,216,  1,  1,  1,  0,  0,  0,226,216,216,
+  216,216,216,  0,220,220,220,  0,230,230,  7,  0, 16, 17, 17, 17,
+   17, 17, 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,
+  129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,237,  0,  1,  2,  2,
+    0,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  5,  0,  0,  0,  0,  6,  7,  8,
+    9,  0,  0,  0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 20,  0,  0, 21, 22,  0,  0,  0,  0,
+   23, 24, 25, 26,  0, 27,  0, 28, 29, 30, 31, 32,  0,  0,  0,  0,
+    0,  0,  0, 33, 34, 35,  0,  0,  0,  0,  0,  0, 36,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 37, 38,  0,  0,  0,  0,  1,  2, 39, 40,
+    0,  1,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,
+    0,  0,  0,  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  5,  0,
+    0,  0,  6,  0,  0,  0,  0,  0,  0,  0,  7,  1,  0,  0,  0,  0,
+    0,  0,  8,  9,  0,  0,  0,  0,  0,  0, 10,  0,  0, 10,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,  0,  0,  0, 10,
+    0,  0,  0,  0,  0,  0, 11, 12,  0, 13,  0, 14, 15, 16,  0,  0,
+    0,  0,  0,  1, 17, 18,  0, 19,  7,  1,  0,  0,  0, 20, 20,  7,
+   20, 20, 20, 20, 20, 20, 20,  8, 21,  0, 22,  0,  7, 23, 24,  0,
+   20, 20, 25,  0,  0,  0, 26, 27,  1,  7, 20, 20, 20, 20, 20,  1,
+   28, 29, 30, 31,  0,  0, 20,  0,  0,  0,  0,  0,  0,  0, 10,  0,
+    0,  0,  0,  0,  0,  0, 20, 20, 20,  1,  0,  0,  8, 21, 32,  4,
+    0, 10,  0, 33,  7, 20, 20, 20,  0,  0,  0,  0,  8, 34, 34, 35,
+   36, 34, 37,  0, 38,  1, 20, 20,  0,  0, 39,  0,  1,  1,  0,  8,
+   21,  1, 20,  0,  0,  0,  1,  0,  0, 40,  1,  1,  0,  0,  8, 21,
+    0,  1,  0,  1,  0,  1,  0,  0,  0,  0, 26, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 21,  7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 21,  0, 42, 43, 44,  0, 45,  0,  8, 21,  0,  0,  0,  0,  0,
+    0,  0,  0, 46,  7,  1, 10,  1,  0,  0,  0,  1, 20, 20,  1,  0,
+    0,  0,  0,  0,  0,  0, 20, 20,  1, 20, 20,  0,  0,  0,  0,  0,
+    0,  0, 26, 21,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  3, 47, 48,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,
+    4,  5,  6,  7,  7,  8,  7,  7,  7,  7,  7,  7,  7,  7,  7,  9,
+   10, 11, 12, 12, 12, 12, 13, 14, 14, 14, 14, 15, 16, 17, 18, 19,
+   20, 14, 21, 14, 22, 14, 14, 14, 14, 23, 24, 24, 25, 26, 14, 14,
+   14, 14, 27, 28, 14, 14, 29, 30, 31, 32, 33, 34,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+   35,  7, 36, 37,  7, 38,  7,  7,  7, 39, 14, 40,  7,  7, 41, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 42,  0,  0,  1,
+    2,  2,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+   32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
+   43, 44, 45, 46, 47, 48, 49, 50, 51, 52,  2,  2, 53, 54, 55, 56,
+   57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
+   59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+   74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 80, 81, 81,
+   81, 81, 81, 81, 81, 81, 81, 82, 83, 83, 84, 85, 86, 87, 88, 89,
+   90, 91, 92, 93, 94, 95, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 96, 97, 97,
+   97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+   70, 70, 98, 99,100,101,102,102,103,104,105,106,107,108,109,110,
+  111,112, 97,113,114,115,116,117,118, 97,119,119,120, 97,121,122,
+  123,124,125,126,127,128,129,130,131, 97,132,133,134,135,136,137,
+  138,139,140,141,142, 97,143,144, 97,145,146,147,148, 97,149,150,
+  151,152,153,154, 97, 97,155,156,157,158, 97,159, 97,160,161,161,
+  161,161,161,161,161,162,163,161,164, 97, 97, 97, 97, 97,165,165,
+  165,165,165,165,165,165,166, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97,167,167,167,167,168, 97, 97, 97,169,169,
+  169,169,170,171,172,173, 97, 97, 97, 97,174,175,176,177,178,178,
+  178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
+  178,178,178,178,178,178,178,178,178,178,178,178,178,179,178,178,
+  178,178,178,178,180,180,180,181,182, 97, 97, 97, 97, 97,183,184,
+  185,186,186,187, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+   97, 97, 97, 97, 97, 97,188,189, 97, 97, 97, 97, 97, 97, 59,190,
+  191,192,193,194,195, 97,196,197,198, 59, 59,199, 59,200,201,201,
+  201,201,201,202, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,203, 97,
+  204, 97, 97,205, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,206,207,
+  208, 97, 97, 97, 97, 97,209,210,211, 97,212,213, 97, 97,214,215,
+   59,216,217, 97, 59, 59, 59, 59, 59, 59, 59,218,219,220,221,222,
+  223,224,225,226, 59,227, 97, 97, 97, 97, 97, 97, 97, 97, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,228, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,229, 70,230, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+   70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,231, 70, 70, 70, 70,
+   70, 70, 70, 70, 70,232, 97, 97, 97, 97, 97, 97, 97, 97, 70, 70,
+   70, 70,233, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 70, 70,
+   70, 70, 70, 70,234, 97, 97, 97, 97, 97, 97, 97, 97, 97,235, 97,
+  236,237,  0,  1,  2,  2,  0,  1,  2,  2,  2,  3,  4,  5,  0,  0,
+    0,  0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19,  0,  0,  0,  0,  0,  0,  0,
+   19,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19, 19, 19,  0, 19,  0,
+    0,  0,  0,  0,  0,  0, 19, 19, 19, 19, 19,  0,  0,  0,  0,  0,
+   26, 26,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  9,  9,
+    9,  9,  0,  9,  9,  9,  2,  2,  9,  9,  9,  9,  0,  9,  2,  2,
+    2,  2,  9,  0,  9,  0,  9,  9,  9,  2,  9,  2,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  9,
+   55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,  6,  6,
+    6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  1,  1,  6,  2,  4,
+    4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  2,  4,  4,  4,  2,  2,  4,  4,  4,  2, 14,
+   14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2,  2,
+    2,  2,  2,  2,  2,  2, 14, 14, 14,  2,  2,  2,  2, 14, 14, 14,
+   14, 14, 14,  2,  2,  2,  3,  3,  3,  3,  3,  0,  3,  3,  3,  3,
+    3,  3,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  0,  3,  2,  3,  0,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+    3,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  3,  3,  1,  3,
+    3,  3,  3,  3,  3,  3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+   37, 37, 37, 37,  2, 37, 37, 37, 37,  2,  2, 37, 37, 37, 38, 38,
+   38, 38, 38, 38, 38, 38, 38, 38,  2,  2,  2,  2,  2,  2, 64, 64,
+   64, 64, 64, 64, 64, 64, 64, 64, 64,  2,  2, 64, 64, 64, 90, 90,
+   90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,  2,  2, 90, 90,
+   90, 90, 90, 90, 90,  2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+   95, 95,  2,  2, 95,  2, 37, 37, 37,  2,  2,  2,  2,  2,  3,  3,
+    3,  3,  3,  2,  3,  3,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,
+    0,  3,  3,  3,  3,  3,  7,  7,  7,  7,  7,  7,  7,  7,  7,  1,
+    1,  1,  1,  7,  7,  7,  7,  7,  7,  7,  0,  0,  7,  7,  5,  5,
+    5,  5,  2,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2,  5,  5,  2,
+    2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,
+    5,  5,  5,  5,  5,  5,  5,  2,  5,  2,  2,  2,  5,  5,  5,  5,
+    2,  2,  5,  5,  5,  5,  5,  2,  2,  5,  5,  5,  5,  2,  2,  2,
+    2,  2,  2,  2,  2,  5,  2,  2,  2,  2,  5,  5,  2,  5,  5,  5,
+    5,  5,  2,  2,  5,  5,  5,  5,  5,  5,  5,  5,  5,  2,  2, 11,
+   11, 11,  2, 11, 11, 11, 11, 11, 11,  2,  2,  2,  2, 11, 11,  2,
+    2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,
+   11, 11, 11, 11, 11, 11, 11,  2, 11, 11,  2, 11, 11,  2, 11, 11,
+    2,  2, 11,  2, 11, 11, 11,  2,  2, 11, 11, 11,  2,  2,  2, 11,
+    2,  2,  2,  2,  2,  2,  2, 11, 11, 11, 11,  2, 11,  2,  2,  2,
+    2,  2,  2,  2, 11, 11, 11, 11, 11, 11, 11, 11, 11,  2,  2, 10,
+   10, 10,  2, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,
+    2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,  2,
+   10, 10, 10, 10, 10, 10, 10,  2, 10, 10,  2, 10, 10, 10, 10, 10,
+    2,  2, 10, 10, 10, 10, 10, 10,  2, 10, 10, 10,  2,  2, 10,  2,
+    2,  2,  2,  2,  2,  2, 10, 10, 10, 10,  2,  2, 10, 10, 10, 10,
+    2,  2,  2,  2,  2,  2,  2, 10, 10, 10, 10, 10, 10, 10,  2, 21,
+   21, 21,  2, 21, 21, 21, 21, 21, 21, 21, 21,  2,  2, 21, 21,  2,
+    2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,  2,
+   21, 21, 21, 21, 21, 21, 21,  2, 21, 21,  2, 21, 21, 21, 21, 21,
+    2,  2, 21, 21, 21, 21, 21,  2,  2, 21, 21, 21,  2,  2,  2,  2,
+    2,  2,  2, 21, 21, 21,  2,  2,  2,  2, 21, 21,  2, 21, 21, 21,
+   21, 21,  2,  2, 21, 21,  2,  2, 22, 22,  2, 22, 22, 22, 22, 22,
+   22,  2,  2,  2, 22, 22, 22,  2, 22, 22, 22, 22,  2,  2,  2, 22,
+   22,  2, 22,  2, 22, 22,  2,  2,  2, 22, 22,  2,  2,  2, 22, 22,
+   22, 22, 22, 22, 22, 22, 22, 22,  2,  2,  2,  2, 22, 22, 22,  2,
+    2,  2,  2,  2,  2, 22,  2,  2,  2,  2,  2,  2, 22, 22, 22, 22,
+   22,  2,  2,  2,  2,  2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+   23, 23, 23,  2, 23, 23, 23,  2, 23, 23, 23, 23, 23, 23, 23, 23,
+    2,  2,  2, 23, 23, 23, 23,  2, 23, 23, 23, 23,  2,  2,  2,  2,
+    2,  2,  2, 23, 23,  2, 23, 23, 23,  2,  2,  2,  2,  2, 23, 23,
+   23, 23,  2,  2, 23, 23,  2,  2,  2,  2,  2,  2,  2, 23, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16,  2,
+   16, 16, 16, 16, 16, 16, 16, 16, 16, 16,  2, 16, 16, 16, 16, 16,
+    2,  2, 16, 16, 16, 16, 16,  2, 16, 16, 16, 16,  2,  2,  2,  2,
+    2,  2,  2, 16, 16,  2,  2,  2,  2,  2,  2,  2, 16,  2, 16, 16,
+   16, 16,  2,  2, 16, 16,  2, 16, 16,  2,  2,  2,  2,  2, 20, 20,
+   20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  2, 20, 20, 20,  2,
+   20, 20, 20, 20, 20, 20,  2,  2,  2,  2, 20, 20, 20, 20, 20, 20,
+   20, 20,  2,  2, 20, 20,  2, 36, 36, 36,  2, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,
+   36, 36, 36, 36, 36, 36, 36, 36,  2, 36, 36, 36, 36, 36, 36, 36,
+   36, 36,  2, 36,  2,  2,  2,  2, 36,  2,  2,  2,  2, 36, 36, 36,
+   36, 36, 36,  2, 36,  2,  2,  2,  2,  2,  2,  2, 36, 36,  2,  2,
+   36, 36, 36,  2,  2,  2,  2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+   24, 24, 24, 24, 24, 24, 24, 24, 24,  2,  2,  2,  2,  0, 24, 24,
+   24, 24,  2,  2,  2,  2,  2, 18, 18,  2, 18,  2, 18, 18, 18, 18,
+   18,  2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+   18, 18,  2, 18,  2, 18, 18, 18, 18, 18, 18, 18,  2,  2, 18, 18,
+   18, 18, 18,  2, 18,  2, 18, 18,  2,  2, 18, 18, 18, 18, 25, 25,
+   25, 25, 25, 25, 25, 25,  2, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+   25, 25, 25,  2,  2,  2, 25, 25, 25, 25, 25,  2, 25, 25, 25, 25,
+   25, 25, 25,  0,  0,  0,  0, 25, 25,  2,  2,  2,  2,  2, 33, 33,
+   33, 33, 33, 33, 33, 33,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  2,  8,  2,  2,  2,  2,  2,  8,  2,  2,  8,  8,
+    8,  0,  8,  8,  8,  8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30,
+   30, 30, 30, 30, 30, 30, 30,  2, 30, 30, 30, 30,  2,  2, 30, 30,
+   30, 30, 30, 30, 30,  2, 30, 30, 30,  2,  2, 30, 30, 30, 30, 30,
+   30, 30, 30,  2,  2,  2, 30, 30,  2,  2,  2,  2,  2,  2, 29, 29,
+   29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,  2,  2, 28, 28,
+   28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34,  2,  2,  2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+   35,  0,  0,  0, 35, 35, 35,  2,  2,  2,  2,  2,  2,  2, 45, 45,
+   45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,  2, 45, 45, 45, 45,
+   45, 45, 45,  2,  2,  2, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+   44, 44, 44,  0,  0,  2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+   43, 43,  2,  2,  2,  2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+   46, 46, 46,  2, 46, 46, 46,  2, 46, 46,  2,  2,  2,  2, 31, 31,
+   31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,  2,  2, 31, 31,
+    2,  2,  2,  2,  2,  2, 32, 32,  0,  0, 32,  0, 32, 32, 32, 32,
+   32, 32, 32, 32, 32,  2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+    2,  2,  2,  2,  2,  2, 32,  2,  2,  2,  2,  2,  2,  2, 32, 32,
+   32,  2,  2,  2,  2,  2, 28, 28, 28, 28, 28, 28,  2,  2, 48, 48,
+   48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,  2, 48, 48,
+   48, 48,  2,  2,  2,  2, 48,  2,  2,  2, 48, 48, 48, 48, 52, 52,
+   52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,  2,  2, 52, 52,
+   52, 52, 52,  2,  2,  2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+   58, 58,  2,  2,  2,  2, 58, 58,  2,  2,  2,  2,  2,  2, 58, 58,
+   58,  2,  2,  2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+   54, 54,  2,  2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+   91, 91, 91, 91, 91,  2, 91, 91, 91, 91, 91,  2,  2, 91, 91, 91,
+    2,  2,  2,  2,  2,  2, 91, 91, 91, 91, 91, 91,  2,  2,  1,  2,
+    2,  2,  2,  2,  2,  2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+   62, 62,  2,  2,  2,  2, 62, 62, 62, 62, 62,  2,  2,  2, 76, 76,
+   76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+   93, 93,  2,  2,  2,  2,  2,  2,  2,  2, 93, 93, 93, 93, 70, 70,
+   70, 70, 70, 70, 70, 70,  2,  2,  2, 70, 70, 70, 70, 70, 70, 70,
+    2,  2,  2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73,  6,  2,
+    2,  2,  2,  2,  2,  2,  8,  8,  8,  2,  2,  8,  8,  8,  1,  1,
+    1,  0,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  0,
+    0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,
+    0,  2,  2,  2,  2,  2, 19, 19, 19, 19, 19, 19,  9,  9,  9,  9,
+    9,  6, 19, 19, 19, 19, 19, 19, 19, 19, 19,  9,  9,  9,  9,  9,
+   19, 19, 19, 19,  9,  9,  9,  9,  9, 19, 19, 19, 19, 19,  6, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,  9,  1,  1,
+    2,  1,  1,  1,  1,  1,  9,  9,  9,  9,  9,  9,  2,  2,  2,  9,
+    2,  9,  2,  9,  2,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  9,
+    9,  9,  2,  2,  9,  9,  9,  9,  9,  9,  2,  9,  9,  9,  2,  2,
+    9,  9,  9,  2,  9,  9,  9,  9,  9,  9,  9,  9,  9,  2,  0,  0,
+    0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0, 19,
+    2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 19,  0,  0,
+    0,  0,  0,  0,  0,  2, 19, 19, 19, 19, 19,  2,  2,  2,  0,  0,
+    0,  0,  0,  0,  9,  0,  0,  0, 19, 19,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 19,  0, 19,  0,  0,  0,  2,  2,  2,  2,  0,  0,
+    0,  2,  2,  2,  2,  2, 27, 27, 27, 27, 27, 27, 27, 27,  0,  0,
+    0,  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  2,  0, 56, 56,
+   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,  2, 55, 55,
+   55, 55,  2,  2,  2,  2,  2, 55, 55, 55, 55, 55, 55, 55, 61, 61,
+   61, 61, 61, 61, 61, 61,  2,  2,  2,  2,  2,  2,  2, 61, 61,  2,
+    2,  2,  2,  2,  2,  2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    2, 13, 13, 13, 13, 13, 13, 13, 13, 13,  2,  2,  2,  2, 13, 13,
+   13, 13, 13, 13,  2,  2,  0,  0,  0,  0,  2,  2,  2,  2,  0,  0,
+    0,  0,  0, 13,  0, 13,  0, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    1,  1,  1,  1, 12, 12, 13, 13, 13, 13,  0,  0,  0,  0,  2, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15,  2,  2,  1,  1,  0,  0, 15, 15, 15,  0, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17,  0,  0, 17, 17, 17,  2,  2,  2,  2,  2, 26, 26, 26, 26, 26,
+   26, 26, 26, 26, 26, 26,  2, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12,  2, 12, 12, 12, 12, 12, 12, 12,  0, 17, 17,
+   17, 17, 17, 17, 17,  0, 13, 13, 13, 13, 13,  2,  2,  2, 39, 39,
+   39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,  2,  2,  2, 39, 39,
+   39, 39, 39, 39, 39,  2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77,
+   77, 77, 77, 77, 77, 77, 77, 77, 77, 77,  2,  2,  2,  2, 79, 79,
+   79, 79, 79, 79, 79, 79,  0,  0, 19, 19, 19, 19, 19, 19,  0,  0,
+    0, 19, 19, 19, 19, 19,  2,  2, 19, 19, 19, 19, 19, 19, 19, 19,
+   19,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 19, 19, 19, 60, 60,
+   60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,  2,  2,  2,  0,  0,
+    2,  2,  2,  2,  2,  2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75,
+   75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,  2,  2,  2,  2,
+    2,  2,  2,  2, 75, 75, 75, 75,  2,  2,  2,  2,  2,  2, 69, 69,
+   69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,  0, 69, 74, 74,
+   74, 74, 74, 74, 74, 74, 74, 74, 74, 74,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2, 74, 12, 12, 12, 12, 12,  2,  2,  2, 84, 84,
+   84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,  2,  0, 84, 84,
+    2,  2,  2,  2, 84, 84, 33, 33, 33, 33, 33, 33, 33,  2, 68, 68,
+   68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,  2, 68, 68,
+   68, 68, 68, 68,  2,  2, 68, 68,  2,  2, 68, 68, 68, 68, 92, 92,
+   92, 92, 92, 92, 92, 92, 92, 92, 92,  2,  2,  2,  2,  2,  2,  2,
+    2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87, 87,  2,  2, 30, 30, 30, 30, 30, 30,  2, 19, 19,
+   19,  0, 19, 19, 19, 19, 19, 19, 19, 19, 19,  9, 19, 19, 19, 19,
+    0,  0,  2,  2,  2,  2, 87, 87, 87, 87, 87, 87,  2,  2, 87, 87,
+    2,  2,  2,  2,  2,  2, 12, 12, 12, 12,  2,  2,  2,  2,  2,  2,
+    2, 12, 12, 12, 12, 12, 13, 13,  2,  2,  2,  2,  2,  2, 19, 19,
+   19, 19, 19, 19, 19,  2,  2,  2,  2,  4,  4,  4,  4,  4,  2,  2,
+    2,  2,  2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,  2, 14, 14,
+   14, 14, 14,  2, 14,  2, 14, 14,  2, 14, 14,  2, 14, 14,  3,  3,
+    2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  0,  0,  2,  2,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  2,  1,  1,
+    1,  1,  1,  1,  6,  6,  0,  0,  0,  2,  0,  0,  0,  0,  3,  3,
+    3,  3,  3,  2,  2,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 17, 17, 17, 17, 17, 17, 17, 17,  0,  0,  2,  2,
+   12, 12, 12, 12, 12, 12,  2,  2, 12, 12, 12,  2,  2,  2,  2,  0,
+    0,  0,  0,  0,  2,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+   49, 49,  2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,  2, 49, 49,
+   49,  2, 49, 49,  2, 49, 49, 49, 49, 49, 49, 49,  2,  2, 49, 49,
+   49,  2,  2,  2,  2,  2,  0,  0,  0,  2,  2,  2,  2,  0,  0,  0,
+    0,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,  2,  2,  2,  9,  2,
+    2,  2,  2,  2,  2,  2,  0,  0,  0,  0,  0,  1,  2,  2, 71, 71,
+   71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,  2,  2,  2, 67, 67,
+   67, 67, 67, 67, 67, 67, 67,  2,  2,  2,  2,  2,  2,  2,  1,  0,
+    0,  0,  0,  0,  0,  0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+   42, 42,  2,  2,  2,  2,  2,  2,  2,  2,  2, 42, 42, 42, 41, 41,
+   41, 41, 41, 41, 41, 41, 41, 41, 41,  2,  2,  2,  2,  2,118,118,
+  118,118,118,118,118,118,118,118,118,  2,  2,  2,  2,  2, 53, 53,
+   53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,  2, 53, 59, 59,
+   59, 59, 59, 59, 59, 59, 59, 59, 59, 59,  2,  2,  2,  2, 59, 59,
+   59, 59, 59, 59,  2,  2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51,
+   51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+   50, 50, 50, 50,  2,  2, 50, 50,  2,  2,  2,  2,  2,  2,135,135,
+  135,135,135,135,135,135,135,135,135,135,  2,  2,  2,  2,106,106,
+  106,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104,
+  104,104,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,104,110,110,
+  110,110,110,110,110,110,110,110,110,110,110,110,110,  2,110,110,
+  110,110,110,110,  2,  2, 47, 47, 47, 47, 47, 47,  2,  2, 47,  2,
+   47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+   47, 47, 47, 47,  2, 47, 47,  2,  2,  2, 47,  2,  2, 47, 81, 81,
+   81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,  2, 81,120,120,
+  120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
+  116,116,116,116,116,  2,  2,  2,  2,  2,  2,  2,  2,116,128,128,
+  128,128,128,128,128,128,128,128,128,  2,128,128,  2,  2,  2,  2,
+    2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+   66, 66,  2,  2,  2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+    2,  2,  2,  2,  2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97,
+   97, 97, 97, 97, 97, 97,  2,  2,  2,  2, 97, 97, 97, 97,  2,  2,
+   97, 97, 97, 97, 97, 97, 57, 57, 57, 57,  2, 57, 57,  2,  2,  2,
+    2,  2, 57, 57, 57, 57, 57, 57, 57, 57,  2, 57, 57, 57,  2, 57,
+   57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+   57, 57, 57, 57,  2,  2, 57, 57, 57,  2,  2,  2,  2, 57, 57,  2,
+    2,  2,  2,  2,  2,  2, 88, 88, 88, 88, 88, 88, 88, 88,117,117,
+  117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
+  112,112,112,112,112,  2,  2,  2,  2,112,112,112,112,112, 78, 78,
+   78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,  2,  2,  2, 78,
+   78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+   83, 83, 83, 83,  2,  2, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+   82,  2,  2,  2,  2,  2,122,122,122,122,122,122,122,122,122,122,
+    2,  2,  2,  2,  2,  2,  2,122,122,122,122,  2,  2,  2,  2,122,
+  122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89,  2,
+    2,  2,  2,  2,  2,  2,130,130,130,130,130,130,130,130,130,130,
+  130,  2,  2,  2,  2,  2,  2,  2,130,130,130,130,130,130,144,144,
+  144,144,144,144,144,144,144,144,  2,  2,  2,  2,  2,  2,  3,  3,
+    3,  3,  3,  3,  3,  2,156,156,156,156,156,156,156,156,156,156,
+    2,156,156,156,  2,  2,156,156,  2,  2,  2,  2,  2,  2,147,147,
+  147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148,
+    2,  2,  2,  2,  2,  2,153,153,153,153,153,153,153,153,153,153,
+  153,153,  2,  2,  2,  2,149,149,149,149,149,149,149,149,149,149,
+  149,149,149,149,149,  2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+   94, 94, 94, 94,  2,  2,  2,  2, 94, 94, 94, 94, 94, 94,  2,  2,
+    2,  2,  2,  2,  2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 85,  2,  2,101,101,
+  101,101,101,101,101,101,101,  2,  2,  2,  2,  2,  2,  2,101,101,
+    2,  2,  2,  2,  2,  2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+   96, 96, 96,  2, 96, 96,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,  2,100,100,100,100,100,100,100,100,  2, 36,
+   36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  2,  2,  2,108,108,
+  108,108,108,108,108,108,108,108,  2,108,108,108,108,108,108,108,
+  108,108,108,108,108,  2,129,129,129,129,129,129,129,  2,129,  2,
+  129,129,129,129,  2,129,129,129,129,129,129,129,129,129,129,129,
+  129,129,129,129,  2,129,129,129,  2,  2,  2,  2,  2,  2,109,109,
+  109,109,109,109,109,109,109,109,109,  2,  2,  2,  2,  2,109,109,
+    2,  2,  2,  2,  2,  2,107,107,107,107,  2,107,107,107,107,107,
+  107,107,107,  2,  2,107,107,  2,  2,107,107,107,107,107,107,107,
+  107,107,107,107,107,107,107,  2,107,107,107,107,107,107,107,  2,
+  107,107,  2,107,107,107,107,107,  2,  1,107,107,107,107,107,  2,
+    2,107,107,107,  2,  2,107,  2,  2,  2,  2,  2,  2,107,  2,  2,
+    2,  2,  2,107,107,107,107,107,107,107,  2,  2,107,107,107,107,
+  107,107,107,  2,  2,  2,137,137,137,137,137,137,137,137,137,137,
+  137,137,  2,137,137,137,137,137,  2,  2,  2,  2,  2,  2,124,124,
+  124,124,124,124,124,124,124,124,  2,  2,  2,  2,  2,  2,123,123,
+  123,123,123,123,123,123,123,123,123,123,123,123,  2,  2,114,114,
+  114,114,114,114,114,114,114,114,114,114,114,  2,  2,  2,114,114,
+    2,  2,  2,  2,  2,  2, 32, 32, 32, 32, 32,  2,  2,  2,102,102,
+  102,102,102,102,102,102,102,  2,  2,  2,  2,  2,  2,  2,102,102,
+    2,  2,  2,  2,  2,  2,126,126,126,126,126,126,126,126,126,126,
+  126,  2,  2,126,126,126,126,126,126,126,  2,  2,  2,  2,142,142,
+  142,142,142,142,142,142,142,142,142,142,  2,  2,  2,  2,125,125,
+  125,125,125,125,125,125,125,125,125,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2,  2,125,154,154,154,154,154,154,154,  2,  2,154,
+    2,  2,154,154,154,154,154,154,154,154,  2,154,154,  2,154,154,
+  154,154,154,154,154,154,154,154,154,154,154,154,  2,154,154,  2,
+    2,154,154,154,154,154,154,154,  2,  2,  2,  2,  2,  2,150,150,
+  150,150,150,150,150,150,  2,  2,150,150,150,150,150,150,150,150,
+  150,150,150,  2,  2,  2,141,141,141,141,141,141,141,141,140,140,
+  140,140,140,140,140,140,140,140,140,  2,  2,  2,  2,  2,121,121,
+  121,121,121,121,121,121,121,  2,  2,  2,  2,  2,  2,  2,133,133,
+  133,133,133,133,133,133,133,  2,133,133,133,133,133,133,133,133,
+  133,133,133,133,133,  2,133,133,133,133,133,133,  2,  2,133,133,
+  133,133,133,  2,  2,  2,134,134,134,134,134,134,134,134,  2,  2,
+  134,134,134,134,134,134,  2,134,134,134,134,134,134,134,134,134,
+  134,134,134,134,134,  2,138,138,138,138,138,138,138,  2,138,138,
+    2,138,138,138,138,138,138,138,138,138,138,138,138,138,  2,  2,
+  138,  2,138,138,  2,138,138,138,  2,  2,  2,  2,  2,  2,143,143,
+  143,143,143,143,  2,143,143,  2,143,143,143,143,143,143,143,143,
+  143,143,143,143,143,143,143,143,143,143,143,143,143,  2,143,143,
+    2,143,143,143,143,143,143,  2,  2,  2,  2,  2,  2,  2,143,143,
+    2,  2,  2,  2,  2,  2,145,145,145,145,145,145,145,145,145,  2,
+    2,  2,  2,  2,  2,  2, 86,  2,  2,  2,  2,  2,  2,  2, 22, 22,
+    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2, 22, 63, 63,
+   63, 63, 63, 63, 63, 63, 63, 63,  2,  2,  2,  2,  2,  2, 63, 63,
+   63, 63, 63, 63, 63,  2, 63, 63, 63, 63, 63,  2,  2,  2, 63, 63,
+   63, 63,  2,  2,  2,  2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+   80, 80, 80, 80, 80,  2, 80,  2,  2,  2,  2,  2,  2,  2,127,127,
+  127,127,127,127,127,127,127,127,127,127,127,127,127,  2, 79,  2,
+    2,  2,  2,  2,  2,  2,115,115,115,115,115,115,115,115,115,115,
+  115,115,115,115,115,  2,115,115,  2,  2,  2,  2,115,115,103,103,
+  103,103,103,103,103,103,103,103,103,103,103,103,  2,  2,119,119,
+  119,119,119,119,119,119,119,119,119,119,119,119,  2,  2,119,119,
+    2,119,119,119,119,119,  2,  2,  2,  2,  2,119,119,119,146,146,
+  146,146,146,146,146,146,146,146,146,  2,  2,  2,  2,  2, 99, 99,
+   99, 99, 99, 99, 99, 99, 99, 99, 99,  2,  2,  2,  2, 99,  2,  2,
+    2,  2,  2,  2,  2, 99,136,139,  0,  0,155,  2,  2,  2,136,136,
+  136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155,
+  155,155,155,155,  2,  2,136,  2,  2,  2,  2,  2,  2,  2, 17, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15,  2,  2,  2,  2,  2,  2,  2,
+    2,  2, 17, 17, 17, 17,139,139,139,139,139,139,139,139,139,139,
+  139,139,  2,  2,  2,  2,105,105,105,105,105,105,105,105,105,105,
+  105,  2,  2,  2,  2,  2,105,105,105,105,105,  2,  2,  2,105,  2,
+    2,  2,  2,  2,  2,  2,105,105,  2,  2,105,105,105,105,  0,  0,
+    0,  0,  0,  0,  2,  2,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,
+    1,  0,  0,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,
+    1,  1,  1,  1,  0,  0,  0,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+    0,  2,  2,  0,  0,  2,  2,  0,  0,  0,  0,  2,  0,  0,  0,  0,
+    2,  0,  2,  0,  0,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  0,
+    0,  2,  2,  0,  0,  0,  0,  0,  2,  0,  0,  0,  0,  2,  0,  0,
+    0,  0,  0,  2,  0,  2,  2,  2,  0,  0,  0,  0,  0,  0,  0,  2,
+    0,  0,  0,  0,  0,  0,131,131,131,131,131,131,131,131,131,131,
+  131,131,  2,  2,  2,  2,  2,  2,  2,131,131,131,131,131,  2,131,
+  131,131,131,131,131,131, 56,  2,  2, 56, 56, 56, 56, 56, 56, 56,
+    2, 56, 56,  2, 56, 56, 56, 56, 56,  2,  2,  2,  2,  2,151,151,
+  151,151,151,151,151,151,151,151,151,151,151,  2,  2,  2,151,151,
+  151,151,151,151,  2,  2,151,151,  2,  2,  2,  2,151,151,152,152,
+  152,152,152,152,152,152,152,152,  2,  2,  2,  2,  2,152,113,113,
+  113,113,113,113,113,113,113,113,113,113,113,  2,  2,113,113,113,
+  113,113,113,113,113,  2,132,132,132,132,132,132,132,132,132,132,
+  132,132,  2,  2,  2,  2,132,132,  2,  2,  2,  2,132,132,  3,  3,
+    3,  3,  2,  3,  3,  3,  2,  3,  3,  2,  3,  2,  2,  3,  2,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  2,  3,  3,  3,  3,  2,  3,
+    2,  3,  2,  2,  2,  2,  2,  2,  3,  2,  2,  2,  2,  3,  2,  3,
+    2,  3,  2,  3,  3,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,
+    3,  3,  3,  2,  3,  2,  3,  3,  2,  3,  3,  3,  3,  3,  3,  3,
+    3,  3,  2,  2,  2,  2,  2,  3,  3,  3,  2,  3,  3,  3,  2,  2,
+    2,  2,  2,  2,  0,  0, 15,  0,  0,  2,  2,  2,  2,  2, 13,  2,
+    2,  2,  2,  2,  2,  2, 13, 13, 13,  2,  2,  2,  2,  2,  2,  0,
+    2,  2,  2,  2,  2,  2,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
+    9,  9,  9, 10,  9, 11, 12, 13,  9,  9,  9, 14,  9,  9, 15,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9, 16, 17,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 18, 19,
+   20,  9, 21,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 22,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9, 23, 24,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,  0,  0, 13, 14,
+   15, 16, 17, 18, 19, 20, 21, 22,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 23,  0,  0, 24, 25, 26, 27, 28,
+   29, 30,  0,  0, 31, 32,  0, 33,  0, 34,  0, 35,  0,  0,  0,  0,
+   36, 37, 38, 39,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   41, 42,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 43, 44,  0, 45,  0,  0,  0,  0,  0,  0,
+   46, 47,  0,  0,  0,  0,  0, 48,  0, 49,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 50, 51,  0,  0,  0, 52,  0,  0,
+   53,  0,  0,  0,  0,  0,  0,  0, 54,  0,  0,  0,  0,  0,  0,  0,
+   55,  0,  0,  0,  0,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0,
+    0, 57,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0, 58, 59, 60, 61, 62, 63, 64, 65,
+    0,  0,  0,  0,  0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 67, 68,  0, 69, 70,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+   83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+   99,100,101,102,103,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,104,  0,  0,  0,  0,  0,  0,105,106,  0,
+  107,  0,  0,  0,108,  0,109,  0,110,  0,111,112,113,  0,114,  0,
+    0,  0,115,  0,  0,  0,116,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,117,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,118,119,120,121,  0,122,123,124,
+  125,126,  0,127,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,128,129,130,131,132,133,134,135,136,137,138,139,
+  140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,
+  156,157,  0,  0,  0,158,159,160,161,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,162,163,  0,
+    0,  0,  0,  0,  0,  0,164,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,165,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,166,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,167,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,168,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,169,170,  0,  0,  0,  0,171,
+  172,  0,  0,  0,173,174,175,176,177,178,179,180,181,182,183,184,
+  185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,
+  201,202,203,204,205,206,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    1,  2,  3,  4,
+};
+static const uint16_t
+_hb_ucd_u16[9080] =
+{
+     0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
+    13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
+    13,  13,  13,  24,  25,  11,  11,  11,  11,  26,  11,  27,  28,  29,  30,  31,
+    32,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  11,  37,  38,  13,  39,
+     9,   9,   9,  11,  11,  11,  13,  13,  40,  13,  13,  13,  41,  13,  13,  13,
+    13,  13,  13,  42,   9,  43,  11,  11,  44,  45,  32,  46,  47,  48,  49,  50,
+    51,  52,  48,  48,  53,  32,  54,  55,  48,  48,  48,  48,  48,  56,  57,  58,
+    59,  60,  48,  32,  61,  48,  48,  48,  48,  48,  62,  63,  64,  48,  65,  66,
+    48,  67,  68,  69,  48,  70,  71,  72,  72,  72,  48,  73,  74,  75,  76,  32,
+    77,  48,  48,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,
+    91,  84,  85,  92,  93,  94,  95,  96,  97,  98,  85,  99, 100, 101,  89, 102,
+   103,  84,  85, 104, 105, 106,  89, 107, 108, 109, 110, 111, 112, 113,  95, 114,
+   115, 116,  85, 117, 118, 119,  89, 120, 121, 116,  85, 122, 123, 124,  89, 125,
+   126, 116,  48, 127, 128, 129,  89, 130, 131, 132,  48, 133, 134, 135,  95, 136,
+   137,  48,  48, 138, 139, 140,  72,  72, 141,  48, 142, 143, 144, 145,  72,  72,
+   146, 147, 148, 149, 150,  48, 151, 152, 153, 154,  32, 155, 156, 157,  72,  72,
+    48,  48, 158, 159, 160, 161, 162, 163, 164, 165,   9,   9, 166,  11,  11, 167,
+    48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 168, 169,  48,  48,
+   168,  48,  48, 170, 171, 172,  48,  48,  48, 171,  48,  48,  48, 173, 174, 175,
+    48, 176,   9,   9,   9,   9,   9, 177, 178,  48,  48,  48,  48,  48,  48,  48,
+    48,  48,  48,  48,  48,  48, 179,  48, 180, 181,  48,  48,  48,  48, 182, 183,
+   184, 185,  48, 186,  48, 187, 184, 188,  48,  48,  48, 189, 190, 191, 192, 193,
+   194, 192,  48,  48, 195,  48,  48, 196, 197,  48, 198,  48,  48,  48,  48, 199,
+    48, 200, 201, 202, 203,  48, 204, 205,  48,  48, 206,  48, 207, 208, 209, 209,
+    48, 210,  48,  48,  48, 211, 212, 213, 192, 192, 214, 215, 216,  72,  72,  72,
+   217,  48,  48, 218, 219, 160, 220, 221, 222,  48, 223,  64,  48,  48, 224, 225,
+    48,  48, 226, 227, 228,  64,  48, 229, 230,   9,   9, 231, 232, 233, 234, 235,
+    11,  11, 236,  27,  27,  27, 237, 238,  11, 239,  27,  27,  32,  32,  32, 240,
+    13,  13,  13,  13,  13,  13,  13,  13,  13, 241,  13,  13,  13,  13,  13,  13,
+   242, 243, 242, 242, 243, 244, 242, 245, 246, 246, 246, 247, 248, 249, 250, 251,
+   252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 262,  72, 263, 264, 216,
+   265, 266, 267, 268, 269, 270, 271, 271, 272, 273, 274, 209, 275, 276, 209, 277,
+   278, 278, 278, 278, 278, 278, 278, 278, 279, 209, 280, 209, 209, 209, 209, 281,
+   209, 282, 278, 283, 209, 284, 285, 209, 209, 209, 286,  72, 287,  72, 270, 270,
+   270, 288, 209, 209, 209, 209, 289, 270, 209, 209, 209, 209, 209, 209, 209, 209,
+   209, 209, 209, 290, 291, 209, 209, 292, 209, 209, 209, 209, 209, 209, 293, 209,
+   209, 209, 209, 209, 209, 209, 294, 295, 270, 296, 209, 209, 297, 278, 298, 278,
+   299, 300, 278, 278, 278, 301, 278, 302, 209, 209, 209, 278, 303, 209, 209, 304,
+   209, 305, 209, 209, 209, 209, 209, 209,   9,   9, 306,  11,  11, 307, 308, 309,
+    13,  13,  13,  13,  13,  13, 310, 311,  11,  11, 312,  48,  48,  48, 313, 314,
+    48, 315, 316, 316, 316, 316,  32,  32, 317, 318, 319, 320, 321, 322,  72,  72,
+   209, 323, 209, 209, 209, 209, 209, 324, 209, 209, 209, 209, 209, 325,  72, 326,
+   327, 328, 329, 330, 137,  48,  48,  48,  48, 331, 178,  48,  48,  48,  48, 332,
+   333,  48,  48, 137,  48,  48,  48,  48, 200, 334,  48,  48, 209, 209, 324,  48,
+   209, 335, 336, 209, 337, 338, 209, 209, 336, 209, 209, 338, 209, 209, 209, 209,
+    48,  48,  48,  48, 209, 209, 209, 209,  48,  48,  48,  48,  48,  48,  48, 151,
+    48, 339,  48,  48,  48,  48,  48,  48, 151, 209, 209, 209, 286,  48,  48, 229,
+   340,  48, 341,  72,  13,  13, 342, 343,  13, 344,  48,  48,  48,  48, 345, 346,
+    31, 347, 348, 349,  13,  13,  13, 350, 351, 352, 353, 354, 355,  72,  72, 356,
+   357,  48, 358, 359,  48,  48,  48, 360, 361,  48,  48, 362, 363, 192,  32, 364,
+    64,  48, 365,  48, 366, 367,  48, 151,  77,  48,  48, 368, 369, 370, 371, 372,
+    48,  48, 373, 374, 375, 376,  48, 377,  48,  48,  48, 378, 379, 380, 381, 382,
+   383, 384, 316,  11,  11, 385, 386,  11,  11,  11,  11,  11,  48,  48, 387, 192,
+    48,  48, 388,  48, 389,  48,  48, 206, 390, 390, 390, 390, 390, 390, 390, 390,
+   391, 391, 391, 391, 391, 391, 391, 391,  48,  48,  48,  48,  48,  48, 204,  48,
+    48,  48,  48,  48,  48, 207,  72,  72, 392, 393, 394, 395, 396,  48,  48,  48,
+    48,  48,  48, 397, 398, 399,  48,  48,  48,  48,  48, 400,  72,  48,  48,  48,
+    48, 401,  48,  48,  74,  72,  72, 402,  32, 403,  32, 404, 405, 406, 407,  73,
+    48,  48,  48,  48,  48,  48,  48, 408, 409,   2,   3,   4,   5, 410, 411, 412,
+    48, 413,  48, 200, 414, 415, 416, 417, 418,  48, 172, 419, 204, 204,  72,  72,
+    48,  48,  48,  48,  48,  48,  48,  71, 420, 270, 270, 421, 271, 271, 271, 422,
+   423, 424, 425,  72,  72, 209, 209, 426,  72,  72,  72,  72,  72,  72,  72,  72,
+    48, 151,  48,  48,  48, 101, 427, 428,  48,  48, 429,  48, 430,  48,  48, 431,
+    48, 432,  48,  48, 433, 434,  72,  72,   9,   9, 435,  11,  11,  48,  48,  48,
+    48, 204, 192,   9,   9, 436,  11, 437,  48,  48,  74,  48,  48,  48, 438,  72,
+    48,  48,  48, 315,  48, 199,  74,  72, 439,  48,  48, 440,  48, 441,  48, 442,
+    48, 200, 443,  72,  72,  72,  48, 444,  48, 445,  48, 446,  72,  72,  72,  72,
+    48,  48,  48, 447, 270, 448, 270, 270, 449, 450,  48, 451, 452, 453,  48, 454,
+    48, 455,  72,  72, 456,  48, 457, 458,  48,  48,  48, 459,  48, 460,  48, 461,
+    48, 462, 463,  72,  72,  72,  72,  72,  48,  48,  48,  48, 196,  72,  72,  72,
+     9,   9,   9, 464,  11,  11,  11, 465,  48,  48, 466, 192,  72,  72,  72,  72,
+    72,  72,  72,  72,  72,  72, 270, 467,  48,  48, 468, 469,  72,  72,  72,  72,
+    48, 455, 470,  48,  62, 471,  72,  72,  72,  72,  72,  48, 472,  72,  48, 315,
+   473,  48,  48, 474, 475, 448, 476, 477, 222,  48,  48, 478, 479,  48, 196, 192,
+   480,  48, 481, 482, 483,  48,  48, 484, 222,  48,  48, 485, 486, 487, 488, 489,
+    48,  98, 490, 491,  72,  72,  72,  72, 492, 493, 494,  48,  48, 495, 496, 192,
+   497,  84,  85, 498, 499, 500, 501, 502,  48,  48,  48, 503, 504, 505, 469,  72,
+    48,  48,  48, 506, 507, 192,  72,  72,  48,  48, 508, 509, 510, 511,  72,  72,
+    48,  48,  48, 512, 513, 192, 514,  72,  48,  48, 515, 516, 192,  72,  72,  72,
+    48, 173, 517, 518,  72,  72,  72,  72,  48,  48, 490, 519,  72,  72,  72,  72,
+    72,  72,   9,   9,  11,  11, 148, 520, 521, 522,  48, 523, 524, 192,  72,  72,
+    72,  72, 525,  48,  48, 526, 527,  72, 528,  48,  48, 529, 530, 531,  48,  48,
+   532, 533, 534,  72,  48,  48,  48, 196,  85,  48, 508, 535, 536, 148, 175, 537,
+    48, 538, 539, 540,  72,  72,  72,  72, 541,  48,  48, 542, 543, 192, 544,  48,
+   545, 546, 192,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  48, 547,
+    72,  72,  72, 101, 270, 548, 549, 550,  48, 207,  72,  72,  72,  72,  72,  72,
+   271, 271, 271, 271, 271, 271, 551, 552,  48,  48,  48,  48, 388,  72,  72,  72,
+    48,  48, 200, 553,  72,  72,  72,  72,  48,  48,  48,  48, 315,  72,  72,  72,
+    48,  48,  48, 196,  48, 200, 370,  72,  72,  72,  72,  72,  72,  48, 204, 554,
+    48,  48,  48, 555, 556, 557, 558, 559,  48,  72,  72,  72,  72,  72,  72,  72,
+    72,  72,  72,  72,   9,   9,  11,  11, 270, 560,  72,  72,  72,  72,  72,  72,
+    48,  48,  48,  48, 561, 562, 563, 563, 564, 565,  72,  72,  72,  72, 566, 567,
+    48,  48,  48,  48,  48,  48,  48,  74,  48,  48,  48,  48,  48, 199,  72,  72,
+   196,  72,  72,  72,  72,  72,  72,  72,  48, 200,  72,  72,  72, 568, 569,  48,
+    48,  48,  48,  48,  48,  48,  48, 206,  48,  48,  48,  48,  48,  48,  71, 151,
+   196, 570, 571,  72,  72,  72,  72,  72, 209, 209, 209, 209, 209, 209, 209, 325,
+   209, 209, 572, 209, 209, 209, 573, 574, 575, 209, 576, 209, 209, 209, 577,  72,
+   209, 209, 209, 209, 578,  72,  72,  72,  72,  72,  72,  72,  72,  72, 270, 579,
+   209, 209, 209, 209, 209, 286, 270, 452,   9, 580,  11, 581, 582, 583, 242,   9,
+   584, 585, 586, 587, 588,   9, 580,  11, 589, 590,  11, 591, 592, 593, 594,   9,
+   595,  11,   9, 580,  11, 581, 582,  11, 242,   9, 584, 594,   9, 595,  11,   9,
+   580,  11, 596,   9, 597, 598, 599, 600,  11, 601,   9, 602, 603, 604, 605,  11,
+   606,   9, 607,  11, 608, 609, 609, 609,  32,  32,  32, 610,  32,  32, 611, 612,
+   613, 614,  45,  72,  72,  72,  72,  72, 615, 616, 617,  72,  72,  72,  72,  72,
+    48,  48, 151, 618, 619,  72,  72,  72,  72,  72,  72,  72,  48,  48, 620, 621,
+    48,  48,  48,  48, 622, 623,  72,  72,   9,   9, 584,  11, 624, 370,  72,  72,
+    72,  72,  72,  72,  72,  72,  72, 488, 270, 270, 625, 626,  72,  72,  72,  72,
+   488, 270, 627, 628,  72,  72,  72,  72, 629,  48, 630, 631, 632, 633, 634, 635,
+   636, 206, 637, 206,  72,  72,  72, 638, 209, 209, 326, 209, 209, 209, 209, 209,
+   209, 324, 335, 639, 639, 639, 209, 325, 640, 209, 209, 209, 209, 209, 209, 209,
+   209, 209, 641,  72,  72,  72, 642, 209, 643, 209, 209, 326, 577, 644, 325,  72,
+   209, 209, 209, 209, 209, 209, 209, 645, 209, 209, 209, 209, 209, 646, 424, 424,
+   209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 209, 209, 209, 577, 326,  72,
+   326, 209, 209, 209, 646, 176, 209, 209, 646, 209, 641, 644,  72,  72,  72,  72,
+   209, 209, 209, 209, 209, 209, 209, 647, 209, 209, 209, 209, 648, 209, 209, 209,
+   209, 209, 209, 209, 209, 324, 641, 649, 286, 209, 577, 286, 643, 286,  72,  72,
+   209, 650, 209, 209, 287,  72,  72, 192,  48,  48,  48,  48,  48, 204,  72,  72,
+    48,  48,  48, 205,  48,  48,  48,  48,  48, 204,  48,  48,  48,  48,  48,  48,
+    48,  48, 469,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48,  48, 101,  72,
+    48, 204,  72,  72,  72,  72,  72,  72,  48,  48,  48,  48,  71,  72,  72,  72,
+   651,  72, 652, 652, 652, 652, 652, 652,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  72, 391, 391, 391, 391, 391, 391, 391, 653,
+   391, 391, 391, 391, 391, 391, 391, 654,   0,   0,   0,   0,   0,   0,   0,   0,
+     1,   2,   2,   3,   1,   2,   2,   3,   0,   0,   0,   0,   0,   4,   0,   4,
+     2,   2,   5,   2,   2,   2,   5,   2,   2,   2,   2,   2,   2,   2,   2,   2,
+     2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   6,
+     0,   0,   0,   0,   7,   8,   0,   0,   9,   9,   9,   9,   9,   9,   9,   9,
+     9,   9,   9,   9,   9,   9,  10,  11,  12,  13,  14,  14,  15,  14,  14,  14,
+    14,  14,  14,  14,  16,  17,  14,  14,  18,  18,  18,  18,  18,  18,  18,  18,
+    18,  18,  18,  18,  18,  18,  18,  18,  19,  18,  18,  18,  18,  18,  18,  18,
+    18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  20,  21,
+    21,  21,  22,  20,  21,  21,  21,  21,  21,  23,  24,  25,  25,  25,  25,  25,
+    25,  26,  25,  25,  25,  27,  28,  26,  29,  30,  31,  32,  31,  31,  31,  31,
+    33,  34,  35,  31,  31,  31,  36,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+    31,  31,  31,  29,  31,  31,  31,  31,  37,  38,  37,  37,  37,  37,  37,  37,
+    37,  39,  31,  31,  31,  31,  31,  31,  40,  40,  40,  40,  40,  40,  41,  26,
+    42,  42,  42,  42,  42,  42,  42,  43,  44,  44,  44,  44,  44,  45,  44,  46,
+    47,  47,  47,  48,  37,  49,  26,  26,  26,  26,  26,  26,  31,  31,  50,  31,
+    31,  26,  51,  31,  52,  31,  31,  31,  53,  53,  53,  53,  53,  53,  53,  53,
+    53,  53,  54,  53,  55,  53,  53,  53,  56,  57,  58,  59,  59,  60,  61,  62,
+    57,  63,  64,  65,  66,  59,  59,  67,  68,  69,  70,  71,  71,  72,  73,  74,
+    69,  75,  76,  77,  78,  71,  79,  26,  80,  81,  82,  83,  83,  84,  85,  86,
+    81,  87,  88,  26,  89,  83,  90,  91,  92,  93,  94,  95,  95,  96,  97,  98,
+    93,  99, 100, 101, 102,  95,  95,  26, 103, 104, 105, 106, 107, 104, 108, 109,
+   104, 105, 110,  26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116,
+   114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126,
+   123, 127, 128, 129, 130, 122, 131,  26, 132, 133, 134, 132, 132, 132, 132, 132,
+   133, 134, 135, 132, 136, 132, 132, 132, 137, 138, 139, 140, 138, 138, 141, 142,
+   139, 143, 144, 138, 145, 138, 146,  26, 147, 148, 148, 148, 148, 148, 148, 149,
+   148, 148, 148, 150,  26,  26,  26,  26, 151, 152, 153, 153, 154, 153, 153, 155,
+   156, 155, 153, 157,  26,  26,  26,  26, 158, 158, 158, 158, 158, 158, 158, 158,
+   158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161,
+   158, 161, 162, 163,  26,  26,  26,  26, 164, 164, 164, 164, 164, 164, 164, 164,
+   164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165,
+   166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169,
+   169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170,
+   170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172,
+   171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170,
+   170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176,
+   176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178,
+   178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181,
+   181, 181, 181, 181, 181, 182, 181, 183, 184, 185, 186,  26, 187, 187, 188,  26,
+   189, 189, 190,  26, 191, 192, 193,  26, 194, 194, 194, 194, 194, 194, 194, 194,
+   194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 199, 200, 199, 199, 199, 199,
+   199, 199, 199, 199, 199, 199, 199, 201, 199, 199, 199, 199, 199, 202, 178, 178,
+   178, 178, 178, 178, 178, 178, 203,  26, 204, 204, 204, 205, 204, 206, 204, 206,
+   207, 204, 208, 208, 208, 209, 210,  26, 211, 211, 211, 211, 211, 212, 211, 211,
+   211, 213, 211, 214, 194, 194, 194, 194, 215, 215, 215, 216, 217, 217, 217, 217,
+   217, 217, 217, 218, 217, 217, 217, 219, 217, 220, 217, 220, 217, 221,   9,   9,
+   222,  26,  26,  26,  26,  26,  26,  26, 223, 223, 223, 223, 223, 223, 223, 223,
+   223, 224, 223, 223, 223, 223, 223, 225, 226, 226, 226, 226, 226, 226, 226, 226,
+   227, 227, 227, 227, 227, 227, 228, 229, 230, 230, 230, 230, 230, 230, 230, 231,
+   230, 232, 233, 233, 233, 233, 233, 233,  18, 234, 165, 165, 165, 165, 165, 235,
+   226,  26, 236,   9, 237, 238, 239, 240,   2,   2,   2,   2, 241, 242,   2,   2,
+     2,   2,   2, 243, 244, 245,   2, 246,   2,   2,   2,   2,   2,   2,   2, 247,
+     9,   9,   9,   9,   9,   9,   9, 248,  14,  14, 249, 249,  14,  14,  14,  14,
+   249, 249,  14, 250,  14,  14,  14, 249,  14,  14,  14,  14,  14,  14, 251,  14,
+   251,  14, 252, 253,  14,  14, 254, 255,   0, 256,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0, 257,   0, 258, 259,   0, 260,   2, 261,   0,   0,   0,   0,
+    26,  26,   9,   9,   9,   9, 222,  26,   0,   0,   0,   0, 262, 263,   4,   0,
+     0, 264,   0,   0,   2,   2,   2,   2,   2, 265,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 260,  26,  26,  26,
+     0, 266,  26,  26,   0,   0,   0,   0, 267, 267, 267, 267, 267, 267, 267, 267,
+   267, 267, 267, 267, 267, 267, 267, 267,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0, 268,   0,   0,   0, 269,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0, 270, 270, 270, 270, 270, 271, 270, 270,
+   270, 270, 270, 271,   2,   2,   2,   2,  17,  17,  17,  17,  17,  17,  17,  17,
+    17,  17,  17,  17,  17,  17, 272, 273, 165, 165, 165, 165, 166, 167, 274, 274,
+   274, 274, 274, 274, 274, 275, 276, 275, 170, 170, 172,  26, 172, 172, 172, 172,
+   172, 172, 172, 172,  18,  18,  18,  18,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 266,  26,  26,  26,  26,  26, 277, 277, 277, 278, 277, 277, 277, 277,
+   277, 277, 277, 277, 277, 277, 279,  26, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 280,  26,  26,  26,   0, 281, 282,   0,   0,   0, 283, 284,   0, 285,
+   286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291,
+   291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169,
+   169, 169, 169, 169, 169, 169, 169, 169, 169, 296,   0,   0, 294, 294, 294, 294,
+     0,   0,   0,   0, 281,  26, 291, 291, 169, 169, 169, 296,   0,   0,   0,   0,
+     0,   0,   0,   0, 169, 169, 169, 297,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291,
+   291, 291, 291,   0,   0,   0,   0,   0, 277, 277, 277, 277, 277, 277, 277, 277,
+     0,   0,   0,   0,   0,   0,   0,   0, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 277, 277, 277, 277, 299, 300, 300, 300, 300, 300, 300, 300, 300,
+   300, 300, 300, 300, 300, 300, 300, 300, 300, 301, 300, 300, 300, 300, 300, 300,
+   302,  26, 303, 303, 303, 303, 303, 303, 304, 304, 304, 304, 304, 304, 304, 304,
+   304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 305,  26,  26,
+    18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18,  18, 306, 306, 306, 306,
+   306, 306, 306, 306, 306, 306, 306,  26,   0,   0,   0,   0, 307,   2,   2,   2,
+     2,   2,   2,   2,   2,   2,   2,   2,   2, 308,   2,   2,   2,   2,   2,   2,
+   309, 310,  26,  26,  26,  26, 311,   2, 312, 312, 312, 312, 312, 313,   0, 314,
+   315, 315, 315, 315, 315, 315, 315,  26, 316, 316, 316, 316, 316, 316, 316, 316,
+   317, 318, 316, 319,  53,  53,  53,  53, 320, 320, 320, 320, 320, 321, 322, 322,
+   322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326,
+   326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331,  26,
+   330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334,
+   335,  26,  26, 336, 337, 337, 338,  26, 339, 339, 339,  26, 172, 172,   2,   2,
+     2,   2,   2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176,
+   337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345,  26, 169, 169,
+   296, 346, 169, 169, 169, 169, 169, 345,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 347,  26,  26,  26,  26, 348,  26, 349, 350,  25,  25, 351, 352,
+   353,  25,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+   354,  26,  51,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+    31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31,  31, 355,
+    26,  26,  31,  31,  31,  31,  31,  31,  31,  31, 356,  31,  31,  31,  31,  31,
+    31,  26,  26,  26,  26,  26,  31, 357,   9,   9,   0, 314,   9, 358,   0,   0,
+     0,   0, 359,   0, 260, 281,  50,  31,  31,  31,  31,  31,  31,  31,  31,  31,
+    31,  31,  31,  31,  31,  31,  31, 360, 361,   0,   0,   0,   1,   2,   2,   3,
+     1,   2,   2,   3, 362, 291, 290, 291, 291, 291, 291, 363, 169, 169, 169, 296,
+   364, 364, 364, 365, 260, 260,  26, 366, 367, 368, 367, 367, 369, 367, 367, 370,
+   367, 371, 367, 371,  26,  26,  26,  26, 367, 367, 367, 367, 367, 367, 367, 367,
+   367, 367, 367, 367, 367, 367, 367, 372, 373,   0,   0,   0,   0,   0, 374,   0,
+    14,  14,  14,  14,  14,  14,  14,  14,  14, 255,   0, 375, 376,  26,  26,  26,
+    26,  26,   0,   0,   0,   0,   0, 377, 378, 378, 378, 379, 380, 380, 380, 380,
+   380, 380, 381,  26, 382,   0,   0, 281, 383, 383, 383, 383, 384, 385, 386, 386,
+   386, 387, 388, 388, 388, 388, 388, 389, 390, 390, 390, 391, 392, 392, 392, 392,
+   393, 392, 394,  26,  26,  26,  26,  26, 395, 395, 395, 395, 395, 395, 395, 395,
+   395, 395, 396, 396, 396, 396, 396, 396, 397, 397, 397, 398, 397, 399, 400, 400,
+   400, 400, 401, 400, 400, 400, 400, 401, 402, 402, 402, 402, 402,  26, 403, 403,
+   403, 403, 403, 403, 404, 405,  26,  26, 406, 406, 406, 406, 406, 406, 406, 406,
+   406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 407,  26,
+   406, 406, 408,  26, 406,  26,  26,  26, 409, 410, 411, 411, 411, 411, 412, 413,
+   414, 414, 415, 414, 416, 416, 416, 416, 417, 417, 417, 418, 419, 417,  26,  26,
+    26,  26,  26,  26, 420, 420, 421, 422, 423, 423, 423, 424, 425, 425, 425, 426,
+    26,  26,  26,  26,  26,  26,  26,  26, 427, 427, 427, 427, 428, 428, 428, 429,
+   428, 428, 430, 428, 428, 428, 428, 428, 431, 432, 433, 434, 435, 435, 436, 437,
+   435, 438, 435, 438, 439, 439, 439, 439, 440, 440, 440, 440,  26,  26,  26,  26,
+   441, 441, 441, 441, 442, 443, 442,  26, 444, 444, 444, 444, 444, 444, 445, 446,
+   447, 447, 448, 447, 449, 449, 450, 449, 451, 451, 452, 453,  26, 454,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 455, 455, 455, 455, 455, 455, 455, 455,
+   455, 456,  26,  26,  26,  26,  26,  26, 457, 457, 457, 457, 457, 457, 458,  26,
+   457, 457, 457, 457, 457, 457, 458, 459, 460, 460, 460, 460, 460,  26, 460, 461,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  31,  31,  31, 462, 463, 463, 463, 463, 463, 464, 465,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 466, 466, 466, 466, 466,  26, 467, 467,
+   467, 467, 467, 468,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 469, 469,
+   469, 470,  26,  26, 471, 471, 472,  26, 473, 473, 473, 473, 473, 473, 473, 473,
+   473, 474, 475, 473, 473, 473,  26, 476, 477, 477, 477, 477, 477, 477, 477, 477,
+   478, 479, 480, 480, 480, 481, 480, 482, 483, 483, 483, 483, 483, 483, 484, 483,
+   483,  26, 485, 485, 485, 485, 486,  26, 487, 487, 487, 487, 487, 487, 487, 487,
+   487, 487, 487, 487, 488, 138, 489,  26, 490, 490, 491, 490, 490, 490, 490, 492,
+    26,  26,  26,  26,  26,  26,  26,  26, 493, 494, 495, 496, 495, 497, 498, 498,
+   498, 498, 498, 498, 498, 499, 498, 500, 501, 502, 503, 504, 504, 505, 506, 507,
+   502, 508, 509, 510, 511, 512, 512,  26, 513, 513, 513, 513, 513, 513, 513, 513,
+   513, 513, 513, 514, 515,  26,  26,  26, 516, 516, 516, 516, 516, 516, 516, 516,
+   516,  26, 516, 517,  26,  26,  26,  26, 518, 518, 518, 518, 518, 518, 519, 518,
+   518, 518, 518, 519,  26,  26,  26,  26, 520, 520, 520, 520, 520, 520, 520, 520,
+   521,  26, 520, 522, 199, 523,  26,  26, 524, 524, 524, 524, 524, 524, 524, 525,
+   524, 526,  26,  26,  26,  26,  26,  26, 527, 527, 527, 528, 527, 529, 527, 527,
+    26,  26,  26,  26,  26,  26,  26,  26, 530, 530, 530, 530, 530, 530, 530, 531,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26, 532, 532, 532, 532,
+   532, 532, 532, 532, 532, 532, 533, 534, 535, 536, 537, 538, 538, 538, 539, 540,
+   535,  26, 538, 541,  26,  26,  26,  26,  26,  26,  26,  26, 542, 543, 542, 542,
+   542, 542, 542, 543, 544,  26,  26,  26, 545, 545, 545, 545, 545, 545, 545, 545,
+   545,  26, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 547,  26,  26,  26,
+   548, 548, 548, 548, 548, 548, 548, 549, 550, 551, 550, 550, 550, 550, 552, 550,
+   553,  26, 550, 550, 550, 554, 555, 555, 555, 555, 556, 555, 555, 557, 558,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 559, 560, 561, 561, 561, 561, 559, 562,
+   561,  26, 561, 563, 564, 565, 566, 566, 566, 567, 568, 569, 566, 570,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26, 571, 571, 571, 572,  26,  26,  26,  26,  26,  26, 573,  26,
+   108, 108, 108, 108, 108, 108, 574, 575, 576, 576, 576, 576, 576, 576, 576, 576,
+   576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 577,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 576, 576, 576, 576, 576, 576, 576, 576,
+   576, 576, 576, 576, 576, 578, 579,  26, 576, 576, 576, 576, 576, 576, 576, 576,
+   580,  26,  26,  26,  26,  26,  26,  26, 581, 581, 581, 581, 581, 581, 581, 581,
+   581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 582, 581, 583,
+    26,  26,  26,  26,  26,  26,  26,  26, 584, 584, 584, 584, 584, 584, 584, 584,
+   584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584,
+   585,  26,  26,  26,  26,  26,  26,  26, 306, 306, 306, 306, 306, 306, 306, 306,
+   306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 586,
+   587, 587, 587, 588, 587, 589,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26, 590, 590, 590, 591, 591,  26, 592, 592, 592, 592, 592, 592, 592, 592,
+   593,  26, 592, 594, 594, 592, 592, 595, 592, 592,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 597,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 598, 598, 598, 598, 598, 598, 598, 598,
+   598, 599, 598, 598, 598, 598, 598, 598, 598, 600, 598, 598,  26,  26,  26,  26,
+    26,  26,  26,  26, 601,  26, 347,  26, 602, 602, 602, 602, 602, 602, 602, 602,
+   602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602,
+   602, 602, 602, 602, 602, 602, 602,  26, 603, 603, 603, 603, 603, 603, 603, 603,
+   603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603,
+   603, 603, 604,  26,  26,  26,  26,  26, 602, 605,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 606, 287, 287, 287, 287, 287, 287, 287,
+   287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287,
+   287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288,  26,  26,  26,  26,
+    26,  26, 607,  26, 608,  26, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609,
+   609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609,
+   609, 609, 609, 609, 609, 609, 609, 610, 611, 611, 611, 611, 611, 611, 611, 611,
+   611, 611, 611, 611, 611, 612, 611, 613, 611, 614, 611, 615, 281,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0, 616,  26,   0,   0,   0,   0, 260, 361,   0,   0,
+     0,   0,   0,   0, 617, 618,   0, 619, 620, 621,   0,   0,   0, 622,   0,   0,
+     0,   0,   0,   0,   0, 623,  26,  26,  14,  14,  14,  14,  14,  14,  14,  14,
+   249,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,   0,   0, 281,  26,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 260,  26,   0,   0,   0, 623,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 257,   0,   0,   0,   0,   0,   0,   0,   0, 257, 624, 625,   0, 626,
+   627,   0,   0,   0,   0,   0,   0,   0, 269, 628, 257, 257,   0,   0,   0, 629,
+   630, 631, 632,   0,   0,   0,   0,   0,   0,   0,   0,   0, 616,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0, 268,   0,   0,   0,   0,   0,   0, 633, 633, 633, 633, 633, 633, 633, 633,
+   633, 633, 633, 633, 633, 633, 633, 633, 633, 634,  26, 635, 636, 633,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 271, 270, 270, 637, 638, 639,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 640, 640, 640, 640, 640, 641, 640, 642,
+   640, 643,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+   644, 644, 644, 644, 644, 644, 644, 645, 646, 646, 646, 646, 646, 646, 646, 646,
+   646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646,
+   647, 646, 648,  26,  26,  26,  26,  26, 649, 649, 649, 649, 649, 649, 649, 649,
+   649, 650, 649, 651,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26, 361,   0,   0,   0,   0,   0,   0,   0, 375,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 361,   0,   0,   0,   0,   0,   0, 616,
+    26,  26,  26,  26,  26,  26,  26,  26, 652,  31,  31,  31, 653, 654, 655, 656,
+   657, 658, 653, 659, 653, 655, 655, 660,  31, 661,  31, 662, 663, 661,  31, 662,
+    26,  26,  26,  26,  26,  26, 354,  26,   0,   0,   0,   0,   0, 281,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 281,  26,   0, 260, 361,   0,
+   361,   0, 361,   0,   0,   0, 616,  26,   0,   0,   0,   0,   0, 616,  26,  26,
+    26,  26,  26,  26, 664,   0,   0,   0, 665,  26,   0,   0,   0,   0,   0, 281,
+     0, 623, 314,  26, 616,  26,  26,  26,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,  26,   0, 375,   0, 375,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0, 281,  26,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0, 623,   0, 281,  26,  26,   0, 281,   0,   0,   0,   0,   0,   0,
+     0,  26,   0, 314,   0,   0,   0,   0,   0,  26,   0,   0,   0, 616, 314,  26,
+    26,  26,  26,  26,  26,  26,  26,  26,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0, 632,   0,   0,   0,   0,   0,   0,   0,   0,
+     0, 627,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0, 281,  26,   0, 616, 375, 266, 260,  26,   0,   0,   0, 623, 260,  26,
+   266,  26, 260,  26,  26,  26,  26,  26,   0,   0, 359,   0,   0,   0,   0,   0,
+     0, 266,  26,  26,  26,  26,   0, 314, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 280,  26,  26,  26,  26, 277, 277, 277, 277, 277, 277, 299,  26,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347,  26, 277, 277,
+   277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 277, 277, 277, 666,  26,  26,  26, 277, 277, 277, 280,  26,  26,  26,  26,
+    26,  26,  26,  26,  26,  26,  26,  26, 277, 277, 277, 277, 277, 277, 277, 277,
+   277, 667,  26,  26,  26,  26,  26,  26, 668,  26,  26,  26,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   9,   9,   9,   9,   9,   9,   9,   9,
+     9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,   9,
+     9,   9,   9,   9,   9,   9,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0, 939, 940, 941, 942, 946, 948,   0, 962,
+   969, 970, 971, 976,1001,1002,1003,1008,   0,1033,1040,1041,1042,1043,1047,   0,
+     0,1080,1081,1082,1086,1110,   0,   0,1124,1125,1126,1127,1131,1133,   0,1147,
+  1154,1155,1156,1161,1187,1188,1189,1193,   0,1219,1226,1227,1228,1229,1233,   0,
+     0,1267,1268,1269,1273,1298,   0,1303, 943,1128, 944,1129, 954,1139, 958,1143,
+   959,1144, 960,1145, 961,1146, 964,1149,   0,   0, 973,1158, 974,1159, 975,1160,
+   983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179,   0,   0,
+  1004,1190,1005,1191,1006,1192,1014,1199,1007,   0,   0,   0,1016,1201,1020,1206,
+     0,1022,1208,1025,1211,1023,1209,   0,   0,   0,   0,1032,1218,1037,1223,1035,
+  1221,   0,   0,   0,1044,1230,1045,1231,1049,1235,   0,   0,1058,1244,1064,1250,
+  1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261,   0,   0,
+  1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299,
+  1115,1118,1307,1120,1309,1121,1310,   0,1053,1239,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,1093,1280,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340,
+  1367,1342,1369,1339,1366,   0,1320,1347,1418,1419,1323,1350,   0,   0, 992,1177,
+  1018,1204,1055,1241,1416,1417,1415,1424,1202,   0,   0,   0, 987,1172,   0,   0,
+  1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165,
+  1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279,
+  1071,1257,1076,1263,   0,   0, 997,1182,   0,   0,   0,   0,   0,   0, 945,1130,
+   982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   8,   9,   0,  10,1425,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   7,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,1314,1427,   5,
+  1434,1438,1443,   0,1450,   0,1455,1461,1514,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1446,1458,1468,1476,1480,1486,1517,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1489,1503,1494,1500,1508,   0,   0,   0,   0,1520,1521,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1526,1528,   0,1525,   0,   0,   0,1522,
+     0,   0,   0,   0,1536,1532,1539,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1534,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1556,   0,   0,   0,   0,   0,   0,1548,1550,   0,1547,   0,   0,   0,1567,
+     0,   0,   0,   0,1558,1554,1561,   0,   0,   0,   0,   0,   0,   0,1568,1569,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1529,1551,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1523,1545,1524,1546,   0,   0,1527,1549,
+     0,   0,1570,1571,1530,1552,1531,1553,   0,   0,1533,1555,1535,1557,1537,1559,
+     0,   0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564,   0,   0,
+  1543,1565,   0,   0,   0,   0,   0,   0,   0,   0,1606,1607,1609,1608,1610,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1613,   0,1611,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1612,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1620,   0,   0,   0,   0,   0,   0,   0,1623,   0,   0,1624,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1614,1615,1616,1617,1618,1619,1621,1622,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1628,1629,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1625,1626,   0,1627,   0,   0,   0,1634,   0,   0,1635,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1630,1631,1632,   0,   0,1633,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1639,   0,   0,1638,1640,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1636,1637,   0,   0,   0,   0,   0,   0,1641,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1642,1644,1643,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1645,   0,   0,   0,   0,   0,   0,   0,1646,   0,   0,   0,   0,   0,   0,1648,
+  1649,   0,1647,1650,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1651,1653,1652,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1654,   0,1655,1657,1656,   0,   0,   0,   0,1659,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1660,   0,   0,   0,   0,1661,   0,   0,   0,   0,1662,
+     0,   0,   0,   0,1663,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1658,   0,   0,   0,   0,   0,   0,   0,   0,   0,1664,   0,1665,1673,   0,
+  1674,   0,   0,   0,   0,   0,   0,   0,   0,1666,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1668,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1669,   0,   0,   0,   0,1670,   0,   0,   0,   0,1671,
+     0,   0,   0,   0,1672,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1667,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1675,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1676,   0,
+  1677,   0,1678,   0,1679,   0,1680,   0,   0,   0,1681,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1682,   0,1683,   0,   0,1684,1685,   0,1686,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0, 953,1138, 955,1140, 956,1141, 957,1142,
+  1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381,
+   984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181,
+   999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210,
+  1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222,
+  1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243,
+  1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389,
+  1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284,
+  1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291,
+  1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260,
+  1293,1305,   0,1394,   0,   0,   0,   0, 952,1137, 947,1132,1317,1344,1316,1343,
+  1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696,
+   981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698,
+  1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359,
+  1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274,
+  1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304,
+  1112,1300,   0,   0,   0,   0,   0,   0,1471,1472,1701,1705,1702,1706,1703,1707,
+  1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732,   0,   0,
+  1435,1436,1733,1735,1734,1736,   0,   0,1481,1482,1737,1741,1738,1742,1739,1743,
+  1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770,
+  1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780,   0,   0,
+  1451,1452,1781,1783,1782,1784,   0,   0,1504,1505,1785,1788,1786,1789,1787,1790,
+     0,1459,   0,1791,   0,1792,   0,1793,1509,1510,1794,1798,1795,1799,1796,1800,
+  1462,1463,1808,1812,1809,1813,1810,1814,1467,  21,1475,  22,1479,  23,1485,  24,
+  1493,  27,1499,  28,1507,  29,   0,   0,1704,1708,1709,1710,1711,1712,1713,1714,
+  1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750,
+  1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807,
+  1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465,   0,1473,1825,
+  1429,1428,1426,  12,1432,   0,  26,   0,   0,1315,1823,1484,1466,   0,1483,1829,
+  1433,  13,1437,  14,1441,1826,1827,1828,1488,1487,1513,  19,   0,   0,1492,1515,
+  1445,1444,1442,  15,   0,1831,1832,1833,1502,1501,1516,  25,1497,1498,1506,1518,
+  1457,1456,1454,  17,1453,1313,  11,   3,   0,   0,1824,1512,1519,   0,1511,1830,
+  1449,  16,1460,  18,1464,   4,   0,   0,  30,  31,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  20,   0,
+     0,   0,   2,   6,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1834,1835,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1836,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1837,1839,1838,   0,   0,   0,   0,1840,   0,   0,   0,
+     0,1841,   0,   0,1842,   0,   0,   0,   0,   0,   0,   0,1843,   0,1844,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1845,   0,   0,1846,   0,   0,1847,
+     0,1848,   0,   0,   0,   0,   0,   0, 937,   0,1850,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1849, 936, 938,1851,1852,   0,   0,1853,1854,   0,   0,
+  1855,1856,   0,   0,   0,   0,   0,   0,1857,1858,   0,   0,1861,1862,   0,   0,
+  1863,1864,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1867,1868,1869,1870,1859,1860,1865,1866,   0,   0,   0,   0,
+     0,   0,1871,1872,1873,1874,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,  32,  33,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1875,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1877,   0,1878,   0,1879,   0,1880,   0,1881,   0,1882,   0,
+  1883,   0,1884,   0,1885,   0,1886,   0,1887,   0,1888,   0,   0,1889,   0,1890,
+     0,1891,   0,   0,   0,   0,   0,   0,1892,1893,   0,1894,1895,   0,1896,1897,
+     0,1898,1899,   0,1900,1901,   0,   0,   0,   0,   0,   0,1876,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1902,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,1904,   0,1905,   0,1906,   0,1907,   0,1908,   0,1909,   0,
+  1910,   0,1911,   0,1912,   0,1913,   0,1914,   0,1915,   0,   0,1916,   0,1917,
+     0,1918,   0,   0,   0,   0,   0,   0,1919,1920,   0,1921,1922,   0,1923,1924,
+     0,1925,1926,   0,1927,1928,   0,   0,   0,   0,   0,   0,1903,   0,   0,1929,
+  1930,1931,1932,   0,   0,   0,1933,   0, 710, 385, 724, 715, 455, 103, 186, 825,
+   825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500,
+   649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679,
+   293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722,
+   781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540,
+   714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589,
+   648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101,
+   430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110,
+   135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801,
+   812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610,
+   726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494,
+   113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748,
+   774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161,
+   395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727,
+   305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684,
+   687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566,
+   568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729,
+   680, 767, 694, 295, 128, 210,   0,   0, 227,   0, 379,   0,   0, 150, 493, 525,
+   544, 551, 552, 556, 783, 576, 604,   0, 661,   0, 703,   0,   0, 735, 743,   0,
+     0,   0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213,
+   215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458,
+   477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591,
+   593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735,
+   777, 786, 790, 315, 869, 623,   0,   0, 102, 145, 134, 115, 129, 138, 165, 171,
+   207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325,
+   321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438,
+   456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526,
+   528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693,
+   695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777,
+   783, 784, 786, 787, 790, 802, 825, 848, 847, 857,  55,  65,  66, 883, 892, 916,
+   822, 824,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,1586,   0,1605,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584,   0,
+  1585,1587,1588,1589,1591,   0,1592,   0,1593,1594,   0,1595,1596,   0,1598,1599,
+  1600,1601,1604,1582,1578,1590,1597,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1936,   0,1937,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1938,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1939,1940,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1941,1942,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1944,1943,   0,1945,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,1946,1947,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1948,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1949,1950,1951,1952,1953,1954,1955,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1956,1957,1958,1960,1959,1961,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0, 106, 104, 107, 826, 114, 118, 119, 121,
+   123, 124, 127, 125,  34, 830, 130, 131, 132, 137, 827,  35, 133, 139, 829, 142,
+   143, 112, 144, 145, 924, 151, 152,  37, 157, 158, 159, 160,  38, 165, 166, 169,
+   171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185,
+   834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206,
+   208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224,
+   230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251,  39,
+    40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264,  41, 266,
+   270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282,  42, 283, 284, 285, 286,
+    43, 843,  44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300,  45, 852,
+   894, 302, 304,  46, 306, 309, 310, 312, 316,  48,  47, 317, 846, 318, 323, 324,
+   325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351,
+   849, 350, 348, 352, 354, 359, 850, 361, 358, 356,  49, 363, 365, 367, 364,  50,
+   369, 371, 851, 376, 386, 378,  53, 381,  52,  51, 140, 141, 387, 382, 614,  78,
+   388, 389, 390, 394, 392, 856,  54, 399, 396, 402, 404, 858, 405, 401, 407,  55,
+   408, 409, 410, 413, 859, 415,  56, 417, 860, 418,  57, 419, 422, 424, 425, 861,
+   840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436,
+   449, 450,  58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464,  59, 467,
+   470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873,
+   495, 497,  60, 498,  61,  61, 504, 505, 507, 508, 511,  62, 513, 874, 515, 875,
+   518, 844, 520, 876, 877, 878,  63,  64, 528, 880, 879, 881, 882, 530, 531, 531,
+   533,  66, 534,  67,  68, 884, 536, 538, 541,  69, 885, 549, 886, 887, 556, 559,
+    70, 561, 562, 563, 888, 889, 889, 567,  71, 890, 570, 571,  72, 891, 577,  73,
+   581, 579, 582, 893, 587,  74, 590, 592, 596,  75, 895, 896,  76, 897, 600, 898,
+   602, 605, 607, 899, 900, 609, 901, 611, 853,  77, 615, 616,  79, 617, 252, 902,
+   903, 854, 855, 621, 622, 731,  80, 627, 626, 628, 164, 629, 630, 631, 633, 904,
+   632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906,  81,
+   653, 654, 656, 911, 657, 908,  82,  83, 909, 910,  84, 664, 665, 666, 667, 669,
+   668, 671, 670, 674, 672, 673, 675,  85, 677, 678,  86, 681, 682, 912, 685, 686,
+    87, 689,  36, 913, 914,  88,  89, 696, 702, 709, 711, 915, 712, 713, 718, 719,
+   917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753,
+   756, 757, 755, 760, 761, 921, 762,  90, 764, 922,  91, 775, 279, 780, 923, 925,
+    92,  93, 785, 926,  94, 927, 787, 787, 789, 928, 792,  95, 796, 797, 798, 800,
+    96, 929, 802, 804, 806,  97,  98, 807, 930,  99, 931, 932, 933, 814, 100, 816,
+   817, 818, 819, 820, 821, 935,   0,   0,
+};
+static const int16_t
+_hb_ucd_i16[196] =
+{
+      0,    0,    0,    0,    1,   -1,    0,    0,    2,    0,   -2,    0,    0,    0,    0,    2,
+      0,   -2,    0,    0,    0,    0,    0,   16,    0,    0,    0,  -16,    0,    0,    1,   -1,
+      0,    0,    0,    1,   -1,    0,    0,    0,    0,    1,   -1,    0,    3,    3,    3,   -3,
+     -3,   -3,    0,    0,    0, 2016,    0,    0,    0,    0,    0, 2527, 1923, 1914, 1918,    0,
+   2250,    0,    0,    0,    0,    0,    0,  138,    0,    7,    0,    0,   -7,    0,    0,    0,
+      1,   -1,    1,   -1,   -1,    1,   -1,    0, 1824,    0,    0,    0,    0,    0, 2104,    0,
+   2108, 2106,    0, 2106, 1316,    0,    0,    0,    0,    1,   -1,    1,   -1, -138,    0,    0,
+      1,   -1,    8,    8,    8,    0,    7,    7,    0,    0,   -8,   -8,   -8,   -7,   -7,    0,
+      1,   -1,    0,    2,-1316,    1,   -1,    0,   -1,    1,   -1,    1,   -1,    3,    1,   -1,
+     -3,    1,   -1,    1,   -1,    0,    0,-1914,-1918,    0,    0,-1923,-1824,    0,    0,    0,
+      0,-2016,    0,    0,    1,   -1,    0,    1,    0,    0,-2104,    0,    0,    0,    0,-2106,
+  -2108,-2106,    0,    0,    1,   -1,-2250,    0,    0,    0,-2527,    0,    0,   -2,    0,    1,
+     -1,    0,    1,   -1,
+};
+
+static inline uint_fast8_t
+_hb_ucd_gc (unsigned u)
+{
+  return u<1114110u?_hb_ucd_u8[6504+(((_hb_ucd_u8[1264+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+}
+static inline uint_fast8_t
+_hb_ucd_ccc (unsigned u)
+{
+  return u<125259u?_hb_ucd_u8[8768+(((_hb_ucd_u8[7792+(((_hb_ucd_u8[7120+(((_hb_ucd_u8[6874+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0;
+}
+static inline unsigned
+_hb_ucd_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline int_fast16_t
+_hb_ucd_bmg (unsigned u)
+{
+  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9508+(((_hb_ucd_u8[9388+(((_hb_ucd_b4(9260+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+}
+static inline uint_fast8_t
+_hb_ucd_sc (unsigned u)
+{
+  return u<918000u?_hb_ucd_u8[10974+(((_hb_ucd_u16[1960+(((_hb_ucd_u8[10286+(((_hb_ucd_u8[9836+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+}
+static inline uint_fast16_t
+_hb_ucd_dm (unsigned u)
+{
+  return u<195102u?_hb_ucd_u16[5768+(((_hb_ucd_u8[16708+(((_hb_ucd_u8[16326+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+}
+
+
+#else
+
+static const uint8_t
+_hb_ucd_u8[13344] =
+{
+    0,  1,  2,  3,  4,  5,  5,  5,  5,  5,  6,  5,  5,  7,  8,  9,
+   10, 11, 12, 13, 14, 15, 16,  5, 17, 15, 15, 18, 15, 19, 20, 21,
+    5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 22, 23,
+    5, 24, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+   25, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+   32, 33, 34, 34, 34, 34, 35, 36, 37, 34, 34, 34, 38, 39, 40, 41,
+   42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+   58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 67, 68, 69, 67, 70, 71,
+   67, 67, 62, 72, 62, 62, 73, 67, 74, 75, 76, 77, 78, 67, 67, 67,
+   79, 80, 34, 81, 82, 83, 67, 67, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 84, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   85, 34, 34, 34, 34, 34, 34, 34, 34, 86, 34, 34, 87, 88, 89, 90,
+   91, 92, 93, 94, 95, 96, 97, 98, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
+  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
+  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
+  100,100, 34, 34, 34, 34,101,102, 34, 34,103,104,105,106,107,108,
+   34, 34,109,110,111,112,113,114,115,116,117,111, 34, 34, 34,111,
+  118,119,120,121,122,123,124,125, 34,126,127,111,128,129,130,131,
+  132,133,134,135,136,137,138,111,139,140,111,141,142,143,144,111,
+  145,146,147,148,149,150,111,111,151,152,153,154,111,155,111,156,
+   34, 34, 34, 34, 34, 34, 34, 34,157, 34, 34,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34, 34, 34,158,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34,159,160,161, 34,111,111,111,111,162,163,164,165,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111, 34,166,111,111,111,111,111,111,
+   67, 67,167,168,169,128, 65,111,170,171,172,173,174,175,176,177,
+   67, 67, 67, 67,178,179,111,111,111,111,111,111,111,111,111,111,
+  180,111,181,111,111,182,111,111,111,111,111,111,111,111,111,111,
+   34,183,184,111,111,111,111,111,128,185,186,111, 34,187,111,111,
+   67, 67,188, 67, 67,111, 67,189, 67, 67, 67, 67, 67, 67, 67, 67,
+   67, 67, 67, 67, 67, 67, 67,190,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+   34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111,
+   34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+  191,111,180,180,111,111,111,111,111,111,111,111,111,111,111,111,
+  111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+    0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  2,  4,  5,  6,  2,
+    7,  7,  7,  7,  7,  2,  8,  9, 10, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 17, 18, 19,  1, 20, 20, 21, 22, 23, 24, 25,
+   26, 27, 15,  2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32,
+   32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11,
+   11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11,
+   34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34,
+   34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32,
+   32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32,
+   16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40,
+   40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41,
+   40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41,
+   43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 16, 44, 16, 10,
+   41, 41, 41, 45, 11, 11, 11, 11, 34, 11, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34,
+   16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 46, 34, 32, 34, 11,
+   32, 47, 43, 43, 48, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+   11, 11, 11, 11, 49,  2,  2,  2, 16, 16, 16, 16, 50, 51, 52, 53,
+   54, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 55,
+   56, 57, 43, 56, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 36, 36,
+   36, 58,  2,  2,  2,  2,  2,  2, 59, 59, 59,  8,  9, 60,  2, 61,
+   43, 43, 43, 43, 43, 57, 59,  2, 62, 36, 36, 36, 36, 63, 43, 43,
+    7,  7,  7,  7,  7,  2,  2, 36, 64, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 65, 43, 43, 43, 66, 47, 43, 43, 67, 68, 69, 43, 43, 36,
+    7,  7,  7,  7,  7, 36, 70, 71,  2,  2,  2,  2,  2,  2,  2, 72,
+   63, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 64, 36,
+   36, 36, 36, 43, 43, 43, 43, 43,  7,  7,  7,  7,  7, 36, 36, 36,
+   36, 36, 36, 36, 36, 63, 43, 43, 43, 43, 40, 21,  2, 40, 68, 20,
+   36, 36, 36, 43, 43, 68, 43, 43, 43, 43, 68, 43, 68, 43, 43, 43,
+    2,  2,  2,  2,  2,  2,  2,  2, 36, 36, 36, 36, 63, 43, 43,  2,
+   36, 63, 43, 43, 43, 43, 43, 43, 43, 73, 43, 43, 43, 43, 43, 43,
+   43, 74, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 74, 64, 75,
+   76, 43, 43, 43, 74, 75, 76, 75, 63, 43, 43, 43, 36, 36, 36, 36,
+   36, 43,  2,  7,  7,  7,  7,  7, 77, 36, 36, 36, 36, 36, 36, 36,
+   63, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 75,
+   76, 43, 43, 74, 75, 75, 76, 36, 36, 36, 36, 79, 75, 75, 36, 36,
+   36, 43, 43,  7,  7,  7,  7,  7, 36, 20, 27, 27, 27, 53, 58, 43,
+   43, 74, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 75,
+   76, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 64, 36, 36, 36,
+   36, 36, 36,  7,  7,  7,  7,  7, 43, 36, 63,  2,  2,  2,  2,  2,
+   76, 43, 43, 43, 74, 75, 76, 43, 60, 20, 20, 20, 80, 43, 43, 43,
+   43, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 76,
+   76, 43, 43, 74, 75, 75, 76, 43, 43, 43, 43, 74, 75, 75, 36, 36,
+   71, 27, 27, 27, 27, 27, 27, 27, 43, 64, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 75, 74, 75, 75, 75, 75, 75, 76, 43,
+   36, 36, 36, 79, 75, 75, 75, 75, 75, 75, 75,  7,  7,  7,  7,  7,
+   27, 81, 61, 61, 53, 61, 61, 61, 74, 75, 64, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36, 43, 74, 75, 75, 43, 43, 43, 43, 43,
+   43, 43, 43, 43, 36, 36, 36, 36,  7,  7,  7, 82, 27, 27, 27, 81,
+   63, 75, 65, 36, 36, 36, 36, 36, 75, 75, 75, 74, 75, 75, 43, 43,
+   43, 43, 74, 75, 75, 75, 75, 36, 83, 36, 36, 36, 36, 36, 36, 36,
+   43, 75, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 64, 75,
+   76, 43, 43, 75, 75, 75, 76, 70, 61, 61, 36, 79, 27, 27, 27, 84,
+   27, 27, 27, 27, 81, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 74,
+   75, 43, 43, 43, 75, 75, 75, 75,  7, 75,  2,  2,  2,  2,  2,  2,
+   63, 36, 43, 43, 43, 43, 43, 85, 36, 36, 36, 68, 43, 43, 43, 57,
+    7,  7,  7,  7,  7,  2,  2,  2, 63, 36, 43, 43, 43, 43, 64, 36,
+   36, 36, 36, 40, 43, 43, 43, 43,  7,  7,  7,  7,  7,  7, 36, 36,
+   70, 61,  2,  2,  2,  2,  2,  2,  2, 86, 86, 61, 43, 61, 61, 61,
+    7,  7,  7,  7,  7, 27, 27, 27, 27, 27, 47, 47, 47,  4,  4, 75,
+   63, 43, 43, 43, 43, 43, 43, 74, 43, 43, 57, 43, 36, 36, 63, 43,
+   43, 43, 43, 43, 43, 43, 43, 61, 61, 61, 61, 69, 61, 61, 61, 61,
+    2,  2, 86, 61, 21,  2,  2,  2, 36, 36, 36, 36, 36, 79, 76, 43,
+   74, 43, 43, 43, 76, 74, 76, 64, 36, 36, 36, 75, 43, 36, 36, 43,
+   64, 75, 78, 79, 75, 75, 75, 36, 63, 43, 64, 36, 36, 36, 36, 36,
+   36, 74, 76, 74, 75, 75, 76, 79,  7,  7,  7,  7,  7, 75, 76, 61,
+   16, 16, 16, 16, 16, 50, 44, 16, 36, 36, 36, 36, 36, 36, 63, 43,
+    2,  2,  2,  2, 87, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+   61, 61, 61, 61, 61, 61, 61, 61, 11, 11, 11, 11, 16, 16, 16, 16,
+   88, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 65,
+   89, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 90, 91, 91,
+   36, 36, 36, 36, 36, 58,  2, 92, 93, 36, 36, 36, 36, 36, 36, 36,
+   36, 43, 43, 43, 43, 43, 43, 43, 36, 43, 57,  2,  2,  2,  2,  2,
+   36, 36, 43, 76, 43, 43, 43, 75, 75, 75, 75, 74, 76, 43, 43, 43,
+   43, 43,  2, 77,  2, 60, 63, 43,  7,  7,  7,  7,  7,  7,  7,  7,
+    2,  2,  2, 94,  2, 56, 43, 59, 36, 95, 36, 36, 36, 36, 36, 36,
+   36, 36, 63, 64, 36, 36, 36, 36, 36, 36, 36, 36, 63, 36, 36, 36,
+   43, 74, 75, 76, 74, 75, 75, 75, 75, 74, 75, 75, 76, 43, 43, 43,
+   61, 61,  2,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 27, 27, 61,
+   36, 36, 36, 63, 74, 76, 43,  2, 36, 36, 79, 74, 43, 43, 43, 43,
+   74, 74, 76, 43, 43, 43, 74, 75, 75, 76, 43, 43, 43, 43, 43, 43,
+    2,  2,  2, 77,  2,  2,  2,  2, 43, 43, 43, 43, 43, 43, 43, 96,
+   43, 43, 78, 36, 36, 36, 36, 36, 36, 36, 74, 43, 43, 74, 74, 75,
+   75, 74, 78, 36, 36, 36, 36, 36, 86, 61, 61, 61, 61, 47, 43, 43,
+   43, 43, 61, 61, 61, 61, 61, 61, 43, 78, 36, 36, 36, 36, 36, 36,
+   79, 43, 43, 75, 43, 76, 43, 36, 36, 36, 36, 74, 43, 75, 76, 76,
+   43, 75, 75, 75, 75, 75,  2,  2, 36, 36, 75, 75, 75, 75, 43, 43,
+   43, 43, 75, 43, 43, 57,  2,  2,  7,  7,  7,  7,  7,  7, 83, 36,
+   36, 36, 36, 36, 40, 40, 40,  2, 43, 57, 43, 43, 43, 43, 43, 43,
+   74, 43, 43, 43, 64, 36, 63, 36, 36, 36, 64, 79, 43, 36, 36, 36,
+   16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 44, 16, 16,
+   16, 16, 16, 16, 44, 16, 16, 16, 16, 16, 16, 16, 16, 97, 40, 40,
+   32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11,
+   16, 16, 16, 16, 34, 11, 11, 11, 16, 16, 16, 16, 98, 98, 98, 98,
+   16, 16, 16, 16, 11, 11, 99,100, 41, 16, 16, 16, 11, 11, 99, 41,
+   16, 16, 16, 16, 11, 11,101, 41,102,102,102,102,102,103, 59, 59,
+   51, 51, 51,  2,104,105,104,105,  2,  2,  2,  2,106, 59, 59,107,
+    2,  2,  2,  2,108,109,  2,110,111,  2,112,113,  2,  2,  2,  2,
+    2,  9,111,  2,  2,  2,  2,114, 59, 59, 59, 59, 59, 59, 59, 59,
+  115, 40, 27, 27, 27,  8,112,116, 27, 27, 27, 27, 27,  8,112, 91,
+   20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,117, 48,
+   96, 48, 96, 43, 43, 43, 43, 43, 61,118, 61,119, 61, 34, 11, 16,
+   11, 32,119, 61, 46, 11, 11, 61, 61, 61,118,118,118, 11, 11,120,
+   11, 11, 35, 36, 39, 61, 16, 11,  8,  8, 46, 16, 16, 26, 61,121,
+   92, 92, 92, 92, 92, 92, 92, 92, 92,122,123, 92,124, 61, 61, 61,
+    8,  8,125, 61, 61,  8, 61, 61,125, 26, 61,125, 61, 61, 61,125,
+   61, 61, 61, 61, 61, 61, 61,  8, 61,125,125, 61, 61, 61, 61, 61,
+   61, 61,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+   61, 61, 61, 61,  4,  4, 61, 61,  8, 61, 61, 61,126,127, 61, 61,
+   61, 61, 61, 61, 61, 61,125, 61, 61, 61, 61, 61, 61, 26,  8,  8,
+    8,  8, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,  8,  8,
+    8, 61, 61, 61, 61, 61, 61, 61, 27, 27, 27, 27, 27, 27, 61, 61,
+   61, 61, 61, 61, 61, 27, 27, 27, 61, 61, 61, 26, 61, 61, 61, 61,
+   26, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,  8,  8,  8,  8,
+   61, 61, 61, 61, 61, 61, 61, 26, 61, 61, 61, 61,  4,  4,  4,  4,
+    4,  4,  4, 27, 27, 27, 27, 27, 27, 27, 61, 61, 61, 61, 61, 61,
+    8,  8,112,128,  8,  8,  8,  8,  8,  8,  8,  4,  4,  4,  4,  4,
+    8,112,129,129,129,129,129,129,129,129,129,129,128,  8,  8,  8,
+    8,  8,  8,  8,  4,  4,  8,  8,  8,  8,  8,  8,  8,  8,  4,  8,
+    8,  8,125, 26,  8,  8,125, 61, 32, 11, 32, 34, 34, 34, 34, 11,
+   32, 32, 34, 16, 16, 16, 40, 11, 32, 32,121, 61, 61,119, 34,130,
+   43, 32, 16, 16, 50,  2, 87,  2, 36, 36, 36, 36, 36, 36, 36, 95,
+    2,  2,  2,  2,  2,  2,  2, 56,  2,104,104,  2,108,109,104,  2,
+    2,  2,  2,  6,  2, 94,104,  2,104,  4,  4,  4,  4,  2,  2, 77,
+    2,  2,  2,  2,  2, 51,  2,  2, 94,131,  2,  2,  2,  2,  2,  2,
+   61,  2,  2,  2,  2,  2,  2,  2,  1,  2,132,133,  4,  4,  4,  4,
+    4, 61,  4,  4,  4,  4,134, 91,135, 92, 92, 92, 92, 43, 43, 75,
+  136, 40, 40, 61, 92,137, 58, 61, 71, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 63,138,139, 62, 36, 36, 36, 36, 36, 58, 40, 62,
+   61, 27, 27, 61, 61, 61, 61, 61, 27, 27, 27, 27, 27, 61, 61, 61,
+   61, 61, 61, 61, 27, 27, 27, 27,140, 27, 27, 27, 27, 27, 27, 27,
+   36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,141,  2,
+   32, 32, 32, 32, 32, 32, 32, 63, 48,142, 43, 43, 43, 43, 43, 77,
+   32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36, 92, 92, 92, 92, 92,
+   43,  2,  2,  2,  2,  2,  2,  2, 41, 41, 41,139, 40, 40, 40, 40,
+   41, 32, 32, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32,
+   44, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,143, 34, 35,
+   32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32,
+   11, 11, 32, 32, 32, 32, 32, 32, 16, 32, 11, 11, 34, 16, 16, 16,
+   16, 16, 34, 35, 40, 35, 36, 36, 36, 64, 36, 64, 36, 63, 36, 36,
+   36, 79, 76, 74, 61, 61, 43, 43, 27, 27, 27, 61,144, 61, 61, 61,
+   36, 36,  2,  2,  2,  2,  2,  2, 75, 36, 36, 36, 36, 36, 36, 36,
+   36, 36, 75, 75, 75, 75, 75, 75, 75, 75, 43, 43, 43, 43, 43,  2,
+   43, 36, 36, 36,  2, 65, 65, 63, 36, 36, 36, 43, 43, 43, 43,  2,
+   36, 36, 36, 63, 43, 43, 43, 43, 43, 75, 75, 75, 75, 75, 75,145,
+   36, 63, 75, 43, 43, 75, 43, 75,145,  2,  2,  2,  2,  2,  2, 77,
+    7,  7,  7,  7,  7,  7,  7,  2, 36, 36, 63, 62, 36, 36, 36, 36,
+   36, 36, 36, 36, 63, 43, 43, 74, 76, 74, 76, 43, 43, 43, 43, 43,
+   36, 63, 36, 36, 36, 36, 74, 75,  7,  7,  7,  7,  7,  7,  2,  2,
+   62, 36, 36, 70, 61, 79, 74, 36, 64, 43, 64, 63, 64, 36, 36, 43,
+   36, 36, 36, 36, 36, 36, 95,  2, 36, 36, 36, 36, 36, 79, 43, 75,
+    2, 95,146, 43, 43, 43, 43, 43, 16, 16, 16, 16, 16,100, 40, 40,
+   16, 16, 16, 16, 97, 41, 41, 41, 36, 79, 76, 75, 74,145, 76, 43,
+  147,147,147,147,147,147,147,147,148,148,148,148,148,148,148,148,
+   16, 16, 16, 16, 16, 16, 35, 64, 36, 36, 36, 36,149, 36, 36, 36,
+   36, 41, 41, 41, 41, 41, 41, 41, 41,150, 36, 36, 36, 36, 36, 36,
+   36, 36, 36, 36, 36, 36, 36,129,151,151,151,151,151,151,151,151,
+   36, 36, 36, 36, 36, 36,144, 61,  2,  2,  2,152,113,  2,  2,  2,
+    6,153,154,129,129,129,129,129,129,129,113,152,113,  2,110,155,
+    2,  2,  2,  2,134,129,129,113,  2,156,  8,  8, 60,  2,  2,  2,
+   36, 36, 36, 36, 36, 36, 36,157,  2,  2,  3,  2,  4,  5,  6,  2,
+   16, 16, 16, 16, 16, 17, 18,112,113,  4,  2, 36, 36, 36, 36, 36,
+   62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40,
+   20,158, 53, 20, 26,  8,125, 61, 61, 61, 61, 61,159, 59, 61, 61,
+    2,  2,  2, 87, 27, 27, 27, 27, 27, 27, 27, 81, 61, 61, 61, 61,
+   92, 92,124, 27, 81, 61, 61, 61, 61, 61, 61, 61, 61, 27, 61, 61,
+   61, 61, 61, 61, 61, 61, 47, 43,160,160,160,160,160,160,160,160,
+  161, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 84, 36,
+  133, 36, 36, 36, 36, 92, 92, 92, 36, 36, 36, 36, 36, 36, 36, 58,
+  162, 92, 92, 92, 92, 92, 92, 92, 36, 36, 36, 58, 27, 27, 27, 27,
+   36, 36, 36, 70,140, 27, 27, 27, 36, 36, 36,163, 27, 27, 27, 27,
+   36, 36, 36, 36, 36,163, 27, 27, 36, 36, 36, 27, 27, 27, 27, 30,
+   36, 36, 36, 36, 36, 36, 27, 36, 63, 43, 43, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,163, 30,
+   36, 36, 36, 36, 36, 36,163, 27, 36, 36, 36, 36, 71, 36, 36, 36,
+   36, 36, 63, 43, 43,161, 27, 27, 36, 36, 36, 36, 58,  2,  2,  2,
+   36, 36, 36, 36, 27, 27, 27, 27, 16, 16, 16, 16, 16, 27, 27, 27,
+   36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 63,164, 51,
+   27, 27, 27, 84, 36, 36, 36, 36,161, 27, 30,  2,  2,  2,  2,  2,
+   36, 36,163, 27, 27, 27, 27, 27, 76, 78, 36, 36, 36, 36, 36, 36,
+   43, 43, 43, 57,  2,  2,  2,  2,  2, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,165,
+   75, 76, 43, 74, 76, 57, 72,  2,  2,  2,  2,  2,  2,  2, 72, 59,
+   36, 36, 36, 63, 43, 43, 76, 43, 43, 43, 43,  7,  7,  7,  7,  7,
+    2,  2, 79, 78, 36, 36, 36, 36, 36, 63,  2, 36, 36, 36, 36, 36,
+   36, 79, 75, 43, 43, 43, 43, 74, 78, 36, 58,  2, 56, 43, 57, 76,
+    7,  7,  7,  7,  7, 58, 58,  2, 87, 27, 27, 27, 27, 27, 27, 27,
+   36, 36, 36, 36, 36, 36, 75, 76, 43, 75, 74, 43,  2,  2,  2, 43,
+   36, 36, 36, 36, 36, 36, 36, 63, 74, 75, 75, 75, 75, 75, 75, 75,
+   36, 36, 36, 79, 75, 75, 78, 36, 36, 75, 75, 43, 43, 43, 43, 43,
+   36, 36, 79, 75, 43, 43, 43, 43, 75, 43, 74, 64, 36, 58,  2,  2,
+    7,  7,  7,  7,  7,  2,  2, 64, 75, 76, 43, 43, 74, 74, 75, 76,
+   74, 43, 36, 65, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 79,
+   75, 43, 43, 43, 75, 75, 43, 76, 57,  2,  2,  2,  2,  2,  2,  2,
+    2,  2,  2,  2, 36, 36, 43, 43, 75, 76, 43, 43, 43, 74, 76, 76,
+   57,  2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 76, 75,
+   43, 43, 43, 76, 36, 36, 36, 36, 75, 43, 43, 76, 43, 43, 43, 43,
+    7,  7,  7,  7,  7, 27,  2, 86, 43, 43, 43, 43, 76, 57,  2,  2,
+   27, 27, 27, 27, 27, 27, 27, 84, 75, 75, 75, 75, 75, 76, 74, 64,
+   78, 76,  2,  2,  2,  2,  2,  2, 79, 75, 43, 43, 43, 43, 75, 75,
+   64, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+   63, 43, 43, 43, 43, 64, 36, 36, 36, 63, 43, 43, 74, 63, 43, 57,
+    2,  2,  2, 56, 43, 43, 43, 43, 63, 43, 43, 74, 76, 43, 36, 36,
+   36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 74, 43,  2, 65,  2,
+   43, 43, 43, 43, 43, 43, 43, 76, 58,  2,  2,  2,  2,  2,  2,  2,
+    2, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 74, 43, 43, 43,
+   74, 43, 76, 43, 43, 43, 43, 43, 43, 43, 43, 63, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 75, 75, 75, 43, 74, 76, 76, 36, 36, 36, 36,
+   36, 63, 74,145,  2,  2,  2,  2, 27, 27, 81, 61, 61, 61, 53, 20,
+  144, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 21,
+   43, 43, 57,  2,  2,  2,  2,  2, 43, 43, 43, 57,  2,  2, 61, 61,
+   40, 40, 86, 61, 61, 61, 61, 61,  7,  7,  7,  7,  7,166, 27, 27,
+   27, 84, 36, 36, 36, 36, 36, 36, 27, 27, 27, 30,  2,  2,  2,  2,
+   79, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 76,
+   43, 67, 40, 40, 40, 40, 40, 40, 40, 77, 43, 43, 43, 43, 43, 43,
+   36, 36, 36, 36, 36, 36, 47, 57, 61, 61,167, 76, 43, 61,167, 75,
+   75,168, 59, 59, 59, 73, 43, 43, 43, 69, 47, 43, 43, 43, 61, 61,
+   61, 61, 61, 61, 61, 43, 43, 61, 61, 43, 69, 61, 61, 61, 61, 61,
+   11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 11, 11, 16, 11, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16,
+   31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16,
+   16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16,
+   16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11,
+   11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16,
+   11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 16,  7,
+   43, 43, 43, 69, 61, 47, 43, 43, 43, 43, 43, 43, 43, 43, 69, 61,
+   61, 61, 47, 61, 61, 61, 61, 61, 61, 61, 69, 21,  2,  2,  2,  2,
+    2,  2,  2,  2,  2, 56, 43, 43, 43, 43, 43, 67, 40, 40, 40, 40,
+    7,  7,  7,  7,  7,  7,  7, 70, 36, 36, 36, 36, 36, 36, 43, 43,
+    7,  7,  7,  7,  7,  7,  7,169, 16, 16, 43, 43, 43, 67, 40, 40,
+   27, 27, 27, 27, 27, 27,140, 27,170, 27, 27, 27, 27, 27, 27, 27,
+   27, 27, 27, 27, 27, 27, 27,140, 27, 27, 27, 27, 27, 27, 81, 61,
+   61, 61, 61, 61, 61, 25, 41, 41,  0,  0, 29, 21, 21, 21, 23, 21,
+   22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21,  9,  9,  9,
+    9, 22, 21, 18, 24, 16, 24,  5,  5,  5,  5, 22, 25, 18, 25,  0,
+   23, 23, 26, 21, 24, 26,  7, 20, 25,  1, 26, 24, 26, 25, 15, 15,
+   24, 15,  7, 19, 15, 21,  9, 25,  9,  5,  5, 25,  5,  9,  5,  7,
+    7,  7,  9,  8,  8,  5,  7,  5,  6,  6, 24, 24,  6, 24, 12, 12,
+    6,  5,  9, 21, 25,  9, 26, 12, 11, 11,  9,  6,  5, 21, 17, 17,
+   17, 26, 26, 23, 23, 12, 17, 12, 21, 12, 12, 21,  7, 21,  1,  1,
+   21, 23, 26, 26,  6,  7,  7, 12, 12,  7, 21,  7, 12,  1, 12,  6,
+    6, 12, 12, 26,  7, 26, 26,  7, 21,  1,  1, 12, 12, 10, 10, 10,
+   10, 12, 21,  6, 10,  7,  7, 10, 23,  7, 15, 26, 13, 21, 13,  7,
+   15,  7, 12, 23, 21, 26, 21, 15, 17,  7, 29,  7,  7, 22, 18, 18,
+   14, 14, 14,  7, 17, 21,  7,  6, 11, 12,  5,  6,  8,  8,  8, 24,
+    5, 24,  9, 24, 29, 29, 29,  1, 20, 19, 22, 20, 27, 28,  1, 29,
+   21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15,  6,
+   18,  6, 12, 11,  9, 26, 26,  9, 26,  5,  5, 26, 14,  9,  5, 14,
+   14, 15, 25, 26, 26, 22, 18, 26, 18, 25, 18, 22,  5, 12, 22, 21,
+   26,  6,  7, 14, 17, 22, 26, 14, 17,  6, 14,  6, 12, 24, 24,  6,
+   26, 15,  6, 21, 11, 21, 24,  9, 23, 26, 10, 21,  6, 10,  4,  4,
+    3,  3,  7, 25, 24,  7, 22, 22, 21, 22, 17, 16, 16, 22, 16, 16,
+   25, 17,  7,  1, 25, 24, 26,  1,  2,  2, 12, 15, 21, 14,  7, 15,
+   12, 17, 13, 12, 13, 15, 26, 10, 10,  1, 13, 23, 23, 15,  0,  1,
+    2,  3,  4,  5,  6,  7,  8,  9,  0, 10, 11, 12, 13,  0, 14,  0,
+    0,  0,  0,  0, 15,  0, 16,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 17, 18, 19,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20,  0, 21, 22, 23,
+    0,  0,  0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 34,  0, 35,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 36,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 37, 38,  0,  0,  0,  0,  0,  0, 39, 40,
+    0,  0, 41,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    1,  2,  0,  0,  0,  0,  3,  0,  0,  0,  4,  5,  6,  7,  0,  8,
+    9, 10,  0, 11, 12, 13,  0, 14, 15, 16, 15, 17, 15, 18, 15, 18,
+   15, 18,  0, 18,  0, 19, 15, 18, 20, 18,  0, 21, 22, 23, 24, 25,
+   26, 27, 28, 29, 30,  0, 31,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0, 32,  0,  0,  0,  0,  0,  0, 33,  0,  0, 34,  0,  0, 35,  0,
+   36,  0,  0,  0, 37, 38, 39, 40, 41, 42, 43, 44, 45,  0,  0, 46,
+    0,  0,  0, 47,  0,  0,  0, 48,  0,  0,  0,  0,  0,  0,  0, 49,
+    0, 50,  0, 51, 52,  0, 53,  0,  0,  0,  0,  0,  0, 54, 55, 56,
+    0,  0,  0,  0, 57,  0,  0, 58, 59, 60, 61, 62,  0,  0, 63, 64,
+    0,  0,  0, 65,  0,  0,  0,  0, 66,  0,  0,  0, 67,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 68,  0,  0,  0, 69,
+    0, 70,  0,  0, 71,  0,  0, 72,  0,  0,  0,  0,  0,  0,  0,  0,
+   73,  0,  0,  0,  0,  0, 74,  0,  0, 75,  0,  0,  0, 76, 77,  0,
+   78, 61,  0, 79, 80,  0,  0, 81, 82, 83,  0,  0,  0, 84,  0, 85,
+    0,  0, 50, 86, 50,  0, 87,  0, 88,  0,  0,  0, 77,  0,  0,  0,
+   89, 90,  0, 91, 92, 93, 94,  0,  0,  0,  0,  0, 50,  0,  0,  0,
+    0, 95, 96,  0,  0,  0,  0, 97, 98,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 99,  0,  0,100,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,101,102,  0,  0,103,  0,  0,  0,  0,  0,  0,104,  0,  0,  0,
+   98,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,  0,  0,106,
+    0,107,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  0,
+    8,  0,  0,  0,  0,  9, 10, 11, 12,  0,  0,  0,  0, 13,  0,  0,
+   14, 15,  0, 16,  0, 17, 18,  0,  0, 19,  0, 20, 21,  0,  0,  0,
+    0,  0, 22, 23,  0, 24, 25,  0,  0, 26,  0,  0,  0, 27, 28, 29,
+    0,  0,  0, 30, 31, 32,  0,  0, 31,  0,  0, 33, 31,  0,  0,  0,
+   31, 34,  0,  0,  0,  0,  0, 35, 36,  0,  0,  0,  0,  0,  0, 37,
+   38,  0,  0,  0,  0,  0,  0, 39, 40,  0,  0,  0,  0, 41,  0, 42,
+    0,  0,  0, 43, 44,  0,  0,  0, 45,  0,  0,  0,  0,  0,  0, 46,
+   47,  0,  0,  0,  0, 48,  0,  0,  0, 49,  0, 49,  0, 50,  0,  0,
+    0,  0, 51,  0,  0,  0,  0, 52,  0, 53,  0,  0,  0,  0, 54, 55,
+    0,  0,  0, 56, 57,  0,  0,  0,  0,  0,  0, 58, 49,  0, 59, 60,
+    0,  0, 61,  0,  0,  0, 62, 63,  0,  0,  0, 64,  0, 65, 66, 67,
+   68, 69,  1, 70,  0, 71, 72, 73,  0,  0, 74, 75,  0,  0,  0, 76,
+    0,  0,  1,  1,  0,  0, 77,  0,  0, 78,  0,  0,  0,  0, 74, 79,
+    0, 80,  0,  0,  0,  0,  0, 75, 81,  0, 82,  0, 49,  0,  1, 75,
+    0,  0, 83,  0,  0, 84,  0,  0,  0,  0,  0, 85, 54,  0,  0,  0,
+    0,  0,  0, 86, 87,  0,  0, 81,  0,  0, 31,  0,  0, 88,  0,  0,
+    0,  0, 89,  0,  0,  0,  0, 47,  0,  0, 57,  0,  0,  0,  0, 90,
+   91,  0,  0, 92,  0,  0, 93,  0,  0,  0, 94,  0,  0,  0, 95,  0,
+   96, 57,  0,  0, 81,  0,  0, 76,  0,  0,  0, 97, 98,  0,  0, 99,
+  100,  0,  0,  0,  0,  0,  0,101,  0,  0,102,  0,  0,  0,  0,103,
+   31,  0,104,105,106, 33,  0,  0,107,  0,  0,  0,108,  0,  0,  0,
+    0,  0,  0,109,  0,  0,110,  0,  0,  0,  0,111, 85,  0,  0,  0,
+    0,  0, 54,  0,  0,  0,  0, 49,112,  0,  0,  0,  0,113,  0,  0,
+  114,  0,  0,  0,  0,112,  0,  0,  0,  0,  0,115,  0,  0,  0,116,
+    0,  0,  0,117,  0,118,  0,  0,  0,  0,119,120,121,  0,122,  0,
+  123,  0,  0,  0,124,125,126,  0,  0,  0,127,  0,  0,128,  0,  0,
+  129,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  2,  3,  4,
+    5,  6,  7,  4,  4,  8,  9, 10,  1, 11, 12, 13, 14, 15, 16, 17,
+   18,  1,  1,  1, 19,  1,  0,  0, 20, 21, 22,  1, 23,  4, 21, 24,
+   25, 26, 27, 28, 29, 30,  0,  0,  1,  1, 31,  0,  0,  0, 32, 33,
+   34, 35,  1, 36, 37,  0,  0,  0,  0, 38,  1, 39, 14, 39, 40, 41,
+   42,  0,  0,  0, 43, 36, 44, 45, 21, 45, 46,  0,  0,  0, 19,  1,
+   21,  0,  0, 47,  0, 38, 48,  1,  1, 49, 49, 50,  0,  0, 51,  0,
+   52,  1,  1,  1, 53, 21, 43, 54, 55, 21, 35,  1,  0,  0,  0, 56,
+    0,  0,  0, 57, 58, 59,  0,  0,  0,  0,  0, 60,  0, 61,  0,  0,
+    0,  0, 62, 63,  0,  0, 64,  0,  0,  0, 65,  0,  0,  0, 66,  0,
+    0,  0, 67,  0,  0,  0, 68,  0,  0,  0, 69,  0,  0, 70, 71,  0,
+   72, 73, 74, 75, 76, 77,  0,  0,  0, 78,  0,  0,  0, 79, 80,  0,
+    0,  0,  0, 47,  0,  0,  0, 49,  0, 63,  0,  0, 64,  0,  0, 81,
+    0,  0, 82,  0,  0,  0, 83,  0,  0, 19, 84,  0, 63,  0,  0,  0,
+    0, 49,  1, 85,  1, 54, 15, 86, 84,  0,  0,  0,  0, 56,  0,  0,
+    0,  0, 19, 10,  1,  0,  0,  0,  0,  0, 87,  0,  0, 88,  0,  0,
+   87,  0,  0,  0,  0, 79,  0,  0, 89,  9, 12,  4, 90,  8, 91, 47,
+    0, 59, 50,  0, 21,  1, 21, 92, 93,  1,  1,  1,  1, 94, 95, 96,
+   97,  1, 98, 59, 81, 99,100,  4, 59,  0,  0,  0,  0,  0,  0, 19,
+   50,  0,  0,  0,  0,  0,  0, 62,  0,  0,101,102,  0,  0,103,  0,
+    0,  1,  1, 50,  0,  0,  0, 38,  0, 64,  0,  0,  0,  0,  0, 63,
+    0,  0, 52, 69, 62,  0,  0,  0, 79,  0,  0,  0,104,105, 59, 38,
+   81,  0,  0,  0,  0,  0,  0,106,  1, 14,  4, 12,  0, 38, 89,  0,
+    0,  0,  0,107,  0,  0,108, 62,  0,109,  0,  0,  0,  1,  0,  0,
+    0,  0, 19, 59,  0,110, 14, 54,  0,  0,111,  0, 89,  0,  0,  0,
+   62, 63,  0,  0, 63,  0, 88,  0,  0,111,  0,  0,  0,  0,112,  0,
+    0,  0, 79, 56,  0, 38,  1, 59,  1, 59,  0,  0, 64, 88,  0,  0,
+  113,  0,  0,  0, 56,  0,  0,  0,  0,113,  0,  0,  0,  0, 62,  0,
+    0,  0,  0, 80,  0, 62,  0,  0,  0,  0, 57,  0, 88,114,  0,  0,
+    8, 91,  0,  0,  1, 89,  0,  0,115,  0,  0,  0,  0,  0,  0,116,
+    0,117,118,119,120,  0, 52,  4,121, 49, 23,  0,  0,  0, 38, 50,
+   38, 59,  0,  0,  1, 89,  1,  1,  1,  1, 39,  1, 48,104, 89,  0,
+    0,  0,  0,  1,  4,121,  0,  0,  0,  1,122,  0,  0,  0,  0,  0,
+  230,230,230,230,230,232,220,220,220,220,232,216,220,220,220,220,
+  220,202,202,220,220,220,220,202,202,220,220,220,  1,  1,  1,  1,
+    1,220,220,220,220,230,230,230,230,240,230,220,220,220,230,230,
+  230,220,220,  0,230,230,230,220,220,220,220,230,232,220,220,230,
+  233,234,234,233,234,234,233,230,  0,  0,  0,230,  0,220,230,230,
+  230,230,220,230,230,230,222,220,230,230,220,220,230,222,228,230,
+   10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22,  0, 23,
+    0, 24, 25,  0,230,220,  0, 18, 30, 31, 32,  0,  0,  0,  0, 27,
+   28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230,230,220,
+   35,  0,  0,  0,  0,  0,230,230,230,  0,  0,230,230,  0,220,230,
+  230,220,  0,  0,  0, 36,  0,  0,230,220,230,230,220,220,230,220,
+  220,230,220,230,220,230,230,  0,  0,220,  0,  0,230,230,  0,230,
+    0,230,230,230,230,230,  0,  0,  0,220,220,220,  0,  0,  0,220,
+  230,230,  0,220,230,220,220,220, 27, 28, 29,230,  7,  0,  0,  0,
+    0,  9,  0,  0,  0,230,220,230,230,  0,  0,  0,  0,  0,230,  0,
+    0, 84, 91,  0,  0,  0,  0,  9,  9,  0,  0,  0,  0,  0,  9,  0,
+  103,103,  9,  0,107,107,107,107,118,118,  9,  0,122,122,122,122,
+  220,220,  0,  0,  0,220,  0,220,  0,216,  0,  0,  0,129,130,  0,
+  132,  0,  0,  0,  0,  0,130,130,130,130,  0,  0,130,  0,230,230,
+    9,  0,230,230,  0,  0,220,  0,  0,  0,  0,  7,  0,  9,  9,  0,
+    0,230,  0,  0,  0,228,  0,  0,  0,222,230,220,220,  0,  0,  0,
+  230,  0,  0,220,230,220,  0,220,  0,  0,  9,  9,  0,  0,  7,  0,
+  230,230,230,  0,230,  0,  1,  1,  1,  0,  0,  0,230,234,214,220,
+  202,230,230,230,230,230,232,228,228,220,  0,230,233,220,230,220,
+  230,230,  1,  1,  1,  1,  1,230,  0,  1,  1,230,220,230,  1,  1,
+    0,  0,218,228,232,222,224,224,  0,  8,  8,  0,230,  0,230,230,
+  220,  0,  0,230,  0,  0, 26,  0,  0,220,  0,230,230,  1,220,  0,
+    0,230,220,  0,  0,  0,220,220,  0,  9,  7,  0,  0,  7,  9,  0,
+    0,  0,  9,  7,  9,  9,  0,  0,  6,  6,  0,  0,  0,  0,  1,  0,
+    0,216,216,  1,  1,  1,  0,  0,  0,226,216,216,216,216,216,  0,
+  220,220,220,  0,230,230,  7,  0, 16, 17, 17, 33, 17, 49, 17, 17,
+   84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17, 17, 17,177,  0,  1,  2,  3,  3,  3,  3,  3,
+    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  4,  3,  3,  3,
+    3,  3,  5,  3,  3,  3,  3,  3,  6,  7,  8,  3,  3,  3,  3,  3,
+    9, 10, 11, 12, 13,  3,  3,  3,  3,  3,  3,  3,  3, 14,  3, 15,
+    3,  3,  3,  3,  3,  3, 16, 17, 18, 19, 20, 21,  3,  3,  3, 22,
+   23,  3,  3,  3,  3,  3,  3,  3, 24,  3,  3,  3,  3,  3,  3,  3,
+    3, 25,  3,  3, 26, 27,  0,  1,  0,  0,  0,  0,  0,  1,  0,  2,
+    0,  0,  0,  3,  0,  0,  0,  3,  0,  0,  0,  0,  0,  4,  0,  5,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,
+    0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,
+    9,  0,  0,  0,  0,  0,  0,  9,  0,  9,  0,  0,  0,  0,  0,  0,
+    0, 10, 11, 12, 13,  0,  0, 14, 15, 16,  6,  0, 17, 18, 19, 19,
+   19, 20, 21, 22, 23, 24, 19, 25,  0, 26, 27, 19, 19, 28, 29, 30,
+    0, 31,  0,  0,  0,  8,  0,  0,  0,  0,  0,  0,  0, 19, 28,  0,
+   32, 33,  9, 34, 35, 19,  0,  0, 36, 37, 38, 39, 40, 19,  0, 41,
+   42, 43, 44, 31,  0,  1, 45, 42,  0,  0,  0,  0,  0, 32, 14, 14,
+    0,  0,  0,  0, 14,  0,  0, 46, 47, 47, 47, 47, 48, 49, 47, 47,
+   47, 47, 50, 51, 52, 53, 43, 21,  0,  0,  0,  0,  0,  0,  0, 54,
+    6, 55,  0, 14, 19,  1,  0,  0,  0, 19, 56, 31,  0,  0,  0,  0,
+    0,  0,  0, 57, 14,  0,  0,  0,  0,  1,  0,  2,  0,  0,  0,  3,
+    0,  0,  0, 58, 59,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,
+    0,  0,  2,  3,  0,  4,  5,  0,  0,  6,  0,  0,  0,  7,  0,  0,
+    0,  1,  1,  0,  0,  8,  9,  0,  8,  9,  0,  0,  0,  0,  8,  9,
+   10, 11, 12,  0,  0,  0, 13,  0,  0,  0,  0, 14, 15, 16, 17,  0,
+    0,  0,  1,  0,  0, 18, 19,  0,  0,  0, 20,  0,  0,  0,  1,  1,
+    1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  0,  8, 21,  9,  0,  0,
+   22,  0,  0,  0,  0,  1,  0, 23, 24, 25,  0,  0, 26,  0,  0,  0,
+    8, 21, 27,  0,  1,  0,  0,  1,  1,  1,  1,  0,  1, 28, 29, 30,
+    0, 31, 32, 20,  1,  1,  0,  0,  0,  8, 21,  9,  1,  4,  5,  0,
+    0,  0, 33,  9,  0,  1,  1,  1,  0,  8, 21, 21, 21, 21, 34,  1,
+   35, 21, 21, 21,  9, 36,  0,  0, 37, 38,  1,  0, 39,  0,  0,  0,
+    1,  0,  1,  0,  0,  0,  0,  8, 21,  9,  1,  0,  0,  0, 40,  0,
+    8, 21, 21, 21, 21, 21, 21, 21, 21,  9,  0,  1,  1,  1,  1,  8,
+   21, 21, 21,  9,  0,  0,  0, 41,  0, 42, 43,  0,  0,  0,  1, 44,
+    0,  0,  0, 45,  8,  9,  1,  0,  1,  0,  1,  1,  8, 21, 21,  9,
+    0,  4,  5,  8,  9,  1,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,
+    7,  8,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  9, 10, 11, 11,
+   11, 11, 11, 12, 12, 12, 12, 13, 14, 15, 16, 17, 18, 12, 19, 12,
+   20, 12, 12, 12, 12, 21, 22, 22, 22, 23, 12, 12, 12, 12, 24, 25,
+   12, 12, 26, 27, 28, 29, 30, 31,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
+    7,  7,  7,  7,  7, 32, 12, 33,  7,  7, 34, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+   12, 12, 12, 12, 12, 12, 12, 12, 35,  0,  0,  1,  2,  2,  2,  3,
+    4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+   20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 33,
+   33, 34, 35, 35, 35, 35, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+   45, 46, 47, 48, 49, 50,  2,  2, 51, 51, 52, 53, 54, 55, 56, 56,
+   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 56, 56, 56, 56,
+   56, 56, 58, 59, 60, 61, 56, 62, 62, 63, 64, 65, 66, 67, 68, 69,
+   70, 56, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+   62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+   62, 62, 62, 62, 62, 71, 62, 62, 62, 62, 72, 72, 72, 72, 72, 72,
+   72, 72, 72, 73, 74, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+   85, 86, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+   32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 87, 87, 87, 87, 87, 87,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62,
+   88, 89, 89, 89, 90, 89, 91, 92, 93, 94, 95, 95, 96, 97, 87, 98,
+   99,100,101,102,103, 87,104,104,104, 87,105,106,107,108,109,110,
+  111,112,113,114,115, 87, 89,116,117,118,119,120,121,122,123,124,
+  125, 87,126,127, 87,128,129,130,131, 87,132,133,134,135,136,137,
+   87, 87,138,139,140,141, 87,142, 87,143,144,144,144,144,144,144,
+  144,144,144,144,144, 87, 87, 87, 87, 87,145,145,145,145,145,145,
+  145,145,145, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+   87, 87,146,146,146,146,146, 87, 87, 87,147,147,147,147,148,149,
+  150,150, 87, 87, 87, 87,151,151,152,153,154,154,154,154,154,154,
+  154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
+  155,155,155,155,154, 87, 87, 87, 87, 87,156,157,158,159,159,159,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+   87, 87,160,161, 87, 87, 87, 87, 87, 87, 56, 56,162,163, 51, 56,
+   56, 87, 56, 56, 56, 56, 56, 56, 56, 56,164,164,164,164,164,164,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87,165, 87,166, 87, 87,167,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87,168,168,169, 87, 87, 87,
+   87, 87, 56, 56, 56, 87, 89, 89, 87, 87, 56, 56, 56, 56,170, 87,
+   56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+   56, 56, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 62, 62,
+   62, 62, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 62, 87,
+   87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 62, 62,
+   62, 87, 87, 87, 87, 87, 87, 87, 87, 87, 56, 87,171,171,  0,  1,
+    2,  2,  0,  1,  2,  2,  2,  3,  4,  5,  0,  0,  0,  0,  1,  2,
+    1,  2,  0,  0,  3,  3,  4,  5,  4,  5,  4,  4,  4,  4,  4,  4,
+    4,  4,  4,  4,  4,  6,  0,  0,  7,  0,  8,  8,  8,  8,  8,  8,
+    8,  9, 10, 11, 11, 11, 11, 11, 12, 11, 13, 13, 13, 13, 13, 13,
+   13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 16, 16,
+   16, 16, 16, 17, 18, 18, 18, 18, 18, 18, 19, 20, 21, 21, 22, 23,
+   21, 24, 21, 21, 21, 21, 21, 25, 21, 21, 26, 26, 26, 26, 26, 21,
+   21, 21, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30,
+   26, 26, 21, 21, 21, 21, 21, 21, 31, 21, 32, 32, 32, 32, 32, 33,
+   34, 32, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36,
+   36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38,
+   38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40,
+   40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42,
+   42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 45, 44, 44,
+   44, 44, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47,
+   47, 47, 47, 47, 47, 47, 47, 48, 47, 47, 49, 49, 49, 49, 49, 49,
+   49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 52, 52, 52, 52, 52, 52,
+   52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54,
+   54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 57, 57, 57, 57,
+   58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 64, 64, 64, 64,
+   64, 64, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 55, 55, 55,
+   55, 55, 67, 67, 67, 67, 67, 68, 68, 68, 69, 69, 69, 69, 69, 69,
+   64, 64, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, 71,  8,  8,  8,
+    8,  8, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74,
+   74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 13, 50, 50, 50, 73, 77,
+   78, 79,  4,  4, 80,  4,  4, 81, 82, 83,  4,  4,  4, 84,  8,  8,
+    8,  8, 11, 11, 11, 11, 11, 11, 11, 11, 85,  0,  0,  0,  0,  0,
+    0, 86,  0,  4,  0,  0,  0,  8,  8,  8,  0,  0, 87, 88, 89,  0,
+    4,  4,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91,
+    4,  4, 92, 92, 92, 92, 92, 92, 92, 92, 50, 50, 50, 93, 93, 93,
+   93, 93, 53, 53, 53, 53, 53, 53, 13, 13, 94, 94, 94, 94, 94, 94,
+   94, 94, 94, 94, 94, 94, 94, 94, 94,  0, 95,  0, 96, 97, 98, 99,
+   99, 99, 99,100,101,102,102,102,102,103,104,104,104,105, 52, 52,
+   52, 52, 52,  0,104,104,  0,  0,  0,102, 52, 52,  0,  0,  0,  0,
+   52,106,  0,  0,  0,  0,  0,102,102,107,102,102,102,102,102,108,
+    0,  0, 94, 94, 94, 94,  0,  0,  0,  0,109,109,109,109,109,109,
+  109,109,109,109,109,109,109,110,110,110,111,111,111,111,111,111,
+  111,111,111,111,111,111, 13, 13, 13, 13, 13, 13,112,112,112,112,
+  112,112,  0,  0,113,  4,  4,  4,  4,  4,114,  4,  4,  4,  4,  4,
+    4,  4,115,115,115,  0,116,116,116,116,117,117,117,117,117,117,
+   32, 32,118,118,119,120,120,120, 52, 52,121,121,121,121,122,121,
+   49, 49,123,123,123,123,123,123, 49, 49,124,124,124,124,124,124,
+  125,125, 53, 53, 53,  4,  4,126,127, 54, 54, 54, 54, 54,125,125,
+  125,125,128,128,128,128,128,128,128,128,  4,129, 18, 18, 18, 21,
+   21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,130,  0, 21,
+   21, 21,  8,  0,131,  0,  0,  0,  0, 21, 21, 21, 21, 21, 21, 21,
+   21,132,  0,  0,  1,  2,  1,  2,133,101,102,134, 52, 52, 52, 52,
+    0,  0,135,135,135,135,135,135,135,135,  0,  0,  0,  0, 11, 11,
+   11, 11, 11,  0, 11, 11, 11,  0,  0,136,137,137,138,138,138,138,
+  139,  0,140,140,140,141,141,142,142,142,143,143,144,144,144,144,
+  144,144,145,145,145,145,145,146,146,146,147,147,147,148,148,148,
+  148,148,149,149,149,150,150,150,150,150,151,151,151,151,151,151,
+  151,151,152,152,152,152,153,153,154,154,155,155,155,155,155,155,
+  156,156,157,157,158,158,158,158,158,158,159,159,160,160,160,160,
+  160,160,161,161,161,161,161,161,162,162,163,163,163,163,164,164,
+  164,164,165,165,165,165,166,166,167,167,168,168,168,168,168,168,
+  168,168,169,169,169,169,169,169,169,169,170,170,170,170,170,170,
+  170,170,171,171,171,171,171,171,171,171,172,172,172,172,172,172,
+  172,172,173,173,173,174,174,174,174,174,175,175,175,175,175,175,
+  176,176,177,177,177,177,177,177,177,177,178,178,178,178,178,179,
+  179,179,180,180,180,180,180,181,181,181,182,182,182,182,182,182,
+  183, 43,184,184,184,184,184,184,184,184,185,185,185,186,186,186,
+  186,186,187,187,187,188,187,187,187,187,189,189,189,189,189,189,
+  189,189,190,190,190,190,190,190,190,190,191,191,191,191,191,191,
+  191,191,192,192,192,192,192,192, 66, 66,193,193,193,193,193,193,
+  193,193,194,194,194,194,194,194,194,194,195,195,195,195,195,195,
+  195,195,196,196,196,196,196,196,196,196,197,197,197,197,197,197,
+  197,197,198,198,198,198,198,198,198,198,199,199,199,199,199,200,
+  200,200,200,200,200,200,201,201,201,201,202,202,202,202,202,202,
+  202,203,203,203,203,203,203,203,203,203,204,204,204,204,204,204,
+  205,205,205,205,205,205,205,205,205,205,206,206,206,206,206,206,
+  206,206,110,110,110,110, 39, 39, 39, 39,207,207,207,207,207,207,
+  207,207,208,208,208,208,208,208,208,208,209,209,209,209,209,209,
+  209,209,112,112,112,112,112,112,112,112,112,112,112,112,210,210,
+  210,210,211,211,211,211,211,211,211,211,212,212,212,212,212,212,
+  212,212,213,213,213,213,213,213,213,213,214,214,214,214,214,214,
+  214,214,214,214,214,214,214,214,215, 94,216,216,216,216,216,216,
+  216,216,217,217,217,217,217,217,217,217,218, 99, 99, 99, 99, 99,
+   99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+  219,220,220,220,220,220,220,220,220,220,221,221,221,221,221,221,
+  221,221,221,221,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  222,223,224,  0,225,  0,  0,  0,  0,  0,226,226,226,226,226,226,
+  226,226, 91, 91, 91, 91, 91, 91, 91, 91,227,227,227,227,227,227,
+  227,227,228,228,228,228,228,228,228,228,229,229,229,229,229,229,
+  229,229,230,230,230,230,230,230,230,230,231,  0,  0,  0,  0,  0,
+    0,  0,  8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  1,  2,
+    2,  2,  2,  2,  3,  0,  0,  0,  4,  0,  2,  2,  2,  2,  2,  3,
+    2,  2,  2,  2,  5,  0,  2,  5,  6,  0,  7,  7,  7,  7,  8,  9,
+    8, 10,  8, 11,  8,  8,  8,  8,  8,  8, 12, 13, 13, 13, 14, 14,
+   14, 14, 14, 15, 14, 14, 16, 17, 17, 17, 17, 17, 17, 17, 18, 19,
+   19, 19, 19, 19, 19, 19, 20, 21, 20, 22, 20, 20, 23, 23, 20, 20,
+   20, 20, 22, 20, 24,  7,  7, 25, 20, 20, 26, 20, 20, 20, 20, 20,
+   20, 21, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30,
+   30, 30, 31, 31, 31, 31, 32, 20, 20, 20, 33, 33, 33, 33, 34, 35,
+   33, 33, 33, 36, 33, 33, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39,
+   39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43,
+   43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46,
+   46, 47, 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 51, 49, 52, 52,
+   52, 52, 53, 53, 53, 53, 53, 53, 54, 53, 55, 55, 55, 55, 56, 56,
+   56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60,
+   60, 60, 60, 60, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65,
+    0,  0, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 70,
+   71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74,
+   74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78,
+   78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82,  7,
+    7,  7, 83,  7, 84, 85,  0, 84, 86,  0,  2, 87, 88,  2,  2,  2,
+    2, 89, 90, 87, 91,  2,  2,  2, 92,  2,  2,  2,  2, 93,  0,  0,
+    0, 86,  1,  0,  0, 94,  0, 95, 96,  0,  4,  0,  0,  0,  0,  0,
+    0,  4, 97, 97, 97, 97, 98, 98, 98, 98, 13, 13, 13, 13, 99, 99,
+   99, 99,100,100,100,100,  0,101,  0,  0,102,100,103,104,  0,  0,
+  100,  0,105,106,106,106,106,106,106,106,106,106,107,105,108,109,
+  109,109,109,109,109,109,109,109,110,108,111,111,111,111,112, 55,
+   55, 55, 55, 55, 55,113,109,109,109,110,109,109,  0,  0,114,114,
+  114,114,115,115,115,115,116,116,116,116,117,117,117,117, 96,  2,
+    2,  2,  2,  2, 94,  2,118,118,118,118,119,119,119,119,120,120,
+  120,120,121,121,121,121,121,121,121,122,123,123,123,123,124,124,
+  124,124,124,124,124,125,126,126,126,126,127,127,127,127,128,128,
+  128,128,  2,  2,  3,  2,  2,129,130,  0,131,131,131,131,132, 17,
+   17, 18, 20, 20, 20,133,  7,  7,  7,134, 20, 20, 20, 23,  0,135,
+  109,109,109,109,109,136,137,137,137,137,  0,  0,  0,138,139,139,
+  139,139,140,140,140,140, 84,  0,  0,  0,141,141,141,141,142,142,
+  142,142,143,143,143,143,144,144,144,144,145,145,145,145,146,146,
+  146,146,147,147,147,147,148,148,148,148,149,149,149,149,150,150,
+  150,150,151,151,151,151,152,152,152,152,153,153,153,153,154,154,
+  154,154,155,155,155,155,156,156,156,156,157,157,157,157,158,158,
+  158,158,159,159,159,159,160,160,160,160,161,161,161,161,162,162,
+  162,162,163,163,163,163,164,164,164,164,165,165,165,165,166,166,
+  166,166,167,167,167,167,168,168,168,168,169,169,169,169,170,170,
+  170,170,171,171,171,171,172,172,172,172,173,173,173,173,174,174,
+  174,174,175,175,175,175,176,176,176,176,177,177,177,177,178,178,
+  178,178,179,179,179,179,180,180,180,180,181,181,181,181,182,182,
+  182,182,183,183,183,183,184, 45, 45, 45,185,185,185,185,186,186,
+  186,186,187,187,187,187,188,188,188,188,188,188,189,188,190,190,
+  190,190,191,191,191,191,192,192,192,192,193,193,193,193,194,194,
+  194,194,195,195,195,195,196,196,196,196,197,197,197,197,198,198,
+  198,198,199,199,199,199,200,200,200,200,201,201,201,201,202,202,
+  202,202,203,203,203,203,204,204,204,204,205,205,205,205,206,206,
+  206,206,207,207,207,207,208,208,208,208,209,209,209,209,210,210,
+  210,210,211,211,211,211,212,212,212,212,213,213,213,213,214,214,
+  214,214,215,215,215,215,216,217,217,217,218,218,218,218,217,217,
+  217,217,219,106,106,106,106,109,109,109,220,220,220,220,221,221,
+  221,221,  0,222, 86,  0,  0,  0,222,  7, 82,138,  7,  0,  0,  0,
+  223, 86,224,224,224,224,225,225,225,225,226,226,226,226,227,227,
+  227,227,228,228,228,228,229,  0,  0,  0,  0,  0,  0,  0,  0, 19,
+   19, 19, 19, 19, 19, 19, 19, 19, 19,  0,  0,  0, 19,  0, 19,  0,
+    0,  0,  0,  0, 26, 26,  1,  1,  1,  1,  9,  9,  9,  9,  0,  9,
+    9,  9,  9,  9,  0,  9,  9,  0,  9,  0,  9,  9, 55, 55, 55, 55,
+   55, 55,  6,  6,  6,  6,  6,  1,  1,  6,  6,  4,  4,  4,  4,  4,
+    4,  4,  4, 14, 14, 14, 14, 14, 14, 14,  3,  3,  3,  3,  3,  0,
+    3,  3,  0,  3,  3,  3,  3,  3,  3,  0,  3,  3,  3,  1,  1,  1,
+    3,  3,  1,  3,  3,  3, 37, 37, 37, 37, 38, 38, 38, 38, 64, 64,
+   64, 64, 90, 90, 90, 90, 95, 95, 95, 95,  3,  3,  0,  3,  7,  7,
+    7,  7,  7,  1,  1,  1,  1,  7,  7,  7,  0,  0,  7,  7,  5,  5,
+    5,  5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 22, 22,
+   22, 22, 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 36, 36,
+   36, 36, 24, 24, 24, 24, 24, 24, 24,  0, 18, 18, 18, 18, 25, 25,
+   25, 25, 25,  0,  0,  0,  0, 25, 25, 25, 33, 33, 33, 33,  8,  8,
+    8,  8,  8,  8,  8,  0, 12, 12, 12, 12, 30, 30, 30, 30, 29, 29,
+   29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35,
+   35,  0,  0,  0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, 44,  0,
+    0,  0, 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, 32, 32,
+    0,  0, 32,  0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 52, 52,
+   52, 52, 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, 62, 62,
+   62, 62, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 73, 73,
+   73, 73,  1,  1,  1,  0,  1,  0,  1,  1,  1,  0,  0,  0,  0,  1,
+    0,  0,  1,  1,  0,  0, 19, 19,  9,  9,  9,  9,  9,  6, 19,  9,
+    9,  9,  9,  9, 19, 19,  9,  9,  9, 19,  6, 19, 19, 19, 19, 19,
+   19,  9,  0,  0,  0, 19,  0,  0,  9,  0,  0,  0, 19, 19, 27, 27,
+   27, 27, 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13,  0, 13,
+    0, 13,  0, 13, 13, 13, 13, 13,  1,  1,  1,  1, 12, 12,  0, 15,
+   15, 15, 15, 15, 15, 15, 15,  1,  1,  0,  0, 17, 17, 17, 17, 17,
+   17, 17, 17, 17, 17,  0, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12,
+   12,  0, 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79,
+   79, 79, 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, 69, 69,
+   69, 69, 69, 69,  0, 69, 74, 74, 74, 74, 84, 84, 84, 84, 84, 84,
+   84,  0, 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, 19,  9,
+   19, 19, 19, 19,  0,  0,  2,  2,  2,  2, 19, 19, 19,  4,  3,  3,
+    0,  0,  1,  1,  6,  6,  0,  0, 17, 17, 17, 17,  0,  0, 49, 49,
+   49, 49,  0,  1,  1,  1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42,
+   42, 42, 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59,
+   59, 59, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135,
+  135,135,106,106,106,106,104,104,104,104,110,110,110,110, 47, 47,
+   47, 47, 81, 81, 81, 81,120,120,120,120,116,116,116,116,128,128,
+  128,128, 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 97, 97,
+   97, 97, 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,112,112,
+  112,112, 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,122,122,
+  122,122, 89, 89, 89, 89,130,130,130,130,144,144,144,144,156,156,
+  156,156,147,147,147,147,148,148,148,148,153,153,153,153,149,149,
+  149,149, 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101, 96, 96,
+   96, 96,111,111,111,111,100,100,100,100,100, 36, 36, 36,108,108,
+  108,108,129,129,129,129,109,109,109,109,107,107,107,107,107,107,
+  107,  1,137,137,137,137,124,124,124,124,123,123,123,123,114,114,
+  114,114,102,102,102,102,126,126,126,126,142,142,142,142,125,125,
+  125,125,154,154,154,154,150,150,150,150,141,141,141,141,140,140,
+  140,140,121,121,121,121,133,133,133,133,134,134,134,134,138,138,
+  138,138,143,143,143,143,145,145,145,145, 63, 63, 63, 63, 80, 80,
+   80, 80,127,127,127,127,115,115,115,115,103,103,103,103,119,119,
+  119,119,146,146,146,146, 99, 99, 99, 99,136,139,  0,  0,155,155,
+  155,155,136,136,136,136, 17, 15, 15, 15,139,139,139,139,105,105,
+  105,105,  0,  0,  0,  1,  0,  0,  1,  1,131,131,131,131,151,151,
+  151,151,152,152,152,152,113,113,113,113,132,132,132,132, 15,  0,
+    0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  9,  9,  9, 10,
+    9, 11, 12, 13,  9,  9,  9, 14,  9,  9, 15,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 16, 17,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 18, 19, 20,  9, 21,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 22,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+    9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, 23, 24,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,
+    5,  6,  7,  8,  9, 10, 11, 12,  0,  0, 13, 14, 15, 16, 17, 18,
+   19, 20, 21, 22,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 23,  0,  0, 24, 25, 26, 27, 28, 29, 30,  0,  0,
+   31, 32,  0, 33,  0, 34,  0, 35,  0,  0,  0,  0, 36, 37, 38, 39,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 40,  0,  0,  0,  0,  0,  0,  0,  0,  0, 41, 42,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0, 43, 44,  0, 45,  0,  0,  0,  0,  0,  0, 46, 47,  0,  0,
+    0,  0,  0, 48,  0, 49,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 50, 51,  0,  0,  0, 52,  0,  0, 53,  0,  0,  0,
+    0,  0,  0,  0, 54,  0,  0,  0,  0,  0,  0,  0, 55,  0,  0,  0,
+    0,  0,  0,  0, 56,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0, 58, 59, 60, 61, 62, 63, 64, 65,  0,  0,  0,  0,
+    0,  0, 66,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   67, 68,  0, 69, 70,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+   87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,
+  103,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,104,  0,  0,  0,  0,  0,  0,105,106,  0,107,  0,  0,  0,
+  108,  0,109,  0,110,  0,111,112,113,  0,114,  0,  0,  0,115,  0,
+    0,  0,116,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,117,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,118,119,120,121,  0,122,123,124,125,126,  0,127,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+  144,145,146,147,148,149,150,151,152,153,154,155,156,157,  0,  0,
+    0,158,159,160,161,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,162,163,  0,  0,  0,  0,  0,
+    0,  0,164,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,165,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,166,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,167,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,168,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,169,170,  0,  0,  0,  0,171,172,  0,  0,  0,
+  173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,
+  189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,
+  205,206,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,
+};
+static const uint16_t
+_hb_ucd_u16[4848] =
+{
+     0,   0,   1,   2,   3,   4,   5,   6,   0,   0,   7,   8,   9,  10,  11,  12,
+    13,  13,  13,  14,  15,  13,  13,  16,  17,  18,  19,  20,  21,  22,  13,  23,
+    13,  13,  13,  24,  25,  11,  11,  11,  11,  26,  11,  27,  28,  29,  30,  31,
+    32,  32,  32,  32,  32,  32,  32,  33,  34,  35,  36,  11,  37,  38,  13,  39,
+     9,   9,   9,  11,  11,  11,  13,  13,  40,  13,  13,  13,  41,  13,  13,  13,
+    13,  13,  13,  35,   9,  42,  11,  11,  43,  44,  32,  45,  46,  47,  47,  48,
+    49,  50,  47,  47,  51,  32,  52,  53,  47,  47,  47,  47,  47,  54,  55,  56,
+    57,  58,  47,  32,  59,  47,  47,  47,  47,  47,  60,  53,  61,  47,  62,  63,
+    47,  64,  65,  66,  47,  67,  47,  47,  47,  47,  47,  47,  47,  68,  69,  32,
+    70,  47,  47,  71,  72,  73,  74,  75,  76,  47,  47,  77,  78,  79,  80,  81,
+    82,  47,  47,  83,  84,  85,  86,  87,  82,  47,  47,  77,  88,  47,  80,  89,
+    90,  47,  47,  91,  92,  93,  80,  94,  95,  47,  47,  96,  97,  98,  99, 100,
+   101,  47,  47, 102, 103, 104,  80, 105, 106,  47,  47,  91, 107, 108,  80, 109,
+   110,  47,  47, 111, 112, 113,  80, 114,  90,  47,  47,  47, 115, 116,  99, 117,
+    47,  47,  47, 118, 119, 120,  66,  66,  47,  47,  47, 121, 122, 123,  47,  47,
+   124, 125, 126, 127,  47,  47,  47, 128, 129,  32,  32, 130, 131, 132,  66,  66,
+    47,  47, 133, 134, 120, 135, 136, 137, 138, 139,   9,   9,   9,  11,  11, 140,
+    47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47,  47, 141, 142, 143,
+    47, 144,   9,   9,   9,   9,   9, 145, 146,  47,  47,  47,  47,  47,  47,  47,
+    47,  47,  47,  47,  47,  47, 147,  47, 148, 149,  47,  47,  47,  47, 150, 151,
+    47, 152,  47, 153,  47, 152,  47, 152,  47,  47,  47, 154, 155, 156, 157, 143,
+   158, 157,  47,  47, 159,  47,  47,  47, 160,  47, 161,  47,  47,  47,  47,  47,
+    47,  47, 162, 163, 164,  47,  47,  47,  47,  47,  47,  47,  47, 165, 144, 144,
+    47, 166,  47,  47,  47, 167, 168, 169, 157, 157, 170, 171,  32,  32,  32,  32,
+   172,  47,  47, 173, 174, 120, 175, 176, 177,  47, 178,  61,  47,  47, 179, 180,
+    47,  47, 181, 182, 183,  61,  47, 184,  11,   9,   9,   9,  66, 185, 186, 187,
+    11,  11, 188,  27,  27,  27, 189, 190,  11, 191,  27,  27,  32,  32,  32,  32,
+    13,  13,  13,  13,  13,  13,  13,  13,  13, 192,  13,  13,  13,  13,  13,  13,
+   193, 193, 193, 193, 193, 194, 193,  11, 195, 195, 195, 196, 197, 198, 198, 197,
+   199, 200, 201, 202, 203, 204, 205, 206, 207,  27, 208, 208, 208, 209, 210,  32,
+   211, 212, 213, 214, 215, 143, 216, 216, 217, 218, 219, 144, 220, 221, 144, 222,
+   223, 223, 223, 223, 223, 223, 223, 223, 224, 144, 225, 144, 144, 144, 144, 226,
+   144, 227, 223, 228, 144, 229, 230, 144, 144, 144, 144, 144, 144, 144, 143, 143,
+   143, 231, 144, 144, 144, 144, 232, 143, 144, 144, 144, 144, 144, 144, 144, 144,
+   144, 144, 144, 233, 234, 144, 144, 235, 144, 144, 144, 144, 144, 144, 236, 144,
+   144, 144, 144, 144, 144, 144, 237, 238, 143, 239, 144, 144, 240, 223, 241, 223,
+   242, 243, 223, 223, 223, 244, 223, 245, 144, 144, 144, 223, 246, 144, 144, 144,
+     9,   9,   9,  11,  11,  11, 247, 248,  13,  13,  13,  13,  13,  13, 249, 250,
+    11,  11,  11,  47,  47,  47, 251, 252,  47,  47,  47,  47,  47,  47,  32,  32,
+   253, 254, 255, 256, 257, 258,  66,  66, 259, 260, 261, 262, 263,  47,  47,  47,
+    47, 264, 146,  47,  47,  47,  47, 265,  47, 266,  47,  47, 144, 144, 144,  47,
+   144, 144, 267, 144, 268, 269, 144, 144, 267, 144, 144, 269, 144, 144, 144, 144,
+    47,  47,  47,  47, 144, 144, 144, 144,  47, 270,  47,  47,  47,  47,  47,  47,
+    47, 144, 144, 144, 144,  47,  47, 184, 271,  47,  61,  47,  13,  13, 272, 273,
+    13, 274,  47,  47,  47,  47, 275, 276,  31, 277, 278, 279,  13,  13,  13, 280,
+   281, 282, 283, 284, 285,  11,  11, 286, 287,  47, 288, 289,  47,  47,  47, 290,
+   291,  47,  47, 292, 293, 157,  32, 294,  61,  47, 295,  47, 296, 297,  47,  47,
+    70,  47,  47, 298, 299, 300, 301,  61,  47,  47, 302, 303, 304, 305,  47, 306,
+    47,  47,  47, 307,  58, 308, 309, 310,  47,  47,  47,  11,  11, 311, 312,  11,
+    11,  11,  11,  11,  47,  47, 313, 157, 314, 314, 314, 314, 314, 314, 314, 314,
+   315, 315, 315, 315, 315, 315, 315, 315,  11, 316, 317,  47,  47,  47,  47,  47,
+    47,  47,  47, 318,  31, 319,  47,  47,  47,  47,  47, 320, 321,  47,  47,  47,
+    47,  47,  47,  47,  47,  47,  47, 322,  32, 323,  32, 324, 325, 326, 327,  47,
+    47,  47,  47,  47,  47,  47,  47, 328, 329,   2,   3,   4,   5, 330, 331, 332,
+    47, 333,  47,  47,  47,  47, 334, 335, 336, 143, 143, 337, 216, 216, 216, 338,
+   339, 144, 144, 144, 144, 144, 144, 340, 341, 341, 341, 341, 341, 341, 341, 341,
+    47,  47,  47,  47,  47,  47, 342, 143,  47,  47, 343,  47, 344,  47,  47,  60,
+    47, 345,  47,  47,  47, 346, 216, 216,   9,   9, 145,  11,  11,  47,  47,  47,
+    47,  47, 157,   9,   9, 145,  11,  11,  47,  47,  47,  47,  47,  47, 345,  66,
+    47,  47,  47,  47,  47, 347,  47, 348,  47,  47, 349, 143, 143, 143,  47, 350,
+    47, 351,  47, 345,  66,  66,  66,  66,  47,  47,  47, 352, 143, 143, 143, 143,
+   353,  47,  47, 354, 143,  66,  47, 355,  47, 356, 143, 143, 357,  47, 358,  66,
+    47,  47,  47, 359,  47, 360,  47, 360,  47, 359, 142, 143, 143, 143, 143, 143,
+     9,   9,   9,   9,  11,  11,  11, 361,  47,  47, 362, 157, 157, 157, 157, 157,
+   143, 143, 143, 143, 143, 143, 143, 143,  47,  47, 363,  47,  47,  47,  47,  47,
+    47, 356, 364,  47,  60, 365,  66,  66,  47,  47,  47,  47, 366, 143,  47,  47,
+   367,  47,  47, 354, 368, 369, 370, 371, 177,  47,  47, 372, 373,  47,  47, 157,
+    95,  47, 374, 375, 376,  47,  47, 377, 177,  47,  47, 378, 379, 380, 381, 143,
+    47,  47, 382, 383,  32,  32,  32,  32,  47,  47, 359,  47,  47, 384, 169, 157,
+    90,  47,  47, 111, 385, 386, 387,  32,  47,  47,  47, 388, 389, 390,  47,  47,
+    47,  47,  47, 391, 392, 157, 157, 157,  47,  47, 393, 394, 395, 396,  32,  32,
+    47,  47,  47, 397, 398, 157,  66,  66,  47,  47, 399, 400, 157, 157, 157, 157,
+    47, 141, 401, 402, 144, 144, 144, 144,  47,  47, 382, 403,  66,  66,  66,  66,
+     9,   9,   9,   9,  11,  11, 126, 404,  47,  47,  47, 405, 406, 157, 157, 157,
+    47,  47,  47,  47,  47, 407, 408, 409, 410,  47,  47, 411, 412, 413,  47,  47,
+   414, 415,  66,  66,  47,  47,  47,  47,  47,  47, 393, 416, 417, 126, 143, 418,
+    47, 152, 419, 420,  32,  32,  32,  32,  47,  47,  47, 353, 421, 157,  47,  47,
+   422, 423, 157, 157, 157, 157, 157, 157,  47,  47,  47,  47,  47,  47,  47, 424,
+    47,  47,  47,  47, 143, 425, 426, 427, 216, 216, 216, 216, 216, 216, 216,  66,
+    47,  47,  47, 205, 205, 205, 205, 205,  47,  47,  47,  47,  47,  47, 300,  66,
+    47,  47,  47,  47,  47,  47,  47, 428,  47,  47,  47, 429, 430, 431, 432,  47,
+     9,   9,   9,   9,   9,   9,  11,  11, 143, 433,  66,  66,  66,  66,  66,  66,
+    47,  47,  47,  47, 384, 434, 409, 409, 435, 436,  27,  27,  27,  27, 437, 409,
+    47, 438, 205, 205, 205, 205, 205, 205, 144, 144, 144, 144, 144, 144, 439, 440,
+   441, 144, 442, 144, 144, 144, 144, 144, 144, 144, 144, 144, 443, 144, 144, 144,
+     9, 444,  11, 445, 446,  11, 193,   9, 447, 448,   9, 449,  11,   9, 444,  11,
+   445, 446,  11, 193,   9, 447, 448,   9, 449,  11,   9, 444,  11, 445, 446,  11,
+   193,   9, 447, 448,   9, 449,  11,   9, 444,  11, 193,   9, 450, 451, 452, 453,
+    11, 454,   9, 455, 456, 457, 458,  11, 459,   9, 460,  11, 461, 157, 157, 157,
+    32,  32,  32, 462,  32,  32, 463, 464, 465, 466,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  47,  47,  47, 467, 468, 144, 144, 144,
+    47,  47,  47,  47,  47,  47, 469, 470,  47,  47,  47,  47, 349,  32,  32,  32,
+     9,   9, 447,  11, 471, 300,  66,  66, 143, 143, 472, 473, 143, 143, 143, 143,
+   143, 143, 474, 143, 143, 143, 143, 143,  47,  47,  47,  47,  47,  47,  47, 223,
+   475, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 476,
+   144, 144, 144, 144, 144, 144, 144, 157, 205, 205, 205, 205, 205, 205, 205, 205,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   939, 940, 941, 942, 946, 948,   0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
+     0,1033,1040,1041,1042,1043,1047,   0,   0,1080,1081,1082,1086,1110,   0,   0,
+  1124,1125,1126,1127,1131,1133,   0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
+     0,1219,1226,1227,1228,1229,1233,   0,   0,1267,1268,1269,1273,1298,   0,1303,
+   943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
+     0,   0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
+   991,1176, 993,1178, 994,1179,   0,   0,1004,1190,1005,1191,1006,1192,1014,1199,
+  1007,   0,   0,   0,1016,1201,1020,1206,   0,1022,1208,1025,1211,1023,1209,   0,
+     0,   0,   0,1032,1218,1037,1223,1035,1221,   0,   0,   0,1044,1230,1045,1231,
+  1049,1235,   0,   0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
+  1069,1255,1077,1264,1074,1261,   0,   0,1083,1270,1084,1271,1085,1272,1088,1275,
+  1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310,   0,
+  1053,1239,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1093,
+  1280,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 949,1134,1010,
+  1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366,   0,1320,1347,
+  1418,1419,1323,1350,   0,   0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
+  1202,   0,   0,   0, 987,1172,   0,   0,1031,1217,1321,1348,1322,1349,1338,1365,
+   950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
+  1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263,   0,   0, 997,1182,
+     0,   0,   0,   0,   0,   0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
+  1422,1423,1113,1301,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     8,   9,   0,  10,1425,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   7,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,
+     0,   0,   0,   0,   0,1314,1427,   5,1434,1438,1443,   0,1450,   0,1455,1461,
+  1514,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1446,1458,1468,1476,1480,1486,
+  1517,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1489,1503,1494,1500,1508,   0,
+     0,   0,   0,1520,1521,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1526,1528,   0,1525,   0,   0,   0,1522,   0,   0,   0,   0,1536,1532,1539,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1534,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1556,   0,   0,   0,   0,   0,   0,
+  1548,1550,   0,1547,   0,   0,   0,1567,   0,   0,   0,   0,1558,1554,1561,   0,
+     0,   0,   0,   0,   0,   0,1568,1569,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1529,1551,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1523,1545,1524,1546,   0,   0,1527,1549,   0,   0,1570,1571,1530,1552,1531,1553,
+     0,   0,1533,1555,1535,1557,1537,1559,   0,   0,1572,1573,1544,1566,1538,1560,
+  1540,1562,1541,1563,1542,1564,   0,   0,1543,1565,   0,   0,   0,   0,   0,   0,
+     0,   0,1606,1607,1609,1608,1610,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  1613,   0,1611,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1612,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1620,   0,   0,   0,   0,   0,   0,
+     0,1623,   0,   0,1624,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1614,1615,1616,1617,1618,1619,1621,1622,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1628,1629,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1625,1626,   0,1627,
+     0,   0,   0,1634,   0,   0,1635,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1630,1631,1632,   0,   0,1633,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1639,   0,   0,1638,1640,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1636,1637,   0,   0,
+     0,   0,   0,   0,1641,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1642,1644,1643,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1645,   0,   0,   0,   0,   0,   0,   0,
+  1646,   0,   0,   0,   0,   0,   0,1648,1649,   0,1647,1650,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1651,1653,1652,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1654,   0,1655,1657,1656,   0,
+     0,   0,   0,1659,   0,   0,   0,   0,   0,   0,   0,   0,   0,1660,   0,   0,
+     0,   0,1661,   0,   0,   0,   0,1662,   0,   0,   0,   0,1663,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1658,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1664,   0,1665,1673,   0,1674,   0,   0,   0,   0,   0,   0,   0,
+     0,1666,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,1668,   0,   0,   0,   0,   0,   0,   0,   0,   0,1669,   0,   0,
+     0,   0,1670,   0,   0,   0,   0,1671,   0,   0,   0,   0,1672,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,1667,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1675,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,1676,   0,1677,   0,1678,   0,1679,   0,1680,   0,
+     0,   0,1681,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1682,   0,1683,   0,   0,
+  1684,1685,   0,1686,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
+   966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
+   989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
+  1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
+  1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
+  1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
+  1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
+  1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
+  1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
+  1119,1308,1122,1311,1123,1312,1186,1260,1293,1305,   0,1394,   0,   0,   0,   0,
+   952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
+  1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
+  1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
+  1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
+  1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
+  1409,1414,1109,1297,1117,1306,1116,1304,1112,1300,   0,   0,   0,   0,   0,   0,
+  1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
+  1477,1478,1729,1731,1730,1732,   0,   0,1435,1436,1733,1735,1734,1736,   0,   0,
+  1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
+  1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
+  1495,1496,1777,1779,1778,1780,   0,   0,1451,1452,1781,1783,1782,1784,   0,   0,
+  1504,1505,1785,1788,1786,1789,1787,1790,   0,1459,   0,1791,   0,1792,   0,1793,
+  1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
+  1467,  21,1475,  22,1479,  23,1485,  24,1493,  27,1499,  28,1507,  29,   0,   0,
+  1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
+  1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
+  1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
+  1470,1469,1822,1474,1465,   0,1473,1825,1429,1428,1426,  12,1432,   0,  26,   0,
+     0,1315,1823,1484,1466,   0,1483,1829,1433,  13,1437,  14,1441,1826,1827,1828,
+  1488,1487,1513,  19,   0,   0,1492,1515,1445,1444,1442,  15,   0,1831,1832,1833,
+  1502,1501,1516,  25,1497,1498,1506,1518,1457,1456,1454,  17,1453,1313,  11,   3,
+     0,   0,1824,1512,1519,   0,1511,1830,1449,  16,1460,  18,1464,   4,   0,   0,
+    30,  31,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,  20,   0,   0,   0,   2,   6,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1834,1835,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1836,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1837,1839,1838,
+     0,   0,   0,   0,1840,   0,   0,   0,   0,1841,   0,   0,1842,   0,   0,   0,
+     0,   0,   0,   0,1843,   0,1844,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,1845,   0,   0,1846,   0,   0,1847,   0,1848,   0,   0,   0,   0,   0,   0,
+   937,   0,1850,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1849, 936, 938,
+  1851,1852,   0,   0,1853,1854,   0,   0,1855,1856,   0,   0,   0,   0,   0,   0,
+  1857,1858,   0,   0,1861,1862,   0,   0,1863,1864,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1867,1868,1869,1870,
+  1859,1860,1865,1866,   0,   0,   0,   0,   0,   0,1871,1872,1873,1874,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,  32,  33,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1875,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1877,   0,1878,   0,
+  1879,   0,1880,   0,1881,   0,1882,   0,1883,   0,1884,   0,1885,   0,1886,   0,
+  1887,   0,1888,   0,   0,1889,   0,1890,   0,1891,   0,   0,   0,   0,   0,   0,
+  1892,1893,   0,1894,1895,   0,1896,1897,   0,1898,1899,   0,1900,1901,   0,   0,
+     0,   0,   0,   0,1876,   0,   0,   0,   0,   0,   0,   0,   0,   0,1902,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1904,   0,1905,   0,
+  1906,   0,1907,   0,1908,   0,1909,   0,1910,   0,1911,   0,1912,   0,1913,   0,
+  1914,   0,1915,   0,   0,1916,   0,1917,   0,1918,   0,   0,   0,   0,   0,   0,
+  1919,1920,   0,1921,1922,   0,1923,1924,   0,1925,1926,   0,1927,1928,   0,   0,
+     0,   0,   0,   0,1903,   0,   0,1929,1930,1931,1932,   0,   0,   0,1933,   0,
+   710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
+   663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
+   810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
+   368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
+   811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
+   594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
+   313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
+   424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
+   193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
+   337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
+   683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
+   608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
+   479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
+   791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
+   377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
+   659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
+   153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210,   0,   0,
+   227,   0, 379,   0,   0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604,   0,
+   661,   0, 703,   0,   0, 735, 743,   0,   0,   0, 793, 794, 795, 808, 741, 773,
+   118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
+   335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
+   549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
+   690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623,   0,   0,
+   102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
+   250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
+   370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
+   493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
+   591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
+   709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
+   847, 857,  55,  65,  66, 883, 892, 916, 822, 824,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1586,   0,1605,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1602,1603,1934,1935,1574,1575,
+  1576,1577,1579,1580,1581,1583,1584,   0,1585,1587,1588,1589,1591,   0,1592,   0,
+  1593,1594,   0,1595,1596,   0,1598,1599,1600,1601,1604,1582,1578,1590,1597,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1936,   0,1937,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1938,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1939,1940,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1941,1942,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1944,1943,   0,1945,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1946,1947,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,1948,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1949,1950,
+  1951,1952,1953,1954,1955,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,1956,1957,1958,1960,1959,
+  1961,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+   106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125,  34, 830, 130, 131,
+   132, 137, 827,  35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152,  37,
+   157, 158, 159, 160,  38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
+   181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
+   197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
+   153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
+   836, 837, 247, 248, 249, 246, 251,  39,  40, 253, 255, 255, 838, 257, 258, 259,
+   261, 839, 262, 263, 301, 264,  41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
+   278, 281, 282,  42, 283, 284, 285, 286,  43, 843,  44, 289, 290, 291, 293, 934,
+   298, 845, 845, 621, 300, 300,  45, 852, 894, 302, 304,  46, 306, 309, 310, 312,
+   316,  48,  47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
+   335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
+   358, 356,  49, 363, 365, 367, 364,  50, 369, 371, 851, 376, 386, 378,  53, 381,
+    52,  51, 140, 141, 387, 382, 614,  78, 388, 389, 390, 394, 392, 856,  54, 399,
+   396, 402, 404, 858, 405, 401, 407,  55, 408, 409, 410, 413, 859, 415,  56, 417,
+   860, 418,  57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
+   437, 441, 438, 439, 442, 443, 864, 436, 449, 450,  58, 454, 453, 865, 447, 460,
+   866, 867, 461, 466, 465, 464,  59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
+   483, 485, 486, 871, 488, 489, 872, 873, 495, 497,  60, 498,  61,  61, 504, 505,
+   507, 508, 511,  62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878,  63,  64,
+   528, 880, 879, 881, 882, 530, 531, 531, 533,  66, 534,  67,  68, 884, 536, 538,
+   541,  69, 885, 549, 886, 887, 556, 559,  70, 561, 562, 563, 888, 889, 889, 567,
+    71, 890, 570, 571,  72, 891, 577,  73, 581, 579, 582, 893, 587,  74, 590, 592,
+   596,  75, 895, 896,  76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
+   853,  77, 615, 616,  79, 617, 252, 902, 903, 854, 855, 621, 622, 731,  80, 627,
+   626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
+   638, 643, 644, 645, 905, 907, 906,  81, 653, 654, 656, 911, 657, 908,  82,  83,
+   909, 910,  84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675,  85,
+   677, 678,  86, 681, 682, 912, 685, 686,  87, 689,  36, 913, 914,  88,  89, 696,
+   702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
+   918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762,  90,
+   764, 922,  91, 775, 279, 780, 923, 925,  92,  93, 785, 926,  94, 927, 787, 787,
+   789, 928, 792,  95, 796, 797, 798, 800,  96, 929, 802, 804, 806,  97,  98, 807,
+   930,  99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935,   0,   0,
+};
+static const int16_t
+_hb_ucd_i16[92] =
+{
+      0,    0,    1,   -1,    2,    0,   -2,    0,    0,    2,    0,   -2,    0,   16,    0,  -16,
+      0,    1,   -1,    0,    3,    3,    3,   -3,   -3,   -3,    0, 2016,    0, 2527, 1923, 1914,
+   1918,    0, 2250,    0,    0,  138,    0,    7,   -7,    0,   -1,    1, 1824,    0, 2104,    0,
+   2108, 2106,    0, 2106, 1316,    0,   -1, -138,    8,    8,    8,    0,    7,    7,   -8,   -8,
+     -8,   -7,-1316,    1,   -1,    3,   -3,    1,    0,-1914,-1918,    0,    0,-1923,-1824,    0,
+      0,-2016,-2104,    0,    0,-2106,-2108,-2106,-2250,    0,-2527,    0,
+};
+
+static inline uint_fast8_t
+_hb_ucd_gc (unsigned u)
+{
+  return u<1114112u?_hb_ucd_u8[4920+(((_hb_ucd_u8[1104+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>3>>5])<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+}
+static inline uint_fast8_t
+_hb_ucd_ccc (unsigned u)
+{
+  return u<125259u?_hb_ucd_u8[6796+(((_hb_ucd_u8[6276+(((_hb_ucd_u8[5844+(((_hb_ucd_u8[5508+(((_hb_ucd_u8[5262+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+}
+static inline unsigned
+_hb_ucd_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline int_fast16_t
+_hb_ucd_bmg (unsigned u)
+{
+  return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7672+(((_hb_ucd_u8[7448+(((_hb_ucd_u8[7352+(((_hb_ucd_b4(7288+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
+}
+static inline uint_fast8_t
+_hb_ucd_sc (unsigned u)
+{
+  return u<918016u?_hb_ucd_u8[11242+(((_hb_ucd_u8[10314+(((_hb_ucd_u8[8938+(((_hb_ucd_u8[8362+(((_hb_ucd_u8[7912+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
+}
+static inline uint_fast16_t
+_hb_ucd_dm (unsigned u)
+{
+  return u<195102u?_hb_ucd_u16[1536+(((_hb_ucd_u8[12544+(((_hb_ucd_u8[12162+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+}
+
+#endif
+
+
+#endif /* HB_UCD_TABLE_HH */
+
+/* == End of generated table == */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucd.cc b/src/java.desktop/share/native/libharfbuzz/hb-ucd.cc
new file mode 100644
index 0000000..f56f05f
--- /dev/null
+++ b/src/java.desktop/share/native/libharfbuzz/hb-ucd.cc
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hb.hh"
+#include "hb-unicode.hh"
+#include "hb-machinery.hh"
+
+#include "hb-ucd-table.hh"
+
+static hb_unicode_combining_class_t
+hb_ucd_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+                        hb_codepoint_t unicode,
+                        void *user_data HB_UNUSED)
+{
+  return (hb_unicode_combining_class_t) _hb_ucd_ccc (unicode);
+}
+
+static hb_unicode_general_category_t
+hb_ucd_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+                         hb_codepoint_t unicode,
+                         void *user_data HB_UNUSED)
+{
+  return (hb_unicode_general_category_t) _hb_ucd_gc (unicode);
+}
+
+static hb_codepoint_t
+hb_ucd_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+                  hb_codepoint_t unicode,
+                  void *user_data HB_UNUSED)
+{
+  return unicode + _hb_ucd_bmg (unicode);
+}
+
+static hb_script_t
+hb_ucd_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+               hb_codepoint_t unicode,
+               void *user_data HB_UNUSED)
+{
+  return _hb_ucd_sc_map[_hb_ucd_sc (unicode)];
+}
+
+
+#define SBASE 0xAC00u
+#define LBASE 0x1100u
+#define VBASE 0x1161u
+#define TBASE 0x11A7u
+#define SCOUNT 11172u
+#define LCOUNT 19u
+#define VCOUNT 21u
+#define TCOUNT 28u
+#define NCOUNT (VCOUNT * TCOUNT)
+
+static inline bool
+_hb_ucd_decompose_hangul (hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b)
+{
+  unsigned si = ab - SBASE;
+
+  if (si >= SCOUNT)
+    return false;
+
+  if (si % TCOUNT)
+  {
+    /* LV,T */
+    *a = SBASE + (si / TCOUNT) * TCOUNT;
+    *b = TBASE + (si % TCOUNT);
+    return true;
+  } else {
+    /* L,V */
+    *a = LBASE + (si / NCOUNT);
+    *b = VBASE + (si % NCOUNT) / TCOUNT;
+    return true;
+  }
+}
+
+static inline bool
+_hb_ucd_compose_hangul (hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab)
+{
+  if (a >= SBASE && a < (SBASE + SCOUNT) && b > TBASE && b < (TBASE + TCOUNT) &&
+    !((a - SBASE) % TCOUNT))
+  {
+    /* LV,T */
+    *ab = a + (b - TBASE);
+    return true;
+  }
+  else if (a >= LBASE && a < (LBASE + LCOUNT) && b >= VBASE && b < (VBASE + VCOUNT))
+  {
+    /* L,V */
+    int li = a - LBASE;
+    int vi = b - VBASE;
+    *ab = SBASE + li * NCOUNT + vi * TCOUNT;
+    return true;
+  }
+  else
+    return false;
+}
+
+static int
+_cmp_pair (const void *_key, const void *_item)
+{
+  uint64_t& a = * (uint64_t*) _key;
+  uint64_t b = (* (uint64_t*) _item) & HB_CODEPOINT_ENCODE3(0x1FFFFFu, 0x1FFFFFu, 0);
+
+  return a < b ? -1 : a > b ? +1 : 0;
+}
+static int
+_cmp_pair_11_7_14 (const void *_key, const void *_item)
+{
+  uint32_t& a = * (uint32_t*) _key;
+  uint32_t b = (* (uint32_t*) _item) & HB_CODEPOINT_ENCODE3_11_7_14(0x1FFFFFu, 0x1FFFFFu, 0);
+
+  return a < b ? -1 : a > b ? +1 : 0;
+}
+
+static hb_bool_t
+hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+                hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
+                void *user_data HB_UNUSED)
+{
+  if (_hb_ucd_compose_hangul (a, b, ab)) return true;
+
+  hb_codepoint_t u = 0;
+
+  if ((a & 0xFFFFF800u) == 0x0000u && (b & 0xFFFFFF80) == 0x0300u)
+  {
+    uint32_t k = HB_CODEPOINT_ENCODE3_11_7_14 (a, b, 0);
+    const uint32_t *v = hb_bsearch (k,
+                                    _hb_ucd_dm2_u32_map,
+                                    ARRAY_LENGTH (_hb_ucd_dm2_u32_map),
+                                    sizeof (*_hb_ucd_dm2_u32_map),
+                                    _cmp_pair_11_7_14);
+    if (likely (!v)) return false;
+    u = HB_CODEPOINT_DECODE3_11_7_14_3 (*v);
+  }
+  else
+  {
+    uint64_t k = HB_CODEPOINT_ENCODE3 (a, b, 0);
+    const uint64_t *v = hb_bsearch (k,
+                                    _hb_ucd_dm2_u64_map,
+                                    ARRAY_LENGTH (_hb_ucd_dm2_u64_map),
+                                    sizeof (*_hb_ucd_dm2_u64_map),
+                                    _cmp_pair);
+    if (likely (!v)) return false;
+    u = HB_CODEPOINT_DECODE3_3 (*v);
+  }
+
+  if (unlikely (!u)) return false;
+  *ab = u;
+  return true;
+}
+
+static hb_bool_t
+hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+                  hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b,
+                  void *user_data HB_UNUSED)
+{
+  if (_hb_ucd_decompose_hangul (ab, a, b)) return true;
+
+  unsigned i = _hb_ucd_dm (ab);
+
+  if (likely (!i)) return false;
+  i--;
+
+  if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map))
+  {
+    if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map))
+      *a = _hb_ucd_dm1_p0_map[i];
+    else
+    {
+      i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map);
+      *a = 0x20000 | _hb_ucd_dm1_p2_map[i];
+    }
+    *b = 0;
+    return true;
+  }
+  i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map);
+
+  if (i < ARRAY_LENGTH (_hb_ucd_dm2_u32_map))
+  {
+    uint32_t v = _hb_ucd_dm2_u32_map[i];
+    *a = HB_CODEPOINT_DECODE3_11_7_14_1 (v);
+    *b = HB_CODEPOINT_DECODE3_11_7_14_2 (v);
+    return true;
+  }
+  i -= ARRAY_LENGTH (_hb_ucd_dm2_u32_map);
+
+  uint64_t v = _hb_ucd_dm2_u64_map[i];
+  *a = HB_CODEPOINT_DECODE3_1 (v);
+  *b = HB_CODEPOINT_DECODE3_2 (v);
+  return true;
+}
+
+
+#if HB_USE_ATEXIT
+static void free_static_ucd_funcs ();
+#endif
+
+static struct hb_ucd_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucd_unicode_funcs_lazy_loader_t>
+{
+  static hb_unicode_funcs_t *create ()
+  {
+    hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
+
+    hb_unicode_funcs_set_combining_class_func (funcs, hb_ucd_combining_class, nullptr, nullptr);
+    hb_unicode_funcs_set_general_category_func (funcs, hb_ucd_general_category, nullptr, nullptr);
+    hb_unicode_funcs_set_mirroring_func (funcs, hb_ucd_mirroring, nullptr, nullptr);
+    hb_unicode_funcs_set_script_func (funcs, hb_ucd_script, nullptr, nullptr);
+    hb_unicode_funcs_set_compose_func (funcs, hb_ucd_compose, nullptr, nullptr);
+    hb_unicode_funcs_set_decompose_func (funcs, hb_ucd_decompose, nullptr, nullptr);
+
+    hb_unicode_funcs_make_immutable (funcs);
+
+#if HB_USE_ATEXIT
+    atexit (free_static_ucd_funcs);
+#endif
+
+    return funcs;
+  }
+} static_ucd_funcs;
+
+#if HB_USE_ATEXIT
+static
+void free_static_ucd_funcs ()
+{
+  static_ucd_funcs.free_instance ();
+}
+#endif
+
+hb_unicode_funcs_t *
+hb_ucd_get_unicode_funcs ()
+{
+#ifdef HB_NO_UCD
+  return hb_unicode_funcs_get_empty ();
+#endif
+  return static_ucd_funcs.get_unconst ();
+}
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucdn.cc b/src/java.desktop/share/native/libharfbuzz/hb-ucdn.cc
deleted file mode 100644
index d80f6e9..0000000
--- a/src/java.desktop/share/native/libharfbuzz/hb-ucdn.cc
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "hb.hh"
-
-#include "hb-machinery.hh"
-
-#include "ucdn.h"
-
-static const hb_script_t ucdn_script_translate[] =
-{
-    HB_SCRIPT_COMMON,
-    HB_SCRIPT_LATIN,
-    HB_SCRIPT_GREEK,
-    HB_SCRIPT_CYRILLIC,
-    HB_SCRIPT_ARMENIAN,
-    HB_SCRIPT_HEBREW,
-    HB_SCRIPT_ARABIC,
-    HB_SCRIPT_SYRIAC,
-    HB_SCRIPT_THAANA,
-    HB_SCRIPT_DEVANAGARI,
-    HB_SCRIPT_BENGALI,
-    HB_SCRIPT_GURMUKHI,
-    HB_SCRIPT_GUJARATI,
-    HB_SCRIPT_ORIYA,
-    HB_SCRIPT_TAMIL,
-    HB_SCRIPT_TELUGU,
-    HB_SCRIPT_KANNADA,
-    HB_SCRIPT_MALAYALAM,
-    HB_SCRIPT_SINHALA,
-    HB_SCRIPT_THAI,
-    HB_SCRIPT_LAO,
-    HB_SCRIPT_TIBETAN,
-    HB_SCRIPT_MYANMAR,
-    HB_SCRIPT_GEORGIAN,
-    HB_SCRIPT_HANGUL,
-    HB_SCRIPT_ETHIOPIC,
-    HB_SCRIPT_CHEROKEE,
-    HB_SCRIPT_CANADIAN_SYLLABICS,
-    HB_SCRIPT_OGHAM,
-    HB_SCRIPT_RUNIC,
-    HB_SCRIPT_KHMER,
-    HB_SCRIPT_MONGOLIAN,
-    HB_SCRIPT_HIRAGANA,
-    HB_SCRIPT_KATAKANA,
-    HB_SCRIPT_BOPOMOFO,
-    HB_SCRIPT_HAN,
-    HB_SCRIPT_YI,
-    HB_SCRIPT_OLD_ITALIC,
-    HB_SCRIPT_GOTHIC,
-    HB_SCRIPT_DESERET,
-    HB_SCRIPT_INHERITED,
-    HB_SCRIPT_TAGALOG,
-    HB_SCRIPT_HANUNOO,
-    HB_SCRIPT_BUHID,
-    HB_SCRIPT_TAGBANWA,
-    HB_SCRIPT_LIMBU,
-    HB_SCRIPT_TAI_LE,
-    HB_SCRIPT_LINEAR_B,
-    HB_SCRIPT_UGARITIC,
-    HB_SCRIPT_SHAVIAN,
-    HB_SCRIPT_OSMANYA,
-    HB_SCRIPT_CYPRIOT,
-    HB_SCRIPT_BRAILLE,
-    HB_SCRIPT_BUGINESE,
-    HB_SCRIPT_COPTIC,
-    HB_SCRIPT_NEW_TAI_LUE,
-    HB_SCRIPT_GLAGOLITIC,
-    HB_SCRIPT_TIFINAGH,
-    HB_SCRIPT_SYLOTI_NAGRI,
-    HB_SCRIPT_OLD_PERSIAN,
-    HB_SCRIPT_KHAROSHTHI,
-    HB_SCRIPT_BALINESE,
-    HB_SCRIPT_CUNEIFORM,
-    HB_SCRIPT_PHOENICIAN,
-    HB_SCRIPT_PHAGS_PA,
-    HB_SCRIPT_NKO,
-    HB_SCRIPT_SUNDANESE,
-    HB_SCRIPT_LEPCHA,
-    HB_SCRIPT_OL_CHIKI,
-    HB_SCRIPT_VAI,
-    HB_SCRIPT_SAURASHTRA,
-    HB_SCRIPT_KAYAH_LI,
-    HB_SCRIPT_REJANG,
-    HB_SCRIPT_LYCIAN,
-    HB_SCRIPT_CARIAN,
-    HB_SCRIPT_LYDIAN,
-    HB_SCRIPT_CHAM,
-    HB_SCRIPT_TAI_THAM,
-    HB_SCRIPT_TAI_VIET,
-    HB_SCRIPT_AVESTAN,
-    HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
-    HB_SCRIPT_SAMARITAN,
-    HB_SCRIPT_LISU,
-    HB_SCRIPT_BAMUM,
-    HB_SCRIPT_JAVANESE,
-    HB_SCRIPT_MEETEI_MAYEK,
-    HB_SCRIPT_IMPERIAL_ARAMAIC,
-    HB_SCRIPT_OLD_SOUTH_ARABIAN,
-    HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
-    HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
-    HB_SCRIPT_OLD_TURKIC,
-    HB_SCRIPT_KAITHI,
-    HB_SCRIPT_BATAK,
-    HB_SCRIPT_BRAHMI,
-    HB_SCRIPT_MANDAIC,
-    HB_SCRIPT_CHAKMA,
-    HB_SCRIPT_MEROITIC_CURSIVE,
-    HB_SCRIPT_MEROITIC_HIEROGLYPHS,
-    HB_SCRIPT_MIAO,
-    HB_SCRIPT_SHARADA,
-    HB_SCRIPT_SORA_SOMPENG,
-    HB_SCRIPT_TAKRI,
-    HB_SCRIPT_UNKNOWN,
-    HB_SCRIPT_BASSA_VAH,
-    HB_SCRIPT_CAUCASIAN_ALBANIAN,
-    HB_SCRIPT_DUPLOYAN,
-    HB_SCRIPT_ELBASAN,
-    HB_SCRIPT_GRANTHA,
-    HB_SCRIPT_KHOJKI,
-    HB_SCRIPT_KHUDAWADI,
-    HB_SCRIPT_LINEAR_A,
-    HB_SCRIPT_MAHAJANI,
-    HB_SCRIPT_MANICHAEAN,
-    HB_SCRIPT_MENDE_KIKAKUI,
-    HB_SCRIPT_MODI,
-    HB_SCRIPT_MRO,
-    HB_SCRIPT_NABATAEAN,
-    HB_SCRIPT_OLD_NORTH_ARABIAN,
-    HB_SCRIPT_OLD_PERMIC,
-    HB_SCRIPT_PAHAWH_HMONG,
-    HB_SCRIPT_PALMYRENE,
-    HB_SCRIPT_PAU_CIN_HAU,
-    HB_SCRIPT_PSALTER_PAHLAVI,
-    HB_SCRIPT_SIDDHAM,
-    HB_SCRIPT_TIRHUTA,
-    HB_SCRIPT_WARANG_CITI,
-    HB_SCRIPT_AHOM,
-    HB_SCRIPT_ANATOLIAN_HIEROGLYPHS,
-    HB_SCRIPT_HATRAN,
-    HB_SCRIPT_MULTANI,
-    HB_SCRIPT_OLD_HUNGARIAN,
-    HB_SCRIPT_SIGNWRITING,
-    HB_SCRIPT_ADLAM,
-    HB_SCRIPT_BHAIKSUKI,
-    HB_SCRIPT_MARCHEN,
-    HB_SCRIPT_NEWA,
-    HB_SCRIPT_OSAGE,
-    HB_SCRIPT_TANGUT,
-    HB_SCRIPT_MASARAM_GONDI,
-    HB_SCRIPT_NUSHU,
-    HB_SCRIPT_SOYOMBO,
-    HB_SCRIPT_ZANABAZAR_SQUARE,
-    HB_SCRIPT_DOGRA,
-    HB_SCRIPT_GUNJALA_GONDI,
-    HB_SCRIPT_HANIFI_ROHINGYA,
-    HB_SCRIPT_MAKASAR,
-    HB_SCRIPT_MEDEFAIDRIN,
-    HB_SCRIPT_OLD_SOGDIAN,
-    HB_SCRIPT_SOGDIAN,
-};
-
-static hb_unicode_combining_class_t
-hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-                        hb_codepoint_t unicode,
-                        void *user_data HB_UNUSED)
-{
-    return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode);
-}
-
-static hb_unicode_general_category_t
-hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-                         hb_codepoint_t unicode,
-                         void *user_data HB_UNUSED)
-{
-    return (hb_unicode_general_category_t)ucdn_get_general_category(unicode);
-}
-
-static hb_codepoint_t
-hb_ucdn_mirroring(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-                  hb_codepoint_t unicode,
-                  void *user_data HB_UNUSED)
-{
-    return ucdn_mirror(unicode);
-}
-
-static hb_script_t
-hb_ucdn_script(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-               hb_codepoint_t unicode,
-               void *user_data HB_UNUSED)
-{
-    return ucdn_script_translate[ucdn_get_script(unicode)];
-}
-
-static hb_bool_t
-hb_ucdn_compose(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-                hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
-                void *user_data HB_UNUSED)
-{
-    return ucdn_compose(ab, a, b);
-}
-
-static hb_bool_t
-hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs HB_UNUSED,
-                  hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b,
-                  void *user_data HB_UNUSED)
-{
-    return ucdn_decompose(ab, a, b);
-}
-
-
-#if HB_USE_ATEXIT
-static void free_static_ucdn_funcs ();
-#endif
-
-static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucdn_unicode_funcs_lazy_loader_t>
-{
-  static hb_unicode_funcs_t *create ()
-  {
-    hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
-
-    hb_unicode_funcs_set_combining_class_func (funcs, hb_ucdn_combining_class, nullptr, nullptr);
-    hb_unicode_funcs_set_general_category_func (funcs, hb_ucdn_general_category, nullptr, nullptr);
-    hb_unicode_funcs_set_mirroring_func (funcs, hb_ucdn_mirroring, nullptr, nullptr);
-    hb_unicode_funcs_set_script_func (funcs, hb_ucdn_script, nullptr, nullptr);
-    hb_unicode_funcs_set_compose_func (funcs, hb_ucdn_compose, nullptr, nullptr);
-    hb_unicode_funcs_set_decompose_func (funcs, hb_ucdn_decompose, nullptr, nullptr);
-
-    hb_unicode_funcs_make_immutable (funcs);
-
-#if HB_USE_ATEXIT
-    atexit (free_static_ucdn_funcs);
-#endif
-
-    return funcs;
-  }
-} static_ucdn_funcs;
-
-#if HB_USE_ATEXIT
-static
-void free_static_ucdn_funcs ()
-{
-  static_ucdn_funcs.free_instance ();
-}
-#endif
-
-extern "C" HB_INTERNAL
-hb_unicode_funcs_t *
-hb_ucdn_get_unicode_funcs ();
-
-hb_unicode_funcs_t *
-hb_ucdn_get_unicode_funcs ()
-{
-  return static_ucdn_funcs.get_unconst ();
-}
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.c b/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.c
deleted file mode 100644
index 30747fe..0000000
--- a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "ucdn.h"
-
-typedef struct {
-    unsigned char category;
-    unsigned char combining;
-    unsigned char bidi_class;
-    unsigned char east_asian_width;
-    unsigned char script;
-    unsigned char linebreak_class;
-} UCDRecord;
-
-typedef struct {
-    unsigned short from, to;
-} MirrorPair;
-
-typedef struct {
-  unsigned short from, to;
-  unsigned char type;
-} BracketPair;
-
-typedef struct {
-    unsigned int start;
-    short count, index;
-} Reindex;
-
-#include "ucdn_db.h"
-
-/* constants required for Hangul (de)composition */
-#define SBASE 0xAC00
-#define LBASE 0x1100
-#define VBASE 0x1161
-#define TBASE 0x11A7
-#define SCOUNT 11172
-#define LCOUNT 19
-#define VCOUNT 21
-#define TCOUNT 28
-#define NCOUNT (VCOUNT * TCOUNT)
-
-static const UCDRecord *get_ucd_record(uint32_t code)
-{
-    int index, offset;
-
-    if (code >= 0x110000)
-        index = 0;
-    else {
-        index  = index0[code >> (SHIFT1+SHIFT2)] << SHIFT1;
-        offset = (code >> SHIFT2) & ((1<<SHIFT1) - 1);
-        index  = index1[index + offset] << SHIFT2;
-        offset = code & ((1<<SHIFT2) - 1);
-        index  = index2[index + offset];
-    }
-
-    return &ucd_records[index];
-}
-
-static const unsigned short *get_decomp_record(uint32_t code)
-{
-    int index, offset;
-
-    if (code >= 0x110000)
-        index = 0;
-    else {
-        index  = decomp_index0[code >> (DECOMP_SHIFT1+DECOMP_SHIFT2)]
-            << DECOMP_SHIFT1;
-        offset = (code >> DECOMP_SHIFT2) & ((1<<DECOMP_SHIFT1) - 1);
-        index  = decomp_index1[index + offset] << DECOMP_SHIFT2;
-        offset = code & ((1<<DECOMP_SHIFT2) - 1);
-        index  = decomp_index2[index + offset];
-    }
-
-    return &decomp_data[index];
-}
-
-static int compare_reindex(const void *a, const void *b)
-{
-    Reindex *ra = (Reindex *)a;
-    Reindex *rb = (Reindex *)b;
-
-    if (ra->start < rb->start)
-        return -1;
-    else if (ra->start > (rb->start + rb->count))
-        return 1;
-    else
-        return 0;
-}
-
-static int get_comp_index(uint32_t code, const Reindex *idx, size_t len)
-{
-    Reindex *res;
-    Reindex r = {0, 0, 0};
-    r.start = code;
-    res = (Reindex *) bsearch(&r, idx, len, sizeof(Reindex), compare_reindex);
-
-    if (res != NULL)
-        return res->index + (code - res->start);
-    else
-        return -1;
-}
-
-static int compare_mp(const void *a, const void *b)
-{
-    MirrorPair *mpa = (MirrorPair *)a;
-    MirrorPair *mpb = (MirrorPair *)b;
-    return mpa->from - mpb->from;
-}
-
-static int compare_bp(const void *a, const void *b)
-{
-    BracketPair *bpa = (BracketPair *)a;
-    BracketPair *bpb = (BracketPair *)b;
-    return bpa->from - bpb->from;
-}
-
-static BracketPair *search_bp(uint32_t code)
-{
-    BracketPair bp = {0,0,2};
-    BracketPair *res;
-
-    bp.from = code;
-    res = (BracketPair *) bsearch(&bp, bracket_pairs, BIDI_BRACKET_LEN,
-                                 sizeof(BracketPair), compare_bp);
-    return res;
-}
-
-static int hangul_pair_decompose(uint32_t code, uint32_t *a, uint32_t *b)
-{
-    int si = code - SBASE;
-
-    if (si < 0 || si >= SCOUNT)
-        return 0;
-
-    if (si % TCOUNT) {
-        /* LV,T */
-        *a = SBASE + (si / TCOUNT) * TCOUNT;
-        *b = TBASE + (si % TCOUNT);
-        return 3;
-    } else {
-        /* L,V */
-        *a = LBASE + (si / NCOUNT);
-        *b = VBASE + (si % NCOUNT) / TCOUNT;
-        return 2;
-    }
-}
-
-static int hangul_pair_compose(uint32_t *code, uint32_t a, uint32_t b)
-{
-    if (a >= SBASE && a < (SBASE + SCOUNT) && b >= TBASE && b < (TBASE + TCOUNT)) {
-        /* LV,T */
-        *code = a + (b - TBASE);
-        return 3;
-    } else if (a >= LBASE && a < (LBASE + LCOUNT) && b >= VBASE && b < (VBASE + VCOUNT)) {
-        /* L,V */
-        int li = a - LBASE;
-        int vi = b - VBASE;
-        *code = SBASE + li * NCOUNT + vi * TCOUNT;
-        return 2;
-    } else {
-        return 0;
-    }
-}
-
-static uint32_t decode_utf16(const unsigned short **code_ptr)
-{
-    const unsigned short *code = *code_ptr;
-
-    if (code[0] < 0xd800 || code[0] > 0xdc00) {
-        *code_ptr += 1;
-        return (uint32_t)code[0];
-    } else {
-        *code_ptr += 2;
-        return 0x10000 + ((uint32_t)code[1] - 0xdc00) +
-            (((uint32_t)code[0] - 0xd800) << 10);
-    }
-}
-
-const char *ucdn_get_unicode_version(void)
-{
-    return UNIDATA_VERSION;
-}
-
-int ucdn_get_combining_class(uint32_t code)
-{
-    return get_ucd_record(code)->combining;
-}
-
-int ucdn_get_east_asian_width(uint32_t code)
-{
-    return get_ucd_record(code)->east_asian_width;
-}
-
-int ucdn_get_general_category(uint32_t code)
-{
-    return get_ucd_record(code)->category;
-}
-
-int ucdn_get_bidi_class(uint32_t code)
-{
-    return get_ucd_record(code)->bidi_class;
-}
-
-int ucdn_get_mirrored(uint32_t code)
-{
-    return ucdn_mirror(code) != code;
-}
-
-int ucdn_get_script(uint32_t code)
-{
-    return get_ucd_record(code)->script;
-}
-
-int ucdn_get_linebreak_class(uint32_t code)
-{
-    return get_ucd_record(code)->linebreak_class;
-}
-
-int ucdn_get_resolved_linebreak_class(uint32_t code)
-{
-    const UCDRecord *record = get_ucd_record(code);
-
-    switch (record->linebreak_class)
-    {
-    case UCDN_LINEBREAK_CLASS_AI:
-    case UCDN_LINEBREAK_CLASS_SG:
-    case UCDN_LINEBREAK_CLASS_XX:
-        return UCDN_LINEBREAK_CLASS_AL;
-
-    case UCDN_LINEBREAK_CLASS_SA:
-        if (record->category == UCDN_GENERAL_CATEGORY_MC ||
-                record->category == UCDN_GENERAL_CATEGORY_MN)
-            return UCDN_LINEBREAK_CLASS_CM;
-        return UCDN_LINEBREAK_CLASS_AL;
-
-    case UCDN_LINEBREAK_CLASS_CJ:
-        return UCDN_LINEBREAK_CLASS_NS;
-
-    case UCDN_LINEBREAK_CLASS_CB:
-        return UCDN_LINEBREAK_CLASS_B2;
-
-    case UCDN_LINEBREAK_CLASS_NL:
-        return UCDN_LINEBREAK_CLASS_BK;
-
-    default:
-        return record->linebreak_class;
-    }
-}
-
-uint32_t ucdn_mirror(uint32_t code)
-{
-    MirrorPair mp = {0};
-    MirrorPair *res;
-
-    mp.from = code;
-    res = (MirrorPair *) bsearch(&mp, mirror_pairs, BIDI_MIRROR_LEN,
-                                sizeof(MirrorPair), compare_mp);
-
-    if (res == NULL)
-        return code;
-    else
-        return res->to;
-}
-
-uint32_t ucdn_paired_bracket(uint32_t code)
-{
-    BracketPair *res = search_bp(code);
-    if (res == NULL)
-        return code;
-    else
-        return res->to;
-}
-
-int ucdn_paired_bracket_type(uint32_t code)
-{
-    BracketPair *res = search_bp(code);
-    if (res == NULL)
-        return UCDN_BIDI_PAIRED_BRACKET_TYPE_NONE;
-    else
-        return res->type;
-}
-
-int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b)
-{
-    const unsigned short *rec;
-    int len;
-
-    if (hangul_pair_decompose(code, a, b))
-        return 1;
-
-    rec = get_decomp_record(code);
-    len = rec[0] >> 8;
-
-    if ((rec[0] & 0xff) != 0 || len == 0)
-        return 0;
-
-    rec++;
-    *a = decode_utf16(&rec);
-    if (len > 1)
-        *b = decode_utf16(&rec);
-    else
-        *b = 0;
-
-    return 1;
-}
-
-int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b)
-{
-    int l, r, index, indexi, offset;
-
-    if (hangul_pair_compose(code, a, b))
-        return 1;
-
-    l = get_comp_index(a, nfc_first, sizeof(nfc_first) / sizeof(Reindex));
-    r = get_comp_index(b, nfc_last, sizeof(nfc_last) / sizeof(Reindex));
-
-    if (l < 0 || r < 0)
-        return 0;
-
-    indexi = l * TOTAL_LAST + r;
-    index  = comp_index0[indexi >> (COMP_SHIFT1+COMP_SHIFT2)] << COMP_SHIFT1;
-    offset = (indexi >> COMP_SHIFT2) & ((1<<COMP_SHIFT1) - 1);
-    index  = comp_index1[index + offset] << COMP_SHIFT2;
-    offset = indexi & ((1<<COMP_SHIFT2) - 1);
-    *code  = comp_data[index + offset];
-
-    return *code != 0;
-}
-
-int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed)
-{
-    int i, len;
-    const unsigned short *rec = get_decomp_record(code);
-    len = rec[0] >> 8;
-
-    if (len == 0)
-        return 0;
-
-    rec++;
-    for (i = 0; i < len; i++)
-        decomposed[i] = decode_utf16(&rec);
-
-    return len;
-}
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.h b/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.h
deleted file mode 100644
index 05d46d2..0000000
--- a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef UCDN_H
-#define UCDN_H
-
-
-
-#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__)
-# define HB_BEGIN_VISIBILITY _Pragma ("GCC visibility push(hidden)")
-# define HB_END_VISIBILITY _Pragma ("GCC visibility pop")
-#else
-# define HB_BEGIN_VISIBILITY
-# define HB_END_VISIBILITY
-#endif
-#ifdef __cplusplus
-# define HB_BEGIN_HEADER  extern "C" { HB_BEGIN_VISIBILITY
-# define HB_END_HEADER  HB_END_VISIBILITY }
-#else
-# define HB_BEGIN_HEADER  HB_BEGIN_VISIBILITY
-# define HB_END_HEADER  HB_END_VISIBILITY
-#endif
-
-HB_BEGIN_HEADER
-
-#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
-    defined (_sgi) || defined (__sun) || defined (sun) || \
-    defined (__digital__) || defined (__HP_cc)
-#  include <inttypes.h>
-#elif defined (_AIX)
-#  include <sys/inttypes.h>
-#elif defined (_MSC_VER) && _MSC_VER < 1600
-/* VS 2010 (_MSC_VER 1600) has stdint.h */
-typedef __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#else
-#  include <stdint.h>
-#endif
-
-
-#define UCDN_EAST_ASIAN_F 0
-#define UCDN_EAST_ASIAN_H 1
-#define UCDN_EAST_ASIAN_W 2
-#define UCDN_EAST_ASIAN_NA 3
-#define UCDN_EAST_ASIAN_A 4
-#define UCDN_EAST_ASIAN_N 5
-
-#define UCDN_SCRIPT_COMMON 0
-#define UCDN_SCRIPT_LATIN 1
-#define UCDN_SCRIPT_GREEK 2
-#define UCDN_SCRIPT_CYRILLIC 3
-#define UCDN_SCRIPT_ARMENIAN 4
-#define UCDN_SCRIPT_HEBREW 5
-#define UCDN_SCRIPT_ARABIC 6
-#define UCDN_SCRIPT_SYRIAC 7
-#define UCDN_SCRIPT_THAANA 8
-#define UCDN_SCRIPT_DEVANAGARI 9
-#define UCDN_SCRIPT_BENGALI 10
-#define UCDN_SCRIPT_GURMUKHI 11
-#define UCDN_SCRIPT_GUJARATI 12
-#define UCDN_SCRIPT_ORIYA 13
-#define UCDN_SCRIPT_TAMIL 14
-#define UCDN_SCRIPT_TELUGU 15
-#define UCDN_SCRIPT_KANNADA 16
-#define UCDN_SCRIPT_MALAYALAM 17
-#define UCDN_SCRIPT_SINHALA 18
-#define UCDN_SCRIPT_THAI 19
-#define UCDN_SCRIPT_LAO 20
-#define UCDN_SCRIPT_TIBETAN 21
-#define UCDN_SCRIPT_MYANMAR 22
-#define UCDN_SCRIPT_GEORGIAN 23
-#define UCDN_SCRIPT_HANGUL 24
-#define UCDN_SCRIPT_ETHIOPIC 25
-#define UCDN_SCRIPT_CHEROKEE 26
-#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
-#define UCDN_SCRIPT_OGHAM 28
-#define UCDN_SCRIPT_RUNIC 29
-#define UCDN_SCRIPT_KHMER 30
-#define UCDN_SCRIPT_MONGOLIAN 31
-#define UCDN_SCRIPT_HIRAGANA 32
-#define UCDN_SCRIPT_KATAKANA 33
-#define UCDN_SCRIPT_BOPOMOFO 34
-#define UCDN_SCRIPT_HAN 35
-#define UCDN_SCRIPT_YI 36
-#define UCDN_SCRIPT_OLD_ITALIC 37
-#define UCDN_SCRIPT_GOTHIC 38
-#define UCDN_SCRIPT_DESERET 39
-#define UCDN_SCRIPT_INHERITED 40
-#define UCDN_SCRIPT_TAGALOG 41
-#define UCDN_SCRIPT_HANUNOO 42
-#define UCDN_SCRIPT_BUHID 43
-#define UCDN_SCRIPT_TAGBANWA 44
-#define UCDN_SCRIPT_LIMBU 45
-#define UCDN_SCRIPT_TAI_LE 46
-#define UCDN_SCRIPT_LINEAR_B 47
-#define UCDN_SCRIPT_UGARITIC 48
-#define UCDN_SCRIPT_SHAVIAN 49
-#define UCDN_SCRIPT_OSMANYA 50
-#define UCDN_SCRIPT_CYPRIOT 51
-#define UCDN_SCRIPT_BRAILLE 52
-#define UCDN_SCRIPT_BUGINESE 53
-#define UCDN_SCRIPT_COPTIC 54
-#define UCDN_SCRIPT_NEW_TAI_LUE 55
-#define UCDN_SCRIPT_GLAGOLITIC 56
-#define UCDN_SCRIPT_TIFINAGH 57
-#define UCDN_SCRIPT_SYLOTI_NAGRI 58
-#define UCDN_SCRIPT_OLD_PERSIAN 59
-#define UCDN_SCRIPT_KHAROSHTHI 60
-#define UCDN_SCRIPT_BALINESE 61
-#define UCDN_SCRIPT_CUNEIFORM 62
-#define UCDN_SCRIPT_PHOENICIAN 63
-#define UCDN_SCRIPT_PHAGS_PA 64
-#define UCDN_SCRIPT_NKO 65
-#define UCDN_SCRIPT_SUNDANESE 66
-#define UCDN_SCRIPT_LEPCHA 67
-#define UCDN_SCRIPT_OL_CHIKI 68
-#define UCDN_SCRIPT_VAI 69
-#define UCDN_SCRIPT_SAURASHTRA 70
-#define UCDN_SCRIPT_KAYAH_LI 71
-#define UCDN_SCRIPT_REJANG 72
-#define UCDN_SCRIPT_LYCIAN 73
-#define UCDN_SCRIPT_CARIAN 74
-#define UCDN_SCRIPT_LYDIAN 75
-#define UCDN_SCRIPT_CHAM 76
-#define UCDN_SCRIPT_TAI_THAM 77
-#define UCDN_SCRIPT_TAI_VIET 78
-#define UCDN_SCRIPT_AVESTAN 79
-#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
-#define UCDN_SCRIPT_SAMARITAN 81
-#define UCDN_SCRIPT_LISU 82
-#define UCDN_SCRIPT_BAMUM 83
-#define UCDN_SCRIPT_JAVANESE 84
-#define UCDN_SCRIPT_MEETEI_MAYEK 85
-#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
-#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
-#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
-#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
-#define UCDN_SCRIPT_OLD_TURKIC 90
-#define UCDN_SCRIPT_KAITHI 91
-#define UCDN_SCRIPT_BATAK 92
-#define UCDN_SCRIPT_BRAHMI 93
-#define UCDN_SCRIPT_MANDAIC 94
-#define UCDN_SCRIPT_CHAKMA 95
-#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
-#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
-#define UCDN_SCRIPT_MIAO 98
-#define UCDN_SCRIPT_SHARADA 99
-#define UCDN_SCRIPT_SORA_SOMPENG 100
-#define UCDN_SCRIPT_TAKRI 101
-#define UCDN_SCRIPT_UNKNOWN 102
-#define UCDN_SCRIPT_BASSA_VAH 103
-#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
-#define UCDN_SCRIPT_DUPLOYAN 105
-#define UCDN_SCRIPT_ELBASAN 106
-#define UCDN_SCRIPT_GRANTHA 107
-#define UCDN_SCRIPT_KHOJKI 108
-#define UCDN_SCRIPT_KHUDAWADI 109
-#define UCDN_SCRIPT_LINEAR_A 110
-#define UCDN_SCRIPT_MAHAJANI 111
-#define UCDN_SCRIPT_MANICHAEAN 112
-#define UCDN_SCRIPT_MENDE_KIKAKUI 113
-#define UCDN_SCRIPT_MODI 114
-#define UCDN_SCRIPT_MRO 115
-#define UCDN_SCRIPT_NABATAEAN 116
-#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
-#define UCDN_SCRIPT_OLD_PERMIC 118
-#define UCDN_SCRIPT_PAHAWH_HMONG 119
-#define UCDN_SCRIPT_PALMYRENE 120
-#define UCDN_SCRIPT_PAU_CIN_HAU 121
-#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
-#define UCDN_SCRIPT_SIDDHAM 123
-#define UCDN_SCRIPT_TIRHUTA 124
-#define UCDN_SCRIPT_WARANG_CITI 125
-#define UCDN_SCRIPT_AHOM 126
-#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127
-#define UCDN_SCRIPT_HATRAN 128
-#define UCDN_SCRIPT_MULTANI 129
-#define UCDN_SCRIPT_OLD_HUNGARIAN 130
-#define UCDN_SCRIPT_SIGNWRITING 131
-#define UCDN_SCRIPT_ADLAM 132
-#define UCDN_SCRIPT_BHAIKSUKI 133
-#define UCDN_SCRIPT_MARCHEN 134
-#define UCDN_SCRIPT_NEWA 135
-#define UCDN_SCRIPT_OSAGE 136
-#define UCDN_SCRIPT_TANGUT 137
-#define UCDN_SCRIPT_MASARAM_GONDI 138
-#define UCDN_SCRIPT_NUSHU 139
-#define UCDN_SCRIPT_SOYOMBO 140
-#define UCDN_SCRIPT_ZANABAZAR_SQUARE 141
-
-#define UCDN_LINEBREAK_CLASS_OP 0
-#define UCDN_LINEBREAK_CLASS_CL 1
-#define UCDN_LINEBREAK_CLASS_CP 2
-#define UCDN_LINEBREAK_CLASS_QU 3
-#define UCDN_LINEBREAK_CLASS_GL 4
-#define UCDN_LINEBREAK_CLASS_NS 5
-#define UCDN_LINEBREAK_CLASS_EX 6
-#define UCDN_LINEBREAK_CLASS_SY 7
-#define UCDN_LINEBREAK_CLASS_IS 8
-#define UCDN_LINEBREAK_CLASS_PR 9
-#define UCDN_LINEBREAK_CLASS_PO 10
-#define UCDN_LINEBREAK_CLASS_NU 11
-#define UCDN_LINEBREAK_CLASS_AL 12
-#define UCDN_LINEBREAK_CLASS_HL 13
-#define UCDN_LINEBREAK_CLASS_ID 14
-#define UCDN_LINEBREAK_CLASS_IN 15
-#define UCDN_LINEBREAK_CLASS_HY 16
-#define UCDN_LINEBREAK_CLASS_BA 17
-#define UCDN_LINEBREAK_CLASS_BB 18
-#define UCDN_LINEBREAK_CLASS_B2 19
-#define UCDN_LINEBREAK_CLASS_ZW 20
-#define UCDN_LINEBREAK_CLASS_CM 21
-#define UCDN_LINEBREAK_CLASS_WJ 22
-#define UCDN_LINEBREAK_CLASS_H2 23
-#define UCDN_LINEBREAK_CLASS_H3 24
-#define UCDN_LINEBREAK_CLASS_JL 25
-#define UCDN_LINEBREAK_CLASS_JV 26
-#define UCDN_LINEBREAK_CLASS_JT 27
-#define UCDN_LINEBREAK_CLASS_RI 28
-#define UCDN_LINEBREAK_CLASS_AI 29
-#define UCDN_LINEBREAK_CLASS_BK 30
-#define UCDN_LINEBREAK_CLASS_CB 31
-#define UCDN_LINEBREAK_CLASS_CJ 32
-#define UCDN_LINEBREAK_CLASS_CR 33
-#define UCDN_LINEBREAK_CLASS_LF 34
-#define UCDN_LINEBREAK_CLASS_NL 35
-#define UCDN_LINEBREAK_CLASS_SA 36
-#define UCDN_LINEBREAK_CLASS_SG 37
-#define UCDN_LINEBREAK_CLASS_SP 38
-#define UCDN_LINEBREAK_CLASS_XX 39
-#define UCDN_LINEBREAK_CLASS_ZWJ 40
-#define UCDN_LINEBREAK_CLASS_EB 41
-#define UCDN_LINEBREAK_CLASS_EM 42
-
-#define UCDN_GENERAL_CATEGORY_CC 0
-#define UCDN_GENERAL_CATEGORY_CF 1
-#define UCDN_GENERAL_CATEGORY_CN 2
-#define UCDN_GENERAL_CATEGORY_CO 3
-#define UCDN_GENERAL_CATEGORY_CS 4
-#define UCDN_GENERAL_CATEGORY_LL 5
-#define UCDN_GENERAL_CATEGORY_LM 6
-#define UCDN_GENERAL_CATEGORY_LO 7
-#define UCDN_GENERAL_CATEGORY_LT 8
-#define UCDN_GENERAL_CATEGORY_LU 9
-#define UCDN_GENERAL_CATEGORY_MC 10
-#define UCDN_GENERAL_CATEGORY_ME 11
-#define UCDN_GENERAL_CATEGORY_MN 12
-#define UCDN_GENERAL_CATEGORY_ND 13
-#define UCDN_GENERAL_CATEGORY_NL 14
-#define UCDN_GENERAL_CATEGORY_NO 15
-#define UCDN_GENERAL_CATEGORY_PC 16
-#define UCDN_GENERAL_CATEGORY_PD 17
-#define UCDN_GENERAL_CATEGORY_PE 18
-#define UCDN_GENERAL_CATEGORY_PF 19
-#define UCDN_GENERAL_CATEGORY_PI 20
-#define UCDN_GENERAL_CATEGORY_PO 21
-#define UCDN_GENERAL_CATEGORY_PS 22
-#define UCDN_GENERAL_CATEGORY_SC 23
-#define UCDN_GENERAL_CATEGORY_SK 24
-#define UCDN_GENERAL_CATEGORY_SM 25
-#define UCDN_GENERAL_CATEGORY_SO 26
-#define UCDN_GENERAL_CATEGORY_ZL 27
-#define UCDN_GENERAL_CATEGORY_ZP 28
-#define UCDN_GENERAL_CATEGORY_ZS 29
-
-#define UCDN_BIDI_CLASS_L 0
-#define UCDN_BIDI_CLASS_LRE 1
-#define UCDN_BIDI_CLASS_LRO 2
-#define UCDN_BIDI_CLASS_R 3
-#define UCDN_BIDI_CLASS_AL 4
-#define UCDN_BIDI_CLASS_RLE 5
-#define UCDN_BIDI_CLASS_RLO 6
-#define UCDN_BIDI_CLASS_PDF 7
-#define UCDN_BIDI_CLASS_EN 8
-#define UCDN_BIDI_CLASS_ES 9
-#define UCDN_BIDI_CLASS_ET 10
-#define UCDN_BIDI_CLASS_AN 11
-#define UCDN_BIDI_CLASS_CS 12
-#define UCDN_BIDI_CLASS_NSM 13
-#define UCDN_BIDI_CLASS_BN 14
-#define UCDN_BIDI_CLASS_B 15
-#define UCDN_BIDI_CLASS_S 16
-#define UCDN_BIDI_CLASS_WS 17
-#define UCDN_BIDI_CLASS_ON 18
-#define UCDN_BIDI_CLASS_LRI 19
-#define UCDN_BIDI_CLASS_RLI 20
-#define UCDN_BIDI_CLASS_FSI 21
-#define UCDN_BIDI_CLASS_PDI 22
-
-#define UCDN_BIDI_PAIRED_BRACKET_TYPE_OPEN 0
-#define UCDN_BIDI_PAIRED_BRACKET_TYPE_CLOSE 1
-#define UCDN_BIDI_PAIRED_BRACKET_TYPE_NONE 2
-
-/**
- * Return version of the Unicode database.
- *
- * @return Unicode database version
- */
-const char *ucdn_get_unicode_version(void);
-
-/**
- * Get combining class of a codepoint.
- *
- * @param code Unicode codepoint
- * @return combining class value, as defined in UAX#44
- */
-int ucdn_get_combining_class(uint32_t code);
-
-/**
- * Get east-asian width of a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_EAST_ASIAN_* and as defined in UAX#11.
- */
-int ucdn_get_east_asian_width(uint32_t code);
-
-/**
- * Get general category of a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_GENERAL_CATEGORY_* and as defined in
- * UAX#44.
- */
-int ucdn_get_general_category(uint32_t code);
-
-/**
- * Get bidirectional class of a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_BIDI_CLASS_* and as defined in UAX#44.
- */
-int ucdn_get_bidi_class(uint32_t code);
-
-/**
- * Get script of a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_SCRIPT_* and as defined in UAX#24.
- */
-int ucdn_get_script(uint32_t code);
-
-/**
- * Get unresolved linebreak class of a codepoint. This does not take
- * rule LB1 of UAX#14 into account. See ucdn_get_resolved_linebreak_class()
- * for resolved linebreak classes.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_LINEBREAK_* and as defined in UAX#14.
- */
-int ucdn_get_linebreak_class(uint32_t code);
-
-/**
- * Get resolved linebreak class of a codepoint. This resolves characters
- * in the AI, SG, XX, SA and CJ classes according to rule LB1 of UAX#14.
- * In addition the CB class is resolved as the equivalent B2 class and
- * the NL class is resolved as the equivalent BK class.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_LINEBREAK_* and as defined in UAX#14.
- */
-int ucdn_get_resolved_linebreak_class(uint32_t code);
-
-/**
- * Check if codepoint can be mirrored.
- *
- * @param code Unicode codepoint
- * @return 1 if mirrored character exists, otherwise 0
- */
-int ucdn_get_mirrored(uint32_t code);
-
-/**
- * Mirror a codepoint.
- *
- * @param code Unicode codepoint
- * @return mirrored codepoint or the original codepoint if no
- * mirrored character exists
- */
-uint32_t ucdn_mirror(uint32_t code);
-
-/**
- * Get paired bracket for a codepoint.
- *
- * @param code Unicode codepoint
- * @return paired bracket codepoint or the original codepoint if no
- * paired bracket character exists
- */
-uint32_t ucdn_paired_bracket(uint32_t code);
-
-/**
- * Get paired bracket type for a codepoint.
- *
- * @param code Unicode codepoint
- * @return value according to UCDN_BIDI_PAIRED_BRACKET_TYPE_* and as defined
- * in UAX#9.
- *
- */
-int ucdn_paired_bracket_type(uint32_t code);
-
-/**
- * Pairwise canonical decomposition of a codepoint. This includes
- * Hangul Jamo decomposition (see chapter 3.12 of the Unicode core
- * specification).
- *
- * Hangul is decomposed into L and V jamos for LV forms, and an
- * LV precomposed syllable and a T jamo for LVT forms.
- *
- * @param code Unicode codepoint
- * @param a filled with first codepoint of decomposition
- * @param b filled with second codepoint of decomposition, or 0
- * @return success
- */
-int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b);
-
-/**
- * Compatibility decomposition of a codepoint.
- *
- * @param code Unicode codepoint
- * @param decomposed filled with decomposition, must be able to hold 18
- * characters
- * @return length of decomposition or 0 in case none exists
- */
-int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed);
-
-/**
- * Pairwise canonical composition of two codepoints. This includes
- * Hangul Jamo composition (see chapter 3.12 of the Unicode core
- * specification).
- *
- * Hangul composition expects either L and V jamos, or an LV
- * precomposed syllable and a T jamo. This is exactly the inverse
- * of pairwise Hangul decomposition.
- *
- * @param code filled with composition
- * @param a first codepoint
- * @param b second codepoint
- * @return success
- */
-int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b);
-
-HB_END_HEADER
-
-#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn_db.h b/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn_db.h
deleted file mode 100644
index d72c7ba..0000000
--- a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn_db.h
+++ /dev/null
@@ -1,5730 +0,0 @@
-/* this file was generated by makeunicodedata.py 3.2 */
-
-#define UNIDATA_VERSION "11.0.0"
-/* a list of unique database records */
-static const UCDRecord ucd_records[] = {
-    {2, 0, 18, 5, 102, 39},
-    {0, 0, 14, 5, 0, 21},
-    {0, 0, 16, 5, 0, 17},
-    {0, 0, 15, 5, 0, 34},
-    {0, 0, 16, 5, 0, 30},
-    {0, 0, 17, 5, 0, 30},
-    {0, 0, 15, 5, 0, 33},
-    {0, 0, 15, 5, 0, 21},
-    {0, 0, 16, 5, 0, 21},
-    {29, 0, 17, 3, 0, 38},
-    {21, 0, 18, 3, 0, 6},
-    {21, 0, 18, 3, 0, 3},
-    {21, 0, 10, 3, 0, 12},
-    {23, 0, 10, 3, 0, 9},
-    {21, 0, 10, 3, 0, 10},
-    {21, 0, 18, 3, 0, 12},
-    {22, 0, 18, 3, 0, 0},
-    {18, 0, 18, 3, 0, 2},
-    {25, 0, 9, 3, 0, 9},
-    {21, 0, 12, 3, 0, 8},
-    {17, 0, 9, 3, 0, 16},
-    {21, 0, 12, 3, 0, 7},
-    {13, 0, 8, 3, 0, 11},
-    {21, 0, 18, 3, 0, 8},
-    {25, 0, 18, 3, 0, 12},
-    {9, 0, 0, 3, 1, 12},
-    {21, 0, 18, 3, 0, 9},
-    {24, 0, 18, 3, 0, 12},
-    {16, 0, 18, 3, 0, 12},
-    {5, 0, 0, 3, 1, 12},
-    {25, 0, 18, 3, 0, 17},
-    {18, 0, 18, 3, 0, 1},
-    {0, 0, 15, 5, 0, 35},
-    {29, 0, 12, 5, 0, 4},
-    {21, 0, 18, 4, 0, 0},
-    {23, 0, 10, 3, 0, 10},
-    {23, 0, 10, 4, 0, 9},
-    {26, 0, 18, 3, 0, 12},
-    {21, 0, 18, 4, 0, 29},
-    {24, 0, 18, 4, 0, 29},
-    {26, 0, 18, 5, 0, 12},
-    {7, 0, 0, 4, 1, 29},
-    {20, 0, 18, 5, 0, 3},
-    {1, 0, 14, 4, 0, 17},
-    {26, 0, 18, 4, 0, 12},
-    {26, 0, 10, 4, 0, 10},
-    {25, 0, 10, 4, 0, 9},
-    {15, 0, 8, 4, 0, 29},
-    {24, 0, 18, 4, 0, 18},
-    {5, 0, 0, 5, 0, 12},
-    {19, 0, 18, 5, 0, 3},
-    {15, 0, 18, 4, 0, 29},
-    {9, 0, 0, 5, 1, 12},
-    {9, 0, 0, 4, 1, 12},
-    {25, 0, 18, 4, 0, 29},
-    {5, 0, 0, 4, 1, 12},
-    {5, 0, 0, 5, 1, 12},
-    {7, 0, 0, 5, 1, 12},
-    {8, 0, 0, 5, 1, 12},
-    {6, 0, 0, 5, 1, 12},
-    {6, 0, 18, 5, 0, 12},
-    {6, 0, 0, 5, 0, 12},
-    {24, 0, 18, 5, 0, 12},
-    {24, 0, 18, 4, 0, 12},
-    {6, 0, 18, 4, 0, 29},
-    {6, 0, 18, 5, 0, 18},
-    {6, 0, 0, 4, 0, 29},
-    {24, 0, 18, 5, 34, 12},
-    {12, 230, 13, 4, 40, 21},
-    {12, 232, 13, 4, 40, 21},
-    {12, 220, 13, 4, 40, 21},
-    {12, 216, 13, 4, 40, 21},
-    {12, 202, 13, 4, 40, 21},
-    {12, 1, 13, 4, 40, 21},
-    {12, 240, 13, 4, 40, 21},
-    {12, 0, 13, 4, 40, 4},
-    {12, 233, 13, 4, 40, 4},
-    {12, 234, 13, 4, 40, 4},
-    {9, 0, 0, 5, 2, 12},
-    {5, 0, 0, 5, 2, 12},
-    {24, 0, 18, 5, 2, 12},
-    {2, 0, 18, 5, 102, 39},
-    {6, 0, 0, 5, 2, 12},
-    {21, 0, 18, 5, 0, 8},
-    {21, 0, 18, 5, 0, 12},
-    {9, 0, 0, 4, 2, 12},
-    {5, 0, 0, 4, 2, 12},
-    {9, 0, 0, 5, 54, 12},
-    {5, 0, 0, 5, 54, 12},
-    {25, 0, 18, 5, 2, 12},
-    {9, 0, 0, 5, 3, 12},
-    {9, 0, 0, 4, 3, 12},
-    {5, 0, 0, 4, 3, 12},
-    {5, 0, 0, 5, 3, 12},
-    {26, 0, 0, 5, 3, 12},
-    {12, 230, 13, 5, 3, 21},
-    {12, 230, 13, 5, 40, 21},
-    {11, 0, 13, 5, 3, 21},
-    {9, 0, 0, 5, 4, 12},
-    {6, 0, 0, 5, 4, 12},
-    {21, 0, 0, 5, 4, 12},
-    {5, 0, 0, 5, 4, 12},
-    {21, 0, 0, 5, 0, 8},
-    {17, 0, 18, 5, 4, 17},
-    {26, 0, 18, 5, 4, 12},
-    {23, 0, 10, 5, 4, 9},
-    {12, 220, 13, 5, 5, 21},
-    {12, 230, 13, 5, 5, 21},
-    {12, 222, 13, 5, 5, 21},
-    {12, 228, 13, 5, 5, 21},
-    {12, 10, 13, 5, 5, 21},
-    {12, 11, 13, 5, 5, 21},
-    {12, 12, 13, 5, 5, 21},
-    {12, 13, 13, 5, 5, 21},
-    {12, 14, 13, 5, 5, 21},
-    {12, 15, 13, 5, 5, 21},
-    {12, 16, 13, 5, 5, 21},
-    {12, 17, 13, 5, 5, 21},
-    {12, 18, 13, 5, 5, 21},
-    {12, 19, 13, 5, 5, 21},
-    {12, 20, 13, 5, 5, 21},
-    {12, 21, 13, 5, 5, 21},
-    {12, 22, 13, 5, 5, 21},
-    {17, 0, 3, 5, 5, 17},
-    {12, 23, 13, 5, 5, 21},
-    {21, 0, 3, 5, 5, 12},
-    {12, 24, 13, 5, 5, 21},
-    {12, 25, 13, 5, 5, 21},
-    {21, 0, 3, 5, 5, 6},
-    {7, 0, 3, 5, 5, 13},
-    {1, 0, 11, 5, 6, 12},
-    {1, 0, 11, 5, 0, 12},
-    {25, 0, 18, 5, 6, 12},
-    {25, 0, 4, 5, 6, 12},
-    {21, 0, 10, 5, 6, 10},
-    {23, 0, 4, 5, 6, 10},
-    {21, 0, 12, 5, 0, 8},
-    {21, 0, 4, 5, 6, 8},
-    {26, 0, 18, 5, 6, 12},
-    {12, 230, 13, 5, 6, 21},
-    {12, 30, 13, 5, 6, 21},
-    {12, 31, 13, 5, 6, 21},
-    {12, 32, 13, 5, 6, 21},
-    {21, 0, 4, 5, 0, 6},
-    {1, 0, 4, 5, 6, 21},
-    {21, 0, 4, 5, 6, 6},
-    {7, 0, 4, 5, 6, 12},
-    {6, 0, 4, 5, 0, 12},
-    {12, 27, 13, 5, 40, 21},
-    {12, 28, 13, 5, 40, 21},
-    {12, 29, 13, 5, 40, 21},
-    {12, 30, 13, 5, 40, 21},
-    {12, 31, 13, 5, 40, 21},
-    {12, 32, 13, 5, 40, 21},
-    {12, 33, 13, 5, 40, 21},
-    {12, 34, 13, 5, 40, 21},
-    {12, 220, 13, 5, 40, 21},
-    {12, 220, 13, 5, 6, 21},
-    {13, 0, 11, 5, 6, 11},
-    {21, 0, 11, 5, 6, 11},
-    {21, 0, 4, 5, 6, 12},
-    {12, 35, 13, 5, 40, 21},
-    {6, 0, 4, 5, 6, 12},
-    {13, 0, 8, 5, 6, 11},
-    {26, 0, 4, 5, 6, 12},
-    {21, 0, 4, 5, 7, 12},
-    {1, 0, 4, 5, 7, 12},
-    {7, 0, 4, 5, 7, 12},
-    {12, 36, 13, 5, 7, 21},
-    {12, 230, 13, 5, 7, 21},
-    {12, 220, 13, 5, 7, 21},
-    {7, 0, 4, 5, 8, 12},
-    {12, 0, 13, 5, 8, 21},
-    {13, 0, 3, 5, 65, 11},
-    {7, 0, 3, 5, 65, 12},
-    {12, 230, 13, 5, 65, 21},
-    {12, 220, 13, 5, 65, 21},
-    {6, 0, 3, 5, 65, 12},
-    {26, 0, 18, 5, 65, 12},
-    {21, 0, 18, 5, 65, 12},
-    {21, 0, 18, 5, 65, 8},
-    {21, 0, 18, 5, 65, 6},
-    {23, 0, 3, 5, 65, 9},
-    {7, 0, 3, 5, 81, 12},
-    {12, 230, 13, 5, 81, 21},
-    {6, 0, 3, 5, 81, 12},
-    {21, 0, 3, 5, 81, 12},
-    {7, 0, 3, 5, 94, 12},
-    {12, 220, 13, 5, 94, 21},
-    {21, 0, 3, 5, 94, 12},
-    {12, 27, 13, 5, 6, 21},
-    {12, 28, 13, 5, 6, 21},
-    {12, 29, 13, 5, 6, 21},
-    {12, 0, 13, 5, 9, 21},
-    {10, 0, 0, 5, 9, 21},
-    {7, 0, 0, 5, 9, 12},
-    {12, 7, 13, 5, 9, 21},
-    {12, 9, 13, 5, 9, 21},
-    {12, 230, 13, 5, 9, 21},
-    {21, 0, 0, 5, 0, 17},
-    {13, 0, 0, 5, 9, 11},
-    {21, 0, 0, 5, 9, 12},
-    {6, 0, 0, 5, 9, 12},
-    {7, 0, 0, 5, 10, 12},
-    {12, 0, 13, 5, 10, 21},
-    {10, 0, 0, 5, 10, 21},
-    {12, 7, 13, 5, 10, 21},
-    {12, 9, 13, 5, 10, 21},
-    {13, 0, 0, 5, 10, 11},
-    {23, 0, 10, 5, 10, 10},
-    {15, 0, 0, 5, 10, 12},
-    {15, 0, 0, 5, 10, 10},
-    {26, 0, 0, 5, 10, 12},
-    {23, 0, 10, 5, 10, 9},
-    {21, 0, 0, 5, 10, 12},
-    {12, 230, 13, 5, 10, 21},
-    {12, 0, 13, 5, 11, 21},
-    {10, 0, 0, 5, 11, 21},
-    {7, 0, 0, 5, 11, 12},
-    {12, 7, 13, 5, 11, 21},
-    {12, 9, 13, 5, 11, 21},
-    {13, 0, 0, 5, 11, 11},
-    {21, 0, 0, 5, 11, 12},
-    {12, 0, 13, 5, 12, 21},
-    {10, 0, 0, 5, 12, 21},
-    {7, 0, 0, 5, 12, 12},
-    {12, 7, 13, 5, 12, 21},
-    {12, 9, 13, 5, 12, 21},
-    {13, 0, 0, 5, 12, 11},
-    {21, 0, 0, 5, 12, 12},
-    {23, 0, 10, 5, 12, 9},
-    {12, 0, 13, 5, 13, 21},
-    {10, 0, 0, 5, 13, 21},
-    {7, 0, 0, 5, 13, 12},
-    {12, 7, 13, 5, 13, 21},
-    {12, 9, 13, 5, 13, 21},
-    {13, 0, 0, 5, 13, 11},
-    {26, 0, 0, 5, 13, 12},
-    {15, 0, 0, 5, 13, 12},
-    {12, 0, 13, 5, 14, 21},
-    {7, 0, 0, 5, 14, 12},
-    {10, 0, 0, 5, 14, 21},
-    {12, 9, 13, 5, 14, 21},
-    {13, 0, 0, 5, 14, 11},
-    {15, 0, 0, 5, 14, 12},
-    {26, 0, 18, 5, 14, 12},
-    {23, 0, 10, 5, 14, 9},
-    {12, 0, 13, 5, 15, 21},
-    {10, 0, 0, 5, 15, 21},
-    {7, 0, 0, 5, 15, 12},
-    {12, 9, 13, 5, 15, 21},
-    {12, 84, 13, 5, 15, 21},
-    {12, 91, 13, 5, 15, 21},
-    {13, 0, 0, 5, 15, 11},
-    {15, 0, 18, 5, 15, 12},
-    {26, 0, 0, 5, 15, 12},
-    {7, 0, 0, 5, 16, 12},
-    {12, 0, 13, 5, 16, 21},
-    {10, 0, 0, 5, 16, 21},
-    {21, 0, 0, 5, 16, 18},
-    {12, 7, 13, 5, 16, 21},
-    {12, 0, 0, 5, 16, 21},
-    {12, 9, 13, 5, 16, 21},
-    {13, 0, 0, 5, 16, 11},
-    {12, 0, 13, 5, 17, 21},
-    {10, 0, 0, 5, 17, 21},
-    {7, 0, 0, 5, 17, 12},
-    {12, 9, 13, 5, 17, 21},
-    {26, 0, 0, 5, 17, 12},
-    {15, 0, 0, 5, 17, 12},
-    {13, 0, 0, 5, 17, 11},
-    {26, 0, 0, 5, 17, 10},
-    {10, 0, 0, 5, 18, 21},
-    {7, 0, 0, 5, 18, 12},
-    {12, 9, 13, 5, 18, 21},
-    {12, 0, 13, 5, 18, 21},
-    {13, 0, 0, 5, 18, 11},
-    {21, 0, 0, 5, 18, 12},
-    {7, 0, 0, 5, 19, 36},
-    {12, 0, 13, 5, 19, 36},
-    {12, 103, 13, 5, 19, 36},
-    {12, 9, 13, 5, 19, 36},
-    {23, 0, 10, 5, 0, 9},
-    {6, 0, 0, 5, 19, 36},
-    {12, 107, 13, 5, 19, 36},
-    {21, 0, 0, 5, 19, 12},
-    {13, 0, 0, 5, 19, 11},
-    {21, 0, 0, 5, 19, 17},
-    {7, 0, 0, 5, 20, 36},
-    {12, 0, 13, 5, 20, 36},
-    {12, 118, 13, 5, 20, 36},
-    {6, 0, 0, 5, 20, 36},
-    {12, 122, 13, 5, 20, 36},
-    {13, 0, 0, 5, 20, 11},
-    {7, 0, 0, 5, 21, 12},
-    {26, 0, 0, 5, 21, 18},
-    {21, 0, 0, 5, 21, 18},
-    {21, 0, 0, 5, 21, 12},
-    {21, 0, 0, 5, 21, 4},
-    {21, 0, 0, 5, 21, 17},
-    {21, 0, 0, 5, 21, 6},
-    {26, 0, 0, 5, 21, 12},
-    {12, 220, 13, 5, 21, 21},
-    {13, 0, 0, 5, 21, 11},
-    {15, 0, 0, 5, 21, 12},
-    {26, 0, 0, 5, 21, 17},
-    {12, 216, 13, 5, 21, 21},
-    {22, 0, 18, 5, 21, 0},
-    {18, 0, 18, 5, 21, 1},
-    {10, 0, 0, 5, 21, 21},
-    {12, 129, 13, 5, 21, 21},
-    {12, 130, 13, 5, 21, 21},
-    {12, 0, 13, 5, 21, 21},
-    {12, 132, 13, 5, 21, 21},
-    {10, 0, 0, 5, 21, 17},
-    {12, 230, 13, 5, 21, 21},
-    {12, 9, 13, 5, 21, 21},
-    {26, 0, 0, 5, 0, 12},
-    {7, 0, 0, 5, 22, 36},
-    {10, 0, 0, 5, 22, 36},
-    {12, 0, 13, 5, 22, 36},
-    {12, 7, 13, 5, 22, 36},
-    {12, 9, 13, 5, 22, 36},
-    {13, 0, 0, 5, 22, 11},
-    {21, 0, 0, 5, 22, 17},
-    {21, 0, 0, 5, 22, 12},
-    {12, 220, 13, 5, 22, 36},
-    {26, 0, 0, 5, 22, 36},
-    {9, 0, 0, 5, 23, 12},
-    {5, 0, 0, 5, 23, 12},
-    {21, 0, 0, 5, 0, 12},
-    {6, 0, 0, 5, 23, 12},
-    {7, 0, 0, 2, 24, 25},
-    {7, 0, 0, 5, 24, 26},
-    {7, 0, 0, 5, 24, 27},
-    {7, 0, 0, 5, 25, 12},
-    {12, 230, 13, 5, 25, 21},
-    {21, 0, 0, 5, 25, 12},
-    {21, 0, 0, 5, 25, 17},
-    {15, 0, 0, 5, 25, 12},
-    {26, 0, 18, 5, 25, 12},
-    {9, 0, 0, 5, 26, 12},
-    {5, 0, 0, 5, 26, 12},
-    {17, 0, 18, 5, 27, 17},
-    {7, 0, 0, 5, 27, 12},
-    {21, 0, 0, 5, 27, 12},
-    {29, 0, 17, 5, 28, 17},
-    {7, 0, 0, 5, 28, 12},
-    {22, 0, 18, 5, 28, 0},
-    {18, 0, 18, 5, 28, 1},
-    {7, 0, 0, 5, 29, 12},
-    {14, 0, 0, 5, 29, 12},
-    {7, 0, 0, 5, 41, 12},
-    {12, 0, 13, 5, 41, 21},
-    {12, 9, 13, 5, 41, 21},
-    {7, 0, 0, 5, 42, 12},
-    {12, 0, 13, 5, 42, 21},
-    {12, 9, 13, 5, 42, 21},
-    {7, 0, 0, 5, 43, 12},
-    {12, 0, 13, 5, 43, 21},
-    {7, 0, 0, 5, 44, 12},
-    {12, 0, 13, 5, 44, 21},
-    {7, 0, 0, 5, 30, 36},
-    {12, 0, 13, 5, 30, 36},
-    {10, 0, 0, 5, 30, 36},
-    {12, 9, 13, 5, 30, 36},
-    {21, 0, 0, 5, 30, 17},
-    {21, 0, 0, 5, 30, 5},
-    {6, 0, 0, 5, 30, 36},
-    {21, 0, 0, 5, 30, 12},
-    {23, 0, 10, 5, 30, 9},
-    {12, 230, 13, 5, 30, 36},
-    {13, 0, 0, 5, 30, 11},
-    {15, 0, 18, 5, 30, 12},
-    {21, 0, 18, 5, 31, 12},
-    {21, 0, 18, 5, 0, 6},
-    {21, 0, 18, 5, 31, 17},
-    {21, 0, 18, 5, 0, 17},
-    {17, 0, 18, 5, 31, 18},
-    {21, 0, 18, 5, 31, 6},
-    {12, 0, 13, 5, 31, 21},
-    {1, 0, 14, 5, 31, 4},
-    {13, 0, 0, 5, 31, 11},
-    {7, 0, 0, 5, 31, 12},
-    {6, 0, 0, 5, 31, 12},
-    {12, 228, 13, 5, 31, 21},
-    {7, 0, 0, 5, 45, 12},
-    {12, 0, 13, 5, 45, 21},
-    {10, 0, 0, 5, 45, 21},
-    {12, 222, 13, 5, 45, 21},
-    {12, 230, 13, 5, 45, 21},
-    {12, 220, 13, 5, 45, 21},
-    {26, 0, 18, 5, 45, 12},
-    {21, 0, 18, 5, 45, 6},
-    {13, 0, 0, 5, 45, 11},
-    {7, 0, 0, 5, 46, 36},
-    {7, 0, 0, 5, 55, 36},
-    {13, 0, 0, 5, 55, 11},
-    {15, 0, 0, 5, 55, 36},
-    {26, 0, 18, 5, 55, 36},
-    {26, 0, 18, 5, 30, 12},
-    {7, 0, 0, 5, 53, 12},
-    {12, 230, 13, 5, 53, 21},
-    {12, 220, 13, 5, 53, 21},
-    {10, 0, 0, 5, 53, 21},
-    {12, 0, 13, 5, 53, 21},
-    {21, 0, 0, 5, 53, 12},
-    {7, 0, 0, 5, 77, 36},
-    {10, 0, 0, 5, 77, 36},
-    {12, 0, 13, 5, 77, 36},
-    {12, 9, 13, 5, 77, 36},
-    {12, 230, 13, 5, 77, 36},
-    {12, 220, 13, 5, 77, 21},
-    {13, 0, 0, 5, 77, 11},
-    {21, 0, 0, 5, 77, 36},
-    {6, 0, 0, 5, 77, 36},
-    {11, 0, 13, 5, 40, 21},
-    {12, 0, 13, 5, 61, 21},
-    {10, 0, 0, 5, 61, 21},
-    {7, 0, 0, 5, 61, 12},
-    {12, 7, 13, 5, 61, 21},
-    {10, 9, 0, 5, 61, 21},
-    {13, 0, 0, 5, 61, 11},
-    {21, 0, 0, 5, 61, 17},
-    {21, 0, 0, 5, 61, 12},
-    {26, 0, 0, 5, 61, 12},
-    {12, 230, 13, 5, 61, 21},
-    {12, 220, 13, 5, 61, 21},
-    {12, 0, 13, 5, 66, 21},
-    {10, 0, 0, 5, 66, 21},
-    {7, 0, 0, 5, 66, 12},
-    {10, 9, 0, 5, 66, 21},
-    {12, 9, 13, 5, 66, 21},
-    {13, 0, 0, 5, 66, 11},
-    {7, 0, 0, 5, 92, 12},
-    {12, 7, 13, 5, 92, 21},
-    {10, 0, 0, 5, 92, 21},
-    {12, 0, 13, 5, 92, 21},
-    {10, 9, 0, 5, 92, 21},
-    {21, 0, 0, 5, 92, 12},
-    {7, 0, 0, 5, 67, 12},
-    {10, 0, 0, 5, 67, 21},
-    {12, 0, 13, 5, 67, 21},
-    {12, 7, 13, 5, 67, 21},
-    {21, 0, 0, 5, 67, 17},
-    {13, 0, 0, 5, 67, 11},
-    {13, 0, 0, 5, 68, 11},
-    {7, 0, 0, 5, 68, 12},
-    {6, 0, 0, 5, 68, 12},
-    {21, 0, 0, 5, 68, 17},
-    {21, 0, 0, 5, 66, 12},
-    {12, 1, 13, 5, 40, 21},
-    {10, 0, 0, 5, 0, 21},
-    {7, 0, 0, 5, 0, 12},
-    {6, 0, 0, 5, 3, 12},
-    {12, 234, 13, 5, 40, 21},
-    {12, 214, 13, 5, 40, 21},
-    {12, 202, 13, 5, 40, 21},
-    {12, 232, 13, 5, 40, 21},
-    {12, 228, 13, 5, 40, 21},
-    {12, 233, 13, 5, 40, 21},
-    {8, 0, 0, 5, 2, 12},
-    {24, 0, 18, 5, 2, 18},
-    {29, 0, 17, 5, 0, 17},
-    {29, 0, 17, 5, 0, 4},
-    {1, 0, 14, 5, 0, 20},
-    {1, 0, 14, 5, 40, 21},
-    {1, 0, 14, 5, 40, 40},
-    {1, 0, 0, 5, 0, 21},
-    {1, 0, 3, 5, 0, 21},
-    {17, 0, 18, 4, 0, 17},
-    {17, 0, 18, 5, 0, 4},
-    {17, 0, 18, 5, 0, 17},
-    {17, 0, 18, 4, 0, 19},
-    {17, 0, 18, 4, 0, 29},
-    {20, 0, 18, 4, 0, 3},
-    {19, 0, 18, 4, 0, 3},
-    {22, 0, 18, 5, 0, 0},
-    {21, 0, 18, 4, 0, 12},
-    {21, 0, 18, 4, 0, 15},
-    {21, 0, 18, 4, 0, 17},
-    {27, 0, 17, 5, 0, 30},
-    {28, 0, 15, 5, 0, 30},
-    {1, 0, 1, 5, 0, 21},
-    {1, 0, 5, 5, 0, 21},
-    {1, 0, 7, 5, 0, 21},
-    {1, 0, 2, 5, 0, 21},
-    {1, 0, 6, 5, 0, 21},
-    {21, 0, 10, 4, 0, 10},
-    {21, 0, 10, 5, 0, 10},
-    {21, 0, 18, 4, 0, 10},
-    {21, 0, 18, 5, 0, 10},
-    {21, 0, 18, 5, 0, 5},
-    {16, 0, 18, 5, 0, 12},
-    {25, 0, 12, 5, 0, 8},
-    {18, 0, 18, 5, 0, 1},
-    {25, 0, 18, 5, 0, 12},
-    {1, 0, 14, 5, 0, 22},
-    {1, 0, 14, 5, 0, 12},
-    {1, 0, 19, 5, 0, 21},
-    {1, 0, 20, 5, 0, 21},
-    {1, 0, 21, 5, 0, 21},
-    {1, 0, 22, 5, 0, 21},
-    {1, 0, 14, 5, 0, 21},
-    {15, 0, 8, 5, 0, 12},
-    {25, 0, 9, 5, 0, 12},
-    {6, 0, 0, 4, 1, 29},
-    {23, 0, 10, 5, 0, 10},
-    {23, 0, 10, 1, 0, 9},
-    {2, 0, 18, 5, 102, 9},
-    {9, 0, 0, 5, 0, 12},
-    {26, 0, 18, 4, 0, 10},
-    {26, 0, 18, 4, 0, 29},
-    {5, 0, 0, 4, 0, 29},
-    {26, 0, 18, 4, 0, 9},
-    {9, 0, 0, 4, 1, 29},
-    {26, 0, 10, 5, 0, 12},
-    {15, 0, 18, 5, 0, 12},
-    {15, 0, 18, 4, 0, 12},
-    {15, 0, 18, 5, 0, 29},
-    {14, 0, 0, 4, 1, 29},
-    {14, 0, 0, 5, 1, 12},
-    {25, 0, 9, 5, 0, 9},
-    {25, 0, 10, 5, 0, 9},
-    {25, 0, 18, 5, 0, 15},
-    {26, 0, 18, 2, 0, 14},
-    {22, 0, 18, 2, 0, 0},
-    {18, 0, 18, 2, 0, 1},
-    {26, 0, 18, 2, 0, 12},
-    {26, 0, 18, 5, 0, 14},
-    {26, 0, 0, 4, 0, 29},
-    {26, 0, 18, 5, 0, 29},
-    {25, 0, 18, 2, 0, 12},
-    {26, 0, 18, 4, 0, 14},
-    {26, 0, 18, 5, 0, 41},
-    {26, 0, 18, 4, 0, 41},
-    {26, 0, 18, 2, 0, 41},
-    {26, 0, 18, 2, 0, 29},
-    {26, 0, 18, 5, 0, 3},
-    {26, 0, 18, 5, 0, 6},
-    {26, 0, 0, 5, 52, 12},
-    {9, 0, 0, 5, 56, 12},
-    {5, 0, 0, 5, 56, 12},
-    {26, 0, 18, 5, 54, 12},
-    {12, 230, 13, 5, 54, 21},
-    {21, 0, 18, 5, 54, 6},
-    {21, 0, 18, 5, 54, 17},
-    {15, 0, 18, 5, 54, 12},
-    {7, 0, 0, 5, 57, 12},
-    {6, 0, 0, 5, 57, 12},
-    {21, 0, 0, 5, 57, 17},
-    {12, 9, 13, 5, 57, 21},
-    {21, 0, 18, 5, 0, 3},
-    {21, 0, 18, 5, 0, 0},
-    {17, 0, 18, 5, 0, 12},
-    {17, 0, 18, 5, 0, 19},
-    {26, 0, 18, 2, 35, 14},
-    {29, 0, 17, 0, 0, 17},
-    {21, 0, 18, 2, 0, 1},
-    {21, 0, 18, 2, 0, 14},
-    {6, 0, 0, 2, 35, 5},
-    {7, 0, 0, 2, 0, 14},
-    {14, 0, 0, 2, 35, 14},
-    {17, 0, 18, 2, 0, 5},
-    {12, 218, 13, 2, 40, 21},
-    {12, 228, 13, 2, 40, 21},
-    {12, 232, 13, 2, 40, 21},
-    {12, 222, 13, 2, 40, 21},
-    {10, 224, 0, 2, 24, 21},
-    {17, 0, 18, 2, 0, 14},
-    {6, 0, 0, 2, 0, 14},
-    {6, 0, 0, 2, 0, 21},
-    {7, 0, 0, 2, 0, 5},
-    {7, 0, 0, 2, 32, 32},
-    {7, 0, 0, 2, 32, 14},
-    {12, 8, 13, 2, 40, 21},
-    {24, 0, 18, 2, 0, 5},
-    {6, 0, 0, 2, 32, 5},
-    {7, 0, 0, 2, 33, 32},
-    {7, 0, 0, 2, 33, 14},
-    {21, 0, 18, 2, 0, 5},
-    {6, 0, 0, 2, 0, 32},
-    {6, 0, 0, 2, 33, 5},
-    {7, 0, 0, 2, 34, 14},
-    {7, 0, 0, 2, 24, 14},
-    {26, 0, 0, 2, 0, 14},
-    {15, 0, 0, 2, 0, 14},
-    {26, 0, 0, 2, 24, 14},
-    {26, 0, 18, 2, 24, 14},
-    {15, 0, 0, 4, 0, 29},
-    {15, 0, 18, 2, 0, 14},
-    {26, 0, 0, 2, 33, 14},
-    {7, 0, 0, 2, 35, 14},
-    {2, 0, 18, 2, 102, 14},
-    {7, 0, 0, 2, 36, 14},
-    {6, 0, 0, 2, 36, 5},
-    {26, 0, 18, 2, 36, 14},
-    {7, 0, 0, 5, 82, 12},
-    {6, 0, 0, 5, 82, 12},
-    {21, 0, 0, 5, 82, 17},
-    {7, 0, 0, 5, 69, 12},
-    {6, 0, 0, 5, 69, 12},
-    {21, 0, 18, 5, 69, 17},
-    {21, 0, 18, 5, 69, 6},
-    {13, 0, 0, 5, 69, 11},
-    {7, 0, 0, 5, 3, 12},
-    {21, 0, 18, 5, 3, 12},
-    {6, 0, 18, 5, 3, 12},
-    {7, 0, 0, 5, 83, 12},
-    {14, 0, 0, 5, 83, 12},
-    {12, 230, 13, 5, 83, 21},
-    {21, 0, 0, 5, 83, 12},
-    {21, 0, 0, 5, 83, 17},
-    {24, 0, 0, 5, 0, 12},
-    {7, 0, 0, 5, 58, 12},
-    {12, 0, 13, 5, 58, 21},
-    {12, 9, 13, 5, 58, 21},
-    {10, 0, 0, 5, 58, 21},
-    {26, 0, 18, 5, 58, 12},
-    {15, 0, 0, 5, 0, 12},
-    {7, 0, 0, 5, 64, 12},
-    {21, 0, 18, 5, 64, 18},
-    {21, 0, 18, 5, 64, 6},
-    {10, 0, 0, 5, 70, 21},
-    {7, 0, 0, 5, 70, 12},
-    {12, 9, 13, 5, 70, 21},
-    {12, 0, 13, 5, 70, 21},
-    {21, 0, 0, 5, 70, 17},
-    {13, 0, 0, 5, 70, 11},
-    {21, 0, 0, 5, 9, 18},
-    {13, 0, 0, 5, 71, 11},
-    {7, 0, 0, 5, 71, 12},
-    {12, 0, 13, 5, 71, 21},
-    {12, 220, 13, 5, 71, 21},
-    {21, 0, 0, 5, 71, 17},
-    {7, 0, 0, 5, 72, 12},
-    {12, 0, 13, 5, 72, 21},
-    {10, 0, 0, 5, 72, 21},
-    {10, 9, 0, 5, 72, 21},
-    {21, 0, 0, 5, 72, 12},
-    {12, 0, 13, 5, 84, 21},
-    {10, 0, 0, 5, 84, 21},
-    {7, 0, 0, 5, 84, 12},
-    {12, 7, 13, 5, 84, 21},
-    {10, 9, 0, 5, 84, 21},
-    {21, 0, 0, 5, 84, 12},
-    {21, 0, 0, 5, 84, 17},
-    {13, 0, 0, 5, 84, 11},
-    {6, 0, 0, 5, 22, 36},
-    {7, 0, 0, 5, 76, 12},
-    {12, 0, 13, 5, 76, 21},
-    {10, 0, 0, 5, 76, 21},
-    {13, 0, 0, 5, 76, 11},
-    {21, 0, 0, 5, 76, 12},
-    {21, 0, 0, 5, 76, 17},
-    {7, 0, 0, 5, 78, 36},
-    {12, 230, 13, 5, 78, 36},
-    {12, 220, 13, 5, 78, 36},
-    {6, 0, 0, 5, 78, 36},
-    {21, 0, 0, 5, 78, 36},
-    {7, 0, 0, 5, 85, 12},
-    {10, 0, 0, 5, 85, 21},
-    {12, 0, 13, 5, 85, 21},
-    {21, 0, 0, 5, 85, 17},
-    {6, 0, 0, 5, 85, 12},
-    {12, 9, 13, 5, 85, 21},
-    {13, 0, 0, 5, 85, 11},
-    {7, 0, 0, 2, 24, 23},
-    {7, 0, 0, 2, 24, 24},
-    {4, 0, 0, 5, 102, 37},
-    {3, 0, 0, 4, 102, 39},
-    {12, 26, 13, 5, 5, 21},
-    {25, 0, 9, 5, 5, 12},
-    {24, 0, 4, 5, 6, 12},
-    {12, 0, 13, 4, 40, 21},
-    {21, 0, 18, 2, 0, 8},
-    {21, 0, 18, 2, 0, 6},
-    {21, 0, 18, 2, 0, 15},
-    {16, 0, 18, 2, 0, 14},
-    {21, 0, 12, 2, 0, 1},
-    {21, 0, 12, 2, 0, 5},
-    {21, 0, 10, 2, 0, 14},
-    {25, 0, 9, 2, 0, 14},
-    {17, 0, 9, 2, 0, 14},
-    {25, 0, 18, 2, 0, 14},
-    {23, 0, 10, 2, 0, 9},
-    {21, 0, 10, 2, 0, 10},
-    {21, 0, 18, 0, 0, 6},
-    {21, 0, 18, 0, 0, 14},
-    {21, 0, 10, 0, 0, 14},
-    {23, 0, 10, 0, 0, 9},
-    {21, 0, 10, 0, 0, 10},
-    {22, 0, 18, 0, 0, 0},
-    {18, 0, 18, 0, 0, 1},
-    {25, 0, 9, 0, 0, 14},
-    {21, 0, 12, 0, 0, 1},
-    {17, 0, 9, 0, 0, 14},
-    {21, 0, 12, 0, 0, 14},
-    {13, 0, 8, 0, 0, 14},
-    {21, 0, 12, 0, 0, 5},
-    {21, 0, 18, 0, 0, 5},
-    {25, 0, 18, 0, 0, 14},
-    {9, 0, 0, 0, 1, 14},
-    {24, 0, 18, 0, 0, 14},
-    {16, 0, 18, 0, 0, 14},
-    {5, 0, 0, 0, 1, 14},
-    {21, 0, 18, 1, 0, 1},
-    {22, 0, 18, 1, 0, 0},
-    {18, 0, 18, 1, 0, 1},
-    {21, 0, 18, 1, 0, 5},
-    {7, 0, 0, 1, 33, 14},
-    {7, 0, 0, 1, 33, 32},
-    {6, 0, 0, 1, 0, 32},
-    {6, 0, 0, 1, 0, 5},
-    {7, 0, 0, 1, 24, 14},
-    {23, 0, 10, 0, 0, 10},
-    {26, 0, 18, 0, 0, 14},
-    {26, 0, 18, 1, 0, 12},
-    {25, 0, 18, 1, 0, 12},
-    {1, 0, 18, 5, 0, 21},
-    {26, 0, 18, 5, 0, 31},
-    {7, 0, 0, 5, 47, 12},
-    {14, 0, 18, 5, 2, 12},
-    {15, 0, 18, 5, 2, 12},
-    {26, 0, 18, 5, 2, 12},
-    {26, 0, 0, 5, 2, 12},
-    {7, 0, 0, 5, 73, 12},
-    {7, 0, 0, 5, 74, 12},
-    {7, 0, 0, 5, 37, 12},
-    {15, 0, 0, 5, 37, 12},
-    {7, 0, 0, 5, 38, 12},
-    {14, 0, 0, 5, 38, 12},
-    {7, 0, 0, 5, 118, 12},
-    {12, 230, 13, 5, 118, 21},
-    {7, 0, 0, 5, 48, 12},
-    {21, 0, 0, 5, 48, 17},
-    {7, 0, 0, 5, 59, 12},
-    {21, 0, 0, 5, 59, 17},
-    {14, 0, 0, 5, 59, 12},
-    {9, 0, 0, 5, 39, 12},
-    {5, 0, 0, 5, 39, 12},
-    {7, 0, 0, 5, 49, 12},
-    {7, 0, 0, 5, 50, 12},
-    {13, 0, 0, 5, 50, 11},
-    {9, 0, 0, 5, 136, 12},
-    {5, 0, 0, 5, 136, 12},
-    {7, 0, 0, 5, 106, 12},
-    {7, 0, 0, 5, 104, 12},
-    {21, 0, 0, 5, 104, 12},
-    {7, 0, 0, 5, 110, 12},
-    {7, 0, 3, 5, 51, 12},
-    {7, 0, 3, 5, 86, 12},
-    {21, 0, 3, 5, 86, 17},
-    {15, 0, 3, 5, 86, 12},
-    {7, 0, 3, 5, 120, 12},
-    {26, 0, 3, 5, 120, 12},
-    {15, 0, 3, 5, 120, 12},
-    {7, 0, 3, 5, 116, 12},
-    {15, 0, 3, 5, 116, 12},
-    {7, 0, 3, 5, 128, 12},
-    {15, 0, 3, 5, 128, 12},
-    {7, 0, 3, 5, 63, 12},
-    {15, 0, 3, 5, 63, 12},
-    {21, 0, 18, 5, 63, 17},
-    {7, 0, 3, 5, 75, 12},
-    {21, 0, 3, 5, 75, 12},
-    {7, 0, 3, 5, 97, 12},
-    {7, 0, 3, 5, 96, 12},
-    {15, 0, 3, 5, 96, 12},
-    {7, 0, 3, 5, 60, 12},
-    {12, 0, 13, 5, 60, 21},
-    {12, 220, 13, 5, 60, 21},
-    {12, 230, 13, 5, 60, 21},
-    {12, 1, 13, 5, 60, 21},
-    {12, 9, 13, 5, 60, 21},
-    {15, 0, 3, 5, 60, 12},
-    {21, 0, 3, 5, 60, 17},
-    {21, 0, 3, 5, 60, 12},
-    {7, 0, 3, 5, 87, 12},
-    {15, 0, 3, 5, 87, 12},
-    {21, 0, 3, 5, 87, 12},
-    {7, 0, 3, 5, 117, 12},
-    {15, 0, 3, 5, 117, 12},
-    {7, 0, 3, 5, 112, 12},
-    {26, 0, 3, 5, 112, 12},
-    {12, 230, 13, 5, 112, 21},
-    {12, 220, 13, 5, 112, 21},
-    {15, 0, 3, 5, 112, 12},
-    {21, 0, 3, 5, 112, 17},
-    {21, 0, 3, 5, 112, 15},
-    {7, 0, 3, 5, 79, 12},
-    {21, 0, 18, 5, 79, 17},
-    {7, 0, 3, 5, 88, 12},
-    {15, 0, 3, 5, 88, 12},
-    {7, 0, 3, 5, 89, 12},
-    {15, 0, 3, 5, 89, 12},
-    {7, 0, 3, 5, 122, 12},
-    {21, 0, 3, 5, 122, 12},
-    {15, 0, 3, 5, 122, 12},
-    {7, 0, 3, 5, 90, 12},
-    {9, 0, 3, 5, 130, 12},
-    {5, 0, 3, 5, 130, 12},
-    {15, 0, 3, 5, 130, 12},
-    {7, 0, 4, 5, 144, 12},
-    {12, 230, 13, 5, 144, 21},
-    {13, 0, 11, 5, 144, 11},
-    {15, 0, 11, 5, 6, 12},
-    {7, 0, 3, 5, 147, 12},
-    {15, 0, 3, 5, 147, 12},
-    {7, 0, 4, 5, 148, 12},
-    {12, 220, 13, 5, 148, 21},
-    {12, 230, 13, 5, 148, 21},
-    {15, 0, 4, 5, 148, 12},
-    {21, 0, 4, 5, 148, 12},
-    {10, 0, 0, 5, 93, 21},
-    {12, 0, 13, 5, 93, 21},
-    {7, 0, 0, 5, 93, 12},
-    {12, 9, 13, 5, 93, 21},
-    {21, 0, 0, 5, 93, 17},
-    {21, 0, 0, 5, 93, 12},
-    {15, 0, 18, 5, 93, 12},
-    {13, 0, 0, 5, 93, 11},
-    {12, 0, 13, 5, 91, 21},
-    {10, 0, 0, 5, 91, 21},
-    {7, 0, 0, 5, 91, 12},
-    {12, 9, 13, 5, 91, 21},
-    {12, 7, 13, 5, 91, 21},
-    {21, 0, 0, 5, 91, 12},
-    {1, 0, 0, 5, 91, 12},
-    {21, 0, 0, 5, 91, 17},
-    {7, 0, 0, 5, 100, 12},
-    {13, 0, 0, 5, 100, 11},
-    {12, 230, 13, 5, 95, 21},
-    {7, 0, 0, 5, 95, 12},
-    {12, 0, 13, 5, 95, 21},
-    {10, 0, 0, 5, 95, 21},
-    {12, 9, 13, 5, 95, 21},
-    {13, 0, 0, 5, 95, 11},
-    {21, 0, 0, 5, 95, 17},
-    {7, 0, 0, 5, 111, 12},
-    {12, 7, 13, 5, 111, 21},
-    {21, 0, 0, 5, 111, 12},
-    {21, 0, 0, 5, 111, 18},
-    {12, 0, 13, 5, 99, 21},
-    {10, 0, 0, 5, 99, 21},
-    {7, 0, 0, 5, 99, 12},
-    {10, 9, 0, 5, 99, 21},
-    {21, 0, 0, 5, 99, 17},
-    {21, 0, 0, 5, 99, 12},
-    {12, 7, 13, 5, 99, 21},
-    {13, 0, 0, 5, 99, 11},
-    {21, 0, 0, 5, 99, 18},
-    {15, 0, 0, 5, 18, 12},
-    {7, 0, 0, 5, 108, 12},
-    {10, 0, 0, 5, 108, 21},
-    {12, 0, 13, 5, 108, 21},
-    {10, 9, 0, 5, 108, 21},
-    {12, 7, 13, 5, 108, 21},
-    {21, 0, 0, 5, 108, 17},
-    {21, 0, 0, 5, 108, 12},
-    {7, 0, 0, 5, 129, 12},
-    {21, 0, 0, 5, 129, 17},
-    {7, 0, 0, 5, 109, 12},
-    {12, 0, 13, 5, 109, 21},
-    {10, 0, 0, 5, 109, 21},
-    {12, 7, 13, 5, 109, 21},
-    {12, 9, 13, 5, 109, 21},
-    {13, 0, 0, 5, 109, 11},
-    {12, 0, 13, 5, 107, 21},
-    {10, 0, 0, 5, 107, 21},
-    {7, 0, 0, 5, 107, 12},
-    {12, 7, 13, 5, 40, 21},
-    {12, 7, 13, 5, 107, 21},
-    {10, 9, 0, 5, 107, 21},
-    {12, 230, 13, 5, 107, 21},
-    {7, 0, 0, 5, 135, 12},
-    {10, 0, 0, 5, 135, 21},
-    {12, 0, 13, 5, 135, 21},
-    {12, 9, 13, 5, 135, 21},
-    {12, 7, 13, 5, 135, 21},
-    {21, 0, 0, 5, 135, 17},
-    {21, 0, 0, 5, 135, 12},
-    {13, 0, 0, 5, 135, 11},
-    {12, 230, 13, 5, 135, 21},
-    {7, 0, 0, 5, 124, 12},
-    {10, 0, 0, 5, 124, 21},
-    {12, 0, 13, 5, 124, 21},
-    {12, 9, 13, 5, 124, 21},
-    {12, 7, 13, 5, 124, 21},
-    {21, 0, 0, 5, 124, 12},
-    {13, 0, 0, 5, 124, 11},
-    {7, 0, 0, 5, 123, 12},
-    {10, 0, 0, 5, 123, 21},
-    {12, 0, 13, 5, 123, 21},
-    {12, 9, 13, 5, 123, 21},
-    {12, 7, 13, 5, 123, 21},
-    {21, 0, 0, 5, 123, 18},
-    {21, 0, 0, 5, 123, 17},
-    {21, 0, 0, 5, 123, 6},
-    {21, 0, 0, 5, 123, 12},
-    {7, 0, 0, 5, 114, 12},
-    {10, 0, 0, 5, 114, 21},
-    {12, 0, 13, 5, 114, 21},
-    {12, 9, 13, 5, 114, 21},
-    {21, 0, 0, 5, 114, 17},
-    {21, 0, 0, 5, 114, 12},
-    {13, 0, 0, 5, 114, 11},
-    {21, 0, 18, 5, 31, 18},
-    {7, 0, 0, 5, 101, 12},
-    {12, 0, 13, 5, 101, 21},
-    {10, 0, 0, 5, 101, 21},
-    {10, 9, 0, 5, 101, 21},
-    {12, 7, 13, 5, 101, 21},
-    {13, 0, 0, 5, 101, 11},
-    {7, 0, 0, 5, 126, 36},
-    {12, 0, 13, 5, 126, 36},
-    {10, 0, 0, 5, 126, 36},
-    {12, 9, 13, 5, 126, 36},
-    {13, 0, 0, 5, 126, 11},
-    {15, 0, 0, 5, 126, 36},
-    {21, 0, 0, 5, 126, 17},
-    {26, 0, 0, 5, 126, 36},
-    {7, 0, 0, 5, 142, 12},
-    {10, 0, 0, 5, 142, 21},
-    {12, 0, 13, 5, 142, 21},
-    {12, 9, 13, 5, 142, 21},
-    {12, 7, 13, 5, 142, 21},
-    {21, 0, 0, 5, 142, 12},
-    {9, 0, 0, 5, 125, 12},
-    {5, 0, 0, 5, 125, 12},
-    {13, 0, 0, 5, 125, 11},
-    {15, 0, 0, 5, 125, 12},
-    {7, 0, 0, 5, 125, 12},
-    {7, 0, 0, 5, 141, 12},
-    {12, 0, 13, 5, 141, 21},
-    {12, 0, 0, 5, 141, 21},
-    {12, 9, 13, 5, 141, 21},
-    {10, 0, 0, 5, 141, 21},
-    {21, 0, 0, 5, 141, 18},
-    {21, 0, 0, 5, 141, 12},
-    {21, 0, 0, 5, 141, 17},
-    {7, 0, 0, 5, 140, 12},
-    {12, 0, 13, 5, 140, 21},
-    {10, 0, 0, 5, 140, 21},
-    {12, 9, 13, 5, 140, 21},
-    {21, 0, 0, 5, 140, 17},
-    {21, 0, 0, 5, 140, 18},
-    {7, 0, 0, 5, 121, 12},
-    {7, 0, 0, 5, 133, 12},
-    {10, 0, 0, 5, 133, 21},
-    {12, 0, 13, 5, 133, 21},
-    {12, 9, 0, 5, 133, 21},
-    {21, 0, 0, 5, 133, 17},
-    {13, 0, 0, 5, 133, 11},
-    {15, 0, 0, 5, 133, 12},
-    {21, 0, 0, 5, 134, 18},
-    {21, 0, 0, 5, 134, 6},
-    {7, 0, 0, 5, 134, 12},
-    {12, 0, 13, 5, 134, 21},
-    {10, 0, 0, 5, 134, 21},
-    {7, 0, 0, 5, 138, 12},
-    {12, 0, 13, 5, 138, 21},
-    {12, 7, 13, 5, 138, 21},
-    {12, 9, 13, 5, 138, 21},
-    {13, 0, 0, 5, 138, 11},
-    {7, 0, 0, 5, 143, 12},
-    {10, 0, 0, 5, 143, 21},
-    {12, 0, 13, 5, 143, 21},
-    {12, 9, 13, 5, 143, 21},
-    {13, 0, 0, 5, 143, 11},
-    {7, 0, 0, 5, 145, 12},
-    {12, 0, 13, 5, 145, 21},
-    {10, 0, 0, 5, 145, 21},
-    {21, 0, 0, 5, 145, 12},
-    {7, 0, 0, 5, 62, 12},
-    {14, 0, 0, 5, 62, 12},
-    {21, 0, 0, 5, 62, 17},
-    {7, 0, 0, 5, 80, 12},
-    {7, 0, 0, 5, 80, 0},
-    {7, 0, 0, 5, 80, 1},
-    {7, 0, 0, 5, 127, 12},
-    {7, 0, 0, 5, 127, 0},
-    {7, 0, 0, 5, 127, 1},
-    {7, 0, 0, 5, 115, 12},
-    {13, 0, 0, 5, 115, 11},
-    {21, 0, 0, 5, 115, 17},
-    {7, 0, 0, 5, 103, 12},
-    {12, 1, 13, 5, 103, 21},
-    {21, 0, 0, 5, 103, 17},
-    {7, 0, 0, 5, 119, 12},
-    {12, 230, 13, 5, 119, 21},
-    {21, 0, 0, 5, 119, 17},
-    {21, 0, 0, 5, 119, 12},
-    {26, 0, 0, 5, 119, 12},
-    {6, 0, 0, 5, 119, 12},
-    {13, 0, 0, 5, 119, 11},
-    {15, 0, 0, 5, 119, 12},
-    {9, 0, 0, 5, 146, 12},
-    {5, 0, 0, 5, 146, 12},
-    {15, 0, 0, 5, 146, 12},
-    {21, 0, 0, 5, 146, 17},
-    {21, 0, 0, 5, 146, 12},
-    {7, 0, 0, 5, 98, 12},
-    {10, 0, 0, 5, 98, 21},
-    {12, 0, 13, 5, 98, 21},
-    {6, 0, 0, 5, 98, 12},
-    {6, 0, 0, 2, 137, 5},
-    {6, 0, 0, 2, 139, 5},
-    {7, 0, 0, 2, 137, 14},
-    {7, 0, 0, 2, 139, 14},
-    {7, 0, 0, 5, 105, 12},
-    {26, 0, 0, 5, 105, 12},
-    {12, 0, 13, 5, 105, 21},
-    {12, 1, 13, 5, 105, 21},
-    {21, 0, 0, 5, 105, 17},
-    {10, 216, 0, 5, 0, 21},
-    {10, 226, 0, 5, 0, 21},
-    {12, 230, 13, 5, 2, 21},
-    {25, 0, 0, 5, 0, 12},
-    {13, 0, 8, 5, 0, 11},
-    {26, 0, 0, 5, 131, 12},
-    {12, 0, 13, 5, 131, 21},
-    {21, 0, 0, 5, 131, 17},
-    {21, 0, 0, 5, 131, 12},
-    {12, 230, 13, 5, 56, 21},
-    {7, 0, 3, 5, 113, 12},
-    {15, 0, 3, 5, 113, 12},
-    {12, 220, 13, 5, 113, 21},
-    {9, 0, 3, 5, 132, 12},
-    {5, 0, 3, 5, 132, 12},
-    {12, 230, 13, 5, 132, 21},
-    {12, 7, 13, 5, 132, 21},
-    {13, 0, 3, 5, 132, 11},
-    {21, 0, 3, 5, 132, 0},
-    {15, 0, 4, 5, 0, 12},
-    {26, 0, 4, 5, 0, 10},
-    {23, 0, 4, 5, 0, 10},
-    {2, 0, 18, 5, 102, 14},
-    {26, 0, 0, 2, 0, 29},
-    {26, 0, 0, 5, 0, 28},
-    {26, 0, 0, 2, 32, 14},
-    {24, 0, 18, 2, 0, 42},
-    {26, 0, 18, 5, 0, 5},
-};
-
-#define BIDI_MIRROR_LEN 420
-static const MirrorPair mirror_pairs[] = {
-    {40, 41},
-    {41, 40},
-    {60, 62},
-    {62, 60},
-    {91, 93},
-    {93, 91},
-    {123, 125},
-    {125, 123},
-    {171, 187},
-    {187, 171},
-    {3898, 3899},
-    {3899, 3898},
-    {3900, 3901},
-    {3901, 3900},
-    {5787, 5788},
-    {5788, 5787},
-    {8249, 8250},
-    {8250, 8249},
-    {8261, 8262},
-    {8262, 8261},
-    {8317, 8318},
-    {8318, 8317},
-    {8333, 8334},
-    {8334, 8333},
-    {8712, 8715},
-    {8713, 8716},
-    {8714, 8717},
-    {8715, 8712},
-    {8716, 8713},
-    {8717, 8714},
-    {8725, 10741},
-    {8735, 11262},
-    {8736, 10659},
-    {8737, 10651},
-    {8738, 10656},
-    {8740, 10990},
-    {8764, 8765},
-    {8765, 8764},
-    {8771, 8909},
-    {8773, 8780},
-    {8780, 8773},
-    {8786, 8787},
-    {8787, 8786},
-    {8788, 8789},
-    {8789, 8788},
-    {8804, 8805},
-    {8805, 8804},
-    {8806, 8807},
-    {8807, 8806},
-    {8808, 8809},
-    {8809, 8808},
-    {8810, 8811},
-    {8811, 8810},
-    {8814, 8815},
-    {8815, 8814},
-    {8816, 8817},
-    {8817, 8816},
-    {8818, 8819},
-    {8819, 8818},
-    {8820, 8821},
-    {8821, 8820},
-    {8822, 8823},
-    {8823, 8822},
-    {8824, 8825},
-    {8825, 8824},
-    {8826, 8827},
-    {8827, 8826},
-    {8828, 8829},
-    {8829, 8828},
-    {8830, 8831},
-    {8831, 8830},
-    {8832, 8833},
-    {8833, 8832},
-    {8834, 8835},
-    {8835, 8834},
-    {8836, 8837},
-    {8837, 8836},
-    {8838, 8839},
-    {8839, 8838},
-    {8840, 8841},
-    {8841, 8840},
-    {8842, 8843},
-    {8843, 8842},
-    {8847, 8848},
-    {8848, 8847},
-    {8849, 8850},
-    {8850, 8849},
-    {8856, 10680},
-    {8866, 8867},
-    {8867, 8866},
-    {8870, 10974},
-    {8872, 10980},
-    {8873, 10979},
-    {8875, 10981},
-    {8880, 8881},
-    {8881, 8880},
-    {8882, 8883},
-    {8883, 8882},
-    {8884, 8885},
-    {8885, 8884},
-    {8886, 8887},
-    {8887, 8886},
-    {8888, 10204},
-    {8905, 8906},
-    {8906, 8905},
-    {8907, 8908},
-    {8908, 8907},
-    {8909, 8771},
-    {8912, 8913},
-    {8913, 8912},
-    {8918, 8919},
-    {8919, 8918},
-    {8920, 8921},
-    {8921, 8920},
-    {8922, 8923},
-    {8923, 8922},
-    {8924, 8925},
-    {8925, 8924},
-    {8926, 8927},
-    {8927, 8926},
-    {8928, 8929},
-    {8929, 8928},
-    {8930, 8931},
-    {8931, 8930},
-    {8932, 8933},
-    {8933, 8932},
-    {8934, 8935},
-    {8935, 8934},
-    {8936, 8937},
-    {8937, 8936},
-    {8938, 8939},
-    {8939, 8938},
-    {8940, 8941},
-    {8941, 8940},
-    {8944, 8945},
-    {8945, 8944},
-    {8946, 8954},
-    {8947, 8955},
-    {8948, 8956},
-    {8950, 8957},
-    {8951, 8958},
-    {8954, 8946},
-    {8955, 8947},
-    {8956, 8948},
-    {8957, 8950},
-    {8958, 8951},
-    {8968, 8969},
-    {8969, 8968},
-    {8970, 8971},
-    {8971, 8970},
-    {9001, 9002},
-    {9002, 9001},
-    {10088, 10089},
-    {10089, 10088},
-    {10090, 10091},
-    {10091, 10090},
-    {10092, 10093},
-    {10093, 10092},
-    {10094, 10095},
-    {10095, 10094},
-    {10096, 10097},
-    {10097, 10096},
-    {10098, 10099},
-    {10099, 10098},
-    {10100, 10101},
-    {10101, 10100},
-    {10179, 10180},
-    {10180, 10179},
-    {10181, 10182},
-    {10182, 10181},
-    {10184, 10185},
-    {10185, 10184},
-    {10187, 10189},
-    {10189, 10187},
-    {10197, 10198},
-    {10198, 10197},
-    {10204, 8888},
-    {10205, 10206},
-    {10206, 10205},
-    {10210, 10211},
-    {10211, 10210},
-    {10212, 10213},
-    {10213, 10212},
-    {10214, 10215},
-    {10215, 10214},
-    {10216, 10217},
-    {10217, 10216},
-    {10218, 10219},
-    {10219, 10218},
-    {10220, 10221},
-    {10221, 10220},
-    {10222, 10223},
-    {10223, 10222},
-    {10627, 10628},
-    {10628, 10627},
-    {10629, 10630},
-    {10630, 10629},
-    {10631, 10632},
-    {10632, 10631},
-    {10633, 10634},
-    {10634, 10633},
-    {10635, 10636},
-    {10636, 10635},
-    {10637, 10640},
-    {10638, 10639},
-    {10639, 10638},
-    {10640, 10637},
-    {10641, 10642},
-    {10642, 10641},
-    {10643, 10644},
-    {10644, 10643},
-    {10645, 10646},
-    {10646, 10645},
-    {10647, 10648},
-    {10648, 10647},
-    {10651, 8737},
-    {10656, 8738},
-    {10659, 8736},
-    {10660, 10661},
-    {10661, 10660},
-    {10664, 10665},
-    {10665, 10664},
-    {10666, 10667},
-    {10667, 10666},
-    {10668, 10669},
-    {10669, 10668},
-    {10670, 10671},
-    {10671, 10670},
-    {10680, 8856},
-    {10688, 10689},
-    {10689, 10688},
-    {10692, 10693},
-    {10693, 10692},
-    {10703, 10704},
-    {10704, 10703},
-    {10705, 10706},
-    {10706, 10705},
-    {10708, 10709},
-    {10709, 10708},
-    {10712, 10713},
-    {10713, 10712},
-    {10714, 10715},
-    {10715, 10714},
-    {10728, 10729},
-    {10729, 10728},
-    {10741, 8725},
-    {10744, 10745},
-    {10745, 10744},
-    {10748, 10749},
-    {10749, 10748},
-    {10795, 10796},
-    {10796, 10795},
-    {10797, 10798},
-    {10798, 10797},
-    {10804, 10805},
-    {10805, 10804},
-    {10812, 10813},
-    {10813, 10812},
-    {10852, 10853},
-    {10853, 10852},
-    {10873, 10874},
-    {10874, 10873},
-    {10875, 10876},
-    {10876, 10875},
-    {10877, 10878},
-    {10878, 10877},
-    {10879, 10880},
-    {10880, 10879},
-    {10881, 10882},
-    {10882, 10881},
-    {10883, 10884},
-    {10884, 10883},
-    {10885, 10886},
-    {10886, 10885},
-    {10887, 10888},
-    {10888, 10887},
-    {10889, 10890},
-    {10890, 10889},
-    {10891, 10892},
-    {10892, 10891},
-    {10893, 10894},
-    {10894, 10893},
-    {10895, 10896},
-    {10896, 10895},
-    {10897, 10898},
-    {10898, 10897},
-    {10899, 10900},
-    {10900, 10899},
-    {10901, 10902},
-    {10902, 10901},
-    {10903, 10904},
-    {10904, 10903},
-    {10905, 10906},
-    {10906, 10905},
-    {10907, 10908},
-    {10908, 10907},
-    {10909, 10910},
-    {10910, 10909},
-    {10911, 10912},
-    {10912, 10911},
-    {10913, 10914},
-    {10914, 10913},
-    {10918, 10919},
-    {10919, 10918},
-    {10920, 10921},
-    {10921, 10920},
-    {10922, 10923},
-    {10923, 10922},
-    {10924, 10925},
-    {10925, 10924},
-    {10927, 10928},
-    {10928, 10927},
-    {10929, 10930},
-    {10930, 10929},
-    {10931, 10932},
-    {10932, 10931},
-    {10933, 10934},
-    {10934, 10933},
-    {10935, 10936},
-    {10936, 10935},
-    {10937, 10938},
-    {10938, 10937},
-    {10939, 10940},
-    {10940, 10939},
-    {10941, 10942},
-    {10942, 10941},
-    {10943, 10944},
-    {10944, 10943},
-    {10945, 10946},
-    {10946, 10945},
-    {10947, 10948},
-    {10948, 10947},
-    {10949, 10950},
-    {10950, 10949},
-    {10951, 10952},
-    {10952, 10951},
-    {10953, 10954},
-    {10954, 10953},
-    {10955, 10956},
-    {10956, 10955},
-    {10957, 10958},
-    {10958, 10957},
-    {10959, 10960},
-    {10960, 10959},
-    {10961, 10962},
-    {10962, 10961},
-    {10963, 10964},
-    {10964, 10963},
-    {10965, 10966},
-    {10966, 10965},
-    {10974, 8870},
-    {10979, 8873},
-    {10980, 8872},
-    {10981, 8875},
-    {10988, 10989},
-    {10989, 10988},
-    {10990, 8740},
-    {10999, 11000},
-    {11000, 10999},
-    {11001, 11002},
-    {11002, 11001},
-    {11262, 8735},
-    {11778, 11779},
-    {11779, 11778},
-    {11780, 11781},
-    {11781, 11780},
-    {11785, 11786},
-    {11786, 11785},
-    {11788, 11789},
-    {11789, 11788},
-    {11804, 11805},
-    {11805, 11804},
-    {11808, 11809},
-    {11809, 11808},
-    {11810, 11811},
-    {11811, 11810},
-    {11812, 11813},
-    {11813, 11812},
-    {11814, 11815},
-    {11815, 11814},
-    {11816, 11817},
-    {11817, 11816},
-    {12296, 12297},
-    {12297, 12296},
-    {12298, 12299},
-    {12299, 12298},
-    {12300, 12301},
-    {12301, 12300},
-    {12302, 12303},
-    {12303, 12302},
-    {12304, 12305},
-    {12305, 12304},
-    {12308, 12309},
-    {12309, 12308},
-    {12310, 12311},
-    {12311, 12310},
-    {12312, 12313},
-    {12313, 12312},
-    {12314, 12315},
-    {12315, 12314},
-    {65113, 65114},
-    {65114, 65113},
-    {65115, 65116},
-    {65116, 65115},
-    {65117, 65118},
-    {65118, 65117},
-    {65124, 65125},
-    {65125, 65124},
-    {65288, 65289},
-    {65289, 65288},
-    {65308, 65310},
-    {65310, 65308},
-    {65339, 65341},
-    {65341, 65339},
-    {65371, 65373},
-    {65373, 65371},
-    {65375, 65376},
-    {65376, 65375},
-    {65378, 65379},
-    {65379, 65378},
-};
-
-#define BIDI_BRACKET_LEN 120
-static const BracketPair bracket_pairs[] = {
-    {40, 41, 0},
-    {41, 40, 1},
-    {91, 93, 0},
-    {93, 91, 1},
-    {123, 125, 0},
-    {125, 123, 1},
-    {3898, 3899, 0},
-    {3899, 3898, 1},
-    {3900, 3901, 0},
-    {3901, 3900, 1},
-    {5787, 5788, 0},
-    {5788, 5787, 1},
-    {8261, 8262, 0},
-    {8262, 8261, 1},
-    {8317, 8318, 0},
-    {8318, 8317, 1},
-    {8333, 8334, 0},
-    {8334, 8333, 1},
-    {8968, 8969, 0},
-    {8969, 8968, 1},
-    {8970, 8971, 0},
-    {8971, 8970, 1},
-    {9001, 9002, 0},
-    {9002, 9001, 1},
-    {10088, 10089, 0},
-    {10089, 10088, 1},
-    {10090, 10091, 0},
-    {10091, 10090, 1},
-    {10092, 10093, 0},
-    {10093, 10092, 1},
-    {10094, 10095, 0},
-    {10095, 10094, 1},
-    {10096, 10097, 0},
-    {10097, 10096, 1},
-    {10098, 10099, 0},
-    {10099, 10098, 1},
-    {10100, 10101, 0},
-    {10101, 10100, 1},
-    {10181, 10182, 0},
-    {10182, 10181, 1},
-    {10214, 10215, 0},
-    {10215, 10214, 1},
-    {10216, 10217, 0},
-    {10217, 10216, 1},
-    {10218, 10219, 0},
-    {10219, 10218, 1},
-    {10220, 10221, 0},
-    {10221, 10220, 1},
-    {10222, 10223, 0},
-    {10223, 10222, 1},
-    {10627, 10628, 0},
-    {10628, 10627, 1},
-    {10629, 10630, 0},
-    {10630, 10629, 1},
-    {10631, 10632, 0},
-    {10632, 10631, 1},
-    {10633, 10634, 0},
-    {10634, 10633, 1},
-    {10635, 10636, 0},
-    {10636, 10635, 1},
-    {10637, 10640, 0},
-    {10638, 10639, 1},
-    {10639, 10638, 0},
-    {10640, 10637, 1},
-    {10641, 10642, 0},
-    {10642, 10641, 1},
-    {10643, 10644, 0},
-    {10644, 10643, 1},
-    {10645, 10646, 0},
-    {10646, 10645, 1},
-    {10647, 10648, 0},
-    {10648, 10647, 1},
-    {10712, 10713, 0},
-    {10713, 10712, 1},
-    {10714, 10715, 0},
-    {10715, 10714, 1},
-    {10748, 10749, 0},
-    {10749, 10748, 1},
-    {11810, 11811, 0},
-    {11811, 11810, 1},
-    {11812, 11813, 0},
-    {11813, 11812, 1},
-    {11814, 11815, 0},
-    {11815, 11814, 1},
-    {11816, 11817, 0},
-    {11817, 11816, 1},
-    {12296, 12297, 0},
-    {12297, 12296, 1},
-    {12298, 12299, 0},
-    {12299, 12298, 1},
-    {12300, 12301, 0},
-    {12301, 12300, 1},
-    {12302, 12303, 0},
-    {12303, 12302, 1},
-    {12304, 12305, 0},
-    {12305, 12304, 1},
-    {12308, 12309, 0},
-    {12309, 12308, 1},
-    {12310, 12311, 0},
-    {12311, 12310, 1},
-    {12312, 12313, 0},
-    {12313, 12312, 1},
-    {12314, 12315, 0},
-    {12315, 12314, 1},
-    {65113, 65114, 0},
-    {65114, 65113, 1},
-    {65115, 65116, 0},
-    {65116, 65115, 1},
-    {65117, 65118, 0},
-    {65118, 65117, 1},
-    {65288, 65289, 0},
-    {65289, 65288, 1},
-    {65339, 65341, 0},
-    {65341, 65339, 1},
-    {65371, 65373, 0},
-    {65373, 65371, 1},
-    {65375, 65376, 0},
-    {65376, 65375, 1},
-    {65378, 65379, 0},
-    {65379, 65378, 1},
-};
-
-/* Reindexing of NFC first characters. */
-#define TOTAL_FIRST 376
-#define TOTAL_LAST 62
-static const Reindex nfc_first[] = {
-  { 60, 2, 0},
-  { 65, 15, 3},
-  { 82, 8, 19},
-  { 97, 15, 28},
-  { 114, 8, 44},
-  { 168, 0, 53},
-  { 194, 0, 54},
-  { 196, 3, 55},
-  { 202, 0, 59},
-  { 207, 0, 60},
-  { 212, 2, 61},
-  { 216, 0, 64},
-  { 220, 0, 65},
-  { 226, 0, 66},
-  { 228, 3, 67},
-  { 234, 0, 71},
-  { 239, 0, 72},
-  { 244, 2, 73},
-  { 248, 0, 76},
-  { 252, 0, 77},
-  { 258, 1, 78},
-  { 274, 1, 80},
-  { 332, 1, 82},
-  { 346, 1, 84},
-  { 352, 1, 86},
-  { 360, 3, 88},
-  { 383, 0, 92},
-  { 416, 1, 93},
-  { 431, 1, 95},
-  { 439, 0, 97},
-  { 490, 1, 98},
-  { 550, 3, 100},
-  { 558, 1, 104},
-  { 658, 0, 106},
-  { 913, 0, 107},
-  { 917, 0, 108},
-  { 919, 0, 109},
-  { 921, 0, 110},
-  { 927, 0, 111},
-  { 929, 0, 112},
-  { 933, 0, 113},
-  { 937, 0, 114},
-  { 940, 0, 115},
-  { 942, 0, 116},
-  { 945, 0, 117},
-  { 949, 0, 118},
-  { 951, 0, 119},
-  { 953, 0, 120},
-  { 959, 0, 121},
-  { 961, 0, 122},
-  { 965, 0, 123},
-  { 969, 2, 124},
-  { 974, 0, 127},
-  { 978, 0, 128},
-  { 1030, 0, 129},
-  { 1040, 0, 130},
-  { 1043, 0, 131},
-  { 1045, 3, 132},
-  { 1050, 0, 136},
-  { 1054, 0, 137},
-  { 1059, 0, 138},
-  { 1063, 0, 139},
-  { 1067, 0, 140},
-  { 1069, 0, 141},
-  { 1072, 0, 142},
-  { 1075, 0, 143},
-  { 1077, 3, 144},
-  { 1082, 0, 148},
-  { 1086, 0, 149},
-  { 1091, 0, 150},
-  { 1095, 0, 151},
-  { 1099, 0, 152},
-  { 1101, 0, 153},
-  { 1110, 0, 154},
-  { 1140, 1, 155},
-  { 1240, 1, 157},
-  { 1256, 1, 159},
-  { 1575, 0, 161},
-  { 1608, 0, 162},
-  { 1610, 0, 163},
-  { 1729, 0, 164},
-  { 1746, 0, 165},
-  { 1749, 0, 166},
-  { 2344, 0, 167},
-  { 2352, 0, 168},
-  { 2355, 0, 169},
-  { 2503, 0, 170},
-  { 2887, 0, 171},
-  { 2962, 0, 172},
-  { 3014, 1, 173},
-  { 3142, 0, 175},
-  { 3263, 0, 176},
-  { 3270, 0, 177},
-  { 3274, 0, 178},
-  { 3398, 1, 179},
-  { 3545, 0, 181},
-  { 3548, 0, 182},
-  { 4133, 0, 183},
-  { 6917, 0, 184},
-  { 6919, 0, 185},
-  { 6921, 0, 186},
-  { 6923, 0, 187},
-  { 6925, 0, 188},
-  { 6929, 0, 189},
-  { 6970, 0, 190},
-  { 6972, 0, 191},
-  { 6974, 1, 192},
-  { 6978, 0, 194},
-  { 7734, 1, 195},
-  { 7770, 1, 197},
-  { 7778, 1, 199},
-  { 7840, 1, 201},
-  { 7864, 1, 203},
-  { 7884, 1, 205},
-  { 7936, 17, 207},
-  { 7960, 1, 225},
-  { 7968, 17, 227},
-  { 7992, 1, 245},
-  { 8000, 1, 247},
-  { 8008, 1, 249},
-  { 8016, 1, 251},
-  { 8025, 0, 253},
-  { 8032, 16, 254},
-  { 8052, 0, 271},
-  { 8060, 0, 272},
-  { 8118, 0, 273},
-  { 8127, 0, 274},
-  { 8134, 0, 275},
-  { 8182, 0, 276},
-  { 8190, 0, 277},
-  { 8592, 0, 278},
-  { 8594, 0, 279},
-  { 8596, 0, 280},
-  { 8656, 0, 281},
-  { 8658, 0, 282},
-  { 8660, 0, 283},
-  { 8707, 0, 284},
-  { 8712, 0, 285},
-  { 8715, 0, 286},
-  { 8739, 0, 287},
-  { 8741, 0, 288},
-  { 8764, 0, 289},
-  { 8771, 0, 290},
-  { 8773, 0, 291},
-  { 8776, 0, 292},
-  { 8781, 0, 293},
-  { 8801, 0, 294},
-  { 8804, 1, 295},
-  { 8818, 1, 297},
-  { 8822, 1, 299},
-  { 8826, 3, 301},
-  { 8834, 1, 305},
-  { 8838, 1, 307},
-  { 8849, 1, 309},
-  { 8866, 0, 311},
-  { 8872, 1, 312},
-  { 8875, 0, 314},
-  { 8882, 3, 315},
-  { 12358, 0, 319},
-  { 12363, 0, 320},
-  { 12365, 0, 321},
-  { 12367, 0, 322},
-  { 12369, 0, 323},
-  { 12371, 0, 324},
-  { 12373, 0, 325},
-  { 12375, 0, 326},
-  { 12377, 0, 327},
-  { 12379, 0, 328},
-  { 12381, 0, 329},
-  { 12383, 0, 330},
-  { 12385, 0, 331},
-  { 12388, 0, 332},
-  { 12390, 0, 333},
-  { 12392, 0, 334},
-  { 12399, 0, 335},
-  { 12402, 0, 336},
-  { 12405, 0, 337},
-  { 12408, 0, 338},
-  { 12411, 0, 339},
-  { 12445, 0, 340},
-  { 12454, 0, 341},
-  { 12459, 0, 342},
-  { 12461, 0, 343},
-  { 12463, 0, 344},
-  { 12465, 0, 345},
-  { 12467, 0, 346},
-  { 12469, 0, 347},
-  { 12471, 0, 348},
-  { 12473, 0, 349},
-  { 12475, 0, 350},
-  { 12477, 0, 351},
-  { 12479, 0, 352},
-  { 12481, 0, 353},
-  { 12484, 0, 354},
-  { 12486, 0, 355},
-  { 12488, 0, 356},
-  { 12495, 0, 357},
-  { 12498, 0, 358},
-  { 12501, 0, 359},
-  { 12504, 0, 360},
-  { 12507, 0, 361},
-  { 12527, 3, 362},
-  { 12541, 0, 366},
-  { 69785, 0, 367},
-  { 69787, 0, 368},
-  { 69797, 0, 369},
-  { 69937, 1, 370},
-  { 70471, 0, 372},
-  { 70841, 0, 373},
-  { 71096, 1, 374},
-  {0,0,0}
-};
-
-static const Reindex nfc_last[] = {
-  { 768, 4, 0},
-  { 774, 6, 5},
-  { 783, 0, 12},
-  { 785, 0, 13},
-  { 787, 1, 14},
-  { 795, 0, 16},
-  { 803, 5, 17},
-  { 813, 1, 23},
-  { 816, 1, 25},
-  { 824, 0, 27},
-  { 834, 0, 28},
-  { 837, 0, 29},
-  { 1619, 2, 30},
-  { 2364, 0, 33},
-  { 2494, 0, 34},
-  { 2519, 0, 35},
-  { 2878, 0, 36},
-  { 2902, 1, 37},
-  { 3006, 0, 39},
-  { 3031, 0, 40},
-  { 3158, 0, 41},
-  { 3266, 0, 42},
-  { 3285, 1, 43},
-  { 3390, 0, 45},
-  { 3415, 0, 46},
-  { 3530, 0, 47},
-  { 3535, 0, 48},
-  { 3551, 0, 49},
-  { 4142, 0, 50},
-  { 6965, 0, 51},
-  { 12441, 1, 52},
-  { 69818, 0, 54},
-  { 69927, 0, 55},
-  { 70462, 0, 56},
-  { 70487, 0, 57},
-  { 70832, 0, 58},
-  { 70842, 0, 59},
-  { 70845, 0, 60},
-  { 71087, 0, 61},
-  {0,0,0}
-};
-
-#define UCDN_EAST_ASIAN_F 0
-#define UCDN_EAST_ASIAN_H 1
-#define UCDN_EAST_ASIAN_W 2
-#define UCDN_EAST_ASIAN_NA 3
-#define UCDN_EAST_ASIAN_A 4
-#define UCDN_EAST_ASIAN_N 5
-
-#define UCDN_SCRIPT_COMMON 0
-#define UCDN_SCRIPT_LATIN 1
-#define UCDN_SCRIPT_GREEK 2
-#define UCDN_SCRIPT_CYRILLIC 3
-#define UCDN_SCRIPT_ARMENIAN 4
-#define UCDN_SCRIPT_HEBREW 5
-#define UCDN_SCRIPT_ARABIC 6
-#define UCDN_SCRIPT_SYRIAC 7
-#define UCDN_SCRIPT_THAANA 8
-#define UCDN_SCRIPT_DEVANAGARI 9
-#define UCDN_SCRIPT_BENGALI 10
-#define UCDN_SCRIPT_GURMUKHI 11
-#define UCDN_SCRIPT_GUJARATI 12
-#define UCDN_SCRIPT_ORIYA 13
-#define UCDN_SCRIPT_TAMIL 14
-#define UCDN_SCRIPT_TELUGU 15
-#define UCDN_SCRIPT_KANNADA 16
-#define UCDN_SCRIPT_MALAYALAM 17
-#define UCDN_SCRIPT_SINHALA 18
-#define UCDN_SCRIPT_THAI 19
-#define UCDN_SCRIPT_LAO 20
-#define UCDN_SCRIPT_TIBETAN 21
-#define UCDN_SCRIPT_MYANMAR 22
-#define UCDN_SCRIPT_GEORGIAN 23
-#define UCDN_SCRIPT_HANGUL 24
-#define UCDN_SCRIPT_ETHIOPIC 25
-#define UCDN_SCRIPT_CHEROKEE 26
-#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
-#define UCDN_SCRIPT_OGHAM 28
-#define UCDN_SCRIPT_RUNIC 29
-#define UCDN_SCRIPT_KHMER 30
-#define UCDN_SCRIPT_MONGOLIAN 31
-#define UCDN_SCRIPT_HIRAGANA 32
-#define UCDN_SCRIPT_KATAKANA 33
-#define UCDN_SCRIPT_BOPOMOFO 34
-#define UCDN_SCRIPT_HAN 35
-#define UCDN_SCRIPT_YI 36
-#define UCDN_SCRIPT_OLD_ITALIC 37
-#define UCDN_SCRIPT_GOTHIC 38
-#define UCDN_SCRIPT_DESERET 39
-#define UCDN_SCRIPT_INHERITED 40
-#define UCDN_SCRIPT_TAGALOG 41
-#define UCDN_SCRIPT_HANUNOO 42
-#define UCDN_SCRIPT_BUHID 43
-#define UCDN_SCRIPT_TAGBANWA 44
-#define UCDN_SCRIPT_LIMBU 45
-#define UCDN_SCRIPT_TAI_LE 46
-#define UCDN_SCRIPT_LINEAR_B 47
-#define UCDN_SCRIPT_UGARITIC 48
-#define UCDN_SCRIPT_SHAVIAN 49
-#define UCDN_SCRIPT_OSMANYA 50
-#define UCDN_SCRIPT_CYPRIOT 51
-#define UCDN_SCRIPT_BRAILLE 52
-#define UCDN_SCRIPT_BUGINESE 53
-#define UCDN_SCRIPT_COPTIC 54
-#define UCDN_SCRIPT_NEW_TAI_LUE 55
-#define UCDN_SCRIPT_GLAGOLITIC 56
-#define UCDN_SCRIPT_TIFINAGH 57
-#define UCDN_SCRIPT_SYLOTI_NAGRI 58
-#define UCDN_SCRIPT_OLD_PERSIAN 59
-#define UCDN_SCRIPT_KHAROSHTHI 60
-#define UCDN_SCRIPT_BALINESE 61
-#define UCDN_SCRIPT_CUNEIFORM 62
-#define UCDN_SCRIPT_PHOENICIAN 63
-#define UCDN_SCRIPT_PHAGS_PA 64
-#define UCDN_SCRIPT_NKO 65
-#define UCDN_SCRIPT_SUNDANESE 66
-#define UCDN_SCRIPT_LEPCHA 67
-#define UCDN_SCRIPT_OL_CHIKI 68
-#define UCDN_SCRIPT_VAI 69
-#define UCDN_SCRIPT_SAURASHTRA 70
-#define UCDN_SCRIPT_KAYAH_LI 71
-#define UCDN_SCRIPT_REJANG 72
-#define UCDN_SCRIPT_LYCIAN 73
-#define UCDN_SCRIPT_CARIAN 74
-#define UCDN_SCRIPT_LYDIAN 75
-#define UCDN_SCRIPT_CHAM 76
-#define UCDN_SCRIPT_TAI_THAM 77
-#define UCDN_SCRIPT_TAI_VIET 78
-#define UCDN_SCRIPT_AVESTAN 79
-#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
-#define UCDN_SCRIPT_SAMARITAN 81
-#define UCDN_SCRIPT_LISU 82
-#define UCDN_SCRIPT_BAMUM 83
-#define UCDN_SCRIPT_JAVANESE 84
-#define UCDN_SCRIPT_MEETEI_MAYEK 85
-#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
-#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
-#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
-#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
-#define UCDN_SCRIPT_OLD_TURKIC 90
-#define UCDN_SCRIPT_KAITHI 91
-#define UCDN_SCRIPT_BATAK 92
-#define UCDN_SCRIPT_BRAHMI 93
-#define UCDN_SCRIPT_MANDAIC 94
-#define UCDN_SCRIPT_CHAKMA 95
-#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
-#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
-#define UCDN_SCRIPT_MIAO 98
-#define UCDN_SCRIPT_SHARADA 99
-#define UCDN_SCRIPT_SORA_SOMPENG 100
-#define UCDN_SCRIPT_TAKRI 101
-#define UCDN_SCRIPT_UNKNOWN 102
-#define UCDN_SCRIPT_BASSA_VAH 103
-#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
-#define UCDN_SCRIPT_DUPLOYAN 105
-#define UCDN_SCRIPT_ELBASAN 106
-#define UCDN_SCRIPT_GRANTHA 107
-#define UCDN_SCRIPT_KHOJKI 108
-#define UCDN_SCRIPT_KHUDAWADI 109
-#define UCDN_SCRIPT_LINEAR_A 110
-#define UCDN_SCRIPT_MAHAJANI 111
-#define UCDN_SCRIPT_MANICHAEAN 112
-#define UCDN_SCRIPT_MENDE_KIKAKUI 113
-#define UCDN_SCRIPT_MODI 114
-#define UCDN_SCRIPT_MRO 115
-#define UCDN_SCRIPT_NABATAEAN 116
-#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
-#define UCDN_SCRIPT_OLD_PERMIC 118
-#define UCDN_SCRIPT_PAHAWH_HMONG 119
-#define UCDN_SCRIPT_PALMYRENE 120
-#define UCDN_SCRIPT_PAU_CIN_HAU 121
-#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
-#define UCDN_SCRIPT_SIDDHAM 123
-#define UCDN_SCRIPT_TIRHUTA 124
-#define UCDN_SCRIPT_WARANG_CITI 125
-#define UCDN_SCRIPT_AHOM 126
-#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127
-#define UCDN_SCRIPT_HATRAN 128
-#define UCDN_SCRIPT_MULTANI 129
-#define UCDN_SCRIPT_OLD_HUNGARIAN 130
-#define UCDN_SCRIPT_SIGNWRITING 131
-#define UCDN_SCRIPT_ADLAM 132
-#define UCDN_SCRIPT_BHAIKSUKI 133
-#define UCDN_SCRIPT_MARCHEN 134
-#define UCDN_SCRIPT_NEWA 135
-#define UCDN_SCRIPT_OSAGE 136
-#define UCDN_SCRIPT_TANGUT 137
-#define UCDN_SCRIPT_MASARAM_GONDI 138
-#define UCDN_SCRIPT_NUSHU 139
-#define UCDN_SCRIPT_SOYOMBO 140
-#define UCDN_SCRIPT_ZANABAZAR_SQUARE 141
-#define UCDN_SCRIPT_DOGRA 142
-#define UCDN_SCRIPT_GUNJALA_GONDI 143
-#define UCDN_SCRIPT_HANIFI_ROHINGYA 144
-#define UCDN_SCRIPT_MAKASAR 145
-#define UCDN_SCRIPT_MEDEFAIDRIN 146
-#define UCDN_SCRIPT_OLD_SOGDIAN 147
-#define UCDN_SCRIPT_SOGDIAN 148
-
-#define UCDN_GENERAL_CATEGORY_CC 0
-#define UCDN_GENERAL_CATEGORY_CF 1
-#define UCDN_GENERAL_CATEGORY_CN 2
-#define UCDN_GENERAL_CATEGORY_CO 3
-#define UCDN_GENERAL_CATEGORY_CS 4
-#define UCDN_GENERAL_CATEGORY_LL 5
-#define UCDN_GENERAL_CATEGORY_LM 6
-#define UCDN_GENERAL_CATEGORY_LO 7
-#define UCDN_GENERAL_CATEGORY_LT 8
-#define UCDN_GENERAL_CATEGORY_LU 9
-#define UCDN_GENERAL_CATEGORY_MC 10
-#define UCDN_GENERAL_CATEGORY_ME 11
-#define UCDN_GENERAL_CATEGORY_MN 12
-#define UCDN_GENERAL_CATEGORY_ND 13
-#define UCDN_GENERAL_CATEGORY_NL 14
-#define UCDN_GENERAL_CATEGORY_NO 15
-#define UCDN_GENERAL_CATEGORY_PC 16
-#define UCDN_GENERAL_CATEGORY_PD 17
-#define UCDN_GENERAL_CATEGORY_PE 18
-#define UCDN_GENERAL_CATEGORY_PF 19
-#define UCDN_GENERAL_CATEGORY_PI 20
-#define UCDN_GENERAL_CATEGORY_PO 21
-#define UCDN_GENERAL_CATEGORY_PS 22
-#define UCDN_GENERAL_CATEGORY_SC 23
-#define UCDN_GENERAL_CATEGORY_SK 24
-#define UCDN_GENERAL_CATEGORY_SM 25
-#define UCDN_GENERAL_CATEGORY_SO 26
-#define UCDN_GENERAL_CATEGORY_ZL 27
-#define UCDN_GENERAL_CATEGORY_ZP 28
-#define UCDN_GENERAL_CATEGORY_ZS 29
-
-#define UCDN_BIDI_CLASS_L 0
-#define UCDN_BIDI_CLASS_LRE 1
-#define UCDN_BIDI_CLASS_LRO 2
-#define UCDN_BIDI_CLASS_R 3
-#define UCDN_BIDI_CLASS_AL 4
-#define UCDN_BIDI_CLASS_RLE 5
-#define UCDN_BIDI_CLASS_RLO 6
-#define UCDN_BIDI_CLASS_PDF 7
-#define UCDN_BIDI_CLASS_EN 8
-#define UCDN_BIDI_CLASS_ES 9
-#define UCDN_BIDI_CLASS_ET 10
-#define UCDN_BIDI_CLASS_AN 11
-#define UCDN_BIDI_CLASS_CS 12
-#define UCDN_BIDI_CLASS_NSM 13
-#define UCDN_BIDI_CLASS_BN 14
-#define UCDN_BIDI_CLASS_B 15
-#define UCDN_BIDI_CLASS_S 16
-#define UCDN_BIDI_CLASS_WS 17
-#define UCDN_BIDI_CLASS_ON 18
-#define UCDN_BIDI_CLASS_LRI 19
-#define UCDN_BIDI_CLASS_RLI 20
-#define UCDN_BIDI_CLASS_FSI 21
-#define UCDN_BIDI_CLASS_PDI 22
-
-/* index tables for the database records */
-#define SHIFT1 5
-#define SHIFT2 3
-static const unsigned char index0[] = {
-    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
-    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
-    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 53, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 54, 55, 56, 56, 56, 57,
-    58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 65, 66, 67, 68,
-    69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65,
-    66, 67, 68, 69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, 72, 73, 73, 73,
-    73, 73, 73, 73, 73, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 52, 75, 76, 77, 78, 79,
-    80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
-    98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 106, 108, 109, 110, 106,
-    111, 111, 111, 112, 113, 114, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 115, 115, 116, 117, 118, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 119, 120, 121, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 122, 122, 123, 124, 106, 106, 125, 126, 127, 127, 127, 127,
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
-    127, 127, 127, 127, 127, 128, 127, 127, 129, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 130, 131, 132, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 133, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 134, 135, 136, 137, 138, 139,
-    140, 141, 142, 142, 143, 106, 106, 106, 106, 106, 144, 106, 106, 106,
-    106, 106, 106, 106, 145, 146, 106, 106, 147, 106, 148, 106, 149, 150,
-    151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 160, 160, 160, 161, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 162, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 163, 164, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 165, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
-    166, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 52, 52,
-    168, 167, 167, 167, 167, 169, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 169, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 170, 171, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
-    106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    172, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
-    74, 74, 74, 74, 172,
-};
-
-static const unsigned short index1[] = {
-    0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 0, 0, 0, 14, 15,
-    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 31, 32,
-    33, 34, 35, 27, 30, 29, 27, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
-    47, 48, 27, 27, 49, 27, 27, 27, 27, 27, 27, 27, 50, 51, 52, 27, 53, 54,
-    53, 54, 54, 54, 54, 54, 55, 54, 54, 54, 56, 57, 58, 59, 60, 61, 62, 63,
-    64, 64, 65, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 65, 77, 78,
-    79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
-    97, 97, 97, 97, 98, 98, 98, 98, 99, 100, 101, 101, 101, 101, 102, 103,
-    101, 101, 101, 101, 101, 101, 104, 105, 101, 101, 101, 101, 101, 101,
-    101, 101, 101, 101, 101, 101, 106, 107, 107, 107, 108, 109, 110, 110,
-    110, 110, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 120,
-    120, 121, 122, 119, 123, 124, 125, 126, 127, 127, 127, 127, 128, 129,
-    130, 131, 132, 133, 134, 127, 127, 127, 127, 127, 127, 127, 127, 127,
-    127, 127, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 144,
-    145, 146, 147, 148, 127, 127, 127, 127, 127, 127, 149, 149, 149, 149,
-    150, 151, 152, 119, 153, 154, 155, 155, 155, 156, 157, 158, 159, 159,
-    160, 161, 162, 163, 164, 165, 166, 166, 166, 167, 144, 168, 119, 119,
-    119, 119, 119, 119, 127, 127, 169, 170, 119, 119, 171, 125, 172, 173,
-    174, 175, 176, 177, 177, 177, 177, 177, 177, 178, 179, 180, 181, 177,
-    182, 183, 184, 177, 185, 186, 187, 188, 188, 189, 190, 191, 192, 193,
-    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206,
-    207, 208, 209, 210, 211, 212, 213, 119, 214, 215, 216, 217, 217, 218,
-    219, 220, 221, 222, 223, 119, 224, 225, 226, 227, 228, 229, 230, 231,
-    231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 119, 242, 243,
-    244, 245, 246, 243, 247, 248, 249, 250, 251, 119, 252, 253, 254, 255,
-    256, 257, 258, 259, 259, 258, 259, 260, 261, 262, 263, 264, 265, 266,
-    119, 267, 268, 269, 270, 271, 271, 270, 272, 273, 274, 275, 276, 277,
-    278, 279, 280, 119, 281, 282, 283, 284, 284, 284, 284, 285, 286, 287,
-    288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 295, 295, 298, 299,
-    296, 300, 301, 302, 303, 304, 305, 119, 306, 307, 307, 307, 307, 307,
-    308, 309, 310, 311, 312, 313, 119, 119, 119, 119, 314, 315, 316, 317,
-    318, 319, 320, 321, 322, 323, 324, 325, 119, 119, 119, 119, 326, 327,
-    328, 329, 330, 331, 332, 333, 334, 335, 334, 334, 334, 336, 337, 338,
-    339, 340, 341, 342, 341, 341, 341, 343, 344, 345, 346, 347, 119, 119,
-    119, 119, 348, 348, 348, 348, 348, 349, 350, 351, 352, 353, 354, 355,
-    356, 357, 358, 348, 359, 360, 352, 361, 362, 362, 362, 362, 363, 364,
-    365, 365, 365, 365, 365, 366, 367, 367, 367, 367, 367, 367, 367, 367,
-    367, 367, 367, 367, 368, 368, 368, 368, 368, 368, 368, 368, 368, 369,
-    369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 370, 370, 370, 370,
-    370, 370, 370, 370, 370, 371, 372, 371, 370, 370, 370, 370, 370, 371,
-    370, 370, 370, 370, 371, 372, 371, 370, 372, 370, 370, 370, 370, 370,
-    370, 370, 371, 370, 370, 370, 370, 370, 370, 370, 370, 373, 374, 375,
-    376, 377, 370, 370, 378, 379, 380, 380, 380, 380, 380, 380, 380, 380,
-    380, 380, 381, 382, 383, 384, 384, 384, 384, 384, 384, 384, 384, 384,
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
-    384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 385, 384, 384,
-    386, 387, 387, 388, 389, 389, 389, 389, 389, 389, 389, 389, 389, 390,
-    391, 392, 393, 394, 395, 119, 396, 396, 397, 119, 398, 398, 399, 119,
-    400, 401, 402, 119, 403, 403, 403, 403, 403, 403, 404, 405, 406, 407,
-    408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 418, 418, 418,
-    419, 418, 418, 418, 418, 418, 418, 420, 421, 418, 418, 418, 418, 422,
-    384, 384, 384, 384, 384, 384, 384, 384, 423, 119, 424, 424, 424, 425,
-    426, 427, 428, 429, 430, 431, 432, 432, 432, 433, 434, 119, 435, 435,
-    435, 435, 435, 436, 435, 435, 435, 437, 438, 439, 440, 440, 440, 440,
-    441, 441, 442, 443, 444, 444, 444, 444, 444, 444, 445, 446, 447, 448,
-    449, 450, 451, 452, 451, 452, 453, 454, 455, 456, 119, 119, 119, 119,
-    119, 119, 119, 119, 457, 458, 458, 458, 458, 458, 459, 460, 461, 462,
-    463, 464, 465, 466, 467, 468, 469, 470, 470, 470, 471, 472, 473, 474,
-    475, 475, 475, 475, 476, 477, 478, 479, 480, 480, 480, 480, 481, 482,
-    483, 484, 485, 486, 487, 488, 489, 489, 489, 490, 100, 491, 362, 362,
-    362, 362, 362, 492, 493, 119, 494, 495, 496, 497, 498, 499, 54, 54, 54,
-    54, 500, 501, 56, 56, 56, 56, 56, 502, 503, 504, 54, 505, 54, 54, 54,
-    506, 56, 56, 56, 507, 508, 509, 510, 511, 511, 511, 512, 513, 27, 27, 27,
-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 514, 515, 27,
-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 516, 517, 518, 519, 516, 517,
-    516, 517, 518, 519, 516, 520, 516, 517, 516, 518, 516, 521, 516, 521,
-    516, 521, 522, 523, 524, 525, 526, 527, 516, 528, 529, 530, 531, 532,
-    533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546,
-    547, 548, 56, 549, 550, 551, 552, 553, 554, 554, 555, 556, 557, 558, 559,
-    119, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572,
-    573, 572, 574, 575, 576, 577, 578, 579, 580, 581, 582, 581, 583, 584,
-    581, 585, 581, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 587,
-    596, 597, 587, 598, 599, 587, 587, 599, 587, 600, 601, 600, 587, 587,
-    602, 587, 587, 587, 587, 587, 603, 587, 587, 581, 604, 605, 606, 607,
-    608, 609, 610, 610, 610, 610, 610, 610, 610, 610, 611, 581, 581, 612,
-    613, 587, 587, 614, 581, 581, 581, 581, 586, 607, 615, 616, 581, 581,
-    581, 581, 581, 617, 119, 119, 119, 581, 618, 119, 119, 619, 619, 619,
-    619, 619, 620, 620, 621, 622, 622, 622, 622, 622, 622, 622, 622, 622,
-    623, 619, 624, 625, 625, 625, 625, 625, 625, 625, 625, 625, 626, 625,
-    625, 625, 625, 627, 581, 625, 625, 628, 581, 629, 630, 631, 632, 633,
-    634, 630, 581, 628, 635, 581, 636, 637, 638, 639, 640, 581, 581, 581,
-    641, 642, 643, 644, 581, 645, 646, 581, 647, 581, 581, 648, 649, 650,
-    651, 581, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 581,
-    581, 581, 663, 581, 664, 581, 665, 666, 667, 668, 669, 670, 619, 671,
-    671, 672, 581, 581, 581, 663, 673, 674, 587, 587, 587, 675, 676, 587,
-    587, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677,
-    677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677,
-    677, 677, 677, 677, 677, 587, 587, 587, 587, 587, 587, 587, 587, 587,
-    587, 587, 587, 587, 587, 587, 587, 678, 679, 679, 680, 587, 587, 587,
-    587, 587, 587, 587, 681, 587, 587, 587, 682, 587, 587, 587, 587, 587,
-    587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587,
-    587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 581,
-    581, 581, 683, 581, 581, 587, 587, 684, 685, 686, 630, 581, 581, 687,
-    581, 581, 581, 688, 581, 581, 581, 581, 581, 581, 689, 581, 581, 581,
-    581, 581, 617, 690, 690, 690, 690, 690, 691, 692, 692, 692, 692, 692,
-    693, 694, 695, 696, 697, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
-    698, 699, 700, 701, 365, 365, 365, 365, 702, 703, 704, 704, 704, 704,
-    704, 704, 704, 705, 706, 707, 370, 370, 372, 119, 372, 372, 372, 372,
-    372, 372, 372, 372, 708, 708, 708, 708, 709, 710, 711, 712, 713, 714,
-    715, 716, 717, 718, 119, 119, 119, 119, 119, 119, 719, 719, 719, 720,
-    719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 721, 119, 719, 719,
-    719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719,
-    719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 722, 119, 119, 119,
-    723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 735,
-    736, 735, 735, 735, 737, 738, 739, 740, 741, 742, 743, 743, 744, 743,
-    743, 743, 745, 746, 747, 748, 749, 750, 750, 750, 750, 750, 751, 752,
-    752, 752, 752, 752, 752, 752, 752, 752, 752, 753, 754, 755, 750, 750,
-    750, 756, 723, 723, 723, 723, 724, 119, 757, 757, 758, 758, 758, 759,
-    760, 761, 755, 755, 755, 762, 763, 764, 758, 758, 758, 765, 760, 761,
-    755, 755, 755, 755, 766, 764, 755, 767, 768, 768, 768, 768, 768, 769,
-    768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 755, 755, 755,
-    770, 771, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 772,
-    755, 755, 755, 770, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 774, 775, 581, 581, 581, 581, 581, 581, 581, 581, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    775, 775, 776, 776, 777, 776, 776, 776, 776, 776, 776, 776, 776, 776,
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776,
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776,
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776,
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776,
-    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 778,
-    779, 779, 779, 779, 779, 779, 780, 119, 781, 781, 781, 781, 781, 782,
-    783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783,
-    783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783,
-    783, 783, 783, 783, 783, 784, 783, 783, 785, 786, 119, 119, 101, 101,
-    101, 101, 101, 787, 788, 789, 101, 101, 101, 790, 791, 791, 791, 791,
-    791, 791, 791, 791, 792, 793, 794, 119, 64, 64, 795, 796, 797, 27, 798,
-    27, 27, 27, 27, 27, 27, 27, 799, 800, 27, 801, 802, 27, 27, 803, 804,
-    805, 119, 119, 119, 119, 119, 119, 806, 807, 808, 809, 810, 810, 811,
-    812, 813, 814, 815, 815, 815, 815, 815, 815, 816, 119, 817, 818, 818,
-    818, 818, 818, 819, 820, 821, 822, 823, 824, 825, 825, 826, 827, 828,
-    829, 830, 830, 831, 832, 833, 833, 834, 835, 836, 837, 367, 367, 367,
-    838, 839, 840, 840, 840, 840, 840, 841, 842, 843, 844, 845, 846, 847,
-    348, 352, 848, 849, 849, 849, 849, 849, 850, 851, 119, 852, 853, 854,
-    855, 348, 348, 856, 857, 858, 858, 858, 858, 858, 858, 859, 860, 861,
-    119, 119, 862, 863, 864, 865, 119, 866, 866, 866, 119, 372, 372, 54, 54,
-    54, 54, 54, 867, 868, 119, 869, 869, 869, 869, 869, 869, 869, 869, 869,
-    869, 863, 863, 863, 863, 870, 871, 872, 873, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875,
-    875, 875, 874, 875, 875, 876, 875, 875, 875, 875, 875, 875, 874, 875,
-    875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875,
-    875, 877, 119, 368, 368, 878, 879, 369, 369, 369, 369, 369, 880, 881,
-    881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881,
-    881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881,
-    881, 881, 881, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882,
-    882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882,
-    882, 882, 882, 882, 882, 882, 882, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 774, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 883, 775, 775, 775, 775, 884, 119, 885,
-    886, 120, 887, 888, 889, 890, 120, 127, 127, 127, 127, 127, 127, 127,
-    127, 127, 127, 127, 127, 891, 892, 893, 119, 894, 127, 127, 127, 127,
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 895, 119,
-    119, 127, 127, 127, 127, 127, 127, 127, 127, 896, 127, 127, 127, 127,
-    127, 127, 119, 119, 119, 119, 119, 127, 897, 898, 898, 899, 900, 901,
-    902, 903, 904, 905, 906, 907, 908, 909, 910, 169, 127, 127, 127, 127,
-    127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 911, 912,
-    913, 914, 915, 916, 917, 917, 918, 919, 920, 920, 921, 922, 923, 924,
-    925, 925, 925, 925, 926, 927, 927, 927, 928, 929, 929, 929, 930, 931,
-    932, 119, 933, 934, 935, 934, 934, 936, 934, 934, 937, 934, 938, 934,
-    938, 119, 119, 119, 119, 934, 934, 934, 934, 934, 934, 934, 934, 934,
-    934, 934, 934, 934, 934, 934, 939, 940, 941, 941, 941, 941, 941, 942,
-    610, 943, 943, 943, 943, 943, 943, 944, 945, 946, 947, 581, 948, 949,
-    119, 119, 119, 119, 119, 610, 610, 610, 610, 610, 950, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 951,
-    951, 951, 952, 953, 953, 953, 953, 953, 953, 954, 119, 955, 956, 956,
-    957, 958, 958, 958, 958, 959, 960, 961, 961, 962, 963, 964, 964, 964,
-    964, 965, 966, 967, 967, 967, 968, 969, 969, 969, 969, 970, 969, 971,
-    119, 119, 119, 119, 119, 972, 972, 972, 972, 972, 973, 973, 973, 973,
-    973, 974, 974, 974, 974, 974, 974, 975, 975, 975, 976, 977, 978, 979,
-    979, 979, 979, 980, 981, 981, 981, 981, 982, 983, 983, 983, 983, 983,
-    119, 984, 984, 984, 984, 984, 984, 985, 986, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 987,
-    987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987,
-    987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987,
-    987, 987, 987, 987, 987, 987, 987, 987, 987, 988, 119, 987, 987, 989,
-    119, 987, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 990, 991, 992, 992, 992, 992, 993,
-    994, 995, 995, 996, 997, 998, 998, 999, 1000, 1001, 1001, 1001, 1002,
-    1003, 1004, 119, 119, 119, 119, 119, 119, 1005, 1005, 1006, 1007, 1008,
-    1008, 1009, 1010, 1011, 1011, 1011, 1012, 119, 119, 119, 119, 119, 119,
-    119, 119, 1013, 1013, 1013, 1013, 1014, 1014, 1014, 1015, 1016, 1016,
-    1017, 1016, 1016, 1016, 1016, 1016, 1018, 1019, 1020, 1021, 1022, 1022,
-    1023, 1024, 1025, 1026, 1027, 1028, 1029, 1029, 1029, 1030, 1031, 1031,
-    1031, 1032, 119, 119, 119, 119, 1033, 1034, 1033, 1033, 1035, 1036, 1037,
-    119, 1038, 1038, 1038, 1038, 1038, 1038, 1039, 1040, 1041, 1041, 1042,
-    1043, 1044, 1044, 1045, 1046, 1047, 1047, 1048, 1049, 119, 1050, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 1051, 1051, 1051, 1051,
-    1051, 1051, 1051, 1051, 1051, 1052, 119, 119, 119, 119, 119, 119, 1053,
-    1053, 1053, 1053, 1053, 1053, 1054, 119, 1055, 1055, 1055, 1055, 1055,
-    1055, 1056, 1057, 1058, 1058, 1058, 1058, 1059, 119, 1060, 1061, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 1062, 1062, 1062, 1063, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1064,
-    1064, 1064, 1065, 1066, 119, 1067, 1067, 1068, 1069, 1070, 1071, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 1072, 1073, 1073, 1073, 1073, 1073, 1073, 1074,
-    1075, 1076, 1077, 1078, 1079, 1080, 119, 1081, 1082, 1083, 1083, 1083,
-    1083, 1083, 1084, 1085, 1086, 1087, 1088, 1088, 1088, 1089, 1090, 1091,
-    1092, 1093, 1093, 1093, 1094, 1095, 1096, 1097, 1098, 119, 1099, 1099,
-    1099, 1099, 1100, 119, 1101, 1102, 1102, 1102, 1102, 1102, 1103, 1104,
-    1105, 1106, 1107, 1108, 1109, 1110, 1111, 119, 1112, 1112, 1113, 1112,
-    1112, 1114, 1115, 1116, 119, 119, 119, 119, 119, 119, 119, 119, 1117,
-    1118, 1119, 1120, 1119, 1121, 1122, 1122, 1122, 1122, 1122, 1123, 1124,
-    1125, 1126, 1127, 1128, 1129, 1130, 1131, 1131, 1132, 1133, 1134, 1135,
-    1136, 1137, 1138, 1139, 1140, 1140, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1141, 1141, 1141, 1141,
-    1141, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 119, 119, 119, 119, 1148,
-    1148, 1148, 1148, 1148, 1148, 1149, 1150, 1151, 119, 1152, 1153, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 1154, 1154, 1154, 1154, 1154, 1155, 1156, 1157,
-    1158, 1159, 1160, 1161, 119, 119, 119, 119, 1162, 1162, 1162, 1162, 1162,
-    1162, 1163, 1164, 1165, 119, 1166, 1167, 1168, 1169, 119, 119, 1170,
-    1170, 1170, 1170, 1170, 1171, 1172, 119, 1173, 1174, 119, 119, 119, 119,
-    119, 119, 1175, 1175, 1175, 1176, 1177, 1178, 1179, 1180, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 1181, 1181, 1181, 1181, 1181, 1182,
-    1183, 1184, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    1185, 1185, 1185, 1185, 1186, 1186, 1186, 1186, 1187, 1188, 1189, 1190,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 1191, 1192, 1193, 1193, 1193, 1193, 1194, 1195, 1196,
-    119, 1197, 1198, 1199, 1199, 1199, 1199, 1200, 1201, 1202, 1203, 1204,
-    119, 119, 119, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1206, 1207,
-    1208, 1207, 1207, 1207, 1209, 1210, 1211, 1212, 119, 1213, 1214, 1215,
-    1216, 1217, 1218, 1218, 1218, 1219, 1220, 1220, 1221, 1222, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 1223, 1224, 1225, 1225, 1225, 1225,
-    1226, 1227, 1228, 119, 1229, 1230, 1231, 1232, 1233, 1233, 1233, 1234,
-    1235, 1236, 1237, 1238, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    1239, 1239, 1240, 1241, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1243, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 1244, 1244, 1244, 1244, 1244, 1244,
-    1244, 1244, 1244, 1244, 1244, 1244, 1244, 1245, 1246, 119, 1242, 1242,
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
-    1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1247, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 1248, 1248, 1248, 1248, 1248,
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248,
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248,
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248,
-    1248, 1248, 1249, 1248, 1248, 1248, 1248, 1250, 1251, 1248, 1248, 1248,
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248,
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248,
-    1248, 1248, 1252, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248,
-    1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248,
-    1253, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1254,
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1255, 1254, 1254, 1254,
-    1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1256,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 791, 791, 791, 791, 791,
-    791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791,
-    791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791,
-    791, 791, 791, 791, 791, 791, 1257, 1258, 1258, 1258, 1259, 1260, 1261,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1262, 1262,
-    1262, 1263, 1264, 119, 1265, 1265, 1265, 1265, 1265, 1265, 1266, 1267,
-    1268, 119, 1269, 1270, 1271, 1265, 1265, 1272, 1265, 1265, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 1273, 1273, 1273, 1273, 1274, 1274, 1274, 1274,
-    1275, 1275, 1276, 1277, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1279, 119,
-    1280, 1281, 1281, 1281, 1281, 1282, 119, 1283, 1284, 1285, 119, 119, 119,
-    119, 119, 119, 119, 119, 1286, 119, 119, 119, 1287, 1287, 1287, 1287,
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1288, 119,
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
-    1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
-    1287, 1287, 1287, 1287, 1287, 1287, 1289, 119, 1290, 735, 735, 735, 735,
-    735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735,
-    735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735,
-    735, 735, 1291, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1292,
-    1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292,
-    1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292,
-    1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292,
-    1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292,
-    1293, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294,
-    1294, 1294, 1295, 1294, 1296, 1294, 1297, 1294, 1298, 1299, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 610, 610, 610, 610, 610,
-    610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610,
-    610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 1300, 119, 610,
-    610, 610, 610, 1301, 1302, 610, 610, 610, 610, 610, 610, 1303, 1304,
-    1305, 1306, 1307, 1308, 610, 610, 610, 1309, 610, 610, 610, 610, 610,
-    610, 610, 1310, 119, 119, 946, 946, 946, 946, 946, 946, 946, 946, 1311,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 941, 941, 1312, 119, 581, 581, 581, 581, 581,
-    581, 581, 581, 581, 581, 617, 119, 941, 941, 941, 1313, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1314,
-    1314, 1314, 1315, 1316, 1316, 1317, 1314, 1314, 1318, 1319, 1316, 1316,
-    1314, 1314, 1314, 1315, 1316, 1316, 1320, 1321, 1322, 1318, 1323, 1324,
-    1316, 1314, 1314, 1314, 1315, 1316, 1316, 1325, 1326, 1327, 1328, 1316,
-    1316, 1316, 1329, 1330, 1331, 1332, 1316, 1316, 1317, 1314, 1314, 1318,
-    1316, 1316, 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1317, 1314, 1314,
-    1318, 1316, 1316, 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1317, 1314,
-    1314, 1318, 1316, 1316, 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1333,
-    1314, 1314, 1314, 1334, 1316, 1316, 1335, 1336, 1314, 1314, 1337, 1316,
-    1316, 1338, 1317, 1314, 1314, 1339, 1316, 1316, 1340, 1341, 1314, 1314,
-    1342, 1316, 1316, 1316, 1343, 1314, 1314, 1314, 1334, 1316, 1316, 1335,
-    1344, 1345, 1345, 1345, 1345, 1345, 1345, 1346, 1346, 1346, 1346, 1346,
-    1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346,
-    1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346,
-    1346, 1346, 1346, 1347, 1347, 1347, 1347, 1347, 1347, 1348, 1349, 1347,
-    1347, 1347, 1347, 1347, 1350, 1351, 1346, 1352, 1353, 119, 1354, 1355,
-    1347, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1356, 1357, 1357,
-    1358, 1359, 1360, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
-    1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361,
-    1361, 1362, 1363, 1364, 119, 119, 119, 119, 119, 1365, 1365, 1365, 1365,
-    1366, 1367, 1367, 1367, 1368, 1369, 1370, 1371, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 1372, 1373, 1373, 1373, 1373, 1373, 1373, 1374, 1375, 119, 119, 119,
-    119, 119, 119, 119, 119, 119, 1376, 127, 127, 127, 1377, 1378, 1379,
-    1380, 1381, 1382, 1377, 1383, 1377, 1379, 1379, 1384, 127, 1385, 127,
-    1386, 1387, 1385, 127, 1386, 119, 119, 119, 119, 119, 119, 1388, 119,
-    1389, 1390, 1390, 1390, 1390, 1391, 1390, 1390, 1390, 1390, 1390, 1390,
-    1390, 1390, 1390, 1390, 1390, 1390, 1391, 1392, 1390, 1393, 1394, 1390,
-    1394, 1395, 1394, 1390, 1390, 1390, 1396, 1392, 620, 1397, 622, 622, 622,
-    1398, 622, 622, 622, 622, 622, 622, 622, 1399, 622, 622, 622, 1400, 1401,
-    1402, 622, 1403, 1392, 1392, 1392, 1392, 1392, 1392, 1404, 1405, 1405,
-    1405, 1406, 1392, 755, 755, 755, 755, 755, 1407, 755, 1408, 1409, 1392,
-    1410, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392,
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 723, 723, 723, 723, 1411,
-    1412, 1413, 723, 723, 723, 723, 723, 723, 723, 723, 1414, 1415, 723,
-    1416, 1417, 723, 723, 1418, 1419, 1420, 1421, 1416, 1390, 723, 723, 1422,
-    1423, 723, 723, 723, 723, 723, 723, 723, 1424, 1425, 1426, 1427, 723,
-    1428, 1429, 1426, 1430, 1431, 723, 723, 723, 1432, 1433, 1434, 723, 723,
-    723, 723, 723, 723, 723, 723, 1435, 1436, 723, 1437, 643, 1438, 723,
-    1439, 1440, 581, 1441, 723, 723, 723, 1390, 1442, 1443, 1390, 1390, 1444,
-    1390, 1389, 1390, 1390, 1390, 1390, 1390, 1445, 1446, 1390, 1390, 1445,
-    1447, 723, 723, 723, 723, 723, 723, 723, 723, 1448, 1449, 581, 581, 581,
-    581, 1450, 1451, 723, 723, 723, 723, 1452, 723, 1453, 723, 1454, 1455,
-    1456, 1392, 1390, 1457, 1458, 1459, 581, 581, 581, 581, 581, 581, 581,
-    581, 581, 581, 581, 581, 581, 581, 1460, 1392, 581, 581, 581, 581, 581,
-    581, 581, 581, 581, 581, 1461, 1462, 1392, 1392, 1392, 1392, 581, 1460,
-    581, 581, 581, 581, 581, 581, 581, 1392, 581, 1463, 581, 581, 581, 581,
-    581, 1392, 581, 581, 581, 1464, 1392, 1392, 1392, 1392, 1392, 1392, 1392,
-    1392, 1392, 1392, 581, 1460, 723, 1465, 1466, 723, 1426, 1467, 723, 723,
-    723, 723, 723, 723, 1468, 1469, 723, 723, 723, 723, 1470, 1392, 1471,
-    1472, 1470, 1392, 1473, 1474, 723, 723, 723, 723, 1392, 1392, 1392, 1392,
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1390, 1396, 1392, 1392,
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392,
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392,
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392,
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392,
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392,
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392,
-    1392, 1392, 1392, 1392, 1392, 1392, 1392, 1475, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 1476, 775, 775, 775, 775, 775, 773,
-    773, 773, 773, 773, 773, 1477, 775, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 774, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 883,
-    775, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
-    773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 1478, 775, 775,
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775,
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775,
-    775, 775, 775, 775, 775, 773, 773, 773, 774, 775, 775, 775, 775, 775,
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775,
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775,
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775,
-    775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 1479, 1480,
-    119, 119, 119, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
-    1481, 1481, 1481, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
-    119, 119, 119, 119, 119, 898, 898, 898, 898, 898, 898, 898, 898, 898,
-    898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898,
-    898, 898, 898, 898, 898, 898, 898, 119, 119, 882, 882, 882, 882, 882,
-    882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882,
-    882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 1482,
-};
-
-static const unsigned short index2[] = {
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 1, 1, 1, 1, 1, 1, 7, 7, 7, 8,
-    9, 10, 11, 12, 13, 14, 15, 11, 16, 17, 15, 18, 19, 20, 19, 21, 22, 22,
-    22, 22, 22, 22, 22, 22, 22, 22, 19, 23, 24, 24, 24, 10, 15, 25, 25, 25,
-    25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 16, 26, 17,
-    27, 28, 27, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
-    29, 29, 29, 16, 30, 31, 24, 1, 1, 1, 1, 1, 1, 32, 1, 1, 33, 34, 35, 13,
-    36, 13, 37, 38, 39, 40, 41, 42, 24, 43, 44, 27, 45, 46, 47, 47, 48, 49,
-    38, 38, 39, 47, 41, 50, 51, 51, 51, 34, 52, 52, 52, 52, 52, 52, 53, 52,
-    52, 52, 52, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 52, 54, 53, 52,
-    52, 52, 52, 52, 53, 55, 55, 55, 56, 56, 56, 56, 55, 56, 55, 55, 55, 56,
-    55, 55, 56, 56, 55, 56, 55, 55, 56, 56, 56, 54, 55, 55, 55, 56, 55, 56,
-    55, 56, 52, 55, 52, 56, 52, 56, 52, 56, 52, 56, 52, 56, 52, 56, 52, 56,
-    52, 55, 52, 55, 52, 56, 52, 56, 52, 56, 52, 55, 52, 56, 52, 56, 52, 56,
-    52, 56, 52, 56, 53, 55, 52, 55, 53, 55, 52, 56, 52, 56, 55, 52, 56, 52,
-    56, 52, 56, 53, 55, 53, 55, 52, 55, 52, 56, 52, 55, 55, 53, 55, 52, 55,
-    52, 56, 52, 56, 53, 55, 52, 56, 52, 56, 52, 52, 56, 52, 56, 52, 56, 56,
-    56, 52, 52, 56, 52, 56, 52, 52, 56, 52, 52, 52, 56, 56, 52, 52, 52, 52,
-    56, 52, 52, 56, 52, 52, 52, 56, 56, 56, 52, 52, 56, 52, 52, 56, 52, 56,
-    52, 56, 52, 52, 56, 52, 56, 56, 52, 56, 52, 52, 56, 52, 52, 52, 56, 52,
-    56, 52, 52, 56, 56, 57, 52, 56, 56, 56, 57, 57, 57, 57, 52, 58, 56, 52,
-    58, 56, 52, 58, 56, 52, 55, 52, 55, 52, 55, 52, 55, 52, 55, 52, 55, 52,
-    55, 52, 55, 56, 52, 56, 56, 52, 58, 56, 52, 56, 52, 52, 52, 56, 52, 56,
-    56, 56, 56, 56, 56, 56, 52, 52, 56, 52, 52, 56, 56, 52, 56, 52, 52, 52,
-    52, 56, 56, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-    56, 56, 56, 56, 57, 56, 56, 56, 59, 59, 59, 59, 59, 59, 59, 59, 59, 60,
-    60, 61, 61, 61, 61, 61, 61, 61, 62, 62, 63, 62, 60, 64, 65, 64, 64, 64,
-    65, 64, 60, 60, 66, 61, 62, 62, 62, 62, 62, 62, 39, 39, 39, 39, 62, 39,
-    62, 48, 59, 59, 59, 59, 59, 62, 62, 62, 62, 62, 67, 67, 60, 62, 61, 62,
-    62, 62, 62, 62, 62, 62, 62, 62, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
-    68, 68, 68, 69, 70, 70, 70, 70, 69, 71, 70, 70, 70, 70, 70, 72, 72, 70,
-    70, 70, 70, 72, 72, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 73, 73,
-    73, 73, 73, 70, 70, 70, 70, 68, 68, 68, 68, 68, 68, 68, 68, 74, 68, 70,
-    70, 70, 68, 68, 68, 70, 70, 75, 68, 68, 68, 70, 70, 70, 70, 68, 69, 70,
-    70, 68, 76, 77, 77, 76, 77, 77, 76, 68, 68, 68, 68, 68, 78, 79, 78, 79,
-    60, 80, 78, 79, 81, 81, 82, 79, 79, 79, 83, 78, 81, 81, 81, 81, 80, 62,
-    78, 84, 78, 78, 78, 81, 78, 81, 78, 78, 79, 85, 85, 85, 85, 85, 85, 85,
-    85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 81, 85, 85, 85, 85, 85, 85, 85,
-    78, 78, 79, 79, 79, 79, 79, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-    86, 86, 86, 86, 86, 86, 79, 86, 86, 86, 86, 86, 86, 86, 79, 79, 79, 79,
-    79, 78, 79, 79, 78, 78, 78, 79, 79, 79, 78, 79, 78, 79, 78, 79, 78, 79,
-    78, 79, 87, 88, 87, 88, 87, 88, 87, 88, 87, 88, 87, 88, 87, 88, 79, 79,
-    79, 79, 78, 79, 89, 78, 79, 78, 78, 79, 79, 78, 78, 78, 90, 91, 90, 90,
-    90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91,
-    91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 93, 92, 93, 93, 93, 93, 93, 93,
-    93, 93, 93, 93, 93, 93, 93, 93, 90, 93, 90, 93, 90, 93, 90, 93, 90, 93,
-    94, 95, 95, 96, 96, 95, 97, 97, 90, 93, 90, 93, 90, 93, 90, 90, 93, 90,
-    93, 90, 93, 90, 93, 90, 93, 90, 93, 90, 93, 93, 81, 98, 98, 98, 98, 98,
-    98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 81,
-    81, 99, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101,
-    101, 101, 102, 103, 81, 81, 104, 104, 105, 81, 106, 107, 107, 107, 107,
-    106, 107, 107, 107, 108, 106, 107, 107, 107, 107, 107, 107, 106, 106,
-    106, 106, 106, 106, 107, 107, 106, 107, 107, 108, 109, 107, 110, 111,
-    112, 113, 114, 115, 116, 117, 118, 119, 119, 120, 121, 122, 123, 124,
-    125, 126, 127, 125, 107, 106, 128, 118, 81, 81, 81, 81, 81, 81, 81, 81,
-    129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 81, 81, 81, 81,
-    129, 129, 129, 129, 125, 125, 81, 81, 81, 130, 130, 130, 130, 130, 131,
-    132, 132, 133, 134, 134, 135, 136, 137, 138, 138, 139, 139, 139, 139,
-    139, 139, 139, 139, 140, 141, 142, 143, 144, 81, 145, 143, 146, 146, 146,
-    146, 146, 146, 146, 146, 147, 146, 146, 146, 146, 146, 146, 146, 146,
-    146, 146, 148, 149, 150, 151, 152, 153, 154, 155, 96, 96, 156, 157, 139,
-    139, 139, 139, 139, 157, 139, 139, 157, 158, 158, 158, 158, 158, 158,
-    158, 158, 158, 158, 134, 159, 159, 160, 146, 146, 161, 146, 146, 146,
-    146, 146, 146, 146, 146, 146, 146, 146, 145, 146, 139, 139, 139, 139,
-    139, 139, 139, 131, 138, 139, 139, 139, 139, 157, 139, 162, 162, 139,
-    139, 138, 157, 139, 139, 157, 146, 146, 163, 163, 163, 163, 163, 163,
-    163, 163, 163, 163, 146, 146, 146, 164, 164, 146, 165, 165, 165, 165,
-    165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 81, 166, 167, 168, 167,
-    167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 169,
-    170, 169, 169, 170, 169, 169, 170, 170, 170, 169, 170, 170, 169, 170,
-    169, 169, 169, 170, 169, 170, 169, 170, 169, 170, 169, 169, 81, 81, 167,
-    167, 167, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
-    171, 171, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 171, 81,
-    81, 81, 81, 81, 81, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
-    174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174,
-    174, 174, 174, 175, 175, 175, 175, 175, 175, 175, 176, 175, 177, 177,
-    178, 179, 180, 181, 177, 81, 81, 176, 182, 182, 183, 183, 183, 183, 183,
-    183, 183, 183, 183, 183, 183, 183, 183, 183, 184, 184, 184, 184, 185,
-    184, 184, 184, 184, 184, 184, 184, 184, 184, 185, 184, 184, 184, 185,
-    184, 184, 184, 184, 184, 81, 81, 186, 186, 186, 186, 186, 186, 186, 186,
-    186, 186, 186, 186, 186, 186, 186, 81, 187, 187, 187, 187, 187, 187, 187,
-    187, 187, 188, 188, 188, 81, 81, 189, 81, 167, 167, 167, 81, 81, 81, 81,
-    81, 146, 146, 146, 146, 146, 81, 146, 146, 146, 146, 146, 146, 146, 146,
-    81, 81, 81, 81, 81, 157, 139, 139, 139, 139, 139, 139, 131, 157, 139,
-    139, 157, 139, 139, 157, 139, 139, 139, 157, 157, 157, 190, 191, 192,
-    139, 139, 139, 157, 139, 139, 157, 157, 139, 139, 139, 139, 139, 193,
-    193, 193, 194, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195,
-    195, 195, 195, 193, 194, 196, 195, 194, 194, 194, 193, 193, 193, 193,
-    193, 193, 193, 193, 194, 194, 194, 194, 197, 194, 194, 195, 96, 156, 198,
-    198, 193, 193, 193, 195, 195, 193, 193, 199, 199, 200, 200, 200, 200,
-    200, 200, 200, 200, 200, 200, 201, 202, 195, 195, 195, 195, 195, 195,
-    203, 204, 205, 205, 81, 203, 203, 203, 203, 203, 203, 203, 203, 81, 81,
-    203, 203, 81, 81, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
-    203, 203, 203, 81, 203, 203, 203, 203, 203, 203, 203, 81, 203, 81, 81,
-    81, 203, 203, 203, 203, 81, 81, 206, 203, 205, 205, 205, 204, 204, 204,
-    204, 81, 81, 205, 205, 81, 81, 205, 205, 207, 203, 81, 81, 81, 81, 81,
-    81, 81, 81, 205, 81, 81, 81, 81, 203, 203, 81, 203, 203, 203, 204, 204,
-    81, 81, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 203, 203, 209,
-    209, 210, 210, 210, 210, 210, 211, 212, 213, 203, 214, 215, 81, 81, 216,
-    216, 217, 81, 218, 218, 218, 218, 218, 218, 81, 81, 81, 81, 218, 218, 81,
-    81, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
-    81, 218, 218, 218, 218, 218, 218, 218, 81, 218, 218, 81, 218, 218, 81,
-    218, 218, 81, 81, 219, 81, 217, 217, 217, 216, 216, 81, 81, 81, 81, 216,
-    216, 81, 81, 216, 216, 220, 81, 81, 81, 216, 81, 81, 81, 81, 81, 81, 81,
-    218, 218, 218, 218, 81, 218, 81, 81, 81, 81, 81, 81, 81, 221, 221, 221,
-    221, 221, 221, 221, 221, 221, 221, 216, 216, 218, 218, 218, 216, 222, 81,
-    81, 223, 223, 224, 81, 225, 225, 225, 225, 225, 225, 225, 225, 225, 81,
-    225, 225, 225, 81, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225,
-    225, 225, 225, 81, 225, 225, 225, 225, 225, 225, 225, 81, 225, 225, 81,
-    225, 225, 225, 225, 225, 81, 81, 226, 225, 224, 224, 224, 223, 223, 223,
-    223, 223, 81, 223, 223, 224, 81, 224, 224, 227, 81, 81, 225, 81, 81, 81,
-    81, 81, 81, 81, 225, 225, 223, 223, 81, 81, 228, 228, 228, 228, 228, 228,
-    228, 228, 228, 228, 229, 230, 81, 81, 81, 81, 81, 81, 81, 225, 223, 223,
-    223, 223, 223, 223, 81, 231, 232, 232, 81, 233, 233, 233, 233, 233, 233,
-    233, 233, 81, 81, 233, 233, 81, 81, 233, 233, 233, 233, 233, 233, 233,
-    233, 233, 233, 233, 233, 233, 233, 81, 233, 233, 233, 233, 233, 233, 233,
-    81, 233, 233, 81, 233, 233, 233, 233, 233, 81, 81, 234, 233, 232, 231,
-    232, 231, 231, 231, 231, 81, 81, 232, 232, 81, 81, 232, 232, 235, 81, 81,
-    81, 81, 81, 81, 81, 81, 231, 232, 81, 81, 81, 81, 233, 233, 81, 233, 233,
-    233, 231, 231, 81, 81, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
-    237, 233, 238, 238, 238, 238, 238, 238, 81, 81, 239, 240, 81, 240, 240,
-    240, 240, 240, 240, 81, 81, 81, 240, 240, 240, 81, 240, 240, 240, 240,
-    81, 81, 81, 240, 240, 81, 240, 81, 240, 240, 81, 81, 81, 240, 240, 81,
-    81, 81, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 81, 81, 81, 81,
-    241, 241, 239, 241, 241, 81, 81, 81, 241, 241, 241, 81, 241, 241, 241,
-    242, 81, 81, 240, 81, 81, 81, 81, 81, 81, 241, 81, 81, 81, 81, 81, 81,
-    243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 244, 244, 244, 245,
-    245, 245, 245, 245, 245, 246, 245, 81, 81, 81, 81, 81, 247, 248, 248,
-    248, 247, 249, 249, 249, 249, 249, 249, 249, 249, 81, 249, 249, 249, 81,
-    249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249,
-    249, 249, 81, 81, 81, 249, 247, 247, 247, 248, 248, 248, 248, 81, 247,
-    247, 247, 81, 247, 247, 247, 250, 81, 81, 81, 81, 81, 81, 81, 251, 252,
-    81, 249, 249, 249, 81, 81, 81, 81, 81, 249, 249, 247, 247, 81, 81, 253,
-    253, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254,
-    254, 254, 255, 256, 257, 258, 258, 259, 256, 256, 256, 256, 256, 256,
-    256, 256, 81, 256, 256, 256, 81, 256, 256, 256, 256, 256, 256, 256, 256,
-    256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 81, 256, 256, 256, 256,
-    256, 81, 81, 260, 256, 258, 261, 258, 258, 258, 258, 258, 81, 261, 258,
-    258, 81, 258, 258, 257, 262, 81, 81, 81, 81, 81, 81, 81, 258, 258, 81,
-    81, 81, 81, 81, 81, 81, 256, 81, 256, 256, 257, 257, 81, 81, 263, 263,
-    263, 263, 263, 263, 263, 263, 263, 263, 81, 256, 256, 81, 81, 81, 81, 81,
-    264, 264, 265, 265, 81, 266, 266, 266, 266, 266, 266, 266, 266, 81, 266,
-    266, 266, 81, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266,
-    266, 266, 266, 266, 266, 267, 267, 266, 265, 265, 265, 264, 264, 264,
-    264, 81, 265, 265, 265, 81, 265, 265, 265, 267, 266, 268, 81, 81, 81, 81,
-    266, 266, 266, 265, 269, 269, 269, 269, 269, 269, 269, 266, 266, 266,
-    264, 264, 81, 81, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 269,
-    269, 269, 269, 269, 269, 269, 269, 269, 271, 266, 266, 266, 266, 266,
-    266, 81, 81, 272, 272, 81, 273, 273, 273, 273, 273, 273, 273, 273, 273,
-    273, 273, 273, 273, 273, 273, 273, 273, 273, 81, 81, 81, 273, 273, 273,
-    273, 273, 273, 273, 273, 81, 273, 273, 273, 273, 273, 273, 273, 273, 273,
-    81, 273, 81, 81, 81, 81, 274, 81, 81, 81, 81, 272, 272, 272, 275, 275,
-    275, 81, 275, 81, 272, 272, 272, 272, 272, 272, 272, 272, 81, 81, 81, 81,
-    81, 81, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 81, 81, 272,
-    272, 277, 81, 81, 81, 81, 278, 278, 278, 278, 278, 278, 278, 278, 278,
-    278, 278, 278, 278, 278, 278, 278, 279, 278, 278, 279, 279, 279, 279,
-    280, 280, 281, 81, 81, 81, 81, 282, 278, 278, 278, 278, 278, 278, 283,
-    279, 284, 284, 284, 284, 279, 279, 279, 285, 286, 286, 286, 286, 286,
-    286, 286, 286, 286, 286, 287, 287, 81, 81, 81, 81, 81, 288, 288, 81, 288,
-    81, 81, 288, 288, 81, 288, 81, 81, 288, 81, 81, 81, 81, 81, 81, 288, 288,
-    288, 288, 81, 288, 288, 288, 288, 288, 288, 288, 81, 288, 288, 288, 81,
-    288, 81, 288, 81, 81, 288, 288, 81, 288, 288, 288, 288, 289, 288, 288,
-    289, 289, 289, 289, 290, 290, 81, 289, 289, 288, 81, 81, 288, 288, 288,
-    288, 288, 81, 291, 81, 292, 292, 292, 292, 289, 289, 81, 81, 293, 293,
-    293, 293, 293, 293, 293, 293, 293, 293, 81, 81, 288, 288, 288, 288, 294,
-    295, 295, 295, 296, 297, 296, 296, 298, 296, 296, 299, 298, 300, 300,
-    300, 300, 300, 298, 301, 300, 301, 301, 301, 302, 302, 301, 301, 301,
-    301, 301, 301, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304,
-    304, 304, 304, 304, 304, 304, 304, 304, 304, 305, 302, 301, 302, 301,
-    306, 307, 308, 307, 308, 309, 309, 294, 294, 294, 294, 294, 294, 294,
-    294, 81, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 81,
-    81, 81, 81, 310, 311, 312, 313, 312, 312, 312, 312, 312, 311, 311, 311,
-    311, 312, 314, 311, 312, 315, 315, 316, 299, 315, 315, 294, 294, 294,
-    294, 294, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 81, 312,
-    312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 81, 305, 305, 301,
-    301, 301, 301, 301, 301, 302, 301, 301, 301, 301, 301, 301, 81, 301, 301,
-    296, 296, 299, 296, 297, 317, 317, 317, 317, 298, 298, 81, 81, 81, 81,
-    81, 318, 318, 318, 318, 318, 318, 318, 318, 318, 318, 318, 319, 319, 320,
-    320, 320, 320, 319, 320, 320, 320, 320, 320, 321, 319, 322, 322, 319,
-    319, 320, 320, 318, 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
-    324, 324, 325, 325, 325, 325, 318, 318, 318, 318, 318, 318, 319, 319,
-    320, 320, 318, 318, 318, 318, 320, 320, 320, 318, 319, 319, 319, 318,
-    318, 319, 319, 319, 319, 319, 319, 319, 318, 318, 318, 320, 320, 320,
-    320, 318, 318, 318, 318, 318, 320, 319, 319, 320, 320, 319, 319, 319,
-    319, 319, 319, 326, 318, 319, 323, 323, 319, 319, 319, 320, 327, 327,
-    328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 81,
-    328, 81, 81, 81, 81, 81, 328, 81, 81, 329, 329, 329, 329, 329, 329, 329,
-    329, 329, 329, 329, 330, 331, 329, 329, 329, 332, 332, 332, 332, 332,
-    332, 332, 332, 333, 333, 333, 333, 333, 333, 333, 333, 334, 334, 334,
-    334, 334, 334, 334, 334, 335, 335, 335, 335, 335, 335, 335, 335, 335, 81,
-    335, 335, 335, 335, 81, 81, 335, 335, 335, 335, 335, 335, 335, 81, 335,
-    335, 335, 81, 81, 336, 336, 336, 337, 338, 337, 337, 337, 337, 337, 337,
-    337, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339,
-    339, 339, 339, 339, 339, 339, 339, 81, 81, 81, 340, 340, 340, 340, 340,
-    340, 340, 340, 340, 340, 81, 81, 81, 81, 81, 81, 341, 341, 341, 341, 341,
-    341, 341, 341, 341, 341, 341, 341, 341, 341, 81, 81, 342, 342, 342, 342,
-    342, 342, 81, 81, 343, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344,
-    344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 345, 345, 344, 346,
-    347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347,
-    347, 347, 347, 347, 348, 349, 81, 81, 81, 350, 350, 350, 350, 350, 350,
-    350, 350, 350, 350, 350, 199, 199, 199, 351, 351, 351, 350, 350, 350,
-    350, 350, 350, 350, 350, 81, 81, 81, 81, 81, 81, 81, 352, 352, 352, 352,
-    352, 352, 352, 352, 352, 352, 352, 352, 352, 81, 352, 352, 352, 352, 353,
-    353, 354, 81, 81, 81, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355,
-    356, 356, 357, 199, 199, 81, 358, 358, 358, 358, 358, 358, 358, 358, 358,
-    358, 359, 359, 81, 81, 81, 81, 360, 360, 360, 360, 360, 360, 360, 360,
-    360, 360, 360, 360, 360, 81, 360, 360, 360, 81, 361, 361, 81, 81, 81, 81,
-    362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 363, 363,
-    364, 363, 363, 363, 363, 363, 363, 363, 364, 364, 364, 364, 364, 364,
-    364, 364, 363, 364, 364, 363, 363, 363, 363, 363, 363, 363, 363, 363,
-    365, 363, 366, 366, 367, 368, 366, 369, 366, 370, 362, 371, 81, 81, 372,
-    372, 372, 372, 372, 372, 372, 372, 372, 372, 81, 81, 81, 81, 81, 81, 373,
-    373, 373, 373, 373, 373, 373, 373, 373, 373, 81, 81, 81, 81, 81, 81, 374,
-    374, 375, 375, 376, 377, 378, 374, 379, 379, 374, 380, 380, 380, 381, 81,
-    382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 81, 81, 81, 81, 81, 81,
-    383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384, 383, 383,
-    383, 383, 383, 81, 81, 81, 81, 81, 81, 81, 383, 383, 383, 383, 383, 380,
-    380, 383, 383, 385, 383, 81, 81, 81, 81, 81, 344, 344, 344, 344, 344,
-    344, 81, 81, 386, 386, 386, 386, 386, 386, 386, 386, 386, 386, 386, 386,
-    386, 386, 386, 81, 387, 387, 387, 388, 388, 388, 388, 387, 387, 388, 388,
-    388, 81, 81, 81, 81, 388, 388, 387, 388, 388, 388, 388, 388, 388, 389,
-    390, 391, 81, 81, 81, 81, 392, 81, 81, 81, 393, 393, 394, 394, 394, 394,
-    394, 394, 394, 394, 394, 394, 395, 395, 395, 395, 395, 395, 395, 395,
-    395, 395, 395, 395, 395, 395, 81, 81, 395, 395, 395, 395, 395, 81, 81,
-    81, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 81, 81,
-    81, 81, 396, 396, 81, 81, 81, 81, 81, 81, 397, 397, 397, 397, 397, 397,
-    397, 397, 397, 397, 398, 81, 81, 81, 399, 399, 400, 400, 400, 400, 400,
-    400, 400, 400, 401, 401, 401, 401, 401, 401, 401, 401, 401, 401, 401,
-    401, 401, 401, 401, 402, 403, 404, 404, 405, 81, 81, 406, 406, 407, 407,
-    407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 408, 409, 408,
-    409, 409, 409, 409, 409, 409, 409, 81, 410, 408, 409, 408, 408, 409, 409,
-    409, 409, 409, 409, 409, 409, 408, 408, 408, 408, 408, 408, 409, 409,
-    411, 411, 411, 411, 411, 411, 411, 411, 81, 81, 412, 413, 413, 413, 413,
-    413, 413, 413, 413, 413, 413, 81, 81, 81, 81, 81, 81, 414, 414, 414, 414,
-    414, 414, 414, 415, 414, 414, 414, 414, 414, 414, 81, 81, 96, 96, 96, 96,
-    96, 156, 156, 156, 156, 156, 156, 96, 96, 156, 416, 81, 417, 417, 417,
-    417, 418, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419,
-    419, 419, 419, 420, 418, 417, 417, 417, 417, 417, 418, 417, 418, 418,
-    418, 418, 418, 417, 418, 421, 419, 419, 419, 419, 419, 419, 419, 81, 81,
-    81, 81, 422, 422, 422, 422, 422, 422, 422, 422, 422, 422, 423, 423, 424,
-    423, 423, 423, 423, 425, 425, 425, 425, 425, 425, 425, 425, 425, 425,
-    426, 427, 426, 426, 426, 426, 426, 426, 426, 425, 425, 425, 425, 425,
-    425, 425, 425, 425, 81, 81, 81, 428, 428, 429, 430, 430, 430, 430, 430,
-    430, 430, 430, 430, 430, 430, 430, 430, 430, 429, 428, 428, 428, 428,
-    429, 429, 428, 428, 431, 432, 428, 428, 430, 430, 433, 433, 433, 433,
-    433, 433, 433, 433, 433, 433, 430, 430, 430, 430, 430, 430, 434, 434,
-    434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 435, 436,
-    437, 437, 436, 436, 436, 437, 436, 437, 437, 437, 438, 438, 81, 81, 81,
-    81, 81, 81, 81, 81, 439, 439, 439, 439, 440, 440, 440, 440, 440, 440,
-    440, 440, 440, 440, 440, 440, 441, 441, 441, 441, 441, 441, 441, 441,
-    442, 442, 442, 442, 442, 442, 442, 442, 441, 441, 442, 443, 81, 81, 81,
-    444, 444, 444, 444, 444, 445, 445, 445, 445, 445, 445, 445, 445, 445,
-    445, 81, 81, 81, 440, 440, 440, 446, 446, 446, 446, 446, 446, 446, 446,
-    446, 446, 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 447,
-    447, 447, 448, 448, 448, 448, 448, 448, 449, 449, 93, 81, 81, 81, 81, 81,
-    81, 81, 328, 328, 328, 81, 81, 328, 328, 328, 450, 450, 450, 450, 450,
-    450, 450, 450, 96, 96, 96, 330, 451, 156, 156, 156, 156, 156, 96, 96,
-    156, 156, 156, 156, 96, 452, 451, 451, 451, 451, 451, 451, 451, 453, 453,
-    453, 453, 156, 453, 453, 453, 453, 452, 452, 96, 453, 453, 452, 96, 96,
-    81, 81, 81, 81, 81, 81, 56, 56, 56, 56, 56, 56, 79, 79, 79, 79, 79, 93,
-    59, 59, 59, 59, 59, 59, 59, 59, 59, 82, 82, 82, 82, 82, 59, 59, 59, 59,
-    82, 82, 82, 82, 82, 56, 56, 56, 56, 56, 454, 56, 56, 56, 56, 56, 56, 56,
-    56, 56, 56, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 82, 96, 96,
-    156, 96, 96, 96, 96, 96, 96, 96, 156, 96, 96, 455, 456, 156, 457, 96, 96,
-    96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-    96, 458, 459, 459, 156, 81, 96, 460, 156, 96, 156, 52, 56, 52, 56, 52,
-    56, 56, 56, 56, 56, 56, 56, 56, 56, 52, 56, 79, 79, 79, 79, 79, 79, 79,
-    79, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 81, 81, 78,
-    78, 78, 78, 78, 78, 81, 81, 81, 78, 81, 78, 81, 78, 81, 78, 461, 461,
-    461, 461, 461, 461, 461, 461, 79, 79, 79, 79, 79, 81, 79, 79, 78, 78, 78,
-    78, 461, 80, 79, 80, 80, 80, 79, 79, 79, 81, 79, 79, 78, 78, 78, 78, 461,
-    80, 80, 80, 79, 79, 79, 79, 81, 81, 79, 79, 78, 78, 78, 78, 81, 80, 80,
-    80, 78, 78, 78, 78, 78, 80, 80, 80, 81, 81, 79, 79, 79, 81, 79, 79, 78,
-    78, 78, 78, 461, 462, 80, 81, 463, 463, 463, 463, 463, 463, 463, 464,
-    463, 463, 463, 465, 466, 467, 468, 469, 470, 471, 472, 470, 473, 474, 38,
-    84, 475, 476, 477, 42, 475, 476, 477, 42, 38, 38, 478, 84, 479, 479, 479,
-    480, 481, 482, 483, 484, 485, 486, 487, 33, 488, 489, 488, 488, 489, 490,
-    491, 491, 84, 42, 50, 38, 492, 492, 478, 493, 493, 84, 84, 84, 494, 477,
-    495, 492, 492, 492, 84, 84, 84, 84, 84, 84, 84, 84, 496, 84, 493, 84,
-    377, 84, 377, 377, 377, 377, 84, 377, 377, 463, 497, 498, 498, 498, 498,
-    81, 499, 500, 501, 502, 503, 503, 503, 503, 503, 503, 504, 59, 81, 81,
-    47, 504, 504, 504, 504, 504, 505, 505, 496, 477, 495, 506, 504, 47, 47,
-    47, 47, 504, 504, 504, 504, 504, 505, 505, 496, 477, 495, 81, 59, 59, 59,
-    59, 59, 81, 81, 81, 282, 282, 282, 282, 282, 282, 282, 507, 282, 508,
-    282, 282, 36, 282, 282, 282, 282, 282, 282, 282, 282, 282, 507, 282, 282,
-    282, 282, 507, 282, 282, 507, 282, 509, 509, 509, 509, 509, 509, 509,
-    509, 96, 96, 451, 451, 96, 96, 96, 96, 451, 451, 451, 96, 96, 416, 416,
-    416, 416, 96, 416, 416, 416, 451, 451, 96, 156, 96, 451, 451, 156, 156,
-    156, 156, 96, 81, 81, 81, 81, 81, 81, 81, 40, 40, 510, 511, 40, 512, 40,
-    510, 40, 511, 49, 510, 510, 510, 49, 49, 510, 510, 510, 513, 40, 510,
-    514, 40, 496, 510, 510, 510, 510, 510, 40, 40, 40, 512, 512, 40, 510, 40,
-    85, 40, 510, 40, 52, 515, 510, 510, 516, 49, 510, 510, 52, 510, 49, 453,
-    453, 453, 453, 49, 40, 40, 49, 49, 510, 510, 496, 496, 496, 496, 496,
-    510, 49, 49, 49, 49, 40, 496, 40, 40, 56, 317, 517, 517, 517, 518, 51,
-    519, 517, 517, 517, 517, 517, 51, 518, 518, 51, 517, 520, 520, 520, 520,
-    520, 520, 520, 520, 520, 520, 520, 520, 521, 521, 521, 521, 520, 520,
-    521, 521, 521, 521, 521, 521, 521, 521, 521, 52, 56, 521, 521, 521, 521,
-    51, 40, 40, 81, 81, 81, 81, 54, 54, 54, 54, 54, 512, 512, 512, 512, 512,
-    496, 496, 40, 40, 40, 40, 496, 40, 40, 496, 40, 40, 496, 40, 40, 40, 40,
-    40, 40, 40, 496, 40, 40, 40, 40, 40, 40, 40, 40, 40, 44, 44, 40, 40, 40,
-    40, 40, 40, 40, 40, 40, 40, 40, 40, 496, 496, 40, 40, 54, 40, 54, 40, 40,
-    40, 40, 40, 40, 40, 40, 40, 40, 44, 40, 40, 40, 40, 496, 496, 496, 496,
-    496, 496, 496, 496, 496, 496, 496, 496, 54, 496, 54, 54, 496, 496, 496,
-    54, 54, 496, 496, 54, 496, 496, 496, 54, 496, 54, 522, 523, 496, 54, 496,
-    496, 496, 496, 54, 496, 496, 54, 54, 54, 54, 496, 496, 54, 496, 54, 496,
-    54, 54, 54, 54, 54, 54, 496, 54, 496, 496, 496, 496, 496, 54, 54, 54, 54,
-    496, 496, 496, 496, 54, 54, 496, 496, 54, 496, 496, 496, 54, 496, 496,
-    496, 496, 496, 54, 496, 496, 496, 496, 496, 54, 54, 496, 496, 54, 54, 54,
-    54, 496, 496, 54, 54, 496, 496, 54, 54, 496, 496, 496, 496, 496, 54, 496,
-    496, 496, 54, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496,
-    496, 54, 496, 496, 496, 496, 496, 496, 496, 524, 477, 495, 477, 495, 40,
-    40, 40, 40, 40, 40, 512, 40, 40, 40, 40, 40, 40, 40, 525, 525, 40, 40,
-    40, 40, 496, 496, 40, 40, 40, 40, 40, 40, 40, 526, 527, 40, 40, 40, 40,
-    40, 40, 40, 40, 40, 40, 40, 317, 317, 317, 317, 317, 317, 317, 317, 317,
-    317, 317, 317, 317, 40, 496, 40, 40, 40, 40, 40, 40, 40, 40, 317, 40, 40,
-    40, 40, 40, 496, 496, 496, 496, 496, 496, 496, 496, 496, 40, 40, 40, 40,
-    40, 528, 528, 528, 528, 40, 40, 40, 525, 529, 529, 525, 40, 40, 40, 40,
-    40, 40, 40, 40, 40, 40, 40, 81, 40, 40, 40, 81, 81, 81, 81, 81, 51, 51,
-    51, 51, 51, 51, 51, 51, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
-    530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530,
-    519, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 518, 512, 512, 512,
-    512, 512, 512, 512, 512, 512, 512, 512, 512, 40, 40, 40, 40, 512, 512,
-    512, 512, 531, 40, 40, 40, 40, 40, 512, 512, 512, 512, 40, 40, 512, 512,
-    40, 512, 512, 512, 512, 512, 512, 512, 40, 40, 40, 40, 40, 40, 40, 40,
-    512, 512, 40, 40, 512, 54, 40, 40, 40, 40, 512, 512, 40, 40, 512, 54, 40,
-    40, 40, 40, 512, 512, 512, 40, 40, 512, 40, 40, 512, 512, 40, 40, 40, 40,
-    40, 40, 40, 512, 496, 496, 496, 496, 496, 532, 532, 496, 529, 529, 529,
-    529, 40, 512, 512, 40, 40, 512, 40, 40, 40, 40, 512, 512, 40, 40, 40, 40,
-    525, 525, 531, 531, 529, 40, 529, 529, 533, 534, 533, 529, 40, 529, 529,
-    529, 40, 40, 40, 40, 512, 40, 512, 40, 40, 40, 40, 40, 528, 528, 528,
-    528, 528, 528, 528, 528, 528, 528, 528, 528, 40, 40, 40, 40, 512, 512,
-    40, 512, 512, 512, 40, 512, 533, 512, 512, 40, 512, 512, 40, 54, 40, 40,
-    40, 40, 40, 40, 40, 525, 40, 40, 40, 528, 40, 40, 40, 40, 40, 40, 40, 40,
-    40, 40, 512, 512, 40, 528, 40, 40, 40, 40, 40, 40, 40, 40, 528, 528, 317,
-    40, 40, 40, 40, 40, 40, 40, 40, 525, 525, 533, 529, 529, 529, 529, 525,
-    525, 533, 533, 533, 512, 512, 512, 512, 533, 528, 533, 533, 533, 512,
-    533, 525, 512, 512, 512, 533, 533, 512, 512, 533, 512, 512, 533, 533,
-    533, 40, 512, 40, 40, 40, 40, 512, 512, 525, 512, 512, 512, 512, 512,
-    512, 533, 525, 525, 533, 525, 512, 533, 533, 535, 525, 512, 512, 525,
-    533, 533, 529, 529, 529, 529, 529, 528, 40, 40, 529, 529, 536, 536, 534,
-    534, 40, 40, 528, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 44, 40,
-    40, 40, 40, 40, 40, 528, 40, 528, 40, 40, 40, 40, 528, 528, 528, 40, 537,
-    40, 40, 40, 538, 538, 538, 538, 538, 538, 40, 539, 539, 529, 40, 40, 40,
-    477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 51,
-    51, 519, 519, 519, 519, 519, 519, 519, 519, 519, 519, 519, 519, 40, 528,
-    528, 528, 40, 40, 40, 40, 40, 40, 40, 528, 496, 496, 496, 496, 496, 477,
-    495, 496, 496, 496, 496, 496, 496, 496, 16, 31, 16, 31, 16, 31, 16, 31,
-    477, 495, 540, 540, 540, 540, 540, 540, 540, 540, 496, 496, 496, 477,
-    495, 16, 31, 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 496, 496,
-    496, 496, 496, 496, 496, 477, 495, 477, 495, 496, 496, 496, 496, 496,
-    496, 496, 496, 477, 495, 496, 496, 40, 40, 40, 528, 528, 40, 40, 40, 496,
-    496, 496, 496, 496, 40, 40, 496, 496, 496, 496, 496, 496, 40, 40, 40,
-    528, 40, 40, 40, 40, 537, 512, 512, 40, 40, 40, 40, 81, 81, 40, 40, 40,
-    40, 40, 40, 40, 40, 81, 81, 40, 81, 40, 40, 40, 40, 40, 40, 541, 541,
-    541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 81, 542,
-    542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 81,
-    52, 56, 52, 52, 52, 56, 56, 52, 56, 52, 56, 52, 56, 52, 52, 52, 52, 56,
-    52, 56, 56, 52, 56, 56, 56, 56, 56, 56, 59, 59, 52, 52, 87, 88, 87, 88,
-    88, 543, 543, 543, 543, 543, 543, 87, 88, 87, 88, 544, 544, 544, 87, 88,
-    81, 81, 81, 81, 81, 545, 546, 546, 546, 547, 545, 546, 329, 329, 329,
-    329, 329, 329, 81, 329, 81, 81, 81, 81, 81, 329, 81, 81, 548, 548, 548,
-    548, 548, 548, 548, 548, 81, 81, 81, 81, 81, 81, 81, 549, 550, 81, 81,
-    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 551, 95, 95, 95, 95, 95,
-    95, 95, 95, 552, 552, 42, 50, 42, 50, 552, 552, 552, 42, 50, 552, 42, 50,
-    377, 377, 377, 377, 377, 377, 377, 377, 84, 472, 553, 377, 554, 84, 42,
-    50, 84, 84, 42, 50, 477, 495, 477, 495, 477, 495, 477, 495, 377, 377,
-    377, 377, 375, 60, 377, 377, 84, 377, 377, 84, 84, 84, 84, 84, 555, 555,
-    377, 377, 377, 84, 472, 377, 477, 377, 377, 377, 377, 377, 377, 377, 377,
-    84, 377, 84, 377, 81, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556,
-    81, 556, 556, 556, 556, 556, 556, 556, 556, 556, 81, 81, 81, 81, 556,
-    556, 556, 556, 556, 556, 81, 81, 525, 525, 525, 525, 525, 525, 525, 525,
-    525, 525, 525, 525, 81, 81, 81, 81, 557, 558, 558, 559, 525, 560, 561,
-    562, 526, 527, 526, 527, 526, 527, 526, 527, 526, 527, 525, 525, 526,
-    527, 526, 527, 526, 527, 526, 527, 563, 526, 527, 527, 525, 562, 562,
-    562, 562, 562, 562, 562, 562, 562, 564, 565, 566, 567, 568, 568, 569,
-    570, 570, 570, 570, 571, 525, 525, 562, 562, 562, 560, 572, 559, 525,
-    529, 81, 573, 574, 573, 574, 573, 574, 573, 574, 573, 574, 574, 574, 574,
-    574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 573,
-    574, 574, 574, 574, 574, 574, 574, 573, 574, 573, 574, 573, 574, 574,
-    574, 574, 574, 574, 573, 574, 574, 574, 574, 574, 574, 573, 573, 81, 81,
-    575, 575, 576, 576, 577, 577, 574, 563, 578, 579, 578, 579, 578, 579,
-    578, 579, 578, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579,
-    579, 579, 579, 579, 579, 579, 578, 579, 579, 579, 579, 579, 579, 579,
-    578, 579, 578, 579, 578, 579, 579, 579, 579, 579, 579, 578, 579, 579,
-    579, 579, 579, 579, 578, 578, 579, 579, 579, 579, 580, 581, 582, 582,
-    579, 81, 81, 81, 81, 81, 583, 583, 583, 583, 583, 583, 583, 583, 583,
-    583, 583, 81, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584,
-    584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 81, 585, 585, 586, 586,
-    586, 586, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 583, 583,
-    583, 81, 81, 81, 81, 81, 578, 578, 578, 578, 578, 578, 578, 578, 587,
-    587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 588, 588, 81,
-    586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 585, 585, 585, 585,
-    585, 585, 589, 589, 589, 589, 589, 589, 589, 589, 525, 590, 590, 590,
-    590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 587, 587,
-    587, 587, 588, 588, 588, 585, 585, 590, 590, 590, 590, 590, 590, 590,
-    585, 585, 585, 585, 525, 525, 525, 525, 591, 591, 591, 591, 591, 591,
-    591, 591, 591, 591, 591, 591, 591, 591, 591, 81, 585, 585, 585, 585, 585,
-    585, 585, 525, 525, 525, 525, 585, 585, 585, 585, 585, 585, 585, 585,
-    585, 585, 585, 525, 525, 592, 592, 592, 592, 592, 592, 592, 592, 592,
-    592, 592, 592, 592, 592, 593, 593, 593, 593, 593, 593, 593, 593, 593,
-    593, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594,
-    595, 594, 594, 594, 594, 594, 594, 594, 81, 81, 81, 596, 596, 596, 596,
-    596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 81, 597, 597, 597,
-    597, 597, 597, 597, 597, 598, 598, 598, 598, 598, 598, 599, 599, 600,
-    600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 601, 602, 603,
-    602, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 600, 600, 81, 81,
-    81, 81, 90, 93, 90, 93, 90, 93, 605, 95, 97, 97, 97, 606, 95, 95, 95, 95,
-    95, 95, 95, 95, 95, 95, 606, 607, 90, 93, 90, 93, 454, 454, 95, 95, 608,
-    608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 609,
-    609, 609, 609, 609, 609, 609, 609, 609, 609, 610, 610, 611, 612, 612,
-    612, 612, 612, 62, 62, 62, 62, 62, 62, 62, 60, 60, 60, 60, 60, 60, 60,
-    60, 60, 62, 62, 52, 56, 52, 56, 52, 56, 56, 56, 52, 56, 52, 56, 52, 56,
-    59, 56, 56, 56, 56, 56, 56, 56, 56, 52, 56, 52, 56, 52, 52, 56, 60, 613,
-    613, 52, 56, 52, 56, 57, 52, 56, 52, 56, 56, 56, 52, 56, 52, 56, 52, 52,
-    52, 52, 52, 56, 52, 52, 52, 52, 52, 56, 52, 56, 52, 56, 81, 81, 81, 81,
-    81, 81, 81, 81, 81, 81, 81, 81, 81, 57, 59, 59, 56, 57, 57, 57, 57, 57,
-    614, 614, 615, 614, 614, 614, 616, 614, 614, 614, 614, 615, 614, 614,
-    614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 617,
-    617, 615, 615, 617, 618, 618, 618, 618, 81, 81, 81, 81, 619, 619, 619,
-    619, 619, 619, 317, 317, 507, 516, 81, 81, 81, 81, 81, 81, 620, 620, 620,
-    620, 620, 620, 620, 620, 620, 620, 620, 620, 621, 621, 622, 622, 623,
-    623, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624,
-    624, 624, 624, 624, 624, 623, 623, 623, 623, 623, 623, 623, 623, 623,
-    623, 623, 623, 623, 623, 623, 623, 625, 626, 81, 81, 81, 81, 81, 81, 81,
-    81, 627, 627, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 81, 81,
-    81, 81, 81, 81, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 195,
-    195, 195, 195, 195, 195, 201, 201, 201, 195, 629, 195, 195, 193, 630,
-    630, 630, 630, 630, 630, 630, 630, 630, 630, 631, 631, 631, 631, 631,
-    631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631,
-    631, 632, 632, 632, 632, 632, 633, 633, 633, 199, 634, 635, 635, 635,
-    635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 636, 636,
-    636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 638, 81, 81, 81, 81,
-    81, 81, 81, 81, 81, 81, 81, 639, 332, 332, 332, 332, 332, 81, 81, 81,
-    640, 640, 640, 641, 642, 642, 642, 642, 642, 642, 642, 642, 642, 642,
-    642, 642, 642, 642, 642, 643, 641, 641, 640, 640, 640, 640, 641, 641,
-    640, 641, 641, 641, 644, 645, 645, 645, 645, 645, 645, 646, 646, 646,
-    645, 645, 645, 645, 81, 61, 647, 647, 647, 647, 647, 647, 647, 647, 647,
-    647, 81, 81, 81, 81, 645, 645, 318, 318, 318, 318, 318, 320, 648, 318,
-    323, 323, 318, 318, 318, 318, 318, 81, 649, 649, 649, 649, 649, 649, 649,
-    649, 649, 650, 650, 650, 650, 650, 650, 651, 651, 650, 650, 651, 651,
-    650, 650, 81, 649, 649, 649, 650, 649, 649, 649, 649, 649, 649, 649, 649,
-    650, 651, 81, 81, 652, 652, 652, 652, 652, 652, 652, 652, 652, 652, 81,
-    81, 653, 654, 654, 654, 648, 318, 318, 318, 318, 318, 318, 327, 327, 327,
-    318, 319, 320, 319, 318, 318, 655, 655, 655, 655, 655, 655, 655, 655,
-    656, 655, 656, 656, 657, 655, 655, 656, 656, 655, 655, 655, 655, 655,
-    656, 656, 655, 656, 655, 81, 81, 81, 81, 81, 81, 81, 81, 655, 655, 658,
-    659, 659, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 661,
-    662, 662, 661, 661, 663, 663, 660, 664, 664, 661, 665, 81, 81, 335, 335,
-    335, 335, 335, 335, 81, 56, 56, 56, 613, 59, 59, 59, 59, 56, 56, 56, 56,
-    56, 79, 81, 81, 342, 342, 342, 342, 342, 342, 342, 342, 660, 660, 660,
-    661, 661, 662, 661, 661, 662, 661, 661, 663, 661, 665, 81, 81, 666, 666,
-    666, 666, 666, 666, 666, 666, 666, 666, 81, 81, 81, 81, 81, 81, 667, 668,
-    668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668,
-    668, 668, 668, 668, 667, 668, 668, 668, 668, 668, 668, 668, 81, 81, 81,
-    81, 333, 333, 333, 333, 333, 333, 333, 81, 81, 81, 81, 334, 334, 334,
-    334, 334, 334, 334, 334, 334, 81, 81, 81, 81, 669, 669, 669, 669, 669,
-    669, 669, 669, 670, 670, 670, 670, 670, 670, 670, 670, 592, 592, 593,
-    593, 593, 593, 593, 593, 56, 56, 56, 56, 56, 56, 56, 81, 81, 81, 81, 101,
-    101, 101, 101, 101, 81, 81, 81, 81, 81, 129, 671, 129, 129, 672, 129,
-    129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 81, 129, 129,
-    129, 129, 129, 81, 129, 81, 129, 129, 81, 129, 129, 81, 129, 129, 146,
-    146, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673,
-    673, 673, 673, 81, 81, 81, 81, 81, 81, 81, 81, 81, 146, 146, 146, 146,
-    146, 146, 146, 146, 146, 146, 146, 495, 477, 81, 81, 146, 146, 146, 146,
-    146, 146, 146, 146, 146, 146, 135, 138, 81, 81, 674, 674, 674, 674, 674,
-    674, 674, 674, 675, 558, 558, 675, 675, 676, 676, 526, 527, 677, 81, 81,
-    81, 81, 81, 81, 96, 96, 96, 96, 96, 96, 96, 156, 156, 156, 156, 156, 156,
-    156, 95, 95, 559, 569, 569, 678, 678, 526, 527, 526, 527, 526, 527, 526,
-    527, 526, 527, 526, 527, 526, 527, 526, 527, 559, 559, 526, 527, 559,
-    559, 559, 559, 678, 678, 678, 679, 559, 679, 81, 580, 680, 676, 676, 569,
-    526, 527, 526, 527, 526, 527, 681, 559, 559, 682, 683, 684, 684, 684, 81,
-    559, 685, 686, 559, 81, 81, 81, 81, 146, 146, 146, 146, 146, 81, 81, 497,
-    81, 687, 688, 689, 690, 691, 688, 688, 692, 693, 688, 694, 695, 696, 695,
-    697, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 699, 700, 701,
-    701, 701, 687, 688, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702,
-    702, 702, 702, 702, 702, 702, 702, 702, 692, 688, 693, 703, 704, 703,
-    705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705,
-    705, 705, 705, 705, 692, 701, 693, 701, 692, 693, 706, 707, 708, 706,
-    709, 710, 711, 711, 711, 711, 711, 711, 711, 711, 711, 712, 710, 710,
-    710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710,
-    710, 710, 710, 710, 710, 713, 713, 714, 714, 714, 714, 714, 714, 714,
-    714, 714, 714, 714, 714, 714, 714, 714, 81, 81, 81, 714, 714, 714, 714,
-    714, 714, 81, 81, 714, 714, 714, 81, 81, 81, 715, 690, 701, 703, 716,
-    690, 690, 81, 717, 718, 718, 718, 718, 717, 717, 81, 81, 719, 719, 719,
-    720, 512, 81, 81, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721,
-    721, 81, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 81, 721, 721,
-    721, 81, 721, 721, 81, 721, 721, 721, 721, 721, 721, 721, 81, 81, 721,
-    721, 721, 81, 81, 81, 81, 81, 199, 377, 199, 81, 81, 81, 81, 619, 619,
-    619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 81, 81, 81, 317,
-    722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 723,
-    723, 723, 723, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724,
-    724, 724, 724, 724, 724, 724, 723, 723, 724, 725, 725, 81, 40, 40, 40,
-    40, 81, 81, 81, 81, 724, 81, 81, 81, 81, 81, 81, 81, 317, 317, 317, 317,
-    317, 156, 81, 81, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726,
-    726, 726, 81, 81, 81, 727, 727, 727, 727, 727, 727, 727, 727, 727, 81,
-    81, 81, 81, 81, 81, 81, 156, 504, 504, 504, 504, 504, 504, 504, 504, 504,
-    504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 81, 81, 81, 81, 728,
-    728, 728, 728, 728, 728, 728, 728, 729, 729, 729, 729, 81, 81, 81, 81,
-    81, 81, 81, 81, 81, 728, 728, 728, 730, 730, 730, 730, 730, 730, 730,
-    730, 730, 731, 730, 730, 730, 730, 730, 730, 730, 730, 731, 81, 81, 81,
-    81, 81, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732,
-    732, 733, 733, 733, 733, 733, 81, 81, 81, 81, 81, 734, 734, 734, 734,
-    734, 734, 734, 734, 734, 734, 734, 734, 734, 734, 81, 735, 736, 736, 736,
-    736, 736, 736, 736, 736, 736, 736, 736, 736, 81, 81, 81, 81, 737, 738,
-    738, 738, 738, 738, 81, 81, 739, 739, 739, 739, 739, 739, 739, 739, 740,
-    740, 740, 740, 740, 740, 740, 740, 741, 741, 741, 741, 741, 741, 741,
-    741, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742,
-    742, 81, 81, 743, 743, 743, 743, 743, 743, 743, 743, 743, 743, 81, 81,
-    81, 81, 81, 81, 744, 744, 744, 744, 744, 744, 744, 744, 744, 744, 744,
-    744, 81, 81, 81, 81, 745, 745, 745, 745, 745, 745, 745, 745, 745, 745,
-    745, 745, 81, 81, 81, 81, 746, 746, 746, 746, 746, 746, 746, 746, 747,
-    747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 81, 81, 81, 81,
-    81, 81, 81, 81, 81, 81, 81, 748, 749, 749, 749, 749, 749, 749, 749, 749,
-    749, 749, 749, 749, 749, 749, 749, 81, 749, 749, 749, 749, 749, 749, 81,
-    81, 750, 750, 750, 750, 750, 750, 81, 81, 750, 81, 750, 750, 750, 750,
-    750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750,
-    750, 750, 81, 750, 750, 81, 81, 81, 750, 81, 81, 750, 751, 751, 751, 751,
-    751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 81, 752, 753, 753, 753,
-    753, 753, 753, 753, 753, 754, 754, 754, 754, 754, 754, 754, 754, 754,
-    754, 754, 754, 754, 754, 754, 755, 755, 756, 756, 756, 756, 756, 756,
-    756, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
-    757, 757, 81, 81, 81, 81, 81, 81, 81, 81, 758, 758, 758, 758, 758, 758,
-    758, 758, 758, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 81,
-    759, 759, 81, 81, 81, 81, 81, 760, 760, 760, 760, 760, 761, 761, 761,
-    761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 762, 762, 762,
-    762, 762, 762, 81, 81, 81, 763, 764, 764, 764, 764, 764, 764, 764, 764,
-    764, 764, 81, 81, 81, 81, 81, 765, 766, 766, 766, 766, 766, 766, 766,
-    766, 767, 767, 767, 767, 767, 767, 767, 767, 81, 81, 81, 81, 768, 768,
-    767, 767, 768, 768, 768, 768, 768, 768, 768, 768, 81, 81, 768, 768, 768,
-    768, 768, 768, 769, 770, 770, 770, 81, 770, 770, 81, 81, 81, 81, 81, 770,
-    771, 770, 772, 769, 769, 769, 769, 81, 769, 769, 769, 81, 769, 769, 769,
-    769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769,
-    769, 769, 769, 769, 81, 81, 772, 773, 771, 81, 81, 81, 81, 774, 775, 775,
-    775, 775, 775, 775, 775, 775, 775, 81, 81, 81, 81, 81, 81, 81, 776, 776,
-    776, 776, 776, 776, 776, 776, 777, 81, 81, 81, 81, 81, 81, 81, 778, 778,
-    778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 779, 779, 780,
-    781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 782,
-    782, 782, 783, 783, 783, 783, 783, 783, 783, 783, 784, 783, 783, 783,
-    783, 783, 783, 783, 783, 783, 783, 783, 783, 785, 786, 81, 81, 81, 81,
-    787, 787, 787, 787, 787, 788, 788, 788, 788, 788, 788, 789, 81, 790, 790,
-    790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 81, 81, 81,
-    791, 791, 791, 791, 791, 791, 791, 792, 792, 792, 792, 792, 792, 792,
-    792, 792, 792, 792, 792, 792, 792, 81, 81, 793, 793, 793, 793, 793, 793,
-    793, 793, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 81, 81,
-    81, 81, 81, 795, 795, 795, 795, 795, 795, 795, 795, 796, 796, 796, 796,
-    796, 796, 796, 796, 796, 796, 81, 81, 81, 81, 81, 81, 81, 797, 797, 797,
-    797, 81, 81, 81, 81, 798, 798, 798, 798, 798, 798, 798, 799, 799, 799,
-    799, 799, 799, 799, 799, 799, 81, 81, 81, 81, 81, 81, 81, 800, 800, 800,
-    800, 800, 800, 800, 800, 800, 800, 800, 81, 81, 81, 81, 81, 801, 801,
-    801, 801, 801, 801, 801, 801, 801, 801, 801, 81, 81, 81, 81, 81, 81, 81,
-    802, 802, 802, 802, 802, 802, 803, 803, 803, 803, 803, 803, 803, 803,
-    803, 803, 803, 803, 804, 804, 804, 804, 805, 805, 805, 805, 805, 805,
-    805, 805, 805, 805, 81, 81, 81, 81, 81, 81, 806, 806, 806, 806, 806, 806,
-    806, 806, 806, 806, 806, 806, 806, 806, 806, 81, 807, 807, 807, 807, 807,
-    807, 807, 807, 807, 807, 807, 807, 807, 808, 808, 808, 808, 808, 808,
-    808, 808, 808, 808, 807, 809, 809, 809, 809, 809, 809, 809, 809, 809,
-    809, 809, 809, 809, 809, 810, 810, 811, 811, 811, 810, 811, 810, 810,
-    810, 810, 812, 812, 812, 812, 813, 813, 813, 813, 813, 81, 81, 81, 81,
-    81, 81, 814, 815, 814, 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
-    816, 816, 816, 815, 815, 815, 815, 815, 815, 815, 815, 815, 815, 815,
-    815, 815, 815, 817, 818, 818, 819, 819, 819, 819, 819, 81, 81, 81, 81,
-    820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820,
-    820, 820, 820, 820, 820, 820, 821, 821, 821, 821, 821, 821, 821, 821,
-    821, 821, 81, 81, 81, 81, 81, 81, 81, 817, 822, 822, 823, 824, 824, 824,
-    824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 823, 823, 823, 822,
-    822, 822, 822, 823, 823, 825, 826, 827, 827, 828, 829, 829, 829, 829, 81,
-    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 828, 81, 81, 830, 830, 830, 830,
-    830, 830, 830, 830, 830, 81, 81, 81, 81, 81, 81, 81, 831, 831, 831, 831,
-    831, 831, 831, 831, 831, 831, 81, 81, 81, 81, 81, 81, 832, 832, 832, 833,
-    833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833,
-    833, 833, 833, 833, 833, 834, 834, 834, 834, 834, 835, 834, 834, 834,
-    834, 834, 834, 836, 836, 81, 837, 837, 837, 837, 837, 837, 837, 837, 837,
-    837, 838, 838, 838, 838, 833, 835, 835, 81, 839, 839, 839, 839, 839, 839,
-    839, 839, 839, 839, 839, 840, 841, 842, 839, 81, 843, 843, 844, 845, 845,
-    845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845,
-    844, 844, 844, 843, 843, 843, 843, 843, 843, 843, 843, 843, 844, 846,
-    845, 845, 845, 845, 847, 847, 848, 847, 843, 849, 843, 843, 848, 81, 81,
-    850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 845, 851, 845, 847,
-    847, 847, 81, 852, 852, 852, 852, 852, 852, 852, 852, 852, 852, 852, 852,
-    852, 852, 852, 852, 852, 852, 852, 852, 81, 81, 81, 853, 853, 853, 853,
-    853, 853, 853, 853, 853, 853, 81, 853, 853, 853, 853, 853, 853, 853, 853,
-    853, 854, 854, 854, 855, 855, 855, 854, 854, 855, 856, 857, 855, 858,
-    858, 859, 858, 858, 859, 855, 81, 860, 860, 860, 860, 860, 860, 860, 81,
-    860, 81, 860, 860, 860, 860, 81, 860, 860, 860, 860, 860, 860, 860, 860,
-    860, 860, 860, 860, 860, 860, 860, 81, 860, 860, 861, 81, 81, 81, 81, 81,
-    81, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862,
-    862, 863, 864, 864, 864, 863, 863, 863, 863, 863, 863, 865, 866, 81, 81,
-    81, 81, 81, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 81, 81, 81,
-    81, 81, 81, 868, 868, 869, 869, 81, 870, 870, 870, 870, 870, 870, 870,
-    870, 81, 81, 870, 870, 81, 81, 870, 870, 870, 870, 870, 870, 870, 870,
-    870, 870, 870, 870, 870, 870, 81, 870, 870, 870, 870, 870, 870, 870, 81,
-    870, 870, 81, 870, 870, 870, 870, 870, 81, 871, 872, 870, 869, 869, 868,
-    869, 869, 869, 869, 81, 81, 869, 869, 81, 81, 869, 869, 873, 81, 81, 870,
-    81, 81, 81, 81, 81, 81, 869, 81, 81, 81, 81, 81, 870, 870, 870, 870, 870,
-    869, 869, 81, 81, 874, 874, 874, 874, 874, 874, 874, 81, 81, 81, 875,
-    875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 876, 876,
-    876, 877, 877, 877, 877, 877, 877, 877, 877, 876, 876, 878, 877, 877,
-    876, 879, 875, 875, 875, 875, 880, 880, 880, 880, 881, 882, 882, 882,
-    882, 882, 882, 882, 882, 882, 882, 81, 880, 81, 881, 883, 81, 884, 884,
-    884, 884, 884, 884, 884, 884, 885, 885, 885, 886, 886, 886, 886, 886,
-    886, 885, 886, 885, 885, 885, 885, 886, 886, 885, 887, 888, 884, 884,
-    889, 884, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 81, 81, 81,
-    81, 81, 81, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891,
-    891, 891, 891, 892, 892, 892, 893, 893, 893, 893, 81, 81, 892, 892, 892,
-    892, 893, 893, 892, 894, 895, 896, 897, 897, 898, 898, 899, 899, 899,
-    897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
-    897, 891, 891, 891, 891, 893, 893, 81, 81, 900, 900, 900, 900, 900, 900,
-    900, 900, 901, 901, 901, 902, 902, 902, 902, 902, 902, 902, 902, 901,
-    901, 902, 901, 903, 902, 904, 904, 905, 900, 81, 81, 81, 906, 906, 906,
-    906, 906, 906, 906, 906, 906, 906, 81, 81, 81, 81, 81, 81, 907, 907, 907,
-    907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 81, 81, 81, 908, 908,
-    908, 908, 908, 908, 908, 908, 908, 908, 908, 909, 910, 909, 910, 910,
-    909, 909, 909, 909, 909, 909, 911, 912, 913, 913, 913, 913, 913, 913,
-    913, 913, 913, 913, 81, 81, 81, 81, 81, 81, 914, 914, 914, 914, 914, 914,
-    914, 914, 914, 914, 914, 81, 81, 915, 915, 915, 916, 916, 915, 915, 915,
-    915, 916, 915, 915, 915, 915, 917, 81, 81, 81, 81, 918, 918, 918, 918,
-    918, 918, 918, 918, 918, 918, 919, 919, 920, 920, 920, 921, 922, 922,
-    922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 923, 923, 923, 924,
-    924, 924, 924, 924, 924, 924, 924, 924, 923, 925, 926, 927, 81, 81, 81,
-    81, 928, 928, 928, 928, 928, 928, 928, 928, 929, 929, 929, 929, 929, 929,
-    929, 929, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 931, 931,
-    931, 931, 931, 931, 931, 931, 931, 81, 81, 81, 81, 81, 81, 81, 81, 81,
-    81, 81, 81, 932, 933, 934, 934, 934, 934, 934, 934, 935, 935, 934, 934,
-    933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933,
-    933, 933, 934, 936, 934, 934, 934, 934, 937, 933, 934, 934, 934, 934,
-    938, 939, 940, 940, 940, 940, 938, 939, 936, 941, 942, 942, 942, 942,
-    942, 942, 943, 943, 942, 942, 942, 941, 941, 941, 941, 941, 941, 941,
-    941, 941, 941, 941, 941, 941, 941, 941, 941, 81, 81, 941, 941, 941, 941,
-    942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 943,
-    942, 944, 945, 945, 945, 941, 946, 946, 946, 945, 945, 81, 81, 81, 81,
-    81, 947, 947, 947, 947, 947, 947, 947, 947, 947, 81, 81, 81, 81, 81, 81,
-    81, 948, 948, 948, 948, 948, 948, 948, 948, 948, 81, 948, 948, 948, 948,
-    948, 948, 948, 948, 948, 948, 948, 948, 948, 949, 950, 950, 950, 950,
-    950, 950, 950, 81, 950, 950, 950, 950, 950, 950, 949, 951, 948, 952, 952,
-    952, 952, 952, 81, 81, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953,
-    954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954,
-    954, 954, 954, 954, 954, 81, 81, 81, 955, 956, 957, 957, 957, 957, 957,
-    957, 957, 957, 957, 957, 957, 957, 957, 957, 81, 81, 958, 958, 958, 958,
-    958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 81, 959, 958, 958, 958,
-    958, 958, 958, 958, 959, 958, 958, 959, 958, 958, 81, 960, 960, 960, 960,
-    960, 960, 960, 81, 960, 960, 81, 960, 960, 960, 960, 960, 960, 960, 960,
-    960, 960, 960, 960, 960, 960, 961, 961, 961, 961, 961, 961, 81, 81, 81,
-    961, 81, 961, 961, 81, 961, 961, 961, 962, 961, 963, 963, 960, 961, 964,
-    964, 964, 964, 964, 964, 964, 964, 964, 964, 81, 81, 81, 81, 81, 81, 965,
-    965, 965, 965, 965, 965, 81, 965, 965, 81, 965, 965, 965, 965, 965, 965,
-    965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 966, 966, 966, 966,
-    966, 81, 967, 967, 81, 966, 966, 967, 966, 968, 965, 81, 81, 81, 81, 81,
-    81, 81, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 81, 81, 81, 81,
-    81, 81, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 971, 971,
-    972, 972, 973, 973, 81, 81, 81, 81, 81, 81, 81, 974, 974, 974, 974, 974,
-    974, 974, 974, 974, 974, 81, 81, 81, 81, 81, 81, 975, 975, 975, 975, 975,
-    975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 81, 976, 976, 976, 976,
-    976, 81, 81, 81, 974, 974, 974, 974, 81, 81, 81, 81, 977, 977, 977, 977,
-    977, 977, 977, 977, 978, 978, 978, 979, 979, 979, 977, 977, 977, 977,
-    979, 977, 977, 977, 978, 979, 978, 979, 977, 977, 977, 977, 977, 977,
-    977, 978, 979, 979, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977,
-    977, 81, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980,
-    980, 981, 982, 980, 980, 980, 980, 980, 980, 980, 81, 608, 81, 81, 81,
-    81, 81, 81, 81, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983,
-    983, 983, 983, 983, 81, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984,
-    81, 81, 81, 81, 985, 985, 986, 986, 986, 986, 986, 986, 986, 986, 986,
-    986, 986, 986, 986, 986, 81, 81, 987, 987, 987, 987, 987, 988, 81, 81,
-    989, 989, 989, 989, 989, 989, 989, 989, 990, 990, 990, 990, 990, 990,
-    990, 991, 991, 991, 992, 992, 993, 993, 993, 993, 994, 994, 994, 994,
-    991, 993, 81, 81, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 81,
-    996, 996, 996, 996, 996, 996, 996, 81, 989, 989, 989, 989, 989, 81, 81,
-    81, 81, 81, 989, 989, 989, 997, 997, 997, 997, 997, 997, 997, 997, 998,
-    998, 998, 998, 998, 998, 998, 998, 999, 999, 999, 999, 999, 999, 999,
-    999, 999, 999, 999, 999, 999, 999, 999, 1000, 1000, 1001, 1001, 81, 81,
-    81, 81, 81, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002,
-    1002, 1002, 1002, 81, 81, 81, 1002, 1003, 1003, 1003, 1003, 1003, 1003,
-    1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003,
-    1003, 1003, 1003, 1003, 81, 81, 81, 81, 81, 81, 81, 81, 1004, 1004, 1004,
-    1004, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005,
-    1005, 1005, 1006, 1007, 81, 81, 81, 81, 81, 81, 1008, 1008, 1008, 1008,
-    1008, 1008, 1008, 1008, 1008, 1008, 81, 81, 81, 81, 81, 81, 1008, 1008,
-    1008, 81, 81, 81, 81, 81, 579, 574, 574, 574, 574, 574, 574, 574, 574,
-    574, 574, 574, 574, 574, 574, 81, 1009, 1009, 1009, 1009, 1009, 1009,
-    1009, 1009, 1009, 1009, 1009, 1009, 81, 81, 81, 81, 1010, 1010, 1010,
-    1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 81, 81, 81, 81, 81, 1010,
-    1010, 1010, 1010, 1010, 81, 81, 81, 1010, 81, 81, 81, 81, 81, 81, 81,
-    1010, 1010, 81, 81, 1011, 1012, 1013, 1014, 503, 503, 503, 503, 81, 81,
-    81, 81, 317, 317, 317, 317, 317, 317, 81, 81, 317, 317, 317, 317, 317,
-    317, 317, 81, 81, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317,
-    317, 1015, 1015, 451, 451, 451, 317, 317, 317, 1016, 1015, 1015, 1015,
-    1015, 1015, 503, 503, 503, 503, 503, 503, 503, 503, 156, 156, 156, 156,
-    156, 156, 156, 156, 317, 317, 96, 96, 96, 96, 96, 156, 156, 317, 317,
-    317, 317, 317, 317, 96, 96, 96, 96, 317, 317, 317, 81, 81, 81, 81, 81,
-    81, 81, 724, 724, 1017, 1017, 1017, 724, 81, 81, 619, 619, 619, 619, 81,
-    81, 81, 81, 619, 81, 81, 81, 81, 81, 81, 81, 510, 510, 510, 510, 510,
-    510, 510, 510, 510, 510, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-    49, 49, 49, 49, 49, 49, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510,
-    49, 49, 49, 49, 49, 49, 49, 81, 49, 49, 49, 49, 49, 49, 510, 81, 510,
-    510, 81, 81, 510, 81, 81, 510, 510, 81, 81, 510, 510, 510, 510, 81, 510,
-    510, 49, 49, 81, 49, 81, 49, 49, 49, 49, 49, 49, 49, 81, 49, 49, 49, 49,
-    49, 49, 49, 510, 510, 81, 510, 510, 510, 510, 81, 81, 510, 510, 510, 510,
-    510, 510, 510, 510, 81, 510, 510, 510, 510, 510, 510, 510, 81, 49, 49,
-    510, 510, 81, 510, 510, 510, 510, 81, 510, 510, 510, 510, 510, 81, 510,
-    81, 81, 81, 510, 510, 510, 510, 510, 510, 510, 81, 49, 49, 49, 49, 49,
-    49, 49, 49, 49, 49, 49, 49, 81, 81, 510, 1018, 49, 49, 49, 49, 49, 49,
-    49, 49, 49, 496, 49, 49, 49, 49, 49, 49, 510, 510, 510, 510, 510, 510,
-    510, 510, 510, 1018, 49, 49, 49, 49, 49, 49, 49, 49, 49, 496, 49, 49,
-    510, 510, 510, 510, 510, 1018, 49, 49, 49, 49, 49, 49, 49, 49, 49, 496,
-    49, 49, 49, 49, 49, 49, 510, 510, 510, 510, 510, 510, 510, 510, 510,
-    1018, 49, 496, 49, 49, 49, 49, 49, 49, 49, 49, 510, 49, 81, 81, 1019,
-    1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1020, 1020, 1020,
-    1020, 1020, 1020, 1020, 1020, 1021, 1021, 1021, 1021, 1021, 1021, 1021,
-    1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1020, 1020, 1020, 1020,
-    1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1020, 1020,
-    1020, 1020, 1020, 1020, 1020, 1020, 1021, 1020, 1020, 1020, 1020, 1020,
-    1020, 1021, 1020, 1020, 1022, 1022, 1022, 1022, 1023, 81, 81, 81, 81, 81,
-    81, 81, 1021, 1021, 1021, 1021, 1021, 81, 1021, 1021, 1021, 1021, 1021,
-    1021, 1021, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 81, 1024, 1024,
-    1024, 1024, 1024, 1024, 1024, 1024, 1024, 81, 81, 1024, 1024, 1024, 1024,
-    1024, 1024, 1024, 81, 1024, 1024, 81, 1024, 1024, 1024, 1024, 1024, 81,
-    81, 81, 81, 81, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025,
-    1025, 1025, 1025, 1025, 81, 81, 1026, 1026, 1026, 1026, 1026, 1026, 1026,
-    1026, 1026, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 81, 1028, 1028,
-    1028, 1028, 1028, 1028, 1028, 1028, 1028, 1028, 1029, 1029, 1029, 1029,
-    1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029,
-    1029, 1029, 1030, 1030, 1030, 1030, 1030, 1030, 1031, 81, 81, 81, 81, 81,
-    1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 81, 81, 81,
-    81, 1033, 1033, 81, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034,
-    1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1035, 1034,
-    1034, 1034, 1036, 1034, 1034, 1034, 1034, 81, 81, 81, 146, 146, 146, 146,
-    81, 146, 146, 146, 81, 146, 146, 81, 146, 81, 81, 146, 81, 146, 146, 146,
-    146, 146, 146, 146, 146, 146, 146, 81, 146, 146, 146, 146, 81, 146, 81,
-    146, 81, 81, 81, 81, 81, 81, 146, 81, 81, 81, 81, 146, 81, 146, 81, 146,
-    81, 146, 146, 146, 81, 146, 81, 146, 81, 146, 81, 146, 81, 146, 146, 146,
-    146, 81, 146, 81, 146, 146, 81, 146, 146, 146, 146, 146, 146, 146, 146,
-    146, 81, 81, 81, 81, 81, 146, 146, 146, 81, 146, 146, 146, 132, 132, 81,
-    81, 81, 81, 81, 81, 529, 529, 529, 529, 525, 529, 529, 529, 529, 529,
-    529, 529, 529, 529, 529, 529, 529, 529, 529, 529, 1037, 1037, 1037, 1037,
-    1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 529, 529, 529, 529, 529,
-    529, 529, 1037, 1037, 529, 529, 529, 529, 529, 529, 529, 529, 529, 529,
-    529, 529, 529, 529, 525, 529, 529, 529, 529, 529, 529, 1037, 1037, 47,
-    47, 47, 519, 519, 1037, 1037, 1037, 530, 530, 530, 530, 530, 530, 317,
-    40, 530, 530, 40, 40, 1037, 1037, 1037, 1037, 530, 530, 530, 530, 530,
-    530, 1038, 530, 530, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038,
-    1038, 1038, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 1037, 1037,
-    1037, 1037, 1037, 1037, 1037, 1037, 1037, 1039, 1039, 1039, 1039, 1039,
-    1039, 1039, 1039, 1039, 1039, 1040, 585, 585, 1037, 1037, 1037, 1037,
-    1037, 585, 585, 585, 585, 1037, 1037, 1037, 1037, 585, 1037, 1037, 1037,
-    1037, 1037, 1037, 1037, 585, 585, 1037, 1037, 1037, 1037, 1037, 1037,
-    525, 525, 525, 525, 525, 525, 1037, 1037, 525, 529, 529, 529, 529, 529,
-    529, 529, 529, 529, 529, 529, 529, 525, 525, 525, 525, 525, 525, 525,
-    525, 525, 529, 525, 525, 525, 525, 525, 525, 529, 525, 525, 525, 525,
-    525, 525, 525, 536, 525, 525, 525, 525, 525, 525, 529, 529, 529, 529,
-    529, 529, 529, 529, 40, 40, 529, 529, 525, 525, 525, 525, 525, 528, 528,
-    525, 525, 525, 525, 525, 528, 525, 525, 525, 525, 525, 536, 536, 536,
-    525, 525, 536, 525, 525, 536, 534, 534, 529, 529, 525, 525, 529, 529,
-    529, 525, 529, 529, 529, 525, 525, 525, 1041, 1041, 1041, 1041, 1041,
-    525, 525, 525, 525, 525, 525, 525, 529, 525, 529, 536, 536, 525, 525,
-    536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 525, 525, 525,
-    525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 536, 536, 536, 536,
-    525, 525, 525, 525, 536, 525, 536, 525, 525, 525, 536, 525, 525, 525,
-    525, 536, 536, 536, 525, 536, 536, 536, 528, 525, 528, 525, 528, 525,
-    525, 525, 525, 525, 536, 525, 525, 525, 525, 528, 525, 528, 528, 525,
-    525, 525, 525, 525, 525, 525, 525, 525, 525, 529, 529, 525, 528, 528,
-    528, 528, 528, 528, 528, 525, 525, 525, 525, 525, 525, 525, 525, 528,
-    528, 528, 528, 528, 528, 525, 525, 525, 525, 525, 528, 528, 528, 528,
-    528, 528, 528, 528, 528, 528, 528, 528, 40, 40, 40, 40, 529, 525, 525,
-    525, 525, 529, 529, 529, 529, 529, 534, 534, 529, 529, 529, 529, 536,
-    529, 529, 529, 529, 529, 534, 529, 529, 529, 529, 536, 536, 529, 529,
-    529, 529, 529, 40, 40, 40, 40, 40, 40, 40, 40, 529, 529, 529, 529, 40,
-    40, 529, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 536, 536, 536,
-    525, 525, 525, 536, 536, 536, 536, 536, 40, 40, 40, 40, 40, 40, 538, 538,
-    538, 1042, 1042, 1042, 40, 40, 40, 40, 525, 525, 525, 536, 525, 525, 525,
-    525, 525, 525, 525, 525, 536, 536, 536, 525, 536, 525, 525, 525, 525,
-    525, 529, 529, 529, 529, 529, 529, 536, 529, 529, 529, 525, 525, 525,
-    529, 529, 1037, 1037, 1037, 529, 529, 529, 525, 525, 1037, 1037, 1037,
-    529, 529, 529, 529, 525, 525, 525, 525, 525, 525, 1037, 1037, 1037, 1037,
-    1037, 1037, 40, 40, 40, 40, 1037, 1037, 1037, 1037, 40, 40, 40, 40, 40,
-    529, 529, 529, 529, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 40, 40,
-    1037, 1037, 1037, 1037, 1037, 1037, 40, 40, 40, 40, 40, 40, 1037, 1037,
-    536, 536, 536, 536, 536, 525, 536, 536, 525, 525, 525, 525, 525, 525,
-    536, 525, 536, 536, 525, 525, 525, 536, 536, 1037, 525, 1037, 1037, 525,
-    525, 525, 525, 1037, 1037, 1037, 525, 1037, 525, 525, 525, 525, 525, 525,
-    525, 1037, 1037, 1037, 1037, 1037, 525, 525, 525, 525, 525, 536, 536,
-    525, 536, 536, 1037, 1037, 1037, 1037, 1037, 1037, 525, 536, 536, 536,
-    536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 525, 525, 1037, 1037,
-    1037, 1037, 1037, 1037, 81, 81, 592, 592, 592, 592, 592, 592, 592, 593,
-    592, 592, 592, 592, 592, 593, 593, 593, 592, 593, 593, 593, 593, 593,
-    593, 593, 593, 593, 593, 593, 593, 593, 81, 81, 81, 503, 81, 81, 81, 81,
-    81, 81, 503, 503, 503, 503, 503, 503, 503, 503, 670, 670, 670, 670, 670,
-    670, 81, 81,
-};
-
-/* decomposition data */
-static const unsigned short decomp_data[] = {
-    0, 257, 32, 514, 32, 776, 259, 97, 514, 32, 772, 259, 50, 259, 51, 514,
-    32, 769, 258, 956, 514, 32, 807, 259, 49, 259, 111, 772, 49, 8260, 52,
-    772, 49, 8260, 50, 772, 51, 8260, 52, 512, 65, 768, 512, 65, 769, 512,
-    65, 770, 512, 65, 771, 512, 65, 776, 512, 65, 778, 512, 67, 807, 512, 69,
-    768, 512, 69, 769, 512, 69, 770, 512, 69, 776, 512, 73, 768, 512, 73,
-    769, 512, 73, 770, 512, 73, 776, 512, 78, 771, 512, 79, 768, 512, 79,
-    769, 512, 79, 770, 512, 79, 771, 512, 79, 776, 512, 85, 768, 512, 85,
-    769, 512, 85, 770, 512, 85, 776, 512, 89, 769, 512, 97, 768, 512, 97,
-    769, 512, 97, 770, 512, 97, 771, 512, 97, 776, 512, 97, 778, 512, 99,
-    807, 512, 101, 768, 512, 101, 769, 512, 101, 770, 512, 101, 776, 512,
-    105, 768, 512, 105, 769, 512, 105, 770, 512, 105, 776, 512, 110, 771,
-    512, 111, 768, 512, 111, 769, 512, 111, 770, 512, 111, 771, 512, 111,
-    776, 512, 117, 768, 512, 117, 769, 512, 117, 770, 512, 117, 776, 512,
-    121, 769, 512, 121, 776, 512, 65, 772, 512, 97, 772, 512, 65, 774, 512,
-    97, 774, 512, 65, 808, 512, 97, 808, 512, 67, 769, 512, 99, 769, 512, 67,
-    770, 512, 99, 770, 512, 67, 775, 512, 99, 775, 512, 67, 780, 512, 99,
-    780, 512, 68, 780, 512, 100, 780, 512, 69, 772, 512, 101, 772, 512, 69,
-    774, 512, 101, 774, 512, 69, 775, 512, 101, 775, 512, 69, 808, 512, 101,
-    808, 512, 69, 780, 512, 101, 780, 512, 71, 770, 512, 103, 770, 512, 71,
-    774, 512, 103, 774, 512, 71, 775, 512, 103, 775, 512, 71, 807, 512, 103,
-    807, 512, 72, 770, 512, 104, 770, 512, 73, 771, 512, 105, 771, 512, 73,
-    772, 512, 105, 772, 512, 73, 774, 512, 105, 774, 512, 73, 808, 512, 105,
-    808, 512, 73, 775, 514, 73, 74, 514, 105, 106, 512, 74, 770, 512, 106,
-    770, 512, 75, 807, 512, 107, 807, 512, 76, 769, 512, 108, 769, 512, 76,
-    807, 512, 108, 807, 512, 76, 780, 512, 108, 780, 514, 76, 183, 514, 108,
-    183, 512, 78, 769, 512, 110, 769, 512, 78, 807, 512, 110, 807, 512, 78,
-    780, 512, 110, 780, 514, 700, 110, 512, 79, 772, 512, 111, 772, 512, 79,
-    774, 512, 111, 774, 512, 79, 779, 512, 111, 779, 512, 82, 769, 512, 114,
-    769, 512, 82, 807, 512, 114, 807, 512, 82, 780, 512, 114, 780, 512, 83,
-    769, 512, 115, 769, 512, 83, 770, 512, 115, 770, 512, 83, 807, 512, 115,
-    807, 512, 83, 780, 512, 115, 780, 512, 84, 807, 512, 116, 807, 512, 84,
-    780, 512, 116, 780, 512, 85, 771, 512, 117, 771, 512, 85, 772, 512, 117,
-    772, 512, 85, 774, 512, 117, 774, 512, 85, 778, 512, 117, 778, 512, 85,
-    779, 512, 117, 779, 512, 85, 808, 512, 117, 808, 512, 87, 770, 512, 119,
-    770, 512, 89, 770, 512, 121, 770, 512, 89, 776, 512, 90, 769, 512, 122,
-    769, 512, 90, 775, 512, 122, 775, 512, 90, 780, 512, 122, 780, 258, 115,
-    512, 79, 795, 512, 111, 795, 512, 85, 795, 512, 117, 795, 514, 68, 381,
-    514, 68, 382, 514, 100, 382, 514, 76, 74, 514, 76, 106, 514, 108, 106,
-    514, 78, 74, 514, 78, 106, 514, 110, 106, 512, 65, 780, 512, 97, 780,
-    512, 73, 780, 512, 105, 780, 512, 79, 780, 512, 111, 780, 512, 85, 780,
-    512, 117, 780, 512, 220, 772, 512, 252, 772, 512, 220, 769, 512, 252,
-    769, 512, 220, 780, 512, 252, 780, 512, 220, 768, 512, 252, 768, 512,
-    196, 772, 512, 228, 772, 512, 550, 772, 512, 551, 772, 512, 198, 772,
-    512, 230, 772, 512, 71, 780, 512, 103, 780, 512, 75, 780, 512, 107, 780,
-    512, 79, 808, 512, 111, 808, 512, 490, 772, 512, 491, 772, 512, 439, 780,
-    512, 658, 780, 512, 106, 780, 514, 68, 90, 514, 68, 122, 514, 100, 122,
-    512, 71, 769, 512, 103, 769, 512, 78, 768, 512, 110, 768, 512, 197, 769,
-    512, 229, 769, 512, 198, 769, 512, 230, 769, 512, 216, 769, 512, 248,
-    769, 512, 65, 783, 512, 97, 783, 512, 65, 785, 512, 97, 785, 512, 69,
-    783, 512, 101, 783, 512, 69, 785, 512, 101, 785, 512, 73, 783, 512, 105,
-    783, 512, 73, 785, 512, 105, 785, 512, 79, 783, 512, 111, 783, 512, 79,
-    785, 512, 111, 785, 512, 82, 783, 512, 114, 783, 512, 82, 785, 512, 114,
-    785, 512, 85, 783, 512, 117, 783, 512, 85, 785, 512, 117, 785, 512, 83,
-    806, 512, 115, 806, 512, 84, 806, 512, 116, 806, 512, 72, 780, 512, 104,
-    780, 512, 65, 775, 512, 97, 775, 512, 69, 807, 512, 101, 807, 512, 214,
-    772, 512, 246, 772, 512, 213, 772, 512, 245, 772, 512, 79, 775, 512, 111,
-    775, 512, 558, 772, 512, 559, 772, 512, 89, 772, 512, 121, 772, 259, 104,
-    259, 614, 259, 106, 259, 114, 259, 633, 259, 635, 259, 641, 259, 119,
-    259, 121, 514, 32, 774, 514, 32, 775, 514, 32, 778, 514, 32, 808, 514,
-    32, 771, 514, 32, 779, 259, 611, 259, 108, 259, 115, 259, 120, 259, 661,
-    256, 768, 256, 769, 256, 787, 512, 776, 769, 256, 697, 514, 32, 837, 256,
-    59, 514, 32, 769, 512, 168, 769, 512, 913, 769, 256, 183, 512, 917, 769,
-    512, 919, 769, 512, 921, 769, 512, 927, 769, 512, 933, 769, 512, 937,
-    769, 512, 970, 769, 512, 921, 776, 512, 933, 776, 512, 945, 769, 512,
-    949, 769, 512, 951, 769, 512, 953, 769, 512, 971, 769, 512, 953, 776,
-    512, 965, 776, 512, 959, 769, 512, 965, 769, 512, 969, 769, 258, 946,
-    258, 952, 258, 933, 512, 978, 769, 512, 978, 776, 258, 966, 258, 960,
-    258, 954, 258, 961, 258, 962, 258, 920, 258, 949, 258, 931, 512, 1045,
-    768, 512, 1045, 776, 512, 1043, 769, 512, 1030, 776, 512, 1050, 769, 512,
-    1048, 768, 512, 1059, 774, 512, 1048, 774, 512, 1080, 774, 512, 1077,
-    768, 512, 1077, 776, 512, 1075, 769, 512, 1110, 776, 512, 1082, 769, 512,
-    1080, 768, 512, 1091, 774, 512, 1140, 783, 512, 1141, 783, 512, 1046,
-    774, 512, 1078, 774, 512, 1040, 774, 512, 1072, 774, 512, 1040, 776, 512,
-    1072, 776, 512, 1045, 774, 512, 1077, 774, 512, 1240, 776, 512, 1241,
-    776, 512, 1046, 776, 512, 1078, 776, 512, 1047, 776, 512, 1079, 776, 512,
-    1048, 772, 512, 1080, 772, 512, 1048, 776, 512, 1080, 776, 512, 1054,
-    776, 512, 1086, 776, 512, 1256, 776, 512, 1257, 776, 512, 1069, 776, 512,
-    1101, 776, 512, 1059, 772, 512, 1091, 772, 512, 1059, 776, 512, 1091,
-    776, 512, 1059, 779, 512, 1091, 779, 512, 1063, 776, 512, 1095, 776, 512,
-    1067, 776, 512, 1099, 776, 514, 1381, 1410, 512, 1575, 1619, 512, 1575,
-    1620, 512, 1608, 1620, 512, 1575, 1621, 512, 1610, 1620, 514, 1575, 1652,
-    514, 1608, 1652, 514, 1735, 1652, 514, 1610, 1652, 512, 1749, 1620, 512,
-    1729, 1620, 512, 1746, 1620, 512, 2344, 2364, 512, 2352, 2364, 512, 2355,
-    2364, 512, 2325, 2364, 512, 2326, 2364, 512, 2327, 2364, 512, 2332, 2364,
-    512, 2337, 2364, 512, 2338, 2364, 512, 2347, 2364, 512, 2351, 2364, 512,
-    2503, 2494, 512, 2503, 2519, 512, 2465, 2492, 512, 2466, 2492, 512, 2479,
-    2492, 512, 2610, 2620, 512, 2616, 2620, 512, 2582, 2620, 512, 2583, 2620,
-    512, 2588, 2620, 512, 2603, 2620, 512, 2887, 2902, 512, 2887, 2878, 512,
-    2887, 2903, 512, 2849, 2876, 512, 2850, 2876, 512, 2962, 3031, 512, 3014,
-    3006, 512, 3015, 3006, 512, 3014, 3031, 512, 3142, 3158, 512, 3263, 3285,
-    512, 3270, 3285, 512, 3270, 3286, 512, 3270, 3266, 512, 3274, 3285, 512,
-    3398, 3390, 512, 3399, 3390, 512, 3398, 3415, 512, 3545, 3530, 512, 3545,
-    3535, 512, 3548, 3530, 512, 3545, 3551, 514, 3661, 3634, 514, 3789, 3762,
-    514, 3755, 3737, 514, 3755, 3745, 257, 3851, 512, 3906, 4023, 512, 3916,
-    4023, 512, 3921, 4023, 512, 3926, 4023, 512, 3931, 4023, 512, 3904, 4021,
-    512, 3953, 3954, 512, 3953, 3956, 512, 4018, 3968, 514, 4018, 3969, 512,
-    4019, 3968, 514, 4019, 3969, 512, 3953, 3968, 512, 3986, 4023, 512, 3996,
-    4023, 512, 4001, 4023, 512, 4006, 4023, 512, 4011, 4023, 512, 3984, 4021,
-    512, 4133, 4142, 259, 4316, 512, 6917, 6965, 512, 6919, 6965, 512, 6921,
-    6965, 512, 6923, 6965, 512, 6925, 6965, 512, 6929, 6965, 512, 6970, 6965,
-    512, 6972, 6965, 512, 6974, 6965, 512, 6975, 6965, 512, 6978, 6965, 259,
-    65, 259, 198, 259, 66, 259, 68, 259, 69, 259, 398, 259, 71, 259, 72, 259,
-    73, 259, 74, 259, 75, 259, 76, 259, 77, 259, 78, 259, 79, 259, 546, 259,
-    80, 259, 82, 259, 84, 259, 85, 259, 87, 259, 97, 259, 592, 259, 593, 259,
-    7426, 259, 98, 259, 100, 259, 101, 259, 601, 259, 603, 259, 604, 259,
-    103, 259, 107, 259, 109, 259, 331, 259, 111, 259, 596, 259, 7446, 259,
-    7447, 259, 112, 259, 116, 259, 117, 259, 7453, 259, 623, 259, 118, 259,
-    7461, 259, 946, 259, 947, 259, 948, 259, 966, 259, 967, 261, 105, 261,
-    114, 261, 117, 261, 118, 261, 946, 261, 947, 261, 961, 261, 966, 261,
-    967, 259, 1085, 259, 594, 259, 99, 259, 597, 259, 240, 259, 604, 259,
-    102, 259, 607, 259, 609, 259, 613, 259, 616, 259, 617, 259, 618, 259,
-    7547, 259, 669, 259, 621, 259, 7557, 259, 671, 259, 625, 259, 624, 259,
-    626, 259, 627, 259, 628, 259, 629, 259, 632, 259, 642, 259, 643, 259,
-    427, 259, 649, 259, 650, 259, 7452, 259, 651, 259, 652, 259, 122, 259,
-    656, 259, 657, 259, 658, 259, 952, 512, 65, 805, 512, 97, 805, 512, 66,
-    775, 512, 98, 775, 512, 66, 803, 512, 98, 803, 512, 66, 817, 512, 98,
-    817, 512, 199, 769, 512, 231, 769, 512, 68, 775, 512, 100, 775, 512, 68,
-    803, 512, 100, 803, 512, 68, 817, 512, 100, 817, 512, 68, 807, 512, 100,
-    807, 512, 68, 813, 512, 100, 813, 512, 274, 768, 512, 275, 768, 512, 274,
-    769, 512, 275, 769, 512, 69, 813, 512, 101, 813, 512, 69, 816, 512, 101,
-    816, 512, 552, 774, 512, 553, 774, 512, 70, 775, 512, 102, 775, 512, 71,
-    772, 512, 103, 772, 512, 72, 775, 512, 104, 775, 512, 72, 803, 512, 104,
-    803, 512, 72, 776, 512, 104, 776, 512, 72, 807, 512, 104, 807, 512, 72,
-    814, 512, 104, 814, 512, 73, 816, 512, 105, 816, 512, 207, 769, 512, 239,
-    769, 512, 75, 769, 512, 107, 769, 512, 75, 803, 512, 107, 803, 512, 75,
-    817, 512, 107, 817, 512, 76, 803, 512, 108, 803, 512, 7734, 772, 512,
-    7735, 772, 512, 76, 817, 512, 108, 817, 512, 76, 813, 512, 108, 813, 512,
-    77, 769, 512, 109, 769, 512, 77, 775, 512, 109, 775, 512, 77, 803, 512,
-    109, 803, 512, 78, 775, 512, 110, 775, 512, 78, 803, 512, 110, 803, 512,
-    78, 817, 512, 110, 817, 512, 78, 813, 512, 110, 813, 512, 213, 769, 512,
-    245, 769, 512, 213, 776, 512, 245, 776, 512, 332, 768, 512, 333, 768,
-    512, 332, 769, 512, 333, 769, 512, 80, 769, 512, 112, 769, 512, 80, 775,
-    512, 112, 775, 512, 82, 775, 512, 114, 775, 512, 82, 803, 512, 114, 803,
-    512, 7770, 772, 512, 7771, 772, 512, 82, 817, 512, 114, 817, 512, 83,
-    775, 512, 115, 775, 512, 83, 803, 512, 115, 803, 512, 346, 775, 512, 347,
-    775, 512, 352, 775, 512, 353, 775, 512, 7778, 775, 512, 7779, 775, 512,
-    84, 775, 512, 116, 775, 512, 84, 803, 512, 116, 803, 512, 84, 817, 512,
-    116, 817, 512, 84, 813, 512, 116, 813, 512, 85, 804, 512, 117, 804, 512,
-    85, 816, 512, 117, 816, 512, 85, 813, 512, 117, 813, 512, 360, 769, 512,
-    361, 769, 512, 362, 776, 512, 363, 776, 512, 86, 771, 512, 118, 771, 512,
-    86, 803, 512, 118, 803, 512, 87, 768, 512, 119, 768, 512, 87, 769, 512,
-    119, 769, 512, 87, 776, 512, 119, 776, 512, 87, 775, 512, 119, 775, 512,
-    87, 803, 512, 119, 803, 512, 88, 775, 512, 120, 775, 512, 88, 776, 512,
-    120, 776, 512, 89, 775, 512, 121, 775, 512, 90, 770, 512, 122, 770, 512,
-    90, 803, 512, 122, 803, 512, 90, 817, 512, 122, 817, 512, 104, 817, 512,
-    116, 776, 512, 119, 778, 512, 121, 778, 514, 97, 702, 512, 383, 775, 512,
-    65, 803, 512, 97, 803, 512, 65, 777, 512, 97, 777, 512, 194, 769, 512,
-    226, 769, 512, 194, 768, 512, 226, 768, 512, 194, 777, 512, 226, 777,
-    512, 194, 771, 512, 226, 771, 512, 7840, 770, 512, 7841, 770, 512, 258,
-    769, 512, 259, 769, 512, 258, 768, 512, 259, 768, 512, 258, 777, 512,
-    259, 777, 512, 258, 771, 512, 259, 771, 512, 7840, 774, 512, 7841, 774,
-    512, 69, 803, 512, 101, 803, 512, 69, 777, 512, 101, 777, 512, 69, 771,
-    512, 101, 771, 512, 202, 769, 512, 234, 769, 512, 202, 768, 512, 234,
-    768, 512, 202, 777, 512, 234, 777, 512, 202, 771, 512, 234, 771, 512,
-    7864, 770, 512, 7865, 770, 512, 73, 777, 512, 105, 777, 512, 73, 803,
-    512, 105, 803, 512, 79, 803, 512, 111, 803, 512, 79, 777, 512, 111, 777,
-    512, 212, 769, 512, 244, 769, 512, 212, 768, 512, 244, 768, 512, 212,
-    777, 512, 244, 777, 512, 212, 771, 512, 244, 771, 512, 7884, 770, 512,
-    7885, 770, 512, 416, 769, 512, 417, 769, 512, 416, 768, 512, 417, 768,
-    512, 416, 777, 512, 417, 777, 512, 416, 771, 512, 417, 771, 512, 416,
-    803, 512, 417, 803, 512, 85, 803, 512, 117, 803, 512, 85, 777, 512, 117,
-    777, 512, 431, 769, 512, 432, 769, 512, 431, 768, 512, 432, 768, 512,
-    431, 777, 512, 432, 777, 512, 431, 771, 512, 432, 771, 512, 431, 803,
-    512, 432, 803, 512, 89, 768, 512, 121, 768, 512, 89, 803, 512, 121, 803,
-    512, 89, 777, 512, 121, 777, 512, 89, 771, 512, 121, 771, 512, 945, 787,
-    512, 945, 788, 512, 7936, 768, 512, 7937, 768, 512, 7936, 769, 512, 7937,
-    769, 512, 7936, 834, 512, 7937, 834, 512, 913, 787, 512, 913, 788, 512,
-    7944, 768, 512, 7945, 768, 512, 7944, 769, 512, 7945, 769, 512, 7944,
-    834, 512, 7945, 834, 512, 949, 787, 512, 949, 788, 512, 7952, 768, 512,
-    7953, 768, 512, 7952, 769, 512, 7953, 769, 512, 917, 787, 512, 917, 788,
-    512, 7960, 768, 512, 7961, 768, 512, 7960, 769, 512, 7961, 769, 512, 951,
-    787, 512, 951, 788, 512, 7968, 768, 512, 7969, 768, 512, 7968, 769, 512,
-    7969, 769, 512, 7968, 834, 512, 7969, 834, 512, 919, 787, 512, 919, 788,
-    512, 7976, 768, 512, 7977, 768, 512, 7976, 769, 512, 7977, 769, 512,
-    7976, 834, 512, 7977, 834, 512, 953, 787, 512, 953, 788, 512, 7984, 768,
-    512, 7985, 768, 512, 7984, 769, 512, 7985, 769, 512, 7984, 834, 512,
-    7985, 834, 512, 921, 787, 512, 921, 788, 512, 7992, 768, 512, 7993, 768,
-    512, 7992, 769, 512, 7993, 769, 512, 7992, 834, 512, 7993, 834, 512, 959,
-    787, 512, 959, 788, 512, 8000, 768, 512, 8001, 768, 512, 8000, 769, 512,
-    8001, 769, 512, 927, 787, 512, 927, 788, 512, 8008, 768, 512, 8009, 768,
-    512, 8008, 769, 512, 8009, 769, 512, 965, 787, 512, 965, 788, 512, 8016,
-    768, 512, 8017, 768, 512, 8016, 769, 512, 8017, 769, 512, 8016, 834, 512,
-    8017, 834, 512, 933, 788, 512, 8025, 768, 512, 8025, 769, 512, 8025, 834,
-    512, 969, 787, 512, 969, 788, 512, 8032, 768, 512, 8033, 768, 512, 8032,
-    769, 512, 8033, 769, 512, 8032, 834, 512, 8033, 834, 512, 937, 787, 512,
-    937, 788, 512, 8040, 768, 512, 8041, 768, 512, 8040, 769, 512, 8041, 769,
-    512, 8040, 834, 512, 8041, 834, 512, 945, 768, 256, 940, 512, 949, 768,
-    256, 941, 512, 951, 768, 256, 942, 512, 953, 768, 256, 943, 512, 959,
-    768, 256, 972, 512, 965, 768, 256, 973, 512, 969, 768, 256, 974, 512,
-    7936, 837, 512, 7937, 837, 512, 7938, 837, 512, 7939, 837, 512, 7940,
-    837, 512, 7941, 837, 512, 7942, 837, 512, 7943, 837, 512, 7944, 837, 512,
-    7945, 837, 512, 7946, 837, 512, 7947, 837, 512, 7948, 837, 512, 7949,
-    837, 512, 7950, 837, 512, 7951, 837, 512, 7968, 837, 512, 7969, 837, 512,
-    7970, 837, 512, 7971, 837, 512, 7972, 837, 512, 7973, 837, 512, 7974,
-    837, 512, 7975, 837, 512, 7976, 837, 512, 7977, 837, 512, 7978, 837, 512,
-    7979, 837, 512, 7980, 837, 512, 7981, 837, 512, 7982, 837, 512, 7983,
-    837, 512, 8032, 837, 512, 8033, 837, 512, 8034, 837, 512, 8035, 837, 512,
-    8036, 837, 512, 8037, 837, 512, 8038, 837, 512, 8039, 837, 512, 8040,
-    837, 512, 8041, 837, 512, 8042, 837, 512, 8043, 837, 512, 8044, 837, 512,
-    8045, 837, 512, 8046, 837, 512, 8047, 837, 512, 945, 774, 512, 945, 772,
-    512, 8048, 837, 512, 945, 837, 512, 940, 837, 512, 945, 834, 512, 8118,
-    837, 512, 913, 774, 512, 913, 772, 512, 913, 768, 256, 902, 512, 913,
-    837, 514, 32, 787, 256, 953, 514, 32, 787, 514, 32, 834, 512, 168, 834,
-    512, 8052, 837, 512, 951, 837, 512, 942, 837, 512, 951, 834, 512, 8134,
-    837, 512, 917, 768, 256, 904, 512, 919, 768, 256, 905, 512, 919, 837,
-    512, 8127, 768, 512, 8127, 769, 512, 8127, 834, 512, 953, 774, 512, 953,
-    772, 512, 970, 768, 256, 912, 512, 953, 834, 512, 970, 834, 512, 921,
-    774, 512, 921, 772, 512, 921, 768, 256, 906, 512, 8190, 768, 512, 8190,
-    769, 512, 8190, 834, 512, 965, 774, 512, 965, 772, 512, 971, 768, 256,
-    944, 512, 961, 787, 512, 961, 788, 512, 965, 834, 512, 971, 834, 512,
-    933, 774, 512, 933, 772, 512, 933, 768, 256, 910, 512, 929, 788, 512,
-    168, 768, 256, 901, 256, 96, 512, 8060, 837, 512, 969, 837, 512, 974,
-    837, 512, 969, 834, 512, 8182, 837, 512, 927, 768, 256, 908, 512, 937,
-    768, 256, 911, 512, 937, 837, 256, 180, 514, 32, 788, 256, 8194, 256,
-    8195, 258, 32, 258, 32, 258, 32, 258, 32, 258, 32, 257, 32, 258, 32, 258,
-    32, 258, 32, 257, 8208, 514, 32, 819, 258, 46, 514, 46, 46, 770, 46, 46,
-    46, 257, 32, 514, 8242, 8242, 770, 8242, 8242, 8242, 514, 8245, 8245,
-    770, 8245, 8245, 8245, 514, 33, 33, 514, 32, 773, 514, 63, 63, 514, 63,
-    33, 514, 33, 63, 1026, 8242, 8242, 8242, 8242, 258, 32, 259, 48, 259,
-    105, 259, 52, 259, 53, 259, 54, 259, 55, 259, 56, 259, 57, 259, 43, 259,
-    8722, 259, 61, 259, 40, 259, 41, 259, 110, 261, 48, 261, 49, 261, 50,
-    261, 51, 261, 52, 261, 53, 261, 54, 261, 55, 261, 56, 261, 57, 261, 43,
-    261, 8722, 261, 61, 261, 40, 261, 41, 261, 97, 261, 101, 261, 111, 261,
-    120, 261, 601, 261, 104, 261, 107, 261, 108, 261, 109, 261, 110, 261,
-    112, 261, 115, 261, 116, 514, 82, 115, 770, 97, 47, 99, 770, 97, 47, 115,
-    262, 67, 514, 176, 67, 770, 99, 47, 111, 770, 99, 47, 117, 258, 400, 514,
-    176, 70, 262, 103, 262, 72, 262, 72, 262, 72, 262, 104, 262, 295, 262,
-    73, 262, 73, 262, 76, 262, 108, 262, 78, 514, 78, 111, 262, 80, 262, 81,
-    262, 82, 262, 82, 262, 82, 515, 83, 77, 770, 84, 69, 76, 515, 84, 77,
-    262, 90, 256, 937, 262, 90, 256, 75, 256, 197, 262, 66, 262, 67, 262,
-    101, 262, 69, 262, 70, 262, 77, 262, 111, 258, 1488, 258, 1489, 258,
-    1490, 258, 1491, 262, 105, 770, 70, 65, 88, 262, 960, 262, 947, 262, 915,
-    262, 928, 262, 8721, 262, 68, 262, 100, 262, 101, 262, 105, 262, 106,
-    772, 49, 8260, 55, 772, 49, 8260, 57, 1028, 49, 8260, 49, 48, 772, 49,
-    8260, 51, 772, 50, 8260, 51, 772, 49, 8260, 53, 772, 50, 8260, 53, 772,
-    51, 8260, 53, 772, 52, 8260, 53, 772, 49, 8260, 54, 772, 53, 8260, 54,
-    772, 49, 8260, 56, 772, 51, 8260, 56, 772, 53, 8260, 56, 772, 55, 8260,
-    56, 516, 49, 8260, 258, 73, 514, 73, 73, 770, 73, 73, 73, 514, 73, 86,
-    258, 86, 514, 86, 73, 770, 86, 73, 73, 1026, 86, 73, 73, 73, 514, 73, 88,
-    258, 88, 514, 88, 73, 770, 88, 73, 73, 258, 76, 258, 67, 258, 68, 258,
-    77, 258, 105, 514, 105, 105, 770, 105, 105, 105, 514, 105, 118, 258, 118,
-    514, 118, 105, 770, 118, 105, 105, 1026, 118, 105, 105, 105, 514, 105,
-    120, 258, 120, 514, 120, 105, 770, 120, 105, 105, 258, 108, 258, 99, 258,
-    100, 258, 109, 772, 48, 8260, 51, 512, 8592, 824, 512, 8594, 824, 512,
-    8596, 824, 512, 8656, 824, 512, 8660, 824, 512, 8658, 824, 512, 8707,
-    824, 512, 8712, 824, 512, 8715, 824, 512, 8739, 824, 512, 8741, 824, 514,
-    8747, 8747, 770, 8747, 8747, 8747, 514, 8750, 8750, 770, 8750, 8750,
-    8750, 512, 8764, 824, 512, 8771, 824, 512, 8773, 824, 512, 8776, 824,
-    512, 61, 824, 512, 8801, 824, 512, 8781, 824, 512, 60, 824, 512, 62, 824,
-    512, 8804, 824, 512, 8805, 824, 512, 8818, 824, 512, 8819, 824, 512,
-    8822, 824, 512, 8823, 824, 512, 8826, 824, 512, 8827, 824, 512, 8834,
-    824, 512, 8835, 824, 512, 8838, 824, 512, 8839, 824, 512, 8866, 824, 512,
-    8872, 824, 512, 8873, 824, 512, 8875, 824, 512, 8828, 824, 512, 8829,
-    824, 512, 8849, 824, 512, 8850, 824, 512, 8882, 824, 512, 8883, 824, 512,
-    8884, 824, 512, 8885, 824, 256, 12296, 256, 12297, 263, 49, 263, 50, 263,
-    51, 263, 52, 263, 53, 263, 54, 263, 55, 263, 56, 263, 57, 519, 49, 48,
-    519, 49, 49, 519, 49, 50, 519, 49, 51, 519, 49, 52, 519, 49, 53, 519, 49,
-    54, 519, 49, 55, 519, 49, 56, 519, 49, 57, 519, 50, 48, 770, 40, 49, 41,
-    770, 40, 50, 41, 770, 40, 51, 41, 770, 40, 52, 41, 770, 40, 53, 41, 770,
-    40, 54, 41, 770, 40, 55, 41, 770, 40, 56, 41, 770, 40, 57, 41, 1026, 40,
-    49, 48, 41, 1026, 40, 49, 49, 41, 1026, 40, 49, 50, 41, 1026, 40, 49, 51,
-    41, 1026, 40, 49, 52, 41, 1026, 40, 49, 53, 41, 1026, 40, 49, 54, 41,
-    1026, 40, 49, 55, 41, 1026, 40, 49, 56, 41, 1026, 40, 49, 57, 41, 1026,
-    40, 50, 48, 41, 514, 49, 46, 514, 50, 46, 514, 51, 46, 514, 52, 46, 514,
-    53, 46, 514, 54, 46, 514, 55, 46, 514, 56, 46, 514, 57, 46, 770, 49, 48,
-    46, 770, 49, 49, 46, 770, 49, 50, 46, 770, 49, 51, 46, 770, 49, 52, 46,
-    770, 49, 53, 46, 770, 49, 54, 46, 770, 49, 55, 46, 770, 49, 56, 46, 770,
-    49, 57, 46, 770, 50, 48, 46, 770, 40, 97, 41, 770, 40, 98, 41, 770, 40,
-    99, 41, 770, 40, 100, 41, 770, 40, 101, 41, 770, 40, 102, 41, 770, 40,
-    103, 41, 770, 40, 104, 41, 770, 40, 105, 41, 770, 40, 106, 41, 770, 40,
-    107, 41, 770, 40, 108, 41, 770, 40, 109, 41, 770, 40, 110, 41, 770, 40,
-    111, 41, 770, 40, 112, 41, 770, 40, 113, 41, 770, 40, 114, 41, 770, 40,
-    115, 41, 770, 40, 116, 41, 770, 40, 117, 41, 770, 40, 118, 41, 770, 40,
-    119, 41, 770, 40, 120, 41, 770, 40, 121, 41, 770, 40, 122, 41, 263, 65,
-    263, 66, 263, 67, 263, 68, 263, 69, 263, 70, 263, 71, 263, 72, 263, 73,
-    263, 74, 263, 75, 263, 76, 263, 77, 263, 78, 263, 79, 263, 80, 263, 81,
-    263, 82, 263, 83, 263, 84, 263, 85, 263, 86, 263, 87, 263, 88, 263, 89,
-    263, 90, 263, 97, 263, 98, 263, 99, 263, 100, 263, 101, 263, 102, 263,
-    103, 263, 104, 263, 105, 263, 106, 263, 107, 263, 108, 263, 109, 263,
-    110, 263, 111, 263, 112, 263, 113, 263, 114, 263, 115, 263, 116, 263,
-    117, 263, 118, 263, 119, 263, 120, 263, 121, 263, 122, 263, 48, 1026,
-    8747, 8747, 8747, 8747, 770, 58, 58, 61, 514, 61, 61, 770, 61, 61, 61,
-    512, 10973, 824, 261, 106, 259, 86, 259, 11617, 258, 27597, 258, 40863,
-    258, 19968, 258, 20008, 258, 20022, 258, 20031, 258, 20057, 258, 20101,
-    258, 20108, 258, 20128, 258, 20154, 258, 20799, 258, 20837, 258, 20843,
-    258, 20866, 258, 20886, 258, 20907, 258, 20960, 258, 20981, 258, 20992,
-    258, 21147, 258, 21241, 258, 21269, 258, 21274, 258, 21304, 258, 21313,
-    258, 21340, 258, 21353, 258, 21378, 258, 21430, 258, 21448, 258, 21475,
-    258, 22231, 258, 22303, 258, 22763, 258, 22786, 258, 22794, 258, 22805,
-    258, 22823, 258, 22899, 258, 23376, 258, 23424, 258, 23544, 258, 23567,
-    258, 23586, 258, 23608, 258, 23662, 258, 23665, 258, 24027, 258, 24037,
-    258, 24049, 258, 24062, 258, 24178, 258, 24186, 258, 24191, 258, 24308,
-    258, 24318, 258, 24331, 258, 24339, 258, 24400, 258, 24417, 258, 24435,
-    258, 24515, 258, 25096, 258, 25142, 258, 25163, 258, 25903, 258, 25908,
-    258, 25991, 258, 26007, 258, 26020, 258, 26041, 258, 26080, 258, 26085,
-    258, 26352, 258, 26376, 258, 26408, 258, 27424, 258, 27490, 258, 27513,
-    258, 27571, 258, 27595, 258, 27604, 258, 27611, 258, 27663, 258, 27668,
-    258, 27700, 258, 28779, 258, 29226, 258, 29238, 258, 29243, 258, 29247,
-    258, 29255, 258, 29273, 258, 29275, 258, 29356, 258, 29572, 258, 29577,
-    258, 29916, 258, 29926, 258, 29976, 258, 29983, 258, 29992, 258, 30000,
-    258, 30091, 258, 30098, 258, 30326, 258, 30333, 258, 30382, 258, 30399,
-    258, 30446, 258, 30683, 258, 30690, 258, 30707, 258, 31034, 258, 31160,
-    258, 31166, 258, 31348, 258, 31435, 258, 31481, 258, 31859, 258, 31992,
-    258, 32566, 258, 32593, 258, 32650, 258, 32701, 258, 32769, 258, 32780,
-    258, 32786, 258, 32819, 258, 32895, 258, 32905, 258, 33251, 258, 33258,
-    258, 33267, 258, 33276, 258, 33292, 258, 33307, 258, 33311, 258, 33390,
-    258, 33394, 258, 33400, 258, 34381, 258, 34411, 258, 34880, 258, 34892,
-    258, 34915, 258, 35198, 258, 35211, 258, 35282, 258, 35328, 258, 35895,
-    258, 35910, 258, 35925, 258, 35960, 258, 35997, 258, 36196, 258, 36208,
-    258, 36275, 258, 36523, 258, 36554, 258, 36763, 258, 36784, 258, 36789,
-    258, 37009, 258, 37193, 258, 37318, 258, 37324, 258, 37329, 258, 38263,
-    258, 38272, 258, 38428, 258, 38582, 258, 38585, 258, 38632, 258, 38737,
-    258, 38750, 258, 38754, 258, 38761, 258, 38859, 258, 38893, 258, 38899,
-    258, 38913, 258, 39080, 258, 39131, 258, 39135, 258, 39318, 258, 39321,
-    258, 39340, 258, 39592, 258, 39640, 258, 39647, 258, 39717, 258, 39727,
-    258, 39730, 258, 39740, 258, 39770, 258, 40165, 258, 40565, 258, 40575,
-    258, 40613, 258, 40635, 258, 40643, 258, 40653, 258, 40657, 258, 40697,
-    258, 40701, 258, 40718, 258, 40723, 258, 40736, 258, 40763, 258, 40778,
-    258, 40786, 258, 40845, 258, 40860, 258, 40864, 264, 32, 258, 12306, 258,
-    21313, 258, 21316, 258, 21317, 512, 12363, 12441, 512, 12365, 12441, 512,
-    12367, 12441, 512, 12369, 12441, 512, 12371, 12441, 512, 12373, 12441,
-    512, 12375, 12441, 512, 12377, 12441, 512, 12379, 12441, 512, 12381,
-    12441, 512, 12383, 12441, 512, 12385, 12441, 512, 12388, 12441, 512,
-    12390, 12441, 512, 12392, 12441, 512, 12399, 12441, 512, 12399, 12442,
-    512, 12402, 12441, 512, 12402, 12442, 512, 12405, 12441, 512, 12405,
-    12442, 512, 12408, 12441, 512, 12408, 12442, 512, 12411, 12441, 512,
-    12411, 12442, 512, 12358, 12441, 514, 32, 12441, 514, 32, 12442, 512,
-    12445, 12441, 521, 12424, 12426, 512, 12459, 12441, 512, 12461, 12441,
-    512, 12463, 12441, 512, 12465, 12441, 512, 12467, 12441, 512, 12469,
-    12441, 512, 12471, 12441, 512, 12473, 12441, 512, 12475, 12441, 512,
-    12477, 12441, 512, 12479, 12441, 512, 12481, 12441, 512, 12484, 12441,
-    512, 12486, 12441, 512, 12488, 12441, 512, 12495, 12441, 512, 12495,
-    12442, 512, 12498, 12441, 512, 12498, 12442, 512, 12501, 12441, 512,
-    12501, 12442, 512, 12504, 12441, 512, 12504, 12442, 512, 12507, 12441,
-    512, 12507, 12442, 512, 12454, 12441, 512, 12527, 12441, 512, 12528,
-    12441, 512, 12529, 12441, 512, 12530, 12441, 512, 12541, 12441, 521,
-    12467, 12488, 258, 4352, 258, 4353, 258, 4522, 258, 4354, 258, 4524, 258,
-    4525, 258, 4355, 258, 4356, 258, 4357, 258, 4528, 258, 4529, 258, 4530,
-    258, 4531, 258, 4532, 258, 4533, 258, 4378, 258, 4358, 258, 4359, 258,
-    4360, 258, 4385, 258, 4361, 258, 4362, 258, 4363, 258, 4364, 258, 4365,
-    258, 4366, 258, 4367, 258, 4368, 258, 4369, 258, 4370, 258, 4449, 258,
-    4450, 258, 4451, 258, 4452, 258, 4453, 258, 4454, 258, 4455, 258, 4456,
-    258, 4457, 258, 4458, 258, 4459, 258, 4460, 258, 4461, 258, 4462, 258,
-    4463, 258, 4464, 258, 4465, 258, 4466, 258, 4467, 258, 4468, 258, 4469,
-    258, 4448, 258, 4372, 258, 4373, 258, 4551, 258, 4552, 258, 4556, 258,
-    4558, 258, 4563, 258, 4567, 258, 4569, 258, 4380, 258, 4573, 258, 4575,
-    258, 4381, 258, 4382, 258, 4384, 258, 4386, 258, 4387, 258, 4391, 258,
-    4393, 258, 4395, 258, 4396, 258, 4397, 258, 4398, 258, 4399, 258, 4402,
-    258, 4406, 258, 4416, 258, 4423, 258, 4428, 258, 4593, 258, 4594, 258,
-    4439, 258, 4440, 258, 4441, 258, 4484, 258, 4485, 258, 4488, 258, 4497,
-    258, 4498, 258, 4500, 258, 4510, 258, 4513, 259, 19968, 259, 20108, 259,
-    19977, 259, 22235, 259, 19978, 259, 20013, 259, 19979, 259, 30002, 259,
-    20057, 259, 19993, 259, 19969, 259, 22825, 259, 22320, 259, 20154, 770,
-    40, 4352, 41, 770, 40, 4354, 41, 770, 40, 4355, 41, 770, 40, 4357, 41,
-    770, 40, 4358, 41, 770, 40, 4359, 41, 770, 40, 4361, 41, 770, 40, 4363,
-    41, 770, 40, 4364, 41, 770, 40, 4366, 41, 770, 40, 4367, 41, 770, 40,
-    4368, 41, 770, 40, 4369, 41, 770, 40, 4370, 41, 1026, 40, 4352, 4449, 41,
-    1026, 40, 4354, 4449, 41, 1026, 40, 4355, 4449, 41, 1026, 40, 4357, 4449,
-    41, 1026, 40, 4358, 4449, 41, 1026, 40, 4359, 4449, 41, 1026, 40, 4361,
-    4449, 41, 1026, 40, 4363, 4449, 41, 1026, 40, 4364, 4449, 41, 1026, 40,
-    4366, 4449, 41, 1026, 40, 4367, 4449, 41, 1026, 40, 4368, 4449, 41, 1026,
-    40, 4369, 4449, 41, 1026, 40, 4370, 4449, 41, 1026, 40, 4364, 4462, 41,
-    1794, 40, 4363, 4457, 4364, 4453, 4523, 41, 1538, 40, 4363, 4457, 4370,
-    4462, 41, 770, 40, 19968, 41, 770, 40, 20108, 41, 770, 40, 19977, 41,
-    770, 40, 22235, 41, 770, 40, 20116, 41, 770, 40, 20845, 41, 770, 40,
-    19971, 41, 770, 40, 20843, 41, 770, 40, 20061, 41, 770, 40, 21313, 41,
-    770, 40, 26376, 41, 770, 40, 28779, 41, 770, 40, 27700, 41, 770, 40,
-    26408, 41, 770, 40, 37329, 41, 770, 40, 22303, 41, 770, 40, 26085, 41,
-    770, 40, 26666, 41, 770, 40, 26377, 41, 770, 40, 31038, 41, 770, 40,
-    21517, 41, 770, 40, 29305, 41, 770, 40, 36001, 41, 770, 40, 31069, 41,
-    770, 40, 21172, 41, 770, 40, 20195, 41, 770, 40, 21628, 41, 770, 40,
-    23398, 41, 770, 40, 30435, 41, 770, 40, 20225, 41, 770, 40, 36039, 41,
-    770, 40, 21332, 41, 770, 40, 31085, 41, 770, 40, 20241, 41, 770, 40,
-    33258, 41, 770, 40, 33267, 41, 263, 21839, 263, 24188, 263, 25991, 263,
-    31631, 778, 80, 84, 69, 519, 50, 49, 519, 50, 50, 519, 50, 51, 519, 50,
-    52, 519, 50, 53, 519, 50, 54, 519, 50, 55, 519, 50, 56, 519, 50, 57, 519,
-    51, 48, 519, 51, 49, 519, 51, 50, 519, 51, 51, 519, 51, 52, 519, 51, 53,
-    263, 4352, 263, 4354, 263, 4355, 263, 4357, 263, 4358, 263, 4359, 263,
-    4361, 263, 4363, 263, 4364, 263, 4366, 263, 4367, 263, 4368, 263, 4369,
-    263, 4370, 519, 4352, 4449, 519, 4354, 4449, 519, 4355, 4449, 519, 4357,
-    4449, 519, 4358, 4449, 519, 4359, 4449, 519, 4361, 4449, 519, 4363, 4449,
-    519, 4364, 4449, 519, 4366, 4449, 519, 4367, 4449, 519, 4368, 4449, 519,
-    4369, 4449, 519, 4370, 4449, 1287, 4366, 4449, 4535, 4352, 4457, 1031,
-    4364, 4462, 4363, 4468, 519, 4363, 4462, 263, 19968, 263, 20108, 263,
-    19977, 263, 22235, 263, 20116, 263, 20845, 263, 19971, 263, 20843, 263,
-    20061, 263, 21313, 263, 26376, 263, 28779, 263, 27700, 263, 26408, 263,
-    37329, 263, 22303, 263, 26085, 263, 26666, 263, 26377, 263, 31038, 263,
-    21517, 263, 29305, 263, 36001, 263, 31069, 263, 21172, 263, 31192, 263,
-    30007, 263, 22899, 263, 36969, 263, 20778, 263, 21360, 263, 27880, 263,
-    38917, 263, 20241, 263, 20889, 263, 27491, 263, 19978, 263, 20013, 263,
-    19979, 263, 24038, 263, 21491, 263, 21307, 263, 23447, 263, 23398, 263,
-    30435, 263, 20225, 263, 36039, 263, 21332, 263, 22812, 519, 51, 54, 519,
-    51, 55, 519, 51, 56, 519, 51, 57, 519, 52, 48, 519, 52, 49, 519, 52, 50,
-    519, 52, 51, 519, 52, 52, 519, 52, 53, 519, 52, 54, 519, 52, 55, 519, 52,
-    56, 519, 52, 57, 519, 53, 48, 514, 49, 26376, 514, 50, 26376, 514, 51,
-    26376, 514, 52, 26376, 514, 53, 26376, 514, 54, 26376, 514, 55, 26376,
-    514, 56, 26376, 514, 57, 26376, 770, 49, 48, 26376, 770, 49, 49, 26376,
-    770, 49, 50, 26376, 522, 72, 103, 778, 101, 114, 103, 522, 101, 86, 778,
-    76, 84, 68, 263, 12450, 263, 12452, 263, 12454, 263, 12456, 263, 12458,
-    263, 12459, 263, 12461, 263, 12463, 263, 12465, 263, 12467, 263, 12469,
-    263, 12471, 263, 12473, 263, 12475, 263, 12477, 263, 12479, 263, 12481,
-    263, 12484, 263, 12486, 263, 12488, 263, 12490, 263, 12491, 263, 12492,
-    263, 12493, 263, 12494, 263, 12495, 263, 12498, 263, 12501, 263, 12504,
-    263, 12507, 263, 12510, 263, 12511, 263, 12512, 263, 12513, 263, 12514,
-    263, 12516, 263, 12518, 263, 12520, 263, 12521, 263, 12522, 263, 12523,
-    263, 12524, 263, 12525, 263, 12527, 263, 12528, 263, 12529, 263, 12530,
-    1034, 12450, 12497, 12540, 12488, 1034, 12450, 12523, 12501, 12449, 1034,
-    12450, 12531, 12506, 12450, 778, 12450, 12540, 12523, 1034, 12452, 12491,
-    12531, 12464, 778, 12452, 12531, 12481, 778, 12454, 12457, 12531, 1290,
-    12456, 12473, 12463, 12540, 12489, 1034, 12456, 12540, 12459, 12540, 778,
-    12458, 12531, 12473, 778, 12458, 12540, 12512, 778, 12459, 12452, 12522,
-    1034, 12459, 12521, 12483, 12488, 1034, 12459, 12525, 12522, 12540, 778,
-    12460, 12525, 12531, 778, 12460, 12531, 12510, 522, 12462, 12460, 778,
-    12462, 12491, 12540, 1034, 12461, 12517, 12522, 12540, 1034, 12462,
-    12523, 12480, 12540, 522, 12461, 12525, 1290, 12461, 12525, 12464, 12521,
-    12512, 1546, 12461, 12525, 12513, 12540, 12488, 12523, 1290, 12461,
-    12525, 12527, 12483, 12488, 778, 12464, 12521, 12512, 1290, 12464, 12521,
-    12512, 12488, 12531, 1290, 12463, 12523, 12476, 12452, 12525, 1034,
-    12463, 12525, 12540, 12493, 778, 12465, 12540, 12473, 778, 12467, 12523,
-    12490, 778, 12467, 12540, 12509, 1034, 12469, 12452, 12463, 12523, 1290,
-    12469, 12531, 12481, 12540, 12512, 1034, 12471, 12522, 12531, 12464, 778,
-    12475, 12531, 12481, 778, 12475, 12531, 12488, 778, 12480, 12540, 12473,
-    522, 12487, 12471, 522, 12489, 12523, 522, 12488, 12531, 522, 12490,
-    12494, 778, 12494, 12483, 12488, 778, 12495, 12452, 12484, 1290, 12497,
-    12540, 12475, 12531, 12488, 778, 12497, 12540, 12484, 1034, 12496, 12540,
-    12524, 12523, 1290, 12500, 12450, 12473, 12488, 12523, 778, 12500, 12463,
-    12523, 522, 12500, 12467, 522, 12499, 12523, 1290, 12501, 12449, 12521,
-    12483, 12489, 1034, 12501, 12451, 12540, 12488, 1290, 12502, 12483,
-    12471, 12455, 12523, 778, 12501, 12521, 12531, 1290, 12504, 12463, 12479,
-    12540, 12523, 522, 12506, 12477, 778, 12506, 12491, 12498, 778, 12504,
-    12523, 12484, 778, 12506, 12531, 12473, 778, 12506, 12540, 12472, 778,
-    12505, 12540, 12479, 1034, 12509, 12452, 12531, 12488, 778, 12508, 12523,
-    12488, 522, 12507, 12531, 778, 12509, 12531, 12489, 778, 12507, 12540,
-    12523, 778, 12507, 12540, 12531, 1034, 12510, 12452, 12463, 12525, 778,
-    12510, 12452, 12523, 778, 12510, 12483, 12495, 778, 12510, 12523, 12463,
-    1290, 12510, 12531, 12471, 12519, 12531, 1034, 12511, 12463, 12525,
-    12531, 522, 12511, 12522, 1290, 12511, 12522, 12496, 12540, 12523, 522,
-    12513, 12460, 1034, 12513, 12460, 12488, 12531, 1034, 12513, 12540,
-    12488, 12523, 778, 12516, 12540, 12489, 778, 12516, 12540, 12523, 778,
-    12518, 12450, 12531, 1034, 12522, 12483, 12488, 12523, 522, 12522, 12521,
-    778, 12523, 12500, 12540, 1034, 12523, 12540, 12502, 12523, 522, 12524,
-    12512, 1290, 12524, 12531, 12488, 12466, 12531, 778, 12527, 12483, 12488,
-    514, 48, 28857, 514, 49, 28857, 514, 50, 28857, 514, 51, 28857, 514, 52,
-    28857, 514, 53, 28857, 514, 54, 28857, 514, 55, 28857, 514, 56, 28857,
-    514, 57, 28857, 770, 49, 48, 28857, 770, 49, 49, 28857, 770, 49, 50,
-    28857, 770, 49, 51, 28857, 770, 49, 52, 28857, 770, 49, 53, 28857, 770,
-    49, 54, 28857, 770, 49, 55, 28857, 770, 49, 56, 28857, 770, 49, 57,
-    28857, 770, 50, 48, 28857, 770, 50, 49, 28857, 770, 50, 50, 28857, 770,
-    50, 51, 28857, 770, 50, 52, 28857, 778, 104, 80, 97, 522, 100, 97, 522,
-    65, 85, 778, 98, 97, 114, 522, 111, 86, 522, 112, 99, 522, 100, 109, 778,
-    100, 109, 178, 778, 100, 109, 179, 522, 73, 85, 522, 24179, 25104, 522,
-    26157, 21644, 522, 22823, 27491, 522, 26126, 27835, 1034, 26666, 24335,
-    20250, 31038, 522, 112, 65, 522, 110, 65, 522, 956, 65, 522, 109, 65,
-    522, 107, 65, 522, 75, 66, 522, 77, 66, 522, 71, 66, 778, 99, 97, 108,
-    1034, 107, 99, 97, 108, 522, 112, 70, 522, 110, 70, 522, 956, 70, 522,
-    956, 103, 522, 109, 103, 522, 107, 103, 522, 72, 122, 778, 107, 72, 122,
-    778, 77, 72, 122, 778, 71, 72, 122, 778, 84, 72, 122, 522, 956, 8467,
-    522, 109, 8467, 522, 100, 8467, 522, 107, 8467, 522, 102, 109, 522, 110,
-    109, 522, 956, 109, 522, 109, 109, 522, 99, 109, 522, 107, 109, 778, 109,
-    109, 178, 778, 99, 109, 178, 522, 109, 178, 778, 107, 109, 178, 778, 109,
-    109, 179, 778, 99, 109, 179, 522, 109, 179, 778, 107, 109, 179, 778, 109,
-    8725, 115, 1034, 109, 8725, 115, 178, 522, 80, 97, 778, 107, 80, 97, 778,
-    77, 80, 97, 778, 71, 80, 97, 778, 114, 97, 100, 1290, 114, 97, 100, 8725,
-    115, 1546, 114, 97, 100, 8725, 115, 178, 522, 112, 115, 522, 110, 115,
-    522, 956, 115, 522, 109, 115, 522, 112, 86, 522, 110, 86, 522, 956, 86,
-    522, 109, 86, 522, 107, 86, 522, 77, 86, 522, 112, 87, 522, 110, 87, 522,
-    956, 87, 522, 109, 87, 522, 107, 87, 522, 77, 87, 522, 107, 937, 522, 77,
-    937, 1034, 97, 46, 109, 46, 522, 66, 113, 522, 99, 99, 522, 99, 100,
-    1034, 67, 8725, 107, 103, 778, 67, 111, 46, 522, 100, 66, 522, 71, 121,
-    522, 104, 97, 522, 72, 80, 522, 105, 110, 522, 75, 75, 522, 75, 77, 522,
-    107, 116, 522, 108, 109, 522, 108, 110, 778, 108, 111, 103, 522, 108,
-    120, 522, 109, 98, 778, 109, 105, 108, 778, 109, 111, 108, 522, 80, 72,
-    1034, 112, 46, 109, 46, 778, 80, 80, 77, 522, 80, 82, 522, 115, 114, 522,
-    83, 118, 522, 87, 98, 778, 86, 8725, 109, 778, 65, 8725, 109, 514, 49,
-    26085, 514, 50, 26085, 514, 51, 26085, 514, 52, 26085, 514, 53, 26085,
-    514, 54, 26085, 514, 55, 26085, 514, 56, 26085, 514, 57, 26085, 770, 49,
-    48, 26085, 770, 49, 49, 26085, 770, 49, 50, 26085, 770, 49, 51, 26085,
-    770, 49, 52, 26085, 770, 49, 53, 26085, 770, 49, 54, 26085, 770, 49, 55,
-    26085, 770, 49, 56, 26085, 770, 49, 57, 26085, 770, 50, 48, 26085, 770,
-    50, 49, 26085, 770, 50, 50, 26085, 770, 50, 51, 26085, 770, 50, 52,
-    26085, 770, 50, 53, 26085, 770, 50, 54, 26085, 770, 50, 55, 26085, 770,
-    50, 56, 26085, 770, 50, 57, 26085, 770, 51, 48, 26085, 770, 51, 49,
-    26085, 778, 103, 97, 108, 259, 1098, 259, 1100, 259, 42863, 259, 294,
-    259, 339, 259, 42791, 259, 43831, 259, 619, 259, 43858, 256, 35912, 256,
-    26356, 256, 36554, 256, 36040, 256, 28369, 256, 20018, 256, 21477, 256,
-    40860, 256, 40860, 256, 22865, 256, 37329, 256, 21895, 256, 22856, 256,
-    25078, 256, 30313, 256, 32645, 256, 34367, 256, 34746, 256, 35064, 256,
-    37007, 256, 27138, 256, 27931, 256, 28889, 256, 29662, 256, 33853, 256,
-    37226, 256, 39409, 256, 20098, 256, 21365, 256, 27396, 256, 29211, 256,
-    34349, 256, 40478, 256, 23888, 256, 28651, 256, 34253, 256, 35172, 256,
-    25289, 256, 33240, 256, 34847, 256, 24266, 256, 26391, 256, 28010, 256,
-    29436, 256, 37070, 256, 20358, 256, 20919, 256, 21214, 256, 25796, 256,
-    27347, 256, 29200, 256, 30439, 256, 32769, 256, 34310, 256, 34396, 256,
-    36335, 256, 38706, 256, 39791, 256, 40442, 256, 30860, 256, 31103, 256,
-    32160, 256, 33737, 256, 37636, 256, 40575, 256, 35542, 256, 22751, 256,
-    24324, 256, 31840, 256, 32894, 256, 29282, 256, 30922, 256, 36034, 256,
-    38647, 256, 22744, 256, 23650, 256, 27155, 256, 28122, 256, 28431, 256,
-    32047, 256, 32311, 256, 38475, 256, 21202, 256, 32907, 256, 20956, 256,
-    20940, 256, 31260, 256, 32190, 256, 33777, 256, 38517, 256, 35712, 256,
-    25295, 256, 27138, 256, 35582, 256, 20025, 256, 23527, 256, 24594, 256,
-    29575, 256, 30064, 256, 21271, 256, 30971, 256, 20415, 256, 24489, 256,
-    19981, 256, 27852, 256, 25976, 256, 32034, 256, 21443, 256, 22622, 256,
-    30465, 256, 33865, 256, 35498, 256, 27578, 256, 36784, 256, 27784, 256,
-    25342, 256, 33509, 256, 25504, 256, 30053, 256, 20142, 256, 20841, 256,
-    20937, 256, 26753, 256, 31975, 256, 33391, 256, 35538, 256, 37327, 256,
-    21237, 256, 21570, 256, 22899, 256, 24300, 256, 26053, 256, 28670, 256,
-    31018, 256, 38317, 256, 39530, 256, 40599, 256, 40654, 256, 21147, 256,
-    26310, 256, 27511, 256, 36706, 256, 24180, 256, 24976, 256, 25088, 256,
-    25754, 256, 28451, 256, 29001, 256, 29833, 256, 31178, 256, 32244, 256,
-    32879, 256, 36646, 256, 34030, 256, 36899, 256, 37706, 256, 21015, 256,
-    21155, 256, 21693, 256, 28872, 256, 35010, 256, 35498, 256, 24265, 256,
-    24565, 256, 25467, 256, 27566, 256, 31806, 256, 29557, 256, 20196, 256,
-    22265, 256, 23527, 256, 23994, 256, 24604, 256, 29618, 256, 29801, 256,
-    32666, 256, 32838, 256, 37428, 256, 38646, 256, 38728, 256, 38936, 256,
-    20363, 256, 31150, 256, 37300, 256, 38584, 256, 24801, 256, 20102, 256,
-    20698, 256, 23534, 256, 23615, 256, 26009, 256, 27138, 256, 29134, 256,
-    30274, 256, 34044, 256, 36988, 256, 40845, 256, 26248, 256, 38446, 256,
-    21129, 256, 26491, 256, 26611, 256, 27969, 256, 28316, 256, 29705, 256,
-    30041, 256, 30827, 256, 32016, 256, 39006, 256, 20845, 256, 25134, 256,
-    38520, 256, 20523, 256, 23833, 256, 28138, 256, 36650, 256, 24459, 256,
-    24900, 256, 26647, 256, 29575, 256, 38534, 256, 21033, 256, 21519, 256,
-    23653, 256, 26131, 256, 26446, 256, 26792, 256, 27877, 256, 29702, 256,
-    30178, 256, 32633, 256, 35023, 256, 35041, 256, 37324, 256, 38626, 256,
-    21311, 256, 28346, 256, 21533, 256, 29136, 256, 29848, 256, 34298, 256,
-    38563, 256, 40023, 256, 40607, 256, 26519, 256, 28107, 256, 33256, 256,
-    31435, 256, 31520, 256, 31890, 256, 29376, 256, 28825, 256, 35672, 256,
-    20160, 256, 33590, 256, 21050, 256, 20999, 256, 24230, 256, 25299, 256,
-    31958, 256, 23429, 256, 27934, 256, 26292, 256, 36667, 256, 34892, 256,
-    38477, 256, 35211, 256, 24275, 256, 20800, 256, 21952, 256, 22618, 256,
-    26228, 256, 20958, 256, 29482, 256, 30410, 256, 31036, 256, 31070, 256,
-    31077, 256, 31119, 256, 38742, 256, 31934, 256, 32701, 256, 34322, 256,
-    35576, 256, 36920, 256, 37117, 256, 39151, 256, 39164, 256, 39208, 256,
-    40372, 256, 37086, 256, 38583, 256, 20398, 256, 20711, 256, 20813, 256,
-    21193, 256, 21220, 256, 21329, 256, 21917, 256, 22022, 256, 22120, 256,
-    22592, 256, 22696, 256, 23652, 256, 23662, 256, 24724, 256, 24936, 256,
-    24974, 256, 25074, 256, 25935, 256, 26082, 256, 26257, 256, 26757, 256,
-    28023, 256, 28186, 256, 28450, 256, 29038, 256, 29227, 256, 29730, 256,
-    30865, 256, 31038, 256, 31049, 256, 31048, 256, 31056, 256, 31062, 256,
-    31069, 256, 31117, 256, 31118, 256, 31296, 256, 31361, 256, 31680, 256,
-    32244, 256, 32265, 256, 32321, 256, 32626, 256, 32773, 256, 33261, 256,
-    33401, 256, 33401, 256, 33879, 256, 35088, 256, 35222, 256, 35585, 256,
-    35641, 256, 36051, 256, 36104, 256, 36790, 256, 36920, 256, 38627, 256,
-    38911, 256, 38971, 256, 24693, 256, 55376, 57070, 256, 33304, 256, 20006,
-    256, 20917, 256, 20840, 256, 20352, 256, 20805, 256, 20864, 256, 21191,
-    256, 21242, 256, 21917, 256, 21845, 256, 21913, 256, 21986, 256, 22618,
-    256, 22707, 256, 22852, 256, 22868, 256, 23138, 256, 23336, 256, 24274,
-    256, 24281, 256, 24425, 256, 24493, 256, 24792, 256, 24910, 256, 24840,
-    256, 24974, 256, 24928, 256, 25074, 256, 25140, 256, 25540, 256, 25628,
-    256, 25682, 256, 25942, 256, 26228, 256, 26391, 256, 26395, 256, 26454,
-    256, 27513, 256, 27578, 256, 27969, 256, 28379, 256, 28363, 256, 28450,
-    256, 28702, 256, 29038, 256, 30631, 256, 29237, 256, 29359, 256, 29482,
-    256, 29809, 256, 29958, 256, 30011, 256, 30237, 256, 30239, 256, 30410,
-    256, 30427, 256, 30452, 256, 30538, 256, 30528, 256, 30924, 256, 31409,
-    256, 31680, 256, 31867, 256, 32091, 256, 32244, 256, 32574, 256, 32773,
-    256, 33618, 256, 33775, 256, 34681, 256, 35137, 256, 35206, 256, 35222,
-    256, 35519, 256, 35576, 256, 35531, 256, 35585, 256, 35582, 256, 35565,
-    256, 35641, 256, 35722, 256, 36104, 256, 36664, 256, 36978, 256, 37273,
-    256, 37494, 256, 38524, 256, 38627, 256, 38742, 256, 38875, 256, 38911,
-    256, 38923, 256, 38971, 256, 39698, 256, 40860, 256, 55370, 56394, 256,
-    55370, 56388, 256, 55372, 57301, 256, 15261, 256, 16408, 256, 16441, 256,
-    55380, 56905, 256, 55383, 56528, 256, 55391, 57043, 256, 40771, 256,
-    40846, 514, 102, 102, 514, 102, 105, 514, 102, 108, 770, 102, 102, 105,
-    770, 102, 102, 108, 514, 383, 116, 514, 115, 116, 514, 1396, 1398, 514,
-    1396, 1381, 514, 1396, 1387, 514, 1406, 1398, 514, 1396, 1389, 512, 1497,
-    1460, 512, 1522, 1463, 262, 1506, 262, 1488, 262, 1491, 262, 1492, 262,
-    1499, 262, 1500, 262, 1501, 262, 1512, 262, 1514, 262, 43, 512, 1513,
-    1473, 512, 1513, 1474, 512, 64329, 1473, 512, 64329, 1474, 512, 1488,
-    1463, 512, 1488, 1464, 512, 1488, 1468, 512, 1489, 1468, 512, 1490, 1468,
-    512, 1491, 1468, 512, 1492, 1468, 512, 1493, 1468, 512, 1494, 1468, 512,
-    1496, 1468, 512, 1497, 1468, 512, 1498, 1468, 512, 1499, 1468, 512, 1500,
-    1468, 512, 1502, 1468, 512, 1504, 1468, 512, 1505, 1468, 512, 1507, 1468,
-    512, 1508, 1468, 512, 1510, 1468, 512, 1511, 1468, 512, 1512, 1468, 512,
-    1513, 1468, 512, 1514, 1468, 512, 1493, 1465, 512, 1489, 1471, 512, 1499,
-    1471, 512, 1508, 1471, 514, 1488, 1500, 267, 1649, 268, 1649, 267, 1659,
-    268, 1659, 269, 1659, 270, 1659, 267, 1662, 268, 1662, 269, 1662, 270,
-    1662, 267, 1664, 268, 1664, 269, 1664, 270, 1664, 267, 1658, 268, 1658,
-    269, 1658, 270, 1658, 267, 1663, 268, 1663, 269, 1663, 270, 1663, 267,
-    1657, 268, 1657, 269, 1657, 270, 1657, 267, 1700, 268, 1700, 269, 1700,
-    270, 1700, 267, 1702, 268, 1702, 269, 1702, 270, 1702, 267, 1668, 268,
-    1668, 269, 1668, 270, 1668, 267, 1667, 268, 1667, 269, 1667, 270, 1667,
-    267, 1670, 268, 1670, 269, 1670, 270, 1670, 267, 1671, 268, 1671, 269,
-    1671, 270, 1671, 267, 1677, 268, 1677, 267, 1676, 268, 1676, 267, 1678,
-    268, 1678, 267, 1672, 268, 1672, 267, 1688, 268, 1688, 267, 1681, 268,
-    1681, 267, 1705, 268, 1705, 269, 1705, 270, 1705, 267, 1711, 268, 1711,
-    269, 1711, 270, 1711, 267, 1715, 268, 1715, 269, 1715, 270, 1715, 267,
-    1713, 268, 1713, 269, 1713, 270, 1713, 267, 1722, 268, 1722, 267, 1723,
-    268, 1723, 269, 1723, 270, 1723, 267, 1728, 268, 1728, 267, 1729, 268,
-    1729, 269, 1729, 270, 1729, 267, 1726, 268, 1726, 269, 1726, 270, 1726,
-    267, 1746, 268, 1746, 267, 1747, 268, 1747, 267, 1709, 268, 1709, 269,
-    1709, 270, 1709, 267, 1735, 268, 1735, 267, 1734, 268, 1734, 267, 1736,
-    268, 1736, 267, 1655, 267, 1739, 268, 1739, 267, 1733, 268, 1733, 267,
-    1737, 268, 1737, 267, 1744, 268, 1744, 269, 1744, 270, 1744, 269, 1609,
-    270, 1609, 523, 1574, 1575, 524, 1574, 1575, 523, 1574, 1749, 524, 1574,
-    1749, 523, 1574, 1608, 524, 1574, 1608, 523, 1574, 1735, 524, 1574, 1735,
-    523, 1574, 1734, 524, 1574, 1734, 523, 1574, 1736, 524, 1574, 1736, 523,
-    1574, 1744, 524, 1574, 1744, 525, 1574, 1744, 523, 1574, 1609, 524, 1574,
-    1609, 525, 1574, 1609, 267, 1740, 268, 1740, 269, 1740, 270, 1740, 523,
-    1574, 1580, 523, 1574, 1581, 523, 1574, 1605, 523, 1574, 1609, 523, 1574,
-    1610, 523, 1576, 1580, 523, 1576, 1581, 523, 1576, 1582, 523, 1576, 1605,
-    523, 1576, 1609, 523, 1576, 1610, 523, 1578, 1580, 523, 1578, 1581, 523,
-    1578, 1582, 523, 1578, 1605, 523, 1578, 1609, 523, 1578, 1610, 523, 1579,
-    1580, 523, 1579, 1605, 523, 1579, 1609, 523, 1579, 1610, 523, 1580, 1581,
-    523, 1580, 1605, 523, 1581, 1580, 523, 1581, 1605, 523, 1582, 1580, 523,
-    1582, 1581, 523, 1582, 1605, 523, 1587, 1580, 523, 1587, 1581, 523, 1587,
-    1582, 523, 1587, 1605, 523, 1589, 1581, 523, 1589, 1605, 523, 1590, 1580,
-    523, 1590, 1581, 523, 1590, 1582, 523, 1590, 1605, 523, 1591, 1581, 523,
-    1591, 1605, 523, 1592, 1605, 523, 1593, 1580, 523, 1593, 1605, 523, 1594,
-    1580, 523, 1594, 1605, 523, 1601, 1580, 523, 1601, 1581, 523, 1601, 1582,
-    523, 1601, 1605, 523, 1601, 1609, 523, 1601, 1610, 523, 1602, 1581, 523,
-    1602, 1605, 523, 1602, 1609, 523, 1602, 1610, 523, 1603, 1575, 523, 1603,
-    1580, 523, 1603, 1581, 523, 1603, 1582, 523, 1603, 1604, 523, 1603, 1605,
-    523, 1603, 1609, 523, 1603, 1610, 523, 1604, 1580, 523, 1604, 1581, 523,
-    1604, 1582, 523, 1604, 1605, 523, 1604, 1609, 523, 1604, 1610, 523, 1605,
-    1580, 523, 1605, 1581, 523, 1605, 1582, 523, 1605, 1605, 523, 1605, 1609,
-    523, 1605, 1610, 523, 1606, 1580, 523, 1606, 1581, 523, 1606, 1582, 523,
-    1606, 1605, 523, 1606, 1609, 523, 1606, 1610, 523, 1607, 1580, 523, 1607,
-    1605, 523, 1607, 1609, 523, 1607, 1610, 523, 1610, 1580, 523, 1610, 1581,
-    523, 1610, 1582, 523, 1610, 1605, 523, 1610, 1609, 523, 1610, 1610, 523,
-    1584, 1648, 523, 1585, 1648, 523, 1609, 1648, 779, 32, 1612, 1617, 779,
-    32, 1613, 1617, 779, 32, 1614, 1617, 779, 32, 1615, 1617, 779, 32, 1616,
-    1617, 779, 32, 1617, 1648, 524, 1574, 1585, 524, 1574, 1586, 524, 1574,
-    1605, 524, 1574, 1606, 524, 1574, 1609, 524, 1574, 1610, 524, 1576, 1585,
-    524, 1576, 1586, 524, 1576, 1605, 524, 1576, 1606, 524, 1576, 1609, 524,
-    1576, 1610, 524, 1578, 1585, 524, 1578, 1586, 524, 1578, 1605, 524, 1578,
-    1606, 524, 1578, 1609, 524, 1578, 1610, 524, 1579, 1585, 524, 1579, 1586,
-    524, 1579, 1605, 524, 1579, 1606, 524, 1579, 1609, 524, 1579, 1610, 524,
-    1601, 1609, 524, 1601, 1610, 524, 1602, 1609, 524, 1602, 1610, 524, 1603,
-    1575, 524, 1603, 1604, 524, 1603, 1605, 524, 1603, 1609, 524, 1603, 1610,
-    524, 1604, 1605, 524, 1604, 1609, 524, 1604, 1610, 524, 1605, 1575, 524,
-    1605, 1605, 524, 1606, 1585, 524, 1606, 1586, 524, 1606, 1605, 524, 1606,
-    1606, 524, 1606, 1609, 524, 1606, 1610, 524, 1609, 1648, 524, 1610, 1585,
-    524, 1610, 1586, 524, 1610, 1605, 524, 1610, 1606, 524, 1610, 1609, 524,
-    1610, 1610, 525, 1574, 1580, 525, 1574, 1581, 525, 1574, 1582, 525, 1574,
-    1605, 525, 1574, 1607, 525, 1576, 1580, 525, 1576, 1581, 525, 1576, 1582,
-    525, 1576, 1605, 525, 1576, 1607, 525, 1578, 1580, 525, 1578, 1581, 525,
-    1578, 1582, 525, 1578, 1605, 525, 1578, 1607, 525, 1579, 1605, 525, 1580,
-    1581, 525, 1580, 1605, 525, 1581, 1580, 525, 1581, 1605, 525, 1582, 1580,
-    525, 1582, 1605, 525, 1587, 1580, 525, 1587, 1581, 525, 1587, 1582, 525,
-    1587, 1605, 525, 1589, 1581, 525, 1589, 1582, 525, 1589, 1605, 525, 1590,
-    1580, 525, 1590, 1581, 525, 1590, 1582, 525, 1590, 1605, 525, 1591, 1581,
-    525, 1592, 1605, 525, 1593, 1580, 525, 1593, 1605, 525, 1594, 1580, 525,
-    1594, 1605, 525, 1601, 1580, 525, 1601, 1581, 525, 1601, 1582, 525, 1601,
-    1605, 525, 1602, 1581, 525, 1602, 1605, 525, 1603, 1580, 525, 1603, 1581,
-    525, 1603, 1582, 525, 1603, 1604, 525, 1603, 1605, 525, 1604, 1580, 525,
-    1604, 1581, 525, 1604, 1582, 525, 1604, 1605, 525, 1604, 1607, 525, 1605,
-    1580, 525, 1605, 1581, 525, 1605, 1582, 525, 1605, 1605, 525, 1606, 1580,
-    525, 1606, 1581, 525, 1606, 1582, 525, 1606, 1605, 525, 1606, 1607, 525,
-    1607, 1580, 525, 1607, 1605, 525, 1607, 1648, 525, 1610, 1580, 525, 1610,
-    1581, 525, 1610, 1582, 525, 1610, 1605, 525, 1610, 1607, 526, 1574, 1605,
-    526, 1574, 1607, 526, 1576, 1605, 526, 1576, 1607, 526, 1578, 1605, 526,
-    1578, 1607, 526, 1579, 1605, 526, 1579, 1607, 526, 1587, 1605, 526, 1587,
-    1607, 526, 1588, 1605, 526, 1588, 1607, 526, 1603, 1604, 526, 1603, 1605,
-    526, 1604, 1605, 526, 1606, 1605, 526, 1606, 1607, 526, 1610, 1605, 526,
-    1610, 1607, 782, 1600, 1614, 1617, 782, 1600, 1615, 1617, 782, 1600,
-    1616, 1617, 523, 1591, 1609, 523, 1591, 1610, 523, 1593, 1609, 523, 1593,
-    1610, 523, 1594, 1609, 523, 1594, 1610, 523, 1587, 1609, 523, 1587, 1610,
-    523, 1588, 1609, 523, 1588, 1610, 523, 1581, 1609, 523, 1581, 1610, 523,
-    1580, 1609, 523, 1580, 1610, 523, 1582, 1609, 523, 1582, 1610, 523, 1589,
-    1609, 523, 1589, 1610, 523, 1590, 1609, 523, 1590, 1610, 523, 1588, 1580,
-    523, 1588, 1581, 523, 1588, 1582, 523, 1588, 1605, 523, 1588, 1585, 523,
-    1587, 1585, 523, 1589, 1585, 523, 1590, 1585, 524, 1591, 1609, 524, 1591,
-    1610, 524, 1593, 1609, 524, 1593, 1610, 524, 1594, 1609, 524, 1594, 1610,
-    524, 1587, 1609, 524, 1587, 1610, 524, 1588, 1609, 524, 1588, 1610, 524,
-    1581, 1609, 524, 1581, 1610, 524, 1580, 1609, 524, 1580, 1610, 524, 1582,
-    1609, 524, 1582, 1610, 524, 1589, 1609, 524, 1589, 1610, 524, 1590, 1609,
-    524, 1590, 1610, 524, 1588, 1580, 524, 1588, 1581, 524, 1588, 1582, 524,
-    1588, 1605, 524, 1588, 1585, 524, 1587, 1585, 524, 1589, 1585, 524, 1590,
-    1585, 525, 1588, 1580, 525, 1588, 1581, 525, 1588, 1582, 525, 1588, 1605,
-    525, 1587, 1607, 525, 1588, 1607, 525, 1591, 1605, 526, 1587, 1580, 526,
-    1587, 1581, 526, 1587, 1582, 526, 1588, 1580, 526, 1588, 1581, 526, 1588,
-    1582, 526, 1591, 1605, 526, 1592, 1605, 524, 1575, 1611, 523, 1575, 1611,
-    781, 1578, 1580, 1605, 780, 1578, 1581, 1580, 781, 1578, 1581, 1580, 781,
-    1578, 1581, 1605, 781, 1578, 1582, 1605, 781, 1578, 1605, 1580, 781,
-    1578, 1605, 1581, 781, 1578, 1605, 1582, 780, 1580, 1605, 1581, 781,
-    1580, 1605, 1581, 780, 1581, 1605, 1610, 780, 1581, 1605, 1609, 781,
-    1587, 1581, 1580, 781, 1587, 1580, 1581, 780, 1587, 1580, 1609, 780,
-    1587, 1605, 1581, 781, 1587, 1605, 1581, 781, 1587, 1605, 1580, 780,
-    1587, 1605, 1605, 781, 1587, 1605, 1605, 780, 1589, 1581, 1581, 781,
-    1589, 1581, 1581, 780, 1589, 1605, 1605, 780, 1588, 1581, 1605, 781,
-    1588, 1581, 1605, 780, 1588, 1580, 1610, 780, 1588, 1605, 1582, 781,
-    1588, 1605, 1582, 780, 1588, 1605, 1605, 781, 1588, 1605, 1605, 780,
-    1590, 1581, 1609, 780, 1590, 1582, 1605, 781, 1590, 1582, 1605, 780,
-    1591, 1605, 1581, 781, 1591, 1605, 1581, 781, 1591, 1605, 1605, 780,
-    1591, 1605, 1610, 780, 1593, 1580, 1605, 780, 1593, 1605, 1605, 781,
-    1593, 1605, 1605, 780, 1593, 1605, 1609, 780, 1594, 1605, 1605, 780,
-    1594, 1605, 1610, 780, 1594, 1605, 1609, 780, 1601, 1582, 1605, 781,
-    1601, 1582, 1605, 780, 1602, 1605, 1581, 780, 1602, 1605, 1605, 780,
-    1604, 1581, 1605, 780, 1604, 1581, 1610, 780, 1604, 1581, 1609, 781,
-    1604, 1580, 1580, 780, 1604, 1580, 1580, 780, 1604, 1582, 1605, 781,
-    1604, 1582, 1605, 780, 1604, 1605, 1581, 781, 1604, 1605, 1581, 781,
-    1605, 1581, 1580, 781, 1605, 1581, 1605, 780, 1605, 1581, 1610, 781,
-    1605, 1580, 1581, 781, 1605, 1580, 1605, 781, 1605, 1582, 1580, 781,
-    1605, 1582, 1605, 781, 1605, 1580, 1582, 781, 1607, 1605, 1580, 781,
-    1607, 1605, 1605, 781, 1606, 1581, 1605, 780, 1606, 1581, 1609, 780,
-    1606, 1580, 1605, 781, 1606, 1580, 1605, 780, 1606, 1580, 1609, 780,
-    1606, 1605, 1610, 780, 1606, 1605, 1609, 780, 1610, 1605, 1605, 781,
-    1610, 1605, 1605, 780, 1576, 1582, 1610, 780, 1578, 1580, 1610, 780,
-    1578, 1580, 1609, 780, 1578, 1582, 1610, 780, 1578, 1582, 1609, 780,
-    1578, 1605, 1610, 780, 1578, 1605, 1609, 780, 1580, 1605, 1610, 780,
-    1580, 1581, 1609, 780, 1580, 1605, 1609, 780, 1587, 1582, 1609, 780,
-    1589, 1581, 1610, 780, 1588, 1581, 1610, 780, 1590, 1581, 1610, 780,
-    1604, 1580, 1610, 780, 1604, 1605, 1610, 780, 1610, 1581, 1610, 780,
-    1610, 1580, 1610, 780, 1610, 1605, 1610, 780, 1605, 1605, 1610, 780,
-    1602, 1605, 1610, 780, 1606, 1581, 1610, 781, 1602, 1605, 1581, 781,
-    1604, 1581, 1605, 780, 1593, 1605, 1610, 780, 1603, 1605, 1610, 781,
-    1606, 1580, 1581, 780, 1605, 1582, 1610, 781, 1604, 1580, 1605, 780,
-    1603, 1605, 1605, 780, 1604, 1580, 1605, 780, 1606, 1580, 1581, 780,
-    1580, 1581, 1610, 780, 1581, 1580, 1610, 780, 1605, 1580, 1610, 780,
-    1601, 1605, 1610, 780, 1576, 1581, 1610, 781, 1603, 1605, 1605, 781,
-    1593, 1580, 1605, 781, 1589, 1605, 1605, 780, 1587, 1582, 1610, 780,
-    1606, 1580, 1610, 779, 1589, 1604, 1746, 779, 1602, 1604, 1746, 1035,
-    1575, 1604, 1604, 1607, 1035, 1575, 1603, 1576, 1585, 1035, 1605, 1581,
-    1605, 1583, 1035, 1589, 1604, 1593, 1605, 1035, 1585, 1587, 1608, 1604,
-    1035, 1593, 1604, 1610, 1607, 1035, 1608, 1587, 1604, 1605, 779, 1589,
-    1604, 1609, 4619, 1589, 1604, 1609, 32, 1575, 1604, 1604, 1607, 32, 1593,
-    1604, 1610, 1607, 32, 1608, 1587, 1604, 1605, 2059, 1580, 1604, 32, 1580,
-    1604, 1575, 1604, 1607, 1035, 1585, 1740, 1575, 1604, 265, 44, 265,
-    12289, 265, 12290, 265, 58, 265, 59, 265, 33, 265, 63, 265, 12310, 265,
-    12311, 265, 8230, 265, 8229, 265, 8212, 265, 8211, 265, 95, 265, 95, 265,
-    40, 265, 41, 265, 123, 265, 125, 265, 12308, 265, 12309, 265, 12304, 265,
-    12305, 265, 12298, 265, 12299, 265, 12296, 265, 12297, 265, 12300, 265,
-    12301, 265, 12302, 265, 12303, 265, 91, 265, 93, 258, 8254, 258, 8254,
-    258, 8254, 258, 8254, 258, 95, 258, 95, 258, 95, 271, 44, 271, 12289,
-    271, 46, 271, 59, 271, 58, 271, 63, 271, 33, 271, 8212, 271, 40, 271, 41,
-    271, 123, 271, 125, 271, 12308, 271, 12309, 271, 35, 271, 38, 271, 42,
-    271, 43, 271, 45, 271, 60, 271, 62, 271, 61, 271, 92, 271, 36, 271, 37,
-    271, 64, 523, 32, 1611, 526, 1600, 1611, 523, 32, 1612, 523, 32, 1613,
-    523, 32, 1614, 526, 1600, 1614, 523, 32, 1615, 526, 1600, 1615, 523, 32,
-    1616, 526, 1600, 1616, 523, 32, 1617, 526, 1600, 1617, 523, 32, 1618,
-    526, 1600, 1618, 267, 1569, 267, 1570, 268, 1570, 267, 1571, 268, 1571,
-    267, 1572, 268, 1572, 267, 1573, 268, 1573, 267, 1574, 268, 1574, 269,
-    1574, 270, 1574, 267, 1575, 268, 1575, 267, 1576, 268, 1576, 269, 1576,
-    270, 1576, 267, 1577, 268, 1577, 267, 1578, 268, 1578, 269, 1578, 270,
-    1578, 267, 1579, 268, 1579, 269, 1579, 270, 1579, 267, 1580, 268, 1580,
-    269, 1580, 270, 1580, 267, 1581, 268, 1581, 269, 1581, 270, 1581, 267,
-    1582, 268, 1582, 269, 1582, 270, 1582, 267, 1583, 268, 1583, 267, 1584,
-    268, 1584, 267, 1585, 268, 1585, 267, 1586, 268, 1586, 267, 1587, 268,
-    1587, 269, 1587, 270, 1587, 267, 1588, 268, 1588, 269, 1588, 270, 1588,
-    267, 1589, 268, 1589, 269, 1589, 270, 1589, 267, 1590, 268, 1590, 269,
-    1590, 270, 1590, 267, 1591, 268, 1591, 269, 1591, 270, 1591, 267, 1592,
-    268, 1592, 269, 1592, 270, 1592, 267, 1593, 268, 1593, 269, 1593, 270,
-    1593, 267, 1594, 268, 1594, 269, 1594, 270, 1594, 267, 1601, 268, 1601,
-    269, 1601, 270, 1601, 267, 1602, 268, 1602, 269, 1602, 270, 1602, 267,
-    1603, 268, 1603, 269, 1603, 270, 1603, 267, 1604, 268, 1604, 269, 1604,
-    270, 1604, 267, 1605, 268, 1605, 269, 1605, 270, 1605, 267, 1606, 268,
-    1606, 269, 1606, 270, 1606, 267, 1607, 268, 1607, 269, 1607, 270, 1607,
-    267, 1608, 268, 1608, 267, 1609, 268, 1609, 267, 1610, 268, 1610, 269,
-    1610, 270, 1610, 523, 1604, 1570, 524, 1604, 1570, 523, 1604, 1571, 524,
-    1604, 1571, 523, 1604, 1573, 524, 1604, 1573, 523, 1604, 1575, 524, 1604,
-    1575, 264, 33, 264, 34, 264, 35, 264, 36, 264, 37, 264, 38, 264, 39, 264,
-    40, 264, 41, 264, 42, 264, 43, 264, 44, 264, 45, 264, 46, 264, 47, 264,
-    48, 264, 49, 264, 50, 264, 51, 264, 52, 264, 53, 264, 54, 264, 55, 264,
-    56, 264, 57, 264, 58, 264, 59, 264, 60, 264, 61, 264, 62, 264, 63, 264,
-    64, 264, 65, 264, 66, 264, 67, 264, 68, 264, 69, 264, 70, 264, 71, 264,
-    72, 264, 73, 264, 74, 264, 75, 264, 76, 264, 77, 264, 78, 264, 79, 264,
-    80, 264, 81, 264, 82, 264, 83, 264, 84, 264, 85, 264, 86, 264, 87, 264,
-    88, 264, 89, 264, 90, 264, 91, 264, 92, 264, 93, 264, 94, 264, 95, 264,
-    96, 264, 97, 264, 98, 264, 99, 264, 100, 264, 101, 264, 102, 264, 103,
-    264, 104, 264, 105, 264, 106, 264, 107, 264, 108, 264, 109, 264, 110,
-    264, 111, 264, 112, 264, 113, 264, 114, 264, 115, 264, 116, 264, 117,
-    264, 118, 264, 119, 264, 120, 264, 121, 264, 122, 264, 123, 264, 124,
-    264, 125, 264, 126, 264, 10629, 264, 10630, 272, 12290, 272, 12300, 272,
-    12301, 272, 12289, 272, 12539, 272, 12530, 272, 12449, 272, 12451, 272,
-    12453, 272, 12455, 272, 12457, 272, 12515, 272, 12517, 272, 12519, 272,
-    12483, 272, 12540, 272, 12450, 272, 12452, 272, 12454, 272, 12456, 272,
-    12458, 272, 12459, 272, 12461, 272, 12463, 272, 12465, 272, 12467, 272,
-    12469, 272, 12471, 272, 12473, 272, 12475, 272, 12477, 272, 12479, 272,
-    12481, 272, 12484, 272, 12486, 272, 12488, 272, 12490, 272, 12491, 272,
-    12492, 272, 12493, 272, 12494, 272, 12495, 272, 12498, 272, 12501, 272,
-    12504, 272, 12507, 272, 12510, 272, 12511, 272, 12512, 272, 12513, 272,
-    12514, 272, 12516, 272, 12518, 272, 12520, 272, 12521, 272, 12522, 272,
-    12523, 272, 12524, 272, 12525, 272, 12527, 272, 12531, 272, 12441, 272,
-    12442, 272, 12644, 272, 12593, 272, 12594, 272, 12595, 272, 12596, 272,
-    12597, 272, 12598, 272, 12599, 272, 12600, 272, 12601, 272, 12602, 272,
-    12603, 272, 12604, 272, 12605, 272, 12606, 272, 12607, 272, 12608, 272,
-    12609, 272, 12610, 272, 12611, 272, 12612, 272, 12613, 272, 12614, 272,
-    12615, 272, 12616, 272, 12617, 272, 12618, 272, 12619, 272, 12620, 272,
-    12621, 272, 12622, 272, 12623, 272, 12624, 272, 12625, 272, 12626, 272,
-    12627, 272, 12628, 272, 12629, 272, 12630, 272, 12631, 272, 12632, 272,
-    12633, 272, 12634, 272, 12635, 272, 12636, 272, 12637, 272, 12638, 272,
-    12639, 272, 12640, 272, 12641, 272, 12642, 272, 12643, 264, 162, 264,
-    163, 264, 172, 264, 175, 264, 166, 264, 165, 264, 8361, 272, 9474, 272,
-    8592, 272, 8593, 272, 8594, 272, 8595, 272, 9632, 272, 9675, 512, 55300,
-    56473, 55300, 56506, 512, 55300, 56475, 55300, 56506, 512, 55300, 56485,
-    55300, 56506, 512, 55300, 56625, 55300, 56615, 512, 55300, 56626, 55300,
-    56615, 512, 55300, 57159, 55300, 57150, 512, 55300, 57159, 55300, 57175,
-    512, 55301, 56505, 55301, 56506, 512, 55301, 56505, 55301, 56496, 512,
-    55301, 56505, 55301, 56509, 512, 55301, 56760, 55301, 56751, 512, 55301,
-    56761, 55301, 56751, 512, 55348, 56663, 55348, 56677, 512, 55348, 56664,
-    55348, 56677, 512, 55348, 56671, 55348, 56686, 512, 55348, 56671, 55348,
-    56687, 512, 55348, 56671, 55348, 56688, 512, 55348, 56671, 55348, 56689,
-    512, 55348, 56671, 55348, 56690, 512, 55348, 56761, 55348, 56677, 512,
-    55348, 56762, 55348, 56677, 512, 55348, 56763, 55348, 56686, 512, 55348,
-    56764, 55348, 56686, 512, 55348, 56763, 55348, 56687, 512, 55348, 56764,
-    55348, 56687, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262,
-    71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262,
-    79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262,
-    87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262,
-    101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262,
-    108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262,
-    115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262,
-    122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262,
-    72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262,
-    80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262,
-    88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262,
-    102, 262, 103, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262,
-    110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262,
-    117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66,
-    262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74,
-    262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82,
-    262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90,
-    262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262,
-    104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262,
-    111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262,
-    118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 67, 262, 68,
-    262, 71, 262, 74, 262, 75, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83,
-    262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97,
-    262, 98, 262, 99, 262, 100, 262, 102, 262, 104, 262, 105, 262, 106, 262,
-    107, 262, 108, 262, 109, 262, 110, 262, 112, 262, 113, 262, 114, 262,
-    115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262,
-    122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262,
-    72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262,
-    80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262,
-    88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262,
-    102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262,
-    109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262,
-    116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65,
-    262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 74, 262, 75, 262, 76,
-    262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, 262, 84, 262, 85,
-    262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100,
-    262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107,
-    262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114,
-    262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121,
-    262, 122, 262, 65, 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 73,
-    262, 74, 262, 75, 262, 76, 262, 77, 262, 79, 262, 83, 262, 84, 262, 85,
-    262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100,
-    262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107,
-    262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114,
-    262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121,
-    262, 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71,
-    262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79,
-    262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87,
-    262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101,
-    262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108,
-    262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115,
-    262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122,
-    262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72,
-    262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80,
-    262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88,
-    262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262,
-    102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262,
-    109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262,
-    116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65,
-    262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73,
-    262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81,
-    262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89,
-    262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262,
-    103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262,
-    110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262,
-    117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66,
-    262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74,
-    262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82,
-    262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90,
-    262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262,
-    104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262,
-    111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262,
-    118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67,
-    262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75,
-    262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83,
-    262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97,
-    262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262,
-    105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262,
-    112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262,
-    119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, 262, 68,
-    262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76,
-    262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84,
-    262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98,
-    262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262,
-    106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262,
-    113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262,
-    120, 262, 121, 262, 122, 262, 305, 262, 567, 262, 913, 262, 914, 262,
-    915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262,
-    922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262,
-    929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262,
-    936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262,
-    949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262,
-    956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262,
-    963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262,
-    8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262,
-    913, 262, 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262,
-    920, 262, 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262,
-    927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262,
-    934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262,
-    947, 262, 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262,
-    954, 262, 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262,
-    961, 262, 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262,
-    968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262,
-    1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, 916, 262, 917, 262,
-    918, 262, 919, 262, 920, 262, 921, 262, 922, 262, 923, 262, 924, 262,
-    925, 262, 926, 262, 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262,
-    932, 262, 933, 262, 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262,
-    945, 262, 946, 262, 947, 262, 948, 262, 949, 262, 950, 262, 951, 262,
-    952, 262, 953, 262, 954, 262, 955, 262, 956, 262, 957, 262, 958, 262,
-    959, 262, 960, 262, 961, 262, 962, 262, 963, 262, 964, 262, 965, 262,
-    966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262,
-    1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262,
-    916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, 922, 262,
-    923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, 929, 262,
-    1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, 936, 262,
-    937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, 949, 262,
-    950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, 956, 262,
-    957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, 963, 262,
-    964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262,
-    1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262,
-    914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262,
-    921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262,
-    928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262,
-    935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262,
-    948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262,
-    955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262,
-    962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262,
-    969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262,
-    982, 262, 988, 262, 989, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52,
-    262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50,
-    262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48,
-    262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56,
-    262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54,
-    262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52,
-    262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 1575, 262, 1576, 262,
-    1580, 262, 1583, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610,
-    262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262, 1593, 262,
-    1601, 262, 1589, 262, 1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579,
-    262, 1582, 262, 1584, 262, 1590, 262, 1592, 262, 1594, 262, 1646, 262,
-    1722, 262, 1697, 262, 1647, 262, 1576, 262, 1580, 262, 1607, 262, 1581,
-    262, 1610, 262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262,
-    1593, 262, 1601, 262, 1589, 262, 1602, 262, 1588, 262, 1578, 262, 1579,
-    262, 1582, 262, 1590, 262, 1594, 262, 1580, 262, 1581, 262, 1610, 262,
-    1604, 262, 1606, 262, 1587, 262, 1593, 262, 1589, 262, 1602, 262, 1588,
-    262, 1582, 262, 1590, 262, 1594, 262, 1722, 262, 1647, 262, 1576, 262,
-    1580, 262, 1607, 262, 1581, 262, 1591, 262, 1610, 262, 1603, 262, 1605,
-    262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262,
-    1588, 262, 1578, 262, 1579, 262, 1582, 262, 1590, 262, 1592, 262, 1594,
-    262, 1646, 262, 1697, 262, 1575, 262, 1576, 262, 1580, 262, 1583, 262,
-    1607, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604,
-    262, 1605, 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262,
-    1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584,
-    262, 1590, 262, 1592, 262, 1594, 262, 1576, 262, 1580, 262, 1583, 262,
-    1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604, 262, 1605,
-    262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262,
-    1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584, 262, 1590,
-    262, 1592, 262, 1594, 514, 48, 46, 514, 48, 44, 514, 49, 44, 514, 50, 44,
-    514, 51, 44, 514, 52, 44, 514, 53, 44, 514, 54, 44, 514, 55, 44, 514, 56,
-    44, 514, 57, 44, 770, 40, 65, 41, 770, 40, 66, 41, 770, 40, 67, 41, 770,
-    40, 68, 41, 770, 40, 69, 41, 770, 40, 70, 41, 770, 40, 71, 41, 770, 40,
-    72, 41, 770, 40, 73, 41, 770, 40, 74, 41, 770, 40, 75, 41, 770, 40, 76,
-    41, 770, 40, 77, 41, 770, 40, 78, 41, 770, 40, 79, 41, 770, 40, 80, 41,
-    770, 40, 81, 41, 770, 40, 82, 41, 770, 40, 83, 41, 770, 40, 84, 41, 770,
-    40, 85, 41, 770, 40, 86, 41, 770, 40, 87, 41, 770, 40, 88, 41, 770, 40,
-    89, 41, 770, 40, 90, 41, 770, 12308, 83, 12309, 263, 67, 263, 82, 519,
-    67, 68, 519, 87, 90, 266, 65, 266, 66, 266, 67, 266, 68, 266, 69, 266,
-    70, 266, 71, 266, 72, 266, 73, 266, 74, 266, 75, 266, 76, 266, 77, 266,
-    78, 266, 79, 266, 80, 266, 81, 266, 82, 266, 83, 266, 84, 266, 85, 266,
-    86, 266, 87, 266, 88, 266, 89, 266, 90, 522, 72, 86, 522, 77, 86, 522,
-    83, 68, 522, 83, 83, 778, 80, 80, 86, 522, 87, 67, 515, 77, 67, 515, 77,
-    68, 522, 68, 74, 522, 12411, 12363, 522, 12467, 12467, 266, 12469, 266,
-    25163, 266, 23383, 266, 21452, 266, 12487, 266, 20108, 266, 22810, 266,
-    35299, 266, 22825, 266, 20132, 266, 26144, 266, 28961, 266, 26009, 266,
-    21069, 266, 24460, 266, 20877, 266, 26032, 266, 21021, 266, 32066, 266,
-    29983, 266, 36009, 266, 22768, 266, 21561, 266, 28436, 266, 25237, 266,
-    25429, 266, 19968, 266, 19977, 266, 36938, 266, 24038, 266, 20013, 266,
-    21491, 266, 25351, 266, 36208, 266, 25171, 266, 31105, 266, 31354, 266,
-    21512, 266, 28288, 266, 26377, 266, 26376, 266, 30003, 266, 21106, 266,
-    21942, 266, 37197, 770, 12308, 26412, 12309, 770, 12308, 19977, 12309,
-    770, 12308, 20108, 12309, 770, 12308, 23433, 12309, 770, 12308, 28857,
-    12309, 770, 12308, 25171, 12309, 770, 12308, 30423, 12309, 770, 12308,
-    21213, 12309, 770, 12308, 25943, 12309, 263, 24471, 263, 21487, 256,
-    20029, 256, 20024, 256, 20033, 256, 55360, 56610, 256, 20320, 256, 20398,
-    256, 20411, 256, 20482, 256, 20602, 256, 20633, 256, 20711, 256, 20687,
-    256, 13470, 256, 55361, 56890, 256, 20813, 256, 20820, 256, 20836, 256,
-    20855, 256, 55361, 56604, 256, 13497, 256, 20839, 256, 20877, 256, 55361,
-    56651, 256, 20887, 256, 20900, 256, 20172, 256, 20908, 256, 20917, 256,
-    55396, 56799, 256, 20981, 256, 20995, 256, 13535, 256, 21051, 256, 21062,
-    256, 21106, 256, 21111, 256, 13589, 256, 21191, 256, 21193, 256, 21220,
-    256, 21242, 256, 21253, 256, 21254, 256, 21271, 256, 21321, 256, 21329,
-    256, 21338, 256, 21363, 256, 21373, 256, 21375, 256, 21375, 256, 21375,
-    256, 55362, 56876, 256, 28784, 256, 21450, 256, 21471, 256, 55362, 57187,
-    256, 21483, 256, 21489, 256, 21510, 256, 21662, 256, 21560, 256, 21576,
-    256, 21608, 256, 21666, 256, 21750, 256, 21776, 256, 21843, 256, 21859,
-    256, 21892, 256, 21892, 256, 21913, 256, 21931, 256, 21939, 256, 21954,
-    256, 22294, 256, 22022, 256, 22295, 256, 22097, 256, 22132, 256, 20999,
-    256, 22766, 256, 22478, 256, 22516, 256, 22541, 256, 22411, 256, 22578,
-    256, 22577, 256, 22700, 256, 55365, 56548, 256, 22770, 256, 22775, 256,
-    22790, 256, 22810, 256, 22818, 256, 22882, 256, 55365, 57000, 256, 55365,
-    57066, 256, 23020, 256, 23067, 256, 23079, 256, 23000, 256, 23142, 256,
-    14062, 256, 14076, 256, 23304, 256, 23358, 256, 23358, 256, 55366, 56776,
-    256, 23491, 256, 23512, 256, 23527, 256, 23539, 256, 55366, 57112, 256,
-    23551, 256, 23558, 256, 24403, 256, 23586, 256, 14209, 256, 23648, 256,
-    23662, 256, 23744, 256, 23693, 256, 55367, 56804, 256, 23875, 256, 55367,
-    56806, 256, 23918, 256, 23915, 256, 23932, 256, 24033, 256, 24034, 256,
-    14383, 256, 24061, 256, 24104, 256, 24125, 256, 24169, 256, 14434, 256,
-    55368, 56707, 256, 14460, 256, 24240, 256, 24243, 256, 24246, 256, 24266,
-    256, 55400, 57234, 256, 24318, 256, 55368, 57137, 256, 55368, 57137, 256,
-    33281, 256, 24354, 256, 24354, 256, 14535, 256, 55372, 57016, 256, 55384,
-    56794, 256, 24418, 256, 24427, 256, 14563, 256, 24474, 256, 24525, 256,
-    24535, 256, 24569, 256, 24705, 256, 14650, 256, 14620, 256, 24724, 256,
-    55369, 57044, 256, 24775, 256, 24904, 256, 24908, 256, 24910, 256, 24908,
-    256, 24954, 256, 24974, 256, 25010, 256, 24996, 256, 25007, 256, 25054,
-    256, 25074, 256, 25078, 256, 25104, 256, 25115, 256, 25181, 256, 25265,
-    256, 25300, 256, 25424, 256, 55370, 57100, 256, 25405, 256, 25340, 256,
-    25448, 256, 25475, 256, 25572, 256, 55370, 57329, 256, 25634, 256, 25541,
-    256, 25513, 256, 14894, 256, 25705, 256, 25726, 256, 25757, 256, 25719,
-    256, 14956, 256, 25935, 256, 25964, 256, 55372, 56330, 256, 26083, 256,
-    26360, 256, 26185, 256, 15129, 256, 26257, 256, 15112, 256, 15076, 256,
-    20882, 256, 20885, 256, 26368, 256, 26268, 256, 32941, 256, 17369, 256,
-    26391, 256, 26395, 256, 26401, 256, 26462, 256, 26451, 256, 55372, 57283,
-    256, 15177, 256, 26618, 256, 26501, 256, 26706, 256, 26757, 256, 55373,
-    56429, 256, 26766, 256, 26655, 256, 26900, 256, 15261, 256, 26946, 256,
-    27043, 256, 27114, 256, 27304, 256, 55373, 56995, 256, 27355, 256, 15384,
-    256, 27425, 256, 55374, 56487, 256, 27476, 256, 15438, 256, 27506, 256,
-    27551, 256, 27578, 256, 27579, 256, 55374, 56973, 256, 55367, 56587, 256,
-    55374, 57082, 256, 27726, 256, 55375, 56508, 256, 27839, 256, 27853, 256,
-    27751, 256, 27926, 256, 27966, 256, 28023, 256, 27969, 256, 28009, 256,
-    28024, 256, 28037, 256, 55375, 56606, 256, 27956, 256, 28207, 256, 28270,
-    256, 15667, 256, 28363, 256, 28359, 256, 55375, 57041, 256, 28153, 256,
-    28526, 256, 55375, 57182, 256, 55375, 57230, 256, 28614, 256, 28729, 256,
-    28702, 256, 28699, 256, 15766, 256, 28746, 256, 28797, 256, 28791, 256,
-    28845, 256, 55361, 56613, 256, 28997, 256, 55376, 56931, 256, 29084, 256,
-    55376, 57259, 256, 29224, 256, 29237, 256, 29264, 256, 55377, 56840, 256,
-    29312, 256, 29333, 256, 55377, 57141, 256, 55378, 56340, 256, 29562, 256,
-    29579, 256, 16044, 256, 29605, 256, 16056, 256, 16056, 256, 29767, 256,
-    29788, 256, 29809, 256, 29829, 256, 29898, 256, 16155, 256, 29988, 256,
-    55379, 56374, 256, 30014, 256, 55379, 56466, 256, 30064, 256, 55368,
-    56735, 256, 30224, 256, 55379, 57249, 256, 55379, 57272, 256, 55380,
-    56388, 256, 16380, 256, 16392, 256, 30452, 256, 55380, 56563, 256, 55380,
-    56562, 256, 55380, 56601, 256, 55380, 56627, 256, 30494, 256, 30495, 256,
-    30495, 256, 30538, 256, 16441, 256, 30603, 256, 16454, 256, 16534, 256,
-    55381, 56349, 256, 30798, 256, 30860, 256, 30924, 256, 16611, 256, 55381,
-    56870, 256, 31062, 256, 55381, 56986, 256, 55381, 57029, 256, 31119, 256,
-    31211, 256, 16687, 256, 31296, 256, 31306, 256, 31311, 256, 55382, 56700,
-    256, 55382, 56999, 256, 55382, 56999, 256, 31470, 256, 16898, 256, 55382,
-    57259, 256, 31686, 256, 31689, 256, 16935, 256, 55383, 56448, 256, 31954,
-    256, 17056, 256, 31976, 256, 31971, 256, 32000, 256, 55383, 57222, 256,
-    32099, 256, 17153, 256, 32199, 256, 32258, 256, 32325, 256, 17204, 256,
-    55384, 56872, 256, 55384, 56903, 256, 17241, 256, 55384, 57049, 256,
-    32634, 256, 55384, 57150, 256, 32661, 256, 32762, 256, 32773, 256, 55385,
-    56538, 256, 55385, 56611, 256, 32864, 256, 55385, 56744, 256, 32880, 256,
-    55372, 57183, 256, 17365, 256, 32946, 256, 33027, 256, 17419, 256, 33086,
-    256, 23221, 256, 55385, 57255, 256, 55385, 57269, 256, 55372, 57235, 256,
-    55372, 57244, 256, 33281, 256, 33284, 256, 36766, 256, 17515, 256, 33425,
-    256, 33419, 256, 33437, 256, 21171, 256, 33457, 256, 33459, 256, 33469,
-    256, 33510, 256, 55386, 57148, 256, 33509, 256, 33565, 256, 33635, 256,
-    33709, 256, 33571, 256, 33725, 256, 33767, 256, 33879, 256, 33619, 256,
-    33738, 256, 33740, 256, 33756, 256, 55387, 56374, 256, 55387, 56683, 256,
-    55387, 56533, 256, 17707, 256, 34033, 256, 34035, 256, 34070, 256, 55388,
-    57290, 256, 34148, 256, 55387, 57132, 256, 17757, 256, 17761, 256, 55387,
-    57265, 256, 55388, 56530, 256, 17771, 256, 34384, 256, 34396, 256, 34407,
-    256, 34409, 256, 34473, 256, 34440, 256, 34574, 256, 34530, 256, 34681,
-    256, 34600, 256, 34667, 256, 34694, 256, 17879, 256, 34785, 256, 34817,
-    256, 17913, 256, 34912, 256, 34915, 256, 55389, 56935, 256, 35031, 256,
-    35038, 256, 17973, 256, 35066, 256, 13499, 256, 55390, 56494, 256, 55390,
-    56678, 256, 18110, 256, 18119, 256, 35488, 256, 35565, 256, 35722, 256,
-    35925, 256, 55391, 56488, 256, 36011, 256, 36033, 256, 36123, 256, 36215,
-    256, 55391, 57135, 256, 55362, 56324, 256, 36299, 256, 36284, 256, 36336,
-    256, 55362, 56542, 256, 36564, 256, 36664, 256, 55393, 56786, 256, 55393,
-    56813, 256, 37012, 256, 37105, 256, 37137, 256, 55393, 57134, 256, 37147,
-    256, 37432, 256, 37591, 256, 37592, 256, 37500, 256, 37881, 256, 37909,
-    256, 55394, 57338, 256, 38283, 256, 18837, 256, 38327, 256, 55395, 56695,
-    256, 18918, 256, 38595, 256, 23986, 256, 38691, 256, 55396, 56645, 256,
-    55396, 56858, 256, 19054, 256, 19062, 256, 38880, 256, 55397, 56330, 256,
-    19122, 256, 55397, 56470, 256, 38923, 256, 38923, 256, 38953, 256, 55397,
-    56758, 256, 39138, 256, 19251, 256, 39209, 256, 39335, 256, 39362, 256,
-    39422, 256, 19406, 256, 55398, 57136, 256, 39698, 256, 40000, 256, 40189,
-    256, 19662, 256, 19693, 256, 40295, 256, 55400, 56526, 256, 19704, 256,
-    55400, 56581, 256, 55400, 56846, 256, 55400, 56977, 256, 40635, 256,
-    19798, 256, 40697, 256, 40702, 256, 40709, 256, 40719, 256, 40726, 256,
-    40763, 256, 55401, 56832,
-};
-
-/* index tables for the decomposition data */
-#define DECOMP_SHIFT1 6
-#define DECOMP_SHIFT2 4
-static const unsigned char decomp_index0[] = {
-    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 13, 14, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 15, 16, 5, 5, 5, 5, 17, 18,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19, 20,
-    5, 5, 5, 5, 5, 21, 22, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    23, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-    5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-};
-
-static const unsigned short decomp_index1[] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
-    14, 0, 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0,
-    25, 0, 26, 27, 0, 0, 0, 0, 0, 28, 0, 0, 29, 30, 31, 32, 33, 34, 35, 0,
-    36, 37, 38, 0, 39, 0, 40, 0, 41, 0, 0, 0, 0, 42, 43, 44, 45, 0, 0, 0, 0,
-    0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 48, 0, 0, 0,
-    0, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 0, 53, 0, 0, 0, 0,
-    0, 0, 54, 55, 0, 0, 0, 0, 0, 56, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 58, 59, 0, 0, 0, 60, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
-    0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0,
-    0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 67, 0, 68, 0, 0, 69, 0, 0, 0, 70,
-    71, 72, 73, 74, 75, 76, 77, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 81, 0,
-    82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 84, 85, 86, 87, 88, 89, 0, 90, 91, 92, 0, 0, 0, 0,
-    93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
-    109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
-    123, 124, 125, 126, 127, 128, 129, 130, 0, 131, 132, 133, 134, 0, 0, 0,
-    0, 0, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 0, 146, 0,
-    0, 0, 147, 0, 148, 149, 150, 0, 151, 152, 153, 0, 154, 0, 0, 0, 155, 0,
-    0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157,
-    158, 159, 160, 161, 162, 163, 164, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0,
-    0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    171, 0, 0, 0, 0, 0, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
-    182, 183, 184, 185, 186, 0, 0, 187, 0, 0, 188, 189, 190, 191, 192, 0,
-    193, 194, 195, 196, 197, 0, 198, 0, 0, 0, 199, 200, 201, 202, 203, 204,
-    205, 0, 0, 0, 0, 0, 0, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
-    216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
-    230, 231, 232, 233, 234, 235, 236, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 0, 0,
-    0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 243, 244, 245, 246, 247,
-    248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261,
-    262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 0, 0, 272, 273, 274,
-    275, 276, 277, 278, 279, 280, 281, 282, 283, 0, 284, 285, 286, 287, 288,
-    289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302,
-    303, 304, 305, 306, 0, 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, 315,
-    0, 316, 0, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328,
-    329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
-    343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 0,
-    347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 352, 0, 0, 0, 0, 353, 354, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
-    365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378,
-    379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392,
-    393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406,
-    407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 431, 432, 433, 434, 435, 0, 436, 0,
-    0, 437, 0, 0, 0, 0, 0, 0, 438, 439, 440, 441, 442, 443, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 444, 445,
-    446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459,
-    460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473,
-    474, 475, 476, 477, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static const unsigned short decomp_index2[] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
-    3, 0, 6, 0, 0, 0, 0, 8, 0, 0, 11, 13, 15, 18, 0, 0, 20, 23, 25, 0, 27,
-    31, 35, 0, 39, 42, 45, 48, 51, 54, 0, 57, 60, 63, 66, 69, 72, 75, 78, 81,
-    0, 84, 87, 90, 93, 96, 99, 0, 0, 102, 105, 108, 111, 114, 0, 0, 117, 120,
-    123, 126, 129, 132, 0, 135, 138, 141, 144, 147, 150, 153, 156, 159, 0,
-    162, 165, 168, 171, 174, 177, 0, 0, 180, 183, 186, 189, 192, 0, 195, 198,
-    201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240,
-    243, 0, 0, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279,
-    282, 285, 288, 291, 294, 297, 300, 303, 0, 0, 306, 309, 312, 315, 318,
-    321, 324, 327, 330, 0, 333, 336, 339, 342, 345, 348, 0, 351, 354, 357,
-    360, 363, 366, 369, 372, 0, 0, 375, 378, 381, 384, 387, 390, 393, 0, 0,
-    396, 399, 402, 405, 408, 411, 0, 0, 414, 417, 420, 423, 426, 429, 432,
-    435, 438, 441, 444, 447, 450, 453, 456, 459, 462, 465, 0, 0, 468, 471,
-    474, 477, 480, 483, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513,
-    516, 519, 522, 525, 528, 531, 534, 537, 539, 542, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 545, 548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 551, 554, 557, 560, 563, 566, 569, 572, 575, 578, 581, 584, 587,
-    590, 593, 596, 599, 602, 605, 608, 611, 614, 617, 620, 623, 0, 626, 629,
-    632, 635, 638, 641, 0, 0, 644, 647, 650, 653, 656, 659, 662, 665, 668,
-    671, 674, 677, 680, 683, 686, 689, 0, 0, 692, 695, 698, 701, 704, 707,
-    710, 713, 716, 719, 722, 725, 728, 731, 734, 737, 740, 743, 746, 749,
-    752, 755, 758, 761, 764, 767, 770, 773, 776, 779, 782, 785, 788, 791,
-    794, 797, 0, 0, 800, 803, 0, 0, 0, 0, 0, 0, 806, 809, 812, 815, 818, 821,
-    824, 827, 830, 833, 836, 839, 842, 845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 848, 850, 852, 854, 856, 858, 860, 862, 864, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 866, 869, 872, 875, 878, 881, 0, 0, 884, 886, 888,
-    890, 892, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 894, 896, 0, 898, 900, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, 0, 0, 0, 905, 0, 0, 0,
-    908, 0, 0, 0, 0, 0, 910, 913, 916, 919, 921, 924, 927, 0, 930, 0, 933,
-    936, 939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 942, 945, 948, 951, 954, 957, 960, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 963, 966, 969, 972, 975,
-    0, 978, 980, 982, 984, 987, 990, 992, 0, 0, 0, 0, 0, 0, 0, 0, 0, 994,
-    996, 998, 0, 1000, 1002, 0, 0, 0, 1004, 0, 0, 0, 0, 0, 0, 1006, 1009, 0,
-    1012, 0, 0, 0, 1015, 0, 0, 0, 0, 1018, 1021, 1024, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 1027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0,
-    0, 0, 0, 0, 1033, 1036, 0, 1039, 0, 0, 0, 1042, 0, 0, 0, 0, 1045, 1048,
-    1051, 0, 0, 0, 0, 0, 0, 0, 1054, 1057, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1060,
-    1063, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1066, 1069, 1072, 1075, 0,
-    0, 1078, 1081, 0, 0, 1084, 1087, 1090, 1093, 1096, 1099, 0, 0, 1102,
-    1105, 1108, 1111, 1114, 1117, 0, 0, 1120, 1123, 1126, 1129, 1132, 1135,
-    1138, 1141, 1144, 1147, 1150, 1153, 0, 0, 1156, 1159, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 1162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1165, 1168,
-    1171, 1174, 1177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1180, 1183,
-    1186, 1189, 0, 0, 0, 0, 0, 0, 0, 1192, 0, 1195, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 1198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 1201, 0, 0, 0, 0, 0, 0, 0, 1204, 0, 0, 1207, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1210, 1213, 1216,
-    1219, 1222, 1225, 1228, 1231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1234,
-    1237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1240, 1243, 0, 1246,
-    0, 0, 0, 1249, 0, 0, 1252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 1255, 1258, 1261, 0, 0, 1264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1267,
-    0, 0, 1270, 1273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1276,
-    1279, 0, 0, 0, 0, 0, 0, 1282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 1285, 1288, 1291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    1294, 0, 0, 0, 0, 0, 0, 0, 1297, 0, 0, 0, 0, 0, 0, 1300, 1303, 0, 1306,
-    1309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1312, 1315, 1318, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1321, 0, 1324, 1327, 1330, 0, 0, 0, 0,
-    1333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1336, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1339, 1342, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1345, 0, 0, 0, 0, 0, 0, 1347, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 1350, 0, 0, 0, 0, 1353, 0, 0, 0, 0, 1356, 0, 0,
-    0, 0, 1359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1362, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 1365, 0, 1368, 1371, 1374, 1377, 1380, 0, 0, 0, 0, 0, 0, 0,
-    1383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1386, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 1389, 0, 0, 0, 0, 1392, 0, 0, 0, 0, 1395, 0, 0, 0, 0,
-    1398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1401, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 1404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 1407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1409, 0, 1412, 0, 1415, 0,
-    1418, 0, 1421, 0, 0, 0, 1424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1427, 0, 1430, 0, 0, 1433, 1436, 0, 1439,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    1442, 1444, 1446, 0, 1448, 1450, 1452, 1454, 1456, 1458, 1460, 1462,
-    1464, 1466, 1468, 0, 1470, 1472, 1474, 1476, 1478, 1480, 1482, 1484,
-    1486, 1488, 1490, 1492, 1494, 1496, 1498, 1500, 1502, 1504, 0, 1506,
-    1508, 1510, 1512, 1514, 1516, 1518, 1520, 1522, 1524, 1526, 1528, 1530,
-    1532, 1534, 1536, 1538, 1540, 1542, 1544, 1546, 1548, 1550, 1552, 1554,
-    1556, 1558, 1560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1562, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1564, 1566, 1568, 1570,
-    1572, 1574, 1576, 1578, 1580, 1582, 1584, 1586, 1588, 1590, 1592, 1594,
-    1596, 1598, 1600, 1602, 1604, 1606, 1608, 1610, 1612, 1614, 1616, 1618,
-    1620, 1622, 1624, 1626, 1628, 1630, 1632, 1634, 1636, 1638, 1641, 1644,
-    1647, 1650, 1653, 1656, 1659, 1662, 1665, 1668, 1671, 1674, 1677, 1680,
-    1683, 1686, 1689, 1692, 1695, 1698, 1701, 1704, 1707, 1710, 1713, 1716,
-    1719, 1722, 1725, 1728, 1731, 1734, 1737, 1740, 1743, 1746, 1749, 1752,
-    1755, 1758, 1761, 1764, 1767, 1770, 1773, 1776, 1779, 1782, 1785, 1788,
-    1791, 1794, 1797, 1800, 1803, 1806, 1809, 1812, 1815, 1818, 1821, 1824,
-    1827, 1830, 1833, 1836, 1839, 1842, 1845, 1848, 1851, 1854, 1857, 1860,
-    1863, 1866, 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896,
-    1899, 1902, 1905, 1908, 1911, 1914, 1917, 1920, 1923, 1926, 1929, 1932,
-    1935, 1938, 1941, 1944, 1947, 1950, 1953, 1956, 1959, 1962, 1965, 1968,
-    1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004,
-    2007, 2010, 2013, 2016, 2019, 2022, 2025, 2028, 2031, 2034, 2037, 2040,
-    2043, 2046, 2049, 2052, 2055, 2058, 2061, 2064, 2067, 2070, 2073, 2076,
-    2079, 2082, 2085, 2088, 2091, 2094, 2097, 2100, 2103, 0, 0, 0, 0, 2106,
-    2109, 2112, 2115, 2118, 2121, 2124, 2127, 2130, 2133, 2136, 2139, 2142,
-    2145, 2148, 2151, 2154, 2157, 2160, 2163, 2166, 2169, 2172, 2175, 2178,
-    2181, 2184, 2187, 2190, 2193, 2196, 2199, 2202, 2205, 2208, 2211, 2214,
-    2217, 2220, 2223, 2226, 2229, 2232, 2235, 2238, 2241, 2244, 2247, 2250,
-    2253, 2256, 2259, 2262, 2265, 2268, 2271, 2274, 2277, 2280, 2283, 2286,
-    2289, 2292, 2295, 2298, 2301, 2304, 2307, 2310, 2313, 2316, 2319, 2322,
-    2325, 2328, 2331, 2334, 2337, 2340, 2343, 2346, 2349, 2352, 2355, 2358,
-    2361, 2364, 2367, 2370, 2373, 0, 0, 0, 0, 0, 0, 2376, 2379, 2382, 2385,
-    2388, 2391, 2394, 2397, 2400, 2403, 2406, 2409, 2412, 2415, 2418, 2421,
-    2424, 2427, 2430, 2433, 2436, 2439, 0, 0, 2442, 2445, 2448, 2451, 2454,
-    2457, 0, 0, 2460, 2463, 2466, 2469, 2472, 2475, 2478, 2481, 2484, 2487,
-    2490, 2493, 2496, 2499, 2502, 2505, 2508, 2511, 2514, 2517, 2520, 2523,
-    2526, 2529, 2532, 2535, 2538, 2541, 2544, 2547, 2550, 2553, 2556, 2559,
-    2562, 2565, 2568, 2571, 0, 0, 2574, 2577, 2580, 2583, 2586, 2589, 0, 0,
-    2592, 2595, 2598, 2601, 2604, 2607, 2610, 2613, 0, 2616, 0, 2619, 0,
-    2622, 0, 2625, 2628, 2631, 2634, 2637, 2640, 2643, 2646, 2649, 2652,
-    2655, 2658, 2661, 2664, 2667, 2670, 2673, 2676, 2679, 2681, 2684, 2686,
-    2689, 2691, 2694, 2696, 2699, 2701, 2704, 2706, 2709, 0, 0, 2711, 2714,
-    2717, 2720, 2723, 2726, 2729, 2732, 2735, 2738, 2741, 2744, 2747, 2750,
-    2753, 2756, 2759, 2762, 2765, 2768, 2771, 2774, 2777, 2780, 2783, 2786,
-    2789, 2792, 2795, 2798, 2801, 2804, 2807, 2810, 2813, 2816, 2819, 2822,
-    2825, 2828, 2831, 2834, 2837, 2840, 2843, 2846, 2849, 2852, 2855, 2858,
-    2861, 2864, 2867, 0, 2870, 2873, 2876, 2879, 2882, 2885, 2887, 2890,
-    2893, 2895, 2898, 2901, 2904, 2907, 2910, 0, 2913, 2916, 2919, 2922,
-    2924, 2927, 2929, 2932, 2935, 2938, 2941, 2944, 2947, 2950, 0, 0, 2952,
-    2955, 2958, 2961, 2964, 2967, 0, 2969, 2972, 2975, 2978, 2981, 2984,
-    2987, 2989, 2992, 2995, 2998, 3001, 3004, 3007, 3010, 3012, 3015, 3018,
-    3020, 0, 0, 3022, 3025, 3028, 0, 3031, 3034, 3037, 3040, 3042, 3045,
-    3047, 3050, 3052, 0, 3055, 3057, 3059, 3061, 3063, 3065, 3067, 3069,
-    3071, 3073, 3075, 0, 0, 0, 0, 0, 0, 3077, 0, 0, 0, 0, 0, 3079, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 3082, 3084, 3087, 0, 0, 0, 0, 0, 0, 0, 0,
-    3091, 0, 0, 0, 3093, 3096, 0, 3100, 3103, 0, 0, 0, 0, 3107, 0, 3110, 0,
-    0, 0, 0, 0, 0, 0, 0, 3113, 3116, 3119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 3122, 0, 0, 0, 0, 0, 0, 0, 3127, 3129, 3131, 0, 0, 3133, 3135,
-    3137, 3139, 3141, 3143, 3145, 3147, 3149, 3151, 3153, 3155, 3157, 3159,
-    3161, 3163, 3165, 3167, 3169, 3171, 3173, 3175, 3177, 3179, 3181, 3183,
-    3185, 0, 3187, 3189, 3191, 3193, 3195, 3197, 3199, 3201, 3203, 3205,
-    3207, 3209, 3211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3213, 0, 0, 0, 0, 0,
-    0, 0, 3216, 3220, 3224, 3226, 0, 3229, 3233, 3237, 0, 3239, 3242, 3244,
-    3246, 3248, 3250, 3252, 3254, 3256, 3258, 3260, 0, 3262, 3264, 0, 0,
-    3267, 3269, 3271, 3273, 3275, 0, 0, 3277, 3280, 3284, 0, 3287, 0, 3289,
-    0, 3291, 0, 3293, 3295, 3297, 3299, 0, 3301, 3303, 3305, 0, 3307, 3309,
-    3311, 3313, 3315, 3317, 3319, 0, 3321, 3325, 3327, 3329, 3331, 3333, 0,
-    0, 0, 0, 3335, 3337, 3339, 3341, 3343, 0, 0, 0, 0, 0, 0, 3345, 3349,
-    3353, 3358, 3362, 3366, 3370, 3374, 3378, 3382, 3386, 3390, 3394, 3398,
-    3402, 3406, 3409, 3411, 3414, 3418, 3421, 3423, 3426, 3430, 3435, 3438,
-    3440, 3443, 3447, 3449, 3451, 3453, 3455, 3457, 3460, 3464, 3467, 3469,
-    3472, 3476, 3481, 3484, 3486, 3489, 3493, 3495, 3497, 3499, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 3501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    3505, 3508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3511,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3514, 3517, 3520, 0, 0, 0, 0,
-    3523, 0, 0, 0, 0, 3526, 0, 0, 3529, 0, 0, 0, 0, 0, 0, 0, 3532, 0, 3535,
-    0, 0, 0, 0, 0, 3538, 3541, 0, 3545, 3548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 3552, 0, 0, 3555, 0, 0, 3558, 0, 3561, 0, 0, 0, 0, 0,
-    0, 3564, 0, 3567, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3570, 3573, 3576, 3579,
-    3582, 0, 0, 3585, 3588, 0, 0, 3591, 3594, 0, 0, 0, 0, 0, 0, 3597, 3600,
-    0, 0, 3603, 3606, 0, 0, 3609, 3612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 3615, 3618, 3621, 3624, 3627, 3630, 3633, 3636, 0, 0,
-    0, 0, 0, 0, 3639, 3642, 3645, 3648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    3651, 3653, 0, 0, 0, 0, 0, 3655, 3657, 3659, 3661, 3663, 3665, 3667,
-    3669, 3671, 3673, 3676, 3679, 3682, 3685, 3688, 3691, 3694, 3697, 3700,
-    3703, 3706, 3710, 3714, 3718, 3722, 3726, 3730, 3734, 3738, 3742, 3747,
-    3752, 3757, 3762, 3767, 3772, 3777, 3782, 3787, 3792, 3797, 3800, 3803,
-    3806, 3809, 3812, 3815, 3818, 3821, 3824, 3828, 3832, 3836, 3840, 3844,
-    3848, 3852, 3856, 3860, 3864, 3868, 3872, 3876, 3880, 3884, 3888, 3892,
-    3896, 3900, 3904, 3908, 3912, 3916, 3920, 3924, 3928, 3932, 3936, 3940,
-    3944, 3948, 3952, 3956, 3960, 3964, 3968, 3972, 3974, 3976, 3978, 3980,
-    3982, 3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004,
-    4006, 4008, 4010, 4012, 4014, 4016, 4018, 4020, 4022, 4024, 4026, 4028,
-    4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046, 4048, 4050, 4052,
-    4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4078, 0, 0, 0, 0, 0,
-    0, 0, 4083, 4087, 4090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 4094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4097,
-    4099, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4101, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4103, 0, 0, 0, 4105, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 4107, 4109, 4111, 4113, 4115, 4117, 4119, 4121,
-    4123, 4125, 4127, 4129, 4131, 4133, 4135, 4137, 4139, 4141, 4143, 4145,
-    4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, 4163, 4165, 4167, 4169,
-    4171, 4173, 4175, 4177, 4179, 4181, 4183, 4185, 4187, 4189, 4191, 4193,
-    4195, 4197, 4199, 4201, 4203, 4205, 4207, 4209, 4211, 4213, 4215, 4217,
-    4219, 4221, 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, 4239, 4241,
-    4243, 4245, 4247, 4249, 4251, 4253, 4255, 4257, 4259, 4261, 4263, 4265,
-    4267, 4269, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, 4289,
-    4291, 4293, 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, 4311, 4313,
-    4315, 4317, 4319, 4321, 4323, 4325, 4327, 4329, 4331, 4333, 4335, 4337,
-    4339, 4341, 4343, 4345, 4347, 4349, 4351, 4353, 4355, 4357, 4359, 4361,
-    4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, 4381, 4383, 4385,
-    4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, 4403, 4405, 4407, 4409,
-    4411, 4413, 4415, 4417, 4419, 4421, 4423, 4425, 4427, 4429, 4431, 4433,
-    4435, 4437, 4439, 4441, 4443, 4445, 4447, 4449, 4451, 4453, 4455, 4457,
-    4459, 4461, 4463, 4465, 4467, 4469, 4471, 4473, 4475, 4477, 4479, 4481,
-    4483, 4485, 4487, 4489, 4491, 4493, 4495, 4497, 4499, 4501, 4503, 4505,
-    4507, 4509, 4511, 4513, 4515, 4517, 4519, 4521, 4523, 4525, 4527, 4529,
-    4531, 4533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4535, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4537, 0, 4539, 4541, 4543, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4545, 0, 4548, 0, 4551, 0,
-    4554, 0, 4557, 0, 4560, 0, 4563, 0, 4566, 0, 4569, 0, 4572, 0, 4575, 0,
-    4578, 0, 0, 4581, 0, 4584, 0, 4587, 0, 0, 0, 0, 0, 0, 4590, 4593, 0,
-    4596, 4599, 0, 4602, 4605, 0, 4608, 4611, 0, 4614, 4617, 0, 0, 0, 0, 0,
-    0, 4620, 0, 0, 0, 0, 0, 0, 4623, 4626, 0, 4629, 4632, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 4635, 0, 4638, 0, 4641, 0, 4644, 0, 4647, 0, 4650, 0,
-    4653, 0, 4656, 0, 4659, 0, 4662, 0, 4665, 0, 4668, 0, 0, 4671, 0, 4674,
-    0, 4677, 0, 0, 0, 0, 0, 0, 4680, 4683, 0, 4686, 4689, 0, 4692, 4695, 0,
-    4698, 4701, 0, 4704, 4707, 0, 0, 0, 0, 0, 0, 4710, 0, 0, 4713, 4716,
-    4719, 4722, 0, 0, 0, 4725, 4728, 0, 4731, 4733, 4735, 4737, 4739, 4741,
-    4743, 4745, 4747, 4749, 4751, 4753, 4755, 4757, 4759, 4761, 4763, 4765,
-    4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, 4789,
-    4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, 4809, 4811, 4813,
-    4815, 4817, 4819, 4821, 4823, 4825, 4827, 4829, 4831, 4833, 4835, 4837,
-    4839, 4841, 4843, 4845, 4847, 4849, 4851, 4853, 4855, 4857, 4859, 4861,
-    4863, 4865, 4867, 4869, 4871, 4873, 4875, 4877, 4879, 4881, 4883, 4885,
-    4887, 4889, 4891, 4893, 4895, 4897, 4899, 4901, 4903, 4905, 4907, 4909,
-    4911, 4913, 4915, 4917, 0, 0, 0, 4919, 4921, 4923, 4925, 4927, 4929,
-    4931, 4933, 4935, 4937, 4939, 4941, 4943, 4945, 4947, 4951, 4955, 4959,
-    4963, 4967, 4971, 4975, 4979, 4983, 4987, 4991, 4995, 4999, 5003, 5008,
-    5013, 5018, 5023, 5028, 5033, 5038, 5043, 5048, 5053, 5058, 5063, 5068,
-    5073, 5078, 5086, 0, 5093, 5097, 5101, 5105, 5109, 5113, 5117, 5121,
-    5125, 5129, 5133, 5137, 5141, 5145, 5149, 5153, 5157, 5161, 5165, 5169,
-    5173, 5177, 5181, 5185, 5189, 5193, 5197, 5201, 5205, 5209, 5213, 5217,
-    5221, 5225, 5229, 5233, 5237, 5239, 5241, 5243, 0, 0, 0, 0, 0, 0, 0, 0,
-    5245, 5249, 5252, 5255, 5258, 5261, 5264, 5267, 5270, 5273, 5276, 5279,
-    5282, 5285, 5288, 5291, 5294, 5296, 5298, 5300, 5302, 5304, 5306, 5308,
-    5310, 5312, 5314, 5316, 5318, 5320, 5322, 5325, 5328, 5331, 5334, 5337,
-    5340, 5343, 5346, 5349, 5352, 5355, 5358, 5361, 5364, 5370, 5375, 0,
-    5378, 5380, 5382, 5384, 5386, 5388, 5390, 5392, 5394, 5396, 5398, 5400,
-    5402, 5404, 5406, 5408, 5410, 5412, 5414, 5416, 5418, 5420, 5422, 5424,
-    5426, 5428, 5430, 5432, 5434, 5436, 5438, 5440, 5442, 5444, 5446, 5448,
-    5450, 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, 5468, 5470, 5472,
-    5474, 5476, 5479, 5482, 5485, 5488, 5491, 5494, 5497, 5500, 5503, 5506,
-    5509, 5512, 5515, 5518, 5521, 5524, 5527, 5530, 5533, 5536, 5539, 5542,
-    5545, 5548, 5552, 5556, 5560, 5563, 5567, 5570, 5574, 5576, 5578, 5580,
-    5582, 5584, 5586, 5588, 5590, 5592, 5594, 5596, 5598, 5600, 5602, 5604,
-    5606, 5608, 5610, 5612, 5614, 5616, 5618, 5620, 5622, 5624, 5626, 5628,
-    5630, 5632, 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, 5650, 5652,
-    5654, 5656, 5658, 5660, 5662, 5664, 5666, 0, 5668, 5673, 5678, 5683,
-    5687, 5692, 5696, 5700, 5706, 5711, 5715, 5719, 5723, 5728, 5733, 5737,
-    5741, 5744, 5748, 5753, 5758, 5761, 5767, 5774, 5780, 5784, 5790, 5796,
-    5801, 5805, 5809, 5813, 5818, 5824, 5829, 5833, 5837, 5841, 5844, 5847,
-    5850, 5853, 5857, 5861, 5867, 5871, 5876, 5882, 5886, 5889, 5892, 5898,
-    5903, 5909, 5913, 5919, 5922, 5926, 5930, 5934, 5938, 5942, 5947, 5951,
-    5954, 5958, 5962, 5966, 5971, 5975, 5979, 5983, 5989, 5994, 5997, 6003,
-    6006, 6011, 6016, 6020, 6024, 6028, 6033, 6036, 6040, 6045, 6048, 6054,
-    6058, 6061, 6064, 6067, 6070, 6073, 6076, 6079, 6082, 6085, 6088, 6092,
-    6096, 6100, 6104, 6108, 6112, 6116, 6120, 6124, 6128, 6132, 6136, 6140,
-    6144, 6148, 6152, 6155, 6158, 6162, 6165, 6168, 6171, 6175, 6179, 6182,
-    6185, 6188, 6191, 6194, 6199, 6202, 6205, 6208, 6211, 6214, 6217, 6220,
-    6223, 6227, 6232, 6235, 6238, 6241, 6244, 6247, 6250, 6253, 6257, 6261,
-    6265, 6269, 6272, 6275, 6278, 6281, 6284, 6287, 6290, 6293, 6296, 6299,
-    6303, 6307, 6310, 6314, 6318, 6322, 6325, 6329, 6333, 6338, 6341, 6345,
-    6349, 6353, 6357, 6363, 6370, 6373, 6376, 6379, 6382, 6385, 6388, 6391,
-    6394, 6397, 6400, 6403, 6406, 6409, 6412, 6415, 6418, 6421, 6424, 6429,
-    6432, 6435, 6438, 6443, 6447, 6450, 6453, 6456, 6459, 6462, 6465, 6468,
-    6471, 6474, 6477, 6481, 6484, 6487, 6491, 6495, 6498, 6503, 6507, 6510,
-    6513, 6516, 6519, 6523, 6527, 6530, 6533, 6536, 6539, 6542, 6545, 6548,
-    6551, 6554, 6558, 6562, 6566, 6570, 6574, 6578, 6582, 6586, 6590, 6594,
-    6598, 6602, 6606, 6610, 6614, 6618, 6622, 6626, 6630, 6634, 6638, 6642,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6646, 6648, 0, 0, 6650, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6652, 6654, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6656, 6658, 6660,
-    6662, 6664, 6666, 6668, 6670, 6672, 6674, 6676, 6678, 6680, 6682, 6684,
-    6686, 6688, 6690, 6692, 6694, 6696, 6698, 6700, 6702, 6704, 6706, 6708,
-    6710, 6712, 6714, 6716, 6718, 6720, 6722, 6724, 6726, 6728, 6730, 6732,
-    6734, 6736, 6738, 6740, 6742, 6744, 6746, 6748, 6750, 6752, 6754, 6756,
-    6758, 6760, 6762, 6764, 6766, 6768, 6770, 6772, 6774, 6776, 6778, 6780,
-    6782, 6784, 6786, 6788, 6790, 6792, 6794, 6796, 6798, 6800, 6802, 6804,
-    6806, 6808, 6810, 6812, 6814, 6816, 6818, 6820, 6822, 6824, 6826, 6828,
-    6830, 6832, 6834, 6836, 6838, 6840, 6842, 6844, 6846, 6848, 6850, 6852,
-    6854, 6856, 6858, 6860, 6862, 6864, 6866, 6868, 6870, 6872, 6874, 6876,
-    6878, 6880, 6882, 6884, 6886, 6888, 6890, 6892, 6894, 6896, 6898, 6900,
-    6902, 6904, 6906, 6908, 6910, 6912, 6914, 6916, 6918, 6920, 6922, 6924,
-    6926, 6928, 6930, 6932, 6934, 6936, 6938, 6940, 6942, 6944, 6946, 6948,
-    6950, 6952, 6954, 6956, 6958, 6960, 6962, 6964, 6966, 6968, 6970, 6972,
-    6974, 6976, 6978, 6980, 6982, 6984, 6986, 6988, 6990, 6992, 6994, 6996,
-    6998, 7000, 7002, 7004, 7006, 7008, 7010, 7012, 7014, 7016, 7018, 7020,
-    7022, 7024, 7026, 7028, 7030, 7032, 7034, 7036, 7038, 7040, 7042, 7044,
-    7046, 7048, 7050, 7052, 7054, 7056, 7058, 7060, 7062, 7064, 7066, 7068,
-    7070, 7072, 7074, 7076, 7078, 7080, 7082, 7084, 7086, 7088, 7090, 7092,
-    7094, 7096, 7098, 7100, 7102, 7104, 7106, 7108, 7110, 7112, 7114, 7116,
-    7118, 7120, 7122, 7124, 7126, 7128, 7130, 7132, 7134, 7136, 7138, 7140,
-    7142, 7144, 7146, 7148, 7150, 7152, 7154, 7156, 7158, 7160, 7162, 7164,
-    7166, 7168, 7170, 7172, 7174, 7176, 7178, 7180, 7182, 7184, 7186, 7188,
-    7190, 7192, 7194, 7196, 7198, 7200, 7202, 0, 0, 7204, 0, 7206, 0, 0,
-    7208, 7210, 7212, 7214, 7216, 7218, 7220, 7222, 7224, 7226, 0, 7228, 0,
-    7230, 0, 0, 7232, 7234, 0, 0, 0, 7236, 7238, 7240, 7242, 7244, 7246,
-    7248, 7250, 7252, 7254, 7256, 7258, 7260, 7262, 7264, 7266, 7268, 7270,
-    7272, 7274, 7276, 7278, 7280, 7282, 7284, 7286, 7288, 7290, 7292, 7294,
-    7296, 7298, 7300, 7302, 7304, 7306, 7308, 7310, 7312, 7314, 7316, 7318,
-    7320, 7322, 7324, 7326, 7328, 7330, 7332, 7334, 7336, 7338, 7340, 7342,
-    7344, 7346, 7348, 7350, 7352, 7354, 7356, 7358, 7360, 7362, 7364, 7366,
-    7368, 7371, 0, 0, 7373, 7375, 7377, 7379, 7381, 7383, 7385, 7387, 7389,
-    7391, 7393, 7395, 7397, 7399, 7401, 7403, 7405, 7407, 7409, 7411, 7413,
-    7415, 7417, 7419, 7421, 7423, 7425, 7427, 7429, 7431, 7433, 7435, 7437,
-    7439, 7441, 7443, 7445, 7447, 7449, 7451, 7453, 7455, 7457, 7459, 7461,
-    7463, 7465, 7467, 7469, 7471, 7473, 7475, 7477, 7479, 7481, 7483, 7485,
-    7487, 7489, 7491, 7493, 7495, 7497, 7499, 7501, 7503, 7505, 7507, 7509,
-    7511, 7513, 7515, 7517, 7519, 7521, 7523, 7525, 7527, 7529, 7531, 7533,
-    7535, 7537, 7539, 7541, 7543, 7545, 7547, 7549, 7551, 7553, 7555, 7557,
-    7559, 7561, 7563, 7566, 7569, 7572, 7574, 7576, 7578, 7581, 7584, 7587,
-    7589, 0, 0, 0, 0, 0, 0, 7591, 7594, 7597, 7600, 7604, 7608, 7611, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7614, 7617, 7620, 7623, 7626, 0, 0, 0, 0,
-    0, 7629, 0, 7632, 7635, 7637, 7639, 7641, 7643, 7645, 7647, 7649, 7651,
-    7653, 7655, 7658, 7661, 7664, 7667, 7670, 7673, 7676, 7679, 7682, 7685,
-    7688, 7691, 0, 7694, 7697, 7700, 7703, 7706, 0, 7709, 0, 7712, 7715, 0,
-    7718, 7721, 0, 7724, 7727, 7730, 7733, 7736, 7739, 7742, 7745, 7748,
-    7751, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774,
-    7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798,
-    7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822,
-    7824, 7826, 7828, 7830, 7832, 7834, 7836, 7838, 7840, 7842, 7844, 7846,
-    7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870,
-    7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894,
-    7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918,
-    7920, 7922, 7924, 7926, 7928, 7930, 7932, 7934, 7936, 7938, 7940, 7942,
-    7944, 7946, 7948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    7950, 7952, 7954, 7956, 7958, 7960, 7962, 7964, 7966, 7968, 7970, 7972,
-    7974, 7976, 7978, 7980, 7982, 7984, 7986, 7988, 7990, 7992, 7994, 7996,
-    7999, 8002, 8005, 8008, 8011, 8014, 8017, 8020, 8023, 8026, 8029, 8032,
-    8035, 8038, 8041, 8044, 8047, 8050, 8052, 8054, 8056, 8058, 8061, 8064,
-    8067, 8070, 8073, 8076, 8079, 8082, 8085, 8088, 8091, 8094, 8097, 8100,
-    8103, 8106, 8109, 8112, 8115, 8118, 8121, 8124, 8127, 8130, 8133, 8136,
-    8139, 8142, 8145, 8148, 8151, 8154, 8157, 8160, 8163, 8166, 8169, 8172,
-    8175, 8178, 8181, 8184, 8187, 8190, 8193, 8196, 8199, 8202, 8205, 8208,
-    8211, 8214, 8217, 8220, 8223, 8226, 8229, 8232, 8235, 8238, 8241, 8244,
-    8247, 8250, 8253, 8256, 8259, 8262, 8265, 8268, 8271, 8274, 8277, 8280,
-    8283, 8286, 8289, 8292, 8295, 8298, 8301, 8304, 8307, 8310, 8313, 8316,
-    8319, 8322, 8325, 8328, 8331, 8334, 8337, 8340, 8344, 8348, 8352, 8356,
-    8360, 8364, 8367, 8370, 8373, 8376, 8379, 8382, 8385, 8388, 8391, 8394,
-    8397, 8400, 8403, 8406, 8409, 8412, 8415, 8418, 8421, 8424, 8427, 8430,
-    8433, 8436, 8439, 8442, 8445, 8448, 8451, 8454, 8457, 8460, 8463, 8466,
-    8469, 8472, 8475, 8478, 8481, 8484, 8487, 8490, 8493, 8496, 8499, 8502,
-    8505, 8508, 8511, 8514, 8517, 8520, 8523, 8526, 8529, 8532, 8535, 8538,
-    8541, 8544, 8547, 8550, 8553, 8556, 8559, 8562, 8565, 8568, 8571, 8574,
-    8577, 8580, 8583, 8586, 8589, 8592, 8595, 8598, 8601, 8604, 8607, 8610,
-    8613, 8616, 8619, 8622, 8625, 8628, 8631, 8634, 8637, 8640, 8643, 8646,
-    8649, 8652, 8655, 8658, 8661, 8664, 8667, 8670, 8673, 8676, 8679, 8682,
-    8685, 8688, 8691, 8694, 8697, 8700, 8703, 8706, 8709, 8712, 8715, 8718,
-    8721, 8724, 8727, 8730, 8733, 8736, 8739, 8742, 8745, 8748, 8751, 8754,
-    8757, 8760, 8763, 8766, 8769, 8772, 8775, 8778, 8781, 8784, 8787, 8790,
-    8794, 8798, 8802, 8805, 8808, 8811, 8814, 8817, 8820, 8823, 8826, 8829,
-    8832, 8835, 8838, 8841, 8844, 8847, 8850, 8853, 8856, 8859, 8862, 8865,
-    8868, 8871, 8874, 8877, 8880, 8883, 8886, 8889, 8892, 8895, 8898, 8901,
-    8904, 8907, 8910, 8913, 8916, 8919, 8922, 8925, 8928, 8931, 8934, 8937,
-    8940, 8943, 8946, 8949, 8952, 8955, 8958, 8961, 8964, 8967, 8970, 8973,
-    8976, 8979, 8982, 8985, 8988, 8991, 8994, 8997, 9000, 9003, 9006, 9009,
-    9012, 9015, 9018, 0, 0, 9021, 9025, 9029, 9033, 9037, 9041, 9045, 9049,
-    9053, 9057, 9061, 9065, 9069, 9073, 9077, 9081, 9085, 9089, 9093, 9097,
-    9101, 9105, 9109, 9113, 9117, 9121, 9125, 9129, 9133, 9137, 9141, 9145,
-    9149, 9153, 9157, 9161, 9165, 9169, 9173, 9177, 9181, 9185, 9189, 9193,
-    9197, 9201, 9205, 9209, 9213, 9217, 9221, 9225, 9229, 9233, 9237, 9241,
-    9245, 9249, 9253, 9257, 9261, 9265, 9269, 9273, 0, 0, 9277, 9281, 9285,
-    9289, 9293, 9297, 9301, 9305, 9309, 9313, 9317, 9321, 9325, 9329, 9333,
-    9337, 9341, 9345, 9349, 9353, 9357, 9361, 9365, 9369, 9373, 9377, 9381,
-    9385, 9389, 9393, 9397, 9401, 9405, 9409, 9413, 9417, 9421, 9425, 9429,
-    9433, 9437, 9441, 9445, 9449, 9453, 9457, 9461, 9465, 9469, 9473, 9477,
-    9481, 9485, 9489, 0, 0, 0, 0, 0, 0, 0, 0, 9493, 9497, 9501, 9506, 9511,
-    9516, 9521, 9526, 9531, 9536, 9540, 9559, 9568, 0, 0, 0, 9573, 9575,
-    9577, 9579, 9581, 9583, 9585, 9587, 9589, 9591, 0, 0, 0, 0, 0, 0, 9593,
-    9595, 9597, 9599, 9601, 9603, 9605, 9607, 9609, 9611, 9613, 9615, 9617,
-    9619, 9621, 9623, 9625, 9627, 9629, 9631, 9633, 0, 0, 9635, 9637, 9639,
-    9641, 9643, 9645, 9647, 9649, 9651, 9653, 9655, 9657, 0, 9659, 9661,
-    9663, 9665, 9667, 9669, 9671, 9673, 9675, 9677, 9679, 9681, 9683, 9685,
-    9687, 9689, 9691, 9693, 9695, 0, 9697, 9699, 9701, 9703, 0, 0, 0, 0,
-    9705, 9708, 9711, 0, 9714, 0, 9717, 9720, 9723, 9726, 9729, 9732, 9735,
-    9738, 9741, 9744, 9747, 9749, 9751, 9753, 9755, 9757, 9759, 9761, 9763,
-    9765, 9767, 9769, 9771, 9773, 9775, 9777, 9779, 9781, 9783, 9785, 9787,
-    9789, 9791, 9793, 9795, 9797, 9799, 9801, 9803, 9805, 9807, 9809, 9811,
-    9813, 9815, 9817, 9819, 9821, 9823, 9825, 9827, 9829, 9831, 9833, 9835,
-    9837, 9839, 9841, 9843, 9845, 9847, 9849, 9851, 9853, 9855, 9857, 9859,
-    9861, 9863, 9865, 9867, 9869, 9871, 9873, 9875, 9877, 9879, 9881, 9883,
-    9885, 9887, 9889, 9891, 9893, 9895, 9897, 9899, 9901, 9903, 9905, 9907,
-    9909, 9911, 9913, 9915, 9917, 9919, 9921, 9923, 9925, 9927, 9929, 9931,
-    9933, 9935, 9937, 9939, 9941, 9943, 9945, 9947, 9949, 9951, 9953, 9955,
-    9957, 9959, 9961, 9963, 9965, 9967, 9969, 9971, 9973, 9975, 9977, 9979,
-    9981, 9984, 9987, 9990, 9993, 9996, 9999, 10002, 0, 0, 0, 0, 10005,
-    10007, 10009, 10011, 10013, 10015, 10017, 10019, 10021, 10023, 10025,
-    10027, 10029, 10031, 10033, 10035, 10037, 10039, 10041, 10043, 10045,
-    10047, 10049, 10051, 10053, 10055, 10057, 10059, 10061, 10063, 10065,
-    10067, 10069, 10071, 10073, 10075, 10077, 10079, 10081, 10083, 10085,
-    10087, 10089, 10091, 10093, 10095, 10097, 10099, 10101, 10103, 10105,
-    10107, 10109, 10111, 10113, 10115, 10117, 10119, 10121, 10123, 10125,
-    10127, 10129, 10131, 10133, 10135, 10137, 10139, 10141, 10143, 10145,
-    10147, 10149, 10151, 10153, 10155, 10157, 10159, 10161, 10163, 10165,
-    10167, 10169, 10171, 10173, 10175, 10177, 10179, 10181, 10183, 10185,
-    10187, 10189, 10191, 10193, 10195, 10197, 10199, 10201, 10203, 10205,
-    10207, 10209, 10211, 10213, 10215, 10217, 10219, 10221, 10223, 10225,
-    10227, 10229, 10231, 10233, 10235, 10237, 10239, 10241, 10243, 10245,
-    10247, 10249, 10251, 10253, 10255, 10257, 10259, 10261, 10263, 10265,
-    10267, 10269, 10271, 10273, 10275, 10277, 10279, 10281, 10283, 10285,
-    10287, 10289, 10291, 10293, 10295, 10297, 10299, 10301, 10303, 10305,
-    10307, 10309, 10311, 10313, 10315, 10317, 10319, 10321, 10323, 10325,
-    10327, 10329, 10331, 10333, 10335, 10337, 10339, 10341, 10343, 10345,
-    10347, 10349, 10351, 10353, 10355, 10357, 10359, 10361, 10363, 10365,
-    10367, 10369, 10371, 10373, 10375, 10377, 10379, 10381, 10383, 0, 0, 0,
-    10385, 10387, 10389, 10391, 10393, 10395, 0, 0, 10397, 10399, 10401,
-    10403, 10405, 10407, 0, 0, 10409, 10411, 10413, 10415, 10417, 10419, 0,
-    0, 10421, 10423, 10425, 0, 0, 0, 10427, 10429, 10431, 10433, 10435,
-    10437, 10439, 0, 10441, 10443, 10445, 10447, 10449, 10451, 10453, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 10455, 0, 10460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 10465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    10470, 10475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10480, 10485, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10490, 10495, 0, 10500, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 10505, 10510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 10515, 10520, 10525, 10530, 10535, 10540, 10545, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10550, 10555, 10560,
-    10565, 10570, 10575, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10580,
-    10582, 10584, 10586, 10588, 10590, 10592, 10594, 10596, 10598, 10600,
-    10602, 10604, 10606, 10608, 10610, 10612, 10614, 10616, 10618, 10620,
-    10622, 10624, 10626, 10628, 10630, 10632, 10634, 10636, 10638, 10640,
-    10642, 10644, 10646, 10648, 10650, 10652, 10654, 10656, 10658, 10660,
-    10662, 10664, 10666, 10668, 10670, 10672, 10674, 10676, 10678, 10680,
-    10682, 10684, 10686, 10688, 10690, 10692, 10694, 10696, 10698, 10700,
-    10702, 10704, 10706, 10708, 10710, 10712, 10714, 10716, 10718, 10720,
-    10722, 10724, 10726, 10728, 10730, 10732, 10734, 10736, 10738, 10740,
-    10742, 10744, 10746, 10748, 0, 10750, 10752, 10754, 10756, 10758, 10760,
-    10762, 10764, 10766, 10768, 10770, 10772, 10774, 10776, 10778, 10780,
-    10782, 10784, 10786, 10788, 10790, 10792, 10794, 10796, 10798, 10800,
-    10802, 10804, 10806, 10808, 10810, 10812, 10814, 10816, 10818, 10820,
-    10822, 10824, 10826, 10828, 10830, 10832, 10834, 10836, 10838, 10840,
-    10842, 10844, 10846, 10848, 10850, 10852, 10854, 10856, 10858, 10860,
-    10862, 10864, 10866, 10868, 10870, 10872, 10874, 10876, 10878, 10880,
-    10882, 10884, 10886, 10888, 10890, 0, 10892, 10894, 0, 0, 10896, 0, 0,
-    10898, 10900, 0, 0, 10902, 10904, 10906, 10908, 0, 10910, 10912, 10914,
-    10916, 10918, 10920, 10922, 10924, 10926, 10928, 10930, 10932, 0, 10934,
-    0, 10936, 10938, 10940, 10942, 10944, 10946, 10948, 0, 10950, 10952,
-    10954, 10956, 10958, 10960, 10962, 10964, 10966, 10968, 10970, 10972,
-    10974, 10976, 10978, 10980, 10982, 10984, 10986, 10988, 10990, 10992,
-    10994, 10996, 10998, 11000, 11002, 11004, 11006, 11008, 11010, 11012,
-    11014, 11016, 11018, 11020, 11022, 11024, 11026, 11028, 11030, 11032,
-    11034, 11036, 11038, 11040, 11042, 11044, 11046, 11048, 11050, 11052,
-    11054, 11056, 11058, 11060, 11062, 11064, 11066, 11068, 11070, 11072,
-    11074, 11076, 11078, 0, 11080, 11082, 11084, 11086, 0, 0, 11088, 11090,
-    11092, 11094, 11096, 11098, 11100, 11102, 0, 11104, 11106, 11108, 11110,
-    11112, 11114, 11116, 0, 11118, 11120, 11122, 11124, 11126, 11128, 11130,
-    11132, 11134, 11136, 11138, 11140, 11142, 11144, 11146, 11148, 11150,
-    11152, 11154, 11156, 11158, 11160, 11162, 11164, 11166, 11168, 11170,
-    11172, 0, 11174, 11176, 11178, 11180, 0, 11182, 11184, 11186, 11188,
-    11190, 0, 11192, 0, 0, 0, 11194, 11196, 11198, 11200, 11202, 11204,
-    11206, 0, 11208, 11210, 11212, 11214, 11216, 11218, 11220, 11222, 11224,
-    11226, 11228, 11230, 11232, 11234, 11236, 11238, 11240, 11242, 11244,
-    11246, 11248, 11250, 11252, 11254, 11256, 11258, 11260, 11262, 11264,
-    11266, 11268, 11270, 11272, 11274, 11276, 11278, 11280, 11282, 11284,
-    11286, 11288, 11290, 11292, 11294, 11296, 11298, 11300, 11302, 11304,
-    11306, 11308, 11310, 11312, 11314, 11316, 11318, 11320, 11322, 11324,
-    11326, 11328, 11330, 11332, 11334, 11336, 11338, 11340, 11342, 11344,
-    11346, 11348, 11350, 11352, 11354, 11356, 11358, 11360, 11362, 11364,
-    11366, 11368, 11370, 11372, 11374, 11376, 11378, 11380, 11382, 11384,
-    11386, 11388, 11390, 11392, 11394, 11396, 11398, 11400, 11402, 11404,
-    11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424,
-    11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444,
-    11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464,
-    11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484,
-    11486, 11488, 11490, 11492, 11494, 11496, 11498, 11500, 11502, 11504,
-    11506, 11508, 11510, 11512, 11514, 11516, 11518, 11520, 11522, 11524,
-    11526, 11528, 11530, 11532, 11534, 11536, 11538, 11540, 11542, 11544,
-    11546, 11548, 11550, 11552, 11554, 11556, 11558, 11560, 11562, 11564,
-    11566, 11568, 11570, 11572, 11574, 11576, 11578, 11580, 11582, 11584,
-    11586, 11588, 11590, 11592, 11594, 11596, 11598, 11600, 11602, 11604,
-    11606, 11608, 11610, 11612, 11614, 11616, 11618, 11620, 11622, 11624,
-    11626, 11628, 11630, 11632, 11634, 11636, 11638, 11640, 11642, 11644,
-    11646, 11648, 11650, 11652, 11654, 11656, 11658, 11660, 11662, 11664,
-    11666, 11668, 11670, 11672, 11674, 11676, 11678, 11680, 11682, 11684,
-    11686, 11688, 11690, 11692, 11694, 11696, 11698, 11700, 11702, 11704,
-    11706, 11708, 11710, 11712, 11714, 11716, 11718, 11720, 11722, 11724,
-    11726, 11728, 11730, 11732, 11734, 11736, 11738, 11740, 11742, 11744,
-    11746, 11748, 11750, 11752, 11754, 11756, 11758, 11760, 11762, 11764,
-    11766, 11768, 11770, 11772, 11774, 11776, 11778, 11780, 11782, 11784,
-    11786, 11788, 11790, 11792, 11794, 11796, 11798, 11800, 11802, 11804,
-    11806, 11808, 11810, 11812, 11814, 11816, 11818, 11820, 11822, 11824,
-    11826, 11828, 11830, 11832, 11834, 11836, 11838, 11840, 11842, 11844,
-    11846, 11848, 11850, 11852, 11854, 11856, 11858, 11860, 11862, 11864,
-    11866, 11868, 11870, 11872, 11874, 11876, 11878, 11880, 11882, 11884,
-    11886, 0, 0, 11888, 11890, 11892, 11894, 11896, 11898, 11900, 11902,
-    11904, 11906, 11908, 11910, 11912, 11914, 11916, 11918, 11920, 11922,
-    11924, 11926, 11928, 11930, 11932, 11934, 11936, 11938, 11940, 11942,
-    11944, 11946, 11948, 11950, 11952, 11954, 11956, 11958, 11960, 11962,
-    11964, 11966, 11968, 11970, 11972, 11974, 11976, 11978, 11980, 11982,
-    11984, 11986, 11988, 11990, 11992, 11994, 11996, 11998, 12000, 12002,
-    12004, 12006, 12008, 12010, 12012, 12014, 12016, 12018, 12020, 12022,
-    12024, 12026, 12028, 12030, 12032, 12034, 12036, 12038, 12040, 12042,
-    12044, 12046, 12048, 12050, 12052, 12054, 12056, 12058, 12060, 12062,
-    12064, 12066, 12068, 12070, 12072, 12074, 12076, 12078, 12080, 12082,
-    12084, 12086, 12088, 12090, 12092, 12094, 12096, 12098, 12100, 12102,
-    12104, 12106, 12108, 12110, 12112, 12114, 12116, 12118, 12120, 12122,
-    12124, 12126, 12128, 12130, 12132, 12134, 12136, 12138, 12140, 12142,
-    12144, 12146, 12148, 12150, 12152, 12154, 12156, 12158, 12160, 12162,
-    12164, 12166, 12168, 12170, 12172, 12174, 12176, 12178, 12180, 12182,
-    12184, 12186, 12188, 12190, 12192, 12194, 12196, 12198, 12200, 12202,
-    12204, 12206, 12208, 12210, 12212, 12214, 12216, 12218, 12220, 12222,
-    12224, 12226, 12228, 12230, 12232, 12234, 12236, 12238, 12240, 12242,
-    12244, 12246, 12248, 12250, 12252, 12254, 12256, 12258, 12260, 12262,
-    12264, 12266, 12268, 12270, 12272, 12274, 12276, 12278, 12280, 12282,
-    12284, 12286, 12288, 12290, 12292, 12294, 12296, 12298, 12300, 12302,
-    12304, 12306, 12308, 12310, 12312, 12314, 12316, 12318, 12320, 12322,
-    12324, 12326, 12328, 12330, 12332, 12334, 12336, 12338, 12340, 12342,
-    12344, 12346, 12348, 12350, 12352, 12354, 12356, 12358, 12360, 12362,
-    12364, 12366, 12368, 12370, 12372, 12374, 12376, 12378, 12380, 12382,
-    12384, 12386, 12388, 12390, 12392, 12394, 12396, 12398, 12400, 12402,
-    12404, 12406, 12408, 12410, 12412, 12414, 12416, 12418, 12420, 12422,
-    12424, 12426, 12428, 12430, 12432, 12434, 12436, 12438, 12440, 12442,
-    12444, 12446, 12448, 12450, 12452, 12454, 12456, 12458, 12460, 12462,
-    12464, 12466, 12468, 12470, 0, 0, 12472, 12474, 12476, 12478, 12480,
-    12482, 12484, 12486, 12488, 12490, 12492, 12494, 12496, 12498, 12500,
-    12502, 12504, 12506, 12508, 12510, 12512, 12514, 12516, 12518, 12520,
-    12522, 12524, 12526, 12528, 12530, 12532, 12534, 12536, 12538, 12540,
-    12542, 12544, 12546, 12548, 12550, 12552, 12554, 12556, 12558, 12560,
-    12562, 12564, 12566, 12568, 12570, 12572, 12574, 12576, 12578, 0, 12580,
-    12582, 12584, 12586, 12588, 12590, 12592, 12594, 12596, 12598, 12600,
-    12602, 12604, 12606, 12608, 12610, 12612, 12614, 12616, 12618, 12620,
-    12622, 12624, 12626, 12628, 12630, 12632, 0, 12634, 12636, 0, 12638, 0,
-    0, 12640, 0, 12642, 12644, 12646, 12648, 12650, 12652, 12654, 12656,
-    12658, 12660, 0, 12662, 12664, 12666, 12668, 0, 12670, 0, 12672, 0, 0, 0,
-    0, 0, 0, 12674, 0, 0, 0, 0, 12676, 0, 12678, 0, 12680, 0, 12682, 12684,
-    12686, 0, 12688, 12690, 0, 12692, 0, 0, 12694, 0, 12696, 0, 12698, 0,
-    12700, 0, 12702, 0, 12704, 12706, 0, 12708, 0, 0, 12710, 12712, 12714,
-    12716, 0, 12718, 12720, 12722, 12724, 12726, 12728, 12730, 0, 12732,
-    12734, 12736, 12738, 0, 12740, 12742, 12744, 12746, 0, 12748, 0, 12750,
-    12752, 12754, 12756, 12758, 12760, 12762, 12764, 12766, 12768, 0, 12770,
-    12772, 12774, 12776, 12778, 12780, 12782, 12784, 12786, 12788, 12790,
-    12792, 12794, 12796, 12798, 12800, 12802, 0, 0, 0, 0, 0, 12804, 12806,
-    12808, 0, 12810, 12812, 12814, 12816, 12818, 0, 12820, 12822, 12824,
-    12826, 12828, 12830, 12832, 12834, 12836, 12838, 12840, 12842, 12844,
-    12846, 12848, 12850, 12852, 0, 0, 0, 0, 12854, 12857, 12860, 12863,
-    12866, 12869, 12872, 12875, 12878, 12881, 12884, 0, 0, 0, 0, 0, 12887,
-    12891, 12895, 12899, 12903, 12907, 12911, 12915, 12919, 12923, 12927,
-    12931, 12935, 12939, 12943, 12947, 12951, 12955, 12959, 12963, 12967,
-    12971, 12975, 12979, 12983, 12987, 12991, 12995, 12997, 12999, 13002, 0,
-    13005, 13007, 13009, 13011, 13013, 13015, 13017, 13019, 13021, 13023,
-    13025, 13027, 13029, 13031, 13033, 13035, 13037, 13039, 13041, 13043,
-    13045, 13047, 13049, 13051, 13053, 13055, 13057, 13060, 13063, 13066,
-    13069, 13073, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13076, 13079, 0, 0, 0, 0,
-    13082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13085, 13088, 13091,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13093, 13095, 13097, 13099, 13101,
-    13103, 13105, 13107, 13109, 13111, 13113, 13115, 13117, 13119, 13121,
-    13123, 13125, 13127, 13129, 13131, 13133, 13135, 13137, 13139, 13141,
-    13143, 13145, 13147, 13149, 13151, 13153, 13155, 13157, 13159, 13161,
-    13163, 13165, 13167, 13169, 13171, 13173, 13175, 13177, 13179, 0, 0, 0,
-    0, 13181, 13185, 13189, 13193, 13197, 13201, 13205, 13209, 13213, 0, 0,
-    0, 0, 0, 0, 0, 13217, 13219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    13221, 13223, 13225, 13227, 13230, 13232, 13234, 13236, 13238, 13240,
-    13242, 13244, 13246, 13248, 13251, 13253, 13255, 13257, 13259, 13262,
-    13264, 13266, 13268, 13271, 13273, 13275, 13277, 13279, 13281, 13284,
-    13286, 13288, 13290, 13292, 13294, 13296, 13298, 13300, 13302, 13304,
-    13306, 13308, 13310, 13312, 13314, 13316, 13318, 13320, 13322, 13324,
-    13326, 13328, 13330, 13333, 13335, 13337, 13339, 13342, 13344, 13346,
-    13348, 13350, 13352, 13354, 13356, 13358, 13360, 13362, 13364, 13366,
-    13368, 13370, 13372, 13374, 13376, 13378, 13380, 13382, 13384, 13386,
-    13388, 13390, 13392, 13394, 13396, 13398, 13400, 13402, 13404, 13406,
-    13409, 13411, 13413, 13415, 13417, 13419, 13421, 13424, 13427, 13429,
-    13431, 13433, 13435, 13437, 13439, 13441, 13443, 13445, 13447, 13450,
-    13452, 13454, 13456, 13458, 13461, 13463, 13465, 13467, 13469, 13471,
-    13473, 13475, 13477, 13479, 13482, 13484, 13487, 13489, 13491, 13493,
-    13495, 13497, 13499, 13501, 13503, 13505, 13507, 13509, 13512, 13514,
-    13516, 13518, 13520, 13522, 13525, 13527, 13530, 13533, 13535, 13537,
-    13539, 13541, 13544, 13547, 13549, 13551, 13553, 13555, 13557, 13559,
-    13561, 13563, 13565, 13567, 13569, 13572, 13574, 13576, 13578, 13580,
-    13582, 13584, 13586, 13588, 13590, 13592, 13594, 13596, 13598, 13600,
-    13602, 13604, 13606, 13608, 13610, 13613, 13615, 13617, 13619, 13621,
-    13623, 13626, 13628, 13630, 13632, 13634, 13636, 13638, 13640, 13642,
-    13644, 13646, 13648, 13651, 13653, 13655, 13657, 13659, 13661, 13663,
-    13665, 13667, 13669, 13671, 13673, 13675, 13677, 13679, 13681, 13683,
-    13685, 13687, 13690, 13692, 13694, 13696, 13698, 13700, 13703, 13705,
-    13707, 13709, 13711, 13713, 13715, 13717, 13719, 13722, 13724, 13726,
-    13728, 13731, 13733, 13735, 13737, 13739, 13741, 13743, 13746, 13749,
-    13752, 13754, 13757, 13759, 13761, 13763, 13765, 13767, 13769, 13771,
-    13773, 13775, 13777, 13780, 13782, 13784, 13786, 13788, 13790, 13792,
-    13795, 13797, 13799, 13802, 13805, 13807, 13809, 13811, 13813, 13815,
-    13817, 13819, 13821, 13823, 13826, 13828, 13831, 13833, 13836, 13838,
-    13840, 13842, 13845, 13847, 13849, 13852, 13855, 13857, 13859, 13861,
-    13863, 13865, 13867, 13869, 13871, 13873, 13875, 13877, 13879, 13881,
-    13884, 13886, 13889, 13891, 13894, 13896, 13899, 13902, 13905, 13907,
-    13909, 13911, 13914, 13917, 13920, 13923, 13925, 13927, 13929, 13931,
-    13933, 13935, 13937, 13939, 13942, 13944, 13946, 13948, 13950, 13953,
-    13955, 13958, 13961, 13963, 13965, 13967, 13969, 13971, 13973, 13976,
-    13979, 13982, 13984, 13986, 13989, 13991, 13993, 13995, 13998, 14000,
-    14002, 14004, 14006, 14008, 14011, 14013, 14015, 14017, 14019, 14021,
-    14023, 14026, 14029, 14031, 14034, 14036, 14039, 14041, 14043, 14045,
-    14048, 14051, 14053, 14056, 14058, 14061, 14063, 14065, 14067, 14069,
-    14071, 14073, 14076, 14079, 14082, 14085, 14087, 14089, 14091, 14093,
-    14095, 14097, 14099, 14101, 14103, 14105, 14107, 14109, 14112, 14114,
-    14116, 14118, 14120, 14122, 14124, 14126, 14128, 14130, 14132, 14134,
-    14136, 14139, 14142, 14145, 14147, 14149, 14151, 14153, 14156, 14158,
-    14161, 14163, 14165, 14168, 14171, 14173, 14175, 14177, 14179, 14181,
-    14183, 14185, 14187, 14189, 14191, 14193, 14195, 14197, 14199, 14201,
-    14203, 14205, 14207, 14209, 14212, 14214, 14216, 14218, 14220, 14222,
-    14225, 14228, 14230, 14232, 14234, 14236, 14238, 14240, 14243, 14245,
-    14247, 14249, 14251, 14254, 14257, 14259, 14261, 14263, 14266, 14268,
-    14270, 14273, 14276, 14278, 14280, 14282, 14285, 14287, 14289, 14291,
-    14293, 14295, 14297, 14299, 14302, 14304, 14306, 14308, 14311, 14313,
-    14315, 14317, 14319, 14322, 14325, 14327, 14329, 14331, 14334, 14336,
-    14339, 14341, 14343, 14345, 14348, 14350, 14352, 14354, 14356, 14358,
-    14360, 14362, 14365, 14367, 14369, 14371, 14373, 14375, 14377, 14380,
-    14382, 14385, 14388, 14391, 14393, 14395, 14397, 14399, 14401, 14403,
-    14405, 14407, 0, 0,
-};
-
-/* NFC pairs */
-#define COMP_SHIFT1 2
-#define COMP_SHIFT2 1
-static const unsigned short comp_index0[] = {
-    0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4,
-    5, 6, 7, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0,
-    15, 16, 17, 0, 0, 0, 0, 18, 19, 20, 21, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0,
-    23, 24, 25, 26, 0, 0, 0, 0, 27, 28, 29, 30, 0, 0, 0, 0, 31, 32, 33, 34,
-    0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 36, 0, 37, 38, 39, 0, 0, 0, 40, 41, 42,
-    43, 0, 0, 0, 0, 44, 45, 46, 0, 0, 0, 0, 0, 47, 48, 49, 50, 0, 0, 0, 51,
-    52, 53, 54, 0, 0, 0, 0, 55, 56, 0, 0, 0, 0, 0, 0, 57, 58, 59, 60, 0, 0,
-    0, 0, 61, 62, 63, 0, 0, 0, 0, 0, 64, 65, 66, 67, 0, 0, 0, 68, 69, 70, 71,
-    0, 0, 0, 0, 72, 0, 73, 0, 0, 0, 0, 0, 74, 0, 75, 0, 0, 0, 0, 0, 76, 0, 0,
-    0, 0, 0, 0, 77, 78, 79, 0, 0, 0, 0, 0, 80, 81, 82, 83, 0, 0, 0, 0, 84,
-    85, 86, 0, 0, 0, 0, 0, 87, 88, 0, 89, 0, 0, 0, 90, 91, 0, 92, 0, 0, 0, 0,
-    0, 93, 94, 95, 0, 0, 0, 0, 96, 97, 98, 99, 0, 0, 0, 0, 100, 0, 0, 0, 0,
-    0, 0, 101, 102, 0, 103, 0, 0, 0, 0, 104, 105, 106, 107, 0, 0, 0, 0, 108,
-    109, 110, 111, 0, 0, 0, 0, 112, 113, 0, 0, 0, 0, 0, 114, 115, 116, 117,
-    0, 0, 0, 0, 118, 119, 120, 121, 0, 0, 0, 0, 122, 0, 123, 0, 0, 0, 0, 124,
-    125, 126, 127, 128, 0, 0, 0, 129, 130, 131, 132, 0, 0, 0, 0, 133, 134, 0,
-    0, 0, 0, 0, 0, 135, 136, 137, 138, 0, 0, 0, 139, 140, 141, 142, 0, 0, 0,
-    0, 0, 143, 144, 145, 0, 0, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0, 150, 0,
-    151, 0, 0, 0, 0, 152, 153, 154, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0,
-    156, 157, 158, 0, 0, 0, 0, 0, 159, 160, 161, 162, 0, 0, 0, 163, 0, 0, 0,
-    164, 0, 0, 0, 165, 166, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, 168,
-    0, 0, 0, 0, 0, 0, 169, 170, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0,
-    172, 173, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 175, 176, 0, 0, 0, 0,
-    0, 0, 177, 178, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0,
-    0, 0, 0, 181, 182, 183, 0, 0, 0, 0, 0, 184, 185, 0, 0, 0, 0, 0, 0, 186,
-    0, 0, 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 188, 189, 0, 0, 0, 0, 0, 0,
-    190, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0,
-    0, 194, 195, 0, 0, 0, 0, 0, 0, 196, 197, 0, 0, 0, 0, 0, 0, 198, 0, 0, 0,
-    0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 200, 201, 202, 0, 0, 0, 0, 0, 203,
-    204, 0, 0, 0, 0, 0, 0, 205, 206, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0,
-    208, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0,
-    0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 0,
-    0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0,
-    0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 219, 0,
-    0, 0, 0, 0, 0, 220, 221, 222, 0, 0, 0, 0, 0, 223, 224, 225, 0, 0, 0, 0,
-    0, 226, 227, 228, 0, 0, 0, 0, 0, 229, 230, 231, 0, 0, 0, 0, 0, 0, 232, 0,
-    0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 235, 0,
-    0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 238,
-    0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0,
-    241, 0, 0, 0, 0, 0, 0, 242, 0, 243, 244, 0, 0, 0, 0, 245, 246, 0, 0, 0,
-    0, 0, 247, 0, 248, 0, 249, 0, 0, 0, 250, 251, 252, 0, 0, 0, 0, 0, 253, 0,
-    254, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 256, 257, 258, 0, 0, 0, 0, 0,
-    259, 0, 260, 0, 261, 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 263, 0,
-    0, 0, 264, 265, 266, 0, 267, 0, 0, 0, 268, 0, 269, 0, 0, 0, 0, 0, 270, 0,
-    271, 272, 0, 0, 0, 0, 273, 274, 0, 275, 0, 0, 0, 276, 0, 277, 0, 0, 0, 0,
-    0, 0, 0, 278, 0, 0, 0, 0, 0, 279, 280, 281, 282, 0, 0, 0, 0, 283, 284, 0,
-    285, 0, 0, 0, 286, 0, 0, 0, 287, 0, 0, 0, 288, 0, 0, 0, 289, 0, 0, 0, 0,
-    0, 0, 290, 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 0, 0, 0, 0,
-    0, 293, 0, 0, 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0,
-    0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 297, 0, 0, 0, 0, 0, 0, 298, 299, 0, 0, 0,
-    0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 302, 0, 0,
-    0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 305, 0,
-    0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 308,
-    0, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, 0,
-    311, 312, 0, 0, 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0,
-    0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 316, 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, 0,
-    0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0,
-    0, 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, 322, 0, 0, 0, 0, 0, 0, 0, 323, 0,
-    0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 326, 0, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0,
-    0, 0, 329, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0,
-    0, 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, 333, 0, 0, 0, 0, 0, 0, 334, 0, 0,
-    0, 0, 0, 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 336, 337, 0, 0, 0, 0, 0, 0, 0,
-    338, 0, 0, 0, 0, 0, 0, 339, 0, 0, 0, 0, 0, 0, 0, 340, 0, 0, 0, 0, 0, 0,
-    0, 341, 0, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0,
-    0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 347, 0, 0, 0,
-    0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 350, 0,
-    0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 353,
-    0, 0, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 0,
-    356, 0, 0, 0, 0, 0, 0, 357, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0,
-    0, 359, 0, 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, 0, 0, 0, 361, 0, 362, 0, 0, 0,
-    0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, 0, 0, 365, 0,
-    0, 0, 0, 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 368,
-    0, 0, 0, 0, 0, 0, 369, 370, 0, 0, 0, 0, 0, 0, 371, 0, 0, 0, 0, 0, 0, 0,
-    372, 0, 0, 0, 0, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, 0, 0,
-    0, 375, 0, 0, 376, 0, 0, 0, 0, 377, 0, 0, 378, 0, 0, 0, 0, 0, 0, 0, 379,
-    0, 0, 0, 0, 0, 0, 0, 380, 0, 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 0, 0,
-    382, 0, 0, 0, 0, 0, 0, 0, 383, 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, 0, 385, 0,
-    0, 386, 0, 0, 0, 0, 387, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 389, 0, 0, 0, 0,
-    0, 0, 0, 390, 0, 0, 0, 0, 0, 0, 391, 0, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0,
-    0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 395, 0, 0, 0, 0, 0,
-    0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 398, 0, 0, 0, 0,
-    0, 0, 0, 399, 0, 0, 400, 0, 0, 0, 0, 401, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0,
-    403, 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 405, 0, 0, 0, 0, 0, 0,
-    0, 406, 0, 0, 0, 0, 0, 0, 0, 407, 0, 0, 0, 0, 0, 0, 0, 408, 0, 0, 0, 409,
-    0, 0, 410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 0, 0, 0, 0, 413, 0, 0, 0,
-    0, 0, 0, 0, 414, 0, 0, 0, 0, 0, 0, 415, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0,
-    0, 0, 0, 0, 0, 417, 0, 0, 0, 0, 0, 0, 0, 418, 0, 0, 0, 419, 0, 0, 420, 0,
-    0, 0, 0, 421, 0, 0, 422, 0, 0, 0, 423, 0, 0, 0, 424, 0, 0, 0, 425, 0, 0,
-    0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, 0, 429, 0,
-    0, 0, 0, 0, 0, 0, 430, 0, 0, 0, 0, 0, 0, 0, 431, 0, 0, 432, 0, 0, 0, 0,
-    433, 0, 0, 434, 0, 0, 0, 435, 0, 0, 0, 436, 0, 0, 0, 437, 0, 0, 0, 438,
-    0, 0, 0, 439, 0, 0, 440, 0, 0, 0, 0, 0, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0,
-    442, 0, 0, 0, 0, 0, 0, 0, 443, 0, 0, 0, 0, 0, 0, 444, 0, 0, 0, 0, 0, 0,
-    0, 445, 0, 0, 0, 0, 0, 0, 0, 446, 0, 0, 0, 447, 0, 0, 0, 448, 0, 0, 0,
-    449, 0, 0, 450, 0, 0, 0, 0, 0, 0, 0, 451, 0, 0, 0, 0, 0, 0, 0, 452, 0, 0,
-    0, 0, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 454, 0, 0, 0, 0, 0, 0, 0, 455, 0,
-    0, 0, 0, 0, 0, 0, 456, 0, 0, 0, 0, 0, 0, 0, 457, 0, 0, 0, 0, 0, 0, 458,
-    0, 0, 0, 0, 0, 0, 0, 459, 0, 0, 0, 0, 0, 0, 0, 460, 0, 0, 0, 461, 0, 0,
-    0, 462, 0, 0, 0, 0, 0, 0, 463, 0, 0, 0, 0, 0, 0, 0, 464, 0, 0, 0, 465, 0,
-    0, 0, 466, 0, 0, 0, 0, 0, 0, 467, 0, 0, 0, 0, 0, 0, 0, 468, 0, 0, 0, 0,
-    0, 0, 0, 469, 0, 0, 0, 0, 0, 0, 0, 470, 0, 0, 0, 0, 0, 0, 471, 0, 0, 0,
-    0, 0, 0, 0, 472, 0, 0, 0, 0, 0, 0, 0, 473, 0, 0, 0, 0, 0, 0, 0, 474, 0,
-    0, 0, 0, 0, 0, 475, 0, 0, 0, 0, 0, 0, 0, 476, 0, 0, 0, 0, 0, 0, 0, 477,
-    0, 0, 0, 0, 0, 0, 0, 478, 0, 0, 0, 0, 0, 0, 479, 0, 0, 0, 0, 0, 0, 0,
-    480, 0, 0, 0, 0, 0, 0, 0, 481, 0, 0, 0, 0, 0, 0, 0, 482, 0, 0, 0, 0, 0,
-    0, 483, 0, 0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 0, 0, 485, 0, 0, 0, 0,
-    0, 0, 0, 486, 0, 0, 0, 0, 0, 0, 487, 0, 0, 0, 0, 0, 0, 0, 488, 0, 0, 0,
-    0, 0, 0, 0, 489, 0, 0, 0, 0, 0, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0,
-    0, 0, 0, 0, 0, 492, 0, 0, 0, 0, 0, 0, 0, 493, 0, 0, 0, 0, 0, 0, 0, 494,
-    0, 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0,
-    497, 0, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, 0, 0,
-    0, 500, 0, 0, 0, 0, 0, 0, 0, 501, 0, 0, 0, 0, 0, 0, 0, 502, 0, 0, 0, 0,
-    0, 0, 503, 0, 0, 0, 0, 0, 0, 0, 504, 0, 0, 0, 0, 0, 0, 0, 505, 0, 0, 0,
-    0, 0, 0, 0, 506, 0, 0, 0, 0, 0, 0, 507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    508, 0, 0, 0, 0, 0, 0, 0, 509, 0, 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0,
-    0, 0, 511, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, 0, 0, 0, 0, 513, 0, 0, 0, 0,
-    0, 0, 0, 514, 0, 0, 0, 0, 0, 0, 0, 515, 0, 0, 0, 0, 0, 0, 516, 0, 0, 0,
-    0, 0, 0, 0, 517, 0, 0, 0, 0, 0, 0, 0, 518, 0, 0, 0, 0, 0, 0, 0, 519, 0,
-    0, 0, 0, 0, 0, 520, 0, 0, 0, 0, 0, 0, 0, 521, 0, 0, 0, 0, 0, 0, 0, 522,
-    0, 0, 0, 0, 0, 0, 0, 523, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0,
-    525, 0, 0, 0, 0, 0, 0, 0, 526, 0, 0, 0, 0, 0, 0, 0, 527, 0, 0, 0, 0, 0,
-    0, 528, 0, 0, 0, 0, 0, 0, 0, 529, 0, 0, 0, 0, 0, 0, 0, 530, 0, 0, 0, 0,
-    0, 0, 0, 531, 0, 0, 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, 0, 0, 533, 0, 0, 0,
-    0, 0, 0, 0, 534, 0, 0, 0, 0, 0, 0, 0, 535, 0, 0, 0, 0, 0, 0, 536, 0, 0,
-    0, 0, 0, 0, 0, 537, 0, 0, 0, 0, 0, 0, 0, 538, 0, 0, 0, 0, 0, 0, 0, 539,
-    0, 0, 0, 0, 0, 0, 540, 0, 0, 0, 0, 0, 0, 0, 541, 0, 0, 0, 0, 0, 0, 0,
-    542, 0, 0, 0, 0, 0, 0, 0, 543, 0, 0, 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 0,
-    0, 545, 0, 0, 0, 0, 0, 0, 0, 546, 0, 0, 0, 0, 0, 0, 0, 547, 0, 0, 0, 0,
-    0, 0, 548, 0, 0, 0, 0, 0, 0, 0, 549, 0, 0, 0, 0, 0, 0, 0, 550, 0, 0, 0,
-    0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 0, 552, 0, 0, 0, 0, 0, 0, 0, 553, 0, 0,
-    0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 556,
-    0, 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, 0, 0,
-    559, 0, 0, 0, 0, 0, 0, 0, 560, 0, 0, 0, 0, 0, 0, 0, 561, 0, 0, 0, 0, 0,
-    0, 0, 562, 0, 0, 0, 0, 0, 0, 0, 563, 0, 0, 0, 0, 0, 0, 564,
-};
-
-static const unsigned short comp_index1[] = {
-    0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10,
-    0, 11, 12, 0, 13, 0, 0, 0, 0, 0, 0, 14, 15, 0, 0, 0, 0, 16, 0, 0, 0, 0,
-    0, 17, 18, 0, 19, 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, 22, 0, 23, 0, 0, 24, 0,
-    25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 33, 34, 0, 35, 0, 36, 37, 38, 0, 0,
-    0, 0, 0, 39, 0, 0, 0, 40, 41, 42, 43, 0, 44, 0, 0, 0, 0, 45, 0, 0, 0, 0,
-    0, 46, 0, 47, 0, 48, 0, 0, 49, 0, 50, 0, 51, 0, 0, 52, 53, 54, 55, 56,
-    57, 58, 0, 59, 0, 0, 60, 61, 0, 0, 0, 62, 0, 0, 0, 0, 0, 63, 64, 0, 0,
-    65, 0, 66, 0, 0, 67, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 69, 0, 0, 70, 0, 71,
-    72, 0, 73, 0, 74, 0, 0, 75, 0, 0, 0, 0, 76, 0, 0, 77, 78, 0, 79, 0, 80,
-    0, 0, 81, 0, 82, 83, 0, 84, 0, 0, 0, 0, 0, 85, 86, 87, 88, 89, 90, 91, 0,
-    92, 0, 0, 93, 0, 0, 0, 94, 0, 0, 95, 0, 0, 0, 96, 0, 0, 97, 0, 98, 99, 0,
-    100, 0, 101, 0, 0, 102, 0, 103, 104, 0, 105, 0, 106, 0, 0, 107, 0, 108,
-    0, 0, 0, 109, 0, 110, 0, 0, 111, 0, 112, 113, 0, 114, 0, 0, 0, 0, 0, 115,
-    116, 117, 118, 119, 120, 121, 0, 122, 123, 0, 124, 125, 0, 0, 0, 126, 0,
-    0, 127, 0, 0, 128, 129, 0, 130, 131, 0, 0, 0, 0, 0, 132, 0, 0, 0, 133,
-    134, 135, 136, 137, 0, 0, 0, 138, 0, 0, 139, 140, 0, 141, 0, 142, 0, 0,
-    143, 0, 0, 0, 0, 144, 0, 145, 146, 147, 148, 149, 150, 151, 0, 152, 153,
-    0, 154, 0, 0, 155, 0, 0, 0, 0, 156, 157, 0, 0, 0, 0, 0, 158, 159, 0, 160,
-    0, 161, 162, 0, 0, 0, 163, 0, 164, 0, 0, 165, 0, 166, 167, 0, 168, 0,
-    169, 170, 171, 172, 173, 174, 175, 0, 176, 0, 177, 178, 179, 0, 0, 0, 0,
-    0, 180, 0, 0, 0, 181, 182, 183, 184, 0, 185, 186, 0, 0, 0, 0, 0, 187, 0,
-    188, 0, 189, 0, 0, 190, 0, 191, 0, 192, 193, 0, 194, 195, 196, 197, 198,
-    199, 200, 0, 201, 0, 0, 202, 203, 0, 0, 0, 204, 0, 0, 0, 205, 0, 0, 0, 0,
-    0, 206, 0, 0, 0, 0, 207, 0, 0, 208, 0, 209, 0, 0, 210, 0, 211, 0, 0, 0,
-    0, 212, 0, 0, 213, 0, 214, 215, 0, 216, 0, 217, 0, 0, 218, 219, 0, 0, 0,
-    0, 0, 0, 220, 221, 0, 222, 0, 223, 0, 0, 224, 0, 225, 226, 0, 227, 0, 0,
-    0, 0, 0, 228, 229, 230, 231, 232, 233, 234, 0, 235, 0, 0, 236, 0, 0, 0,
-    237, 0, 0, 238, 0, 0, 0, 239, 0, 0, 240, 0, 241, 242, 0, 243, 0, 244, 0,
-    0, 245, 0, 0, 0, 0, 0, 246, 247, 0, 248, 0, 249, 0, 0, 250, 0, 251, 0, 0,
-    0, 252, 0, 253, 0, 0, 254, 0, 255, 256, 0, 257, 0, 258, 259, 260, 261,
-    262, 263, 264, 0, 265, 266, 0, 267, 268, 0, 0, 0, 269, 0, 0, 270, 0, 0,
-    0, 0, 0, 0, 271, 272, 0, 273, 274, 0, 0, 0, 275, 0, 276, 0, 0, 0, 277,
-    278, 279, 280, 281, 0, 0, 0, 282, 0, 0, 283, 284, 0, 285, 0, 286, 0, 0,
-    287, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 289, 0, 290, 0, 0, 0, 0, 291, 292,
-    0, 0, 293, 0, 0, 0, 0, 294, 295, 0, 0, 0, 0, 0, 0, 296, 0, 297, 0, 0, 0,
-    0, 298, 0, 0, 299, 300, 0, 0, 301, 0, 0, 302, 0, 0, 0, 0, 0, 0, 303, 304,
-    0, 0, 305, 0, 0, 306, 0, 307, 308, 0, 0, 0, 0, 0, 309, 310, 0, 0, 0, 0,
-    0, 0, 311, 0, 312, 0, 0, 313, 0, 0, 0, 0, 0, 314, 315, 0, 0, 316, 0, 0,
-    0, 0, 317, 318, 0, 0, 0, 0, 0, 0, 319, 0, 320, 0, 0, 0, 0, 321, 0, 0,
-    322, 323, 0, 0, 324, 0, 0, 325, 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, 328, 0,
-    0, 329, 0, 330, 331, 0, 0, 0, 0, 0, 332, 333, 0, 0, 0, 0, 0, 0, 334, 0,
-    335, 0, 0, 336, 0, 0, 0, 0, 0, 337, 338, 0, 0, 339, 0, 0, 340, 341, 0, 0,
-    342, 0, 0, 343, 0, 0, 0, 0, 0, 0, 344, 0, 0, 345, 0, 0, 346, 0, 0, 0, 0,
-    0, 347, 0, 0, 348, 0, 0, 349, 0, 0, 350, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0,
-    352, 0, 353, 0, 0, 354, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 356, 357, 0, 0,
-    358, 0, 0, 0, 359, 0, 0, 360, 361, 0, 0, 362, 0, 0, 0, 363, 0, 0, 364,
-    365, 0, 0, 366, 0, 0, 0, 367, 0, 0, 368, 369, 0, 0, 370, 0, 0, 0, 371, 0,
-    0, 0, 372, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 375, 0, 0, 376, 0,
-    0, 377, 0, 0, 0, 0, 0, 0, 378, 0, 0, 379, 0, 0, 380, 0, 0, 0, 0, 0, 381,
-    0, 382, 0, 383, 384, 0, 0, 0, 0, 0, 0, 385, 386, 0, 0, 0, 0, 0, 0, 387,
-    0, 0, 0, 388, 0, 0, 389, 0, 0, 390, 0, 0, 0, 0, 391, 0, 392, 393, 0, 0,
-    0, 394, 0, 0, 0, 395, 0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 398, 0,
-    399, 400, 0, 0, 0, 401, 0, 0, 0, 402, 0, 0, 403, 0, 0, 404, 0, 0, 0, 0,
-    0, 0, 405, 0, 0, 406, 0, 0, 0, 0, 407, 0, 408, 0, 0, 0, 0, 409, 0, 0,
-    410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 413, 0, 0, 414, 0, 0, 0, 0, 0,
-    0, 415, 416, 0, 417, 418, 0, 0, 0, 419, 0, 0, 420, 0, 0, 0, 0, 421, 0, 0,
-    422, 0, 0, 423, 0, 0, 0, 424, 0, 425, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0,
-    0, 428, 429, 0, 0, 0, 0, 0, 0, 430, 0, 0, 431, 0, 0, 0, 0, 432, 0, 433,
-    0, 0, 0, 0, 434, 0, 435, 0, 0, 0, 0, 0, 0, 436, 437, 0, 0, 438, 0, 0,
-    439, 0, 440, 441, 0, 0, 0, 442, 0, 0, 443, 0, 444, 445, 0, 446, 447, 0,
-    0, 448, 0, 0, 0, 449, 0, 450, 451, 0, 0, 0, 452, 0, 0, 0, 0, 0, 453, 0,
-    454, 455, 0, 456, 457, 0, 0, 0, 0, 0, 0, 458, 0, 0, 459, 0, 460, 461, 0,
-    0, 0, 462, 0, 0, 463, 0, 464, 465, 0, 466, 467, 0, 0, 468, 0, 0, 0, 469,
-    0, 470, 471, 0, 0, 0, 472, 0, 0, 0, 0, 0, 473, 0, 474, 475, 0, 476, 477,
-    0, 0, 0, 0, 0, 0, 478, 0, 0, 479, 0, 0, 480, 0, 0, 0, 0, 0, 481, 0, 0,
-    482, 0, 0, 0, 483, 0, 0, 484, 0, 0, 485, 0, 0, 0, 0, 0, 0, 486, 0, 0,
-    487, 488, 0, 489, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0, 492, 0, 0, 493,
-    0, 0, 0, 494, 0, 0, 495, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 497, 0, 0, 0,
-    498, 499, 0, 0, 0, 500, 0, 0, 0, 0, 0, 501, 502, 0, 503, 0, 0, 0, 504, 0,
-    0, 0, 505, 0, 0, 506, 507, 0, 0, 0, 0, 0, 508, 0, 0, 0, 509, 510, 0, 0,
-    0, 0, 0, 511, 0, 0, 0, 512, 513, 0, 514, 0, 0, 0, 0, 515, 0, 0, 516, 0,
-    0, 517, 0, 0, 0, 0, 0, 0, 518, 0, 0, 519, 0, 0, 520, 0, 0, 521, 0, 0, 0,
-    0, 0, 0, 522, 0, 0, 523, 0, 0, 524, 0, 0, 525, 0, 0, 0, 0, 0, 0, 526, 0,
-    0, 0, 527, 0, 0, 528, 0, 0, 529, 0, 0, 530, 0, 0, 0, 531, 0, 0, 0, 0, 0,
-    0, 532, 533, 534, 0, 0, 0, 0, 0, 535, 536, 0, 0, 0, 0, 0, 537, 0, 0, 538,
-    0, 0, 539, 0, 0, 0, 0, 0, 0, 540, 0, 541, 0, 0, 0, 0, 0, 542, 543, 0, 0,
-    0, 0, 0, 544, 0, 0, 545, 0, 0, 546, 0, 0, 0, 0, 0, 0, 547, 0, 0, 548, 0,
-    0, 549, 0, 0, 550, 0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 552, 553, 0, 0, 0, 0,
-    0, 554, 0, 0, 555, 0, 0, 556, 0, 0, 0, 0, 0, 0, 557, 0, 0, 558, 0, 0,
-    559, 0, 0, 560, 0, 0, 0, 0, 561, 0, 0, 562, 0, 0, 0, 0, 0, 0, 563, 0, 0,
-    564, 0, 0, 565, 0, 0, 0, 0, 0, 566, 567, 0, 0, 0, 0, 0, 568, 0, 0, 569,
-    0, 0, 570, 0, 0, 0, 0, 0, 0, 571, 0, 0, 572, 0, 0, 573, 0, 0, 574, 0, 0,
-    0, 0, 575, 0, 0, 0, 0, 0, 576, 577, 0, 0, 0, 0, 0, 578, 0, 0, 579, 0, 0,
-    580, 0, 0, 0, 0, 0, 0, 581, 0, 0, 582, 0, 0, 583, 0, 0, 584, 0, 0, 0, 0,
-    585, 0, 0, 0, 0, 0, 586, 587, 0, 0, 0, 0, 0, 588, 0, 0, 0, 0, 589, 0,
-    590, 0, 0, 0, 0, 591, 0, 592, 0, 0, 0, 0, 593, 0, 0, 594, 0, 0, 0, 0, 0,
-    0, 595, 0, 0, 596, 0, 0, 597, 0, 0, 0, 0, 0, 598, 599, 0, 0, 0, 0, 0,
-    600, 0, 0, 0, 0, 601, 0, 602, 0, 0, 0, 0, 603, 0, 604, 0, 0, 0, 0, 605,
-    0, 0, 0, 0, 0, 606, 0, 0, 607, 0, 0, 608, 0, 0, 609, 0, 0, 0, 0, 0, 0,
-    610, 0, 0, 611, 0, 0, 612, 0, 0, 0, 0, 613, 0, 614, 0, 0, 0, 0, 615, 0,
-    0, 0, 0, 0, 616, 0, 0, 617, 0, 0, 618, 0, 0, 619, 0, 0, 0, 0, 0, 0, 620,
-    0, 0, 621, 0, 0, 622, 0, 0, 623, 0, 0, 0, 0, 0, 0, 624, 0, 0, 625, 0, 0,
-    626, 0, 0, 0, 0, 627, 0, 628, 0, 0, 0, 0, 0, 0, 629, 0, 0, 630, 0, 0, 0,
-    0, 631, 0, 632, 0, 0, 0, 0, 0, 633, 0, 0, 634, 0, 0, 635, 0, 0, 636, 0,
-    0, 0, 0, 0, 0, 637, 0, 0, 638, 0, 0, 639, 0, 0, 640, 0, 0, 0, 0, 0, 0,
-    641, 0, 0, 642, 0, 0, 643, 0, 0, 644, 0, 0, 0, 0, 0, 0, 645, 0, 0, 646,
-    0, 0, 647, 0, 0, 648, 0, 0, 0, 0, 0, 0, 649, 0, 0, 650, 0, 0, 651, 0, 0,
-    652, 0, 0, 0, 0, 0, 0, 653, 0, 0, 654, 0, 0, 655, 0, 0, 656, 0, 0, 0, 0,
-    0, 0, 657, 0, 0, 658, 0, 0, 659, 0, 0, 660, 0, 0, 0, 0, 0, 0, 661, 0, 0,
-    662, 0, 0, 663, 0, 0, 664, 0, 0, 0, 0, 0, 0, 665, 0, 0, 666, 0, 0, 667,
-    0, 0, 668, 0, 0, 0, 0, 0, 0, 669, 0, 0, 670, 0, 0, 671, 0, 0, 672, 0, 0,
-    0, 0, 0, 0, 673, 0, 0, 0, 674, 0, 0, 675, 0, 0, 676, 0, 0, 677, 0, 0, 0,
-    0, 0, 0, 678, 0, 0, 679, 0, 0, 680, 0, 0, 681, 0, 0, 0, 0, 0, 0, 682, 0,
-    0, 683, 0, 0, 684, 0, 0, 685, 0, 0, 0, 0, 0, 0, 686, 0, 0, 687, 0, 0,
-    688, 0, 0, 689, 0, 0, 0, 0, 0, 0, 690, 0, 0, 691, 0, 0, 692, 0, 0, 693,
-    0, 0, 0, 0, 0, 0, 694, 0, 0, 695, 0, 0, 696, 0, 0, 697, 0, 0, 0, 0, 0, 0,
-    698, 0, 0, 699, 0, 0, 700, 0, 0, 701, 0, 0, 0, 0, 0, 0, 702, 0, 0, 703,
-    0, 0, 704, 0, 0, 705, 0, 0, 0, 0, 0, 0, 706, 0, 0, 707, 0, 0, 708, 0, 0,
-    709, 0, 0, 0, 0, 0, 0, 710, 0, 0, 711, 0, 0, 712, 0, 0, 713, 0, 0, 0, 0,
-    0, 0, 714, 0, 0, 715, 0, 0, 716, 0, 0, 717, 0, 0, 0, 0, 0, 0, 718, 0, 0,
-    719, 0, 0, 720, 0, 0, 721, 0, 0, 0, 722, 0, 0, 0, 0, 0, 0, 723, 0, 0,
-    724, 0, 0, 725, 0, 0, 726, 0, 0, 0, 727, 0, 0, 0, 728, 729, 0, 0, 730, 0,
-    0, 0, 0, 0, 0, 731,
-};
-
-static const unsigned int comp_data[] = {
-    0, 0, 0, 8814, 0, 8800, 0, 8815, 192, 193, 194, 195, 256, 258, 550, 196,
-    7842, 197, 0, 461, 512, 514, 0, 7840, 0, 7680, 260, 0, 7682, 0, 0, 7684,
-    7686, 0, 0, 262, 264, 0, 266, 0, 0, 268, 0, 199, 7690, 0, 0, 270, 0,
-    7692, 0, 7696, 0, 7698, 7694, 0, 200, 201, 202, 7868, 274, 276, 278, 203,
-    7866, 0, 0, 282, 516, 518, 0, 7864, 0, 552, 280, 7704, 0, 7706, 7710, 0,
-    0, 500, 284, 0, 7712, 286, 288, 0, 0, 486, 0, 290, 292, 0, 7714, 7718, 0,
-    542, 0, 7716, 0, 7720, 7722, 0, 204, 205, 206, 296, 298, 300, 304, 207,
-    7880, 0, 0, 463, 520, 522, 0, 7882, 302, 0, 0, 7724, 308, 0, 0, 7728, 0,
-    488, 0, 7730, 0, 310, 7732, 0, 0, 313, 0, 317, 0, 7734, 0, 315, 0, 7740,
-    7738, 0, 0, 7742, 7744, 0, 0, 7746, 504, 323, 0, 209, 7748, 0, 0, 327, 0,
-    7750, 0, 325, 0, 7754, 7752, 0, 210, 211, 212, 213, 332, 334, 558, 214,
-    7886, 0, 336, 465, 524, 526, 416, 7884, 490, 0, 0, 7764, 7766, 0, 0, 340,
-    7768, 0, 0, 344, 528, 530, 0, 7770, 0, 342, 7774, 0, 0, 346, 348, 0,
-    7776, 0, 0, 352, 0, 7778, 536, 350, 7786, 0, 0, 356, 0, 7788, 538, 354,
-    0, 7792, 7790, 0, 217, 218, 219, 360, 362, 364, 0, 220, 7910, 366, 368,
-    467, 532, 534, 431, 7908, 7794, 0, 370, 7798, 0, 7796, 0, 7804, 0, 7806,
-    7808, 7810, 372, 0, 7814, 7812, 0, 7816, 7818, 7820, 7922, 221, 374,
-    7928, 562, 0, 7822, 376, 7926, 0, 0, 7924, 0, 377, 7824, 0, 379, 0, 0,
-    381, 0, 7826, 7828, 0, 224, 225, 226, 227, 257, 259, 551, 228, 7843, 229,
-    0, 462, 513, 515, 0, 7841, 0, 7681, 261, 0, 7683, 0, 0, 7685, 7687, 0, 0,
-    263, 265, 0, 267, 0, 0, 269, 0, 231, 7691, 0, 0, 271, 0, 7693, 0, 7697,
-    0, 7699, 7695, 0, 232, 233, 234, 7869, 275, 277, 279, 235, 7867, 0, 0,
-    283, 517, 519, 0, 7865, 0, 553, 281, 7705, 0, 7707, 7711, 0, 0, 501, 285,
-    0, 7713, 287, 289, 0, 0, 487, 0, 291, 293, 0, 7715, 7719, 0, 543, 0,
-    7717, 0, 7721, 7723, 0, 7830, 0, 236, 237, 238, 297, 299, 301, 0, 239,
-    7881, 0, 0, 464, 521, 523, 0, 7883, 303, 0, 0, 7725, 309, 0, 0, 496, 0,
-    7729, 0, 489, 0, 7731, 0, 311, 7733, 0, 0, 314, 0, 318, 0, 7735, 0, 316,
-    0, 7741, 7739, 0, 0, 7743, 7745, 0, 0, 7747, 505, 324, 0, 241, 7749, 0,
-    0, 328, 0, 7751, 0, 326, 0, 7755, 7753, 0, 242, 243, 244, 245, 333, 335,
-    559, 246, 7887, 0, 337, 466, 525, 527, 417, 7885, 491, 0, 0, 7765, 7767,
-    0, 0, 341, 7769, 0, 0, 345, 529, 531, 0, 7771, 0, 343, 7775, 0, 0, 347,
-    349, 0, 7777, 0, 0, 353, 0, 7779, 537, 351, 7787, 7831, 0, 357, 0, 7789,
-    539, 355, 0, 7793, 7791, 0, 249, 250, 251, 361, 363, 365, 0, 252, 7911,
-    367, 369, 468, 533, 535, 432, 7909, 7795, 0, 371, 7799, 0, 7797, 0, 7805,
-    0, 7807, 7809, 7811, 373, 0, 7815, 7813, 0, 7832, 0, 7817, 7819, 7821,
-    7923, 253, 375, 7929, 563, 0, 7823, 255, 7927, 7833, 0, 7925, 0, 378,
-    7825, 0, 380, 0, 0, 382, 0, 7827, 7829, 0, 8173, 901, 8129, 0, 7846,
-    7844, 0, 7850, 7848, 0, 478, 0, 0, 506, 0, 508, 482, 0, 0, 7688, 7872,
-    7870, 0, 7876, 7874, 0, 0, 7726, 7890, 7888, 0, 7894, 7892, 0, 0, 7756,
-    556, 0, 0, 7758, 554, 0, 0, 510, 475, 471, 469, 0, 0, 473, 7847, 7845, 0,
-    7851, 7849, 0, 479, 0, 0, 507, 0, 509, 483, 0, 0, 7689, 7873, 7871, 0,
-    7877, 7875, 0, 0, 7727, 7891, 7889, 0, 7895, 7893, 0, 0, 7757, 557, 0, 0,
-    7759, 555, 0, 0, 511, 476, 472, 470, 0, 0, 474, 7856, 7854, 0, 7860,
-    7858, 0, 7857, 7855, 0, 7861, 7859, 0, 7700, 7702, 7701, 7703, 7760,
-    7762, 7761, 7763, 7780, 0, 7781, 0, 7782, 0, 7783, 0, 0, 7800, 0, 7801,
-    0, 7802, 0, 7803, 7835, 0, 7900, 7898, 0, 7904, 7902, 0, 0, 7906, 7901,
-    7899, 0, 7905, 7903, 0, 0, 7907, 7914, 7912, 0, 7918, 7916, 0, 0, 7920,
-    7915, 7913, 0, 7919, 7917, 0, 0, 7921, 0, 494, 492, 0, 493, 0, 480, 0,
-    481, 0, 0, 7708, 0, 7709, 560, 0, 561, 0, 0, 495, 8122, 902, 8121, 8120,
-    7944, 7945, 0, 8124, 8136, 904, 7960, 7961, 8138, 905, 7976, 7977, 0,
-    8140, 8154, 906, 8153, 8152, 0, 938, 7992, 7993, 8184, 908, 8008, 8009,
-    0, 8172, 8170, 910, 8169, 8168, 0, 939, 0, 8025, 8186, 911, 8040, 8041,
-    0, 8188, 0, 8116, 0, 8132, 8048, 940, 8113, 8112, 7936, 7937, 8118, 8115,
-    8050, 941, 7952, 7953, 8052, 942, 7968, 7969, 8134, 8131, 8054, 943,
-    8145, 8144, 0, 970, 7984, 7985, 8150, 0, 8056, 972, 8000, 8001, 8164,
-    8165, 8058, 973, 8161, 8160, 0, 971, 8016, 8017, 8166, 0, 8060, 974,
-    8032, 8033, 8182, 8179, 8146, 912, 8151, 0, 8162, 944, 8167, 0, 0, 8180,
-    0, 979, 0, 980, 0, 1031, 0, 1232, 0, 1234, 0, 1027, 1024, 0, 0, 1238, 0,
-    1025, 0, 1217, 0, 1244, 0, 1246, 1037, 0, 1250, 1049, 0, 1252, 0, 1036,
-    0, 1254, 1262, 1038, 0, 1264, 1266, 0, 0, 1268, 0, 1272, 0, 1260, 0,
-    1233, 0, 1235, 0, 1107, 1104, 0, 0, 1239, 0, 1105, 0, 1218, 0, 1245, 0,
-    1247, 1117, 0, 1251, 1081, 0, 1253, 0, 1116, 0, 1255, 1263, 1118, 0,
-    1265, 1267, 0, 0, 1269, 0, 1273, 0, 1261, 0, 1111, 1142, 0, 1143, 0, 0,
-    1242, 0, 1243, 0, 1258, 0, 1259, 1570, 1571, 1573, 0, 0, 1572, 0, 1574,
-    0, 1730, 0, 1747, 0, 1728, 0, 2345, 0, 2353, 0, 2356, 2507, 2508, 2891,
-    2888, 2892, 0, 2964, 0, 0, 3018, 3020, 0, 0, 3019, 0, 3144, 0, 3264,
-    3274, 3271, 3272, 0, 0, 3275, 0, 3402, 3404, 0, 0, 3403, 0, 3546, 3548,
-    3550, 0, 3549, 4134, 0, 0, 6918, 0, 6920, 0, 6922, 0, 6924, 0, 6926, 0,
-    6930, 0, 6971, 0, 6973, 0, 6976, 0, 6977, 0, 6979, 7736, 0, 7737, 0,
-    7772, 0, 7773, 0, 7784, 0, 7785, 0, 7852, 0, 0, 7862, 7853, 0, 0, 7863,
-    7878, 0, 7879, 0, 7896, 0, 7897, 0, 7938, 7940, 7942, 8064, 7939, 7941,
-    7943, 8065, 0, 8066, 0, 8067, 0, 8068, 0, 8069, 0, 8070, 0, 8071, 7946,
-    7948, 7950, 8072, 7947, 7949, 7951, 8073, 0, 8074, 0, 8075, 0, 8076, 0,
-    8077, 0, 8078, 0, 8079, 7954, 7956, 7955, 7957, 7962, 7964, 7963, 7965,
-    7970, 7972, 7974, 8080, 7971, 7973, 7975, 8081, 0, 8082, 0, 8083, 0,
-    8084, 0, 8085, 0, 8086, 0, 8087, 7978, 7980, 7982, 8088, 7979, 7981,
-    7983, 8089, 0, 8090, 0, 8091, 0, 8092, 0, 8093, 0, 8094, 0, 8095, 7986,
-    7988, 7990, 0, 7987, 7989, 7991, 0, 7994, 7996, 7998, 0, 7995, 7997,
-    7999, 0, 8002, 8004, 8003, 8005, 8010, 8012, 8011, 8013, 8018, 8020,
-    8022, 0, 8019, 8021, 8023, 0, 8027, 8029, 8031, 0, 8034, 8036, 8038,
-    8096, 8035, 8037, 8039, 8097, 0, 8098, 0, 8099, 0, 8100, 0, 8101, 0,
-    8102, 0, 8103, 8042, 8044, 8046, 8104, 8043, 8045, 8047, 8105, 0, 8106,
-    0, 8107, 0, 8108, 0, 8109, 0, 8110, 0, 8111, 0, 8114, 0, 8130, 0, 8178,
-    0, 8119, 8141, 8142, 8143, 0, 0, 8135, 0, 8183, 8157, 8158, 8159, 0, 0,
-    8602, 0, 8603, 0, 8622, 0, 8653, 0, 8655, 0, 8654, 0, 8708, 0, 8713, 0,
-    8716, 0, 8740, 0, 8742, 0, 8769, 0, 8772, 0, 8775, 0, 8777, 0, 8813, 0,
-    8802, 0, 8816, 0, 8817, 0, 8820, 0, 8821, 0, 8824, 0, 8825, 0, 8832, 0,
-    8833, 0, 8928, 0, 8929, 0, 8836, 0, 8837, 0, 8840, 0, 8841, 0, 8930, 0,
-    8931, 0, 8876, 0, 8877, 0, 8878, 0, 8879, 0, 8938, 0, 8939, 0, 8940, 0,
-    8941, 12436, 0, 12364, 0, 12366, 0, 12368, 0, 12370, 0, 12372, 0, 12374,
-    0, 12376, 0, 12378, 0, 12380, 0, 12382, 0, 12384, 0, 12386, 0, 12389, 0,
-    12391, 0, 12393, 0, 12400, 12401, 12403, 12404, 12406, 12407, 12409,
-    12410, 12412, 12413, 12446, 0, 12532, 0, 12460, 0, 12462, 0, 12464, 0,
-    12466, 0, 12468, 0, 12470, 0, 12472, 0, 12474, 0, 12476, 0, 12478, 0,
-    12480, 0, 12482, 0, 12485, 0, 12487, 0, 12489, 0, 12496, 12497, 12499,
-    12500, 12502, 12503, 12505, 12506, 12508, 12509, 12535, 0, 12536, 0,
-    12537, 0, 12538, 0, 12542, 0, 69786, 0, 69788, 0, 69803, 0, 0, 69934, 0,
-    69935, 70475, 70476, 70844, 70843, 70846, 0, 0, 71098, 0, 71099,
-};
-
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh
index 1dd0b32..eb7776e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh
@@ -7,13 +7,13 @@
  * on file with this header:
  *
  * # emoji-data.txt
- * # Date: 2018-02-07, 07:55:18 GMT
- * # © 2018 Unicode®, Inc.
+ * # Date: 2020-01-28, 20:52:38 GMT
+ * # © 2020 Unicode®, Inc.
  * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
  * # For terms of use, see http://www.unicode.org/terms_of_use.html
  * #
  * # Emoji Data for UTS #51
- * # Version: 11.0
+ * # Version: 13.0
  * #
  * # For documentation and usage, see http://www.unicode.org/reports/tr51
  */
@@ -23,88 +23,56 @@
 
 #include "hb-unicode.hh"
 
-
-static const struct hb_unicode_range_t _hb_unicode_emoji_Extended_Pictographic_table[] =
+static const uint8_t
+_hb_emoji_u8[448] =
 {
-  {0x00A9, 0x00A9},
-  {0x00AE, 0x00AE},
-  {0x203C, 0x203C},
-  {0x2049, 0x2049},
-  {0x2122, 0x2122},
-  {0x2139, 0x2139},
-  {0x2194, 0x2199},
-  {0x21A9, 0x21AA},
-  {0x231A, 0x231B},
-  {0x2328, 0x2328},
-  {0x2388, 0x2388},
-  {0x23CF, 0x23CF},
-  {0x23E9, 0x23F3},
-  {0x23F8, 0x23FA},
-  {0x24C2, 0x24C2},
-  {0x25AA, 0x25AB},
-  {0x25B6, 0x25B6},
-  {0x25C0, 0x25C0},
-  {0x25FB, 0x25FE},
-  {0x2600, 0x2605},
-  {0x2607, 0x2612},
-  {0x2614, 0x2685},
-  {0x2690, 0x2705},
-  {0x2708, 0x2712},
-  {0x2714, 0x2714},
-  {0x2716, 0x2716},
-  {0x271D, 0x271D},
-  {0x2721, 0x2721},
-  {0x2728, 0x2728},
-  {0x2733, 0x2734},
-  {0x2744, 0x2744},
-  {0x2747, 0x2747},
-  {0x274C, 0x274C},
-  {0x274E, 0x274E},
-  {0x2753, 0x2755},
-  {0x2757, 0x2757},
-  {0x2763, 0x2767},
-  {0x2795, 0x2797},
-  {0x27A1, 0x27A1},
-  {0x27B0, 0x27B0},
-  {0x27BF, 0x27BF},
-  {0x2934, 0x2935},
-  {0x2B05, 0x2B07},
-  {0x2B1B, 0x2B1C},
-  {0x2B50, 0x2B50},
-  {0x2B55, 0x2B55},
-  {0x3030, 0x3030},
-  {0x303D, 0x303D},
-  {0x3297, 0x3297},
-  {0x3299, 0x3299},
-  {0x1F000, 0x1F0FF},
-  {0x1F10D, 0x1F10F},
-  {0x1F12F, 0x1F12F},
-  {0x1F16C, 0x1F171},
-  {0x1F17E, 0x1F17F},
-  {0x1F18E, 0x1F18E},
-  {0x1F191, 0x1F19A},
-  {0x1F1AD, 0x1F1E5},
-  {0x1F201, 0x1F20F},
-  {0x1F21A, 0x1F21A},
-  {0x1F22F, 0x1F22F},
-  {0x1F232, 0x1F23A},
-  {0x1F23C, 0x1F23F},
-  {0x1F249, 0x1F3FA},
-  {0x1F400, 0x1F53D},
-  {0x1F546, 0x1F64F},
-  {0x1F680, 0x1F6FF},
-  {0x1F774, 0x1F77F},
-  {0x1F7D5, 0x1F7FF},
-  {0x1F80C, 0x1F80F},
-  {0x1F848, 0x1F84F},
-  {0x1F85A, 0x1F85F},
-  {0x1F888, 0x1F88F},
-  {0x1F8AE, 0x1F8FF},
-  {0x1F90C, 0x1F93A},
-  {0x1F93C, 0x1F945},
-  {0x1F947, 0x1FFFD},
+    0,  0,  0,  0, 33,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 84,118,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  2,  0,  0,  3,
+    0,  0,  0,  0,  0,  0,  4,  5,  6,  7,  8,  7,  9, 10, 11,  0,
+    0,  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0, 13,  0,  0,  0,
+    7,  7,  7, 14, 15, 16, 17, 18, 19, 20,  7,  7,  7,  7,  7, 21,
+    7,  7,  7,  7, 22, 23,  7,  7,  7, 24,  7, 14,  0, 25,  0, 26,
+   27, 28, 29, 14, 30, 31,  7,  7,  7,  7,  7, 14,  0,  0,  0,  0,
+    7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7, 22,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,  1,  0,  2,  0,  0,
+    0,  0,  0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0,254,  7,  3,
+    0,  0,  0,  0,  0,  4,  0,  0,  0,  0,  0,  0,  0,  0,  0, 56,
+  159,255,243,255,255,255,255,255,255,255,255,255,255,255,255,255,
+   31,  0,255,255,255,255,255,255, 31,255,  3,  0,  0,  0,  8,  0,
+    0,  0, 24,  0,120,  0,  0,  0,  0,  0, 96,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0, 16,  0, 96,  0,  0,  8,  0,  0,  0,  0,
+  255,255,255,255,255,255,255,127,  0, 96,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,240,  1, 64,  0,  0,254,  3,  0,224,255,255,
+  255,255,255,255, 31,  0,  0,  0,254,127,  0,  0,  0,  0,252,115,
+    0,254,255,255,255,255,255,255,255,255,255,255,255,255,255,  3,
+  255,255,255,255,255,255,255, 31,192,255,255,255,255,255,255,255,
+  255,127,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,127,
+    0,  0,224,255,255,255,255,127,  0,112,  0,  0,  0,  0,  0,  0,
+    0,127,  0,124,  0,  0,  0,  0,  0,127,  0,  0,  0,192,255,255,
+    0,240,255,255,255,255,255,243,159,255,255,255,255,255,255,255,
 };
 
+static inline unsigned
+_hb_emoji_b4 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline unsigned
+_hb_emoji_b1 (const uint8_t* a, unsigned i)
+{
+  return (a[i>>3]>>((i&7u)<<0))&1u;
+}
+static inline uint_fast8_t
+_hb_emoji_is_Extended_Pictographic (unsigned u)
+{
+  return u<131069u?_hb_emoji_b1(192+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0;
+}
+
+
 #endif /* HB_UNICODE_EMOJI_TABLE_HH */
 
 /* == End of generated table == */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc b/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc
index 47e6af6..8530289 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc
+++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc
@@ -60,6 +60,7 @@
   return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED;
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 static unsigned int
 hb_unicode_eastasian_width_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
                                 hb_codepoint_t      unicode   HB_UNUSED,
@@ -67,6 +68,7 @@
 {
   return 1;
 }
+#endif
 
 static hb_unicode_general_category_t
 hb_unicode_general_category_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
@@ -113,6 +115,7 @@
 }
 
 
+#ifndef HB_DISABLE_DEPRECATED
 static unsigned int
 hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs     HB_UNUSED,
                                         hb_codepoint_t      u          HB_UNUSED,
@@ -121,20 +124,23 @@
 {
   return 0;
 }
+#endif
 
-
-extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs ();
-extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs ();
-extern "C" hb_unicode_funcs_t *hb_ucdn_get_unicode_funcs ();
+#if !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_GLIB)
+#include "hb-glib.h"
+#endif
+#if !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
+#include "hb-icu.h"
+#endif
 
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_default ()
 {
-#if defined(HAVE_UCDN)
-  return hb_ucdn_get_unicode_funcs ();
-#elif defined(HAVE_GLIB)
+#if !defined(HB_NO_UNICODE_FUNCS) && !defined(HB_NO_UCD)
+  return hb_ucd_get_unicode_funcs ();
+#elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_GLIB)
   return hb_glib_get_unicode_funcs ();
-#elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
+#elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
   return hb_icu_get_unicode_funcs ();
 #else
 #define HB_UNICODE_FUNCS_NIL 1
@@ -144,7 +150,7 @@
 
 #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
 #error "Could not find any Unicode functions implementation, you have to provide your own"
-#error "Consider building hb-ucdn.c.  If you absolutely want to build without any, check the code."
+#error "Consider building hb-ucd.cc.  If you absolutely want to build without any, check the code."
 #endif
 
 /**
@@ -206,7 +212,7 @@
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_empty ()
 {
-  return const_cast<hb_unicode_funcs_t *> (&Null(hb_unicode_funcs_t));
+  return const_cast<hb_unicode_funcs_t *> (&Null (hb_unicode_funcs_t));
 }
 
 /**
@@ -425,6 +431,7 @@
   return ufuncs->decompose (ab, a, b);
 }
 
+#ifndef HB_DISABLE_DEPRECATED
 /**
  * hb_unicode_decompose_compatibility:
  * @ufuncs: Unicode functions.
@@ -445,8 +452,10 @@
 {
   return ufuncs->decompose_compatibility (u, decomposed);
 }
+#endif
 
 
+#ifndef HB_NO_OT_SHAPE
 /* See hb-unicode.hh for details. */
 const uint8_t
 _hb_modified_combining_class[256] =
@@ -559,19 +568,19 @@
   241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
   255, /* HB_UNICODE_COMBINING_CLASS_INVALID */
 };
+#endif
 
 
 /*
  * Emoji
  */
+#ifndef HB_NO_EMOJI_SEQUENCES
 
 #include "hb-unicode-emoji-table.hh"
 
 bool
 _hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp)
 {
-  return hb_bsearch (&cp, _hb_unicode_emoji_Extended_Pictographic_table,
-                     ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table),
-                     sizeof (hb_unicode_range_t),
-                     hb_unicode_range_t::cmp);
+  return _hb_emoji_is_Extended_Pictographic (cp);
 }
+#endif
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh
index 24b03c2..40f6a5a 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh
@@ -42,19 +42,19 @@
 
 #define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS \
   HB_UNICODE_FUNC_IMPLEMENT (combining_class) \
-  HB_UNICODE_FUNC_IMPLEMENT (eastasian_width) \
+  HB_IF_NOT_DEPRECATED (HB_UNICODE_FUNC_IMPLEMENT (eastasian_width)) \
   HB_UNICODE_FUNC_IMPLEMENT (general_category) \
   HB_UNICODE_FUNC_IMPLEMENT (mirroring) \
   HB_UNICODE_FUNC_IMPLEMENT (script) \
   HB_UNICODE_FUNC_IMPLEMENT (compose) \
   HB_UNICODE_FUNC_IMPLEMENT (decompose) \
-  HB_UNICODE_FUNC_IMPLEMENT (decompose_compatibility) \
+  HB_IF_NOT_DEPRECATED (HB_UNICODE_FUNC_IMPLEMENT (decompose_compatibility)) \
   /* ^--- Add new callbacks here */
 
 /* Simple callbacks are those taking a hb_codepoint_t and returning a hb_codepoint_t */
 #define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE \
   HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_combining_class_t, combining_class) \
-  HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width) \
+  HB_IF_NOT_DEPRECATED (HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width)) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_general_category_t, general_category) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_codepoint_t, mirroring) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_script_t, script) \
@@ -89,7 +89,11 @@
   unsigned int decompose_compatibility (hb_codepoint_t  u,
                                         hb_codepoint_t *decomposed)
   {
+#ifdef HB_DISABLE_DEPRECATED
+    unsigned int ret  = 0;
+#else
     unsigned int ret = func.decompose_compatibility (this, u, decomposed, user_data.decompose_compatibility);
+#endif
     if (ret == 1 && u == decomposed[0]) {
       decomposed[0] = 0;
       return 0;
@@ -101,9 +105,6 @@
   unsigned int
   modified_combining_class (hb_codepoint_t u)
   {
-    /* XXX This hack belongs to the Myanmar shaper. */
-    if (unlikely (u == 0x1037u)) u = 0x103Au;
-
     /* XXX This hack belongs to the USE shaper (for Tai Tham):
      * Reorder SAKOT to ensure it comes after any tone marks. */
     if (unlikely (u == 0x1A60u)) return 254;
@@ -322,11 +323,11 @@
  *
  * Modify Telugu length marks (ccc=84, ccc=91).
  * These are the only matras in the main Indic scripts range that have
- * a non-zero ccc.  That makes them reorder with the Halant that is
- * ccc=9.  Just zero them, we don't need them in our Indic shaper.
+ * a non-zero ccc.  That makes them reorder with the Halant (ccc=9).
+ * Assign 4 and 5, which are otherwise unassigned.
  */
-#define HB_MODIFIED_COMBINING_CLASS_CCC84 0 /* length mark */
-#define HB_MODIFIED_COMBINING_CLASS_CCC91 0 /* ai length mark */
+#define HB_MODIFIED_COMBINING_CLASS_CCC84 4 /* length mark */
+#define HB_MODIFIED_COMBINING_CLASS_CCC91 5 /* ai length mark */
 
 /* Thai
  *
@@ -391,4 +392,7 @@
 _hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp);
 
 
+extern "C" HB_INTERNAL hb_unicode_funcs_t *hb_ucd_get_unicode_funcs ();
+
+
 #endif /* HB_UNICODE_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh
index b438675..4a7a7a7 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh
@@ -38,103 +38,141 @@
   typedef Type item_t;
   static constexpr unsigned item_size = hb_static_size (Type);
 
-  HB_NO_COPY_ASSIGN_TEMPLATE (hb_vector_t, Type);
   hb_vector_t ()  { init (); }
+  hb_vector_t (const hb_vector_t &o)
+  {
+    init ();
+    alloc (o.length);
+    hb_copy (o, *this);
+  }
+  hb_vector_t (hb_vector_t &&o)
+  {
+    allocated = o.allocated;
+    length = o.length;
+    arrayZ = o.arrayZ;
+    o.init ();
+  }
   ~hb_vector_t () { fini (); }
 
-  unsigned int length;
   private:
   int allocated; /* == -1 means allocation failed. */
-  Type *arrayZ_;
   public:
+  unsigned int length;
+  public:
+  Type *arrayZ;
 
   void init ()
   {
     allocated = length = 0;
-    arrayZ_ = nullptr;
+    arrayZ = nullptr;
   }
 
   void fini ()
   {
-    if (arrayZ_)
-      free (arrayZ_);
+    free (arrayZ);
     init ();
   }
   void fini_deep ()
   {
-    Type *array = arrayZ();
     unsigned int count = length;
     for (unsigned int i = 0; i < count; i++)
-      array[i].fini ();
+      arrayZ[i].fini ();
     fini ();
   }
 
-  const Type * arrayZ () const { return arrayZ_; }
-        Type * arrayZ ()       { return arrayZ_; }
+  void reset () { resize (0); }
+
+  hb_vector_t& operator = (const hb_vector_t &o)
+  {
+    reset ();
+    alloc (o.length);
+    hb_copy (o, *this);
+    return *this;
+  }
+  hb_vector_t& operator = (hb_vector_t &&o)
+  {
+    fini ();
+    allocated = o.allocated;
+    length = o.length;
+    arrayZ = o.arrayZ;
+    o.init ();
+    return *this;
+  }
+
+  hb_bytes_t as_bytes () const
+  { return hb_bytes_t ((const char *) arrayZ, length * item_size); }
+
+  bool operator == (const hb_vector_t &o) const { return as_array () == o.as_array (); }
+  bool operator != (const hb_vector_t &o) const { return !(*this == o); }
+  uint32_t hash () const { return as_array ().hash (); }
 
   Type& operator [] (int i_)
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= length))
       return Crap (Type);
-    return arrayZ()[i];
+    return arrayZ[i];
   }
   const Type& operator [] (int i_) const
   {
     unsigned int i = (unsigned int) i_;
     if (unlikely (i >= length))
-      return Null(Type);
-    return arrayZ()[i];
+      return Null (Type);
+    return arrayZ[i];
   }
 
-  explicit_operator bool () const { return length; }
+  Type& tail () { return (*this)[length - 1]; }
+  const Type& tail () const { return (*this)[length - 1]; }
 
-  hb_array_t<Type> as_array ()
-  { return hb_array (arrayZ(), length); }
-  hb_array_t<const Type> as_array () const
-  { return hb_array (arrayZ(), length); }
+  explicit operator bool () const { return length; }
+  unsigned get_size () const { return length * item_size; }
+
+  /* Sink interface. */
+  template <typename T>
+  hb_vector_t& operator << (T&& v) { push (hb_forward<T> (v)); return *this; }
+
+  hb_array_t<      Type> as_array ()       { return hb_array (arrayZ, length); }
+  hb_array_t<const Type> as_array () const { return hb_array (arrayZ, length); }
+
+  /* Iterator. */
+  typedef hb_array_t<const Type>   iter_t;
+  typedef hb_array_t<      Type> writer_t;
+    iter_t   iter () const { return as_array (); }
+  writer_t writer ()       { return as_array (); }
+  operator   iter_t () const { return   iter (); }
+  operator writer_t ()       { return writer (); }
 
   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_array ().sub_array (start_offset, count);}
+  { return as_array ().sub_array (start_offset, count); }
 
   hb_sorted_array_t<Type> as_sorted_array ()
-  { return hb_sorted_array (arrayZ(), length); }
+  { return hb_sorted_array (arrayZ, length); }
   hb_sorted_array_t<const Type> as_sorted_array () const
-  { return hb_sorted_array (arrayZ(), length); }
+  { return hb_sorted_array (arrayZ, length); }
 
-  hb_array_t<const Type> sorted_sub_array (unsigned int start_offset, unsigned int count) const
-  { return as_sorted_array ().sorted_sub_array (start_offset, count);}
-  hb_array_t<const Type> sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
-  { return as_sorted_array ().sorted_sub_array (start_offset, count);}
-  hb_array_t<Type> sorted_sub_array (unsigned int start_offset, unsigned int count)
-  { return as_sorted_array ().sorted_sub_array (start_offset, count);}
-  hb_array_t<Type> sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
-  { return as_sorted_array ().sorted_sub_array (start_offset, count);}
+  template <typename T> explicit operator T * () { return arrayZ; }
+  template <typename T> explicit operator const T * () const { return arrayZ; }
 
-  template <typename T> explicit_operator T * () { return arrayZ(); }
-  template <typename T> explicit_operator const T * () const { return arrayZ(); }
-  operator hb_array_t<Type> ()             { return as_array (); }
-  operator hb_array_t<const Type> () const { return as_array (); }
-
-  Type * operator  + (unsigned int i) { return arrayZ() + i; }
-  const Type * operator  + (unsigned int i) const { return arrayZ() + i; }
+  Type * operator  + (unsigned int i) { return arrayZ + i; }
+  const Type * operator  + (unsigned int i) const { return arrayZ + i; }
 
   Type *push ()
   {
     if (unlikely (!resize (length + 1)))
-      return &Crap(Type);
-    return &arrayZ()[length - 1];
+      return &Crap (Type);
+    return &arrayZ[length - 1];
   }
-  Type *push (const Type& v)
+  template <typename T>
+  Type *push (T&& v)
   {
     Type *p = push ();
-    *p = v;
+    *p = hb_forward<T> (v);
     return p;
   }
 
@@ -161,7 +199,7 @@
       (new_allocated < (unsigned) allocated) ||
       hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
     if (likely (!overflows))
-      new_array = (Type *) realloc (arrayZ_, new_allocated * sizeof (Type));
+      new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
 
     if (unlikely (!new_array))
     {
@@ -169,7 +207,7 @@
       return false;
     }
 
-    arrayZ_ = new_array;
+    arrayZ = new_array;
     allocated = new_allocated;
 
     return true;
@@ -182,25 +220,24 @@
       return false;
 
     if (size > length)
-      memset (arrayZ() + length, 0, (size - length) * sizeof (*arrayZ()));
+      memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
 
     length = size;
     return true;
   }
 
-  void pop ()
+  Type pop ()
   {
-    if (!length) return;
-    length--;
+    if (!length) return Null (Type);
+    return hb_move (arrayZ[--length]); /* Does this move actually work? */
   }
 
   void remove (unsigned int i)
   {
     if (unlikely (i >= length))
       return;
-    Type *array = arrayZ();
-    memmove (static_cast<void *> (&array[i]),
-             static_cast<void *> (&array[i + 1]),
+    memmove (static_cast<void *> (&arrayZ[i]),
+             static_cast<void *> (&arrayZ[i + 1]),
              (length - i - 1) * sizeof (Type));
     length--;
   }
@@ -215,19 +252,17 @@
   template <typename T>
   Type *find (T v)
   {
-    Type *array = arrayZ();
     for (unsigned int i = 0; i < length; i++)
-      if (array[i] == v)
-        return &array[i];
+      if (arrayZ[i] == v)
+        return &arrayZ[i];
     return nullptr;
   }
   template <typename T>
   const Type *find (T v) const
   {
-    const Type *array = arrayZ();
     for (unsigned int i = 0; i < length; i++)
-      if (array[i] == v)
-        return &array[i];
+      if (arrayZ[i] == v)
+        return &arrayZ[i];
     return nullptr;
   }
 
@@ -242,19 +277,37 @@
   template <typename T>
   const Type *lsearch (const T &x, const Type *not_found = nullptr) const
   { return as_array ().lsearch (x, not_found); }
+  template <typename T>
+  bool lfind (const T &x, unsigned *pos = nullptr) const
+  { return as_array ().lfind (x, pos); }
+};
+
+template <typename Type>
+struct hb_sorted_vector_t : hb_vector_t<Type>
+{
+  hb_sorted_array_t<      Type> as_array ()       { return hb_sorted_array (this->arrayZ, this->length); }
+  hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->length); }
+
+  /* Iterator. */
+  typedef hb_sorted_array_t<const Type> const_iter_t;
+  typedef hb_sorted_array_t<      Type>       iter_t;
+  const_iter_t  iter () const { return as_array (); }
+  const_iter_t citer () const { return as_array (); }
+        iter_t  iter ()       { return as_array (); }
+  operator       iter_t ()       { return iter (); }
+  operator const_iter_t () const { return iter (); }
 
   template <typename T>
   Type *bsearch (const T &x, Type *not_found = nullptr)
-  { return as_sorted_array ().bsearch (x, not_found); }
+  { return as_array ().bsearch (x, not_found); }
   template <typename T>
   const Type *bsearch (const T &x, const Type *not_found = nullptr) const
-  { return as_sorted_array ().bsearch (x, not_found); }
+  { return as_array ().bsearch (x, not_found); }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-                     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
-                     unsigned int to_store = (unsigned int) -1) const
-  { return as_sorted_array ().bfind (x, i, not_found, to_store); }
+              hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+              unsigned int to_store = (unsigned int) -1) const
+  { return as_array ().bfind (x, i, not_found, to_store); }
 };
 
-
 #endif /* HB_VECTOR_HH */
diff --git a/src/java.desktop/share/native/libharfbuzz/hb-version.h b/src/java.desktop/share/native/libharfbuzz/hb-version.h
index 0124879..b9ab5f5 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb-version.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb-version.h
@@ -37,10 +37,10 @@
 
 
 #define HB_VERSION_MAJOR 2
-#define HB_VERSION_MINOR 3
-#define HB_VERSION_MICRO 1
+#define HB_VERSION_MINOR 7
+#define HB_VERSION_MICRO 2
 
-#define HB_VERSION_STRING "2.3.1"
+#define HB_VERSION_STRING "2.7.2"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
         ((major)*10000+(minor)*100+(micro) <= \
diff --git a/src/java.desktop/share/native/libharfbuzz/hb.h b/src/java.desktop/share/native/libharfbuzz/hb.h
index c5e7072..360686c 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb.h
+++ b/src/java.desktop/share/native/libharfbuzz/hb.h
@@ -32,12 +32,14 @@
 #include "hb-buffer.h"
 #include "hb-common.h"
 #include "hb-deprecated.h"
+#include "hb-draw.h"
 #include "hb-face.h"
 #include "hb-font.h"
 #include "hb-map.h"
 #include "hb-set.h"
 #include "hb-shape.h"
 #include "hb-shape-plan.h"
+#include "hb-style.h"
 #include "hb-unicode.h"
 #include "hb-version.h"
 
diff --git a/src/java.desktop/share/native/libharfbuzz/hb.hh b/src/java.desktop/share/native/libharfbuzz/hb.hh
index f2d3906..8f0ba2e 100644
--- a/src/java.desktop/share/native/libharfbuzz/hb.hh
+++ b/src/java.desktop/share/native/libharfbuzz/hb.hh
@@ -29,8 +29,9 @@
 #ifndef HB_HH
 #define HB_HH
 
+
 #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC
-#if defined(_MSC_VER)
+#ifdef _MSC_VER
 #pragma warning( disable: 4068 ) /* Unknown pragma */
 #endif
 #if defined(__GNUC__) || defined(__clang__)
@@ -65,9 +66,12 @@
 #pragma GCC diagnostic error   "-Wcast-align"
 #pragma GCC diagnostic error   "-Wcast-function-type"
 #pragma GCC diagnostic error   "-Wdelete-non-virtual-dtor"
+#pragma GCC diagnostic error   "-Wembedded-directive"
+#pragma GCC diagnostic error   "-Wextra-semi-stmt"
 #pragma GCC diagnostic error   "-Wformat-security"
 #pragma GCC diagnostic error   "-Wimplicit-function-declaration"
 #pragma GCC diagnostic error   "-Winit-self"
+#pragma GCC diagnostic error   "-Winjected-class-name"
 #pragma GCC diagnostic error   "-Wmissing-braces"
 #pragma GCC diagnostic error   "-Wmissing-declarations"
 #pragma GCC diagnostic error   "-Wmissing-prototypes"
@@ -93,13 +97,17 @@
 /* Warning.  To be investigated if happens. */
 #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
 #pragma GCC diagnostic warning "-Wbuiltin-macro-redefined"
+#pragma GCC diagnostic warning "-Wdeprecated"
+#pragma GCC diagnostic warning "-Wdeprecated-declarations"
 #pragma GCC diagnostic warning "-Wdisabled-optimization"
+#pragma GCC diagnostic warning "-Wdouble-promotion"
 #pragma GCC diagnostic warning "-Wformat=2"
 #pragma GCC diagnostic warning "-Wignored-pragma-optimize"
 #pragma GCC diagnostic warning "-Wlogical-op"
 #pragma GCC diagnostic warning "-Wmaybe-uninitialized"
 #pragma GCC diagnostic warning "-Wmissing-format-attribute"
 #pragma GCC diagnostic warning "-Wundef"
+#pragma GCC diagnostic warning "-Wunused-but-set-variable"
 #endif
 
 /* Ignored currently, but should be fixed at some point. */
@@ -120,14 +128,15 @@
 #pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang
 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
 #pragma GCC diagnostic ignored "-Wtype-limits"
+#pragma GCC diagnostic ignored "-Wc++11-compat" // only gcc raises it
 #endif
 
 #endif
 #endif
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+
+#include "hb-config.hh"
+
 
 /*
  * Following added based on what AC_USE_SYSTEM_EXTENSIONS adds to
@@ -166,20 +175,30 @@
 #include "hb-aat.h"
 #define HB_AAT_H_IN
 
-#include "hb-aat.h"
-
+#include <limits.h>
 #include <math.h>
+#include <float.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
 #include <assert.h>
-#include <errno.h>
 #include <stdio.h>
 #include <stdarg.h>
 
 #if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
+#ifdef __MINGW32_VERSION
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#else
 #include <intrin.h>
 #endif
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <winapifamily.h>
+#endif
 
 #define HB_PASTE1(a,b) a##b
 #define HB_PASTE(a,b) HB_PASTE1(a,b)
@@ -187,10 +206,15 @@
 
 /* Compile-time custom allocator support. */
 
-#if defined(hb_malloc_impl) \
- && defined(hb_calloc_impl) \
- && defined(hb_realloc_impl) \
- && defined(hb_free_impl)
+#if !defined(HB_CUSTOM_MALLOC) \
+  && defined(hb_malloc_impl) \
+  && defined(hb_calloc_impl) \
+  && defined(hb_realloc_impl) \
+  && defined(hb_free_impl)
+#define HB_CUSTOM_MALLOC
+#endif
+
+#ifdef HB_CUSTOM_MALLOC
 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);
@@ -199,14 +223,6 @@
 #define calloc hb_calloc_impl
 #define realloc hb_realloc_impl
 #define free hb_free_impl
-
-#if defined(hb_memalign_impl)
-extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size);
-#define posix_memalign hb_memalign_impl
-#else
-#undef HAVE_POSIX_MEMALIGN
-#endif
-
 #endif
 
 
@@ -214,58 +230,6 @@
  * Compiler attributes
  */
 
-#if __cplusplus < 201103L
-
-#ifndef nullptr
-#define nullptr NULL
-#endif
-
-#ifndef constexpr
-#define constexpr const
-#endif
-
-#ifndef static_assert
-#define static_assert(e, msg) \
-        HB_UNUSED typedef int HB_PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1]
-#endif // static_assert
-
-#if defined(__GNUC__)
-#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
-#define thread_local __thread
-#endif
-#else
-#define thread_local
-#endif
-
-template <typename T>
-struct _hb_alignof
-{
-  struct s
-  {
-    char c;
-    T t;
-  };
-  static constexpr size_t value = offsetof (s, t);
-};
-#ifndef alignof
-#define alignof(x) (_hb_alignof<x>::value)
-#endif
-
-/* https://github.com/harfbuzz/harfbuzz/issues/1127 */
-#ifndef explicit_operator
-#define explicit_operator operator
-#endif
-
-#else /* __cplusplus >= 201103L */
-
-/* https://github.com/harfbuzz/harfbuzz/issues/1127 */
-#ifndef explicit_operator
-#define explicit_operator explicit operator
-#endif
-
-#endif /* __cplusplus < 201103L */
-
-
 #if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
 #define likely(expr) (__builtin_expect (!!(expr), 1))
 #define unlikely(expr) (__builtin_expect (!!(expr), 0))
@@ -288,7 +252,7 @@
 #define HB_CONST_FUNC
 #define HB_PRINTF_FUNC(format_idx, arg_idx)
 #endif
-#if defined(__GNUC__) && (__GNUC__ >= 4)
+#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__)
 #define HB_UNUSED       __attribute__((unused))
 #elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */
 #define HB_UNUSED __pragma(warning(suppress: 4100 4101))
@@ -311,6 +275,13 @@
 # endif
 #endif
 
+/* https://github.com/harfbuzz/harfbuzz/issues/1651 */
+#if defined(__clang__) && __clang_major__ < 10
+#define static_const static
+#else
+#define static_const static const
+#endif
+
 #if defined(__GNUC__) && (__GNUC__ >= 3)
 #define HB_FUNC __PRETTY_FUNCTION__
 #elif defined(_MSC_VER)
@@ -357,7 +328,20 @@
 #  define HB_FALLTHROUGH /* FALLTHROUGH */
 #endif
 
-#if defined(__clang__)
+/* A tag to enforce use of return value for a function */
+#if __cplusplus >= 201703L
+#  define HB_NODISCARD [[nodiscard]]
+#elif defined(__GNUC__) || defined(__clang__)
+#  define HB_NODISCARD __attribute__((warn_unused_result))
+#elif defined(_MSC_VER)
+#  define HB_NODISCARD _Check_return_
+#else
+#  define HB_NODISCARD
+#endif
+#define hb_success_t HB_NODISCARD bool
+
+/* https://github.com/harfbuzz/harfbuzz/issues/1852 */
+#if defined(__clang__) && !(defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__)))
 /* Disable certain sanitizer errors. */
 /* https://github.com/harfbuzz/harfbuzz/issues/1247 */
 #define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow")))
@@ -374,7 +358,7 @@
 #    undef _WIN32_WINNT
 #  endif
 #  ifndef _WIN32_WINNT
-#    if !defined(WINAPI_FAMILY) || !(WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#    if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
 #      define _WIN32_WINNT 0x0600
 #    endif
 #  endif
@@ -388,19 +372,35 @@
 #  if defined(_WIN32_WCE)
      /* Some things not defined on Windows CE. */
 #    define vsnprintf _vsnprintf
-#    define getenv(Name) nullptr
-#    if _WIN32_WCE < 0x800
-#      define setlocale(Category, Locale) "C"
-static int errno = 0; /* Use something better? */
+#    ifndef HB_NO_GETENV
+#      define HB_NO_GETENV
 #    endif
-#  elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
-#    define getenv(Name) nullptr
+#    if _WIN32_WCE < 0x800
+#      define HB_NO_SETLOCALE
+#      define HB_NO_ERRNO
+#    endif
+#  elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#    ifndef HB_NO_GETENV
+#      define HB_NO_GETENV
+#    endif
 #  endif
 #  if defined(_MSC_VER) && _MSC_VER < 1900
 #    define snprintf _snprintf
 #  endif
 #endif
 
+#ifdef HB_NO_GETENV
+#define getenv(Name) nullptr
+#endif
+
+#ifndef HB_NO_ERRNO
+#  include <errno.h>
+#else
+static int HB_UNUSED _hb_errno = 0;
+#  undef errno
+#  define errno _hb_errno
+#endif
+
 #if defined(HAVE_ATEXIT) && !defined(HB_USE_ATEXIT)
 /* atexit() is only safe to be called from shared libraries on certain
  * platforms.  Whitelist.
@@ -459,87 +459,13 @@
 static_assert ((sizeof (hb_mask_t) == 4), "");
 static_assert ((sizeof (hb_var_int_t) == 4), "");
 
-
-#if __cplusplus >= 201103L
-
-/* We only enable these with C++11 or later, since earlier language
- * does not allow structs with constructors in unions, and we need
- * those. */
-
-#define HB_NO_COPY_ASSIGN(TypeName) \
-  TypeName(const TypeName&); \
-  void operator=(const TypeName&)
-#define HB_NO_COPY_ASSIGN_TEMPLATE(TypeName, T) \
-  TypeName(const TypeName<T>&); \
-  void operator=(const TypeName<T>&)
-#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \
-  TypeName(const TypeName<T1, T2>&); \
-  void operator=(const TypeName<T1, T2>&)
-#define HB_NO_CREATE_COPY_ASSIGN(TypeName) \
-  TypeName(); \
-  TypeName(const TypeName&); \
-  void operator=(const TypeName&)
-#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) \
-  TypeName(); \
-  TypeName(const TypeName<T>&); \
-  void operator=(const TypeName<T>&)
-#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \
-  TypeName(); \
-  TypeName(const TypeName<T1, T2>&); \
-  void operator=(const TypeName<T1, T2>&)
-
-#else /* __cpluspplus >= 201103L */
-
-#define HB_NO_COPY_ASSIGN(TypeName) static_assert (true, "")
-#define HB_NO_COPY_ASSIGN_TEMPLATE(TypeName, T) static_assert (true, "")
-#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) static_assert (true, "")
-#define HB_NO_CREATE_COPY_ASSIGN(TypeName) static_assert (true, "")
-#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) static_assert (true, "")
-#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) static_assert (true, "")
-
-#endif /* __cpluspplus >= 201103L */
-
-
-/*
- * Compiler-assisted vectorization parameters.
- */
-
-/*
- * Disable vectorization for now.  To correctly use them, we should
- * use posix_memalign() to allocate in hb_vector_t.  Otherwise, can
- * cause misaligned access.
- *
- * https://bugs.chromium.org/p/chromium/issues/detail?id=860184
- */
-#if !defined(HB_VECTOR_SIZE)
-#  define HB_VECTOR_SIZE 0
-#endif
-
-/* The `vector_size' attribute was introduced in gcc 3.1. */
-#if !defined(HB_VECTOR_SIZE)
-#  if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
-#    define HB_VECTOR_SIZE 128
-#  else
-#    define HB_VECTOR_SIZE 0
-#  endif
-#endif
-static_assert (0 == (HB_VECTOR_SIZE & (HB_VECTOR_SIZE - 1)), "HB_VECTOR_SIZE is not power of 2.");
-static_assert (0 == (HB_VECTOR_SIZE % 64), "HB_VECTOR_SIZE is not multiple of 64.");
-#if HB_VECTOR_SIZE
-typedef uint64_t hb_vector_size_impl_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
-#else
-typedef uint64_t hb_vector_size_impl_t;
-#endif
-
-
-/* HB_NDEBUG disables some sanity checks that are very safe to disable and
- * should be disabled in production systems.  If NDEBUG is defined, enable
- * HB_NDEBUG; but if it's desirable that normal assert()s (which are very
- * light-weight) to be enabled, then HB_DEBUG can be defined to disable
- * the costlier checks. */
-#ifdef NDEBUG
-#define HB_NDEBUG 1
-#endif
+#define HB_DELETE_COPY_ASSIGN(TypeName) \
+  TypeName(const TypeName&) = delete; \
+  void operator=(const TypeName&) = delete
+#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
+  TypeName() = delete; \
+  TypeName(const TypeName&) = delete; \
+  void operator=(const TypeName&) = delete
 
 
 /* Flags */
@@ -579,47 +505,107 @@
 
 
 /* Size signifying variable-sized array */
-#define VAR 1
-
-
-/* fallback for round() */
-static inline double
-_hb_round (double x)
-{
-  if (x >= 0)
-    return floor (x + 0.5);
-  else
-    return ceil (x - 0.5);
-}
-#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
-#define round(x) _hb_round(x)
+#ifndef HB_VAR_ARRAY
+#define HB_VAR_ARRAY 1
 #endif
 
+static inline float
+_hb_roundf (float x) { return floorf (x + .5f); }
+#define roundf(x) _hb_roundf(x)
 
-/* fallback for posix_memalign() */
-static inline int
-_hb_memalign(void **memptr, size_t alignment, size_t size)
+/* Endian swap, used in Windows related backends */
+static inline uint16_t hb_uint16_swap (const uint16_t v)
+{ return (v >> 8) | (v << 8); }
+static inline uint32_t hb_uint32_swap (const uint32_t v)
+{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
+
+/*
+ * Big-endian integers.  Here because fundamental.
+ */
+
+template <typename Type, int Bytes> struct BEInt;
+
+template <typename Type>
+struct BEInt<Type, 1>
 {
-  if (unlikely (0 != (alignment & (alignment - 1)) ||
-                !alignment ||
-                0 != (alignment & (sizeof (void *) - 1))))
-    return EINVAL;
-
-  char *p = (char *) malloc (size + alignment - 1);
-  if (unlikely (!p))
-    return ENOMEM;
-
-  size_t off = (size_t) p & (alignment - 1);
-  if (off)
-    p += alignment - off;
-
-  *memptr = (void *) p;
-
-  return 0;
-}
-#if !defined(posix_memalign) && !defined(HAVE_POSIX_MEMALIGN)
-#define posix_memalign _hb_memalign
+  public:
+  BEInt<Type, 1>& operator = (Type V)
+  {
+    v = V;
+    return *this;
+  }
+  operator Type () const { return v; }
+  private: uint8_t v;
+};
+template <typename Type>
+struct BEInt<Type, 2>
+{
+  public:
+  BEInt<Type, 2>& operator = (Type V)
+  {
+    v[0] = (V >>  8) & 0xFF;
+    v[1] = (V      ) & 0xFF;
+    return *this;
+  }
+  operator Type () const
+  {
+#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
+    defined(__BYTE_ORDER) && \
+    (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
+    /* Spoon-feed the compiler a big-endian integer with alignment 1.
+     * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+    struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    return __builtin_bswap16 (((packed_uint16_t *) this)->v);
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+    return ((packed_uint16_t *) this)->v;
 #endif
+#endif
+    return (v[0] <<  8)
+         + (v[1]      );
+  }
+  private: uint8_t v[2];
+};
+template <typename Type>
+struct BEInt<Type, 3>
+{
+  public:
+  BEInt<Type, 3>& operator = (Type V)
+  {
+    v[0] = (V >> 16) & 0xFF;
+    v[1] = (V >>  8) & 0xFF;
+    v[2] = (V      ) & 0xFF;
+    return *this;
+  }
+  operator Type () const
+  {
+    return (v[0] << 16)
+         + (v[1] <<  8)
+         + (v[2]      );
+  }
+  private: uint8_t v[3];
+};
+template <typename Type>
+struct BEInt<Type, 4>
+{
+  public:
+  BEInt<Type, 4>& operator = (Type V)
+  {
+    v[0] = (V >> 24) & 0xFF;
+    v[1] = (V >> 16) & 0xFF;
+    v[2] = (V >>  8) & 0xFF;
+    v[3] = (V      ) & 0xFF;
+    return *this;
+  }
+  operator Type () const
+  {
+    return (v[0] << 24)
+         + (v[1] << 16)
+         + (v[2] <<  8)
+         + (v[3]      );
+  }
+  private: uint8_t v[4];
+};
 
 
 /*
@@ -630,28 +616,18 @@
 #define HB_SCRIPT_MYANMAR_ZAWGYI        ((hb_script_t) HB_TAG ('Q','a','a','g'))
 
 
-/* Some really basic things everyone wants. */
-template <typename T> struct hb_remove_const { typedef T value; };
-template <typename T> struct hb_remove_const<const T> { typedef T value; };
-#define hb_remove_const(T) hb_remove_const<T>::value
-template <typename T> struct hb_remove_reference { typedef T value; };
-template <typename T> struct hb_remove_reference<T &> { typedef T value; };
-#define hb_remove_reference(T) hb_remove_reference<T>::value
-template <typename T> struct hb_remove_pointer { typedef T value; };
-template <typename T> struct hb_remove_pointer<T *> { typedef T value; };
-#define hb_remove_pointer(T) hb_remove_pointer<T>::value
-
-
 /* Headers we include for everyone.  Keep topologically sorted by dependency.
  * They express dependency amongst themselves, but no other file should include
  * them directly.*/
-#include "hb-atomic.hh"
+#include "hb-meta.hh"
 #include "hb-mutex.hh"
-#include "hb-null.hh"
-#include "hb-dsalgs.hh" // Requires: hb-null
-#include "hb-iter.hh"   // Requires: hb-null
-#include "hb-debug.hh"  // Requires: hb-atomic hb-dsalgs
-#include "hb-array.hh"  // Requires: hb-dsalgs hb-iter hb-null
+#include "hb-number.hh"
+#include "hb-atomic.hh" // Requires: hb-meta
+#include "hb-null.hh"   // Requires: hb-meta
+#include "hb-algs.hh"   // Requires: hb-meta hb-null hb-number
+#include "hb-iter.hh"   // Requires: hb-algs hb-meta
+#include "hb-debug.hh"  // Requires: hb-algs hb-atomic
+#include "hb-array.hh"  // Requires: hb-algs hb-iter hb-null
 #include "hb-vector.hh" // Requires: hb-array hb-null
 #include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector