From 0eeacb5b385fcd57ff5d26e6b0f5f755acc8ff57 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Fri, 29 May 2026 21:47:12 +0000 Subject: [PATCH 001/115] 8382130: Remove test/failure_handler/Makefile Reviewed-by: lmesnik, erikj, syan --- test/failure_handler/Makefile | 109 ---------------------------------- test/failure_handler/README | 3 +- 2 files changed, 1 insertion(+), 111 deletions(-) delete mode 100644 test/failure_handler/Makefile diff --git a/test/failure_handler/Makefile b/test/failure_handler/Makefile deleted file mode 100644 index ec0361abdd1..00000000000 --- a/test/failure_handler/Makefile +++ /dev/null @@ -1,109 +0,0 @@ -# -# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# -# This is a temporary standalone makefile -# - -BUILD_DIR := $(shell pwd)/build -CLASSES_DIR := ${BUILD_DIR}/classes -IMAGE_DIR := ${BUILD_DIR}/image -RUN_DIR := $(shell pwd)/run -CLASSPATH := ${JTREG_HOME}/lib/jtreg.jar:${JAVA_HOME}/lib/tools.jar -SRC_DIR := src/share/classes/ -SOURCES := ${SRC_DIR}/jdk/test/failurehandler/*.java \ - ${SRC_DIR}/jdk/test/failurehandler/action/*.java \ - ${SRC_DIR}/jdk/test/failurehandler/jtreg/*.java \ - ${SRC_DIR}/jdk/test/failurehandler/value/*.java - -CONF_DIR = src/share/conf - -JAVA_RELEASE = 15 - -TARGET_JAR = ${IMAGE_DIR}/lib/jtregFailureHandler.jar - -OS_NAME := $(shell uname -o 2>&1) - -ifeq ("${OS_NAME}", "Cygwin") -BUILD_DIR := $(shell cygpath -m "${BUILD_DIR}") -CLASSES_DIR := $(shell cygpath -m "${CLASSES_DIR}") -IMAGE_DIR := $(shell cygpath -m "${IMAGE_DIR}") -RUN_DIR := $(shell cygpath -m "${RUN_DIR}") -SRC_DIR := $(shell cygpath -m "${SRC_DIR}") -JAVA_HOME := $(shell cygpath -m "${JAVA_HOME}") -JTREG_HOME := $(shell cygpath -m "${JTREG_HOME}") -CLASSPATH := $(shell cygpath -pm "${CLASSPATH}") -endif - -all: clean test - -check_defined = $(foreach 1,$1,$(__check_defined)) -__check_defined = $(if $(value $1),, $(error $1 is not set)) - -classes: require_env - mkdir -p ${IMAGE_DIR}/bin ${IMAGE_DIR}/lib ${CLASSES_DIR} - "${JAVA_HOME}"/bin/javac -target ${JAVA_RELEASE} -source ${JAVA_RELEASE} \ - -sourcepath "$(shell pwd)" \ - -cp "${CLASSPATH}" \ - -d ${CLASSES_DIR} \ - ${SOURCES} - "${JAVA_HOME}"/bin/jar cf "${TARGET_JAR}" -C "${CLASSES_DIR}" . - "${JAVA_HOME}"/bin/jar uf "${TARGET_JAR}" -C "${CONF_DIR}" . - -# -# Use JTREG_TEST_OPTS for test VM options -# Use JTREG_TESTS for jtreg tests parameter -# -test: require_env build - rm -rf "${RUN_DIR}" - mkdir -p "${RUN_DIR}" - "${JTREG_HOME}"/bin/jtreg \ - -jdk:"${JAVA_HOME}" \ - ${JTREG_TEST_OPTS} \ - -timeout:0.1 -va -retain:all \ - -noreport \ - -agentvm \ - -thd:"${TARGET_JAR}" \ - -th:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler \ - -thtimeout:0 \ - -od:"${TARGET_JAR}" \ - -o:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver \ - -w:"${RUN_DIR}/JTwork" \ - -r:"${RUN_DIR}/JTreport" \ - $(if ${JTREG_TESTS}, ${JTREG_TESTS}, test) \ - && false || true - -debug: JTREG_TEST_OPTS += "-J-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005'" -debug: test - -require_env: - $(call check_defined, JAVA_HOME) - $(call check_defined, JTREG_HOME) - -clean: - rm -rf "${BUILD_DIR}" "${RUN_DIR}" - -build: classes - -.PHONY: all build classes test require_env clean -.DEFAULT: all diff --git a/test/failure_handler/README b/test/failure_handler/README index 4271bfbceaf..77979217b69 100644 --- a/test/failure_handler/README +++ b/test/failure_handler/README @@ -1,4 +1,4 @@ -Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. This code is free software; you can redistribute it and/or modify it @@ -106,7 +106,6 @@ $ ${JTREG_HOME}/bin/jtreg -jdk:${JAVA_HOME} \ TESTING There are a few make targets for testing the failure_handler itself. - - Everything in `test/failure_handler/Makefile` - The `test-failure-handler` target in `make/RunTests.gmk` - The `test` target in `make/test/BuildFailureHandler.gmk` All of these targets are written for manual testing only. They rely on From b66dcc947488060a60c42fea67a30d9278dafcf7 Mon Sep 17 00:00:00 2001 From: Ashay Rane <253344819+raneashay@users.noreply.github.com> Date: Fri, 29 May 2026 23:38:31 +0000 Subject: [PATCH 002/115] 8385345: AWT and ImageIO shell tests fail when run using MSys/MinGW Reviewed-by: prr, macarte --- .../TestDetectHeadless/TestDetectHeadless.sh | 2 +- test/jdk/java/awt/JAWT/JAWT.sh | 2 +- .../AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.sh | 2 +- .../awt/Toolkit/AutoShutdown/ShowExitTest/ShowExitTest.sh | 2 +- test/jdk/java/awt/Toolkit/BadDisplayTest/BadDisplayTest.sh | 2 +- .../java/lang/instrument/BootClassPath/BootClassPathTest.sh | 2 +- .../lang/instrument/appendToClassLoaderSearch/CommonSetup.sh | 2 +- .../metadata/IIOMetadataFormat/runMetadataFormatTest.sh | 2 +- .../metadata/IIOMetadataFormat/runMetadataFormatThreadTest.sh | 2 +- .../plugins/external_plugin_tests/TestClassPathPlugin.sh | 2 +- .../spi/AppletContextTest/BadPluginConfigurationTest.sh | 4 ++-- test/jdk/javax/script/CommonSetup.sh | 2 +- test/jdk/sun/jvmstat/testlibrary/utils.sh | 4 ++-- test/jdk/tools/launcher/MultipleJRE.sh | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/test/jdk/java/awt/GraphicsEnvironment/TestDetectHeadless/TestDetectHeadless.sh b/test/jdk/java/awt/GraphicsEnvironment/TestDetectHeadless/TestDetectHeadless.sh index 2e1fd42c588..010ed17382b 100644 --- a/test/jdk/java/awt/GraphicsEnvironment/TestDetectHeadless/TestDetectHeadless.sh +++ b/test/jdk/java/awt/GraphicsEnvironment/TestDetectHeadless/TestDetectHeadless.sh @@ -36,7 +36,7 @@ OS=`uname -s` case "$OS" in - Windows* | CYGWIN* | Darwin) + Windows* | CYGWIN* | MSYS* | MINGW* | Darwin) echo "Passed"; exit 0 ;; * ) unset DISPLAY ;; esac diff --git a/test/jdk/java/awt/JAWT/JAWT.sh b/test/jdk/java/awt/JAWT/JAWT.sh index f0e0118cbef..2ffe3b72a2e 100644 --- a/test/jdk/java/awt/JAWT/JAWT.sh +++ b/test/jdk/java/awt/JAWT/JAWT.sh @@ -83,7 +83,7 @@ case "$OS" in fi SYST="windows" ;; - CYGWIN* ) + CYGWIN* | MSYS* | MINGW* ) NULL=/dev/null PS=":" FS="/" diff --git a/test/jdk/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.sh b/test/jdk/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.sh index e550221c50f..e860f5786a3 100644 --- a/test/jdk/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.sh +++ b/test/jdk/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.sh @@ -60,7 +60,7 @@ pass() # The beginning of the script proper OS=`uname -s` case "$OS" in - AIX | CYGWIN* | Darwin | Linux ) + AIX | CYGWIN* | MSYS* | MINGW* | Darwin | Linux ) FILESEP="/" ;; diff --git a/test/jdk/java/awt/Toolkit/AutoShutdown/ShowExitTest/ShowExitTest.sh b/test/jdk/java/awt/Toolkit/AutoShutdown/ShowExitTest/ShowExitTest.sh index 8de5f6554d7..15d5378a676 100644 --- a/test/jdk/java/awt/Toolkit/AutoShutdown/ShowExitTest/ShowExitTest.sh +++ b/test/jdk/java/awt/Toolkit/AutoShutdown/ShowExitTest/ShowExitTest.sh @@ -87,7 +87,7 @@ case "$OS" in TMP=`cd "${SystemRoot}/Temp"; echo ${PWD}` ;; - CYGWIN* ) + CYGWIN* | MSYS* | MINGW* ) VAR="A different value for Cygwin" DEFAULT_JDK="/cygdrive/c/Program\ Files/Java/jdk1.8.0" FILESEP="/" diff --git a/test/jdk/java/awt/Toolkit/BadDisplayTest/BadDisplayTest.sh b/test/jdk/java/awt/Toolkit/BadDisplayTest/BadDisplayTest.sh index acd31541dc8..fc5cb058a14 100644 --- a/test/jdk/java/awt/Toolkit/BadDisplayTest/BadDisplayTest.sh +++ b/test/jdk/java/awt/Toolkit/BadDisplayTest/BadDisplayTest.sh @@ -23,7 +23,7 @@ ${TESTJAVA}/bin/javac -cp ${TESTSRC} -d . ${TESTSRC}/BadDisplayTest.java OS=`uname -s` case "$OS" in - Windows* | CYGWIN* | Darwin) + Windows* | CYGWIN* | MSYS* | MINGW* | Darwin) echo "Passed"; exit 0 ;; esac diff --git a/test/jdk/java/lang/instrument/BootClassPath/BootClassPathTest.sh b/test/jdk/java/lang/instrument/BootClassPath/BootClassPathTest.sh index 32306c97fbc..5765ab98966 100644 --- a/test/jdk/java/lang/instrument/BootClassPath/BootClassPathTest.sh +++ b/test/jdk/java/lang/instrument/BootClassPath/BootClassPathTest.sh @@ -66,7 +66,7 @@ echo "Creating manifest file..." OS=`uname -s` case ${OS} in - CYGWIN*) + CYGWIN* | MSYS* | MINGW*) CYGWIN="CYGWIN" ;; *) diff --git a/test/jdk/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh b/test/jdk/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh index 91aedeca234..f2412a92a43 100644 --- a/test/jdk/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh +++ b/test/jdk/java/lang/instrument/appendToClassLoaderSearch/CommonSetup.sh @@ -52,7 +52,7 @@ case "$OS" in OS="Windows" FS="\\" ;; - CYGWIN*) + CYGWIN* | MSYS* | MINGW*) PS=";" OS="Windows" FS="\\" diff --git a/test/jdk/javax/imageio/metadata/IIOMetadataFormat/runMetadataFormatTest.sh b/test/jdk/javax/imageio/metadata/IIOMetadataFormat/runMetadataFormatTest.sh index 60b3df59acc..0d14ec822a4 100644 --- a/test/jdk/javax/imageio/metadata/IIOMetadataFormat/runMetadataFormatTest.sh +++ b/test/jdk/javax/imageio/metadata/IIOMetadataFormat/runMetadataFormatTest.sh @@ -96,7 +96,7 @@ case "$OS" in FILESEP="\\" ;; - CYGWIN* ) + CYGWIN* | MSYS* | MINGW* ) VAR="A different value for CYGWIN" DEFAULT_JDK=/none FILESEP="/" diff --git a/test/jdk/javax/imageio/metadata/IIOMetadataFormat/runMetadataFormatThreadTest.sh b/test/jdk/javax/imageio/metadata/IIOMetadataFormat/runMetadataFormatThreadTest.sh index 24ee627f614..246d5babbb8 100644 --- a/test/jdk/javax/imageio/metadata/IIOMetadataFormat/runMetadataFormatThreadTest.sh +++ b/test/jdk/javax/imageio/metadata/IIOMetadataFormat/runMetadataFormatThreadTest.sh @@ -97,7 +97,7 @@ case "$OS" in FILESEP="\\" ;; - CYGWIN* ) + CYGWIN* | MSYS* | MINGW* ) VAR="A different value for CYGWIN" DEFAULT_JDK=/none FILESEP="/" diff --git a/test/jdk/javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh b/test/jdk/javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh index 03444e96302..853cb1cc6ac 100644 --- a/test/jdk/javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh +++ b/test/jdk/javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh @@ -60,7 +60,7 @@ $JAR cf $PLUGINDIR/simp.jar -C $TESTCLASSES/tmpdir META-INF/services \ OS=`uname -s` case "$OS" in - Windows_* | CYGWIN* ) + Windows_* | CYGWIN* | MSYS* | MINGW* ) CPSEP=";" ;; * ) diff --git a/test/jdk/javax/imageio/spi/AppletContextTest/BadPluginConfigurationTest.sh b/test/jdk/javax/imageio/spi/AppletContextTest/BadPluginConfigurationTest.sh index 66c890a1cd4..9d3f78975e3 100644 --- a/test/jdk/javax/imageio/spi/AppletContextTest/BadPluginConfigurationTest.sh +++ b/test/jdk/javax/imageio/spi/AppletContextTest/BadPluginConfigurationTest.sh @@ -115,7 +115,7 @@ case "$OS" in TMP=`cd "${SystemRoot}/Temp"; echo ${PWD}` ;; - CYGWIN* ) + CYGWIN* | MSYS* | MINGW* ) FILESEP="/" PATHSEP=";" TMP="/tmp" @@ -243,7 +243,7 @@ echo case "$OS" in - CYGWIN* ) + CYGWIN* | MSYS* | MINGW* ) TEST_CODEBASE=$(cygpath -m ${PWD}) TEST_PLUGIN_JAR=$(cygpath -m ${PLUGINDST_DIR}${FILESEP}${TEST_PLUGIN}) ;; diff --git a/test/jdk/javax/script/CommonSetup.sh b/test/jdk/javax/script/CommonSetup.sh index a03b767bc6d..4b59f9cbbc7 100644 --- a/test/jdk/javax/script/CommonSetup.sh +++ b/test/jdk/javax/script/CommonSetup.sh @@ -45,7 +45,7 @@ case "$OS" in OS="Windows" FS="\\" ;; - CYGWIN* ) + CYGWIN* | MSYS* | MINGW* ) PS=";" OS="Windows" FS="\\" diff --git a/test/jdk/sun/jvmstat/testlibrary/utils.sh b/test/jdk/sun/jvmstat/testlibrary/utils.sh index a08ae37a99d..c0ceac45999 100644 --- a/test/jdk/sun/jvmstat/testlibrary/utils.sh +++ b/test/jdk/sun/jvmstat/testlibrary/utils.sh @@ -40,7 +40,7 @@ setup() { OS=`uname -s` case ${OS} in - Windows_* | CYGWIN*) + Windows_* | CYGWIN* | MSYS* | MINGW*) PS=";" FS="\\" ;; @@ -54,7 +54,7 @@ setup() { verify_os() { OS=`uname -s` case ${OS} in - Windows_95 | Windows_98 | Windows_ME | CYGWIN* ) + Windows_95 | Windows_98 | Windows_ME | CYGWIN* | MSYS* | MINGW* ) echo "Test bypassed: jvmstat feature not supported on ${OS}" exit 0 ;; diff --git a/test/jdk/tools/launcher/MultipleJRE.sh b/test/jdk/tools/launcher/MultipleJRE.sh index fabfbca1d9c..ea6b29f7279 100644 --- a/test/jdk/tools/launcher/MultipleJRE.sh +++ b/test/jdk/tools/launcher/MultipleJRE.sh @@ -63,7 +63,7 @@ OS=`uname -s`; # IsWindows() { case "$OS" in - Windows* | CYGWIN* ) + Windows* | CYGWIN* | MSYS* | MINGW* ) printf "true" ;; * ) From 6e07965d6d5e352efc2b285621714484a993dfd4 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Fri, 29 May 2026 23:46:49 +0000 Subject: [PATCH 003/115] 8385606: Shenandoah: Remove PLAB card-table alignment and per-object register_object during old-gen allocation Reviewed-by: wkemper, kdnilsen --- .../gc/shenandoah/shenandoahAffiliation.hpp | 2 + .../share/gc/shenandoah/shenandoahFreeSet.cpp | 96 ++----------------- .../share/gc/shenandoah/shenandoahFreeSet.hpp | 2 - .../shenandoah/shenandoahGenerationalHeap.cpp | 7 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 32 +------ .../gc/shenandoah/shenandoahHeapRegion.hpp | 6 -- .../shenandoahHeapRegion.inline.hpp | 53 ---------- .../share/gc/shenandoah/shenandoahPLAB.cpp | 17 +--- 8 files changed, 20 insertions(+), 195 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAffiliation.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAffiliation.hpp index 6b3c846f5fe..3dc8becfb62 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAffiliation.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAffiliation.hpp @@ -25,6 +25,8 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHAFFILIATION_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHAFFILIATION_HPP +#include "utilities/debug.hpp" + enum ShenandoahAffiliation { FREE, YOUNG_GENERATION, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 9bbbada0be1..4c474f2f86c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -1478,55 +1478,6 @@ HeapWord* ShenandoahFreeSet::try_allocate_from_mutator(ShenandoahAllocRequest& r return nullptr; } -// This work method takes an argument corresponding to the number of bytes -// free in a region, and returns the largest amount in heapwords that can be allocated -// such that both of the following conditions are satisfied: -// -// 1. it is a multiple of card size -// 2. any remaining shard may be filled with a filler object -// -// The idea is that the allocation starts and ends at card boundaries. Because -// a region ('s end) is card-aligned, the remainder shard that must be filled is -// at the start of the free space. -// -// This is merely a helper method to use for the purpose of such a calculation. -size_t ShenandoahFreeSet::get_usable_free_words(size_t free_bytes) const { - // e.g. card_size is 512, card_shift is 9, min_fill_size() is 8 - // free is 514 - // usable_free is 512, which is decreased to 0 - size_t usable_free = (free_bytes / CardTable::card_size()) << CardTable::card_shift(); - assert(usable_free <= free_bytes, "Sanity check"); - if ((free_bytes != usable_free) && (free_bytes - usable_free < ShenandoahHeap::min_fill_size() * HeapWordSize)) { - // After aligning to card multiples, the remainder would be smaller than - // the minimum filler object, so we'll need to take away another card's - // worth to construct a filler object. - if (usable_free >= CardTable::card_size()) { - usable_free -= CardTable::card_size(); - } else { - assert(usable_free == 0, "usable_free is a multiple of card_size and card_size > min_fill_size"); - } - } - - return usable_free / HeapWordSize; -} - -// Given a size argument, which is a multiple of card size, a request struct -// for a PLAB, and an old region, return a pointer to the allocated space for -// a PLAB which is card-aligned and where any remaining shard in the region -// has been suitably filled by a filler object. -// It is assumed (and assertion-checked) that such an allocation is always possible. -HeapWord* ShenandoahFreeSet::allocate_aligned_plab(size_t size, ShenandoahAllocRequest& req, ShenandoahHeapRegion* r) { - assert(_heap->mode()->is_generational(), "PLABs are only for generational mode"); - assert(r->is_old(), "All PLABs reside in old-gen"); - assert(!req.is_mutator_alloc(), "PLABs should not be allocated by mutators."); - assert(is_aligned(size, CardTable::card_size_in_words()), "Align by design"); - - HeapWord* result = r->allocate_aligned(size, req, CardTable::card_size()); - assert(result != nullptr, "Allocation cannot fail"); - assert(r->top() <= r->end(), "Allocation cannot span end of region"); - assert(is_aligned(result, CardTable::card_size_in_words()), "Align by design"); - return result; -} HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, ShenandoahAllocRequest& req, bool& in_new_region) { assert (has_alloc_capacity(r), "Performance: should avoid full regions on this path: %zu", r->index()); @@ -1578,44 +1529,17 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah // req.size() is in words, r->free() is in bytes. if (req.is_lab_alloc()) { size_t adjusted_size = req.size(); - size_t free = r->free(); // free represents bytes available within region r - if (req.is_old()) { - // This is a PLAB allocation(lab alloc in old gen) - assert(_heap->mode()->is_generational(), "PLABs are only for generational mode"); - assert(_partitions.in_free_set(ShenandoahFreeSetPartitionId::OldCollector, r->index()), - "PLABS must be allocated in old_collector_free regions"); - - // Need to assure that plabs are aligned on multiple of card region - // Convert free from unaligned bytes to aligned number of words - size_t usable_free = get_usable_free_words(free); - if (adjusted_size > usable_free) { - adjusted_size = usable_free; - } - adjusted_size = align_down(adjusted_size, CardTable::card_size_in_words()); - if (adjusted_size >= req.min_size()) { - result = allocate_aligned_plab(adjusted_size, req, r); - assert(result != nullptr, "allocate must succeed"); - req.set_actual_size(adjusted_size); - } else { - // Otherwise, leave result == nullptr because the adjusted size is smaller than min size. - log_trace(gc, free)("Failed to shrink PLAB request (%zu) in region %zu to %zu" - " because min_size() is %zu", req.size(), r->index(), adjusted_size, req.min_size()); - } + size_t free = align_down(r->free() >> LogHeapWordSize, MinObjAlignment); + if (adjusted_size > free) { + adjusted_size = free; + } + if (adjusted_size >= req.min_size()) { + result = r->allocate(adjusted_size, req); + assert (result != nullptr, "Allocation must succeed: free %zu, actual %zu", free, adjusted_size); + req.set_actual_size(adjusted_size); } else { - // This is a GCLAB or a TLAB allocation - // Convert free from unaligned bytes to aligned number of words - free = align_down(free >> LogHeapWordSize, MinObjAlignment); - if (adjusted_size > free) { - adjusted_size = free; - } - if (adjusted_size >= req.min_size()) { - result = r->allocate(adjusted_size, req); - assert (result != nullptr, "Allocation must succeed: free %zu, actual %zu", free, adjusted_size); - req.set_actual_size(adjusted_size); - } else { - log_trace(gc, free)("Failed to shrink TLAB or GCLAB request (%zu) in region %zu to %zu" - " because min_size() is %zu", req.size(), r->index(), adjusted_size, req.min_size()); - } + log_trace(gc, free)("Failed to shrink LAB request (%zu) in region %zu to %zu" + " because min_size() is %zu", req.size(), r->index(), adjusted_size, req.min_size()); } } else { size_t size = req.size(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 083dd551aaa..7481b81c9c6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -453,7 +453,6 @@ private: // locks will acquire them in the same order: first the global heap lock and then the rebuild lock. ShenandoahRebuildLock _rebuild_lock; - HeapWord* allocate_aligned_plab(size_t size, ShenandoahAllocRequest& req, ShenandoahHeapRegion* r); size_t _total_humongous_waste; @@ -639,7 +638,6 @@ private: // Determine whether we prefer to allocate from left to right or from right to left within the OldCollector free-set. void establish_old_collector_alloc_bias(); - size_t get_usable_free_words(size_t free_bytes) const; void reduce_young_reserve(size_t adjusted_young_reserve, size_t requested_young_reserve); void reduce_old_reserve(size_t adjusted_old_reserve, size_t requested_old_reserve); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 8c781f651d5..4af2c9b1e5d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -65,12 +65,11 @@ protected: }; size_t ShenandoahGenerationalHeap::calculate_min_plab() { - return align_up(PLAB::min_size(), CardTable::card_size_in_words()); + return PLAB::min_size(); } size_t ShenandoahGenerationalHeap::calculate_max_plab() { - size_t MaxTLABSizeWords = ShenandoahHeapRegion::max_tlab_size_words(); - return align_down(MaxTLABSizeWords, CardTable::card_size_in_words()); + return ShenandoahHeapRegion::max_tlab_size_words(); } // Returns size in bytes @@ -86,8 +85,6 @@ ShenandoahGenerationalHeap::ShenandoahGenerationalHeap(ShenandoahCollectorPolicy _regulator_thread(nullptr), _young_gen_memory_pool(nullptr), _old_gen_memory_pool(nullptr) { - assert(is_aligned(_min_plab_size, CardTable::card_size_in_words()), "min_plab_size must be aligned"); - assert(is_aligned(_max_plab_size, CardTable::card_size_in_words()), "max_plab_size must be aligned"); } void ShenandoahGenerationalHeap::initialize_generations() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 91e92b500a3..c0df4bbe10c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1035,7 +1035,6 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // memory. HeapWord* result = _free_set->allocate(req, in_new_region); - // Record the plab configuration for this result and register the object. if (result != nullptr) { if (req.is_mutator_alloc()) { _alloc_rate.allocated((req.actual_size() + req.waste()) * HeapWordSize); @@ -1044,33 +1043,10 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req if (req.is_old()) { if (req.is_lab_alloc()) { old_generation()->configure_plab_for_current_thread(req); - } else { - // Register the newly allocated object while we're holding the global lock since there's no synchronization - // built in to the implementation of register_object(). There are potential races when multiple independent - // threads are allocating objects, some of which might span the same card region. For example, consider - // a card table's memory region within which three objects are being allocated by three different threads: - // - // objects being "concurrently" allocated: - // [-----a------][-----b-----][--------------c------------------] - // [---- card table memory range --------------] - // - // Before any objects are allocated, this card's memory range holds no objects. Note that allocation of object a - // wants to set the starts-object, first-start, and last-start attributes of the preceding card region. - // Allocation of object b wants to set the starts-object, first-start, and last-start attributes of this card region. - // Allocation of object c also wants to set the starts-object, first-start, and last-start attributes of this - // card region. - // - // The thread allocating b and the thread allocating c can "race" in various ways, resulting in confusion, such as - // last-start representing object b while first-start represents object c. This is why we need to require all - // register_object() invocations to be "mutually exclusive" with respect to each card's memory range. - old_generation()->card_scan()->register_object(result); - - if (req.is_promotion()) { - // Shared promotion. - const size_t actual_size = req.actual_size() * HeapWordSize; - log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size); - old_generation()->expend_promoted(actual_size); - } + } else if (req.is_promotion()) { + const size_t actual_size = req.actual_size() * HeapWordSize; + log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size); + old_generation()->expend_promoted(actual_size); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 7853238f080..9040a81848e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -386,12 +386,6 @@ public: HeapWord* get_top_at_evac_start() const { return _top_at_evac_start; } void record_top_at_evac_start() { _top_at_evac_start = _top; } - // If next available memory is not aligned on address that is multiple of alignment, fill the empty space - // so that returned object is aligned on an address that is a multiple of alignment_in_bytes. Requested - // size is in words. It is assumed that this->is_old(). A pad object is allocated, filled, and registered - // if necessary to assure the new allocation is properly aligned. Return nullptr if memory is not available. - inline HeapWord* allocate_aligned(size_t word_size, ShenandoahAllocRequest &req, size_t alignment_in_bytes); - // Allocation (return nullptr if full) inline HeapWord* allocate(size_t word_size, const ShenandoahAllocRequest& req); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp index 39b7c732703..f004fdf0ea2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp @@ -33,59 +33,6 @@ #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" -HeapWord* ShenandoahHeapRegion::allocate_aligned(size_t size, ShenandoahAllocRequest &req, size_t alignment_in_bytes) { - shenandoah_assert_heaplocked_or_safepoint(); - assert(req.is_lab_alloc(), "allocate_aligned() only applies to LAB allocations"); - assert(is_object_aligned(size), "alloc size breaks alignment: %zu", size); - assert(is_old(), "aligned allocations are only taken from OLD regions to support PLABs"); - assert(is_aligned(alignment_in_bytes, HeapWordSize), "Expect heap word alignment"); - - HeapWord* orig_top = top(); - size_t alignment_in_words = alignment_in_bytes / HeapWordSize; - - // unalignment_words is the amount by which current top() exceeds the desired alignment point. We subtract this amount - // from alignment_in_words to determine padding required to next alignment point. - - HeapWord* aligned_obj = (HeapWord*) align_up(orig_top, alignment_in_bytes); - size_t pad_words = aligned_obj - orig_top; - if ((pad_words > 0) && (pad_words < ShenandoahHeap::min_fill_size())) { - pad_words += alignment_in_words; - aligned_obj += alignment_in_words; - } - - if (pointer_delta(end(), aligned_obj) < size) { - // Shrink size to fit within available space and align it - size = pointer_delta(end(), aligned_obj); - size = align_down(size, alignment_in_words); - } - - // Both originally requested size and adjusted size must be properly aligned - assert (is_aligned(size, alignment_in_words), "Size must be multiple of alignment constraint"); - if (size >= req.min_size()) { - // Even if req.min_size() may not be a multiple of card size, we know that size is. - if (pad_words > 0) { - assert(pad_words >= ShenandoahHeap::min_fill_size(), "pad_words expanded above to meet size constraint"); - ShenandoahHeap::fill_with_object(orig_top, pad_words); - ShenandoahGenerationalHeap::heap()->old_generation()->card_scan()->register_object(orig_top); - } - - make_regular_allocation(req.affiliation()); - adjust_alloc_metadata(req, size); - - HeapWord* new_top = aligned_obj + size; - assert(new_top <= end(), "PLAB cannot span end of heap region"); - set_top(new_top); - // We do not req.set_actual_size() here. The caller sets it. - req.set_waste(pad_words); - assert(is_object_aligned(new_top), "new top breaks alignment: " PTR_FORMAT, p2i(new_top)); - assert(is_aligned(aligned_obj, alignment_in_bytes), "obj is not aligned: " PTR_FORMAT, p2i(aligned_obj)); - return aligned_obj; - } else { - // The aligned size that fits in this region is smaller than min_size, so don't align top and don't allocate. Return failure. - return nullptr; - } -} - HeapWord* ShenandoahHeapRegion::allocate_fill(size_t size) { shenandoah_assert_heaplocked_or_safepoint(); assert(is_object_aligned(size), "alloc size breaks alignment: %zu", size); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp index 5049113b665..3d98d431b86 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp @@ -22,7 +22,6 @@ * */ -#include "gc/shared/cardTable.hpp" #include "gc/shenandoah/shenandoahAllocRequest.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" @@ -43,7 +42,7 @@ ShenandoahPLAB::ShenandoahPLAB() : _allows_promotion(false), _retries_enabled(false), _heap(ShenandoahGenerationalHeap::heap()) { - _plab = new PLAB(align_up(PLAB::min_size(), CardTable::card_size_in_words())); + _plab = new PLAB(PLAB::min_size()); } ShenandoahPLAB::~ShenandoahPLAB() { @@ -93,10 +92,8 @@ HeapWord* ShenandoahPLAB::allocate(size_t size, bool is_promotion) { HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) { assert(_heap->mode()->is_generational(), "PLABs only relevant to generational GC"); - // PLABs are aligned to card boundaries to avoid synchronization with concurrent - // allocations in other PLABs. const size_t plab_min_size = _heap->plab_min_size(); - const size_t min_size = (size > plab_min_size)? align_up(size, CardTable::card_size_in_words()): plab_min_size; + const size_t min_size = (size > plab_min_size) ? size : plab_min_size; // Figure out size of new PLAB, using value determined at last refill. size_t cur_size = _desired_size; @@ -105,12 +102,7 @@ HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) { } // Expand aggressively, doubling at each refill in this epoch, ceiling at plab_max_size() - // Doubling, starting at a card-multiple, should give us a card-multiple. (Ceiling and floor - // are card multiples.) const size_t future_size = MIN2(cur_size * 2, _heap->plab_max_size()); - assert(is_aligned(future_size, CardTable::card_size_in_words()), "Card multiple by construction, future_size: %zu" - ", card_size: %u, cur_size: %zu, max: %zu", - future_size, CardTable::card_size_in_words(), cur_size, _heap->plab_max_size()); // Record new heuristic value even if we take any shortcut. This captures // the case when moderately-sized objects always take a shortcut. At some point, @@ -128,8 +120,6 @@ HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) { if (_plab->words_remaining() < plab_min_size) { // Retire current PLAB. This takes care of any PLAB book-keeping. - // retire_plab() registers the remnant filler object with the remembered set scanner without a lock. - // Since PLABs are card-aligned, concurrent registrations in other PLABs don't interfere. retire(); size_t actual_size = 0; @@ -157,7 +147,6 @@ HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) { Copy::fill_to_words(plab_buf + hdr_size, actual_size - hdr_size, badHeapWordVal); #endif } - assert(is_aligned(actual_size, CardTable::card_size_in_words()), "Align by design"); _plab->set_buf(plab_buf, actual_size); if (is_promotion && !_allows_promotion) { return nullptr; @@ -173,7 +162,6 @@ HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) { } HeapWord* ShenandoahPLAB::allocate_new_plab(size_t min_size, size_t word_size, size_t* actual_size) { - assert(is_aligned(min_size, CardTable::card_size_in_words()), "Align by design"); assert(word_size >= min_size, "Requested PLAB is too small"); ShenandoahAllocRequest req = ShenandoahAllocRequest::for_plab(min_size, word_size); @@ -183,7 +171,6 @@ HeapWord* ShenandoahPLAB::allocate_new_plab(size_t min_size, size_t word_size, s } else { *actual_size = 0; } - assert(is_aligned(res, CardTable::card_size_in_words()), "Align by design"); return res; } From d3073b53d34c47976191acaa0d07cd1d919f3251 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Sat, 30 May 2026 02:08:31 +0000 Subject: [PATCH 004/115] 8385610: Shenandoah: TestSoftMaxHeapSizeAvailableCalc should have more tolerance for other GC triggers Reviewed-by: kdnilsen, xpeng, syan, ruili --- .../gc/shenandoah/TestSoftMaxHeapSizeAvailableCalc.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/gc/shenandoah/TestSoftMaxHeapSizeAvailableCalc.java b/test/hotspot/jtreg/gc/shenandoah/TestSoftMaxHeapSizeAvailableCalc.java index e70f2f0849f..100666fe859 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestSoftMaxHeapSizeAvailableCalc.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestSoftMaxHeapSizeAvailableCalc.java @@ -35,6 +35,7 @@ * -XX:ShenandoahGCMode=satb * -XX:+ShenandoahDegeneratedGC * -XX:ShenandoahGCHeuristics=adaptive + * -XX:ShenandoahLearningSteps=0 * TestSoftMaxHeapSizeAvailableCalc */ @@ -60,6 +61,7 @@ * -XX:+UseShenandoahGC -Xlog:gc=info * -XX:ShenandoahGCMode=generational * -XX:ShenandoahGCHeuristics=adaptive + * -XX:ShenandoahLearningSteps=0 * TestSoftMaxHeapSizeAvailableCalc * */ @@ -87,12 +89,13 @@ public class TestSoftMaxHeapSizeAvailableCalc { // Soft max: 512M, ShenandoahMinFreeThreshold: 10 (default), ShenandoahEvacReserve: 5 (default) // Soft max for mutator: 512M * (100.0 - 5) / 100 = 486.4M // Threshold to trigger gc: 486.4M - 512 * 10 / 100.0 = 435.2M, just above (300 + 100)M. - // Expect gc count to be less than 1 / sec. + // Expect gc count to be less than 1 / sec, but to allow for other trigger conditions (like allocation rate), + // we bump the max allowed gc count to 35. public static class Allocate { static final List longLived = new ArrayList<>(); public static void test() throws Exception { - final int expectedMaxGcCount = Integer.getInteger("expectedMaxGcCount", 30); + final int expectedMaxGcCount = Integer.getInteger("expectedMaxGcCount", 35); List collectors = ManagementFactory.getGarbageCollectorMXBeans(); java.lang.management.GarbageCollectorMXBean cycleCollector = null; for (java.lang.management.GarbageCollectorMXBean bean : collectors) { From 7b2845eab4011c4ceca01eecb8d8f920fe457d9d Mon Sep 17 00:00:00 2001 From: Ashay Rane <253344819+raneashay@users.noreply.github.com> Date: Mon, 1 Jun 2026 00:26:50 +0000 Subject: [PATCH 005/115] 8384087: Test tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java fails Reviewed-by: almatvee, asemenyuk --- .../jdk/jpackage/internal/cli/MainTest.java | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java index 93d22df4d26..69db18ccb3a 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java @@ -50,6 +50,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.Globals; +import jdk.jpackage.internal.model.BundlingOperationDescriptor; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.ExecutableAttributesWithCapturedOutput; import jdk.jpackage.internal.model.JPackageException; @@ -491,8 +492,35 @@ public class MainTest extends JUnitAdapter { var os = OperatingSystem.current(); var exitCode = Main.run(os, () -> { - CliBundlingEnvironment bundlingEnv = JPackageMockUtils.createBundlingEnvironment(os); - return bundlingEnv; + return new CliBundlingEnvironment() { + @Override + public Optional defaultOperation() { + switch (os) { + case LINUX -> { + return Optional.of(StandardBundlingOperation.CREATE_LINUX_DEB.descriptor()); + } + case WINDOWS -> { + return Optional.of(StandardBundlingOperation.CREATE_WIN_MSI.descriptor()); + } + case MACOS -> { + return Optional.of(StandardBundlingOperation.CREATE_MAC_PKG.descriptor()); + } + default -> { + throw new AssertionError(); + } + } + } + + @Override + public void createBundle(BundlingOperationDescriptor op, Options cmdline) { + if (StandardBundlingOperation.CREATE_APP_IMAGE.contains(StandardBundlingOperation.valueOf(op).orElseThrow())) { + CliBundlingEnvironment bundlingEnv = JPackageMockUtils.createBundlingEnvironment(os); + bundlingEnv.createBundle(op, cmdline); + } else { + throw new AssertionError(); + } + } + }; }, new PrintWriter(stdout), new PrintWriter(stderr), args); return new ExecutionResult(lines(stdout.toString()), lines(stderr.toString()), exitCode); From 9489e12f42d34372fdeadc3461215552019d7083 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Mon, 1 Jun 2026 01:09:28 +0000 Subject: [PATCH 006/115] 8385656: Misplaced comment on enum value in jdk.internal.util.Architecture Reviewed-by: liach --- .../share/classes/jdk/internal/util/Architecture.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/util/Architecture.java b/src/java.base/share/classes/jdk/internal/util/Architecture.java index 4f193e75597..31f328c2ead 100644 --- a/src/java.base/share/classes/jdk/internal/util/Architecture.java +++ b/src/java.base/share/classes/jdk/internal/util/Architecture.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,15 +37,15 @@ import java.util.Locale; * architecture values. */ public enum Architecture { - /* - * An unknown architecture not specifically named. - * The addrSize and ByteOrder values are those of the current architecture. - */ AARCH64(64, ByteOrder.LITTLE_ENDIAN), ARM(32, ByteOrder.LITTLE_ENDIAN), LOONGARCH64(64, ByteOrder.LITTLE_ENDIAN), MIPSEL(32, ByteOrder.LITTLE_ENDIAN), MIPS64EL(64, ByteOrder.LITTLE_ENDIAN), + /* + * An unknown architecture not specifically named. + * The addrSize and ByteOrder values are those of the current architecture. + */ OTHER(is64bit() ? 64 : 32, ByteOrder.nativeOrder()), PPC(32, ByteOrder.BIG_ENDIAN), PPC64(64, ByteOrder.BIG_ENDIAN), From 62843fcdcec870a920dadd30b5a9c4a695892ecf Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 1 Jun 2026 06:56:33 +0000 Subject: [PATCH 007/115] 8346420: C2: IfNode::fold_compares_helper() wrongly folds two CmpI nodes to a single CmpU node Reviewed-by: roland, qamai, galder --- src/hotspot/share/opto/ifnode.cpp | 727 ++++++++++++----- src/hotspot/share/opto/subnode.hpp | 7 +- .../rangechecks/TestFoldCompares.java | 346 +++++++++ .../rangechecks/TestFoldComparesFuzzer.java | 728 ++++++++++++++++++ 4 files changed, 1606 insertions(+), 202 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestFoldCompares.java create mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestFoldComparesFuzzer.java diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 9f99874d76a..347d63ef57c 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -654,6 +654,12 @@ Node* IfNode::up_one_dom(Node *curr, bool linear_only) { //------------------------------filtered_int_type-------------------------------- // Return a possibly more restrictive type for val based on condition control flow for an if +// +// Important: we only parse if val is on the lhs. This is a limitation, but it makes +// optimizations simpler. We rely on canonicalization to get us to this +// shape, which works well for comparisions with constants, as they are +// canonicalized to the rhs. This may not happen with variables, and so +// the optimization may not work for those cases, when val stays on the rhs. const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node* val, Node* if_proj) { assert(if_proj && (if_proj->Opcode() == Op_IfTrue || if_proj->Opcode() == Op_IfFalse), "expecting an if projection"); @@ -663,11 +669,14 @@ const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node* val, Node* if_proj BoolNode* bol = iff->in(1)->as_Bool(); if (bol->in(1) && bol->in(1)->is_Cmp()) { const CmpNode* cmp = bol->in(1)->as_Cmp(); + // Val is always the lhs of the comparision: val cmp2 if (cmp->in(1) == val) { + assert(cmp->Opcode() == Op_CmpI, "signed comparison required"); const TypeInt* cmp2_t = gvn->type(cmp->in(2))->isa_int(); if (cmp2_t != nullptr) { jint lo = cmp2_t->_lo; jint hi = cmp2_t->_hi; + // Negate the test if we are on the false branch. BoolTest::mask msk = if_proj->Opcode() == Op_IfTrue ? bol->_test._test : bol->_test.negate(); switch (msk) { case BoolTest::ne: { @@ -675,8 +684,12 @@ const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node* val, Node* if_proj const TypeInt* val_t = gvn->type(val)->isa_int(); if (val_t != nullptr && !val_t->singleton() && cmp2_t->is_con()) { if (val_t->_lo == lo) { + // Condition leading to if_proj: val != val->lo + // val in [val->lo + 1, val->hi] return TypeInt::make(val_t->_lo + 1, val_t->_hi, val_t->_widen); } else if (val_t->_hi == hi) { + // Condition leading to if_proj: val != val->hi + // val in [val->lo, val->hi - 1] return TypeInt::make(val_t->_lo, val_t->_hi - 1, val_t->_widen); } } @@ -684,28 +697,38 @@ const TypeInt* IfNode::filtered_int_type(PhaseGVN* gvn, Node* val, Node* if_proj return nullptr; } case BoolTest::eq: + // Condition leading to if_proj: val == cmp2 + // val in cmp2_t return cmp2_t; case BoolTest::lt: - lo = TypeInt::INT->_lo; + // Condition leading to if_proj: val < cmp2 + // val in [min_int .. max(min_int, cmp2->_hi - 1)] + lo = min_jint; if (hi != min_jint) { hi = hi - 1; } break; case BoolTest::le: - lo = TypeInt::INT->_lo; + // Condition leading to if_proj: val <= cmp2 + // val in [min_int .. cmp2->_hi] + lo = min_jint; break; case BoolTest::gt: + // Condition leading to if_proj: val > cmp2 + // val in [min(cmp2->_lo + 1, max_int) .. max_int] if (lo != max_jint) { lo = lo + 1; } - hi = TypeInt::INT->_hi; + hi = max_jint; break; case BoolTest::ge: - // lo unchanged - hi = TypeInt::INT->_hi; + // Condition leading to if_proj: val >= cmp2 + // val in [cmp2->_lo .. max_int] + hi = max_jint; break; default: - break; + assert(false, "impossible case"); + return nullptr; } const TypeInt* rtn_t = TypeInt::make(lo, hi, cmp2_t->_widen); return rtn_t; @@ -902,219 +925,523 @@ bool IfNode::has_only_uncommon_traps(IfProjNode* proj, IfProjNode*& success, IfP return false; } -// Check that the 2 CmpI can be folded into as single CmpU and proceed with the folding -bool IfNode::fold_compares_helper(IfProjNode* proj, IfProjNode* success, IfProjNode* fail, PhaseIterGVN* igvn) { - Node* this_cmp = in(1)->in(1); - BoolNode* this_bool = in(1)->as_Bool(); - IfNode* dom_iff = proj->in(0)->as_If(); - BoolNode* dom_bool = dom_iff->in(1)->as_Bool(); - Node* lo = dom_iff->in(1)->in(1)->in(2); - Node* orig_lo = lo; - Node* hi = this_cmp->in(2); - Node* n = this_cmp->in(1); - IfProjNode* otherproj = proj->other_if_proj(); +// We are given the following code shape with two CmpI: +// +// n v1 +// | | +// cmp1 +// | +// entry bool1(test1) +// | | +// iff1 +// | \ +// middle fail1-------------+ +// | | +// | n v2 | +// | | | | +// maybe cmp2 | +// null-check | | +// | bool2(test2) | +// | | | +// iff2 | +// | \ v +// succ fail2----> go to same region +// or uncommon trap +// +// 1. In some cases, we can prove that succ cannot be reached, +// and we can fold away the iff2. Example: +// +// if (n < -1 && n > 1) { succ } else { fail } +// // 1st condition: n in [min_int .. -2] +// // 2nd condition: n in [2 .. max_int] +// // -> no overlap -> constant fold iff2 towards fail2 +// // +// // Equivalent, if we flip everything: +// if (n >= -1 || n <= 1) { fail } else { succ } +// +// 2. In other cases, we can replace the two CmpI with +// a single CmpU. We fold iff1 towards middle, and +// replace the iff2 condition with the CmpU. Example: +// +// if (n >= 0 && n < 10) { succ } else { fail } +// // transformed to: +// if (n = arr.length) { throw ArrayOutOfBoundsException } +// // transformed to: +// if (n >=u arr.length) { throw ArrayOutOfBoundsException } +// +// Note1: we assume that the CmpI nodes are canonicalized to the +// point where n is always on the lhs. This is a limitation, +// but as long as v1 and v2 are constants they will eventually +// be canonicalized to the rhs. For variables, this may not always +// happen. +// +// Note2: We are flexible about the IfProj nodes: middle and succ +// could both be either IfTrue or IfFalse. +// +// Note3: Surrounding code has a different naming scheme! +// In has_only_uncommon_traps, the path towards the +// uncommon trap (e.g. failed range check) is called +// "success", while the path that does not go to +// the uncommon trap (e.g. in-bounds access) is called +// "fail". I think that is counter-intuitive, so I now +// used a different naming scheme here. +// +// Return true iff we could perform one of the optimizations. +bool IfNode::fold_compares_helper(IfProjNode* middle, IfProjNode* fail2, IfProjNode* succ, PhaseIterGVN* igvn) { + assert(fail2->in(0) == this, "link iff2->fail2"); + assert(succ->in(0) == this, "link iff2->succ"); - const TypeInt* lo_type = IfNode::filtered_int_type(igvn, n, otherproj); - const TypeInt* hi_type = IfNode::filtered_int_type(igvn, n, success); + IfNode* iff1 = middle->in(0)->as_If(); + IfNode* iff2 = this; + BoolNode* bool1 = iff1->in(1)->as_Bool(); + BoolNode* bool2 = iff2->in(1)->as_Bool(); + CmpNode* cmp1 = bool1->in(1)->as_Cmp(); + CmpNode* cmp2 = bool2->in(1)->as_Cmp(); + assert(cmp1->Opcode() == Op_CmpI, "comparisons must be CmpI"); + assert(cmp2->Opcode() == Op_CmpI, "comparisons must be CmpI"); - BoolTest::mask lo_test = dom_bool->_test._test; - BoolTest::mask hi_test = this_bool->_test._test; - BoolTest::mask cond = hi_test; + IfProjNode* fail1 = middle->other_if_proj(); - PhaseTransform::SpeculativeProgressGuard progress_guard(igvn); - // convert: - // - // dom_bool = x {<,<=,>,>=} a - // / \ - // proj = {True,False} / \ otherproj = {False,True} - // / - // this_bool = x {<,<=} b - // / \ - // fail = {True,False} / \ success = {False,True} - // / - // - // (Second test guaranteed canonicalized, first one may not have - // been canonicalized yet) - // - // into: - // - // cond = (x - lo) {u,>=u} adjusted_lim - // / \ - // fail / \ success - // / - // + Node* v1 = cmp1->in(2); + Node* v2 = cmp2->in(2); + Node* n = cmp1->in(1); + assert(cmp2->in(1) == n, "n must be lhs in both CmpI"); - // Figure out which of the two tests sets the upper bound and which - // sets the lower bound if any. - Node* adjusted_lim = nullptr; - if (lo_type != nullptr && hi_type != nullptr && hi_type->_lo > lo_type->_hi && - hi_type->_hi == max_jint && lo_type->_lo == min_jint && lo_test != BoolTest::ne) { - assert((dom_bool->_test.is_less() && !proj->_con) || - (dom_bool->_test.is_greater() && proj->_con), "incorrect test"); - - // this_bool = < - // dom_bool = >= (proj = True) or dom_bool = < (proj = False) - // x in [a, b[ on the fail (= True) projection, b > a-1 (because of hi_type->_lo > lo_type->_hi test above): - // lo = a, hi = b, adjusted_lim = b-a, cond = (proj = True) or dom_bool = <= (proj = False) - // x in ]a, b[ on the fail (= True) projection, b > a: - // lo = a+1, hi = b, adjusted_lim = b-a-1, cond = = (proj = True) or dom_bool = < (proj = False) - // x in [a, b] on the fail (= True) projection, b+1 > a-1: - // lo = a, hi = b, adjusted_lim = b-a+1, cond = (proj = True) or dom_bool = <= (proj = False) - // x in ]a, b] on the fail (= True) projection b+1 > a: - // lo = a+1, hi = b, adjusted_lim = b-a, cond = transform(new AddINode(lo, igvn->intcon(1))); + // Optimization 1: try to prove that succ is not reachable. + // Which values of n can pass iff1 to middle AND iff2 to succ? + const TypeInt* type_middle = filtered_int_type(igvn, n, middle); + if (type_middle != nullptr) { + const TypeInt* type_succ = filtered_int_type(igvn, n, succ); + if (type_succ != nullptr) { + if (type_middle->filter(type_succ) == Type::TOP) { + // The intersection is empty -> succ is not reachable. + // Fold iff2 towards fail2 (and away from succ). + igvn->replace_input_of(iff2, 1, igvn->intcon(fail2->_con)); + return true; // success: succ not reachable } - } else if (hi_test == BoolTest::le) { - if (lo_test == BoolTest::ge || lo_test == BoolTest::lt) { - adjusted_lim = igvn->transform(new SubINode(hi, lo)); - adjusted_lim = igvn->transform(new AddINode(adjusted_lim, igvn->intcon(1))); - cond = BoolTest::lt; - } else if (lo_test == BoolTest::gt || lo_test == BoolTest::le) { - adjusted_lim = igvn->transform(new SubINode(hi, lo)); - lo = igvn->transform(new AddINode(lo, igvn->intcon(1))); - cond = BoolTest::lt; - } else { - assert(false, "unhandled lo_test: %d", lo_test); - return false; - } - } else { - assert(igvn->_worklist.member(in(1)) && in(1)->Value(igvn) != igvn->type(in(1)), "unhandled hi_test: %d", hi_test); - return false; } - // this test was canonicalized - assert(this_bool->_test.is_less() && fail->_con, "incorrect test"); - } else if (lo_type != nullptr && hi_type != nullptr && lo_type->_lo > hi_type->_hi && - lo_type->_hi == max_jint && hi_type->_lo == min_jint && lo_test != BoolTest::ne) { + } - // this_bool = < - // dom_bool = < (proj = True) or dom_bool = >= (proj = False) - // x in [b, a[ on the fail (= False) projection, a > b-1 (because of lo_type->_lo > hi_type->_hi above): - // lo = b, hi = a, adjusted_lim = a-b, cond = >=u - // dom_bool = <= (proj = True) or dom_bool = > (proj = False) - // x in [b, a] on the fail (= False) projection, a+1 > b-1: - // lo = b, hi = a, adjusted_lim = a-b+1, cond = >=u - // lo = b, hi = a, adjusted_lim = a-b, cond = >u doesn't work because a = b - 1 is possible, then b-a = -1 - // this_bool = <= - // dom_bool = < (proj = True) or dom_bool = >= (proj = False) - // x in ]b, a[ on the fail (= False) projection, a > b: - // lo = b+1, hi = a, adjusted_lim = a-b-1, cond = >=u - // dom_bool = <= (proj = True) or dom_bool = > (proj = False) - // x in ]b, a] on the fail (= False) projection, a+1 > b: - // lo = b+1, hi = a, adjusted_lim = a-b, cond = >=u - // lo = b+1, hi = a, adjusted_lim = a-b-1, cond = >u doesn't work because a = b is possible, then b-a-1 = -1 + // Optimization 2: try to replace the two CmpI with one CmpU + // We can handle the following 4 cases: + // Input: two CmpI Output: one CmpU Assumption + // -------------------- ------------------------- ------------------- + // a) (n > lo && n < hi) -> n - lo - 1 2 && n < 5 ) n - 3 lo && n <= hi) -> n - lo - 1 2 && n <= 5 ) n - 3 = lo && n < hi) -> n - lo = 2 && n < 5 ) n - 2 = lo && n <= hi) -> n - lo <=u hi - lo (assuming lo <= hi) + // (n >= 2 && n <= 5 ) n - 2 <=u 3 + // range: [2, 3, 4, 5] + // + // Note1: the rhs of the CmpU indicates the cardinality of the range, + // allowing n to have exactly that many different values. + // + // Note2: all 4 case have an assumption: lo must be sufficiently smaller + // than hi. Below, and with the use of Lemma1 from below, we will + // prove that this implies that the rhs of the CmpU never + // underflows or overflows, which is critical for correctness. + // + // Below, we will prove and implement each of these cases. But first, + // we must handle the combinations of IfTrue/IfFalse projections for + // middle and succ, and extract which one is the lower bound (lo) and + // which one the upper bound (hi). + // + // <---- lower bound -----> <----------- succ -------------> <---- upper bound -----> + // [min_int .. lo_type->hi] [lo_type->hi+1 .. hi_type->lo-1] [hi_type->lo .. max_int] + // ^ ^ + // n {>/>=} lo n { <------------ unsigned upper bound -------------> + // [0 .. ] [ .. max_uint] + // ^ + // CmpU - swap(lo, hi); - swap(lo_type, hi_type); - swap(lo_test, hi_test); + BoolTest::mask test1 = bool1->_test._test; + BoolTest::mask test2 = bool2->_test._test; + if (middle->Opcode() == Op_IfFalse) { test1 = BoolTest::negate_mask(test1); } + if (succ->Opcode() == Op_IfFalse) { test2 = BoolTest::negate_mask(test2); } - assert((dom_bool->_test.is_less() && proj->_con) || - (dom_bool->_test.is_greater() && !proj->_con), "incorrect test"); - - cond = (hi_test == BoolTest::le || hi_test == BoolTest::gt) ? BoolTest::gt : BoolTest::ge; - - if (lo_test == BoolTest::lt) { - if (hi_test == BoolTest::lt || hi_test == BoolTest::ge) { - cond = BoolTest::ge; - } else if (hi_test == BoolTest::le || hi_test == BoolTest::gt) { - adjusted_lim = igvn->transform(new SubINode(hi, lo)); - adjusted_lim = igvn->transform(new AddINode(adjusted_lim, igvn->intcon(1))); - cond = BoolTest::ge; - } else { - assert(false, "unhandled hi_test: %d", hi_test); - return false; - } - } else if (lo_test == BoolTest::le) { - if (hi_test == BoolTest::lt || hi_test == BoolTest::ge) { - lo = igvn->transform(new AddINode(lo, igvn->intcon(1))); - cond = BoolTest::ge; - } else if (hi_test == BoolTest::le || hi_test == BoolTest::gt) { - adjusted_lim = igvn->transform(new SubINode(hi, lo)); - lo = igvn->transform(new AddINode(lo, igvn->intcon(1))); - cond = BoolTest::ge; - } else { - assert(false, "unhandled hi_test: %d", hi_test); - return false; - } - } else { - assert(igvn->_worklist.member(in(1)) && in(1)->Value(igvn) != igvn->type(in(1)), "unhandled lo_test: %d", lo_test); - return false; - } - // this test was canonicalized - assert(this_bool->_test.is_less() && !fail->_con, "incorrect test"); + Node* lo = nullptr; + Node* hi = nullptr; + const TypeInt* lo_type = nullptr; + const TypeInt* hi_type = nullptr; + BoolTest::mask lo_test = BoolTest::illegal; + BoolTest::mask hi_test = BoolTest::illegal; + if (BoolTest::is_greater(test1) && BoolTest::is_less(test2)) { + lo = v1; + hi = v2; + lo_type = IfNode::filtered_int_type(igvn, n, fail1); + hi_type = IfNode::filtered_int_type(igvn, n, fail2); + lo_test = test1; + hi_test = test2; + } else if (BoolTest::is_less(test1) && BoolTest::is_greater(test2)) { + lo = v2; + hi = v1; + lo_type = IfNode::filtered_int_type(igvn, n, fail2); + hi_type = IfNode::filtered_int_type(igvn, n, fail1); + lo_test = test2; + hi_test = test1; } else { - const TypeInt* failtype = filtered_int_type(igvn, n, proj); - if (failtype != nullptr) { - const TypeInt* type2 = filtered_int_type(igvn, n, fail); - if (type2 != nullptr) { - if (failtype->filter(type2) == Type::TOP) { - // previous if determines the result of this if so - // replace Bool with constant - igvn->replace_input_of(this, 1, igvn->intcon(success->_con)); - progress_guard.commit(); - return true; - } - } - } + // Could not find upper and lower bound. + return false; + } + assert(BoolTest::is_greater(lo_test), "lower bound: n {>/>=} lo"); + assert(BoolTest::is_less(hi_test), "upper bound: n {_hi != max_jint || + lo_type->_lo != min_jint) { + // Upper and lower bounds could not be established. return false; } - assert(lo != nullptr && hi != nullptr, "sanity"); - Node* hook = new Node(lo); // Add a use to lo to prevent him from dying - // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) (hi - lo)) - Node* adjusted_val = igvn->transform(new SubINode(n, lo)); - if (adjusted_lim == nullptr) { - adjusted_lim = igvn->transform(new SubINode(hi, lo)); - } - hook->destruct(igvn); + // ------------------------------------------------------------------- + // In the proofs below, we need some basic Lemmas to deal with integer + // signed and unsigned arithmetic. + // + // Lemma1: + // Let a and b be in [min_int .. max_int]. + // If a >=s b, then: + // U(a - b) = a - b + // + // Proof: + // a >= b + // -> a - b >= 0 + // + // a <= max_int + // b >= min_int + // -> a - b <= max_int - min_int = 2^32-1 + // + // 0 <= a - b <= 2^32-1 + // -> cast to unsigned has no overflow + // -> U(a - b) = a - b + // + // Lemma2: + // Let a and b be in [min_int .. max_int]. + // If a a - b < 0 + // + // a >= min_int + // b <= max_int + // -> a - b >= min_int - max_int = 2^32-1 + // + // 2^32-1 <= a - b < 0 + // -> cast to unsigned leads to exactly one overflow + // -> U(a - b) = a - b + 2^32 + // + // Lemma3: + // Let a and b be in [min_int .. max_int]. + // a + 2^32 > b + // + // Proof: + // Using a >= min_int, and b <= max_int: + // a + 2^32 >= min_int + 2^32 + // = max_int + 1 + // >= b + 1 + // > b + // ------------------------------------------------------------------- - if (adjusted_val->is_top() || adjusted_lim->is_top()) { - return false; + // Handle the 4 cases. + // All produce this form: n - lo + x1 hi - lo + x2 + Node* x1 = nullptr; + Node* x2 = nullptr; + BoolTest::mask cond = BoolTest::illegal; + if (lo_test == BoolTest::gt && hi_test == BoolTest::lt) { + // We perform the the (CHECK) below, which implies (LO-HI), + // as we will show below. + if (lo_type->_hi >= hi_type->_lo) { + return false; // (CHECK) fails, we cannot establish (LO-HI) assumption. + } + // a) (n > lo && n < hi) -> n - lo - 1 _hi] for n <= lo + // -> lo_type->_hi = lo->_hi + // hi_type = [hi->_lo .. max_int] for n >= lo + // -> hi_type->_lo = hi->_lo + // We will need the assumption (LO-HI) below, which we can + // establish with the following (CHECK): + // lo_type->_hi < hi_type->_lo (CHECK) + // -> lo->_hi < hi->_lo + // -> lo < hi (LO-HI) + // + // Case n <= lo: + // (BEFORE) is always false, show (AFTER) is always false. + // Since lo < hi (LO-HI), S(lo+1) = lo+1 (no overflow): + // -> lo+1 <= hi + // -> n < lo+1 + // U(n - (lo + 1)) < U(hi - (lo + 1)) + // -- Lemma2 (n < lo+1) -- -- Lemma1 (lo+1 <= hi) -- + // n - (lo + 1) + 2^32 < hi - (lo + 1) + // n + 2^32 < hi + // Always false by Lemma3. + // + // Case lo < n < hi: + // (BEFORE) is always true, show (AFTER) is always true. + // Since lo < hi (LO-HI), S(lo+1) = lo+1 (no overflow): + // -> lo+1 <= hi + // -> n >= lo+1 + // U(n - (lo + 1)) < U(hi - (lo + 1)) + // -- Lemma1 (n >= lo+1) -- -- Lemma1 (lo+1 <= hi) -- + // n - (lo + 1) < hi - (lo + 1) + // n < hi + // Corresponds to case assumption, so always true. + // + // Case n >= hi: + // (BEFORE) is always false, show (AFTER) is always false. + // Since lo < hi (LO-HI), S(lo+1) = lo+1 (no overflow): + // -> lo+1 <= hi + // U(n - (lo + 1)) < U(hi - (lo + 1)) + // -- Lemma1 (n >= lo+1) -- -- Lemma1 (lo+1 <= hi) -- + // n - (lo + 1) < hi - (lo + 1) + // n < hi + // Contradicts case assumption, so always false. + // QED. + // + // Note: we cannot use anything more relaxed than the assumption + // lo < hi: with lo=hi the rhs of the CmpU would underflow. + // + // Produce form: n - lo + x1 hi - lo + x2 + // n - lo - 1 intcon(-1); + x2 = igvn->intcon(-1); + cond = BoolTest::lt; + } else if (lo_test == BoolTest::gt && hi_test == BoolTest::le) { + // We perform the the (CHECK) below, which implies (LO-HI), + // as we will show below. + if (lo_type->_hi >= hi_type->_lo) { + return false; // (CHECK) fails, we cannot establish (LO-HI) assumption. + } + // b) (n > lo && n <= hi) -> n - lo - 1 _hi] for n <= lo + // -> lo_type->_hi = lo->_hi + // hi_type = [min(hi->_lo+1, max_int) .. max_int] for n > hi + // -> hi_type->_lo <= lo->_lo + 1 + // We will need the assumption (LO-HI) below, which we can + // establish with the following (CHECK): + // lo_type->_hi < hi_type->_lo (CHECK) + // -> lo->_hi < hi->_lo + 1 + // -> lo < hi + 1 + // -> lo <= hi (LO-HI) + // + // Case A: lo = hi + // Let y = lo = hi + // -> n > lo && n <= hi vs n - lo - 1 n > y && n <= y vs n - y - 1 n < lo+1 + // U(n - (lo + 1)) < U(hi - lo) + // -- Lemma2 (n < lo+1) -- -- Lemma1 (lo <= hi, LO-HI) -- + // n - (lo + 1) + 2^32 < hi - lo + // n - 1 + 2^32 < hi + // n + 2^32 <= hi + // Always false by Lemma3. + // Note: To apply Lemma2 above, we must use (Case B), we + // could not have done it with (LO-HI) alone. + // + // Case lo < n <= hi: + // (BEFORE) is always true, show (AFTER) is always true. + // Since lo < hi (Case B), S(lo+1) = lo+1 (no overflow): + // -> n >= lo+1 + // U(n - (lo + 1)) < U(hi - lo) + // -- Lemma1 (n >= lo+1) -- -- Lemma1 (lo <= hi, LO-HI) -- + // n - (lo + 1) < hi - lo + // n - 1 < hi + // n <= hi + // Follows from case assumption, so always true. + // + // Case n > hi: + // (BEFORE) is always false, show (AFTER) is always false. + // Since lo < hi (Case B), S(lo+1) = lo+1 (no overflow): + // -> lo+1 <= hi + // -> n > lo+1 + // U(n - (lo + 1)) < U(hi - lo) + // -- Lemma1 (n > lo+1) -- -- Lemma1 (lo <= hi, LO-HI) -- + // n - (lo + 1) < hi - lo + // n - 1 < hi + // n <= hi + // Contradicts case assumption, so always false. + // QED. + // + // Note: we cannot use anything more relaxed than the assumption + // lo <= hi: with lo=hi+1 the rhs of the CmpU would underflow. + // + // Produce form: n - lo + x1 hi - lo + x2 + // n - lo - 1 intcon(-1); + x2 = igvn->intcon(0); + cond = BoolTest::lt; + } else if (lo_test == BoolTest::ge && hi_test == BoolTest::lt) { + // We perform the the (CHECK) below, which implies (LO-HI), + // as we will show below. + if (lo_type->_hi >= hi_type->_lo) { + return false; // (CHECK) fails, we cannot establish (LO-HI) assumption. + } + // c) (n >= lo && n < hi) -> n - lo _hi - 1)] for n < lo + // -> lo_type->_hi >= lo->_hi - 1 + // hi_type = [b->_lo .. max_int] for n >= hi + // -> hi_type->_lo = hi->_lo + // We will need the assumption (LO-HI) below, which we can + // establish with the following (CHECK): + // lo_type->_hi < hi_type->_lo + // -> lo->_hi - 1 < hi->_lo + // -> lo->_hi <= hi->_lo + // -> lo <= hi (HI-LO) + // + // Case n < lo: + // (BEFORE) is always false, show (AFTER) is always false. + // U(n - lo) < U(hi - lo) + // -- Lemma2 (n < lo) -- -- Lemma1 (lo <= hi, LO-HI) -- + // n - lo + 2^32 < hi - lo + // n + 2^32 < hi + // Always false by Lemma3. + // + // Case lo <=s n = lo) -- -- Lemma1 (lo <= hi, LO-HI) -- + // n - lo < hi - lo + // n < hi + // Follows from case assumption, so always true. + // + // Case n >=s hi: + // (BEFORE) is always false, show (AFTER) is always false. + // U(n - lo) < U(hi - lo) + // -- Lemma1 (n >= lo) -- -- Lemma1 (lo <= hi, LO-HI) -- + // n - lo < hi - lo + // n < hi + // Contradicts case assumption, so always false. + // QED. + // + /// Note: we cannot use anything more relaxed than the assumption + // lo <= hi: with lo=hi+1 the rhs of the CmpU would underflow. + // + // Produce form: n - lo + x1 hi - lo + x2 + // n - lo intcon(0); + x2 = igvn->intcon(0); + cond = BoolTest::lt; + } else { + assert (lo_test == BoolTest::ge && hi_test == BoolTest::le, ""); + // We perform the the (CHECK) below, which implies (LO-HI), + // as we will show below. + jlong lo_type_hi = lo_type->_hi; + jlong hi_type_lo = hi_type->_lo; + if (lo_type_hi >= hi_type_lo - 1) { + return false; // (CHECK) fails, we cannot establish (LO-HI) assumption. + } + // d) (n >= lo && n <= hi) -> n - lo <=u hi - lo (assuming lo <= hi) + // (BEFORE) (AFTER) (LO-HI) + // + // Proof: + // From IfNode::filtered_int_type, we get: + // lo_type = [min_int .. max(min_int, lo->_hi-1)] for n < lo + // -> lo_type->_hi >= lo->_hi - 1 + // hi_type = [min(hi->_lo+1, max_int) .. max_int] for n > hi + // -> hi_type->_lo <= hi->_lo + 1 + // We will need the assumption (LO-HI) below, which we can + // establish with the following (CHECK), which we must compute in + // long to avoid underflow: + // lo_type->_hi < hi_type->_lo - 1 (CHECK) + // -> lo_type->_hi + 1 <= hi_type->_lo - 1 + // -> lo->_hi <= hi->_lo + // -> lo <= hi (LO-HI) + // + // Case n = lo, LO-HI) -- + // n - lo + 2^32 <= hi - lo + // n + 2^32 <= hi + // Always false by Lemma3. + // + // Case lo <=s n <=s hi: + // (BEFORE) is always true, show (AFTER) is always true. + // U(n - lo) <= U(hi - lo) + // -- Lemma1 (n >= lo) -- -- Lemma1 (hi >= lo, LO-HI) -- + // n - lo <= hi - lo + // n <= hi + // Corresponds to case assumption, so always true. + // + // Case n >s hi: + // (BEFORE) is always false, show (AFTER) is always false. + // U(n - lo) <= U(hi - lo) + // -- Lemma1 (n > lo) -- -- Lemma1 (hi >= lo, LO-HI) -- + // n - lo <= hi - lo + // n <= hi + // n <= hi + // Contradicts case assumption, so always false. + // QED. + // + // Note: (CHECK) is stronger in this case than in (a, b, c). We have + // had multiple bugs around this case (d) in the past. For example: + // - Before JDK-8135069: transform into: n - lo <=u hi - lo + // leads to rhs underflow with lo=0 and hi=-1 + // -> we are coming back to this solution, but instead + // of checking lo_type->_hi < hi_type->_lo + // we now check: lo_type->_hi < hi_type->_lo - 1 + // which implies lo <= hi and excludes this bad case. + // - Before JDK-8346420: transform into: n - lo hi - lo + x2 + // n - lo <=u hi - lo + x1 = igvn->intcon(0); + x2 = igvn->intcon(0); + cond = BoolTest::le; } - if (igvn->type(adjusted_lim)->is_int()->_lo < 0 && - !igvn->C->post_loop_opts_phase()) { - // If range check elimination applies to this comparison, it includes code to protect from overflows that may - // cause the main loop to be skipped entirely. Delay this transformation. - // Example: - // for (int i = 0; i < limit; i++) { - // if (i < max_jint && i > min_jint) {... - // } - // Comparisons folded as: - // i - min_jint - 1 outcnt() == 0) { - igvn->remove_dead_node(lo, PhaseIterGVN::NodeOrigin::Speculative); - } - if (adjusted_val->outcnt() == 0) { - igvn->remove_dead_node(adjusted_val, PhaseIterGVN::NodeOrigin::Speculative); - } - if (adjusted_lim->outcnt() == 0) { - igvn->remove_dead_node(adjusted_lim, PhaseIterGVN::NodeOrigin::Speculative); - } - igvn->C->record_for_post_loop_opts_igvn(this); - return false; - } - - Node* newcmp = igvn->transform(new CmpUNode(adjusted_val, adjusted_lim)); + // Construct the new check: n - lo + x1 hi - lo + x2 + Node* lhs = igvn->transform(new SubINode(n, lo)); + lhs = igvn->transform(new AddINode(lhs, x1)); + Node* rhs = igvn->transform(new SubINode(hi, lo)); + rhs = igvn->transform(new AddINode(rhs, x2)); + Node* newcmp = igvn->transform(new CmpUNode(lhs, rhs)); + if (succ->Opcode() == Op_IfFalse) { cond = BoolTest::negate_mask(cond); } Node* newbool = igvn->transform(new BoolNode(newcmp, cond)); - igvn->replace_input_of(dom_iff, 1, igvn->intcon(proj->_con)); - igvn->replace_input_of(this, 1, newbool); + // Fold iff1 towards middle, and replace the iff2 condition: + igvn->replace_input_of(iff1, 1, igvn->intcon(middle->_con)); + igvn->replace_input_of(iff2, 1, newbool); - progress_guard.commit(); - return true; + return true; // Success with CmpU } // Merge the branches that trap for this If and the dominating If into diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp index 29ec25b41f8..358508248d0 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -334,8 +334,11 @@ struct BoolTest { static mask negate_mask(mask btm) { return mask(btm ^ 4); } static mask unsigned_mask(mask btm); bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le || _test == BoolTest::overflow); } - bool is_less( ) const { return _test == BoolTest::lt || _test == BoolTest::le; } - bool is_greater( ) const { return _test == BoolTest::gt || _test == BoolTest::ge; } + bool is_less( ) const { return is_less(_test); } + bool is_greater( ) const { return is_greater(_test); } + static bool is_less(mask btm) { return btm == BoolTest::lt || btm == BoolTest::le; } + static bool is_greater(mask btm) { return btm == BoolTest::gt || btm == BoolTest::ge; } + void dump_on(outputStream *st) const; mask merge(BoolTest other) const; }; diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestFoldCompares.java b/test/hotspot/jtreg/compiler/rangechecks/TestFoldCompares.java new file mode 100644 index 00000000000..bec3e442403 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestFoldCompares.java @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=vanilla + * @bug 8346420 + * @summary Test logic in IfNode::fold_compares, which folds 2 signed comparisons + * into a single comparison. + * @library /test/lib / + * @run main ${test.main.class} + */ + +/* + * @test id=Xcomp + * @bug 8346420 + * @library /test/lib / + * @run main ${test.main.class} -Xcomp -XX:-TieredCompilation -XX:CompileCommand=compileonly,${test.main.class}::test* + */ + +package compiler.rangechecks; + +import compiler.lib.ir_framework.*; + +/** + * This test here is here to cover some basic cases of IfNode::fold_compares. It also contains the + * reproducers for JDK-8346420. We don't do any result verification, other than that we should never + * hit an Exception. For a test with result verification, see TestFoldComparesFuzzer.java + */ +public class TestFoldCompares { + public static boolean FLAG_FALSE = false; + + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + framework.addFlags(args); + framework.start(); + } + + // ------------------------- Failing cases for JDK-8346420 ------------------------------ + + @Test + @Arguments(values = {Argument.NUMBER_42}) + // Reported overflow case with wrong result in JDK-8346420 + public static void test_Case3a_LTLE_overflow(int i) { + int minimum, maximum; + if (FLAG_FALSE) { + minimum = 0; + maximum = 1; + } else { + // Always goes to else-path + minimum = Integer.MIN_VALUE; + maximum = Integer.MAX_VALUE; + } + // i < INT_MIN || i > MAX_INT + // 42 < INT_MIN || 42 > MAX_INT + // false false + // => false + // + // C2 transforms this into: + // i - minimum >=u (maximum - minimum) + 1 + // 42 - INT_MIN >=u (INT_MAX - INT_MIN) + 1 + // 42 + MIN_INT >=u -1 + 1 + // ------ overflow ------- + // 42 + MIN_INT >=u 0 + // => true + if (i < minimum || i > maximum) { + throw new RuntimeException("i can never be outside [min_int, max_int]"); + } + } + + @Test + @Arguments(values = {Argument.NUMBER_42}) + // Same as test_Case3a_LTLE_overflow, just with swapped conditions (JDK-8346420). + public static void test_Case3b_LTLE_overflow(int i) { + int minimum, maximum; + if (FLAG_FALSE) { + minimum = 0; + maximum = 1; + } else { + // Always goes to else-path + minimum = Integer.MIN_VALUE; + maximum = Integer.MAX_VALUE; + } + if (i > maximum || i < minimum) { + throw new RuntimeException("i can never be outside [min_int, max_int]"); + } + } + + @Test + @Arguments(values = {Argument.NUMBER_42}) + // 22 ConI === 0 [[ 25 37 ]] #int:0 + // 35 ConI === 0 [[ 37 ]] #int:minint + // 33 ConI === 0 [[ 38 81 ]] #int:1 + // 37 Phi === 34 35 22 [[ 42 80 81 84 ]] #int:minint..0, 0u..maxint+1 + // 81 AddI === _ 37 33 [[ 82 ]] + // 82 Node === 81 [[ ]] <----- hook + // + // We hit this assert, found while working on JDK-8346420: + // "fatal error: no reachable node should have no use" + // + // Because we compute: + // lo = lo + 1 + // hook = Node(lo) + // adjusted_val = i - lo + // -> gvn transformed to: (i - lo) + -1 + // -> the "lo = lo + 1" AddI now is only used by the hook, + // but once the hook is destroyed, it has no use any more, + // and we hit the assert. + public static void test_Case4a_LELE_assert(int i) { + int minimum, maximum; + if (FLAG_FALSE) { + minimum = 0; + maximum = 1; + } else { + minimum = Integer.MIN_VALUE; + maximum = Integer.MAX_VALUE; + } + if (i <= minimum || i > maximum) { + throw new RuntimeException("should never be reached"); + } + } + + // ------------------- IR tests to check that optimization was performed ------------------------ + + // The following tests with constant bounds are expected to fold to a single CmpU. + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}) + @Arguments(values = {Argument.NUMBER_42}) + public static void test_lohi_ltle(int i) { + if (i < -100_000 || i > 100_000) { + throw new RuntimeException(); + } + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}) + @Arguments(values = {Argument.NUMBER_42}) + public static void test_lohi_lele(int i) { + if (i <= -100_000 || i > 100_000) { + throw new RuntimeException(); + } + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}) + @Arguments(values = {Argument.NUMBER_42}) + public static void test_lohi_ltlt(int i) { + if (i < -100_000 || i >= 100_000) { + throw new RuntimeException(); + } + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}) + @Arguments(values = {Argument.NUMBER_42}) + public static void test_lohi_lelt(int i) { + if (i <= -100_000 || i >= 100_000) { + throw new RuntimeException(); + } + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}) + @Arguments(values = {Argument.NUMBER_42}) + public static void test_hilo_ltle(int i) { + if (i >= 100_000 || i <= -100_000) { + throw new RuntimeException(); + } + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}) + @Arguments(values = {Argument.NUMBER_42}) + public static void test_hilo_lele(int i) { + if (i > 100_000 || i <= -100_000) { + throw new RuntimeException(); + } + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}) + @Arguments(values = {Argument.NUMBER_42}) + public static void test_hilo_lelt(int i) { + if (i > 100_000 || i < -100_000) { + throw new RuntimeException(); + } + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}) + @Arguments(values = {Argument.NUMBER_42}) + public static void test_hilo_ltlt(int i) { + if (i >= 100_000 || i < -100_000) { + throw new RuntimeException(); + } + } + + // The following tests can completely remove the test and branches, we can prove that + // the path cannot be taken. + + @Setup + public static Object[] range256(SetupInfo info) { + return new Object[]{info.invocationCounter() & 255}; + } + + @Setup + public static Object[] rangeM128P127(SetupInfo info) { + return new Object[]{(info.invocationCounter() & 255) - 128}; + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 0"}) + @Arguments(setup = "rangeM128P127") + // Case from JDK-8135069. We used to do the CmpI->CmpU trick, but we can also constant fold + // this directly! + public static void test_empty_0(int i) { + if (i < 0 || i > -1) { + return; // always success + } + throw new RuntimeException("should not be reached"); + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 0"}) + @Arguments(setup = "range256") + public static void test_empty_1(int i) { + if (i < 100 || i > 50) { + return; // always success + } + throw new RuntimeException("should not be reached"); + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 0"}) + @Arguments(setup = "range256") + public static void test_empty_2(int i) { + if (i <= 100 || i >= 101) { + return; // always success + } + throw new RuntimeException("should not be reached"); + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 1", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + // Note: the two CmpI->Bool pairs are already canonicallized and commoned to a single pair. + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 0"}) + @Arguments(setup = "range256") + public static void test_empty_3(int i) { + if (i <= 100 || i > 100) { + return; // always success + } + throw new RuntimeException("should not be reached"); + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 1", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + // Note: the two CmpI->Bool pairs are already canonicallized and commoned to a single pair. + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 0"}) + @Arguments(setup = "range256") + public static void test_empty_4(int i) { + if (i < 101 || i >= 101) { + return; // always success + } + throw new RuntimeException("should not be reached"); + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 0"}) + @Arguments(setup = "range256") + public static void test_empty_5(int i) { + if (i < 101 || i > 100) { + return; // always success + } + throw new RuntimeException("should not be reached"); + } + + // Now test that we can use a.length, which means we do a null-check + // and then a comparison with a LoadRange that has type int[>=0] + + public static int[] ARR = new int[256]; + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING, + applyIf = {"TieredCompilation", "true"}) // proxy for "not Xcomp" + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}, + applyIf = {"TieredCompilation", "true"}) // proxy for "not Xcomp" + @Arguments(setup = "range256") + // Note: cannot get optimized with Xcomp + static int test_array_length_and_null_check_1(int i) { + if (i < 0 || i >= ARR.length) { + return -1; // never happens + } + return i; + } + + @Check(test = "test_array_length_and_null_check_1") + public void check_test_array_length_and_null_check_1(int i) { + if (i < 0) { throw new RuntimeException("Wrong value: " + i); } + } + + @Test + @IR(counts = {IRNode.CMP_I, "= 2", IRNode.CMP_U, "= 0"}, phase = CompilePhase.AFTER_PARSING, + applyIf = {"TieredCompilation", "true"}) // proxy for "not Xcomp" + @IR(counts = {IRNode.CMP_I, "= 0", IRNode.CMP_U, "= 1"}, + applyIf = {"TieredCompilation", "true"}) // proxy for "not Xcomp" + @Arguments(setup = "range256") + // Note: cannot get optimized with Xcomp + static int test_array_length_and_null_check_2(int i) { + if (i < 0 || i >= ARR.length) { + throw new RuntimeException("never go out of bounds"); + } + return i; + } +} diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestFoldComparesFuzzer.java b/test/hotspot/jtreg/compiler/rangechecks/TestFoldComparesFuzzer.java new file mode 100644 index 00000000000..0467689eb17 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestFoldComparesFuzzer.java @@ -0,0 +1,728 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * @bug 8346420 + * @summary Fuzz patterns for IfNode::fold_compares_helper + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @compile ../lib/ir_framework/TestFramework.java + * @compile ../lib/generators/Generators.java + * @compile ../lib/verify/Verify.java + * @run driver ${test.main.class} + */ + +package compiler.rangechecks; + +import java.util.List; +import java.util.ArrayList; +import java.util.Random; +import java.util.HashSet; +import java.util.Set; + +import jdk.test.lib.Utils; + +import compiler.lib.compile_framework.*; +import compiler.lib.generators.*; +import compiler.lib.template_framework.Template; +import compiler.lib.template_framework.TemplateToken; +import static compiler.lib.template_framework.Template.scope; +import static compiler.lib.template_framework.Template.let; +import static compiler.lib.template_framework.Template.$; + +import compiler.lib.template_framework.library.TestFrameworkClass; + +/** + * For more basic examples, see TestFoldCompares.java + * + * I'm only covering some basic cases to test the fundamental + * logic inside IfNode::fold_compares_helper. + * - TestMethodGeneratorConstIR does extensive result and IR verification + * for the cases a-d) in IfNode::fold_compares_helper, but only with + * constant lo and hi. + * - Other test generators currently don't have IR rules, but check + * correctness in various relevant scenarios I came across during + * the bugfix of JDK-8346420. + * - I'm also mixing signed and unsigned comparisons, just to ensure + * the less often used (and tested) unsigned comparisons don't slip + * through the cracks. + * + * In the future, we could add more cases: + * - Extend to long - though the optimization does not yet cover longs anyway. + * - More IR rules: difficult to make stable. Not all permutations are covered + * by the optimizations, edge-cases could make IR rules brittle. + */ +public class TestFoldComparesFuzzer { + private static final Random RANDOM = Utils.getRandomInstance(); + private static final RestrictableGenerator INT_GEN = Generators.G.ints(); + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + long t0 = System.nanoTime(); + // Add a java source file. + comp.addJavaSourceCode("compiler.rangecheck.templated.Generated", generate(comp)); + + long t1 = System.nanoTime(); + // Compile the source file. + comp.compile(); + + long t2 = System.nanoTime(); + + // Run the tests without any additional VM flags. + comp.invoke("compiler.rangecheck.templated.Generated", "main", new Object[] {new String[] {}}); + long t3 = System.nanoTime(); + + System.out.println("Code Generation: " + (t1-t0) * 1e-9f); + System.out.println("Code Compilation: " + (t2-t1) * 1e-9f); + System.out.println("Running Tests: " + (t3-t2) * 1e-9f); + } + + public static String generate(CompileFramework comp) { + // Create a list to collect all tests. + List testTemplateTokens = new ArrayList<>(); + + for (int i = 0; i < 100; i++) { + testTemplateTokens.add(generateTest(/* no warmup, like -Xcomp */ 0)); + } + for (int i = 0; i < 5; i++) { + testTemplateTokens.add(generateTest(/* with warmup, slower */ 10_000)); + } + + // Create the test class, which runs all testTemplateTokens. + return TestFrameworkClass.render( + // package and class name. + "compiler.rangecheck.templated", "Generated", + // List of imports. + Set.of("compiler.lib.generators.*", + "compiler.lib.verify.*", + "java.util.Random", + "jdk.test.lib.Utils"), + // classpath, so the Test VM has access to the compiled class files. + comp.getEscapedClassPathOfCompiledClasses(), + // The list of tests. + testTemplateTokens); + } + + enum Comparator { + // TODO: enable again after JDK-8385157 + // ULT(" < 0", false), + // ULE(" <= 0", false), + // UGT(" > 0", false), + // UGE(" >= 0", false), + // UEQ(" == 0", false), + // UNE(" != 0", false), + LT(" < ", true), + LE(" <= ", true), + GT(" > ", true), + GE(" >= ", true), + EQ(" == ", true), + NE(" != ", true); + + private final String token; + private final boolean signed; + + Comparator(String token, boolean signed) { + this.token = token; + this.signed = signed; + } + + public String getToken() { + return token; + } + + public boolean isSigned() { + return signed; + } + + public Comparator negate() { + return switch(this) { + // TODO: enable again after JDK-8385157 + // case ULT -> UGE; + // case ULE -> UGT; + // case UGT -> ULE; + // case UGE -> ULT; + // case UEQ -> UNE; + // case UNE -> UEQ; + case LT -> GE; + case LE -> GT; + case GT -> LE; + case GE -> LT; + case EQ -> NE; + case NE -> EQ; + }; + } + + public Comparator flip() { + return switch(this) { + // TODO: enable again after JDK-8385157 + // case ULT -> UGT; + // case ULE -> UGE; + // case UGT -> ULT; + // case UGE -> ULE; + // case UEQ -> UEQ; + // case UNE -> UNE; + case LT -> GT; + case LE -> GE; + case GT -> LT; + case GE -> LE; + case EQ -> EQ; + case NE -> NE; + }; + } + + static Comparator random() { + return values()[RANDOM.nextInt(values().length)]; + } + + static Comparator randomGreater() { + return RANDOM.nextBoolean() ? GE : GT; + } + + static Comparator randomLess() { + return RANDOM.nextBoolean() ? LE : LT; + } + } + + record Comparison(String lhs, Comparator cmp, String rhs, boolean negated) { + public Comparison(String lhs, Comparator cmp, String rhs) { + this(lhs, cmp, rhs, false); + } + + public String toString() { + return cmp.isSigned() + ? ((negated ? "!" : "") + "(" + lhs + " "+ cmp.getToken() + " " + rhs + ")") + : ((negated ? "!" : "") + "(Integer.compareUnsigned(" + lhs + ", " + rhs + ")" + cmp.getToken() + ")"); + } + + // Keep the same semantics of the test, but change its form. + Comparison permuteRandom() { + return flipRandom().complementRandom(); + } + + Comparison flipRandom() { + return RANDOM.nextBoolean() ? this : new Comparison(rhs, cmp.flip(), lhs); + } + + Comparison complementRandom() { + return RANDOM.nextBoolean() ? this : new Comparison(lhs, cmp.negate(), rhs, true); + } + + Comparison negateCmp() { + return new Comparison(lhs, cmp.negate(), rhs, negated); + } + } + + interface TestMethodGenerator { + Template.OneArg getTestTemplate(); + + default Template.ZeroArgs getIRTemplate(boolean withWarmup) { + return Template.make(() -> scope("// No IR rule.\n")); + } + + default Template.ZeroArgs getInputTemplate() { + return Template.make(() -> scope( + """ + RestrictableGenerator gen = Generators.G.ints(); + int n = gen.next(); + int a = gen.next(); + int b = gen.next(); + """ + )); + }; + } + + // Some basic ranges with constant bounds. + // This should test some basic correctness, and also covers the case + // of bug JDK-8135069. + static class TestMethodGeneratorConst implements TestMethodGenerator { + private final int con1 = INT_GEN.next(); + private final int con2 = INT_GEN.next(); + + private final Comparison c1 = new Comparison("n", Comparator.random(), "con1").permuteRandom(); + private final Comparison c2 = new Comparison("n", Comparator.random(), "con2").permuteRandom(); + + private final Template.OneArg testTemplate = Template.make("methodName", (String methodName) -> scope( + let("con1", con1), + let("con2", con2), + let("c1", c1), + let("c2", c2), + """ + static boolean #methodName(int n, int a, int b) { + int con1 = #con1; + int con2 = #con2; + if (#c1 || #c2) { + return true; + } + return false; + } + """ + )); + + public Template.OneArg getTestTemplate() { return testTemplate; } + } + + // Cases where a and b are ranges that touch min_int/max_int. + // Note: if con1=0 and con2=1 then this is like the cases: + // - test_Case3a_LTLE_overflow + // - test_Case3b_LTLE_overflow + // - test_Case4a_LELE_assert + // + // Hence, I think this test gives us quite good coverage for the kinds of bugs + // such as JDK-8346420. + static class TestMethodGeneratorWithIf implements TestMethodGenerator { + private final int con1 = INT_GEN.next(); + private final int con2 = INT_GEN.next(); + private final String m1 = RANDOM.nextBoolean() ? "Integer.MIN_VALUE" : "Integer.MAX_VALUE"; + private final String m2 = RANDOM.nextBoolean() ? "Integer.MIN_VALUE" : "Integer.MAX_VALUE"; + + private final Comparison c1 = new Comparison("n", Comparator.random(), "a").permuteRandom(); + private final Comparison c2 = new Comparison("n", Comparator.random(), "b").permuteRandom(); + + private final Template.OneArg testTemplate = Template.make("methodName", (String methodName) -> scope( + let("con1", con1), + let("con2", con2), + let("m1", m1), + let("m2", m2), + let("c1", c1), + let("c2", c2), + """ + static boolean #methodName(int n, int a, int b) { + if (a < b) { + a = #con1; + b = #con2; + } else { + a = #m1; + b = #m2; + } + if (#c1 || #c2) { + return true; + } + return false; + } + """ + )); + + public Template.OneArg getTestTemplate() { return testTemplate; } + } + + // Just for good practice: add some case where the ranges are more free. + static class TestMethodGeneratorRanges implements TestMethodGenerator { + private final int n_hi = INT_GEN.next(); + private final int n_lo = INT_GEN.next(); + private final int a_hi = INT_GEN.next(); + private final int a_lo = INT_GEN.next(); + private final int b_hi = INT_GEN.next(); + private final int b_lo = INT_GEN.next(); + + private final Comparison c1 = new Comparison("n", Comparator.random(), "a").permuteRandom(); + private final Comparison c2 = new Comparison("n", Comparator.random(), "b").permuteRandom(); + + private final Template.OneArg template = Template.make("methodName", (String methodName) -> scope( + let("n_hi", n_hi), + let("n_lo", n_lo), + let("a_hi", a_hi), + let("a_lo", a_lo), + let("b_hi", b_hi), + let("b_lo", b_lo), + let("c1", c1), + let("c2", c2), + """ + static boolean #methodName(int n, int a, int b) { + n = Math.min(#n_hi, Math.max(#n_lo, n)); + a = Math.min(#a_hi, Math.max(#a_lo, a)); + b = Math.min(#b_hi, Math.max(#b_lo, b)); + if (#c1 || #c2) { + return true; + } + return false; + } + """ + )); + + public Template.OneArg getTestTemplate() { + return template; + } + } + + // Generate some more constrained cases, but with IR rules + static class TestMethodGeneratorConstIR implements TestMethodGenerator { + private final int lo; + private final int hi; + { // instance initializer + // We want to cover all cases for lo and hi combinations. But the + // critical cases happen around int_min and int_max, and when + // lo and hi are close to each other. + switch (RANDOM.nextInt(3)) { + case 0 -> { + // Full freedom, will eventually cover all cases + lo = INT_GEN.next(); + hi = INT_GEN.next(); + } + case 1 -> { + // Pick cases around overflow and underflow + lo = Integer.MAX_VALUE - 5 + RANDOM.nextInt(10); + hi = Integer.MAX_VALUE - 5 + RANDOM.nextInt(10); + } + default -> { + // Pick cases where lo and hi are close to each other + lo = INT_GEN.next(); + hi = lo - 5 + RANDOM.nextInt(10); + } + } + } + + // Since we are using constants for lo and hi, the checks should get canonicalized, + // so that n is always in the lhs. We only create cases that are covered by the + // 4 cases of "2 CmpI -> 1 CmpU" optimization in IfNode::fold_compares_helper. + private final Comparison c_lo = new Comparison("n", Comparator.randomGreater(), "lo"); + private final Comparison c_hi = new Comparison("n", Comparator.randomLess(), "hi"); + private final boolean swap = RANDOM.nextBoolean(); + private final Comparison c1Permuted = (swap ? c_lo : c_hi).permuteRandom(); + private final Comparison c2Permuted = (swap ? c_hi : c_lo).permuteRandom(); + // n > lo && n < hi -> check for inside range + // n <= lo || n >= hi -> chedk for outside range + private final boolean withAnd = RANDOM.nextBoolean(); + private final String operator = withAnd ? "&&" : "||"; + private final Comparison c1 = withAnd ? c1Permuted : c1Permuted.negateCmp(); + private final Comparison c2 = withAnd ? c2Permuted : c2Permuted.negateCmp(); + + private final Template.OneArg testTemplate = Template.make("methodName", (String methodName) -> scope( + let("lo", lo), + let("hi", hi), + let("c1", c1), + let("c2", c2), + let("op", operator), + """ + static boolean #methodName(int n, int a, int b) { + int lo = #lo; + int hi = #hi; + if (#c1 #op #c2) { + return true; + } + return false; + } + """ + )); + + public Template.OneArg getTestTemplate() { return testTemplate; } + + public Template.ZeroArgs getIRTemplate(boolean withWarmup) { + return Template.make(() -> { + String cmpIParse, cmpUParse, cmpIFinal, cmpUFinal; + String comment; + + // If both branches are compiled (in -Xcomp mode, i.e. no warmup), then + // we can know very precisely what happens in each case. + if (c_lo.cmp() == Comparator.GT && c_hi.cmp() == Comparator.LT) { + // a) (n > lo && n < hi) + if (lo == Integer.MAX_VALUE || hi == Integer.MIN_VALUE) { + cmpIParse = "< 2"; cmpUParse = "= 0"; cmpIFinal = "< 2"; cmpUFinal = "= 0"; + comment = "a) one or both checks fold at parse time"; + } else if (lo < hi && lo+2 == hi) { + // Not yet folded at parsing, because lo != hi + // BoolNode::Ideal: x x==0 (signed) + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 1"; cmpUFinal = "= 0"; + comment = "a) replace with CmpU (single element) -> CmpI eq"; + } else if (lo < hi && lo+1 == hi) { + // Not yet folded at parsing, because lo != hi + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 0"; + comment = "a) impossible condition (exact) -> fold away"; + } else if (lo < hi) { + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 1"; + comment = "a) replace with CmpU (non-empty)"; + } else if (lo == hi) { + // same CmpI at parse time + cmpIParse = "= 1"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 0"; + comment = "a) impossible condition -> fold away"; + } else { + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 0"; + comment = "a) impossible condition -> fold away"; + } + } else if (c_lo.cmp() == Comparator.GT && c_hi.cmp() == Comparator.LE) { + // b) (n > lo && n <= hi) + if (lo == Integer.MAX_VALUE || hi == Integer.MAX_VALUE) { + cmpIParse = "< 2"; cmpUParse = "= 0"; cmpIFinal = "< 2"; cmpUFinal = "= 0"; + comment = "b) one or both checks fold at parse time"; + } else if (lo < hi && lo+1 == hi) { + // BoolNode::Ideal: x x==0 (signed) + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 1"; cmpUFinal = "= 0"; + comment = "b) replace with CmpU (single element) -> CmpI eq"; + } else if (lo < hi && lo+1 < hi) { + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 1"; + comment = "b) replace with CmpU (non-empty)"; + } else if (lo == hi) { + cmpIParse = "= 1"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 0"; + comment = "b) impossible condition (exact) -> fold away"; + } else { + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 0"; + comment = "b) impossible condition -> fold away"; + } + } else if (c_lo.cmp() == Comparator.GE && c_hi.cmp() == Comparator.LT) { + // c) (n >= lo && n < hi) + if (lo == Integer.MIN_VALUE || hi == Integer.MIN_VALUE) { + cmpIParse = "< 2"; cmpUParse = "= 0"; cmpIFinal = "< 2"; cmpUFinal = "= 0"; + comment = "c) one or both checks fold at parse time"; + } else if (lo < hi && lo+1 == hi) { + // BoolNode::Ideal: x x==0 (signed) + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 1"; cmpUFinal = "= 0"; + comment = "c) replace with CmpU (single element) -> CmpI eq"; + } else if (lo < hi && lo+1 < hi) { + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 1"; + comment = "c) replace with CmpU (non-empty)"; + } else if (lo == hi) { + // RegionNode::optimize_trichotomy: can fold (n >= x && n < x) -> never + cmpIParse = "< 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 0"; + comment = "c) impossible condition (exact) -> fold away"; + } else { + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 0"; + comment = "c) impossible condition -> fold away"; + } + } else if (c_lo.cmp() == Comparator.GE && c_hi.cmp() == Comparator.LE) { + // d) (n >= lo && n <= hi) + if (lo == Integer.MIN_VALUE || hi == Integer.MAX_VALUE) { + cmpIParse = "< 2"; cmpUParse = "= 0"; cmpIFinal = "< 2"; cmpUFinal = "= 0"; + comment = "d) one or both checks fold at parse time"; + } else if (lo == hi) { + // same CmpI at parse time + // BoolNode::Ideal: x x==0 (signed) + cmpIParse = "= 1"; cmpUParse = "= 0"; cmpIFinal = "= 1"; cmpUFinal = "= 0"; + comment = "d) replace with CmpU (single element) -> CmpI eq"; + } else if (lo < hi) { + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 1"; + comment = "d) replace with CmpU (non-empty)"; + } else { + cmpIParse = "= 2"; cmpUParse = "= 0"; cmpIFinal = "= 0"; cmpUFinal = "= 0"; + comment = "d) impossible condition -> fold away"; + } + } else { + throw new RuntimeException("should not be generated: " + c_lo + " and " + c_hi); + } + + // All the precise counting above assumes that both ifs get compiled, and hence + // both CmpI are generated. Further, it assumes that both of the "or" branches + // (fail1 and fail2) end up "in the same place": either at the same region, or + // both in an uncommon trap. With profiling, the following cases are possible: + // - The first if is constant folded to fail1, and we have no CmpI nor CmpU + // in the graph. + // - The first if always leads to fail1, and away from the second if, and so we + // only have a single CmpI in the graph after parsing. + // - The first if always leads towards the second if, and away from fail1. And + // the second if always points towards fail2 and away from succ. We get an + // uncommon trap for fail1 and succ, and only the fail2 path is compiled. + // Hence, we have two CmpI, but fail1 and fail2 do not end up "in the same place". + // This makes our IR rule quite weak, sadly. We could make the IR rules stronger, + // but we would need to control warmup, and generate corresponding inputs that + // ensure the right paths are compiled or not compiled. + if (withWarmup) { + cmpIParse = "<= 2"; cmpUParse = "= 0"; cmpIFinal = "<= 2"; cmpUFinal = "< 2"; + comment = "with warmup: unstable-if makes precise counting hard."; + } + + return scope( + let("IP", cmpIParse), + let("UP", cmpUParse), + let("IF", cmpIFinal), + let("UF", cmpUFinal), + let("comment", comment), + """ + // #comment + @IR(counts = {IRNode.CMP_I, "#IP", IRNode.CMP_U, "#UP"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.CMP_I, "#IF", IRNode.CMP_U, "#UF"}) + """ + ); + }); + } + + @Override + public Template.ZeroArgs getInputTemplate() { + return Template.make(() -> scope( + let("lo", lo), + let("hi", hi), + """ + Random r = Utils.getRandomInstance(); + RestrictableGenerator gen = Generators.G.ints(); + int a = gen.next(); + int b = gen.next(); + """, + switch (RANDOM.nextInt(9)) { + // Random values + case 0 -> "int n = gen.next();\n"; + // Fuzz around specific values + case 1 -> "int n = r.nextInt(10) - 5 + #lo;\n"; + case 2 -> "int n = r.nextInt(10) - 5 + #hi;\n"; + case 3 -> "int n = r.nextInt(10) - 5 + (r.nextBoolean() ? #lo : #hi);\n"; + case 4 -> "int n = r.nextInt(10) - 5 + Integer.MAX_VALUE;\n"; + // Only very low or very high values, or in the middle + case 5 -> "int n = r.nextInt(10) - 10 + Integer.MAX_VALUE;\n"; + case 6 -> "int n = r.nextInt(10) + Integer.MIN_VALUE;\n"; + case 7 -> "int n = r.nextInt(10) - 5 + #lo/2 + #hi/2;\n"; + // Always the same constant + default -> "int n = " + INT_GEN.next() + ";\n"; + } + )); + }; + } + + // switch cases can also be implemented with range checks using + // constants, and then we can optimize 2 CmpI with a single CmpU, + // at least in some cases. + static class TestMethodGeneratorSwitch implements TestMethodGenerator { + Set cases = new HashSet<>(); + { // instance initializer + int n = RANDOM.nextInt(1, 20); + for (int i = 0; i < n; i++) { + cases.add((short)(int)INT_GEN.next()); + } + } + + private final Template.OneArg testTemplate = Template.make("methodName", (String methodName) -> scope( + """ + static boolean #methodName(int n, int a, int b) { + switch((short)n) { + """, + cases.stream().map(i -> scope( + let("i", i), + """ + case (short)#i: + """ + )).toList(), + """ + return true; + default: + return false; + } + } + """ + )); + + public Template.OneArg getTestTemplate() { return testTemplate; } + } + + // If arr.length is in the second check, the null-check for arr + // is located between the two checks. + // I'm not adding any IR rules here, just checking for correctness. + static class TestMethodGeneratorArrLength implements TestMethodGenerator { + private final int n_hi = INT_GEN.next(); + private final int n_lo = INT_GEN.next(); + private final int a_hi = INT_GEN.next(); + private final int a_lo = INT_GEN.next(); + private final int size = INT_GEN.restricted(0, 100_000).next(); + + // Get checks like: n < a || n >= arr.length + private final Comparison c_lo = new Comparison("n", Comparator.random(), "a").permuteRandom(); + private final Comparison c_hi = new Comparison("n", Comparator.random(), "arr.length").permuteRandom(); + private final boolean swap = RANDOM.nextBoolean(); + private final Comparison c1Permuted = (swap ? c_lo : c_hi).permuteRandom(); + private final Comparison c2Permuted = (swap ? c_hi : c_lo).permuteRandom(); + // n > lo && n < hi -> check for inside range + // n <= lo || n >= hi -> chedk for outside range + private final boolean withAnd = RANDOM.nextBoolean(); + private final String operator = withAnd ? "&&" : "||"; + private final Comparison c1 = withAnd ? c1Permuted : c1Permuted.negateCmp(); + private final Comparison c2 = withAnd ? c2Permuted : c2Permuted.negateCmp(); + + private final Template.OneArg testTemplate = Template.make("methodName", (String methodName) -> scope( + let("n_hi", n_hi), + let("n_lo", n_lo), + let("a_hi", a_hi), + let("a_lo", a_lo), + let("size", size), + let("c1", c1), + let("c2", c2), + let("op", operator), + """ + static boolean #methodName(int n, int a, int b) { + int[] arr = $arr; + n = Math.min(#n_hi, Math.max(#n_lo, n)); + a = Math.min(#a_hi, Math.max(#a_lo, a)); + if (#c1 #op #c2) { + return true; + } + return false; + } + static int[] $arr = new int[#size]; + """ + )); + + public Template.OneArg getTestTemplate() { return testTemplate; } + } + + public static TemplateToken generateTest(int warmup) { + TestMethodGenerator tg = switch(RANDOM.nextInt(6)) { + case 0 -> new TestMethodGeneratorConst(); + case 1 -> new TestMethodGeneratorWithIf(); + case 2 -> new TestMethodGeneratorRanges(); + case 3 -> new TestMethodGeneratorConstIR(); + case 4 -> new TestMethodGeneratorSwitch(); + case 5 -> new TestMethodGeneratorArrLength(); + default -> throw new RuntimeException("not expected"); + }; + Template.ZeroArgs testInputTemplate = tg.getInputTemplate(); + Template.OneArg testMethodTemplate = tg.getTestTemplate(); + Template.ZeroArgs testIRTemplate = tg.getIRTemplate(warmup >= 10_000); + + var testTemplate = Template.make(() -> scope( + let("warmup", warmup / 100), + """ + // --- $test start --- + @Run(test = "$test") + @Warmup(#warmup) + public static void $run() { + for (int i = 0; i < 100; i++) { + // Generate random values for n, a, b. + """, + testInputTemplate.asToken(), + """ + + // Run test and compare with interpreter results. + var result = $test(n, a, b); + var expected = $reference(n, a, b); + if (result != expected) { + throw new RuntimeException("wrong result: " + result + " vs " + expected + + "\\nn: " + n + + "\\na: " + a + + "\\nb: " + b); + } + } + } + + @Test + """, + testIRTemplate.asToken(), + testMethodTemplate.asToken($("test")), + """ + + @DontCompile + """, + testMethodTemplate.asToken($("reference")), + """ + // --- $test end --- + """ + )); + return testTemplate.asToken(); + } +} From 9536b7f6c004e0ad0a8e7db756735946ab0a56a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Mon, 1 Jun 2026 07:17:50 +0000 Subject: [PATCH 008/115] 8384964: Add an entry count to the MallocSiteTable Reviewed-by: coleenp, fbredberg --- src/hotspot/share/nmt/mallocSiteTable.cpp | 8 +++++++ src/hotspot/share/nmt/mallocSiteTable.hpp | 1 + .../jtreg/runtime/NMT/MallocStressTest.java | 23 ++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/nmt/mallocSiteTable.cpp b/src/hotspot/share/nmt/mallocSiteTable.cpp index 0b8dc8e5fa0..d0b4bbe379f 100644 --- a/src/hotspot/share/nmt/mallocSiteTable.cpp +++ b/src/hotspot/share/nmt/mallocSiteTable.cpp @@ -32,6 +32,7 @@ Atomic* MallocSiteTable::_table = nullptr; const NativeCallStack* MallocSiteTable::_hash_entry_allocation_stack = nullptr; const MallocSiteHashtableEntry* MallocSiteTable::_hash_entry_allocation_site = nullptr; +Atomic MallocSiteTable::_entry_count(0); /* * Initialize malloc site table. @@ -82,6 +83,7 @@ bool MallocSiteTable::initialize() { // Add the allocation site to hashtable. int index = hash_to_index(entry.hash()); _table[index].store_relaxed(const_cast(&entry)); + _entry_count.add_then_fetch(1ul, memory_order_relaxed); return true; } @@ -127,6 +129,7 @@ MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, uint32_t* // swap in the head if (_table[index].compare_set(nullptr, entry)) { + _entry_count.add_then_fetch(1ul, memory_order_relaxed); *marker = build_marker(index, 0); return entry->data(); } @@ -152,6 +155,7 @@ MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, uint32_t* if (head->atomic_insert(entry)) { pos_idx ++; *marker = build_marker(index, pos_idx); + _entry_count.add_then_fetch(1ul, memory_order_relaxed); return entry->data(); } // contended, other thread won @@ -236,6 +240,10 @@ void MallocSiteTable::print_tuning_statistics(outputStream* st) { } st->print_cr("Malloc allocation site table:"); +#ifdef ASSERT + // This is solely for testing + st->print_cr("\tExpected entry count: %zu", _entry_count.load_relaxed()); +#endif st->print_cr("\tTotal entries: %d", total_entries); st->print_cr("\tEmpty entries (no outstanding mallocs): %d (%2.2f%%)", empty_entries, ((float)empty_entries * 100) / (float)total_entries); diff --git a/src/hotspot/share/nmt/mallocSiteTable.hpp b/src/hotspot/share/nmt/mallocSiteTable.hpp index d78e6ebba6e..22b944301d3 100644 --- a/src/hotspot/share/nmt/mallocSiteTable.hpp +++ b/src/hotspot/share/nmt/mallocSiteTable.hpp @@ -196,6 +196,7 @@ class MallocSiteTable : AllStatic { private: // The callsite hashtable. It has to be a static table, // since malloc call can come from C runtime linker. + static Atomic _entry_count; static Atomic* _table; static const NativeCallStack* _hash_entry_allocation_stack; static const MallocSiteHashtableEntry* _hash_entry_allocation_site; diff --git a/test/hotspot/jtreg/runtime/NMT/MallocStressTest.java b/test/hotspot/jtreg/runtime/NMT/MallocStressTest.java index 6af14268c7e..db65348246b 100644 --- a/test/hotspot/jtreg/runtime/NMT/MallocStressTest.java +++ b/test/hotspot/jtreg/runtime/NMT/MallocStressTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2023, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -137,6 +137,27 @@ public class MallocStressTest { pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "statistics"}); output = new OutputAnalyzer(pb.start()); output.shouldNotContain("Tracking level has been downgraded due to lack of resources"); + + if (Platform.isDebugBuild()) { + String expectedCountString = output.firstMatch("\\s*Expected entry count: (\\d+)", 1); + String totalEntriesString = output.firstMatch("\\s*Total entries: (\\d+)", 1); + + if (expectedCountString == null || totalEntriesString == null) { + throw new RuntimeException("Missing malloc site table entry counts in NMT statistics output"); + } + + int expectedCount = Integer.parseInt(expectedCountString); + int totalEntries = Integer.parseInt(totalEntriesString); + + // The expected count is loaded after the total entries has accumulated (internal impl detail from hotspot). + // As this is a concurrent hashtable, we might have added more malloc sites. + // So, we're ok with the expectedCount being larger than totalEntries, but if it's *A lot* larger something + // really weird is going on. + if (expectedCount - totalEntries > 5) { + throw new RuntimeException("Malloc site table entry count mismatch: expected " + + expectedCount + ", walked " + totalEntries); + } + } } private static void sleep_wait(int n) { From 3760d75e66cbafe8206394afdabf4a2a9ccfd2b8 Mon Sep 17 00:00:00 2001 From: Anton Seoane Ampudia Date: Mon, 1 Jun 2026 07:20:32 +0000 Subject: [PATCH 009/115] 8384104: Obsolete Xmaxjitcodesize Reviewed-by: kvn, dholmes --- src/hotspot/share/runtime/arguments.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index a607484d02a..dc177bdce6d 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -2195,11 +2195,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin if (FLAG_SET_CMDLINE(ThreadStackSize, value) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - } else if (match_option(option, "-Xmaxjitcodesize", &tail) || - match_option(option, "-XX:ReservedCodeCacheSize=", &tail)) { - if (match_option(option, "-Xmaxjitcodesize", &tail)) { - warning("Option -Xmaxjitcodesize was deprecated in JDK 26 and will likely be removed in a future release."); - } + } else if (match_option(option, "-Xmaxjitcodesize", &tail)) { + warning("Ignoring option %s; support was removed in JDK 27", option->optionString); + } else if (match_option(option, "-XX:ReservedCodeCacheSize=", &tail)) { julong long_ReservedCodeCacheSize = 0; ArgsRange errcode = parse_memory_size(tail, &long_ReservedCodeCacheSize, 1); From 2820c789fa6daf625b1f0f6bfe03a7c3eb428d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Mon, 1 Jun 2026 07:26:30 +0000 Subject: [PATCH 010/115] 8385408: C2: no reachable node should have no use Reviewed-by: dlong, kvn --- src/hotspot/share/opto/mulnode.cpp | 3 +- .../compiler/igvn/TestShiftWorklist.java | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/igvn/TestShiftWorklist.java diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 5e05d6a6e04..e48acd23b87 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -894,7 +894,8 @@ static Node* mask_and_replace_shift_amount(PhaseGVN* phase, Node* shift_node, ui } if (replace) { - shift_node->set_req(2, phase->intcon(masked_shift)); // Replace shift count with masked value. + // Replace shift count with masked value and put potential dead nodes on the worklist. + shift_node->set_req_X(2, phase->intcon(masked_shift), phase); // We need to notify the caller that the graph was reshaped, as Ideal needs // to return the root of the reshaped graph if any change was made. diff --git a/test/hotspot/jtreg/compiler/igvn/TestShiftWorklist.java b/test/hotspot/jtreg/compiler/igvn/TestShiftWorklist.java new file mode 100644 index 00000000000..64c5a5fe658 --- /dev/null +++ b/test/hotspot/jtreg/compiler/igvn/TestShiftWorklist.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8385408 + * @summary Test that inputs to removed shifts are put on the worklist and cleaned up + * @library /test/lib / + * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:-UseOnStackReplacement + * -XX:CompileCommand=compileonly,${test.main.class}::test + * ${test.main.class} + * @run main ${test.main.class} + */ + +package compiler.igvn; + +import jdk.test.lib.Asserts; + +public class TestShiftWorklist { + int N = 400; + int iArr[] = new int[N]; + + public static void main(String[] args) { + TestShiftWorklist t = new TestShiftWorklist(); + for (int i = 0; i < 2_000; i++) { + int result = t.test(); + Asserts.assertEQ(result, 0); + } + } + + private int test() { + long[] lArr = new long[N]; + long l = 1957; // l % 32 = 5 + int n = 1; + for (int i = 1; i < 30; ++i) { + for (double j = 1; j < 12; j++) { + iArr[i] = 3; + for (long k = 1; k < 2; k++) { + // C2 is able to prove that the effecive shift value for the int n is always 5. + n >>= l; + } + l = 907436423360901L; // l % 32 = 5 + } + } + return (int) checkSum(lArr); + } + + private static long checkSum(long[] a) { + long sum = 0; + for (int j = 0; j < a.length; j++) { + sum += (a[j] / (j + 1) + a[j] % (j + 1)); + } + return sum; + } +} From 05a6580883e4badccf72898f7f27c1f4812e5400 Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Mon, 1 Jun 2026 07:34:49 +0000 Subject: [PATCH 011/115] 8385583: RISC-V: Debugger very slow during stepping Reviewed-by: fyang, dzhang --- src/hotspot/cpu/riscv/interp_masm_riscv.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index 443f3e3d17f..bb56acb3f38 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -1221,6 +1221,7 @@ void InterpreterMacroAssembler::notify_method_exit( // track stack depth. If it is possible to enter interp_only_mode we add // the code to check if the event should be sent. if (mode == NotifyJVMTI && (JvmtiExport::can_post_interpreter_events() || JvmtiExport::can_post_frame_pop())) { + Label L; // Note: frame::interpreter_frame_result has a dependency on how the // method result is saved across the call to post_method_exit. If this // is changed then the interpreter_frame_result implementation will @@ -1228,8 +1229,18 @@ void InterpreterMacroAssembler::notify_method_exit( // template interpreter will leave the result on the top of the stack. push(state); + + ld(t1, Address(xthread, JavaThread::jvmti_thread_state_offset())); + beqz(t1, L); // if (thread->jvmti_thread_state() == nullptr) exit; + + lwu(t1, Address(t1, JvmtiThreadState::frame_pop_cnt_offset())); + lwu(t0, Address(xthread, JavaThread::interp_only_mode_offset())); + orr(t0, t0, t1); + beqz(t0, L); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); + bind(L); pop(state); } From 3f2002d4880af3f3cbd5344039fd97c073f98486 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Mon, 1 Jun 2026 08:27:38 +0000 Subject: [PATCH 012/115] 8384507: Incorrect vector reassociation for signed saturating addition Reviewed-by: shade, epeter --- src/hotspot/share/opto/vectornode.cpp | 32 ++- .../TestIncorrectVectorReassociation.java | 218 ++++++++++++++++++ 2 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestIncorrectVectorReassociation.java diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 1059bfe20e5..92777f97d7b 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -1168,6 +1168,32 @@ static bool is_commutative_vector_operation(int opcode) { } } +static bool is_associative_and_commutative_vector_operation(int opcode) { + switch (opcode) { + case Op_AddVB: + case Op_AddVS: + case Op_AddVI: + case Op_AddVL: + case Op_MulVB: + case Op_MulVS: + case Op_MulVI: + case Op_MulVL: + case Op_MaxV: + case Op_MinV: + case Op_UMinV: + case Op_UMaxV: + case Op_XorV: + case Op_OrV: + case Op_AndV: + case Op_AndVMask: + case Op_OrVMask: + case Op_XorVMask: + return true; + default: + return false; + } +} + bool VectorNode::should_swap_inputs_to_help_global_value_numbering() { // Predicated vector operations are sensitive to ordering of inputs. // When the mask corresponding to a vector lane is false then @@ -1299,7 +1325,7 @@ Node* VectorNode::create_reassociated_node(Node* parent, Node* child, Node* cinp return cloned_parent; } -// Try to reassociate commutative vector operations using the following ideal transformation, +// Try to reassociate associative vector operations using the following ideal transformation, // this will facilitate strength reducing a vector operation with all replicated inputs to // a scalar operation. // @@ -1312,8 +1338,8 @@ Node* VectorNode::reassociate_vector_operation(PhaseGVN* phase) { return nullptr; } - // Enable re-association for commutative vector operations. - if (!is_commutative_vector_operation(Opcode())) { + // Enable re-association only for associative and commutative vector operations. + if (!is_associative_and_commutative_vector_operation(Opcode())) { return nullptr; } diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestIncorrectVectorReassociation.java b/test/hotspot/jtreg/compiler/vectorapi/TestIncorrectVectorReassociation.java new file mode 100644 index 00000000000..bc94c0b19cc --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestIncorrectVectorReassociation.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.vectorapi; + +import compiler.lib.ir_framework.*; +import compiler.lib.verify.*; +import java.util.Arrays; +import jdk.incubator.vector.*; + +/** + * @test + * @bug 8384507 8385308 + * @library /test/lib / + * @summary Incorrect vector reassociation for signed saturating addition + * @modules jdk.incubator.vector + * + * @run driver compiler.vectorapi.TestIncorrectVectorReassociation + */ + +public class TestIncorrectVectorReassociation { + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); + } + + /* ======================= + * BYTE: a=100, b=100, arr[i]=-50 + * Correct: sat_add(100, sat_add(100, -50)) = sat_add(100, 50) = 127 + * Wrong: sat_add(sat_add(100, 100), -50) = sat_add(127, -50) = 77 + * ======================= */ + + static final VectorSpecies BSP = ByteVector.SPECIES_PREFERRED; + static byte[] byteIn = new byte[BSP.length()]; + static byte[] byteOut = new byte[BSP.length()]; + static final byte BA = 100, BB = 100; + + static { + Arrays.fill(byteIn, (byte) -50); + } + + @Test + @IR(counts = {IRNode.SATURATING_ADD_VB, " 2 "}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}) + static void test_byte_sadd(int index) { + ByteVector.broadcast(BSP, BA) + .lanewise(VectorOperators.SADD, + ByteVector.broadcast(BSP, BB) + .lanewise(VectorOperators.SADD, + ByteVector.fromArray(BSP, byteIn, index))) + .intoArray(byteOut, index); + } + + @Run(test = "test_byte_sadd") + void run_byte_sadd() { + for (int i = 0; i < BSP.loopBound(byteIn.length); i += BSP.length()) { + test_byte_sadd(i); + } + for (int i = 0; i < BSP.loopBound(byteIn.length); i++) { + Verify.checkEQ(byteOut[i], VectorMath.addSaturating(BA, VectorMath.addSaturating(BB, byteIn[i]))); + } + } + + /* ======================= + * SHORT: a=30000, b=30000, arr[i]=-50 + * Correct: sat_add(30000, sat_add(30000, -50)) = sat_add(30000, 29950) = 32767 + * Wrong: sat_add(sat_add(30000, 30000), -50) = sat_add(32767, -50) = 32717 + * ======================= */ + + static final VectorSpecies SSP = ShortVector.SPECIES_PREFERRED; + static short[] shortIn = new short[SSP.length()]; + static short[] shortOut = new short[SSP.length()]; + static final short SA = 30000, SB = 30000; + + static { + Arrays.fill(shortIn, (short) -50); + } + + @Test + @IR(counts = {IRNode.SATURATING_ADD_VS, " 2 "}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}) + static void test_short_sadd(int index) { + ShortVector.broadcast(SSP, SA) + .lanewise(VectorOperators.SADD, + ShortVector.broadcast(SSP, SB) + .lanewise(VectorOperators.SADD, + ShortVector.fromArray(SSP, shortIn, index))) + .intoArray(shortOut, index); + } + + @Run(test = "test_short_sadd") + void run_short_sadd() { + for (int i = 0; i < SSP.loopBound(shortIn.length); i += SSP.length()) { + test_short_sadd(i); + } + for (int i = 0; i < SSP.loopBound(shortIn.length); i++) { + Verify.checkEQ(shortOut[i], VectorMath.addSaturating(SA, VectorMath.addSaturating(SB, shortIn[i]))); + } + } + + /* ======================= + * INT: a=2_000_000_000, b=2_000_000_000, arr[i]=-50 + * Correct: sat_add(2B, sat_add(2B, -50)) = sat_add(2B, 1_999_999_950) = MAX + * Wrong: sat_add(sat_add(2B, 2B), -50) = sat_add(MAX, -50) = MAX-50 + * ======================= */ + + static final VectorSpecies ISP = IntVector.SPECIES_PREFERRED; + static int[] intIn = new int[ISP.length()]; + static int[] intOut = new int[ISP.length()]; + static final int IA = 2_000_000_000, IB = 2_000_000_000; + + static { + Arrays.fill(intIn, -50); + } + + @Test + @IR(counts = {IRNode.SATURATING_ADD_VI, " 2 "}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}) + static void test_int_sadd(int index) { + IntVector.broadcast(ISP, IA) + .lanewise(VectorOperators.SADD, + IntVector.broadcast(ISP, IB) + .lanewise(VectorOperators.SADD, + IntVector.fromArray(ISP, intIn, index))) + .intoArray(intOut, index); + } + + @Run(test = "test_int_sadd") + void run_int_sadd() { + for (int i = 0; i < ISP.loopBound(intIn.length); i += ISP.length()) { + test_int_sadd(i); + } + for (int i = 0; i < ISP.loopBound(intIn.length); i++) { + Verify.checkEQ(intOut[i], VectorMath.addSaturating(IA, VectorMath.addSaturating(IB, intIn[i]))); + } + } + + /* ======================= + * LONG: a=8_000_000_000_000_000_000L, b=8_000_000_000_000_000_000L, arr[i]=-50 + * Correct: sat_add(8e18, sat_add(8e18, -50)) = sat_add(8e18, 7_999_999_999_999_999_950) = MAX + * Wrong: sat_add(sat_add(8e18, 8e18), -50) = sat_add(MAX, -50) = MAX-50 + * ======================= */ + + static final VectorSpecies LSP = LongVector.SPECIES_PREFERRED; + static long[] longIn = new long[LSP.length()]; + static long[] longOut = new long[LSP.length()]; + static final long LA = 8_000_000_000_000_000_000L, LB = 8_000_000_000_000_000_000L; + + static { + Arrays.fill(longIn, -50L); + } + + @Test + @IR(counts = {IRNode.SATURATING_ADD_VL, " 2 "}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}) + static void test_long_sadd(int index) { + LongVector.broadcast(LSP, LA) + .lanewise(VectorOperators.SADD, + LongVector.broadcast(LSP, LB) + .lanewise(VectorOperators.SADD, + LongVector.fromArray(LSP, longIn, index))) + .intoArray(longOut, index); + } + + @Run(test = "test_long_sadd") + void run_long_sadd() { + for (int i = 0; i < LSP.loopBound(longIn.length); i += LSP.length()) { + test_long_sadd(i); + } + for (int i = 0; i < LSP.loopBound(longIn.length); i++) { + Verify.checkEQ(longOut[i], VectorMath.addSaturating(LA, VectorMath.addSaturating(LB, longIn[i]))); + } + } + + @Test + @IR(counts = {IRNode.SATURATING_ADD_VI, " 2 "}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}) + static IntVector test_mixed_sadd_suadd() { + IntVector v0 = IntVector.broadcast(ISP, 1); + IntVector v1 = IntVector.broadcast(ISP, 0); + IntVector v2 = v0.lanewise(VectorOperators.SADD, v1); + return v2.lanewise(VectorOperators.SUADD, -1); + } + + @Run(test = "test_mixed_sadd_suadd") + void run_mixed_sadd_suadd() { + IntVector result = test_mixed_sadd_suadd(); + int expected = VectorMath.addSaturatingUnsigned( + VectorMath.addSaturating(1, 0), -1); + int[] res = result.toArray(); + for (int i = 0; i < res.length; i++) { + Verify.checkEQ(res[i], expected); + } + } +} From 9acd9f8790fafbddb7dd5a25360b589efcc5ebf5 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 1 Jun 2026 11:17:01 +0000 Subject: [PATCH 013/115] 8381965: NullPointerException in TypeAnnotationPositions Reviewed-by: mcimadamore --- .../sun/tools/javac/comp/DeferredAttr.java | 15 ++ .../TypeAnnotationsOnVariables.java | 188 +++++++++++++++++- 2 files changed, 202 insertions(+), 1 deletion(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java index 89422ac4671..c9c2375fab9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java @@ -25,6 +25,7 @@ package com.sun.tools.javac.comp; +import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.LambdaExpressionTree.BodyKind; import com.sun.source.tree.NewClassTree; import com.sun.tools.javac.code.*; @@ -62,6 +63,7 @@ import java.util.function.Predicate; import java.util.function.Supplier; import com.sun.source.tree.MemberReferenceTree; +import com.sun.source.tree.ModifiersTree; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.tree.JCTree.JCMemberReference.OverloadKind; @@ -191,6 +193,19 @@ public class DeferredAttr extends JCTree.Visitor { result.pos = t.pos; return result; } + + @Override + public JCTree visitAnnotatedType(AnnotatedTypeTree node, Void p) { + return copy(((JCAnnotatedType) node).underlyingType, p); + } + + @Override + public JCTree visitModifiers(ModifiersTree node, Void p) { + JCModifiers mods = (JCModifiers) super.visitModifiers(node, p); + + mods.annotations = List.nil(); + return mods; + } }; deferredCopier = new TypeMapping () { @Override diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java index f89e3ff7398..9c61c3f6d4a 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8371155 8379550 8384843 + * @bug 8371155 8379550 8381965 8384843 * @summary Verify type annotations on local-like variables are propagated to * their types at an appropriate time. * @library /tools/lib @@ -559,6 +559,192 @@ public class TypeAnnotationsOnVariables { " Test$TypeAnno"); } + @Test + void explicitLambdaHeader3() throws Exception { + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + tb.writeJavaFiles(src, + """ + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + import java.util.function.Consumer; + import java.util.List; + + class Test { + @Target(ElementType.TYPE_USE) + @interface TypeAnno { } + + static final Consumer> TEST = + id((List<@TypeAnno String> arg1) -> {}); + + private static Consumer id(Consumer t) { return t;} + private void test() { + Object test = + id((List<@TypeAnno String> arg2) -> {}); + } + } + """); + Files.createDirectories(classes); + List actual = new ArrayList<>(); + new JavacTask(tb) + .options("-d", classes.toString()) + .files(tb.findJavaFiles(src)) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + @Override + public Void visitVariable(VariableTree node, Void p) { + actual.add(node.getName() + ": " + typeToString(trees.getTypeMirror(getCurrentPath()))); + return super.visitVariable(node, p); + } + @Override + public Void visitLambdaExpression(LambdaExpressionTree node, Void p) { + actual.add(treeToString(node)+ ": " + typeToString(trees.getTypeMirror(getCurrentPath()))); + return super.visitLambdaExpression(node, p); + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run() + .writeAll(); + + List expected = List.of( + "TEST: java.util.function.Consumer>", + "(List<@TypeAnno String> arg1)->{ }: java.util.function.Consumer>", + "arg1: java.util.List", + "t: java.util.function.Consumer", + "test: java.lang.Object", + "(List<@TypeAnno String> arg2)->{ }: java.util.function.Consumer>", + "arg2: java.util.List" + ); + + actual.forEach(System.out::println); + if (!expected.equals(actual)) { + throw new AssertionError("Expected: " + expected + ", but got: " + actual); + } + + Path testClass = classes.resolve("Test.class"); + TestClassDesc testClassDesc = TestClassDesc.create(testClass); + MethodModel clInit = singletonValue(testClassDesc.name2Method().get("")); + assertEmpty(getAnnotationsFromHeader(clInit)); + assertEmpty(getAnnotationsFromCode(clInit)); + MethodModel test = singletonValue(testClassDesc.name2Method().get("test")); + assertEmpty(getAnnotationsFromHeader(test)); + assertEmpty(getAnnotationsFromCode(test)); + + checkTypeAnnotations(testClassDesc, + "lambda$static$0", + this::getAnnotationsFromHeader, + " 0: LTest$TypeAnno;(): METHOD_FORMAL_PARAMETER, param_index=0, location=[TYPE_ARGUMENT(0)]", + " Test$TypeAnno"); + + checkTypeAnnotations(testClassDesc, + "lambda$test$0", + this::getAnnotationsFromHeader, + " 0: LTest$TypeAnno;(): METHOD_FORMAL_PARAMETER, param_index=0, location=[TYPE_ARGUMENT(0)]", + " Test$TypeAnno"); + } + + @Test + void explicitLambdaHeader4() throws Exception { + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + tb.writeJavaFiles(src, + """ + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + import java.util.function.Consumer; + import java.util.List; + + class Test { + @Target(ElementType.TYPE_USE) + @interface TypeAnno { } + + static final Consumer> TEST = + id((@TypeAnno List arg) -> {}); + + private static Consumer id(Consumer t) { return t;} + private void test() { + Object test = + id((@TypeAnno List arg) -> {}); + } + } + """); + Files.createDirectories(classes); + List actual = new ArrayList<>(); + new JavacTask(tb) + .options("-d", classes.toString()) + .files(tb.findJavaFiles(src)) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + @Override + public Void visitVariable(VariableTree node, Void p) { + actual.add(node.getName() + ": " + typeToString(trees.getTypeMirror(getCurrentPath()))); + return super.visitVariable(node, p); + } + @Override + public Void visitLambdaExpression(LambdaExpressionTree node, Void p) { + actual.add(treeToString(node)+ ": " + typeToString(trees.getTypeMirror(getCurrentPath()))); + return super.visitLambdaExpression(node, p); + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run() + .writeAll(); + + List expected = List.of( + "TEST: java.util.function.Consumer>", + "(@TypeAnno List arg)->{ }: java.util.function.Consumer>", + "arg: java.util.@Test.TypeAnno List", + "t: java.util.function.Consumer", + "test: java.lang.Object", + "(@TypeAnno List arg)->{ }: java.util.function.Consumer>", + "arg: java.util.@Test.TypeAnno List" + ); + + actual.forEach(System.out::println); + if (!expected.equals(actual)) { + throw new AssertionError("Expected: " + expected + ", but got: " + actual); + } + + Path testClass = classes.resolve("Test.class"); + TestClassDesc testClassDesc = TestClassDesc.create(testClass); + MethodModel clInit = singletonValue(testClassDesc.name2Method().get("")); + assertEmpty(getAnnotationsFromHeader(clInit)); + assertEmpty(getAnnotationsFromCode(clInit)); + MethodModel test = singletonValue(testClassDesc.name2Method().get("test")); + assertEmpty(getAnnotationsFromHeader(test)); + assertEmpty(getAnnotationsFromCode(test)); + + checkTypeAnnotations(testClassDesc, + "lambda$static$0", + this::getAnnotationsFromHeader, + " 0: LTest$TypeAnno;(): METHOD_FORMAL_PARAMETER, param_index=0", + " Test$TypeAnno"); + + checkTypeAnnotations(testClassDesc, + "lambda$test$0", + this::getAnnotationsFromHeader, + " 0: LTest$TypeAnno;(): METHOD_FORMAL_PARAMETER, param_index=0", + " Test$TypeAnno"); + } + private void checkTypeAnnotations(TestClassDesc testClassDesc, String lambdaMethodName, String... expectedEntries) throws IOException { From 64d6cbad08372801b7999810fa14a515954d6d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Mon, 1 Jun 2026 13:53:03 +0000 Subject: [PATCH 014/115] 8385632: ZGC: Incorrect object undo in relocation race for relocation workers Reviewed-by: stefank, aboldtch, tschatzl --- src/hotspot/share/gc/z/zRelocate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 1c2a4078904..d69475e62a3 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -642,7 +642,7 @@ private: const zaddress to_addr = _forwarding->insert(from_addr, allocated_addr, &cursor); if (to_addr != allocated_addr) { // Already relocated, undo allocation - _allocator->undo_alloc_object(to_page, to_addr, size); + _allocator->undo_alloc_object(to_page, allocated_addr, size); increase_other_forwarded(size); } From 886eb11c645b52ec0af9024d5d2c94fe8d3ceea7 Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Mon, 1 Jun 2026 16:24:26 +0000 Subject: [PATCH 015/115] 8385409: Javap documentation says by default protected and public members are printed but package private members are also printed by default (`-package` behavior, not `-protected`) Reviewed-by: liach --- src/jdk.jdeps/share/man/javap.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jdk.jdeps/share/man/javap.md b/src/jdk.jdeps/share/man/javap.md index d09ac57f196..0e11176aa10 100644 --- a/src/jdk.jdeps/share/man/javap.md +++ b/src/jdk.jdeps/share/man/javap.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1994, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,8 @@ javap - disassemble one or more class files The `javap` command disassembles one or more class files. The output depends on the options used. When no options are used, the `javap` command prints the -protected and public fields, and methods of the classes passed to it. +package private, protected, and public fields and methods declared in the classes passed +to it. The `javap` command isn't multirelease JAR aware. Using the class path form of the command results in viewing the base entry in all JAR files, multirelease or From d60fead5cf5679c52069006f474e3437b76a0afb Mon Sep 17 00:00:00 2001 From: Rui Li Date: Mon, 1 Jun 2026 17:11:05 +0000 Subject: [PATCH 016/115] 8384604: Shenandoah: Completed GC count doesn't add up in the log Reviewed-by: wkemper, xpeng, kdnilsen --- .../share/gc/shenandoah/shenandoahCollectorPolicy.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp index cfa79fc055e..e3267517e05 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp @@ -205,8 +205,15 @@ void ShenandoahCollectorPolicy::print_gc_stats(outputStream* out) const { out->print_cr("enough regions with no live objects to skip evacuation."); out->cr(); + size_t gc_attempts = 0; + for (int c = 0; c < GCCause::_last_gc_cause; c++) { + gc_attempts += _collection_cause_counts[c]; + } + size_t completed_gcs = _success_full_gcs + _success_degenerated_gcs + _success_concurrent_gcs + _success_old_gcs; - out->print_cr("%5zu Completed GCs", completed_gcs); + size_t cancelled_gcs = gc_attempts - completed_gcs; + out->print_cr("%5zu GC attempts. %zu Completed GCs (%.2f%%).", + gc_attempts, completed_gcs, percent_of(completed_gcs, gc_attempts)); size_t explicit_requests = 0; size_t implicit_requests = 0; @@ -220,7 +227,7 @@ void ShenandoahCollectorPolicy::print_gc_stats(outputStream* out) const { implicit_requests += cause_count; } const char* desc = GCCause::to_string(cause); - out->print_cr(" %5zu caused by %s (%.2f%%)", cause_count, desc, percent_of(cause_count, completed_gcs)); + out->print_cr(" %5zu caused by %s (%.2f%%)", cause_count, desc, percent_of(cause_count, gc_attempts)); } } From b2bf91bf1289af4d664261b865dacf0808638995 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Mon, 1 Jun 2026 17:36:17 +0000 Subject: [PATCH 017/115] 8376621: Should not suspend thread in start_transition if _is_disable_suspend set Reviewed-by: dholmes, sspitsyn --- src/hotspot/share/runtime/continuation.cpp | 3 +- src/hotspot/share/runtime/javaThread.hpp | 2 +- .../share/runtime/mountUnmountDisabler.cpp | 2 +- .../SuspendResume4/SuspendResume4.java | 109 ++++++++++++++++++ .../SuspendResume4/libSuspendResume4.cpp | 74 ++++++++++++ 5 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume4/SuspendResume4.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume4/libSuspendResume4.cpp diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index 0b7e64a3ba6..26d865057e6 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -87,7 +87,8 @@ class UnmountBeginMark : public StackObj { } ~UnmountBeginMark() { assert(!_current->is_suspended() - JVMTI_ONLY(|| (_current->is_vthread_transition_disabler() && _result != freeze_ok)), "must be"); + JVMTI_ONLY(|| (_result != freeze_ok && + (_current->is_vthread_transition_disabler() || _current->is_disable_suspend()))), "must be"); assert(_current->is_in_vthread_transition(), "must be"); if (_result != freeze_ok) { diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 08d3cde8562..9e3c629ad78 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -873,7 +873,7 @@ public: // Atomic version; invoked by a thread other than the owning thread. bool in_critical_atomic() { return AtomicAccess::load(&_jni_active_critical) > 0; } - bool jni_deferred_suspension() { return AtomicAccess::load(&_jni_deferred_suspension_count); } + bool jni_deferred_suspension() const { return AtomicAccess::load(&_jni_deferred_suspension_count); } inline void enter_jni_deferred_suspension(); void exit_jni_deferred_suspension() { precond(Thread::current() == this); diff --git a/src/hotspot/share/runtime/mountUnmountDisabler.cpp b/src/hotspot/share/runtime/mountUnmountDisabler.cpp index 65a82d6c563..277a841a88c 100644 --- a/src/hotspot/share/runtime/mountUnmountDisabler.cpp +++ b/src/hotspot/share/runtime/mountUnmountDisabler.cpp @@ -129,7 +129,7 @@ bool MountUnmountDisabler::is_start_transition_disabled(JavaThread* thread, oop int base_disable_count = notify_jvmti_events() ? 1 : 0; return java_lang_Thread::vthread_transition_disable_count(vthread) > 0 || global_vthread_transition_disable_count() > base_disable_count - JVMTI_ONLY(|| (!thread->is_vthread_transition_disabler() && + JVMTI_ONLY(|| (!thread->is_vthread_transition_disabler() && !thread->is_disable_suspend() && (JvmtiVTSuspender::is_vthread_suspended(java_lang_Thread::thread_id(vthread)) || thread->is_suspended()))); } diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume4/SuspendResume4.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume4/SuspendResume4.java new file mode 100644 index 00000000000..db2eff4c1b5 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume4/SuspendResume4.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8376621 + * @summary Suspend virtual thread while it's inside disableSuspendAndPreempt region + * @requires vm.continuations + * @requires vm.jvmti + * @library /test/lib /test/hotspot/jtreg/testlibrary + * @run main/othervm SuspendResume4 + */ + +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.File; + +import jvmti.JVMTIUtils; + +public class SuspendResume4 { + native static void suspendThread(Thread thread); + native static void resumeThread(Thread thread); + + public static void main(String[] args) throws Exception { + // Run test in child VM where Locale won't be initialized already by jtreg + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-Djava.library.path=" + Utils.TEST_NATIVE_PATH, + "-agentpath:" + Utils.TEST_NATIVE_PATH + File.separator + System.mapLibraryName("SuspendResume4"), + "SuspendResume4$Test"); + OutputAnalyzer output = ProcessTools.executeProcess(pb); + System.out.println(output.getStdout()); + output.shouldHaveExitValue(0); + } + + static class Test{ + static String targetName; + + private void runTest() throws Exception { + // start target vthread + Thread target = Thread.ofVirtual().name("target").start(() -> { + // Give time for reader to get suspended in + // disableSuspendAndPreempt region. + spinWaitMillis(100); + // Force unmounting. If reader was suspended inside + // disableSuspendAndPreempt region this will block + // in VirtualThread.unmount. + Thread.yield(); + }); + + // start clinit contender + Thread contender = Thread.ofPlatform().name("contender").start(() -> { + "JAVA".toLowerCase(java.util.Locale.ROOT); + }); + + // start vthread that reads target's state + Thread reader = Thread.ofVirtual().name("reader").start(() -> { + targetName = "name: " + target; + }); + + // start suspend/resumer + Thread suspender = Thread.ofPlatform().name("suspender").start(() -> { + SuspendResume4.suspendThread(reader); + // Give target time for Thread.yield + spinWaitMillis(100); + SuspendResume4.resumeThread(reader); + }); + + target.join(); + contender.join(); + suspender.join(); + reader.join(); + } + + public static void main(String[] args) throws Exception { + Test obj = new Test(); + obj.runTest(); + } + + static void spinWaitMillis(long millis) { + long durationNanos = millis * 1_000_000L; + long start = System.nanoTime(); + while (System.nanoTime() - start < durationNanos) { + Thread.onSpinWait(); + } + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume4/libSuspendResume4.cpp b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume4/libSuspendResume4.cpp new file mode 100644 index 00000000000..38e90889b7a --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendResume4/libSuspendResume4.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include "jvmti_common.hpp" + +// set by Agent_OnLoad +static jvmtiEnv* jvmti = nullptr; + +extern "C" { + +JNIEXPORT void JNICALL +Java_SuspendResume4_suspendThread(JNIEnv* jni, jclass klass, jthread thread) { + jvmtiError err = jvmti->SuspendThread(thread); + if (err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_THREAD_NOT_ALIVE) { + jni->FatalError("error in JVMTI SuspendThread"); + } +} + +JNIEXPORT void JNICALL +Java_SuspendResume4_resumeThread(JNIEnv* jni, jclass klass, jthread thread) { + jvmtiError err = jvmti->ResumeThread(thread); + if (err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_THREAD_NOT_ALIVE) { + jni->FatalError("error in JVMTI ResumeThread"); + } +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM* jvm, char* options, void* reserved) { + jvmtiCapabilities caps; + jvmtiError err; + + printf("Agent_OnLoad: started\n"); + if (jvm->GetEnv((void **) (&jvmti), JVMTI_VERSION) != JNI_OK) { + LOG("Agent_OnLoad: error in GetEnv"); + return JNI_ERR; + } + + memset(&caps, 0, sizeof(caps)); + caps.can_suspend = 1; + err = jvmti->AddCapabilities(&caps); + if (err != JVMTI_ERROR_NONE) { + LOG("Agent_OnLoad: error in JVMTI AddCapabilities: %d\n", err); + } + + printf("Agent_OnLoad: finished\n"); + + return 0; +} + +} // extern "C" From a23ce9cd30305e7d7339c7f74e1084ea20e345ca Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 1 Jun 2026 17:48:51 +0000 Subject: [PATCH 018/115] 8379535: test/jdk/java/io/File/ListRoots.java fails with RuntimeException: Does not match FileSystem::getRootDirectories Reviewed-by: alanb --- test/jdk/java/io/File/ListRoots.java | 66 +++++++++++++++++++--------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/test/jdk/java/io/File/ListRoots.java b/test/jdk/java/io/File/ListRoots.java index 7b14b2f3b08..d8717b0246a 100644 --- a/test/jdk/java/io/File/ListRoots.java +++ b/test/jdk/java/io/File/ListRoots.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,11 @@ /* @test @bug 4071322 @summary Basic test for File.listRoots method + @run junit ListRoots */ import java.io.File; +import java.io.IOException; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Path; @@ -35,33 +37,57 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class ListRoots { - public static void main(String[] args) throws Exception { + private static Set expectedSet; + private static Set actualSet; + + @BeforeAll + public static void init() throws IOException { File[] rs = File.listRoots(); for (int i = 0; i < rs.length; i++) { - System.out.println(i + ": " + rs[i]); - } - - File f = new File(System.getProperty("test.src", "."), "ListRoots.java"); - String cp = f.getCanonicalPath(); - boolean found = Stream.of(rs) - .map(File::getPath) - .anyMatch(p -> cp.startsWith(p)); - if (!found) { - throw new RuntimeException(cp + " does not have a recognized root"); + System.err.println(i + ": " + rs[i]); } // the list of roots should match FileSystem::getRootDirectories - Set roots1 = Stream.of(rs).collect(Collectors.toSet()); FileSystem fs = FileSystems.getDefault(); - Set roots2 = StreamSupport.stream(fs.getRootDirectories().spliterator(), false) - .map(Path::toFile) - .collect(Collectors.toSet()); - if (!roots1.equals(roots2)) { - System.out.println(roots2); - throw new RuntimeException("Does not match FileSystem::getRootDirectories"); - } + expectedSet = + StreamSupport.stream(fs.getRootDirectories().spliterator(), false) + .map(Path::toFile) + .collect(Collectors.toSet()); + actualSet = Stream.of(rs).collect(Collectors.toSet()); } + @Test + public void checkRoot() throws IOException { + File f = new File(System.getProperty("user.dir")); + String cp = f.getCanonicalPath(); + boolean found = Stream.of(File.listRoots()) + .map(File::getPath) + .anyMatch(p -> cp.startsWith(p)); + assertTrue(found, cp + " does not have a recognized root"); + } + + @Test + @DisabledOnOs(OS.WINDOWS) + public void listRootsUnix() throws IOException { + assertEquals(expectedSet, actualSet, + "Does not equal FileSystem::getRootDirectories"); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + public void listRootsWindows() throws IOException { + assertTrue(expectedSet.stream().anyMatch(actualSet::contains), + "Does not intersect FileSystem::getRootDirectories"); + } } From 045ae965e122a1e867f5aa0e7e9813cb0967693e Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 1 Jun 2026 18:04:17 +0000 Subject: [PATCH 019/115] 8384221: GenShen: WhiteBox full GC promotion is not reliable Reviewed-by: wkemper, ysr --- .../shenandoahGenerationalHeuristics.cpp | 12 +++++++- .../shenandoahGenerationalHeuristics.hpp | 2 +- .../heuristics/shenandoahGlobalHeuristics.cpp | 6 ++++ .../gc/shenandoah/shenandoahAgeCensus.cpp | 2 +- .../gc/shenandoah/shenandoahAgeCensus.hpp | 28 ++++++++++--------- .../shenandoahGenerationalControlThread.cpp | 2 +- .../share/gc/shenandoah/shenandoahPLAB.cpp | 2 +- 7 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index c880af7fd49..ca4dfc71c61 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -358,7 +358,7 @@ size_t ShenandoahGenerationalHeuristics::select_aged_regions(ShenandoahInPlacePr // Having chosen the collection set, adjust the budgets for generational mode based on its composition. Note // that young_generation->available() now knows about recently discovered immediate garbage. -void ShenandoahGenerationalHeuristics::adjust_evacuation_budgets(ShenandoahHeap* const heap, +void ShenandoahGenerationalHeuristics::adjust_evacuation_budgets(ShenandoahGenerationalHeap* const heap, ShenandoahCollectionSet* const collection_set) { shenandoah_assert_generational(); // We may find that old_evacuation_reserve and/or loaned_for_young_evacuation are not fully consumed, in which case we may @@ -481,6 +481,16 @@ void ShenandoahGenerationalHeuristics::adjust_evacuation_budgets(ShenandoahHeap* if (add_regions_to_young > 0) { assert(excess_old >= add_regions_to_young * region_size_bytes, "Cannot xfer more than excess old"); + if (heap->age_census()->is_always_tenure()) { + // Cap excess_old at one min-PLAB per worker so this much stays in old's promotion reserve + // instead of being transferred to young. + const size_t min_plab_total = heap->plab_min_size() * HeapWordSize * heap->workers()->max_workers(); + if (excess_old > min_plab_total) { + excess_old = min_plab_total; + // Avoid underflowing excess_old when we subtract below. + add_regions_to_young = 0; + } + } excess_old -= add_regions_to_young * region_size_bytes; log_debug(gc, ergo)("Before start of evacuation, total_promotion reserve is young_advance_promoted_reserve: %zu " "plus excess: old: %zu", young_advance_promoted_reserve_used, excess_old); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp index a0e4ab78d5c..1860e3d4c0f 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp @@ -92,7 +92,7 @@ private: // Adjust evacuation budgets after choosing collection set. On entry, the instance variable _regions_to_xfer // represents regions to be transferred to old based on decisions made in top_off_collection_set() - void adjust_evacuation_budgets(ShenandoahHeap* const heap, + void adjust_evacuation_budgets(ShenandoahGenerationalHeap* const heap, ShenandoahCollectionSet* const collection_set); protected: diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp index e4ac576aa6f..d9f3bdee828 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp @@ -179,6 +179,12 @@ void ShenandoahGlobalHeuristics::choose_global_collection_set(ShenandoahCollecti size_t free_target = (capacity * ShenandoahMinFreeThreshold) / 100 + original_young_evac_reserve; size_t min_garbage = (free_target > actual_free) ? (free_target - actual_free) : 0; + // Admit every region with any garbage so every live object gets a chance to be promoted. + if (heap->age_census()->is_always_tenure()) { + ignore_threshold = 0; + min_garbage = SIZE_MAX; + } + ShenandoahGlobalCSetBudget budget(region_size_bytes, shared_reserve_regions * region_size_bytes, garbage_threshold, ignore_threshold, min_garbage, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index 4989c929b32..8fa497802fd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -34,7 +34,7 @@ ShenandoahAgeCensus::ShenandoahAgeCensus() } ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers) - : _max_workers(max_workers) + : _max_workers(max_workers), _always_tenure(false) { if (ShenandoahGenerationalMinTenuringAge > ShenandoahGenerationalMaxTenuringAge) { vm_exit_during_initialization( diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index c140f445e21..5636dee3ae2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -121,6 +121,8 @@ class ShenandoahAgeCensus: public CHeapObj { uint _max_workers; // Maximum number of workers for parallel tasks + bool _always_tenure; // When true, every age is tenurable. + // Mortality rate of a cohort, given its population in // previous and current epochs double mortality_rate(size_t prev_pop, size_t cur_pop); @@ -150,9 +152,9 @@ class ShenandoahAgeCensus: public CHeapObj { return _tenuring_threshold[prev]; } - // Override the tenuring threshold for the current epoch. This is used to - // cause everything to be promoted for a whitebox full gc request. - void set_tenuring_threshold(uint threshold) { _tenuring_threshold[_epoch] = threshold; } + // Set always tenure mode. Currently only used by ShenandoahTenuringOverride + // to force is_tenurable() to be true for every age during WB.fullGC tests. + void set_always_tenure(bool always_tenure) { _always_tenure = always_tenure; } #ifndef PRODUCT // Return the sum of size of objects of all ages recorded in the @@ -187,11 +189,13 @@ class ShenandoahAgeCensus: public CHeapObj { // Visible for testing. Use is_tenurable for consistent tenuring comparisons. uint tenuring_threshold() const { return _tenuring_threshold[_epoch]; } - // Return true if this age is at or above the tenuring threshold. + // Return true if this age is at or above the tenuring threshold, or if always tenure is enabled. bool is_tenurable(uint age) const { - return age >= tenuring_threshold(); + return age >= tenuring_threshold() || _always_tenure; } + bool is_always_tenure() const { return _always_tenure; } + // Update the local age table for worker_id by size for // given obj_age, region_age, and region_youth CENSUS_NOISE(void add(uint obj_age, uint region_age, uint region_youth, size_t size, uint worker_id);) @@ -244,24 +248,22 @@ class ShenandoahAgeCensus: public CHeapObj { void print(); }; -// RAII object that temporarily overrides the tenuring threshold for the -// duration of a scope, restoring the original value on destruction. -// Used to force promotion of all young objects during whitebox full GCs. +// RAII object that enables ShenandoahAgeCensus always tenure mode for the +// duration of a scope and disables it on destruction. Used to force promotion +// of all young objects during whitebox full GCs. class ShenandoahTenuringOverride : public StackObj { ShenandoahAgeCensus* _census; - uint _saved_threshold; bool _active; public: ShenandoahTenuringOverride(bool active, ShenandoahAgeCensus* census) : - _census(census), _saved_threshold(0), _active(active) { + _census(census), _active(active) { if (_active) { - _saved_threshold = _census->tenuring_threshold(); - _census->set_tenuring_threshold(0); + _census->set_always_tenure(true); } } ~ShenandoahTenuringOverride() { if (_active) { - _census->set_tenuring_threshold(_saved_threshold); + _census->set_always_tenure(false); } } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index b3a48f85114..94f3409ac41 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -269,7 +269,7 @@ void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest // Cannot uncommit bitmap slices during concurrent reset ShenandoahNoUncommitMark forbid_region_uncommit(_heap); - // When a whitebox full GC is requested, set the tenuring threshold to zero + // When a whitebox full GC is requested, set the age census to always tenure // so that all young objects are promoted to old. This ensures that tests // using WB.fullGC() to promote objects to old gen will not loop forever. ShenandoahTenuringOverride tenuring_override(request.cause == GCCause::_wb_full_gc, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp index 3d98d431b86..f139f94fc8b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp @@ -39,7 +39,7 @@ ShenandoahPLAB::ShenandoahPLAB() : _promoted(0), _promotion_failure_count(0), _promotion_failure_words(0), - _allows_promotion(false), + _allows_promotion(true), _retries_enabled(false), _heap(ShenandoahGenerationalHeap::heap()) { _plab = new PLAB(PLAB::min_size()); From 70c92d6c2bce373067b6a8df72f194b6f9d08259 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Mon, 1 Jun 2026 18:37:35 +0000 Subject: [PATCH 020/115] 8382275: Update nsk/stress/jni to use ThreadWrapper Reviewed-by: lmesnik, syan --- .../vmTestbase/nsk/stress/jni/GarbageGenerator.java | 5 +++-- .../vmTestbase/nsk/stress/jni/jnistress001.java | 12 ++++++++---- .../vmTestbase/nsk/stress/jni/jnistress002.java | 12 ++++++++---- .../vmTestbase/nsk/stress/jni/jnistress003.java | 12 ++++++++---- .../vmTestbase/nsk/stress/jni/jnistress004.java | 12 ++++++++---- .../vmTestbase/nsk/stress/jni/jnistress005.java | 12 ++++++++---- .../vmTestbase/nsk/stress/jni/jnistress006.java | 12 ++++++++---- .../vmTestbase/nsk/stress/jni/jnistress007.java | 12 ++++++++---- 8 files changed, 59 insertions(+), 30 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/GarbageGenerator.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/GarbageGenerator.java index bb9c9afa394..bc3ada61136 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/GarbageGenerator.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/GarbageGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,9 @@ */ package nsk.stress.jni; +import jdk.test.lib.thread.ThreadWrapper; -class GarbageGenerator extends Thread { +class GarbageGenerator extends ThreadWrapper { class Garbage { Garbage() { this(1024); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress001.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress001.java index 0335942e775..16ccaa310a7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,8 +61,9 @@ package nsk.stress.jni; import nsk.share.Consts; import nsk.share.Debug; import nsk.share.test.StressOptions; +import jdk.test.lib.thread.ThreadWrapper; -public class jnistress001 extends Thread { +public class jnistress001 extends ThreadWrapper { /* Maximum number of iterations. Ignored if <= 0L */ static long numIteration = 0L; @@ -256,8 +257,11 @@ public class jnistress001 extends Thread { garb = new GarbageGenerator[nGarb]; for (i = 0; i < nJNI; i++) jniter[i] = new JNIter001(sync); + Thread[] jniterThreads = new Thread[nJNI]; + for (i = 0; i < nJNI; i++) + jniterThreads[i] = jniter[i].getThread(); for (i = 0; i < nInter; i++) { - irupt[i] = new Interrupter(jniter, sync); + irupt[i] = new Interrupter(jniterThreads, sync); irupt[i].setInterval(iruptInterval); } for (i = 0; i < nGarb; i++) { @@ -372,7 +376,7 @@ public class jnistress001 extends Thread { final private static boolean DEBUG = false; } -class JNIter001 extends Thread { +class JNIter001 extends ThreadWrapper { // The native method for testing JNI UTF-8 calls public native String jnistress(String threadName, int nstr, int printPeriod); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress002.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress002.java index 1a9e2999f20..5b6912b623d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,12 +60,13 @@ package nsk.stress.jni; import nsk.share.Consts; import nsk.share.Debug; import nsk.share.test.StressOptions; +import jdk.test.lib.thread.ThreadWrapper; import jdk.test.lib.Utils; import java.lang.reflect.Field; import java.util.Random; -public class jnistress002 extends Thread { +public class jnistress002 extends ThreadWrapper { /* Maximum number of iterations. Ignored if <= 0L */ static long numIteration = 0L; @@ -246,8 +247,11 @@ public class jnistress002 extends Thread { garb = new GarbageGenerator[nGarb]; for (i = 0; i < nJNI; i++) jniter[i] = new JNIter002(sync); + Thread[] jniterThreads = new Thread[nJNI]; + for (i = 0; i < nJNI; i++) + jniterThreads[i] = jniter[i].getThread(); for (i = 0; i < nInter; i++) { - irupt[i] = new Interrupter(jniter, sync); + irupt[i] = new Interrupter(jniterThreads, sync); irupt[i].setInterval(iruptInterval); } for (i = 0; i < nGarb; i++) { @@ -423,7 +427,7 @@ class objectsJNI { } } -class JNIter002 extends Thread { +class JNIter002 extends ThreadWrapper { // The native method for testing JNI Object's calls public native objectsJNI[] jniobjects(String s, int i, long l, diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress003.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress003.java index e06f2e6279f..b1e2702011a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,10 +60,11 @@ package nsk.stress.jni; import nsk.share.Consts; import nsk.share.Debug; import nsk.share.test.StressOptions; +import jdk.test.lib.thread.ThreadWrapper; import java.lang.reflect.Array; -public class jnistress003 extends Thread { +public class jnistress003 extends ThreadWrapper { /* Maximum number of iterations. Ignored if <= 0L */ static long numIteration = 0L; @@ -257,8 +258,11 @@ public class jnistress003 extends Thread { garb = new GarbageGenerator[nGarb]; for (i = 0; i < nJNI; i++) jniter[i] = new JNIter003(sync); + Thread[] jniterThreads = new Thread[nJNI]; + for (i = 0; i < nJNI; i++) + jniterThreads[i] = jniter[i].getThread(); for (i = 0; i < nInter; i++) { - irupt[i] = new Interrupter(jniter, sync); + irupt[i] = new Interrupter(jniterThreads, sync); irupt[i].setInterval(iruptInterval); } for (i = 0; i < nGarb; i++) { @@ -379,7 +383,7 @@ public class jnistress003 extends Thread { final private static boolean DEBUG = false; } -class JNIter003 extends Thread { +class JNIter003 extends ThreadWrapper { // The native methods for testing JNI Arrays calls diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress004.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress004.java index 6432b0ccc3c..705ddd8a5f1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,8 +60,9 @@ package nsk.stress.jni; import nsk.share.Consts; import nsk.share.Debug; import nsk.share.test.StressOptions; +import jdk.test.lib.thread.ThreadWrapper; -public class jnistress004 extends Thread { +public class jnistress004 extends ThreadWrapper { /* Maximum number of iterations. Ignored if <= 0L */ static long numIteration = 2L; @@ -243,8 +244,11 @@ public class jnistress004 extends Thread { garb = new GarbageGenerator[nGarb]; for (i = 0; i < nJNI; i++) jniter[i] = new JNIter004(sync); + Thread[] jniterThreads = new Thread[nJNI]; + for (i = 0; i < nJNI; i++) + jniterThreads[i] = jniter[i].getThread(); for (i = 0; i < nInter; i++) { - irupt[i] = new Interrupter(jniter, sync); + irupt[i] = new Interrupter(jniterThreads, sync); irupt[i].setInterval(iruptInterval); } for (i = 0; i < nGarb; i++) { @@ -364,7 +368,7 @@ public class jnistress004 extends Thread { final private static boolean DEBUG = false; } -class JNIter004 extends Thread { +class JNIter004 extends ThreadWrapper { // The native methods for testing JNI critical calls public native char[] CheckSum(String str); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress005.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress005.java index a841635462b..0144c116f1e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,8 +61,9 @@ package nsk.stress.jni; import nsk.share.Consts; import nsk.share.Debug; import nsk.share.test.StressOptions; +import jdk.test.lib.thread.ThreadWrapper; -public class jnistress005 extends Thread { +public class jnistress005 extends ThreadWrapper { /* Maximum number of iterations. Ignored if <= 0L */ static long numIteration = 0L; @@ -244,8 +245,11 @@ public class jnistress005 extends Thread { garb = new GarbageGenerator[nGarb]; for (i = 0; i < nJNI; i++) jniter[i] = new JNIter005(sync); + Thread[] jniterThreads = new Thread[nJNI]; + for (i = 0; i < nJNI; i++) + jniterThreads[i] = jniter[i].getThread(); for (i = 0; i < nInter; i++) { - irupt[i] = new Interrupter(jniter, sync); + irupt[i] = new Interrupter(jniterThreads, sync); irupt[i].setInterval(iruptInterval); } for (i = 0; i < nGarb; i++) { @@ -366,7 +370,7 @@ public class jnistress005 extends Thread { final private static boolean DEBUG = false; } -class JNIter005 extends Thread { +class JNIter005 extends ThreadWrapper { // The native methods for testing JNI exception calls public native void except(Throwable tobj); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress006.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress006.java index b6646bb45d4..80178bdef28 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,8 +61,9 @@ package nsk.stress.jni; import nsk.share.Consts; import nsk.share.Debug; import nsk.share.test.StressOptions; +import jdk.test.lib.thread.ThreadWrapper; -public class jnistress006 extends Thread { +public class jnistress006 extends ThreadWrapper { /* Maximum number of iterations. Ignored if <= 0L */ static long numIteration = 0L; @@ -245,8 +246,11 @@ public class jnistress006 extends Thread { garb = new GarbageGenerator[nGarb]; for (i = 0; i < nJNI; i++) jniter[i] = new JNIter006(sync); + Thread[] jniterThreads = new Thread[nJNI]; + for (i = 0; i < nJNI; i++) + jniterThreads[i] = jniter[i].getThread(); for (i = 0; i < nInter; i++) { - irupt[i] = new Interrupter(jniter, sync); + irupt[i] = new Interrupter(jniterThreads, sync); irupt[i].setInterval(iruptInterval); } for (i = 0; i < nGarb; i++) { @@ -366,7 +370,7 @@ public class jnistress006 extends Thread { final private static boolean DEBUG = false; } -class JNIter006 extends Thread { +class JNIter006 extends ThreadWrapper { // The native methods for testing JNI exception calls public native boolean refs(Object tobj, int jniStringAllocSize); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress007.java b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress007.java index 7497660c9e0..727560fae30 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/jnistress007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,8 +61,9 @@ package nsk.stress.jni; import nsk.share.Consts; import nsk.share.Debug; import nsk.share.test.StressOptions; +import jdk.test.lib.thread.ThreadWrapper; -public class jnistress007 extends Thread { +public class jnistress007 extends ThreadWrapper { /* Maximum number of iterations. Ignored if <= 0L */ static long numIteration = 0L; @@ -244,8 +245,11 @@ public class jnistress007 extends Thread { garb = new GarbageGenerator[nGarb]; for (i = 0; i < nJNI; i++) jniter[i] = new JNIter007(sync); + Thread[] jniterThreads = new Thread[nJNI]; + for (i = 0; i < nJNI; i++) + jniterThreads[i] = jniter[i].getThread(); for (i = 0; i < nInter; i++) { - irupt[i] = new Interrupter(jniter, sync); + irupt[i] = new Interrupter(jniterThreads, sync); irupt[i].setInterval(iruptInterval); } for (i = 0; i < nGarb; i++) { @@ -364,7 +368,7 @@ public class jnistress007 extends Thread { final private static boolean DEBUG = false; } -class JNIter007 extends Thread { +class JNIter007 extends ThreadWrapper { // The native methods for testing JNI monitors calls public native void incCount(String name); From f640edebf0074f231c1c0a24273536738eb18e28 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Tue, 2 Jun 2026 00:04:01 +0000 Subject: [PATCH 021/115] 8341382: EXCEPTION_ACCESS_VIOLATION in awt.dll after JDK-8185862 Reviewed-by: kizune, prr, vdyakov --- .../windows/native/libawt/windows/Devices.cpp | 144 ++++++++++++------ .../windows/native/libawt/windows/Devices.h | 7 +- .../native/libawt/windows/awt_Toolkit.cpp | 104 +++++++++++-- .../windows/awt_Win32GraphicsDevice.cpp | 70 +++++++-- .../libawt/windows/awt_Win32GraphicsDevice.h | 4 +- .../libawt/windows/awt_Win32GraphicsEnv.cpp | 12 +- 6 files changed, 260 insertions(+), 81 deletions(-) diff --git a/src/java.desktop/windows/native/libawt/windows/Devices.cpp b/src/java.desktop/windows/native/libawt/windows/Devices.cpp index 8096b1084a2..7192f65425b 100644 --- a/src/java.desktop/windows/native/libawt/windows/Devices.cpp +++ b/src/java.desktop/windows/native/libawt/windows/Devices.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,47 +117,78 @@ static BOOL IsValidMonitor(HMONITOR hMon) return TRUE; } -// Callback for CountMonitors below -static BOOL WINAPI clb_fCountMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorCounter) -{ - if (IsValidMonitor(hMon)) { - (*((int *)lpMonitorCounter))++; - } - - return TRUE; -} - -int WINAPI CountMonitors(void) -{ - int monitorCounter = 0; - ::EnumDisplayMonitors(NULL, NULL, clb_fCountMonitors, (LPARAM)&monitorCounter); - return monitorCounter; -} // Callback for CollectMonitors below static BOOL WINAPI clb_fCollectMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorData) { MonitorData* pMonitorData = (MonitorData *)lpMonitorData; - if ((pMonitorData->monitorCounter < pMonitorData->monitorLimit) && (IsValidMonitor(hMon))) { - pMonitorData->hmpMonitors[pMonitorData->monitorCounter] = hMon; - pMonitorData->monitorCounter++; + + if (!IsValidMonitor(hMon)) { + return TRUE; } + if (pMonitorData->monitorCounter == pMonitorData->monitorLimit) { + TRY; + + int newMonitorLimit = pMonitorData->monitorLimit * 2; + HMONITOR* newMonitors = + (HMONITOR*)SAFE_SIZE_ARRAY_REALLOC( + safe_Realloc, pMonitorData->hmpMonitors, + newMonitorLimit, sizeof(HMONITOR) + ); + pMonitorData->hmpMonitors = newMonitors; + pMonitorData->monitorLimit = newMonitorLimit; + + CATCH_BAD_ALLOC_RET(FALSE); + } + + pMonitorData->hmpMonitors[pMonitorData->monitorCounter] = hMon; + pMonitorData->monitorCounter++; + return TRUE; } -static int WINAPI CollectMonitors(HMONITOR* hmpMonitors, int nNum) +static HMONITOR* CollectMonitors(int* numScreens) { - if (NULL != hmpMonitors) { - MonitorData monitorData; - monitorData.monitorCounter = 0; - monitorData.monitorLimit = nNum; - monitorData.hmpMonitors = hmpMonitors; - ::EnumDisplayMonitors(NULL, NULL, clb_fCollectMonitors, (LPARAM)&monitorData); - return monitorData.monitorCounter; - } else { - return 0; + const int initialMonitorLimit = 4; + + *numScreens = 0; + + MonitorData data; + data.monitorCounter = 0; + data.monitorLimit = initialMonitorLimit; + + TRY; + + data.hmpMonitors = (HMONITOR*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, + initialMonitorLimit, sizeof(HMONITOR)); + CATCH_BAD_ALLOC_RET(NULL); + + if (!::EnumDisplayMonitors(NULL, NULL, clb_fCollectMonitors, (LPARAM)&data)) { + free(data.hmpMonitors); + return NULL; } + + *numScreens = data.monitorCounter; + return data.hmpMonitors; +} + +int WINAPI CountMonitors() +{ + int numScreens = 0; + HMONITOR* monHds = CollectMonitors(&numScreens); + free(monHds); + return numScreens; +} + +static BOOL AreSameMonitorInfo(LPMONITORINFOEX oldInfo, LPMONITORINFOEX newInfo) +{ + if (oldInfo == NULL || newInfo == NULL) { + return FALSE; + } + + return oldInfo->dwFlags == newInfo->dwFlags + && ::lstrcmp(oldInfo->szDevice, newInfo->szDevice) == 0; } BOOL WINAPI MonitorBounds(HMONITOR hmMonitor, RECT* rpBounds) @@ -206,17 +237,26 @@ BOOL Devices::UpdateInstance(JNIEnv *env) { J2dTraceLn(J2D_TRACE_INFO, "Devices::UpdateInstance"); - int numScreens = CountMonitors(); - HMONITOR *monHds = (HMONITOR *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, - numScreens, sizeof(HMONITOR)); - if (numScreens != CollectMonitors(monHds, numScreens)) { + int numScreens = 0; + HMONITOR *monHds = CollectMonitors(&numScreens); + if (monHds == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, - "Devices::UpdateInstance: Failed to get all "\ + "Devices::UpdateInstance: Failed to get "\ "monitor handles."); free(monHds); return FALSE; } + if (numScreens == 0) { + CriticalSection::Lock l(arrayLock); + if (theInstance != NULL) { + J2dRlsTraceLn(J2D_TRACE_ERROR, + "Devices::UpdateInstance: No valid monitor handles."); + free(monHds); + return FALSE; + } + } + Devices *newDevices = new Devices(numScreens); // This way we know that the array will not be disposed of // at least until we replaced it with a new one. @@ -242,18 +282,26 @@ BOOL Devices::UpdateInstance(JNIEnv *env) theInstance = newDevices; if (oldDevices) { - // Invalidate the devices with indexes out of the new set of - // devices. This doesn't cover all cases when the device - // might should be invalidated (like if it's not the last device - // that was removed), but it will have to do for now. int oldNumScreens = oldDevices->GetNumDevices(); - int newNumScreens = theInstance->GetNumDevices(); - J2dTraceLn(J2D_TRACE_VERBOSE, " Invalidating removed devices"); - for (int i = newNumScreens; i < oldNumScreens; i++) { - // removed device, needs to be invalidated + J2dTraceLn(J2D_TRACE_VERBOSE, " Invalidating changed devices"); + for (int i = 0; i < oldNumScreens; i++) { + AwtWin32GraphicsDevice *oldDevice = + oldDevices->GetDevice(i, FALSE); + AwtWin32GraphicsDevice *newDevice = + theInstance->GetDevice(i, FALSE); + BOOL changed = (newDevice == NULL) + || !AreSameMonitorInfo( + (LPMONITORINFOEX) oldDevice->GetMonitorInfo(), + (LPMONITORINFOEX) newDevice->GetMonitorInfo()); + + if (!changed) { + newDevice->TransferJavaDevice(env, oldDevice); + continue; + } + J2dTraceLn(J2D_TRACE_WARNING, - "Devices::UpdateInstance: device removed: %d", i); - oldDevices->GetDevice(i)->Invalidate(env); + "Devices::UpdateInstance: device changed: %d", i); + oldDevice->Invalidate(env); } // Now that we have a new array in place, remove this (possibly the // last) reference to the old instance. @@ -346,6 +394,12 @@ AwtWin32GraphicsDevice *Devices::GetDevice(int index, BOOL adjust) J2dTraceLn(J2D_TRACE_INFO, "Devices::GetDevice index=%d adjust?=%d", index, adjust); + if (numDevices <= 0) { + J2dTraceLn(J2D_TRACE_WARNING, + "Devices::GetDevice: "\ + "no devices, returning NULL."); + return NULL; + } if (index < 0 || index >= numDevices) { if (!adjust) { J2dTraceLn(J2D_TRACE_WARNING, diff --git a/src/java.desktop/windows/native/libawt/windows/Devices.h b/src/java.desktop/windows/native/libawt/windows/Devices.h index 0972ef1414e..7e7a419453e 100644 --- a/src/java.desktop/windows/native/libawt/windows/Devices.h +++ b/src/java.desktop/windows/native/libawt/windows/Devices.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,8 +47,11 @@ static BOOL UpdateInstance(JNIEnv *env); class InstanceAccess { public: INLINE InstanceAccess() { devices = Devices::GetInstance(); } - INLINE ~InstanceAccess() { devices->Release(); } + INLINE ~InstanceAccess() { if (devices != NULL) devices->Release(); } Devices* operator->() { return devices; } + INLINE AwtWin32GraphicsDevice* Device(int index, BOOL adjust = TRUE) { + return devices == NULL ? NULL : devices->GetDevice(index, adjust); + } private: Devices* devices; // prevent bad things like copying or getting address of diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp index b447ad6889a..a94c96c58c5 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ #include #include -extern void initScreens(JNIEnv *env); +extern BOOL initScreens(JNIEnv *env); extern "C" void awt_dnd_initialize(); extern "C" void awt_dnd_uninitialize(); extern "C" void awt_clipboard_uninitialize(JNIEnv *env); @@ -157,6 +157,78 @@ extern "C" JNIEXPORT jboolean JNICALL AWTIsHeadless() { } #define IDT_AWT_MOUSECHECK 0x101 +#define IDT_AWT_DISPLAYCHANGE 0x102 + +#define AWT_DISPLAYCHANGE_RETRY_DELAY 250 +#define AWT_DISPLAYCHANGE_RETRY_LIMIT 20 + +class DisplayChangeHandler { +public: + static BOOL Handle(JNIEnv *env, HWND hWnd) { + // Reinitialize screens + if (!initScreens(env)) { + OnDisplayChangeFailed(hWnd); + return FALSE; + } + + OnDisplayChangeSucceeded(hWnd); + + // Notify Java side - call WToolkit.displayChanged() + jclass clazz = env->FindClass("sun/awt/windows/WToolkit"); + DASSERT(clazz != NULL); + if (!clazz) throw std::bad_alloc(); + env->CallStaticVoidMethod(clazz, AwtToolkit::displayChangeMID); + + return !env->ExceptionCheck(); + } + + static void Reset(HWND hWnd) { + ::KillTimer(hWnd, IDT_AWT_DISPLAYCHANGE); + retryCount = 0; + } + + static void ScheduleFromSessionChange(HWND hWnd) { + if (!recoveryPending) { + return; + } + Reset(hWnd); + Schedule(hWnd); + } + +private: + static void OnDisplayChangeFailed(HWND hWnd) { + recoveryPending = TRUE; + Schedule(hWnd); + } + + static void OnDisplayChangeSucceeded(HWND hWnd) { + recoveryPending = FALSE; + Reset(hWnd); + } + + static void Schedule(HWND hWnd) { + if (retryCount >= AWT_DISPLAYCHANGE_RETRY_LIMIT) { + Reset(hWnd); + J2dRlsTraceLn(J2D_TRACE_ERROR, + "AwtToolkit: Display change retry limit exceeded."); + return; + } + + retryCount++; + if (::SetTimer(hWnd, IDT_AWT_DISPLAYCHANGE, + AWT_DISPLAYCHANGE_RETRY_DELAY, NULL) == 0) { + Reset(hWnd); + J2dRlsTraceLn(J2D_TRACE_ERROR, + "AwtToolkit: Failed to schedule display change retry."); + } + } + + static int retryCount; + static BOOL recoveryPending; +}; + +int DisplayChangeHandler::retryCount = 0; +BOOL DisplayChangeHandler::recoveryPending = FALSE; static LPCTSTR szAwtToolkitClassName = TEXT("SunAwtToolkit"); @@ -1004,6 +1076,14 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message, } case WM_TIMER: { + if (wParam == IDT_AWT_DISPLAYCHANGE) { + if (DisplayChangeHandler::Handle(env, hWnd)) { + GetInstance().m_displayChanged = TRUE; + ::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL); + } + return 0; + } + // 6479820. Should check if a window is in manual resizing process: skip // sending any MouseExit/Enter events while inside resize-loop. // Note that window being in manual moving process could still @@ -1245,18 +1325,11 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message, return tk.m_inputMethodData; } case WM_DISPLAYCHANGE: { - // Reinitialize screens - initScreens(env); - - // Notify Java side - call WToolkit.displayChanged() - jclass clazz = env->FindClass("sun/awt/windows/WToolkit"); - DASSERT(clazz != NULL); - if (!clazz) throw std::bad_alloc(); - env->CallStaticVoidMethod(clazz, AwtToolkit::displayChangeMID); - - GetInstance().m_displayChanged = TRUE; - - ::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL); + DisplayChangeHandler::Reset(hWnd); + if (DisplayChangeHandler::Handle(env, hWnd)) { + GetInstance().m_displayChanged = TRUE; + ::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL); + } break; } /* Session management */ @@ -1341,6 +1414,9 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message, activate ? JNI_TRUE : JNI_FALSE, reason); + if (activate) { + DisplayChangeHandler::ScheduleFromSessionChange(hWnd); + } } break; } diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp index 785f1301516..a43bd9c6bef 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -612,13 +612,52 @@ void AwtWin32GraphicsDevice::Release() } /** - * Links this native object with its java Win32GraphicsDevice. - * Need this link because the colorModel of the java device - * may be updated from native code. + * Links this native object with its java Win32GraphicsDevice peer. + * + * The link is needed for upcalls to the java peer, such as invalidate() + * and dynamic color model updates. + * + * Passing NULL intentionally clears the link. + * Clearing it here prevents stale peer links and releases + * the old JNI weak global ref. + * + * During display changes, the native device array is recreated, + * changed or removed devices invalidate their java peers. + * Unchanged monitors transfer the existing weak ref to + * the new native device by TransferJavaDevice(). */ void AwtWin32GraphicsDevice::SetJavaDevice(JNIEnv *env, jobject objPtr) { - javaDevice = env->NewWeakGlobalRef(objPtr); + jobject newJavaDevice = NULL; + if (objPtr != NULL) { + newJavaDevice = env->NewWeakGlobalRef(objPtr); + if (newJavaDevice == NULL) { + return; + } + } + + if (javaDevice != NULL) { + env->DeleteWeakGlobalRef(javaDevice); + } + javaDevice = newJavaDevice; +} + +/** + * Transfers the java Win32GraphicsDevice's link from a native device that is + * being replaced by a new native device for the same monitor. + */ +void AwtWin32GraphicsDevice::TransferJavaDevice(JNIEnv *env, + AwtWin32GraphicsDevice *device) +{ + if (device == NULL || device == this || device->javaDevice == NULL) { + return; + } + + if (javaDevice != NULL) { + env->DeleteWeakGlobalRef(javaDevice); + } + javaDevice = device->javaDevice; + device->javaDevice = NULL; } /** @@ -1398,7 +1437,10 @@ JNIEXPORT void JNICALL (JNIEnv *env, jobject thisPtr, jint screen) { Devices::InstanceAccess devices; - devices->GetDevice(screen)->SetJavaDevice(env, thisPtr); + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); + if (device != NULL) { + device->SetJavaDevice(env, thisPtr); + } } /* @@ -1411,9 +1453,8 @@ JNIEXPORT void JNICALL (JNIEnv *env, jobject thisPtr, jint screen, jfloat scaleX, jfloat scaleY) { Devices::InstanceAccess devices; - AwtWin32GraphicsDevice *device = devices->GetDevice(screen); - - if (device != NULL ) { + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); + if (device != NULL) { device->DisableScaleAutoRefresh(); device->SetScale(scaleX, scaleY); } @@ -1429,8 +1470,8 @@ JNIEXPORT jfloat JNICALL (JNIEnv *env, jobject thisPtr, jint screen) { Devices::InstanceAccess devices; - AwtWin32GraphicsDevice *device = devices->GetDevice(screen); - return (device == NULL) ? 1 : device->GetScaleX(); + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); + return device == NULL ? 1 : device->GetScaleX(); } /* @@ -1443,8 +1484,8 @@ JNIEXPORT jfloat JNICALL (JNIEnv *env, jobject thisPtr, jint screen) { Devices::InstanceAccess devices; - AwtWin32GraphicsDevice *device = devices->GetDevice(screen); - return (device == NULL) ? 1 : device->GetScaleY(); + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); + return device == NULL ? 1 : device->GetScaleY(); } /* @@ -1457,8 +1498,7 @@ Java_sun_awt_Win32GraphicsDevice_initNativeScale (JNIEnv *env, jobject thisPtr, jint screen) { Devices::InstanceAccess devices; - AwtWin32GraphicsDevice *device = devices->GetDevice(screen); - + AwtWin32GraphicsDevice *device = devices.Device(screen, FALSE); if (device != NULL) { device->InitDesktopScales(); } diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h index 55f6c1623a8..b3619dcc545 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,8 @@ public: unsigned int *GetSystemPaletteEntries(); unsigned char *GetSystemInverseLUT(); void SetJavaDevice(JNIEnv *env, jobject objPtr); + void TransferJavaDevice(JNIEnv *env, + AwtWin32GraphicsDevice *device); HPALETTE SelectPalette(HDC hDC); void RealizePalette(HDC hDC); HPALETTE GetPalette(); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp index 50591434d4c..cc53f4a3322 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,10 +35,12 @@ BOOL DWMIsCompositionEnabled(); -void initScreens(JNIEnv *env) { +BOOL initScreens(JNIEnv *env) { if (!Devices::UpdateInstance(env)) { - JNU_ThrowInternalError(env, "Could not update the devices array."); + J2dRlsTraceLn(J2D_TRACE_ERROR, "initScreens: Could not update the devices array."); + return FALSE; } + return TRUE; } /** @@ -144,7 +146,9 @@ Java_sun_awt_Win32GraphicsEnvironment_initDisplay(JNIEnv *env, DWMIsCompositionEnabled(); - initScreens(env); + if (!initScreens(env)) { + JNU_ThrowInternalError(env, "Could not update the devices array."); + } } /* From 207dc4e82f46d5991421f5a6c66fa82048d3bc74 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 2 Jun 2026 04:37:09 +0000 Subject: [PATCH 022/115] 8322256: Define and document GZIPInputStream concatenated stream semantics Reviewed-by: lancea, alanb, simonis --- .../java/util/zip/GZIPInputStream.java | 93 ++++--- .../zip/GZIP/BasicGZIPInputStreamTest.java | 36 ++- .../util/zip/GZIP/GZIPInputStreamRead.java | 238 +++++++++++++----- 3 files changed, 272 insertions(+), 95 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/GZIPInputStream.java b/src/java.base/share/classes/java/util/zip/GZIPInputStream.java index 72fb8036f08..88d08386e8c 100644 --- a/src/java.base/share/classes/java/util/zip/GZIPInputStream.java +++ b/src/java.base/share/classes/java/util/zip/GZIPInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,17 +34,55 @@ import java.io.EOFException; import java.util.Objects; /** - * This class implements a stream filter for reading compressed data in - * the GZIP file format. + * This class implements a stream filter for decompressing GZIP file format data. + * + *

GZIP file format

+ * The GZIP file format is specified by RFC 1952. The format, as specified in section 2.2 of + * the RFC, consists of a series of "members" that appear one after another in the stream with + * no additional information before, between, or after them. Each member consists of a header, + * followed by data that is compressed using the {@code deflate} algorithm, and then a trailer. + *

+ * This class is capable of reading a stream consisting of a series of members. + *

+ * Reading from the stream may read and buffer bytes from the underlying stream. + * This includes bytes that follow a member's trailer. Whether or not any additional bytes + * have been read past a member's trailer, the read methods on this class yield decompressed + * data from at most one member; data from multiple members is not combined in + * a single read operation. + * + *

Thread safety

+ * {@code GZIPInputStream} is not safe for use by multiple concurrent threads. Any multithreaded + * concurrent use must be guarded by appropriate synchronization. + * + * @apiNote + * The {@link #close} method should be called to release resources used by this + * stream, either directly, or with the {@code try}-with-resources statement. + * + * @spec https://www.rfc-editor.org/info/rfc1952 + * RFC 1952: GZIP file format specification version 4.3 + * + * @see InflaterInputStream * - * @see InflaterInputStream - * @author David Connelly * @since 1.1 - * */ public class GZIPInputStream extends InflaterInputStream { /** - * CRC-32 for uncompressed data. + * GZIP header magic number. + */ + public static final int GZIP_MAGIC = 0x8b1f; + + /* + * File header flags. + */ + private static final int FHCRC = 2; // Header CRC + private static final int FEXTRA = 4; // Extra field + private static final int FNAME = 8; // File name + private static final int FCOMMENT = 16; // File comment + + private final byte[] tmpbuf = new byte[128]; + + /** + * CRC-32 for decompressed data. */ protected CRC32 crc = new CRC32(); @@ -66,13 +104,15 @@ public class GZIPInputStream extends InflaterInputStream { /** * Creates a new input stream with the specified buffer size. + * * @param in the input stream * @param size the input buffer size * * @throws ZipException if a GZIP format error has occurred or the * compression method used is unsupported * @throws NullPointerException if {@code in} is null - * @throws IOException if an I/O error has occurred + * @throws IOException if an I/O error occurs when reading the member header + * from the underlying stream * @throws IllegalArgumentException if {@code size <= 0} */ public GZIPInputStream(InputStream in, int size) throws IOException { @@ -103,25 +143,27 @@ public class GZIPInputStream extends InflaterInputStream { /** * Creates a new input stream with a default buffer size. + * * @param in the input stream * * @throws ZipException if a GZIP format error has occurred or the * compression method used is unsupported * @throws NullPointerException if {@code in} is null - * @throws IOException if an I/O error has occurred + * @throws IOException if an I/O error occurs when reading the member header + * from the underlying stream */ public GZIPInputStream(InputStream in) throws IOException { this(in, 512); } /** - * Reads uncompressed data into an array of bytes, returning the number of inflated + * Reads decompressed data into an array of bytes, returning the number of decompressed * bytes. If {@code len} is not zero, the method will block until some input can be * decompressed; otherwise, no bytes are read and {@code 0} is returned. *

* If this method returns a nonzero integer n then {@code buf[off]} - * through {@code buf[off+}n{@code -1]} contain the uncompressed - * data. The content of elements {@code buf[off+}n{@code ]} through + * through {@code buf[off+}n{@code -1]} contain the decompressed + * data. The content of elements {@code buf[off+}n{@code ]} through * {@code buf[off+}len{@code -1]} is undefined, contrary to the * specification of the {@link java.io.InputStream InputStream} superclass, * so an implementation is free to modify these elements during the inflate @@ -131,18 +173,20 @@ public class GZIPInputStream extends InflaterInputStream { * * @param buf the buffer into which the data is read * @param off the start offset in the destination array {@code buf} - * @param len the maximum number of bytes read - * @return the actual number of bytes inflated, or -1 if the end of the - * compressed input stream is reached + * @param len the maximum number of bytes to read into {@code buf} + * @return the actual number of bytes decompressed from a GZIP member, or -1 if the + * end-of-stream is reached * * @throws NullPointerException If {@code buf} is {@code null}. * @throws IndexOutOfBoundsException If {@code off} is negative, * {@code len} is negative, or {@code len} is greater than * {@code buf.length - off} * @throws ZipException if the compressed input data is corrupt. - * @throws IOException if an I/O error has occurred. + * @throws IOException if the stream is closed or an I/O error has occurred. * + * @see ##gzip_file_format GZIP file format */ + @Override public int read(byte[] buf, int off, int len) throws IOException { ensureOpen(); if (eos) { @@ -165,6 +209,7 @@ public class GZIPInputStream extends InflaterInputStream { * with the stream. * @throws IOException if an I/O error has occurred */ + @Override public void close() throws IOException { if (!closed) { super.close(); @@ -173,20 +218,6 @@ public class GZIPInputStream extends InflaterInputStream { } } - /** - * GZIP header magic number. - */ - public static final int GZIP_MAGIC = 0x8b1f; - - /* - * File header flags. - */ - private static final int FTEXT = 1; // Extra text - private static final int FHCRC = 2; // Header CRC - private static final int FEXTRA = 4; // Extra field - private static final int FNAME = 8; // File name - private static final int FCOMMENT = 16; // File comment - /* * Reads GZIP member header and returns the total byte number * of this member header. @@ -309,8 +340,6 @@ public class GZIPInputStream extends InflaterInputStream { return b; } - private byte[] tmpbuf = new byte[128]; - /* * Skips bytes of input data blocking until all bytes are skipped. * Does not assume that the input stream is capable of seeking. diff --git a/test/jdk/java/util/zip/GZIP/BasicGZIPInputStreamTest.java b/test/jdk/java/util/zip/GZIP/BasicGZIPInputStreamTest.java index 1f52d44146e..642b0bafa66 100644 --- a/test/jdk/java/util/zip/GZIP/BasicGZIPInputStreamTest.java +++ b/test/jdk/java/util/zip/GZIP/BasicGZIPInputStreamTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +22,21 @@ */ import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.stream.Stream; import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /* * @test @@ -51,7 +57,7 @@ public class BasicGZIPInputStreamTest { @ParameterizedTest @MethodSource("npeFromConstructors") public void testNPEFromConstructors(final Executable constructor) { - Assertions.assertThrows(NullPointerException.class, constructor, + assertThrows(NullPointerException.class, constructor, "GZIPInputStream constructor did not throw NullPointerException"); } @@ -71,7 +77,7 @@ public class BasicGZIPInputStreamTest { @ParameterizedTest @MethodSource("iaeFromConstructors") public void testIAEFromConstructors(final Executable constructor) { - Assertions.assertThrows(IllegalArgumentException.class, constructor, + assertThrows(IllegalArgumentException.class, constructor, "GZIPInputStream constructor did not throw IllegalArgumentException"); } @@ -89,7 +95,29 @@ public class BasicGZIPInputStreamTest { @ParameterizedTest @MethodSource("ioeFromConstructors") public void testIOEFromConstructors(final Executable constructor) { - Assertions.assertThrows(IOException.class, constructor, + assertThrows(IOException.class, constructor, "GZIPInputStream constructor did not throw IOException"); } + + /* + * Verifies that GZIPInputStream.read() throws IOException when invoked on a closed + * stream + */ + @Test + void testClosedStreamRead() throws Exception { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (GZIPOutputStream gzos = new GZIPOutputStream(baos)) { + gzos.write(new byte[] {0x42, 0x42}); // GZIP compress these input bytes + } + final byte[] gzipCompressed = baos.toByteArray(); + // create the GZIPInputStream to test + final GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(gzipCompressed)); + in.close(); + final IOException ioe = assertThrows(IOException.class, () -> in.read(new byte[1], 0, 1)); + final String exMessage = ioe.getMessage(); + if (exMessage == null || !exMessage.contains("Stream closed")) { + // unexpected exception message, propagate the original exception + throw ioe; + } + } } diff --git a/test/jdk/java/util/zip/GZIP/GZIPInputStreamRead.java b/test/jdk/java/util/zip/GZIP/GZIPInputStreamRead.java index 56bd58e1aaf..9cc13b29f34 100644 --- a/test/jdk/java/util/zip/GZIP/GZIPInputStreamRead.java +++ b/test/jdk/java/util/zip/GZIP/GZIPInputStreamRead.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,81 +21,201 @@ * questions. */ -/* @test +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import jdk.test.lib.RandomFactory; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test * @bug 4691425 * @summary Test the read and write of GZIPInput/OutputStream, including * concatenated .gz inputstream * @key randomness + * @library /test/lib + * @build jdk.test.lib.RandomFactory + * @run junit ${test.main.class} */ +class GZIPInputStreamRead { -import java.io.*; -import java.util.*; -import java.util.zip.*; + private static final Random random = RandomFactory.getRandom(); -public class GZIPInputStreamRead { - public static void main(String[] args) throws Throwable { - Random rnd = new Random(); - for (int i = 1; i < 100; i++) { - int members = rnd.nextInt(10) + 1; + /* + * Generates GZIP content containing multiple members and then verifies + * that using GZIPInputStream to decompress that content generates the correct + * expected decompressed data. + */ + @Test + void testMultipleMembers() throws Exception { + final int numMembers = random.nextInt(10) + 1; + final ByteArrayOutputStream rawUncompressedBaos = new ByteArrayOutputStream(); + final ByteArrayOutputStream gzipCompressedBaos = new ByteArrayOutputStream(); + // generate GZIP content with multiple members + for (int j = 0; j < numMembers; j++) { + byte[] src = new byte[random.nextInt(8192) + 1]; + random.nextBytes(src); + rawUncompressedBaos.write(src); - ByteArrayOutputStream srcBAOS = new ByteArrayOutputStream(); - ByteArrayOutputStream dstBAOS = new ByteArrayOutputStream(); - for (int j = 0; j < members; j++) { - byte[] src = new byte[rnd.nextInt(8192) + 1]; - rnd.nextBytes(src); - srcBAOS.write(src); - - try (GZIPOutputStream gzos = new GZIPOutputStream(dstBAOS)) { - gzos.write(src); - } - } - byte[] srcBytes = srcBAOS.toByteArray(); - byte[] dstBytes = dstBAOS.toByteArray(); - // try different size of buffer to read the - // GZIPInputStream - /* just for fun when running manually - for (int j = 1; j < 10; j++) { - test(srcBytes, dstBytes, j); - } - */ - for (int j = 0; j < 10; j++) { - int readBufSZ = rnd.nextInt(2048) + 1; - test(srcBytes, - dstBytes, - readBufSZ, - 512); // the defualt buffer size - test(srcBytes, - dstBytes, - readBufSZ, - rnd.nextInt(4096) + 1); + try (GZIPOutputStream gzos = new GZIPOutputStream(gzipCompressedBaos)) { + gzos.write(src); } } + final byte[] uncompressedRawBytes = rawUncompressedBaos.toByteArray(); + final byte[] gzipCompressedBytes = gzipCompressedBaos.toByteArray(); + // decompress using GZIPInputStream and verify the decompressed output. + // use different input buffer size for GZIPInputStream when running the verification. + for (int j = 0; j < 10; j++) { + final int readBufSZ = random.nextInt(2048) + 1; + verifyDecompressed(uncompressedRawBytes, + gzipCompressedBytes, + readBufSZ, + 512); // the default input buffer size + verifyDecompressed(uncompressedRawBytes, + gzipCompressedBytes, + readBufSZ, + random.nextInt(4096) + 1); + } } - private static void test(byte[] src, byte[] dst, - int readBufSize, int gzisBufSize) - throws Throwable - { - try (ByteArrayInputStream bais = new ByteArrayInputStream(dst); - GZIPInputStream gzis = new GZIPInputStream(bais, gzisBufSize)) - { - byte[] result = new byte[src.length + 10]; + /* + * Generates GZIP content containing one member followed by some arbitrary non-member data. + * The test then verifies that using GZIPInputStream to decompress that content generates + * the correct expected decompressed data. + */ + @Test + void testNonMemberAfterTrailer() throws Exception { + final byte[] rawUncompressed = new byte[random.nextInt(1234)]; + random.nextBytes(rawUncompressed); + final ByteArrayOutputStream gzipCompressedPlusExtra = new ByteArrayOutputStream(); + // generate a valid GZIP member + try (GZIPOutputStream gzos = new GZIPOutputStream(gzipCompressedPlusExtra)) { + gzos.write(rawUncompressed); // GZIP compress + } + final int numCompressedBytes = gzipCompressedPlusExtra.size(); + // past the GZIP trailer, write some additional bytes that doesn't represent a GZIP member + final byte[] notGZIPMagic = ByteBuffer.allocate(Integer.BYTES). + putInt(GZIPInputStream.GZIP_MAGIC + 42) + .array(); + gzipCompressedPlusExtra.write(notGZIPMagic); + assertEquals(numCompressedBytes + notGZIPMagic.length, gzipCompressedPlusExtra.size(), + "unexpected number of compressed + extra bytes"); + // now use GZIPInputStream to decompress the compressed plus extra bytes and verify + // that the extra bytes don't cause unexpected decompressed output + final ByteArrayOutputStream decompressedBaos = new ByteArrayOutputStream(); + int n = 0; + try (ByteArrayInputStream bais = new ByteArrayInputStream(gzipCompressedPlusExtra.toByteArray()); + GZIPInputStream gzipIn = new GZIPInputStream(bais)) { + + final byte[] tmpBuf = new byte[42]; + while ((n = gzipIn.read(tmpBuf)) != -1) { + decompressedBaos.write(tmpBuf, 0, n); + } + final byte[] decompressed = decompressedBaos.toByteArray(); + // verify the decompressed content + assertEquals(rawUncompressed.length, decompressed.length, + "unexpected number of decompressed bytes"); + assertArrayEquals(rawUncompressed, decompressed, "unexpected decompressed data"); + // make sure additional calls to read still return EOF + assertEquals(-1, gzipIn.read(), "unexpected return from read(), expected EOF"); + assertEquals(-1, gzipIn.read(new byte[10]), "unexpected return from read(), expected EOF"); + } + } + + /* + * Verifies that the InputStream.available() method is invoked on the underlying InputStream + * to determine presence of additional GZIP members in the stream. + */ + @Test + void testInputStreamAvailableCalled() throws Exception { + final byte[] rawUncompressedMember1 = new byte[random.nextInt(111)]; + random.nextBytes(rawUncompressedMember1); + System.err.println("GZIP member 1 has " + rawUncompressedMember1.length + " bytes"); + + final byte[] rawUncompressedMember2 = new byte[random.nextInt(33)]; + random.nextBytes(rawUncompressedMember2); + System.err.println("GZIP member 2 has " + rawUncompressedMember2.length + " bytes"); + + final ByteArrayOutputStream twoMemberGzipCompressedBaos = new ByteArrayOutputStream(); + // generate GZIP format data with 2 valid GZIP members + try (GZIPOutputStream gzos = new GZIPOutputStream(twoMemberGzipCompressedBaos)) { + gzos.write(rawUncompressedMember1); // GZIP compress + gzos.write(rawUncompressedMember2); // GZIP compress + } + final byte[] gzipCompressed = twoMemberGzipCompressedBaos.toByteArray(); + final AtomicBoolean availableInvoked = new AtomicBoolean(); + // an InputStream which tracks the calls to available() + final ByteArrayInputStream underlying = new ByteArrayInputStream(gzipCompressed) { + @Override + public int available() { + availableInvoked.set(true); + return super.available(); + } + }; + // now use GZIPInputStream to decompress the compressed data and expect the decompressed + // data to be correct and also expect the InputStream.available() to have been invoked + final ByteArrayOutputStream decompressedBaos = new ByteArrayOutputStream(); + int n = 0; + try (GZIPInputStream gzipIn = new GZIPInputStream(underlying)) { + + final byte[] tmpBuf = new byte[1024]; + while ((n = gzipIn.read(tmpBuf)) != -1) { + decompressedBaos.write(tmpBuf, 0, n); + } + assertTrue(availableInvoked.get(), "InputStream.available() wasn't invoked"); + final byte[] decompressed = decompressedBaos.toByteArray(); + // verify the decompressed content, it should represent the two GZIP members + assertEquals(rawUncompressedMember1.length + rawUncompressedMember2.length, + decompressed.length, "unexpected number of decompressed bytes"); + + assertArrayEquals(rawUncompressedMember1, + Arrays.copyOfRange(decompressed, 0, rawUncompressedMember1.length), + "unexpected decompressed data of first member"); + + assertArrayEquals(rawUncompressedMember2, + Arrays.copyOfRange(decompressed, rawUncompressedMember1.length, decompressed.length), + "unexpected decompressed data of second member"); + + // make sure additional calls to read still return EOF + assertEquals(-1, gzipIn.read(), "unexpected return from read(), expected EOF"); + assertEquals(-1, gzipIn.read(new byte[42]), "unexpected return from read(), expected EOF"); + } + } + + // verify that decompressing the gzipCompressed data using GZIPInputStream + // generates the expected output + private static void verifyDecompressed(final byte[] rawUncompressed, + final byte[] gzipCompressed, + final int readBufSize, final int gzisBufSize) + throws IOException { + try (ByteArrayInputStream bais = new ByteArrayInputStream(gzipCompressed); + GZIPInputStream gzis = new GZIPInputStream(bais, gzisBufSize)) { + + byte[] result = new byte[rawUncompressed.length + 10]; byte[] buf = new byte[readBufSize]; int n = 0; - int off = 0; - + int numDecompressed = 0; while ((n = gzis.read(buf, 0, buf.length)) != -1) { - System.arraycopy(buf, 0, result, off, n); - off += n; + System.arraycopy(buf, 0, result, numDecompressed, n); + numDecompressed += n; // no range check, if overflow, let it fail } - if (off != src.length || gzis.available() != 0 || - !Arrays.equals(src, Arrays.copyOf(result, off))) { - throw new RuntimeException( - "GZIPInputStream reading failed! " + - ", src.len=" + src.length + - ", read=" + off); - } + assertEquals(rawUncompressed.length, numDecompressed, + "unexpected number of decompressed bytes"); + assertEquals(0, gzis.available(), + "unexpected additional bytes available in the GZIPInputStream"); + assertArrayEquals(rawUncompressed, Arrays.copyOf(result, numDecompressed), + "unexpected decompressed data"); } } } From 29e37422a5e537eba6de2f05dc30de8dadecc83d Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 2 Jun 2026 04:55:29 +0000 Subject: [PATCH 023/115] 8385670: Incorrect warning: Unexpected gaps for Klass alignment Reviewed-by: matsaave, kvn --- src/hotspot/share/cds/archiveUtils.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 7985c62d67b..bfaa1d6644c 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -303,7 +303,8 @@ public: AllocGapNode* node = allocate_node(gap, Empty{}); insert(gap, node); - log_trace(aot, alloc)("adding a gap of %zu bytes @ %p (total = %zu) in %zu blocks", gap_bytes, gap_bottom, _total_gap_bytes, size()); + log_trace(aot, alloc)("adding a gap of %zu bytes @ %p (total = %zu, used = %zu) in %zu blocks", + gap_bytes, gap_bottom, _total_gap_bytes, _total_gap_bytes_used, size()); return gap_bytes; } @@ -325,29 +326,25 @@ public: remove(node); - precond(_total_gap_bytes >= num_bytes); - _total_gap_bytes -= num_bytes; _total_gap_bytes_used += num_bytes; _total_gap_allocs++; DEBUG_ONLY(node = nullptr); // Don't use it anymore! precond(gap_bytes >= num_bytes); if (gap_bytes > num_bytes) { - gap_bytes -= num_bytes; - gap_bottom += num_bytes; - - AllocGap gap(gap_bytes, gap_bottom); // constructor checks alignment + AllocGap gap(gap_bytes - num_bytes, gap_bottom + num_bytes); // constructor checks alignment AllocGapNode* new_node = allocate_node(gap, Empty{}); insert(gap, new_node); } + size_t unfilled_bytes = _total_gap_bytes - _total_gap_bytes_used; log_trace(aot, alloc)("%zu bytes @ %p in a gap of %zu bytes (used gaps %zu times, remain gap = %zu bytes in %zu blocks)", - num_bytes, result, gap_bytes, _total_gap_allocs, _total_gap_bytes, size()); + num_bytes, result, gap_bytes, _total_gap_allocs, unfilled_bytes, size()); return result; } }; -size_t DumpRegion::_total_gap_bytes = 0; -size_t DumpRegion::_total_gap_bytes_used = 0; +size_t DumpRegion::_total_gap_bytes = 0; // All the gaps that have ever been created +size_t DumpRegion::_total_gap_bytes_used = 0; // All the gaps that have been used size_t DumpRegion::_total_gap_allocs = 0; DumpRegion::AllocGapTree DumpRegion::_gap_tree; @@ -418,20 +415,21 @@ void DumpRegion::report_gaps(DumpAllocStats* stats) { }); double unfilled_percent = 0.0; + size_t unfilled_bytes = _total_gap_bytes - _total_gap_bytes_used; if (_gap_tree.size() > 0) { - unfilled_percent = percent_of(_total_gap_bytes, _total_gap_allocs); + unfilled_percent = percent_of(unfilled_bytes, _total_gap_bytes); if (unfilled_percent > 5.0) { // We have a limited number of small objects, so some small gaps may remain // unfilled. If more than 5% of the gaps are unfilled, this likely indicates // a systematic error that should be investigated. Otherwise, do not warn to // avoid noise. - log_warning(aot)("Unexpected %zu gaps (%zu bytes) for Klass alignment", - _gap_tree.size(), _total_gap_bytes); + log_warning(aot)("Unexpected %zu gaps (%zu bytes, %.2f%%) for Klass alignment", + _gap_tree.size(), _total_gap_bytes, unfilled_percent); } } if (_total_gap_allocs > 0) { log_info(aot)("Allocated %zu objects of %zu bytes in gaps (remain = %zu bytes, %.2f%%)", - _total_gap_allocs, _total_gap_bytes_used, _total_gap_bytes, unfilled_percent); + _total_gap_allocs, _total_gap_bytes_used, unfilled_bytes, unfilled_percent); } } From 9c244ec182052f7b2ecaba4088710330e93fea2b Mon Sep 17 00:00:00 2001 From: Eric Fang Date: Tue, 2 Jun 2026 06:37:35 +0000 Subject: [PATCH 024/115] 8382532: C2: VectorAPI: disable VectorMaskCmp-not optimization for predicated compares Reviewed-by: epeter, vlivanov --- src/hotspot/share/opto/vectornode.cpp | 5 +- .../vectorapi/VectorMaskCompareNotTest.java | 839 ++++++++++++++---- 2 files changed, 648 insertions(+), 196 deletions(-) diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 92777f97d7b..dd49d88ce96 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -2727,9 +2727,7 @@ Node* XorVNode::Ideal_XorV_VectorMaskCmp(PhaseGVN* phase, bool can_reshape) { Node* in1 = in(1); Node* in2 = in(2); // Transformations for predicated vectors are not supported for now. - if (is_predicated_vector() || - in1->is_predicated_vector() || - in2->is_predicated_vector()) { + if (is_predicated_vector()) { return nullptr; } @@ -2753,6 +2751,7 @@ Node* XorVNode::Ideal_XorV_VectorMaskCmp(PhaseGVN* phase, bool can_reshape) { } if (in1->Opcode() != Op_VectorMaskCmp || in1->outcnt() != 1 || + in1->is_predicated_vector() || !in1->as_VectorMaskCmp()->predicate_can_be_negated() || !VectorNode::is_all_ones_vector(in2)) { return nullptr; diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java index 09185f63c69..9a2f440ea82 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * Copyright (c) 2025, 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ import jdk.test.lib.Asserts; /* * @test - * @bug 8354242 + * @bug 8354242 8382532 * @key randomness * @library /test/lib / * @summary test combining vector not operation with compare @@ -42,6 +42,7 @@ import jdk.test.lib.Asserts; public class VectorMaskCompareNotTest { private static int LENGTH = 128; + private static float TWO_FLOAT = 2.0f; private static final VectorSpecies B_SPECIES = VectorSpecies.ofLargestShape(byte.class); private static final VectorSpecies S_SPECIES = VectorSpecies.ofLargestShape(short.class); @@ -77,6 +78,7 @@ public class VectorMaskCompareNotTest { private static double[] dnan; private static double[] dpinf; private static double[] dninf; + private static boolean[] mi; private static boolean[] mr; static { @@ -99,6 +101,7 @@ public class VectorMaskCompareNotTest { dnan = new double[LENGTH]; dpinf = new double[LENGTH]; dninf = new double[LENGTH]; + mi = new boolean[LENGTH]; mr = new boolean[LENGTH]; Generator iGen = RD.ints(); @@ -125,6 +128,7 @@ public class VectorMaskCompareNotTest { dnan[i] = Double.NaN; dpinf[i] = Double.POSITIVE_INFINITY; dninf[i] = Double.NEGATIVE_INFINITY; + mi[i] = true; } } @@ -271,523 +275,363 @@ public class VectorMaskCompareNotTest { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareEQMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.EQ); testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.EQ); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.EQ, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.EQ); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareNEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.NE); testCompareMaskNotByte(B_SPECIES, VectorOperators.NE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.NE); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.NE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.NE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareLTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.LT); testCompareMaskNotByte(B_SPECIES, VectorOperators.LT, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.LT); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareGTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.GT); testCompareMaskNotByte(B_SPECIES, VectorOperators.GT, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.GT); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareLEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.LE); testCompareMaskNotByte(B_SPECIES, VectorOperators.LE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.LE); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareGEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.GE); testCompareMaskNotByte(B_SPECIES, VectorOperators.GE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.GE); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareULTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.ULT); testCompareMaskNotByte(B_SPECIES, VectorOperators.ULT, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.ULT); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareUGTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.UGT); testCompareMaskNotByte(B_SPECIES, VectorOperators.UGT, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.UGT); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareULEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.ULE); testCompareMaskNotByte(B_SPECIES, VectorOperators.ULE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.ULE); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 1", - IRNode.VECTOR_MASK_CMP, "= 3" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareUGEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.UGE); testCompareMaskNotByte(B_SPECIES, VectorOperators.UGE, (m) -> { return B_SPECIES.maskAll(true).xor(m); }); verifyResultsByte(B_SPECIES, VectorOperators.UGE); - - testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); - verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGE); } // Short tests @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareEQMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.EQ); testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.EQ); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.EQ, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.EQ); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.EQ, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.EQ); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareNEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.NE); testCompareMaskNotShort(S_SPECIES, VectorOperators.NE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.NE); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.NE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.NE); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.NE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.NE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareLTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.LT); testCompareMaskNotShort(S_SPECIES, VectorOperators.LT, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.LT); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LT); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.LT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.LT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareGTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.GT); testCompareMaskNotShort(S_SPECIES, VectorOperators.GT, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.GT); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GT); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.GT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.GT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareLEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.LE); testCompareMaskNotShort(S_SPECIES, VectorOperators.LE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.LE); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LE); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.LE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.LE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareGEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.GE); testCompareMaskNotShort(S_SPECIES, VectorOperators.GE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.GE); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GE); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.GE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.GE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareULTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.ULT); testCompareMaskNotShort(S_SPECIES, VectorOperators.ULT, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.ULT); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULT); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.ULT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.ULT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareUGTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.UGT); testCompareMaskNotShort(S_SPECIES, VectorOperators.UGT, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.UGT); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGT); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.UGT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.UGT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareULEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.ULE); testCompareMaskNotShort(S_SPECIES, VectorOperators.ULE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.ULE); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULE); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.ULE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.ULE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareUGEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.UGE); testCompareMaskNotShort(S_SPECIES, VectorOperators.UGE, (m) -> { return S_SPECIES.maskAll(true).xor(m); }); verifyResultsShort(S_SPECIES, VectorOperators.UGE); - - testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); - verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGE); - testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.UGE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); - verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.UGE); } // Int tests @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.EQ); testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.EQ); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.EQ, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.EQ); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.EQ, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.EQ); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.NE); testCompareMaskNotInt(I_SPECIES, VectorOperators.NE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.NE); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.NE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.NE); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.NE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.NE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareLTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.LT); testCompareMaskNotInt(I_SPECIES, VectorOperators.LT, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.LT); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LT); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.LT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.LT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareGTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.GT); testCompareMaskNotInt(I_SPECIES, VectorOperators.GT, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.GT); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GT); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.GT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.GT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareLEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.LE); testCompareMaskNotInt(I_SPECIES, VectorOperators.LE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.LE); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LE); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.LE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.LE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareGEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.GE); testCompareMaskNotInt(I_SPECIES, VectorOperators.GE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.GE); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GE); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.GE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.GE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareULTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.ULT); testCompareMaskNotInt(I_SPECIES, VectorOperators.ULT, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.ULT); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULT); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.ULT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.ULT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareUGTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.UGT); testCompareMaskNotInt(I_SPECIES, VectorOperators.UGT, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.UGT); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGT); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.UGT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.UGT); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareULEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.ULE); testCompareMaskNotInt(I_SPECIES, VectorOperators.ULE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.ULE); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULE); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.ULE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.ULE); } @Test @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", - IRNode.VECTOR_MASK_CAST, "= 2", - IRNode.VECTOR_MASK_CMP, "= 4" }, + IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareUGEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.UGE); testCompareMaskNotInt(I_SPECIES, VectorOperators.UGE, (m) -> { return I_SPECIES.maskAll(true).xor(m); }); verifyResultsInt(I_SPECIES, VectorOperators.UGE); - - testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); - verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGE); - testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.UGE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); - verifyResultsInt(IntVector.SPECIES_128, VectorOperators.UGE); } // Long tests @@ -1291,9 +1135,618 @@ public class VectorMaskCompareNotTest { verifyResultsDouble(D_SPECIES, VectorOperators.LT, da, db); } + // Cast variants of the byte, short and int tests above. These cases use + // mask compares whose result feeds into a VectorMaskCast (and either an + // explicit .not()/xor or an all-true mask xor). + // + // The IR expectation depends on whether the platform requires partial + // vector operations (see Matcher::vector_needs_partial_operations): + // * On SVE, a sub-register vector compare is lowered via + // ideal_partial_operations(), which generates an all-true predicate + // with VectorMaskGen and attaches it to the VectorMaskCmp. The + // compare becomes predicated, so after JDK-8382532 the + // XorV-VectorMaskCmp optimization does not fire and one not node + // (XorVMask) remains. + // * On all other supported platforms (ASIMD-only, AVX2/AVX-512, RVV), + // vector_needs_partial_operations() returns false, the + // VectorMaskCmp stays unpredicated, the optimization fires and the + // not nodes are folded into negated VectorMaskCmps. No XorV/XorVMask + // remains. + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareEQMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.EQ, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.EQ); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareNEMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.NE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareLTMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareGTMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareLEMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareGEMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareULTMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareUGTMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareULEMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "sve", "true" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareUGEMaskNotByteCast() { + testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); + verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareEQMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.EQ, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.EQ); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.EQ, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.EQ); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareNEMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.NE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.NE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.NE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareLTMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LT); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.LT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.LT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareGTMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GT); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.GT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.GT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareLEMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.LE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.LE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareGEMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.GE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.GE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareULTMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULT); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.ULT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.ULT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareUGTMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGT); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.UGT, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.UGT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareULEMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.ULE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.ULE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareUGEMaskNotShortCast() { + testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); + verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGE); + testCompareMaskNotShort(ShortVector.SPECIES_128, VectorOperators.UGE, (m) -> { return m.cast(ByteVector.SPECIES_64).not(); }); + verifyResultsShort(ShortVector.SPECIES_128, VectorOperators.UGE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareEQMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.EQ, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.EQ); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.EQ, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.EQ); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareNEMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.NE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.NE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.NE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.NE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareLTMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LT); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.LT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.LT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareGTMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GT); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.GT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.GT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareLEMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.LE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.LE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareGEMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.GE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.GE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareULTMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULT); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.ULT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.ULT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareUGTMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGT); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.UGT, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.UGT); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareULEMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.ULE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.ULE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "MaxVectorSize", "= 16" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V_MASK, "= 0", + IRNode.XOR_V, "= 0", + IRNode.VECTOR_MASK_CMP, "= 2" }, + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + public static void testCompareUGEMaskNotIntCast() { + testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); + verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGE); + testCompareMaskNotInt(IntVector.SPECIES_128, VectorOperators.UGE, (m) -> { return m.cast(ShortVector.SPECIES_64).not(); }); + verifyResultsInt(IntVector.SPECIES_128, VectorOperators.UGE); + } + + @Test + @IR(counts = { IRNode.XOR_V_MASK, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + @IR(counts = { IRNode.XOR_V, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + @IR(counts = { IRNode.XOR_V, "= 1", + IRNode.VECTOR_MASK_CMP, "= 1" }, + applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }) + public static void testMaskedCompareMaskNotNegative() { + int expected = F_SPECIES.length(); + var ones = FloatVector.broadcast(F_SPECIES, 1f); + // All true mask + VectorMask on = VectorMask.fromArray(F_SPECIES, mi, 0); + int got = ones.compare(VectorOperators.NE, TWO_FLOAT, on) + .not() + .firstTrue(); + Asserts.assertEquals(expected, got); + } + public static void main(String[] args) { TestFramework testFramework = new TestFramework(); - testFramework.setDefaultWarmup(5000) + testFramework.setDefaultWarmup(10000) .addFlags("--add-modules=jdk.incubator.vector") .start(); } From e83e79460bcc47a5f6b1c5b9835dae362d688ea2 Mon Sep 17 00:00:00 2001 From: Eric Fang Date: Tue, 2 Jun 2026 07:35:53 +0000 Subject: [PATCH 025/115] 8376285: AArch64: Support fusion optimization for SVE destructive instructions Reviewed-by: aph, dlong, adinn --- src/hotspot/cpu/aarch64/aarch64_vector.ad | 404 +++++++++++++----- src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 | 150 ++++--- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 8 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 23 + .../cpu/aarch64/macroAssembler_aarch64.hpp | 96 +++++ .../cpu/aarch64/nativeInst_aarch64.hpp | 23 + 6 files changed, 540 insertions(+), 164 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 2ff93c9e288..b9899995531 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -1671,24 +1671,42 @@ instruct vnotL(vReg dst, vReg src, immL_M1 m1) %{ // vector not - predicated -instruct vnotI_masked(vReg dst_src, immI_M1 m1, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vnotI_masked(vReg dst, vReg src, immI_M1 m1, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (XorV (Binary dst_src (Replicate m1)) pg)); - format %{ "vnotI_masked $dst_src, $pg, $dst_src" %} + match(Set dst (XorV (Binary src (Replicate m1)) pg)); + format %{ "vnotI_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_not($dst_src$$FloatRegister, get_reg_variant(this), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_not($dst$$FloatRegister, get_reg_variant(this), + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vnotL_masked(vReg dst_src, immL_M1 m1, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vnotL_masked(vReg dst, vReg src, immL_M1 m1, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (XorV (Binary dst_src (Replicate m1)) pg)); - format %{ "vnotL_masked $dst_src, $pg, $dst_src" %} + match(Set dst (XorV (Binary src (Replicate m1)) pg)); + format %{ "vnotL_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_not($dst_src$$FloatRegister, get_reg_variant(this), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_not($dst$$FloatRegister, get_reg_variant(this), + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -1985,62 +2003,116 @@ instruct vabsD(vReg dst, vReg src) %{ // vector abs - predicated -instruct vabsB_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vabsB_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (AbsVB dst_src pg)); - format %{ "vabsB_masked $dst_src, $pg, $dst_src" %} + match(Set dst (AbsVB src pg)); + format %{ "vabsB_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_abs($dst_src$$FloatRegister, __ B, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_abs($dst$$FloatRegister, __ B, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vabsS_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vabsS_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (AbsVS dst_src pg)); - format %{ "vabsS_masked $dst_src, $pg, $dst_src" %} + match(Set dst (AbsVS src pg)); + format %{ "vabsS_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_abs($dst_src$$FloatRegister, __ H, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_abs($dst$$FloatRegister, __ H, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vabsI_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vabsI_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (AbsVI dst_src pg)); - format %{ "vabsI_masked $dst_src, $pg, $dst_src" %} + match(Set dst (AbsVI src pg)); + format %{ "vabsI_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_abs($dst_src$$FloatRegister, __ S, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_abs($dst$$FloatRegister, __ S, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vabsL_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vabsL_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (AbsVL dst_src pg)); - format %{ "vabsL_masked $dst_src, $pg, $dst_src" %} + match(Set dst (AbsVL src pg)); + format %{ "vabsL_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_abs($dst_src$$FloatRegister, __ D, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_abs($dst$$FloatRegister, __ D, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vabsF_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vabsF_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (AbsVF dst_src pg)); - format %{ "vabsF_masked $dst_src, $pg, $dst_src" %} + match(Set dst (AbsVF src pg)); + format %{ "vabsF_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_fabs($dst_src$$FloatRegister, __ S, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_fabs($dst$$FloatRegister, __ S, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vabsD_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vabsD_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (AbsVD dst_src pg)); - format %{ "vabsD_masked $dst_src, $pg, $dst_src" %} + match(Set dst (AbsVD src pg)); + format %{ "vabsD_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_fabs($dst_src$$FloatRegister, __ D, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_fabs($dst$$FloatRegister, __ D, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -2158,44 +2230,80 @@ instruct vnegD(vReg dst, vReg src) %{ // vector neg - predicated -instruct vnegI_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vnegI_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (NegVI dst_src pg)); - format %{ "vnegI_masked $dst_src, $pg, $dst_src" %} + match(Set dst (NegVI src pg)); + format %{ "vnegI_masked $dst, $pg, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); - __ sve_neg($dst_src$$FloatRegister, __ elemType_to_regVariant(bt), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_neg($dst$$FloatRegister, __ elemType_to_regVariant(bt), + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vnegL_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vnegL_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (NegVL dst_src pg)); - format %{ "vnegL_masked $dst_src, $pg, $dst_src" %} + match(Set dst (NegVL src pg)); + format %{ "vnegL_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_neg($dst_src$$FloatRegister, __ D, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_neg($dst$$FloatRegister, __ D, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vnegF_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vnegF_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (NegVF dst_src pg)); - format %{ "vnegF_masked $dst_src, $pg, $dst_src" %} + match(Set dst (NegVF src pg)); + format %{ "vnegF_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_fneg($dst_src$$FloatRegister, __ S, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_fneg($dst$$FloatRegister, __ S, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vnegD_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vnegD_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (NegVD dst_src pg)); - format %{ "vnegD_masked $dst_src, $pg, $dst_src" %} + match(Set dst (NegVD src pg)); + format %{ "vnegD_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_fneg($dst_src$$FloatRegister, __ D, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_fneg($dst$$FloatRegister, __ D, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -2251,22 +2359,40 @@ instruct vsqrtD(vReg dst, vReg src) %{ // vector sqrt - predicated -instruct vsqrtF_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vsqrtF_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (SqrtVF dst_src pg)); - format %{ "vsqrtF_masked $dst_src, $pg, $dst_src" %} + match(Set dst (SqrtVF src pg)); + format %{ "vsqrtF_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_fsqrt($dst_src$$FloatRegister, __ S, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_fsqrt($dst$$FloatRegister, __ S, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vsqrtD_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vsqrtD_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (SqrtVD dst_src pg)); - format %{ "vsqrtD_masked $dst_src, $pg, $dst_src" %} + match(Set dst (SqrtVD src pg)); + format %{ "vsqrtD_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_fsqrt($dst_src$$FloatRegister, __ D, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_fsqrt($dst$$FloatRegister, __ D, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -5331,9 +5457,7 @@ instruct insertI_index_lt32(vReg dst, vReg src, iRegIorL2I val, immI idx, __ sve_index($tmp$$FloatRegister, size, -16, 1); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, size, ptrue, $tmp$$FloatRegister, (int)($idx$$constant) - 16); - if ($dst$$FloatRegister != $src$$FloatRegister) { - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); - } + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, size, $pgtmp$$PRegister, $val$$Register); %} ins_pipe(pipe_slow); @@ -5356,9 +5480,7 @@ instruct insertI_index_ge32(vReg dst, vReg src, iRegIorL2I val, immI idx, vReg t __ sve_dup($tmp2$$FloatRegister, size, (int)($idx$$constant)); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, size, ptrue, $tmp1$$FloatRegister, $tmp2$$FloatRegister); - if ($dst$$FloatRegister != $src$$FloatRegister) { - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); - } + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, size, $pgtmp$$PRegister, $val$$Register); %} ins_pipe(pipe_slow); @@ -5392,9 +5514,7 @@ instruct insertL_gt128b(vReg dst, vReg src, iRegL val, immI idx, __ sve_index($tmp$$FloatRegister, __ D, -16, 1); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ D, ptrue, $tmp$$FloatRegister, (int)($idx$$constant) - 16); - if ($dst$$FloatRegister != $src$$FloatRegister) { - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); - } + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, __ D, $pgtmp$$PRegister, $val$$Register); %} ins_pipe(pipe_slow); @@ -5432,7 +5552,7 @@ instruct insertF_index_lt32(vReg dst, vReg src, vRegF val, immI idx, __ sve_index($dst$$FloatRegister, __ S, -16, 1); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ S, ptrue, $dst$$FloatRegister, (int)($idx$$constant) - 16); - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); + __ sve_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, __ S, $pgtmp$$PRegister, $val$$FloatRegister); %} ins_pipe(pipe_slow); @@ -5451,7 +5571,7 @@ instruct insertF_index_ge32(vReg dst, vReg src, vRegF val, immI idx, vReg tmp, __ sve_dup($dst$$FloatRegister, __ S, (int)($idx$$constant)); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ S, ptrue, $tmp$$FloatRegister, $dst$$FloatRegister); - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); + __ sve_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, __ S, $pgtmp$$PRegister, $val$$FloatRegister); %} ins_pipe(pipe_slow); @@ -5486,7 +5606,7 @@ instruct insertD_gt128b(vReg dst, vReg src, vRegD val, immI idx, __ sve_index($dst$$FloatRegister, __ D, -16, 1); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ D, ptrue, $dst$$FloatRegister, (int)($idx$$constant) - 16); - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); + __ sve_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, __ D, $pgtmp$$PRegister, $val$$FloatRegister); %} ins_pipe(pipe_slow); @@ -5656,8 +5776,12 @@ instruct extractF(vRegF dst, vReg src, immI idx) %{ __ ins($dst$$FloatRegister, __ S, $src$$FloatRegister, 0, index); } else { assert(UseSVE > 0, "must be sve"); - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); - __ sve_ext($dst$$FloatRegister, $dst$$FloatRegister, index << 2); + __ sve_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the second source of ext. The movprfx destination register + // must not appear in any source operand of the following instruction + // except as the destructive operand. + __ sve_ext($dst$$FloatRegister, $src$$FloatRegister, index << 2); } %} ins_pipe(pipe_slow); @@ -5677,8 +5801,12 @@ instruct extractD(vRegD dst, vReg src, immI idx) %{ __ ins($dst$$FloatRegister, __ D, $src$$FloatRegister, 0, index); } else { assert(UseSVE > 0, "must be sve"); - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); - __ sve_ext($dst$$FloatRegister, $dst$$FloatRegister, index << 3); + __ sve_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the second source of ext. The movprfx destination register + // must not appear in any source operand of the following instruction + // except as the destructive operand. + __ sve_ext($dst$$FloatRegister, $src$$FloatRegister, index << 3); } %} ins_pipe(pipe_slow); @@ -6855,25 +6983,43 @@ instruct vpopcountL(vReg dst, vReg src) %{ // vector popcount - predicated -instruct vpopcountI_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vpopcountI_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (PopCountVI dst_src pg)); - format %{ "vpopcountI_masked $dst_src, $pg, $dst_src" %} + match(Set dst (PopCountVI src pg)); + format %{ "vpopcountI_masked $dst, $pg, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); - __ sve_cnt($dst_src$$FloatRegister, __ elemType_to_regVariant(bt), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_cnt($dst$$FloatRegister, __ elemType_to_regVariant(bt), + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} -instruct vpopcountL_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vpopcountL_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (PopCountVL dst_src pg)); - format %{ "vpopcountL_masked $dst_src, $pg, $dst_src" %} + match(Set dst (PopCountVL src pg)); + format %{ "vpopcountL_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_cnt($dst_src$$FloatRegister, __ D, - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_cnt($dst$$FloatRegister, __ D, + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -7240,14 +7386,23 @@ instruct vcountLeadingZeros(vReg dst, vReg src) %{ // The dst and src should use the same register to make sure the // inactive lanes in dst save the same elements as src. -instruct vcountLeadingZeros_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vcountLeadingZeros_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (CountLeadingZerosV dst_src pg)); - format %{ "vcountLeadingZeros_masked $dst_src, $pg, $dst_src" %} + match(Set dst (CountLeadingZerosV src pg)); + format %{ "vcountLeadingZeros_masked $dst, $pg, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); - __ sve_clz($dst_src$$FloatRegister, __ elemType_to_regVariant(bt), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_clz($dst$$FloatRegister, __ elemType_to_regVariant(bt), + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -7296,19 +7451,26 @@ instruct vcountTrailingZeros(vReg dst, vReg src) %{ ins_pipe(pipe_slow); %} -// The dst and src should use the same register to make sure the -// inactive lanes in dst save the same elements as src. -instruct vcountTrailingZeros_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vcountTrailingZeros_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (CountTrailingZerosV dst_src pg)); - format %{ "vcountTrailingZeros_masked $dst_src, $pg, $dst_src" %} + match(Set dst (CountTrailingZerosV src pg)); + format %{ "vcountTrailingZeros_masked $dst, $pg, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt); - __ sve_rbit($dst_src$$FloatRegister, size, - $pg$$PRegister, $dst_src$$FloatRegister); - __ sve_clz($dst_src$$FloatRegister, size, - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_rbit($dst$$FloatRegister, size, + $pg$$PRegister, $src$$FloatRegister); + __ sve_clz($dst$$FloatRegister, size, + $pg$$PRegister, $dst$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -7347,14 +7509,23 @@ instruct vreverse(vReg dst, vReg src) %{ // The dst and src should use the same register to make sure the // inactive lanes in dst save the same elements as src. -instruct vreverse_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vreverse_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (ReverseV dst_src pg)); - format %{ "vreverse_masked $dst_src, $pg, $dst_src" %} + match(Set dst (ReverseV src pg)); + format %{ "vreverse_masked $dst, $pg, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); - __ sve_rbit($dst_src$$FloatRegister, __ elemType_to_regVariant(bt), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_rbit($dst$$FloatRegister, __ elemType_to_regVariant(bt), + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -7393,19 +7564,28 @@ instruct vreverseBytes(vReg dst, vReg src) %{ ins_pipe(pipe_slow); %} -// The dst and src should use the same register to make sure the -// inactive lanes in dst save the same elements as src. -instruct vreverseBytes_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vreverseBytes_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (ReverseBytesV dst_src pg)); - format %{ "vreverseBytes_masked $dst_src, $pg, $dst_src" %} + match(Set dst (ReverseBytesV src pg)); + format %{ "vreverseBytes_masked $dst, $pg, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); if (bt == T_BYTE) { - // do nothing + if ($dst$$FloatRegister != $src$$FloatRegister) { + __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); + } } else { - __ sve_revb($dst_src$$FloatRegister, __ elemType_to_regVariant(bt), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_revb($dst$$FloatRegister, __ elemType_to_regVariant(bt), + $pg$$PRegister, $src$$FloatRegister); } %} ins_pipe(pipe_slow); diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index c5df949dfb6..a53efd43d5d 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -899,13 +899,22 @@ dnl dnl VECTOR_NOT_PREDICATE($1 ) dnl VECTOR_NOT_PREDICATE(type) define(`VECTOR_NOT_PREDICATE', ` -instruct vnot$1_masked`'(vReg dst_src, imm$1_M1 m1, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vnot$1_masked`'(vReg dst, vReg src, imm$1_M1 m1, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (XorV (Binary dst_src (Replicate m1)) pg)); - format %{ "vnot$1_masked $dst_src, $pg, $dst_src" %} + match(Set dst (XorV (Binary src (Replicate m1)) pg)); + format %{ "vnot$1_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_not($dst_src$$FloatRegister, get_reg_variant(this), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_not($dst$$FloatRegister, get_reg_variant(this), + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %}')dnl @@ -1042,14 +1051,23 @@ dnl dnl UNARY_OP_PREDICATE($1, $2, $3 ) dnl UNARY_OP_PREDICATE(rule_name, op_name, insn) define(`UNARY_OP_PREDICATE', ` -instruct $1_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct $1_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src ($2 dst_src pg)); - format %{ "$1_masked $dst_src, $pg, $dst_src" %} + match(Set dst ($2 src pg)); + format %{ "$1_masked $dst, $pg, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); - __ $3($dst_src$$FloatRegister, __ elemType_to_regVariant(bt), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ $3($dst$$FloatRegister, __ elemType_to_regVariant(bt), + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %}')dnl @@ -1057,12 +1075,21 @@ dnl dnl UNARY_OP_PREDICATE_WITH_SIZE($1, $2, $3, $4 ) dnl UNARY_OP_PREDICATE_WITH_SIZE(rule_name, op_name, insn, size) define(`UNARY_OP_PREDICATE_WITH_SIZE', ` -instruct $1_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct $1_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src ($2 dst_src pg)); - format %{ "$1_masked $dst_src, $pg, $dst_src" %} + match(Set dst ($2 src pg)); + format %{ "$1_masked $dst, $pg, $src" %} ins_encode %{ - __ $3($dst_src$$FloatRegister, __ $4, $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ $3($dst$$FloatRegister, __ $4, $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %}')dnl @@ -3368,9 +3395,7 @@ instruct insertI_index_lt32(vReg dst, vReg src, iRegIorL2I val, immI idx, __ sve_index($tmp$$FloatRegister, size, -16, 1); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, size, ptrue, $tmp$$FloatRegister, (int)($idx$$constant) - 16); - if ($dst$$FloatRegister != $src$$FloatRegister) { - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); - } + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, size, $pgtmp$$PRegister, $val$$Register); %} ins_pipe(pipe_slow); @@ -3393,9 +3418,7 @@ instruct insertI_index_ge32(vReg dst, vReg src, iRegIorL2I val, immI idx, vReg t __ sve_dup($tmp2$$FloatRegister, size, (int)($idx$$constant)); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, size, ptrue, $tmp1$$FloatRegister, $tmp2$$FloatRegister); - if ($dst$$FloatRegister != $src$$FloatRegister) { - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); - } + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, size, $pgtmp$$PRegister, $val$$Register); %} ins_pipe(pipe_slow); @@ -3429,9 +3452,7 @@ instruct insertL_gt128b(vReg dst, vReg src, iRegL val, immI idx, __ sve_index($tmp$$FloatRegister, __ D, -16, 1); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ D, ptrue, $tmp$$FloatRegister, (int)($idx$$constant) - 16); - if ($dst$$FloatRegister != $src$$FloatRegister) { - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); - } + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, __ D, $pgtmp$$PRegister, $val$$Register); %} ins_pipe(pipe_slow); @@ -3469,7 +3490,7 @@ instruct insertF_index_lt32(vReg dst, vReg src, vRegF val, immI idx, __ sve_index($dst$$FloatRegister, __ S, -16, 1); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ S, ptrue, $dst$$FloatRegister, (int)($idx$$constant) - 16); - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); + __ sve_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, __ S, $pgtmp$$PRegister, $val$$FloatRegister); %} ins_pipe(pipe_slow); @@ -3488,7 +3509,7 @@ instruct insertF_index_ge32(vReg dst, vReg src, vRegF val, immI idx, vReg tmp, __ sve_dup($dst$$FloatRegister, __ S, (int)($idx$$constant)); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ S, ptrue, $tmp$$FloatRegister, $dst$$FloatRegister); - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); + __ sve_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, __ S, $pgtmp$$PRegister, $val$$FloatRegister); %} ins_pipe(pipe_slow); @@ -3523,7 +3544,7 @@ instruct insertD_gt128b(vReg dst, vReg src, vRegD val, immI idx, __ sve_index($dst$$FloatRegister, __ D, -16, 1); __ sve_cmp(Assembler::EQ, $pgtmp$$PRegister, __ D, ptrue, $dst$$FloatRegister, (int)($idx$$constant) - 16); - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); + __ sve_movprfx($dst$$FloatRegister, $src$$FloatRegister); __ sve_cpy($dst$$FloatRegister, __ D, $pgtmp$$PRegister, $val$$FloatRegister); %} ins_pipe(pipe_slow); @@ -3621,8 +3642,12 @@ instruct extract$1(vReg$1 dst, vReg src, immI idx) %{ __ ins($dst$$FloatRegister, __ $4, $src$$FloatRegister, 0, index); } else { assert(UseSVE > 0, "must be sve"); - __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); - __ sve_ext($dst$$FloatRegister, $dst$$FloatRegister, index << $5); + __ sve_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the second source of ext. The movprfx destination register + // must not appear in any source operand of the following instruction + // except as the destructive operand. + __ sve_ext($dst$$FloatRegister, $src$$FloatRegister, index << $5); } %} ins_pipe(pipe_slow); @@ -4682,13 +4707,22 @@ instruct vpopcountL(vReg dst, vReg src) %{ // vector popcount - predicated UNARY_OP_PREDICATE(vpopcountI, PopCountVI, sve_cnt) -instruct vpopcountL_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vpopcountL_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (PopCountVL dst_src pg)); - format %{ "vpopcountL_masked $dst_src, $pg, $dst_src" %} + match(Set dst (PopCountVL src pg)); + format %{ "vpopcountL_masked $dst, $pg, $src" %} ins_encode %{ - __ sve_cnt($dst_src$$FloatRegister, __ D, - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_cnt($dst$$FloatRegister, __ D, + $pg$$PRegister, $src$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -5100,19 +5134,26 @@ instruct vcountTrailingZeros(vReg dst, vReg src) %{ ins_pipe(pipe_slow); %} -// The dst and src should use the same register to make sure the -// inactive lanes in dst save the same elements as src. -instruct vcountTrailingZeros_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vcountTrailingZeros_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (CountTrailingZerosV dst_src pg)); - format %{ "vcountTrailingZeros_masked $dst_src, $pg, $dst_src" %} + match(Set dst (CountTrailingZerosV src pg)); + format %{ "vcountTrailingZeros_masked $dst, $pg, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); Assembler::SIMD_RegVariant size = __ elemType_to_regVariant(bt); - __ sve_rbit($dst_src$$FloatRegister, size, - $pg$$PRegister, $dst_src$$FloatRegister); - __ sve_clz($dst_src$$FloatRegister, size, - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_rbit($dst$$FloatRegister, size, + $pg$$PRegister, $src$$FloatRegister); + __ sve_clz($dst$$FloatRegister, size, + $pg$$PRegister, $dst$$FloatRegister); %} ins_pipe(pipe_slow); %} @@ -5186,19 +5227,28 @@ instruct vreverseBytes(vReg dst, vReg src) %{ ins_pipe(pipe_slow); %} -// The dst and src should use the same register to make sure the -// inactive lanes in dst save the same elements as src. -instruct vreverseBytes_masked(vReg dst_src, pRegGov pg) %{ +// The Java Vector API specification requires that for masked unary operations, +// suppressed lanes are filled from the first vector operand (see "Masked +// Operations" in Vector.java around line 568). So we use movprfx to copy src +// into dst before emitting the predicated instruction. +instruct vreverseBytes_masked(vReg dst, vReg src, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src (ReverseBytesV dst_src pg)); - format %{ "vreverseBytes_masked $dst_src, $pg, $dst_src" %} + match(Set dst (ReverseBytesV src pg)); + format %{ "vreverseBytes_masked $dst, $pg, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); if (bt == T_BYTE) { - // do nothing + if ($dst$$FloatRegister != $src$$FloatRegister) { + __ sve_orr($dst$$FloatRegister, $src$$FloatRegister, $src$$FloatRegister); + } } else { - __ sve_revb($dst_src$$FloatRegister, __ elemType_to_regVariant(bt), - $pg$$PRegister, $dst_src$$FloatRegister); + __ maybe_movprfx($dst$$FloatRegister, $src$$FloatRegister); + // Although dst and src hold the same value after movprfx, we must use src + // (not dst) as the source of the following instruction. The movprfx + // destination register must not appear in any source operand of the + // following instruction except as the destructive operand. + __ sve_revb($dst$$FloatRegister, __ elemType_to_regVariant(bt), + $pg$$PRegister, $src$$FloatRegister); } %} ins_pipe(pipe_slow); diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 67dc4966d64..cb9e308197e 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -2494,8 +2494,12 @@ void C2_MacroAssembler::sve_extract_integral(Register dst, BasicType bt, FloatRe smov(dst, src, size, idx); } } else { - sve_orr(vtmp, src, src); - sve_ext(vtmp, vtmp, idx << size); + sve_movprfx(vtmp, src); + // Although vtmp and src hold the same value after movprfx, we must use src + // (not vtmp) as the second source of ext. The movprfx destination register + // must not appear in any source operand of the following instruction except + // as the destructive operand. + sve_ext(vtmp, src, idx << size); if (bt == T_INT || bt == T_LONG) { umov(dst, vtmp, size, 0); } else { diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index a52ad112560..ac5bae22384 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -7278,3 +7278,26 @@ void MacroAssembler::neon_vector_rotate(FloatRegister dst, SIMD_Arrangement T, sli(dst, T, src, lshift); } } + +void MacroAssembler::try_to_replace_prev_vector_copy_with_movprfx(FloatRegister dst) { + if (code_section()->is_empty()) { + return; + } + + address prev = pc() - NativeInstruction::instruction_size; + uint32_t insn = nativeInstruction_at(prev)->encoding(); + if (!NativeInstruction::is_neon_vector_mov_alias(insn) && + !NativeInstruction::is_sve_vector_mov_alias(insn)) { + return; + } + + // The destructive instruction must reuse the mov alias destination. + uint32_t rd = Instruction_aarch64::extract(insn, 4, 0); + if (rd != (uint32_t)dst->encoding()) { + return; + } + + uint32_t rn = Instruction_aarch64::extract(insn, 9, 5); + Instruction_aarch64::patch(prev, 31, 0, + NativeInstruction::encode_sve_movprfx(rd, rn)); +} diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index ad8827bd9c0..b1050b45731 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1734,7 +1734,103 @@ public: private: // Check the current thread doesn't need a cross modify fence. void verify_cross_modify_fence_not_required() PRODUCT_RETURN; + void try_to_replace_prev_vector_copy_with_movprfx(FloatRegister dst); +public: + void maybe_movprfx(FloatRegister dst, FloatRegister src) { + if (dst != src) { + sve_movprfx(dst, src); + } + } + +// Wrappers for SVE explicit destructive instructions, overriding the +// same-signature Assembler entry points to enable movprfx fusion optimization. +// +// Implicit destructive instructions (e.g. predicated unary ops like sve_abs/ +// sve_neg/sve_not, whose ISA encoding allows Zd != Zn but whose use as a Java +// Vector API masked operation requires pass-through of the first source) are +// not covered here. For those, the .ad file is responsible for emitting +// movprfx explicitly via maybe_movprfx() before the destructive op. +#define SVE_DESTRUCTIVE_BINARY_INS(NAME) \ + using Assembler::NAME; \ + void NAME(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, \ + FloatRegister Zm) { \ + if (Zd != Zm) { \ + try_to_replace_prev_vector_copy_with_movprfx(Zd); \ + } \ + Assembler::NAME(Zd, T, Pg, Zm); \ + } + +#define SVE_DESTRUCTIVE_BINARY_5(I1, I2, I3, I4, I5) \ + SVE_DESTRUCTIVE_BINARY_INS(I1); SVE_DESTRUCTIVE_BINARY_INS(I2); \ + SVE_DESTRUCTIVE_BINARY_INS(I3); SVE_DESTRUCTIVE_BINARY_INS(I4); \ + SVE_DESTRUCTIVE_BINARY_INS(I5); + + SVE_DESTRUCTIVE_BINARY_5(sve_add, sve_and, sve_asr, sve_bic, sve_eor) + SVE_DESTRUCTIVE_BINARY_5(sve_fabd, sve_fadd, sve_fdiv, sve_fmax, sve_fmin) + SVE_DESTRUCTIVE_BINARY_5(sve_fmul, sve_fsub, sve_lsl, sve_lsr, sve_mul) + SVE_DESTRUCTIVE_BINARY_5(sve_orr, sve_smax, sve_smin, sve_sqadd, sve_sqsub) + SVE_DESTRUCTIVE_BINARY_5(sve_sub, sve_uqadd, sve_uqsub, sve_umax, sve_umin) + +#undef SVE_DESTRUCTIVE_BINARY_INS +#undef SVE_DESTRUCTIVE_BINARY_5 + +#define SVE_DESTRUCTIVE_SHIFT_IMM_INS(NAME) \ + void NAME(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, int shift) { \ + try_to_replace_prev_vector_copy_with_movprfx(Zd); \ + Assembler::NAME(Zd, T, Pg, shift); \ + } + + SVE_DESTRUCTIVE_SHIFT_IMM_INS(sve_asr); + SVE_DESTRUCTIVE_SHIFT_IMM_INS(sve_lsl); + SVE_DESTRUCTIVE_SHIFT_IMM_INS(sve_lsr); + +#undef SVE_DESTRUCTIVE_SHIFT_IMM_INS + +#define SVE_DESTRUCTIVE_UNPRED_IMM_INS(NAME, IMM_TYPE) \ + void NAME(FloatRegister Zd, SIMD_RegVariant T, IMM_TYPE imm) { \ + try_to_replace_prev_vector_copy_with_movprfx(Zd); \ + Assembler::NAME(Zd, T, imm); \ + } + + SVE_DESTRUCTIVE_UNPRED_IMM_INS(sve_add, unsigned); + SVE_DESTRUCTIVE_UNPRED_IMM_INS(sve_sub, unsigned); + SVE_DESTRUCTIVE_UNPRED_IMM_INS(sve_and, uint64_t); + SVE_DESTRUCTIVE_UNPRED_IMM_INS(sve_eor, uint64_t); + SVE_DESTRUCTIVE_UNPRED_IMM_INS(sve_orr, uint64_t); + +#undef SVE_DESTRUCTIVE_UNPRED_IMM_INS + +#define SVE_DESTRUCTIVE_TERNARY_INS(NAME) \ + using Assembler::NAME; \ + void NAME(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, \ + FloatRegister Zn, FloatRegister Zm) { \ + if (Zd != Zn && Zd != Zm) { \ + try_to_replace_prev_vector_copy_with_movprfx(Zd); \ + } \ + Assembler::NAME(Zd, T, Pg, Zn, Zm); \ + } + + SVE_DESTRUCTIVE_TERNARY_INS(sve_fmad); + SVE_DESTRUCTIVE_TERNARY_INS(sve_fmla); + SVE_DESTRUCTIVE_TERNARY_INS(sve_fmls); + SVE_DESTRUCTIVE_TERNARY_INS(sve_fmsb); + SVE_DESTRUCTIVE_TERNARY_INS(sve_fnmad); + SVE_DESTRUCTIVE_TERNARY_INS(sve_fnmla); + SVE_DESTRUCTIVE_TERNARY_INS(sve_fnmls); + SVE_DESTRUCTIVE_TERNARY_INS(sve_fnmsb); + SVE_DESTRUCTIVE_TERNARY_INS(sve_mla); + SVE_DESTRUCTIVE_TERNARY_INS(sve_mls); + +#undef SVE_DESTRUCTIVE_TERNARY_INS + + using Assembler::sve_eor3; + void sve_eor3(FloatRegister Zd, FloatRegister Zm, FloatRegister Zk) { + if (Zd != Zm && Zd != Zk) { + try_to_replace_prev_vector_copy_with_movprfx(Zd); + } + Assembler::sve_eor3(Zd, Zm, Zk); + } }; #ifdef ASSERT diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index 4bccbc59582..57bb9a91533 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -140,6 +140,29 @@ public: Instruction_aarch64::extract(insn, 23, 23) == 0b0 && Instruction_aarch64::extract(insn, 26, 25) == 0b00; } + + static bool is_neon_vector_mov_alias(uint32_t insn) { + if (Instruction_aarch64::extract(insn, 31, 31) != 0 || + Instruction_aarch64::extract(insn, 29, 21) != 0b001110101 || + Instruction_aarch64::extract(insn, 15, 10) != 0b000111) { + return false; + } + return Instruction_aarch64::extract(insn, 9, 5) == + Instruction_aarch64::extract(insn, 20, 16); + } + + static bool is_sve_vector_mov_alias(uint32_t insn) { + if (Instruction_aarch64::extract(insn, 31, 21) != 0b00000100011 || + Instruction_aarch64::extract(insn, 15, 10) != 0b001100) { + return false; + } + return Instruction_aarch64::extract(insn, 9, 5) == + Instruction_aarch64::extract(insn, 20, 16); + } + + static uint32_t encode_sve_movprfx(uint32_t dst, uint32_t src) { + return 0x1082f << 10 | (src << 5) | dst; + } }; inline NativeInstruction* nativeInstruction_at(address address) { From 3f8a7213efc383cf8d4cd323a5c3a9f163a311f3 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Tue, 2 Jun 2026 08:47:44 +0000 Subject: [PATCH 026/115] 8385664: Stale comment about JDK-6996415 Reviewed-by: vromero --- .../share/classes/com/sun/tools/javac/comp/TransTypes.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java index 1229939c0bf..86bdc5ac7b7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -248,9 +248,6 @@ public class TransTypes extends TreeTranslator { meth.name, bridgeType, origin); - /* once JDK-6996415 is solved it should be checked if this approach can - * be applied to method addOverrideBridgesIfNeeded - */ bridge.params = createBridgeParams(impl, bridge, bridgeType); bridge.setAttributes(impl); From 3efa011b968f3a7a8232526e92b85db361b275ce Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 2 Jun 2026 13:29:16 +0000 Subject: [PATCH 027/115] 8385648: PPC64: Improve receiver type profiling reliability Reviewed-by: shade, dbriemann --- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 97 ++---------- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp | 2 +- src/hotspot/cpu/ppc/interp_masm_ppc.hpp | 4 +- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 86 +--------- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 167 ++++++++++++++++++++ src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 6 + 6 files changed, 192 insertions(+), 170 deletions(-) diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index a9f34b148c6..1270471d150 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2226,39 +2226,12 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { } +// kills recv void LIR_Assembler::type_profile_helper(Register mdo, int mdo_offset_bias, ciMethodData *md, ciProfileData *data, - Register recv, Register tmp1, Label* update_done) { - uint i; - for (i = 0; i < VirtualCallData::row_limit(); i++) { - Label next_test; - // See if the receiver is receiver[n]. - __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo); - __ verify_klass_ptr(tmp1); - __ cmpd(CR0, recv, tmp1); - __ bne(CR0, next_test); - - __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo); - __ addi(tmp1, tmp1, DataLayout::counter_increment); - __ std(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo); - __ b(*update_done); - - __ bind(next_test); - } - - // Didn't find receiver; find next empty slot and fill it in. - for (i = 0; i < VirtualCallData::row_limit(); i++) { - Label next_test; - __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo); - __ cmpdi(CR0, tmp1, 0); - __ bne(CR0, next_test); - __ li(tmp1, DataLayout::counter_increment); - __ std(recv, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo); - __ std(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo); - __ b(*update_done); - - __ bind(next_test); - } + Register recv, Register tmp) { + int mdp_offset = md->byte_offset_of_slot(data, in_ByteSize(0)) - mdo_offset_bias; + __ profile_receiver_type(recv, mdo, mdp_offset, tmp, noreg); } @@ -2320,15 +2293,9 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L __ b(*obj_is_null); __ bind(not_null); - Label update_done; Register recv = klass_RInfo; __ load_klass(recv, obj); - type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1, &update_done); - const int slot_offset = md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias; - __ ld(Rtmp1, slot_offset, mdo); - __ addi(Rtmp1, Rtmp1, DataLayout::counter_increment); - __ std(Rtmp1, slot_offset, mdo); - __ bind(update_done); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1); // kills recv } else { __ cmpdi(CR0, obj, 0); __ beq(CR0, *obj_is_null); @@ -2427,15 +2394,9 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ b(done); __ bind(not_null); - Label update_done; Register recv = klass_RInfo; __ load_klass(recv, value); - type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1, &update_done); - const int slot_offset = md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias; - __ ld(Rtmp1, slot_offset, mdo); - __ addi(Rtmp1, Rtmp1, DataLayout::counter_increment); - __ std(Rtmp1, slot_offset, mdo); - __ bind(update_done); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1); // kills recv } else { __ cmpdi(CR0, value, 0); __ beq(CR0, done); @@ -2648,55 +2609,27 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { // We know the type that will be seen at this call site; we can // statically update the MethodData* rather than needing to do // dynamic tests on the receiver type. - - // NOTE: we should probably put a lock around this search to - // avoid collisions by concurrent compilations. ciVirtualCallData* vc_data = (ciVirtualCallData*) data; - uint i; - for (i = 0; i < VirtualCallData::row_limit(); i++) { + for (uint i = 0; i < VirtualCallData::row_limit(); i++) { ciKlass* receiver = vc_data->receiver(i); if (known_klass->equals(receiver)) { - __ ld(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); - __ addi(tmp1, tmp1, DataLayout::counter_increment); - __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ increment_mem64(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, + DataLayout::counter_increment, tmp1); return; } } - // Receiver type not found in profile data; select an empty slot. - - // Note that this is less efficient than it should be because it - // always does a write to the receiver part of the - // VirtualCallData rather than just the first time. - for (i = 0; i < VirtualCallData::row_limit(); i++) { - ciKlass* receiver = vc_data->receiver(i); - if (receiver == nullptr) { - metadata2reg(known_klass->constant_encoding(), tmp1); - __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) - mdo_offset_bias, mdo); - - __ ld(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); - __ addi(tmp1, tmp1, DataLayout::counter_increment); - __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); - return; - } - } + // Receiver type is not found in profile data. + // Fall back to runtime helper to handle the rest at runtime. + metadata2reg(known_klass->constant_encoding(), recv); } else { __ load_klass(recv, recv); - Label update_done; - type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &update_done); - // Receiver did not match any saved receiver and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); - __ addi(tmp1, tmp1, DataLayout::counter_increment); - __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); - - __ bind(update_done); } + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1); // kills recv } else { // Static call - __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); - __ addi(tmp1, tmp1, DataLayout::counter_increment); - __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + __ increment_mem64(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, + DataLayout::counter_increment, tmp1); } } diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp index 7399a4544e6..5a065d364b2 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp @@ -52,7 +52,7 @@ friend class ArrayCopyStub; // Record the type of the receiver in ReceiverTypeData. void type_profile_helper(Register mdo, int mdo_offset_bias, ciMethodData *md, ciProfileData *data, - Register recv, Register tmp1, Label* update_done); + Register recv, Register tmp); // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot. void setup_md_access(ciMethod* method, int bci, ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp index 275ff92c699..45af9bfc252 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -264,8 +264,6 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_switch_default(Register scratch1, Register scratch2); void profile_switch_case(Register index, Register scratch1,Register scratch2, Register scratch3); void profile_null_seen(Register Rscratch1, Register Rscratch2); - void record_klass_in_profile(Register receiver, Register scratch1, Register scratch2); - void record_klass_in_profile_helper(Register receiver, Register scratch1, Register scratch2, int start_row, Label& done); // Argument and return type profiling. void profile_obj_type(Register obj, Register mdo_addr_base, RegisterOrConstant mdo_addr_offs, Register tmp, Register tmp2); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index a1798289b62..789f8da9574 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -1348,7 +1348,7 @@ void InterpreterMacroAssembler::profile_virtual_call(Register Rreceiver, test_method_data_pointer(profile_continue); // Record the receiver type. - record_klass_in_profile(Rreceiver, Rscratch1, Rscratch2); + profile_receiver_type(Rreceiver, R28_mdx, 0, Rscratch1, Rscratch2); // The method data pointer needs to be updated to reflect the new target. update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); @@ -1367,7 +1367,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register Rklass, Register Rscr mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); // Record the object type. - record_klass_in_profile(Rklass, Rscratch1, Rscratch2); + profile_receiver_type(Rklass, R28_mdx, 0, Rscratch1, Rscratch2); } // The method data pointer needs to be updated. @@ -1481,88 +1481,6 @@ void InterpreterMacroAssembler::profile_null_seen(Register Rscratch1, Register R } } -void InterpreterMacroAssembler::record_klass_in_profile(Register Rreceiver, - Register Rscratch1, Register Rscratch2) { - assert(ProfileInterpreter, "must be profiling"); - assert_different_registers(Rreceiver, Rscratch1, Rscratch2); - - Label done; - record_klass_in_profile_helper(Rreceiver, Rscratch1, Rscratch2, 0, done); - bind (done); -} - -void InterpreterMacroAssembler::record_klass_in_profile_helper( - Register receiver, Register scratch1, Register scratch2, - int start_row, Label& done) { - if (TypeProfileWidth == 0) { - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); - return; - } - - int last_row = VirtualCallData::row_limit() - 1; - assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. - // Take any of three different outcomes: - // 1. found receiver => increment count and goto done - // 2. found null => keep looking for case 1, maybe allocate this cell - // 3. found something else => keep looking for cases 1 and 2 - // Case 3 is handled by a recursive call. - for (int row = start_row; row <= last_row; row++) { - Label next_test; - bool test_for_null_also = (row == start_row); - - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(recvr_offset, receiver, next_test, scratch1); - // delayed()->tst(scratch); - - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); - increment_mdp_data_at(count_offset, scratch1, scratch2); - b(done); - bind(next_test); - - if (test_for_null_also) { - Label found_null; - // Failed the equality check on receiver[n]... Test for null. - if (start_row == last_row) { - // The only thing left to do is handle the null case. - // Scratch1 contains test_out from test_mdp_data_at. - cmpdi(CR0, scratch1, 0); - beq(CR0, found_null); - // Receiver did not match any saved receiver and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2); - b(done); - bind(found_null); - break; - } - // Since null is rare, make it be the branch-taken case. - cmpdi(CR0, scratch1, 0); - beq(CR0, found_null); - - // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, scratch1, scratch2, start_row + 1, done); - - // Found a null. Keep searching for a matching receiver, - // but remember that this is an empty (unused) slot. - bind(found_null); - } - } - - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is null. - - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); - li(scratch1, DataLayout::counter_increment); - set_mdp_data_at(count_offset, scratch1); - if (start_row > 0) { - b(done); - } -} // Argument and return type profilig. // kills: tmp, tmp2, R0, CR0, CR1 diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 95d58d470c8..0d6c272decb 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -4329,6 +4329,173 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, bind(L_done); } // multiply_to_len +void MacroAssembler::increment_mem64(Register base, RegisterOrConstant ind_or_offs, int val, Register tmp) { + ld(tmp, ind_or_offs, base); + addi(tmp, tmp, val); + std(tmp, ind_or_offs, base); +} + +// Handle the receiver type profile update given the "recv" klass. +// +// Normally updates the ReceiverData (RD) that starts at "mdp" + "mdp_offset". +// If there are no matching or claimable receiver entries in RD, updates +// the polymorphic counter. +// +// This code expected to run by either the interpreter or JIT-ed code, without +// extra synchronization. For safety, receiver cells are claimed atomically, which +// avoids grossly misrepresenting the profiles under concurrent updates. For speed, +// counter updates are not atomic. +// +void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_offset, Register tmp1, Register tmp2) { + assert_different_registers(recv, mdp, tmp1, tmp2); + + int base_receiver_offset = in_bytes(ReceiverTypeData::receiver_offset(0)); + int poly_count_offset = in_bytes(CounterData::count_offset()); + int receiver_step = in_bytes(ReceiverTypeData::receiver_offset(1)) - base_receiver_offset; + int receiver_to_count_step = in_bytes(ReceiverTypeData::receiver_count_offset(0)) - base_receiver_offset; + + // Adjust for MDP offsets. + base_receiver_offset += mdp_offset; + poly_count_offset += mdp_offset; + +#ifdef ASSERT + // We are about to walk the MDO slots without asking for offsets. + // Check that our math hits all the right spots. + for (uint c = 0; c < ReceiverTypeData::row_limit(); c++) { + int real_recv_offset = mdp_offset + in_bytes(ReceiverTypeData::receiver_offset(c)); + int real_count_offset = mdp_offset + in_bytes(ReceiverTypeData::receiver_count_offset(c)); + int offset = base_receiver_offset + receiver_step*c; + int count_offset = offset + receiver_to_count_step; + assert(offset == real_recv_offset, "receiver slot math"); + assert(count_offset == real_count_offset, "receiver count math"); + } + int real_poly_count_offset = mdp_offset + in_bytes(CounterData::count_offset()); + assert(poly_count_offset == real_poly_count_offset, "poly counter math"); +#endif + + // Corner case: no profile table. Increment poly counter and exit. + if (ReceiverTypeData::row_limit() == 0) { + increment_mem64(mdp, poly_count_offset, DataLayout::counter_increment, tmp1); + return; + } + + Label L_loop_search_receiver, L_loop_search_empty; + Label L_restart, L_found_recv, L_found_empty, L_count_update; + Register offset = tmp1, count = tmp2; + + // The code here recognizes three major cases: + // A. Fastest: receiver found in the table + // B. Fast: no receiver in the table, and the table is full + // C. Slow: no receiver in the table, free slots in the table + // + // The case A performance is most important, as perfectly-behaved code would end up + // there, especially with larger TypeProfileWidth. The case B performance is + // important as well, this is where bulk of code would land for normally megamorphic + // cases. The case C performance is not essential, its job is to deal with installation + // races, we optimize for code density instead. Case C needs to make sure that receiver + // rows are only claimed once. This makes sure we never overwrite a row for another + // receiver and never duplicate the receivers in the list, making profile type-accurate. + // + // It is very tempting to handle these cases in a single loop, and claim the first slot + // without checking the rest of the table. But, profiling code should tolerate free slots + // in the table, as class unloading can clear them. After such cleanup, the receiver + // we need might be _after_ the free slot. Therefore, we need to let at least full scan + // to complete, before trying to install new slots. Splitting the code in several tight + // loops also helpfully optimizes for cases A and B. + // + // This code is effectively: + // + // restart: + // // Fastest: receiver is already installed + // for (i = 0; i < receiver_count(); i++) { + // if (receiver(i) == recv) goto found_recv(i); + // } + // + // // Fast: no receiver, but profile is full + // for (i = 0; i < receiver_count(); i++) { + // if (receiver(i) == null) goto found_null(i); + // } + // goto polymorphic + // + // // Slow: try to install receiver + // found_null(i): + // CAS(&receiver(i), null, recv); + // goto restart + // + // polymorphic: + // count++; + // return + // + // found_recv(i): + // *receiver_count(i)++ + // + + if (count != noreg) { + li(count, ReceiverTypeData::row_limit()); + } + + bind(L_restart); + + // Fastest: receiver is already installed + if (count != noreg) { + mtctr(count); + } else { + li(R0, ReceiverTypeData::row_limit()); + mtctr(R0); + } + li(offset, base_receiver_offset); + bind(L_loop_search_receiver); + ldx(R0, offset, mdp); + cmpd(CR0, R0, recv); + beq(CR0, L_found_recv); + addi(offset, offset, receiver_step); + bdnz(L_loop_search_receiver); + + // Fast: no receiver, but profile is full + if (count != noreg) { + mtctr(count); + } else { + li(R0, ReceiverTypeData::row_limit()); + mtctr(R0); + } + li(offset, base_receiver_offset); + bind(L_loop_search_empty); + ldx(R0, offset, mdp); + cmpdi(CR0, R0, 0); + beq(CR0, L_found_empty); + addi(offset, offset, receiver_step); + bdnz(L_loop_search_empty); + + // Polymorphic: Increment polymorphic counter instead of receiver slot. + li(offset, poly_count_offset); + b(L_count_update); + + // Slow: try to install receiver + bind(L_found_empty); + + // Atomically swing receiver slot: null -> recv. + { + Register receiver_addr = offset; + add(receiver_addr, mdp, offset); // kills offset + cmpxchgd(CR0, R0, RegisterOrConstant(0), recv, receiver_addr, MemBarNone, cmpxchgx_hint_atomic_update(), + noreg, nullptr, /* check without ldarx first */ false, /* weak */ true); + } + + // CAS success means the slot now has the receiver we want. CAS failure means + // something had claimed the slot concurrently: it can be the same receiver we want, + // or something else. Since this is a slow path, we can optimize for code density, + // and just restart the search from the beginning. + b(L_restart); + + // Found a receiver, convert its slot offset to corresponding count offset. + bind(L_found_recv); + addi(offset, offset, receiver_to_count_step); + + // Counter update + bind(L_count_update); + increment_mem64(mdp, offset, DataLayout::counter_increment, /* temp */ (count != noreg) ? count : recv); +} + #ifdef ASSERT void MacroAssembler::asm_assert(AsmAssertCond cond, const char *msg) { Label ok; diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 21ab192373f..bbfa75f5151 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -870,6 +870,12 @@ class MacroAssembler: public Assembler { Register tmp6, Register tmp7, Register tmp8, Register tmp9, Register tmp10, Register tmp11, Register tmp12, Register tmp13); + // non-atomic 64-bit memory increment by simm16 + void increment_mem64(Register base, RegisterOrConstant ind_or_offs, int val, Register tmp); + + // Bytecode profiling (tmp2 = noreg is allowed, but then recv is killed) + void profile_receiver_type(Register recv, Register mdp, int mdp_offset, Register tmp1, Register tmp2); + // Emitters for CRC32 calculation. // A note on invertCRC: // Unfortunately, internal representation of crc differs between CRC32 and CRC32C. From e5d8e332050854da0c1b635df57e13bb4d920c06 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 2 Jun 2026 13:33:09 +0000 Subject: [PATCH 028/115] 8385658: Debug code in frame::patch_pc() doesn't initialize on_heap info Reviewed-by: dlong, mbaesken --- src/hotspot/cpu/ppc/frame_ppc.cpp | 6 +++--- src/hotspot/cpu/ppc/frame_ppc.inline.hpp | 2 +- src/hotspot/cpu/x86/frame_x86.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 6b6a792117d..7d2e22b5965 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -319,7 +319,7 @@ void frame::patch_pc(Thread* thread, address pc) { #ifdef ASSERT { - frame f(this->sp(), pc, this->unextended_sp()); + frame f(sp(), unextended_sp(), fp(), pc, cb(), oop_map(), is_heap_frame()); assert(f.is_deoptimized_frame() == this->is_deoptimized_frame() && f.pc() == this->pc() && f.raw_pc() == this->raw_pc(), "must be (f.is_deoptimized_frame(): %d this->is_deoptimized_frame(): %d " "f.pc(): " INTPTR_FORMAT " this->pc(): " INTPTR_FORMAT " f.raw_pc(): " INTPTR_FORMAT " this->raw_pc(): " INTPTR_FORMAT ")", diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index cedcb399a83..123e6d8a0b1 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -81,7 +81,7 @@ inline void frame::setup(kind knd) { // Continuation frames on the java heap are not aligned. // When thawing interpreted frames the sp can be unaligned (see new_stack_frame()). assert(_on_heap || - ((is_aligned(_sp, alignment_in_bytes) || is_interpreted_frame() || is_deoptimized_frame()) && + ((is_aligned(_sp, alignment_in_bytes) || is_interpreted_frame()) && (is_aligned(_fp, alignment_in_bytes) || !is_fully_initialized())), "invalid alignment sp:" PTR_FORMAT " unextended_sp:" PTR_FORMAT " fp:" PTR_FORMAT, p2i(_sp), p2i(_unextended_sp), p2i(_fp)); } diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index 27741ee3bb1..2b06f9ee80c 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -298,7 +298,7 @@ void frame::patch_pc(Thread* thread, address pc) { #ifdef ASSERT { - frame f(this->sp(), this->unextended_sp(), this->fp(), pc); + frame f(sp(), unextended_sp(), fp(), pc, cb(), oop_map(), is_heap_frame()); assert(f.is_deoptimized_frame() == this->is_deoptimized_frame() && f.pc() == this->pc() && f.raw_pc() == this->raw_pc(), "must be (f.is_deoptimized_frame(): %d this->is_deoptimized_frame(): %d " "f.pc(): " INTPTR_FORMAT " this->pc(): " INTPTR_FORMAT " f.raw_pc(): " INTPTR_FORMAT " this->raw_pc(): " INTPTR_FORMAT ")", From cb502e7993cc0a9d89a69901db0b22a236962137 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 2 Jun 2026 14:46:25 +0000 Subject: [PATCH 029/115] 8385747: Test gc/g1/TestGCLogMessages.java failed: 'Update Derived Pointers' found in stdout Reviewed-by: dholmes, tschatzl --- src/hotspot/share/prims/whitebox.cpp | 9 +++++++++ test/hotspot/jtreg/gc/g1/TestGCLogMessages.java | 2 +- test/lib/jdk/test/whitebox/WhiteBox.java | 2 ++ test/lib/jdk/test/whitebox/code/Compiler.java | 9 +++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index b7e12fc1c92..2c389d37fec 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -747,6 +747,14 @@ WB_ENTRY(void, WB_NMTArenaMalloc(JNIEnv* env, jobject o, jlong arena, jlong size a->Amalloc(size_t(size)); WB_END +WB_ENTRY(jboolean, WB_isC2Included(JNIEnv* env)) +#ifdef COMPILER2 + return true; +#else + return false; +#endif +WB_END + static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) { assert(method != nullptr, "method should not be null"); ThreadToNativeFromVM ttn(thread); @@ -2843,6 +2851,7 @@ static JNINativeMethod methods[] = { {CC"NMTNewArena", CC"(J)J", (void*)&WB_NMTNewArena }, {CC"NMTFreeArena", CC"(J)V", (void*)&WB_NMTFreeArena }, {CC"NMTArenaMalloc", CC"(JJ)V", (void*)&WB_NMTArenaMalloc }, + {CC"isC2Included", CC"()Z", (void*)&WB_isC2Included }, {CC"deoptimizeFrames", CC"(Z)I", (void*)&WB_DeoptimizeFrames }, {CC"isFrameDeoptimized", CC"(I)Z", (void*)&WB_IsFrameDeoptimized}, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, diff --git a/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java b/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java index 36e38e6e2fb..68391893a32 100644 --- a/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java +++ b/test/hotspot/jtreg/gc/g1/TestGCLogMessages.java @@ -86,7 +86,7 @@ public class TestGCLogMessages { } public boolean isAvailable() { - return Compiler.isC2Enabled(); + return Compiler.isC2Included(); } } diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 311502a16e2..c4b2da9beb0 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -336,6 +336,8 @@ public class WhiteBox { // Compiler + public native boolean isC2Included(); + public native int matchesMethod(Executable method, String pattern); public native int matchesInline(Executable method, String pattern); public native boolean shouldPrintAssembly(Executable method, int comp_level); diff --git a/test/lib/jdk/test/whitebox/code/Compiler.java b/test/lib/jdk/test/whitebox/code/Compiler.java index 333ca42782c..2450fa81ee6 100644 --- a/test/lib/jdk/test/whitebox/code/Compiler.java +++ b/test/lib/jdk/test/whitebox/code/Compiler.java @@ -34,6 +34,15 @@ public class Compiler { private static final WhiteBox WB = WhiteBox.getWhiteBox(); + /** + * Check if C2 was included in the VM build + * + * @return true if C2 was included in the VM build. + */ + public static boolean isC2Included() { + return WB.isC2Included(); + } + /** * Check if C2 is used as JIT compiler. * From c469bb2cd71bb1bd4f635767ac5902c46a9137a7 Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Tue, 2 Jun 2026 14:54:16 +0000 Subject: [PATCH 030/115] 8383867: File.getCanonicalPath drops backslash from UNC path with directory junctions Reviewed-by: alanb --- .../windows/native/libjava/canonicalize_md.c | 6 ++- test/jdk/java/io/File/GetCanonicalPath.java | 38 ++++++++++++++----- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/java.base/windows/native/libjava/canonicalize_md.c b/src/java.base/windows/native/libjava/canonicalize_md.c index 8596521509c..bc17531e4a5 100644 --- a/src/java.base/windows/native/libjava/canonicalize_md.c +++ b/src/java.base/windows/native/libjava/canonicalize_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -181,10 +181,12 @@ WCHAR* getFinalPath(WCHAR* path, WCHAR* finalPath, DWORD size) int isUnc = (finalPath[4] == L'U' && finalPath[5] == L'N' && finalPath[6] == L'C'); + // keep leading double backslashes in case of UNC + const int startIdx = (isUnc) ? 1 : 0; int prefixLen = (isUnc) ? 7 : 4; // the amount to copy includes terminator int amountToCopy = len - prefixLen + 1; - wmemmove(finalPath, finalPath + prefixLen, amountToCopy); + wmemmove(finalPath + startIdx, finalPath + prefixLen, amountToCopy); } return finalPath; diff --git a/test/jdk/java/io/File/GetCanonicalPath.java b/test/jdk/java/io/File/GetCanonicalPath.java index 14ef90260fc..f1d517c2202 100644 --- a/test/jdk/java/io/File/GetCanonicalPath.java +++ b/test/jdk/java/io/File/GetCanonicalPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - * @bug 4899022 8003887 8355342 + * @bug 4899022 8003887 8355342 8383867 * @summary Look for erroneous representation of drive letter * @run junit GetCanonicalPath */ @@ -148,7 +148,14 @@ public class GetCanonicalPath { Runtime rt = Runtime.getRuntime(); String share = "\\\\localhost\\" + cwd.charAt(0) + "$" + cwd.substring(2); + String junctionName = "tmpDir"; try { + // create directory junction + Path tmpDir = Files.createTempDirectory(junctionName); + String tmpDirLink = cwd + "\\" + junctionName; + Process pmklink = rt.exec(new String[] {"cmd", "/c", "mklink", "/J", tmpDirLink, tmpDir.toString()}); + assertEquals(0, pmklink.waitFor()); + Process p = rt.exec(new String[] {"net", "use", drive + ":", share}); assertEquals(0, p.waitFor()); } catch (InterruptedException x) { @@ -157,13 +164,26 @@ public class GetCanonicalPath { // check that the canonical path name and its content are as expected try { - final String filename = "file.txt"; - final String text = "This is some text"; - Files.writeString(Path.of(share, filename), text); - File file = new File(drive + ":\\" + filename); - String canonicalPath = file.getCanonicalPath(); - assertEquals(drive + ":\\" + filename, canonicalPath); - assertEquals(text, Files.readString(Path.of(canonicalPath))); + // use drive letter + { + final String filename = "file.txt"; + final String text = "This is some text"; + Files.writeString(Path.of(share, filename), text); + File file = new File(drive + ":\\" + filename); + String canonicalPath = file.getCanonicalPath(); + assertEquals(drive + ":\\" + filename, canonicalPath); + assertEquals(text, Files.readString(Path.of(canonicalPath))); + } + // use reparse point (directory junction) + { + final String filename = junctionName + "\\file.txt"; + final String text = "This is some text"; + Files.writeString(Path.of(share, filename), text); + File file = new File(drive + ":\\" + filename); + String canonicalPath = file.getCanonicalPath(); + assertTrue(canonicalPath.startsWith("\\\\localhost\\")); + assertEquals(text, Files.readString(Path.of(canonicalPath))); + } } finally { try { Process p = rt.exec(new String[] {"net", "use", drive + ":", "/Delete"}); From 1e67c84b66617668da2e9323c8e0b27ad5cd3a19 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Tue, 2 Jun 2026 15:26:28 +0000 Subject: [PATCH 031/115] 8382936: C2: Load folding must not drop Type information Reviewed-by: kvn, vlivanov --- src/hotspot/share/opto/graphKit.cpp | 29 ++--- src/hotspot/share/opto/memnode.cpp | 22 +++- src/hotspot/share/opto/type.cpp | 28 +++-- src/hotspot/share/opto/type.hpp | 1 + .../compiler/parsing/TestAastoreTypeSafe.java | 113 ++++++++++++++++++ 5 files changed, 163 insertions(+), 30 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/parsing/TestAastoreTypeSafe.java diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 78bfc1ab5b8..3112bb6b169 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -3401,7 +3401,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); - Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null); + Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, false /*safe_for_replace*/, speculative_not_null); // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a null? @@ -3429,7 +3429,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, // a speculative type use it to perform an exact cast. ciKlass* spec_obj_type = obj_type->speculative_type(); if (spec_obj_type != nullptr || data != nullptr) { - cast_obj = maybe_cast_profiled_receiver(not_null_obj, improved_klass_ptr_type, spec_obj_type, safe_for_replace); + cast_obj = maybe_cast_profiled_receiver(not_null_obj, improved_klass_ptr_type, spec_obj_type, false /*safe_for_replace*/); if (cast_obj != nullptr) { if (failure_control != nullptr) // failure is now impossible (*failure_control) = top(); @@ -3467,24 +3467,17 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, region->init_req(_obj_path, control()); phi ->init_req(_obj_path, cast_obj); - // A merge of null or Casted-NotNull obj - Node* res = _gvn.transform(phi); - - // Note I do NOT always 'replace_in_map(obj,result)' here. - // if( tk->klass()->can_be_primary_super() ) - // This means that if I successfully store an Object into an array-of-String - // I 'forget' that the Object is really now known to be a String. I have to - // do this because we don't have true union types for interfaces - if I store - // a Baz into an array-of-Interface and then tell the optimizer it's an - // Interface, I forget that it's also a Baz and cannot do Baz-like field - // references to it. FIX THIS WHEN UNION TYPES APPEAR! - // replace_in_map( obj, res ); - // Return final merged results set_control( _gvn.transform(region) ); record_for_igvn(region); - return record_profiled_receiver_for_speculation(res); + // A merge of null or Casted-NotNull obj + Node* res = _gvn.transform(phi); + res = record_profiled_receiver_for_speculation(res); + if (safe_for_replace) { + replace_in_map(obj, res); + } + return res; } //------------------------------next_monitor----------------------------------- @@ -4208,13 +4201,13 @@ Node* GraphKit::load_String_value(Node* str, bool set_ctrl) { const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, nullptr, 0); const TypePtr* value_field_type = string_type->add_offset(value_offset); - const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull, + const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE, TypeInt::POS), ciTypeArrayKlass::make(T_BYTE), true, 0); Node* p = basic_plus_adr(str, str, value_offset); Node* load = access_load_at(str, p, value_field_type, value_type, T_OBJECT, IN_HEAP | (set_ctrl ? C2_CONTROL_DEPENDENT_LOAD : 0) | MO_UNORDERED); - return load; + return must_be_not_null(load, true); } Node* GraphKit::load_String_coder(Node* str, bool set_ctrl) { diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index d5737166bb6..4f68ff281a0 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -53,6 +53,7 @@ #include "opto/vectornode.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/powerOfTwo.hpp" #include "utilities/vmError.hpp" @@ -1217,7 +1218,9 @@ Node* LoadNode::can_see_stored_value_through_membars(Node* st, PhaseValues* phas } } - return can_see_stored_value(st, phase); + Node* res = can_see_stored_value(st, phase); + assert(res == nullptr || is_java_primitive(value_basic_type()) || res->bottom_type()->higher_equal(type()), "the fold is unsafe"); + return res; } // If st is a store to the same location as this, return the stored value @@ -1273,7 +1276,22 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseValues* phase) const { return nullptr; } } - return st->in(MemNode::ValueIn); + + // Even if we can see the store, we cannot fold the load if the store is not type safe (e.g. + // store a j.l.Object into an array of j.l.String) because folding makes the compiler lose the + // type information that the uses of this node may need. This is only necessary for pointers, we + // can see the stored value of a LoadS even if it is an int because LoadSNode::Ideal will do the + // necessary truncation. + // The same phenomenon is not an issue for StoreNodes because they don't use res. + Node* res = st->in(MemNode::ValueIn); + if (is_Store() || is_java_primitive(value_basic_type()) || res->bottom_type()->higher_equal(bottom_type())) { + return res; + } + + // Type-unsafe stores must be due to array polymorphism + const TypePtr* adr_type = this->adr_type(); + assert(adr_type == nullptr || adr_type->isa_aryptr() != nullptr, "unexpected type-unsafe store"); + return nullptr; } // A load from a freshly-created object always returns zero. diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 6c48ad470c9..fcdf9b09fc3 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -22,6 +22,7 @@ * */ +#include "ci/ciInstanceKlass.hpp" #include "ci/ciMethodData.hpp" #include "ci/ciTypeFlow.hpp" #include "classfile/javaClasses.hpp" @@ -3280,6 +3281,17 @@ bool TypeInterfaces::eq(ciInstanceKlass* k) const { return true; } +// Check whether an instance of type k will satisfy this +bool TypeInterfaces::is_subset(ciInstanceKlass* k) const { + assert(k->is_loaded(), "should be loaded"); + GrowableArray* k_interfaces = k->transitive_interfaces(); + for (int i = 0; i < _interfaces.length(); i++) { + if (!k_interfaces->contains(_interfaces.at(i))) { + return false; + } + } + return true; +} uint TypeInterfaces::hash() const { assert(_initialized, "must be"); @@ -5958,20 +5970,16 @@ const TypeKlassPtr* TypeInstKlassPtr::try_improve() const { Compile* C = Compile::current(); Dependencies* deps = C->dependencies(); assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity"); - const TypeInterfaces* interfaces = _interfaces; if (k->is_loaded()) { ciInstanceKlass* ik = k->as_instance_klass(); bool klass_is_exact = ik->is_final(); - if (!klass_is_exact && - deps != nullptr) { + if (!klass_is_exact && deps != nullptr) { ciInstanceKlass* sub = ik->unique_concrete_subklass(); - if (sub != nullptr) { - if (_interfaces->eq(sub)) { - deps->assert_abstract_with_unique_concrete_subtype(ik, sub); - k = ik = sub; - klass_is_exact = sub->is_final(); - return TypeKlassPtr::make(klass_is_exact ? Constant : _ptr, k, _offset); - } + if (sub != nullptr && _interfaces->is_subset(sub)) { + deps->assert_abstract_with_unique_concrete_subtype(ik, sub); + k = ik = sub; + klass_is_exact = sub->is_final(); + return TypeKlassPtr::make(klass_is_exact ? Constant : _ptr, k, _offset); } } } diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 3e029c387b1..6eaa497e86d 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -1137,6 +1137,7 @@ public: static const TypeInterfaces* make(GrowableArray* interfaces = nullptr); bool eq(const Type* other) const; bool eq(ciInstanceKlass* k) const; + bool is_subset(ciInstanceKlass* k) const; uint hash() const; const Type *xdual() const; void dump(outputStream* st) const; diff --git a/test/hotspot/jtreg/compiler/parsing/TestAastoreTypeSafe.java b/test/hotspot/jtreg/compiler/parsing/TestAastoreTypeSafe.java new file mode 100644 index 00000000000..f33c0fc0b87 --- /dev/null +++ b/test/hotspot/jtreg/compiler/parsing/TestAastoreTypeSafe.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.parsing; + +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8382936 + * @library /test/lib + * @summary Test that aastore generates a type safe graph + * @run main ${test.main.class} + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:-TieredCompilation + * -XX:CompileOnly=${test.main.class}::test* -XX:-MonomorphicArrayCheck + * -XX:+AlwaysIncrementalInline -XX:+UseCompressedOops ${test.main.class} + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:-TieredCompilation + * -XX:CompileOnly=${test.main.class}::test* -XX:-MonomorphicArrayCheck + * -XX:+AlwaysIncrementalInline -XX:-UseCompressedOops ${test.main.class} + */ +public class TestAastoreTypeSafe { + private static final class A { + int v; + } + + private static class B { + } + + private static final class C extends B { + int v; + } + + public static void main(String[] args) { + { + A[] array = new A[1]; + A element = new A(); + for (int i = 0; i < 10; i++) { + test1(true, array, element, element); + Asserts.assertEQ(0, element.v); + } + } + + { + C[] array = new C[1]; + C element = new C(); + for (int i = 0; i < 10; i++) { + test2(true, array, element, element); + Asserts.assertEQ(0, element.v); + } + } + } + + // The array load will be folded, but the element type is lost in the graph. This leads to the + // scheduler missing the dependency between the load from the return value of aaload and the + // store into alias.v. The load will then be put late just before the second store to alias.v, + // which is an invalid schedule. + private static void test1(boolean b, A[] array, Object element, A alias) { + aastoreA(array, element); + int v = aaloadA(array).v; + alias.v = 1; + if (b) { + alias.v = v; + } + } + + private static void aastoreA(A[] array, Object element) { + // This forces the compiler to try storing an Object into an A[]. Otherwise, doing + // array[0] = (A)element will make it so that the stored value being an A already. + ((Object[]) array)[0] = element; + } + + private static A aaloadA(A[] array) { + return array[0]; + } + + // Similar to above, but the store cannot be truly type safe because the exact array type is + // unknown + private static void test2(boolean b, B[] array, Object element, C alias) { + aastoreB(array, element); + int v = aaloadC(array).v; + alias.v = 1; + if (b) { + alias.v = v; + } + } + + private static void aastoreB(B[] array, Object element) { + ((Object[]) array)[0] = element; + } + + private static C aaloadC(B[] array) { + return ((C[]) array)[0]; + } +} From 6253a03af30f11f684a17ff7874c6e91a0e160f7 Mon Sep 17 00:00:00 2001 From: Ferenc Rakoczi Date: Tue, 2 Jun 2026 16:43:57 +0000 Subject: [PATCH 032/115] 8383635: Improve performance of ML-KEM's implKyberNttMultJava() method Reviewed-by: semery, weijun --- .../cpu/aarch64/stubGenerator_aarch64.cpp | 18 ++++ .../cpu/x86/stubGenerator_x86_64_kyber.cpp | 21 ++++ .../com/sun/crypto/provider/ML_KEM.java | 98 +++++++++---------- 3 files changed, 84 insertions(+), 53 deletions(-) diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 46849b329cb..8e9af2b7b8a 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -6276,6 +6276,24 @@ class StubGenerator: public StubCodeGenerator { // static int implKyberNttMult( // short[] result, short[] ntta, short[] nttb, short[] zetas) {} // + // The actual algorithm that is used here differs from the one in the Java + // implementation, it uses Montgomery multiplications instead of Barrett + // reduction, but the end result modulo MLKEM_Q is the same. This is the + // Java equivalent of this intrinsic implementation: + // static void implKyberNttMultJava(short[] result, short[] ntta, short[] nttb) { + // for (int m = 0; m < ML_KEM_N / 2; m++) { + // int a0 = ntta[2 * m]; + // int a1 = ntta[2 * m + 1]; + // int b0 = nttb[2 * m]; + // int b1 = nttb[2 * m + 1]; + // int r = montMul(a0, b0) + + // montMul(montMul(a1, b1), MONT_ZETAS_FOR_NTT_MULT[m]); + // result[2 * m] = (short) montMul(r, MONT_R_SQUARE_MOD_Q); + // result[2 * m + 1] = (short) montMul( + // (montMul(a0, b1) + montMul(a1, b0)), MONT_R_SQUARE_MOD_Q); + // } + // } + // // result (short[256]) = c_rarg0 // ntta (short[256]) = c_rarg1 // nttb (short[256]) = c_rarg2 diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp index 13b1c942213..c35a2a1bba6 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp @@ -631,6 +631,27 @@ address generate_kyberInverseNtt_avx512(StubGenerator *stubgen, } // Kyber multiply polynomials in the NTT domain. +// Implements +// static int implKyberNttMult( +// short[] result, short[] ntta, short[] nttb, short[] zetas) {} +// +// The actual algorithm that is used here differs from the one in the Java +// implementation, it uses Montgomery multiplications instead of Barrett +// reduction, but the end result modulo MLKEM_Q is the same. This is the +// Java equivalent of this intrinsic implementation: +// static void implKyberNttMultJava(short[] result, short[] ntta, short[] nttb) { +// for (int m = 0; m < ML_KEM_N / 2; m++) { +// int a0 = ntta[2 * m]; +// int a1 = ntta[2 * m + 1]; +// int b0 = nttb[2 * m]; +// int b1 = nttb[2 * m + 1]; +// int r = montMul(a0, b0) + +// montMul(montMul(a1, b1), MONT_ZETAS_FOR_NTT_MULT[m]); +// result[2 * m] = (short) montMul(r, MONT_R_SQUARE_MOD_Q); +// result[2 * m + 1] = (short) montMul( +// (montMul(a0, b1) + montMul(a1, b0)), MONT_R_SQUARE_MOD_Q); +// } +// } // // result (short[256]) = c_rarg0 // ntta (short[256]) = c_rarg1 diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java index 6bd70c3cdd6..96a1eb686cc 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ML_KEM.java @@ -46,14 +46,17 @@ public final class ML_KEM { private static final int XOF_PAD = 24; private static final int MONT_R_BITS = 20; private static final int MONT_Q = 3329; - private static final int MONT_R_SQUARE_MOD_Q = 152; private static final int MONT_Q_INV_MOD_R = 586497; // toMont((ML_KEM_N / 2)^-1 mod ML_KEM_Q) using R = 2^MONT_R_BITS private static final int MONT_DIM_HALF_INVERSE = 1534; private static final int BARRETT_MULTIPLIER = 20159; + private static final int BARRETT_ADDEND = 1665; private static final int BARRETT_SHIFT = 26; - private static final int[] MONT_ZETAS_FOR_NTT = new int[]{ + + // The values from Appendix A of the FIPS 203 standard converted to the + // Montgomery domain, i.e. toMont(zeta^ (bitrev_7(i)) for i = 0..127 + private static final int[] MONT_ZETAS_FOR_NTT = new int[] { 1188, 914, -969, 585, -551, 1263, -97, 593, -35, -1400, -417, -1253, 742, -281, 185, -819, -1226, 895, -530, 52, 25, 1000, 1249, -909, @@ -72,7 +75,7 @@ public final class ML_KEM { -1599, -709, -789, -1317, -57, 1049, -584 }; - private static final short[] montZetasForVectorNttArr = new short[]{ + private static final short[] montZetasForVectorNttArr = new short[] { // level 0 -758, -758, -758, -758, -758, -758, -758, -758, -758, -758, -758, -758, -758, -758, -758, -758, @@ -193,26 +196,8 @@ public final class ML_KEM { -108, -108, -308, -308, 996, 996, 991, 991, 958, 958, -1460, -1460, 1522, 1522, 1628, 1628 }; - private static final int[] MONT_ZETAS_FOR_INVERSE_NTT = new int[]{ - 584, -1049, 57, 1317, 789, 709, 1599, -1601, - -990, 604, 348, 857, 612, 474, 1177, -1014, - -88, -982, -191, 668, 1386, 486, -1153, -534, - 514, 137, 586, -1178, 227, 339, -907, 244, - 1200, -833, 1394, -30, 1074, 636, -317, -1192, - -1259, -355, -425, -884, -977, 1430, 868, 607, - 184, 1448, 702, 1327, 431, 497, 595, -94, - 1649, -1497, -620, 42, -172, 1107, -222, 1003, - 426, -845, 395, -510, 1613, 825, 1269, -290, - -1429, 623, -567, 1617, 36, 1007, 1440, 332, - -201, 1313, -1382, -744, 669, -1538, 128, -1598, - 1401, 1183, -553, 714, 405, -1155, -445, 406, - -1496, -49, 82, 1369, 259, 1604, 373, 909, - -1249, -1000, -25, -52, 530, -895, 1226, 819, - -185, 281, -742, 1253, 417, 1400, 35, -593, - 97, -1263, 551, -585, 969, -914, -1188 - }; - private static final short[] montZetasForVectorInverseNttArr = new short[]{ + private static final short[] montZetasForVectorInverseNttArr = new short[] { // level 0 -1628, -1628, -1522, -1522, 1460, 1460, -958, -958, -991, -991, -996, -996, 308, 308, 108, 108, @@ -334,25 +319,28 @@ public final class ML_KEM { 758, 758, 758, 758, 758, 758, 758, 758 }; - private static final int[] MONT_ZETAS_FOR_NTT_MULT = new int[]{ - -1003, 1003, 222, -222, -1107, 1107, 172, -172, - -42, 42, 620, -620, 1497, -1497, -1649, 1649, - 94, -94, -595, 595, -497, 497, -431, 431, - -1327, 1327, -702, 702, -1448, 1448, -184, 184, - -607, 607, -868, 868, -1430, 1430, 977, -977, - 884, -884, 425, -425, 355, -355, 1259, -1259, - 1192, -1192, 317, -317, -636, 636, -1074, 1074, - 30, -30, -1394, 1394, 833, -833, -1200, 1200, - -244, 244, 907, -907, -339, 339, -227, 227, - 1178, -1178, -586, 586, -137, 137, -514, 514, - 534, -534, 1153, -1153, -486, 486, -1386, 1386, - -668, 668, 191, -191, 982, -982, 88, -88, - 1014, -1014, -1177, 1177, -474, 474, -612, 612, - -857, 857, -348, 348, -604, 604, 990, -990, - 1601, -1601, -1599, 1599, -709, 709, -789, 789, - -1317, 1317, -57, 57, 1049, -1049, -584, 584 + // modulo MLKEM_Q positive equivalents of the values listed for + // the MultiplyNTTs algorithm in the FIPS 203 standard + private static final int[] ZETAS_FOR_NTT_MULT = new int[] { + 17, 3312, 2761, 568, 583, 2746, 2649, 680, + 1637, 1692, 723, 2606, 2288, 1041, 1100, 2229, + 1409, 1920, 2662, 667, 3281, 48, 233, 3096, + 756, 2573, 2156, 1173, 3015, 314, 3050, 279, + 1703, 1626, 1651, 1678, 2789, 540, 1789, 1540, + 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, + 939, 2390, 2308, 1021, 2437, 892, 2388, 941, + 733, 2596, 2337, 992, 268, 3061, 641, 2688, + 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, + 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, + 1063, 2266, 319, 3010, 2773, 556, 757, 2572, + 2099, 1230, 561, 2768, 2466, 863, 2594, 735, + 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, + 1143, 2186, 2150, 1179, 2775, 554, 886, 2443, + 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, + 2110, 1219, 2935, 394, 885, 2444, 2154, 1175 }; - private static final short[] montZetasForVectorNttMultArr = new short[]{ + + private static final short[] montZetasForVectorNttMultArr = new short[] { -1103, 1103, 430, -430, 555, -555, 843, -843, -1251, 1251, 871, -871, 1550, -1550, 105, -105, 422, -422, 587, -587, 177, -177, -235, 235, @@ -1174,17 +1162,20 @@ public final class ML_KEM { } static void implKyberNttMultJava(short[] result, short[] ntta, short[] nttb) { - for (int m = 0; m < ML_KEM_N / 2; m++) { - - int a0 = ntta[2 * m]; - int a1 = ntta[2 * m + 1]; - int b0 = nttb[2 * m]; - int b1 = nttb[2 * m + 1]; - int r = montMul(a0, b0) + - montMul(montMul(a1, b1), MONT_ZETAS_FOR_NTT_MULT[m]); - result[2 * m] = (short) montMul(r, MONT_R_SQUARE_MOD_Q); - result[2 * m + 1] = (short) montMul( - (montMul(a0, b1) + montMul(a1, b0)), MONT_R_SQUARE_MOD_Q); + for (int m = 0; m < ML_KEM_N; m += 2) { + int a0 = ntta[m]; + int a1 = ntta[m + 1]; + int b0 = nttb[m]; + int b1 = nttb[m + 1]; + long r = a1 * b1; + r -= ((r * BARRETT_MULTIPLIER) >> BARRETT_SHIFT) * ML_KEM_Q; + r *= ZETAS_FOR_NTT_MULT[m >> 1]; + r += a0 * b0; + result[m] = (short) (r - (((r + BARRETT_ADDEND) * + BARRETT_MULTIPLIER) >> BARRETT_SHIFT) * ML_KEM_Q); + long r1 = a0 * b1 + a1 * b0; + result[m + 1] = (short) (r1 - (((r1 + BARRETT_ADDEND) * + BARRETT_MULTIPLIER) >> BARRETT_SHIFT) * ML_KEM_Q); } } @@ -1552,9 +1543,10 @@ public final class ML_KEM { } static void implKyberBarrettReduceJava(short[] poly) { + int tmp = 0; for (int m = 0; m < ML_KEM_N; m++) { - int tmp = ((int) poly[m] * BARRETT_MULTIPLIER) >> BARRETT_SHIFT; - poly[m] = (short) (poly[m] - tmp * ML_KEM_Q); + tmp = poly[m]; + poly[m] = (short) (tmp - ((tmp * BARRETT_MULTIPLIER) >> BARRETT_SHIFT) * ML_KEM_Q); } } From 4192f9bf2edb14e6449e922a8bb27ec14c1003d4 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 2 Jun 2026 20:27:12 +0000 Subject: [PATCH 033/115] 8385736: Optimize ListFormat custom pattern parsing Reviewed-by: jlu --- .../share/classes/java/text/ListFormat.java | 162 ++++++++++++------ .../Format/ListFormat/TestListFormat.java | 58 ++++++- 2 files changed, 163 insertions(+), 57 deletions(-) diff --git a/src/java.base/share/classes/java/text/ListFormat.java b/src/java.base/share/classes/java/text/ListFormat.java index 5cd0e9e3651..3f320bbcc9b 100644 --- a/src/java.base/share/classes/java/text/ListFormat.java +++ b/src/java.base/share/classes/java/text/ListFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Objects; -import java.util.regex.Pattern; import java.util.stream.IntStream; import sun.util.locale.provider.LocaleProviderAdapter; @@ -112,6 +111,7 @@ public final class ListFormat extends Format { private static final int TWO = 3; private static final int THREE = 4; private static final int PATTERN_ARRAY_LENGTH = THREE + 1; + private static final int PLACEHOLDER_LENGTH = 3; // i.e., "{i}".length() /** * The locale to use for formatting list patterns. @@ -126,14 +126,11 @@ public final class ListFormat extends Format { */ private final String[] patterns; - private static final Pattern PARSE_START = Pattern.compile("(.*?)\\{0}(.*?)\\{1}"); - private static final Pattern PARSE_MIDDLE = Pattern.compile("\\{0}(.*?)\\{1}"); - private static final Pattern PARSE_END = Pattern.compile("\\{0}(.*?)\\{1}(.*?)"); - private static final Pattern PARSE_TWO = Pattern.compile("(.*?)\\{0}(.*?)\\{1}(.*?)"); - private static final Pattern PARSE_THREE = Pattern.compile("(.*?)\\{0}(.*?)\\{1}(.*?)\\{2}(.*?)"); - private transient Pattern startPattern; + private transient String startBefore; + private transient String startBetween; private transient String middleBetween; - private transient Pattern endPattern; + private transient String endBetween; + private transient String endAfter; private ListFormat(Locale l, String[] patterns) { locale = l; @@ -149,50 +146,60 @@ public final class ListFormat extends Format { } } - // get pattern strings - var m = PARSE_START.matcher(patterns[START]); - String startBefore; - String startBetween; - if (m.matches()) { - startBefore = m.group(1); - startBetween = m.group(2); + // Get pattern strings. Pattern conditions from LDML are: + // - it contains the placeholders {0}, {1}, and {2} ("3"-pattern only) in order + // - "start" and "middle" patterns end with the {1} placeholder + // - "middle" and "end" patterns begin with the {0} placeholder + var pattern = patterns[START]; + var placeholderPositions = findPlaceholders(pattern); + if (placeholderPositions != null && + placeholderPositions[1] + PLACEHOLDER_LENGTH == pattern.length()) { + startBefore = pattern.substring(0, placeholderPositions[0]); + startBetween = pattern.substring(placeholderPositions[0] + PLACEHOLDER_LENGTH, + placeholderPositions[1]); } else { - throw new IllegalArgumentException("start pattern is incorrect: " + patterns[START]); + throw new IllegalArgumentException("start pattern is incorrect: " + pattern); } - m = PARSE_MIDDLE.matcher(patterns[MIDDLE]); - if (m.matches()) { - middleBetween = m.group(1); + + pattern = patterns[MIDDLE]; + placeholderPositions = findPlaceholders(pattern); + if (placeholderPositions != null && + placeholderPositions[0] == 0 && + placeholderPositions[1] + PLACEHOLDER_LENGTH == pattern.length()) { + middleBetween = pattern.substring(placeholderPositions[0] + PLACEHOLDER_LENGTH, + placeholderPositions[1]); } else { - throw new IllegalArgumentException("middle pattern is incorrect: " + patterns[MIDDLE]); + throw new IllegalArgumentException("middle pattern is incorrect: " + pattern); } - m = PARSE_END.matcher(patterns[END]); - String endBetween; - String endAfter; - if (m.matches()) { - endBetween = m.group(1); - endAfter = m.group(2); + + pattern = patterns[END]; + placeholderPositions = findPlaceholders(pattern); + if (placeholderPositions != null && placeholderPositions[0] == 0) { + endBetween = pattern.substring(placeholderPositions[0] + PLACEHOLDER_LENGTH, + placeholderPositions[1]); + endAfter = pattern.substring(placeholderPositions[1] + PLACEHOLDER_LENGTH); } else { - throw new IllegalArgumentException("end pattern is incorrect: " + patterns[END]); + throw new IllegalArgumentException("end pattern is incorrect: " + pattern); } // Validate two/three patterns, if given. Otherwise, generate them - if (!patterns[TWO].isEmpty()) { - if (!PARSE_TWO.matcher(patterns[TWO]).matches()) { - throw new IllegalArgumentException("pattern for two is incorrect: " + patterns[TWO]); + pattern = patterns[TWO]; + if (!pattern.isEmpty()) { + if (findPlaceholders(pattern) == null) { + throw new IllegalArgumentException("pattern for two is incorrect: " + pattern); } } else { patterns[TWO] = startBefore + "{0}" + endBetween + "{1}" + endAfter; } - if (!patterns[THREE].isEmpty()) { - if (!PARSE_THREE.matcher(patterns[THREE]).matches()) { - throw new IllegalArgumentException("pattern for three is incorrect: " + patterns[THREE]); + pattern = patterns[THREE]; + if (!pattern.isEmpty()) { + placeholderPositions = findPlaceholders(pattern); + if (placeholderPositions == null || placeholderPositions[2] == -1) { + throw new IllegalArgumentException("pattern for three is incorrect: " + pattern); } } else { patterns[THREE] = startBefore + "{0}" + startBetween + "{1}" + endBetween + "{2}" + endAfter; } - - startPattern = Pattern.compile(startBefore + "(.+?)" + startBetween); - endPattern = Pattern.compile(endBetween + "(.+?)" + endAfter); } /** @@ -455,21 +462,29 @@ public final class ListFormat extends Format { public Object parseObject(String source, ParsePosition parsePos) { Objects.requireNonNull(source); Objects.requireNonNull(parsePos); - var sm = startPattern.matcher(source); - var em = endPattern.matcher(source); + var startPattern = findPattern(source, parsePos.getIndex(), startBefore, startBetween); + var endPattern = findPattern(source, parsePos.getIndex(), endBetween, endAfter); Object parsed = null; - if (sm.find(parsePos.getIndex()) && em.find(parsePos.getIndex())) { - // get em to the last - var c = em.start(); - while (em.find()) { - c = em.start(); + if (startPattern != null && endPattern != null) { + // get endPattern to the last + var ep = endPattern; + while ((ep = findPattern(source, ep[1], endBetween, endAfter)) != null) { + endPattern = ep; } - em.find(c); - var startEnd = sm.end(); - var endStart = em.start(); + + var startEnd = startPattern[1]; + var endStart = endPattern[0]; if (startEnd <= endStart) { var mid = source.substring(startEnd, endStart); - var count = mid.split(middleBetween).length + 2; + var count = 3; + var mbLength = middleBetween.length(); + if (mbLength > 0) { + var midIndex = 0; + while ((midIndex = mid.indexOf(middleBetween, midIndex)) >= 0) { + count++; + midIndex += mbLength; + } + } parsed = new MessageFormat(createMessageFormatString(count), locale).parseObject(source, parsePos); } } @@ -565,7 +580,9 @@ public final class ListFormat extends Format { private String createMessageFormatString(int count) { var sb = new StringBuilder(256).append(patterns[START]); IntStream.range(2, count - 1).forEach(i -> sb.append(middleBetween).append("{").append(i).append("}")); - sb.append(patterns[END].replaceFirst("\\{0}", "").replaceFirst("\\{1}", "\\{" + (count - 1) + "\\}")); + sb.append(endBetween) + .append("{").append(count - 1).append("}") + .append(endAfter); return sb.toString(); } @@ -643,4 +660,51 @@ public final class ListFormat extends Format { */ NARROW } + + /** + * {@return the positions of the "{0}", "{1}", and "{2}" placeholders in the + * given pattern string, or null if the pattern is invalid} + * + * The returned array contains -1 for "{2}" if that placeholder is absent. + * + * @param pattern pattern string to parse + */ + private static int[] findPlaceholders(String pattern) { + var positions = new int[3]; + for (int i = 0; i < positions.length; i++) { + positions[i] = pattern.indexOf("{" + i + "}"); + } + + // Check the existence and order of the placeholders + if (positions[0] == -1 || + positions[1] == -1 || + positions[0] + PLACEHOLDER_LENGTH > positions[1] || + positions[2] != -1 && positions[1] + PLACEHOLDER_LENGTH > positions[2]) { + return null; + } + + return positions; + } + + /** + * {@return the start and end positions of the first pattern found in + * the given {@code source} starting at {@code pos}, or null if no such + * pattern exists} + * + * The pattern must contain at least one character between the + * {@code prefix} and {@code suffix} strings. The returned end position is + * exclusive. + * + * @param source string to search + * @param pos position at which to start the search + * @param prefix starting string within the pattern + * @param suffix ending string within the pattern + */ + private static int[] findPattern(String source, int pos, String prefix, String suffix) { + var prefixPos = source.indexOf(prefix, pos); + var suffixPos = prefixPos != -1 ? source.indexOf(suffix, prefixPos + prefix.length() + 1) : -1; + + return prefixPos < suffixPos ? + new int[] {prefixPos, suffixPos + suffix.length()} : null; + } } diff --git a/test/jdk/java/text/Format/ListFormat/TestListFormat.java b/test/jdk/java/text/Format/ListFormat/TestListFormat.java index bcccc2873f5..1500a1b0818 100644 --- a/test/jdk/java/text/Format/ListFormat/TestListFormat.java +++ b/test/jdk/java/text/Format/ListFormat/TestListFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8041488 8316974 8318569 8306116 + * @bug 8041488 8316974 8318569 8306116 8385736 * @summary Tests for ListFormat class * @run junit TestListFormat */ @@ -66,6 +66,14 @@ public class TestListFormat { "", "", }; + // Ensures regex metacharacters in custom patterns are treated as literals. + private static final String[] CUSTOM_PATTERNS_METACHAR = { + ". {0} * {1}", + "{0} + {1}", + "{0} | {1} [", + "", + "", + }; private static final String[] CUSTOM_PATTERNS_IAE_START = { "{0}", "{0} mid {1}", @@ -120,7 +128,7 @@ public class TestListFormat { assertEquals(ListFormat.getInstance(), ListFormat.getInstance(Locale.getDefault(Locale.Category.FORMAT), ListFormat.Type.STANDARD, ListFormat.Style.FULL)); } - static Arguments[] getInstance_1Arg() { + private static Arguments[] getInstance_1Arg() { return new Arguments[] { arguments(CUSTOM_PATTERNS_FULL, SAMPLE1, "foo"), arguments(CUSTOM_PATTERNS_FULL, SAMPLE2, "twobef foo two bar twoaft"), @@ -130,10 +138,14 @@ public class TestListFormat { arguments(CUSTOM_PATTERNS_MINIMAL, SAMPLE2, "sbef foo ebet bar eaft"), arguments(CUSTOM_PATTERNS_MINIMAL, SAMPLE3, "sbef foo sbet bar ebet baz eaft"), arguments(CUSTOM_PATTERNS_MINIMAL, SAMPLE4, "sbef foo sbet bar mid baz ebet qux eaft"), + arguments(CUSTOM_PATTERNS_METACHAR, SAMPLE1, "foo"), + arguments(CUSTOM_PATTERNS_METACHAR, SAMPLE2, ". foo | bar ["), + arguments(CUSTOM_PATTERNS_METACHAR, SAMPLE3, ". foo * bar | baz ["), + arguments(CUSTOM_PATTERNS_METACHAR, SAMPLE4, ". foo * bar + baz | qux ["), }; } - static Arguments[] getInstance_1Arg_IAE() { + private static Arguments[] getInstance_1Arg_IAE() { return new Arguments[] { arguments(new String[1], "Pattern array length should be 5"), arguments(new String[6], "Pattern array length should be 5"), @@ -146,7 +158,7 @@ public class TestListFormat { }; } - static Arguments[] getInstance_3Arg() { + private static Arguments[] getInstance_3Arg() { return new Arguments[] { arguments(Locale.US, ListFormat.Type.STANDARD, ListFormat.Style.FULL, "foo, bar, and baz", true), @@ -188,7 +200,7 @@ public class TestListFormat { }; } - static Arguments[] parseObject_parsePos() { + private static Arguments[] parseObject_parsePos() { return new Arguments[] { arguments(CUSTOM_PATTERNS_FULL, SAMPLE1), arguments(CUSTOM_PATTERNS_FULL, SAMPLE2), @@ -201,7 +213,7 @@ public class TestListFormat { }; } - static Arguments[] getInstance_3Arg_InheritPatterns() { + private static Arguments[] getInstance_3Arg_InheritPatterns() { return new Arguments[] { arguments(ListFormat.Type.STANDARD, ListFormat.Style.FULL), arguments(ListFormat.Type.STANDARD, ListFormat.Style.SHORT), @@ -215,7 +227,7 @@ public class TestListFormat { }; } - static Arguments[] getLocale_localeDependent() { + private static Arguments[] getLocale_localeDependent() { return new Arguments[] { arguments(Locale.ROOT), arguments(Locale.US), @@ -225,6 +237,16 @@ public class TestListFormat { }; } + private static Arguments[] getInstance_1Arg_InvalidLongPattern() { + return new Arguments[] { + arguments(0, "start pattern is incorrect:"), + arguments(1, "middle pattern is incorrect:"), + arguments(2, "end pattern is incorrect:"), + arguments(3, "pattern for two is incorrect:"), + arguments(4, "pattern for three is incorrect:"), + }; + } + @ParameterizedTest @MethodSource void getInstance_1Arg(String[] patterns, List input, String expected) throws ParseException { @@ -240,6 +262,25 @@ public class TestListFormat { assertEquals(errorMsg, ex.getMessage()); } + @ParameterizedTest + @MethodSource + void getInstance_1Arg_InvalidLongPattern(int index, String expected) { + var patterns = new String[]{ + "{0}, {1}", + "{0}, {1}", + "{0}, and {1}", + "{0} and {1}", + "{0} {1} {2}" + }; + patterns[index] = "{0}".repeat(100_000); + + // Ensures validation of invalid long patterns completes without timing out + var msg = assertThrows(IllegalArgumentException.class, + () -> ListFormat.getInstance(patterns)) + .getMessage(); + assertEquals(expected, msg.substring(0, Math.min(msg.length(), expected.length()))); + } + @ParameterizedTest @MethodSource void getInstance_3Arg(Locale l, ListFormat.Type type, ListFormat.Style style, String expected, boolean roundTrip) throws ParseException { @@ -348,6 +389,7 @@ public class TestListFormat { // should be inherited from parent locales. Locale.availableLocales().forEach(l -> ListFormat.getInstance(l, type, style)); } + @Test void getInstance_3Arg_InheritanceValidation() { // Tests if inheritance works as expected. From 43d80fd19233cc6691db9fb47963a4a227996eb6 Mon Sep 17 00:00:00 2001 From: Anthony Scarpino Date: Tue, 2 Jun 2026 21:42:24 +0000 Subject: [PATCH 034/115] 8329548: Change KeyUpdate messages from TLS 1.3 Reviewed-by: jnimeh --- .../classes/sun/security/ssl/SSLCipher.java | 18 +- .../ssl/SSLEngineImpl/KeyUpdateOnce.java | 546 ++++++++++++++++++ 2 files changed, 560 insertions(+), 4 deletions(-) create mode 100644 test/jdk/sun/security/ssl/SSLEngineImpl/KeyUpdateOnce.java diff --git a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java index 9d1d6dabaec..a0fc6c6e207 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package sun.security.ssl; import sun.security.ssl.Authenticator.MAC; +import sun.security.util.Debug; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -371,15 +372,15 @@ enum SSLCipher { ProtocolVersion[]>[] writeCipherGenerators; // Map of Ciphers listed in jdk.tls.keyLimits - private static final HashMap cipherLimits = new HashMap<>(); + static final HashMap cipherLimits = new HashMap<>(); // Keywords found on the jdk.tls.keyLimits security property. static final String[] tag = {"KEYUPDATE"}; + static final long COUNTDOWNWARN = 20000; // Print debug warning under limit static { final long max = 4611686018427387904L; // 2^62 String prop = Security.getProperty("jdk.tls.keyLimits"); - if (prop != null) { String[] propvalue = prop.split(","); @@ -617,12 +618,21 @@ enum SSLCipher { /** * Check if processed bytes have reached the key usage limit. - * If key usage limit is not be monitored, return false. + * If key usage limits are not be monitored, return false. */ public boolean atKeyLimit() { + if (keyLimitCountdown < COUNTDOWNWARN && SSLLogger.isOn()) { + SSLLogger.fine("keyLimitCountdown: " + keyLimitCountdown); + } if (keyLimitCountdown >= 0) { return false; } + if (keyLimitEnabled == false) { + if (SSLLogger.isOn()) { + SSLLogger.fine("KeyUpdate already sent, skipping"); + } + return false; + } // Turn off limit checking as KeyUpdate will be occurring keyLimitEnabled = false; diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/KeyUpdateOnce.java b/test/jdk/sun/security/ssl/SSLEngineImpl/KeyUpdateOnce.java new file mode 100644 index 00000000000..298ba86250a --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/KeyUpdateOnce.java @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8329548 + * @library ../../ + * /test/lib + * /javax/net/ssl/templates + * @summary Verify KeyUpdate messages skipped after first one sent. + * + * @run main KeyUpdateOnce server TLS_AES_256_GCM_SHA384 200000 + * @run main KeyUpdateOnce client TLS_AES_256_GCM_SHA384 200000 + */ + +/* + * This test runs in another process so we can monitor the debug + * results. The OutputAnalyzer must see correct debug output to return a + * success. + */ + +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; + +import java.lang.reflect.Field; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; + +/** + * This server/client TLS test will force side A to stop reading as it + * continuously writes out. These write ops will trigger the side B to + * request a KeyUpdate. With side A not reading, side B must skip + * sending more KeyUpdate messages. Only one KeyUpdate message will be + * sent by side B. + * + * This test depends on debug messages string match. Changing the KeyUpdate- + * related messages may cause a failure. + */ + +public class KeyUpdateOnce extends SSLContextTemplate { + + private static final int DATALEN = 10240; + private static final int BUF_DATALEN = 4 * DATALEN; + private static final int MAXLOOPS = 150; + private static final int COUNTDOWNLIMIT = 5; + + private static final boolean DEBUG = true; + + private static ByteBuffer cTos; + private static ByteBuffer sToc; + private static ByteBuffer outData; + private final ByteBuffer inData; + + // thread flags + private static boolean ready = false; + private static boolean sc = true; + private static boolean readDone = false; + private static boolean serverWrites = true; + + private static long newLimit; + + // Reflection handle captured on read side once handshake completes + private static Object readSideInputRecord = null; + + protected SSLEngine engine; + private final int delay = 1; + private int totalDataLen = 0; + + KeyUpdateOnce() { + this.inData = ByteBuffer.allocate(BUF_DATALEN); + } + + /** + * args should have: + * server|client, cipherSuite, + * + * Prepending 'p' is for internal use only (test harness relaunch). + */ + public static void main(String[] args) throws Exception { + for (String arg : args) { + System.out.print(" " + arg); + } + System.out.println(); + + // Harness mode: relaunch self with 'p' to force add-opens + debugging flags + if (!"p".equals(args[0])) { + // args[]: 0 = client/server, 1 = cipher suite, 2 = newLimit + System.setProperty("test.java.opts", + System.getProperty("test.java.opts") + + " -Dtest.src=" + System.getProperty("test.src") + + " -Dtest.jdk=" + System.getProperty("test.jdk") + + " -Djavax.net.debug=ssl,handshake" + + " -Djavatest.maxOutputSize=99999999" + + " --add-opens java.base/sun.security.ssl=ALL-UNNAMED"); + + System.out.println("test.java.opts: " + + System.getProperty("test.java.opts")); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + Utils.addTestJavaOpts("KeyUpdateOnce", "p", args[0], + args[1], args[2])); + + OutputAnalyzer output = ProcessTools.executeProcess(pb); + try { + output.shouldContain(String.format( + "\"cipher suite\" : \"%s", args[1])); + System.err.println("Output logs should show KeyUpdate has" + + " been sent and skipped"); + List producedList = output.asLines().stream() + .filter(s -> s.contains("Produced KeyUpdate")) + .toList(); + List skippingList = output.asLines().stream() + .filter(s -> s.contains("KeyUpdate already sent, skipping")) + .toList(); + producedList.forEach(System.err::println); + skippingList.forEach(System.err::println); + System.err.println("\"Produced KeyUpdate\" count = " + producedList.size()); + System.err.println("\"KeyUpdate already send, skipping\" count = " + skippingList.size()); + + /* + * Sometimes debug messages may not be consistent. The below + * checks verify that at least 1 of each message were received. + */ + // Ideally there should be 2 "Produced KeyUpdate" + if (producedList.isEmpty()) { + throw new AssertionError("No \"Produced KeyUpdate\""); + } + // Ideally there should be 5 "KeyUpdate already send, skipping" + if (skippingList.isEmpty()) { + throw new AssertionError("No \"KeyUpdate already send, skipping\""); + } + + } finally { + System.out.println("-- BEGIN Stdout:"); + System.out.println(output.getStdout()); + System.out.println("-- END Stdout"); + System.out.println("-- BEGIN Stderr:"); + System.out.println(output.getStderr()); + System.out.println("-- END Stderr"); + } + return; + } + + // Worker mode: + // args[]: 0 = p, 1 = client/server, 2 = cipher suite, 3 = newLimit + serverWrites = !"client".equals(args[1]); + newLimit = Long.parseLong(args[3]); + + cTos = ByteBuffer.allocateDirect(BUF_DATALEN); + sToc = ByteBuffer.allocateDirect(BUF_DATALEN); + outData = ByteBuffer.allocateDirect(DATALEN); + + byte[] data = new byte[DATALEN]; + Arrays.fill(data, (byte) 0x0A); + outData.put(data).flip(); + + cTos.clear(); + sToc.clear(); + + Thread peer = new Thread(serverWrites ? new Client() : + new Server(args[2])); + peer.start(); + + (serverWrites ? new Server(args[2]) : new Client()).run(); + + peer.interrupt(); + peer.join(); + } + + private static void doTask(SSLEngineResult result, SSLEngine engine) + throws Exception { + if (result.getHandshakeStatus() == + SSLEngineResult.HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + print("\trunning delegated task..."); + runnable.run(); + } + SSLEngineResult.HandshakeStatus hsStatus = + engine.getHandshakeStatus(); + if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) { + throw new Exception("handshake shouldn't need additional tasks"); + } + print("\tnew HandshakeStatus: " + hsStatus); + } + } + + private static void print(String s) { + if (DEBUG) { + System.err.println(s); + } + } + + private static void log(String s, SSLEngineResult r) { + if (DEBUG) { + System.err.println(s + ": " + + r.getStatus() + "/" + r.getHandshakeStatus() + " " + + r.bytesConsumed() + "/" + r.bytesProduced()); + } + } + + private static void dumpBuffers(String aName, ByteBuffer a) { + if (DEBUG) { + System.err.println(aName + " pos=" + a.position() + + " rem=" + a.remaining() + + " lim=" + a.limit() + " cap=" + a.capacity()); + } + } + + void writeLoop() throws Exception { + int i = 0; + SSLEngineResult r; + int countdown = COUNTDOWNLIMIT; + + while (!ready) { + Thread.sleep(delay); + } + + print("Write-side begins"); + + while (i++ < MAXLOOPS) { + while (sc) { + if (readDone) { + return; + } + Thread.sleep(delay); + } + + outData.rewind(); + + while (true) { + r = engine.wrap(outData, getWriteBuf()); + log("write wrap", r); + + if (DEBUG && r.getStatus() != SSLEngineResult.Status.OK) { + dumpBuffers("outData", outData); + dumpBuffers("writeBuf", getWriteBuf()); + } + + if (r.getStatus() == SSLEngineResult.Status.OK && + r.getHandshakeStatus() == + SSLEngineResult.HandshakeStatus.NEED_WRAP) { + continue; + } + break; + } + + doTask(r, engine); + + getWriteBuf().flip(); + sc = true; + + while (sc) { + if (readDone) { + return; + } + Thread.sleep(delay); + } + + long rlimit = Long.MAX_VALUE; + if (readSideInputRecord != null) { + rlimit = getReadLimit(readSideInputRecord); + } + if (rlimit <= 0) { + countdown--; + } + System.err.println("Write side readLimit = " + rlimit); + + if (countdown == COUNTDOWNLIMIT || countdown <= 0) { + inData.clear(); + r = engine.unwrap(getReadBuf(), inData); + log("write unwrap", r); + + if (DEBUG && r.getStatus() != SSLEngineResult.Status.OK) { + dumpBuffers("inData", inData); + dumpBuffers("readBuf", getReadBuf()); + } + } else { + print("write side unwrap skipped"); + } + + doTask(r, engine); + getReadBuf().compact(); + dumpBuffers("compacted getReadBuf()", getReadBuf()); + sc = true; + } + } + + void readLoop() throws Exception { + byte b = 0x0B; + ByteBuffer buf = ByteBuffer.allocateDirect(DATALEN); + + SSLEngineResult r = null; + boolean again = true; + boolean firstNotHandshake = false; + + while (engine == null) { + Thread.sleep(delay); + } + + try { + System.out.println("connected"); + print("entering read loop"); + ready = true; + + while (true) { + while (!sc) { + Thread.sleep(delay); + } + + boolean exit = false; + while (!exit) { + buf.put(b); + buf.flip(); + + r = engine.wrap(buf, getWriteBuf()); + log("read wrap", r); + + if (DEBUG) { + dumpBuffers("buf", buf); + dumpBuffers( "writeBuf", getWriteBuf()); + } + + if (again && r.getStatus() == SSLEngineResult.Status.OK && + r.getHandshakeStatus() == + SSLEngineResult.HandshakeStatus.NEED_WRAP) { + buf.compact(); + again = false; + continue; + } + exit = true; + } + + doTask(r, engine); + + buf.clear(); + getWriteBuf().flip(); + sc = false; + + while (!sc) { + Thread.sleep(delay); + } + + while (true) { + inData.clear(); + r = engine.unwrap(getReadBuf(), inData); + log("read unwrap", r); + + if (DEBUG && r.getStatus() != SSLEngineResult.Status.OK) { + dumpBuffers("inData", inData); + dumpBuffers("readBuf", getReadBuf()); + + doTask(r, engine); + } + + if (again && r.getStatus() == SSLEngineResult.Status.OK && + r.getHandshakeStatus() == + SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { + inData.clear(); + print("again"); + again = false; + continue; + } + break; + } + + inData.clear(); + getReadBuf().compact(); + + totalDataLen += r.bytesProduced(); + sc = false; + + if (!firstNotHandshake && + r.getHandshakeStatus() == + SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { + + try { + readSideInputRecord = getInputRecord(engine); + setReadLimit(readSideInputRecord, newLimit); + } catch (Exception e) { + throw new RuntimeException(e); + } + System.err.println("Resetting readside"); + firstNotHandshake = true; + } + } + } catch (Exception e) { + sc = false; + readDone = true; + + System.out.println(e.getMessage()); + e.printStackTrace(); + System.out.println("Total data read = " + totalDataLen); + } + } + + // Overridden in Server/Client + ByteBuffer getReadBuf() { + return null; + } + ByteBuffer getWriteBuf() { + return null; + } + + SSLContext initContext() throws Exception { + return createServerSSLContext(); + } + + @Override + protected SSLContextTemplate.ContextParameters getServerContextParameters() { + return new SSLContextTemplate.ContextParameters("TLSv1.3", "PKIX", "NewSunX509"); + } + + static Object getInputRecord(SSLEngine eng) throws Exception { + Class engineImplCls = Class.forName("sun.security.ssl.SSLEngineImpl"); + Object conContext = getPrivate(eng, engineImplCls, "conContext"); + + Class transportCtxCls = Class.forName("sun.security.ssl.TransportContext"); + return getPrivate(conContext, transportCtxCls, "inputRecord"); + } + + static void setReadLimit(Object inputRecord, long newCountdown) throws Exception { + Class inputRecordCls = Class.forName("sun.security.ssl.InputRecord"); + Object readCipher = getPrivate(inputRecord, inputRecordCls, "readCipher"); + Class sslReadCipher = readCipher.getClass().getSuperclass(); + + Field f = getField(sslReadCipher, "keyLimitCountdown"); + f.setLong(readCipher, newCountdown); + } + + static long getReadLimit(Object inputRecord) throws Exception { + Class inputRecordCls = Class.forName("sun.security.ssl.InputRecord"); + Object readCipher = getPrivate(inputRecord, inputRecordCls, "readCipher"); + Class sslReadCipher = readCipher.getClass().getSuperclass(); + + Field f = getField(sslReadCipher, "keyLimitCountdown"); + return f.getLong(readCipher); + } + + private static Field getField(Class type, String name) throws Exception { + Field f = type.getDeclaredField(name); + f.setAccessible(true); // requires --add-opens for sun.security.ssl + return f; + } + + private static Object getPrivate(Object target, Class owner, String name) throws Exception { + return getField(owner, name).get(target); + } + + static class Server extends KeyUpdateOnce implements Runnable { + Server(String cipherSuite) throws Exception { + super(); + engine = initContext().createSSLEngine(); + engine.setUseClientMode(false); + engine.setNeedClientAuth(true); + + if (cipherSuite != null && !cipherSuite.isEmpty()) { + engine.setEnabledCipherSuites(new String[] { cipherSuite }); + } + } + + @Override + public void run() { + try { + if (serverWrites) { + writeLoop(); + } else { + readLoop(); + } + } catch (Exception e) { + System.out.println("server: " + e.getMessage()); + e.printStackTrace(); + } + System.out.println("Server closed"); + } + + @Override + ByteBuffer getWriteBuf() { + return sToc; + } + + @Override + ByteBuffer getReadBuf() { + return cTos; + } + } + + static class Client extends KeyUpdateOnce implements Runnable { + Client() throws Exception { + super(); + engine = initContext().createSSLEngine(); + engine.setUseClientMode(true); + } + + @Override + public void run() { + try { + if (!serverWrites) { + writeLoop(); + } else { + readLoop(); + } + } catch (Exception e) { + System.out.println("client: " + e.getMessage()); + e.printStackTrace(); + } + System.out.println("Client closed"); + } + + @Override + ByteBuffer getWriteBuf() { + return cTos; + } + + @Override + ByteBuffer getReadBuf() { + return sToc; + } + } +} From f630ab0e5fc1c1b9d598ae80f0fe99262049eabe Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Tue, 2 Jun 2026 22:35:48 +0000 Subject: [PATCH 035/115] 8384250: [macos] Test tools/jpackage/share/AsyncTest.java failed Reviewed-by: asemenyuk --- test/jdk/tools/jpackage/share/AsyncTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/jdk/tools/jpackage/share/AsyncTest.java b/test/jdk/tools/jpackage/share/AsyncTest.java index b7dd13f91fa..ae90e6315e8 100644 --- a/test/jdk/tools/jpackage/share/AsyncTest.java +++ b/test/jdk/tools/jpackage/share/AsyncTest.java @@ -113,7 +113,10 @@ public class AsyncTest { @Test @ParameterSupplier("ids") public void testNativeBundle(int id) throws Exception { - new PackageTest().addInitializer(AsyncTest::init).run(Action.CREATE_AND_UNPACK); + new PackageTest() + .excludeTypes(PackageType.MAC_DMG) // See JDK-8384250 + .addInitializer(AsyncTest::init) + .run(Action.CREATE_AND_UNPACK); } public static Collection ids() { From ab33d9d33121086a037db577753b743ef3f7047c Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 3 Jun 2026 03:55:28 +0000 Subject: [PATCH 036/115] 8385490: Update HarfBuzz to 14.2.0 Reviewed-by: prr, azvegint --- src/java.desktop/share/legal/harfbuzz.md | 4 +- .../native/libharfbuzz/OT/Color/COLR/COLR.hh | 17 +- .../native/libharfbuzz/OT/Color/CPAL/CPAL.hh | 2 +- .../native/libharfbuzz/OT/Color/sbix/sbix.hh | 2 +- .../native/libharfbuzz/OT/Color/svg/svg.hh | 684 +- .../native/libharfbuzz/OT/Layout/GDEF/GDEF.hh | 4 +- .../OT/Layout/GPOS/CursivePosFormat1.hh | 22 +- .../libharfbuzz/OT/Layout/GPOS/PairSet.hh | 6 +- .../OT/Layout/GPOS/SinglePosFormat1.hh | 2 +- .../OT/Layout/GPOS/SinglePosFormat2.hh | 2 +- .../libharfbuzz/OT/Layout/GPOS/ValueFormat.hh | 2 +- .../native/libharfbuzz/OT/Var/VARC/VARC.cc | 68 +- .../libharfbuzz/OT/glyf/CompositeGlyph.hh | 2 +- .../share/native/libharfbuzz/OT/glyf/Glyph.hh | 28 +- .../native/libharfbuzz/OT/glyf/SimpleGlyph.hh | 1 + .../share/native/libharfbuzz/OT/glyf/glyf.hh | 4 +- .../share/native/libharfbuzz/OT/name/name.hh | 2 +- .../libharfbuzz/graph/classdef-graph.hh | 6 +- .../libharfbuzz/graph/coverage-graph.hh | 6 +- .../share/native/libharfbuzz/graph/graph.hh | 22 + .../libharfbuzz/graph/gsubgpos-graph.hh | 8 +- .../libharfbuzz/graph/markbasepos-graph.hh | 9 +- .../native/libharfbuzz/graph/pairpos-graph.hh | 5 +- .../native/libharfbuzz/graph/serialize.hh | 2 +- .../libharfbuzz/hb-aat-layout-kerx-table.hh | 2 +- .../libharfbuzz/hb-aat-layout-morx-table.hh | 17 +- .../share/native/libharfbuzz/hb-algs.hh | 227 +- .../share/native/libharfbuzz/hb-array.hh | 46 +- .../share/native/libharfbuzz/hb-atomic.hh | 3 + .../share/native/libharfbuzz/hb-bimap.hh | 2 +- .../libharfbuzz/hb-bit-set-invertible.hh | 9 +- .../share/native/libharfbuzz/hb-bit-set.hh | 30 +- .../share/native/libharfbuzz/hb-blob.cc | 310 +- .../share/native/libharfbuzz/hb-blob.hh | 158 + .../native/libharfbuzz/hb-buffer-serialize.cc | 44 +- .../native/libharfbuzz/hb-buffer-verify.cc | 31 +- .../share/native/libharfbuzz/hb-buffer.cc | 58 +- .../share/native/libharfbuzz/hb-buffer.h | 14 +- .../share/native/libharfbuzz/hb-buffer.hh | 39 +- .../libharfbuzz/hb-cff-interp-common.hh | 41 +- .../native/libharfbuzz/hb-cff2-interp-cs.hh | 11 +- .../share/native/libharfbuzz/hb-config.hh | 27 +- .../share/native/libharfbuzz/hb-cplusplus.hh | 72 +- .../share/native/libharfbuzz/hb-draw.cc | 278 +- .../share/native/libharfbuzz/hb-draw.h | 52 + .../native/libharfbuzz/hb-face-builder.cc | 6 +- .../share/native/libharfbuzz/hb-font.cc | 41 +- .../share/native/libharfbuzz/hb-font.hh | 26 +- .../share/native/libharfbuzz/hb-ft.cc | 20 +- .../share/native/libharfbuzz/hb-geometry.hh | 52 +- .../share/native/libharfbuzz/hb-limits.hh | 29 + .../share/native/libharfbuzz/hb-machinery.hh | 4 +- .../share/native/libharfbuzz/hb-map.hh | 6 +- .../share/native/libharfbuzz/hb-number.cc | 7 + .../share/native/libharfbuzz/hb-object.hh | 17 +- .../share/native/libharfbuzz/hb-open-type.hh | 39 +- .../native/libharfbuzz/hb-ot-cff-common.hh | 6 +- .../native/libharfbuzz/hb-ot-cff1-table.cc | 7 + .../native/libharfbuzz/hb-ot-cff1-table.hh | 12 +- .../native/libharfbuzz/hb-ot-cff2-table.cc | 7 + .../native/libharfbuzz/hb-ot-cff2-table.hh | 4 +- .../native/libharfbuzz/hb-ot-cmap-table.hh | 170 +- .../share/native/libharfbuzz/hb-ot-color.cc | 68 + .../share/native/libharfbuzz/hb-ot-color.h | 14 + .../libharfbuzz/hb-ot-face-table-list.hh | 2 + .../share/native/libharfbuzz/hb-ot-font.cc | 20 +- .../native/libharfbuzz/hb-ot-hdmx-table.hh | 4 +- .../native/libharfbuzz/hb-ot-kern-table.hh | 2 +- .../native/libharfbuzz/hb-ot-layout-common.hh | 41 +- .../libharfbuzz/hb-ot-layout-gsubgpos.hh | 70 +- .../share/native/libharfbuzz/hb-ot-layout.cc | 12 +- .../native/libharfbuzz/hb-ot-os2-table.hh | 2 +- .../native/libharfbuzz/hb-ot-post-table.hh | 14 +- .../libharfbuzz/hb-ot-shape-normalize.cc | 6 +- .../share/native/libharfbuzz/hb-ot-shape.cc | 24 +- .../share/native/libharfbuzz/hb-ot-shape.h | 15 + .../libharfbuzz/hb-ot-shaper-arabic-pua.hh | 138 +- .../libharfbuzz/hb-ot-shaper-arabic-table.hh | 267 +- .../native/libharfbuzz/hb-ot-shaper-arabic.cc | 50 +- .../native/libharfbuzz/hb-ot-shaper-hangul.cc | 4 +- .../libharfbuzz/hb-ot-shaper-indic-table.cc | 488 +- .../native/libharfbuzz/hb-ot-shaper-thai.cc | 12 +- .../libharfbuzz/hb-ot-shaper-use-table.hh | 1052 +- .../hb-ot-shaper-vowel-constraints.cc | 2 +- .../native/libharfbuzz/hb-ot-tag-table.hh | 1278 ++- .../share/native/libharfbuzz/hb-ot-tag.cc | 153 +- .../native/libharfbuzz/hb-ot-var-common.hh | 52 +- .../libharfbuzz/hb-ot-var-gvar-table.hh | 111 +- .../libharfbuzz/hb-ot-var-hvar-table.hh | 2 +- .../share/native/libharfbuzz/hb-outline.hh | 2 +- .../share/native/libharfbuzz/hb-paint.cc | 420 +- .../share/native/libharfbuzz/hb-paint.h | 248 +- .../share/native/libharfbuzz/hb-paint.hh | 28 + .../native/libharfbuzz/hb-priority-queue.hh | 2 +- .../share/native/libharfbuzz/hb-repacker.hh | 7 +- .../share/native/libharfbuzz/hb-static.cc | 7 + .../libharfbuzz/hb-subset-cff-common.cc | 8 +- .../libharfbuzz/hb-subset-cff-common.hh | 26 +- .../native/libharfbuzz/hb-subset-cff1.cc | 6 +- .../native/libharfbuzz/hb-subset-cff2.cc | 596 +- .../libharfbuzz/hb-subset-instancer-solver.cc | 35 +- .../share/native/libharfbuzz/hb-subset.h | 16 +- .../share/native/libharfbuzz/hb-ucd-table.hh | 8449 +++++++++-------- .../libharfbuzz/hb-unicode-emoji-table.hh | 61 +- .../share/native/libharfbuzz/hb-unicode.cc | 12 +- .../share/native/libharfbuzz/hb-vector.hh | 69 +- .../share/native/libharfbuzz/hb-version.h | 8 +- .../share/native/libharfbuzz/hb-zlib.hh | 37 + .../share/native/libharfbuzz/hb.hh | 10 +- 109 files changed, 9835 insertions(+), 6949 deletions(-) create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-zlib.hh diff --git a/src/java.desktop/share/legal/harfbuzz.md b/src/java.desktop/share/legal/harfbuzz.md index 3aa5ca841d6..448de3faee1 100644 --- a/src/java.desktop/share/legal/harfbuzz.md +++ b/src/java.desktop/share/legal/harfbuzz.md @@ -1,4 +1,4 @@ -## Harfbuzz 12.3.2 +## Harfbuzz v14.2.0 ### Harfbuzz License @@ -75,7 +75,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. The below applies to the following file(s): libharfbuzz/hb-unicode-emoji-table.hh -© 2024 Unicode®, Inc. +© 2025 Unicode®, Inc. Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh index 011b5ad5520..37bb8a8f945 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh @@ -525,7 +525,13 @@ struct ColorLine hb_paint_extend_t get_extend () const { - return (hb_paint_extend_t) (unsigned int) extend; + switch ((unsigned int) extend) + { + case Extend::EXTEND_REPEAT: return HB_PAINT_EXTEND_REPEAT; + case Extend::EXTEND_REFLECT: return HB_PAINT_EXTEND_REFLECT; + case Extend::EXTEND_PAD: + default: return HB_PAINT_EXTEND_PAD; + } } HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line, @@ -1520,9 +1526,9 @@ struct PaintComposite void paint_glyph (hb_paint_context_t *c) const { TRACE_PAINT (this); - c->funcs->push_group (c->data); + c->funcs->push_group_for (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); c->recurse (this+backdrop); - c->funcs->push_group (c->data); + c->funcs->push_group_for (c->data, (hb_paint_composite_mode_t) (int) mode); c->recurse (this+src); c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode); c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); @@ -1814,10 +1820,7 @@ struct ClipList { auto *rec = clips.as_array ().bsearch (gid); if (rec) - { - rec->get_extents (extents, this, instancer); - return true; - } + return rec->get_extents (extents, this, instancer); return false; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh index 71417fdf3cf..f79e236bce9 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh @@ -172,7 +172,7 @@ struct CPAL bool has_data () const { return numPalettes; } - unsigned int get_size () const + size_t get_size () const { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); } unsigned int get_palette_count () const { return numPalettes; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh index b77486a4340..f6e6c5e3a9d 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh @@ -79,7 +79,7 @@ struct SBIXGlyph struct SBIXStrike { - static unsigned int get_size (unsigned num_glyphs) + static size_t get_size (unsigned num_glyphs) { return min_size + num_glyphs * HBUINT32::static_size; } bool sanitize (hb_sanitize_context_t *c) const diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh index 9249abf7075..a0fd2c88d0a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh @@ -27,7 +27,12 @@ #include "../../../hb-open-type.hh" #include "../../../hb-blob.hh" +#include "../../../hb-limits.hh" +#include "../../../hb-map.hh" #include "../../../hb-paint.hh" +#include "../../../hb-zlib.hh" +#include +#include /* * SVG -- SVG (Scalable Vector Graphics) @@ -39,12 +44,62 @@ namespace OT { +static inline hb_blob_t * +hb_ot_svg_reference_normalized_blob (hb_blob_t *image, + const char **svg, + unsigned *len) +{ + hb_blob_t *blob = hb_blob_reference (image); + unsigned data_len = 0; + const char *data = hb_blob_get_data (blob, &data_len); + + if (!data || !data_len) + goto fail; + + if (hb_blob_is_gzip (data, data_len)) + { + uint32_t expected_size = 0; + if (hb_gzip_get_uncompressed_size (data, data_len, &expected_size) && + unlikely ((size_t) expected_size > (size_t) HB_SVG_MAX_DOCUMENT_SIZE)) + goto fail; + + hb_blob_t *uncompressed = hb_blob_decompress_gzip (blob, + HB_SVG_MAX_DOCUMENT_SIZE); + if (!uncompressed) + goto fail; + + hb_blob_destroy (blob); + blob = uncompressed; + data = hb_blob_get_data (blob, &data_len); + if (!data || !data_len) + goto fail; + } + + if (unlikely ((size_t) data_len > (size_t) HB_SVG_MAX_DOCUMENT_SIZE)) + goto fail; + + if (svg) *svg = data; + if (len) *len = data_len; + return blob; + +fail: + hb_blob_destroy (blob); + if (svg) *svg = nullptr; + if (len) *len = 0; + return nullptr; +} struct SVGDocumentIndexEntry { int cmp (hb_codepoint_t g) const { return g < startGlyphID ? -1 : g > endGlyphID ? 1 : 0; } + hb_codepoint_t get_start_glyph () const + { return startGlyphID; } + + hb_codepoint_t get_end_glyph () const + { return endGlyphID; } + hb_blob_t *reference_blob (hb_blob_t *svg_blob, unsigned int index_offset) const { return hb_blob_create_sub_blob (svg_blob, @@ -78,13 +133,50 @@ struct SVG { static constexpr hb_tag_t tableTag = HB_OT_TAG_SVG; + struct svg_id_span_t + { + const char *p; + unsigned len; + + bool operator == (const svg_id_span_t &o) const + { + return len == o.len && !memcmp (p, o.p, len); + } + + uint32_t hash () const + { + uint32_t h = hb_hash (len); + for (unsigned i = 0; i < len; i++) + h = h * 33u + (unsigned char) p[i]; + return h; + } + }; + + struct svg_defs_entry_t + { + svg_id_span_t id; + unsigned start; + unsigned end; + }; + + struct svg_doc_cache_t + { + hb_blob_t *blob = nullptr; + const char *svg = nullptr; + unsigned len = 0; + hb_vector_t defs_entries; + hb_codepoint_t start_glyph = HB_CODEPOINT_INVALID; + hb_codepoint_t end_glyph = HB_CODEPOINT_INVALID; + hb_vector_t> glyph_spans; + hb_hashmap_t> id_spans; + }; + bool has_data () const { return svgDocEntries; } struct accelerator_t { - accelerator_t (hb_face_t *face) - { table = hb_sanitize_context_t ().reference_table (face); } - ~accelerator_t () { table.destroy (); } + accelerator_t (hb_face_t *face); + ~accelerator_t (); hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const { @@ -92,8 +184,52 @@ struct SVG table->svgDocEntries); } + unsigned get_document_count () const + { return table->get_document_count (); } + + bool get_glyph_document_index (hb_codepoint_t glyph_id, unsigned *index) const + { return table->get_glyph_document_index (glyph_id, index); } + + bool get_document_glyph_range (unsigned index, + hb_codepoint_t *start_glyph, + hb_codepoint_t *end_glyph) const + { return table->get_document_glyph_range (index, start_glyph, end_glyph); } + bool has_data () const { return table->has_data (); } + const svg_doc_cache_t * + get_or_create_doc_cache (hb_blob_t *image, + const char *svg, + unsigned len, + unsigned doc_index, + hb_codepoint_t start_glyph, + hb_codepoint_t end_glyph) const; + + const char * + doc_cache_get_svg (const svg_doc_cache_t *doc, + unsigned *len) const; + + const hb_vector_t * + doc_cache_get_defs_entries (const svg_doc_cache_t *doc) const; + + bool + doc_cache_get_glyph_span (const svg_doc_cache_t *doc, + hb_codepoint_t glyph, + unsigned *start, + unsigned *end) const; + + bool + doc_cache_find_id_span (const svg_doc_cache_t *doc, + svg_id_span_t id, + unsigned *start, + unsigned *end) const; + + bool + doc_cache_find_id_cstr (const svg_doc_cache_t *doc, + const char *id, + unsigned *start, + unsigned *end) const; + bool paint_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const { if (!has_data ()) @@ -117,14 +253,56 @@ struct SVG } private: + svg_doc_cache_t * + make_doc_cache (hb_blob_t *image, + const char *svg, + unsigned len, + hb_codepoint_t start_glyph, + hb_codepoint_t end_glyph) const; + + static void destroy_doc_cache (svg_doc_cache_t *doc); + hb_blob_ptr_t table; + mutable hb_vector_t> doc_caches; public: - DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t)); + DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t) + + sizeof (hb_vector_t>)); }; const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const { return (this+svgDocEntries).bsearch (glyph_id); } + unsigned get_document_count () const + { + if (!has_data ()) + return 0; + return (this + svgDocEntries).len; + } + + bool get_glyph_document_index (hb_codepoint_t glyph_id, unsigned *index) const + { + if (!has_data ()) + return false; + return (this + svgDocEntries).bfind (glyph_id, index); + } + + bool get_document_glyph_range (unsigned index, + hb_codepoint_t *start_glyph, + hb_codepoint_t *end_glyph) const + { + if (!has_data ()) + return false; + + const auto &entries = this + svgDocEntries; + if (index >= entries.len) + return false; + + const auto &entry = entries.arrayZ[index]; + if (start_glyph) *start_glyph = entry.get_start_glyph (); + if (end_glyph) *end_glyph = entry.get_end_glyph (); + return true; + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -143,6 +321,504 @@ struct SVG DEFINE_SIZE_STATIC (10); }; +namespace _hb_svg_cache_impl { + +struct glyph_entry_t +{ + hb_codepoint_t glyph; + uint32_t start; + uint32_t end; +}; + +struct id_entry_t +{ + SVG::svg_id_span_t id; + uint32_t start; + uint32_t end; +}; + +struct open_elem_t +{ + unsigned start; + SVG::svg_id_span_t id; + bool in_defs_content; + bool is_defs; +}; + +static const unsigned MAX_DEPTH = 128; + +static inline int +find_substr (const char *s, + unsigned n, + unsigned from, + const char *needle, + unsigned needle_len) +{ + if (!needle_len || from >= n || needle_len > n) + return -1; + for (unsigned i = from; i + needle_len <= n; i++) + if (s[i] == needle[0] && !memcmp (s + i, needle, needle_len)) + return (int) i; + return -1; +} + +static inline bool +parse_id_in_start_tag (const char *svg, + unsigned tag_start, + unsigned tag_end, + SVG::svg_id_span_t *id) +{ + unsigned p = tag_start; + while (p + 4 <= tag_end) + { + if (!memcmp (svg + p, "id=\"", 4)) + { + unsigned b = p + 4; + unsigned e = b; + while (e < tag_end && svg[e] != '"') e++; + if (e <= tag_end && e > b) + { + *id = {svg + b, e - b}; + return true; + } + } + if (!memcmp (svg + p, "id='", 4)) + { + unsigned b = p + 4; + unsigned e = b; + while (e < tag_end && svg[e] != '\'') e++; + if (e <= tag_end && e > b) + { + *id = {svg + b, e - b}; + return true; + } + } + p++; + } + return false; +} + +static inline bool +parse_glyph_id_span (const SVG::svg_id_span_t &id, + hb_codepoint_t *glyph) +{ + if (id.len <= 5 || memcmp (id.p, "glyph", 5)) + return false; + + hb_codepoint_t gid = 0; + for (unsigned i = 5; i < id.len; i++) + { + unsigned char c = (unsigned char) id.p[i]; + if (c < '0' || c > '9') + return false; + hb_codepoint_t digit = (hb_codepoint_t) (c - '0'); + if (unlikely (gid > HB_CODEPOINT_INVALID / 10 || + (gid == HB_CODEPOINT_INVALID / 10 && + digit > HB_CODEPOINT_INVALID % 10))) + return false; + gid = (hb_codepoint_t) (gid * 10 + digit); + } + + *glyph = gid; + return true; +} + +static inline bool +parse_cache_entries_linear (const char *svg, + unsigned len, + hb_vector_t *defs_entries, + hb_vector_t *glyph_spans, + hb_vector_t *id_entries) +{ + open_elem_t stack[MAX_DEPTH] = {}; + unsigned depth = 0; + if (unlikely (!defs_entries->alloc (256) || + !glyph_spans->alloc (256) || + !id_entries->alloc (256))) + return false; + + unsigned defs_depth = 0; + unsigned i = 0; + while (i < len) + { + if (svg[i] != '<') + { + i++; + continue; + } + + if (i + 4 <= len && !memcmp (svg + i, "", 3); + if (cend < 0) return false; + i = (unsigned) cend + 3; + continue; + } + if (i + 9 <= len && !memcmp (svg + i, "", 9)) + { + int cend = find_substr (svg, len, i + 9, "", 3); + if (cend < 0) return false; + i = (unsigned) cend + 3; + continue; + } + + bool closing = (i + 1 < len && svg[i + 1] == '/'); + bool special = (i + 1 < len && (svg[i + 1] == '!' || svg[i + 1] == '?')); + + unsigned gt = i + 1; + char quote = 0; + while (gt < len) + { + char c = svg[gt]; + if (quote) + { + if (c == quote) quote = 0; + } + else + { + if (c == '"' || c == '\'') + quote = c; + else if (c == '>') + break; + } + gt++; + } + if (gt >= len) + return false; + + if (special) + { + i = gt + 1; + continue; + } + + unsigned p = i + (closing ? 2 : 1); + while (p < gt && isspace ((unsigned char) svg[p])) p++; + const char *name = svg + p; + unsigned name_len = 0; + while (p + name_len < gt) + { + unsigned char c = (unsigned char) name[name_len]; + if (!(isalnum (c) || c == '_' || c == '-' || c == ':')) + break; + name_len++; + } + bool is_defs = (name_len == 4 && !memcmp (name, "defs", 4)); + + if (closing) + { + if (!depth) + { + i = gt + 1; + continue; + } + + open_elem_t e = stack[--depth]; + unsigned end = gt + 1; + + if (e.id.len) + { + if (unlikely (!id_entries->push_or_fail (id_entry_t {e.id, (uint32_t) e.start, (uint32_t) end}))) + return false; + + if (e.in_defs_content) + { + if (unlikely (!defs_entries->push_or_fail ())) + return false; + auto &slot = defs_entries->tail (); + slot.id = e.id; + slot.start = e.start; + slot.end = end; + } + + hb_codepoint_t gid; + if (parse_glyph_id_span (e.id, &gid)) + { + if (unlikely (!glyph_spans->push_or_fail (glyph_entry_t {gid, (uint32_t) e.start, (uint32_t) end}))) + return false; + } + } + + if (e.is_defs && defs_depth) + defs_depth--; + + i = end; + continue; + } + + SVG::svg_id_span_t id = {}; + parse_id_in_start_tag (svg, i, gt, &id); + + unsigned r = gt; + while (r > i && isspace ((unsigned char) svg[r - 1])) r--; + bool self_closing = (r > i && svg[r - 1] == '/'); + + open_elem_t e = {}; + e.start = i; + e.id = id; + e.in_defs_content = defs_depth > 0; + e.is_defs = is_defs; + + if (self_closing) + { + unsigned end = gt + 1; + if (e.id.len) + { + if (unlikely (!id_entries->push_or_fail (id_entry_t {e.id, (uint32_t) e.start, (uint32_t) end}))) + return false; + + if (e.in_defs_content) + { + if (unlikely (!defs_entries->push_or_fail ())) + return false; + auto &slot = defs_entries->tail (); + slot.id = e.id; + slot.start = e.start; + slot.end = end; + } + + hb_codepoint_t gid; + if (parse_glyph_id_span (e.id, &gid)) + { + if (unlikely (!glyph_spans->push_or_fail (glyph_entry_t {gid, (uint32_t) e.start, (uint32_t) end}))) + return false; + } + } + } + else + { + if (unlikely (depth >= MAX_DEPTH)) + return false; + stack[depth++] = e; + if (is_defs) + defs_depth++; + } + + i = gt + 1; + } + + return true; +} + +} /* namespace _hb_svg_cache_impl */ + +inline +SVG::accelerator_t::accelerator_t (hb_face_t *face) +{ + table = hb_sanitize_context_t ().reference_table (face); + doc_caches.init (); + unsigned doc_count = table->get_document_count (); + if (doc_count && unlikely (!doc_caches.resize (doc_count))) + doc_caches.clear (); + for (unsigned i = 0; i < doc_caches.length; i++) + doc_caches.arrayZ[i].set_relaxed (nullptr); +} + +inline +SVG::accelerator_t::~accelerator_t () +{ + for (unsigned i = 0; i < doc_caches.length; i++) + destroy_doc_cache (doc_caches.arrayZ[i].get_relaxed ()); + doc_caches.fini (); + table.destroy (); +} + +inline void +SVG::accelerator_t::destroy_doc_cache (svg_doc_cache_t *doc) +{ + if (!doc) + return; + doc->glyph_spans.fini (); + doc->defs_entries.fini (); + doc->id_spans.fini (); + hb_blob_destroy (doc->blob); + hb_free (doc); +} + +inline SVG::svg_doc_cache_t * +SVG::accelerator_t::make_doc_cache (hb_blob_t *image, + const char *svg, + unsigned len, + hb_codepoint_t start_glyph, + hb_codepoint_t end_glyph) const +{ + static const uint32_t INVALID_SPAN = 0xFFFFFFFFu; + + auto *doc = (svg_doc_cache_t *) hb_malloc (sizeof (svg_doc_cache_t)); + if (!doc) + return nullptr; + + doc->blob = nullptr; + doc->svg = nullptr; + doc->len = 0; + doc->defs_entries.init (); + doc->start_glyph = HB_CODEPOINT_INVALID; + doc->end_glyph = HB_CODEPOINT_INVALID; + doc->glyph_spans.init (); + doc->id_spans.init (); + + doc->blob = hb_blob_reference (image); + doc->svg = svg; + doc->len = len; + doc->start_glyph = start_glyph; + doc->end_glyph = end_glyph; + + if (unlikely (start_glyph == HB_CODEPOINT_INVALID || end_glyph < start_glyph)) + { + destroy_doc_cache (doc); + return nullptr; + } + + unsigned glyph_count = end_glyph - start_glyph + 1; + if (!doc->glyph_spans.resize ((int) glyph_count)) + { + destroy_doc_cache (doc); + return nullptr; + } + for (unsigned i = 0; i < glyph_count; i++) + doc->glyph_spans.arrayZ[i] = hb_pair_t (INVALID_SPAN, INVALID_SPAN); + + hb_vector_t<_hb_svg_cache_impl::glyph_entry_t> glyph_spans; + glyph_spans.init (); + hb_vector_t<_hb_svg_cache_impl::id_entry_t> id_entries; + id_entries.init (); + if (!_hb_svg_cache_impl::parse_cache_entries_linear (svg, len, + &doc->defs_entries, + &glyph_spans, + &id_entries)) + { + id_entries.fini (); + glyph_spans.fini (); + destroy_doc_cache (doc); + return nullptr; + } + + for (unsigned i = 0; i < glyph_spans.length; i++) + { + const auto &span = glyph_spans.arrayZ[i]; + if (unlikely (span.glyph < start_glyph || span.glyph > end_glyph)) + continue; + doc->glyph_spans.arrayZ[span.glyph - start_glyph] = hb_pair_t (span.start, span.end); + } + + for (unsigned i = 0; i < id_entries.length; i++) + { + const auto &e = id_entries.arrayZ[i]; + hb_pair_t *out = nullptr; + if (doc->id_spans.has (e.id, &out)) + continue; + if (unlikely (!doc->id_spans.set (e.id, hb_pair_t (e.start, e.end)))) + { + id_entries.fini (); + glyph_spans.fini (); + destroy_doc_cache (doc); + return nullptr; + } + } + + id_entries.fini (); + glyph_spans.fini (); + return doc; +} + +inline const SVG::svg_doc_cache_t * +SVG::accelerator_t::get_or_create_doc_cache (hb_blob_t *image, + const char *svg, + unsigned len, + unsigned doc_index, + hb_codepoint_t start_glyph, + hb_codepoint_t end_glyph) const +{ + if (doc_index >= doc_caches.length) + return nullptr; + + auto &slot = doc_caches.arrayZ[doc_index]; + auto *doc = slot.get_acquire (); + if (doc) + return doc; + + auto *fresh = make_doc_cache (image, svg, len, start_glyph, end_glyph); + if (!fresh) + return nullptr; + + auto *expected = (svg_doc_cache_t *) nullptr; + if (slot.cmpexch (expected, fresh)) + return fresh; + + destroy_doc_cache (fresh); + return expected; +} + +inline const char * +SVG::accelerator_t::doc_cache_get_svg (const svg_doc_cache_t *doc, + unsigned *len) const +{ + if (!doc) + { + if (len) *len = 0; + return nullptr; + } + if (len) *len = doc->len; + return doc->svg; +} + +inline const hb_vector_t * +SVG::accelerator_t::doc_cache_get_defs_entries (const svg_doc_cache_t *doc) const +{ + return doc ? &doc->defs_entries : nullptr; +} + +inline bool +SVG::accelerator_t::doc_cache_get_glyph_span (const svg_doc_cache_t *doc, + hb_codepoint_t glyph, + unsigned *start, + unsigned *end) const +{ + static const uint32_t INVALID_SPAN = 0xFFFFFFFFu; + if (!doc || doc->start_glyph == HB_CODEPOINT_INVALID || + glyph < doc->start_glyph || glyph > doc->end_glyph) + return false; + + const auto &span = doc->glyph_spans.arrayZ[glyph - doc->start_glyph]; + if (span.first == INVALID_SPAN) + return false; + if (unlikely (span.first > span.second || span.second > doc->len)) + return false; + + if (start) *start = span.first; + if (end) *end = span.second; + return true; +} + +inline bool +SVG::accelerator_t::doc_cache_find_id_span (const svg_doc_cache_t *doc, + svg_id_span_t id, + unsigned *start, + unsigned *end) const +{ + if (!doc || !id.p || !id.len) + return false; + hb_pair_t *span = nullptr; + if (!doc->id_spans.has (id, &span)) + return false; + if (unlikely (span->first > span->second || span->second > doc->len)) + return false; + if (start) *start = span->first; + if (end) *end = span->second; + return true; +} + +inline bool +SVG::accelerator_t::doc_cache_find_id_cstr (const svg_doc_cache_t *doc, + const char *id, + unsigned *start, + unsigned *end) const +{ + if (!id) return false; + svg_id_span_t key = {id, (unsigned) strlen (id)}; + return doc_cache_find_id_span (doc, key, start, end); +} + struct SVG_accelerator_t : SVG::accelerator_t { SVG_accelerator_t (hb_face_t *face) : SVG::accelerator_t (face) {} }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh index 89e110990bc..23412914feb 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh @@ -616,7 +616,7 @@ struct GDEFVersion1_2 public: DEFINE_SIZE_MIN (4 + 4 * Types::size); - unsigned int get_size () const + size_t get_size () const { return min_size + (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + @@ -755,7 +755,7 @@ struct GDEF ComponentGlyph = 4 }; - unsigned int get_size () const + size_t get_size () const { switch (u.version.major) { case 1: return u.version1.get_size (); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh index f5a09e07d73..c96f66da9b3 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh @@ -51,7 +51,11 @@ struct EntryExitRecord }; static inline void -reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) +reverse_cursive_minor_offset (hb_glyph_position_t *pos, + unsigned int len, + unsigned int i, + hb_direction_t direction, + unsigned int new_parent) { int chain = pos[i].attach_chain(), type = pos[i].attach_type(); if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE))) @@ -61,18 +65,28 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc unsigned int j = (int) i + chain; + if (unlikely (j >= len)) + return; + /* Stop if we see new parent in the chain. */ if (j == new_parent) return; - reverse_cursive_minor_offset (pos, j, direction, new_parent); + int16_t reversed_chain = -chain; + /* The old edge was cleared above; if the reversed distance truncates, + * keep it detached instead of storing a poisoned chain. + */ + if (unlikely (reversed_chain != -chain)) + return; + + reverse_cursive_minor_offset (pos, len, j, direction, new_parent); if (HB_DIRECTION_IS_HORIZONTAL (direction)) pos[j].y_offset = -pos[i].y_offset; else pos[j].x_offset = -pos[i].x_offset; - pos[j].attach_chain() = -chain; + pos[j].attach_chain() = reversed_chain; pos[j].attach_type() = type; } @@ -228,7 +242,7 @@ struct CursivePosFormat1 * previous connection now attaches to new parent. Watch out for case * where new parent is on the path from old chain... */ - reverse_cursive_minor_offset (pos, child, c->direction, parent); + reverse_cursive_minor_offset (pos, buffer->len, child, c->direction, parent); pos[child].attach_chain() = (int) parent - (int) child; if (pos[child].attach_chain() != (int) parent - (int) child) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh index e610fcd7517..d8428a12562 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh @@ -24,11 +24,11 @@ struct PairSet : ValueBase public: DEFINE_SIZE_MIN (2); - static unsigned get_size (unsigned len1, unsigned len2) + static size_t get_size (unsigned len1, unsigned len2) { return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2); } - static unsigned get_size (const ValueFormat valueFormats[2]) + static size_t get_size (const ValueFormat valueFormats[2]) { unsigned len1 = valueFormats[0].get_len (); unsigned len2 = valueFormats[1].get_len (); @@ -39,7 +39,7 @@ struct PairSet : ValueBase { const ValueFormat *valueFormats; unsigned int len1; /* valueFormats[0].get_len() */ - unsigned int stride; /* bytes */ + size_t stride; /* bytes */ }; bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh index 1a14be020f9..b33e761bac2 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh @@ -100,7 +100,7 @@ struct SinglePosFormat1 : ValueBase if (likely (index == NOT_COVERED)) return false; /* This is ugly... */ - hb_buffer_t buffer; + hb_buffer_t buffer {}; buffer.props.direction = direction; OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh index 455796b4b27..686126c9f5e 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh @@ -104,7 +104,7 @@ struct SinglePosFormat2 : ValueBase if (unlikely (index >= valueCount)) return false; /* This is ugly... */ - hb_buffer_t buffer; + hb_buffer_t buffer {}; buffer.props.direction = direction; OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh index b961a5139d8..613de17bf6a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh @@ -64,7 +64,7 @@ struct ValueFormat : HBUINT16 // be added to ValueFormat. As such, we use the faster hb_popcount8 // that only processes the lowest 8 bits. unsigned int get_len () const { return hb_popcount8 ((uint8_t) *this); } - unsigned int get_size () const { return get_len () * Value::static_size; } + size_t get_size () const { return get_len () * Value::static_size; } hb_vector_t get_device_table_indices () const { unsigned i = 0; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc index f0e7f934579..792a7553d8f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc +++ b/src/java.desktop/share/native/libharfbuzz/OT/Var/VARC/VARC.cc @@ -228,28 +228,28 @@ VarComponent::get_path_at (const hb_varc_context_t &c, #define PROCESS_TRANSFORM_COMPONENTS \ HB_STMT_START { \ - PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_X, translateX); \ - PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_Y, translateY); \ - PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_ROTATION, rotation); \ - PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_X, scaleX); \ - PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_Y, scaleY); \ - PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_X, skewX); \ - PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_Y, skewY); \ - PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_X, tCenterX); \ - PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_Y, tCenterY); \ + PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_X, translateX); \ + PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_Y, translateY); \ + PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_ROTATION, rotation); \ + PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_X, scaleX); \ + PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_Y, scaleY); \ + PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_X, skewX); \ + PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_Y, skewY); \ + PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_X, tCenterX); \ + PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_Y, tCenterY); \ } HB_STMT_END hb_transform_decomposed_t<> transform; // Read transform components -#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ +#define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ if (flags & (unsigned) flags_t::flag) \ { \ static_assert (type::static_size == HBINT16::static_size, ""); \ if (unlikely (unsigned (end - record) < HBINT16::static_size)) \ return hb_ubytes_t (); \ hb_barrier (); \ - transform.name = mult * * (const HBINT16 *) record; \ + transform.name = * (const HBINT16 *) record; \ record += HBINT16::static_size; \ } PROCESS_TRANSFORM_COMPONENTS; @@ -270,9 +270,8 @@ VarComponent::get_path_at (const hb_varc_context_t &c, { // Only use coord_setter if there's actually any axis overrides. coord_setter_t coord_setter (axisIndices ? component_coords : hb_array ()); - // Go backwards, to reduce coord_setter vector reallocations. - for (unsigned i = axisIndices.length; i; i--) - coord_setter[axisIndices[i - 1]] = axisValues[i - 1]; + for (unsigned i = 0; i < axisIndices.length; i++) + coord_setter[axisIndices[i]] = roundf (axisValues[i]); if (axisIndices) component_coords = coord_setter.get_coords (); @@ -281,39 +280,35 @@ VarComponent::get_path_at (const hb_varc_context_t &c, { float transformValues[9]; unsigned numTransformValues = 0; -#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ +#define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ if (flags & (unsigned) flags_t::flag) \ - transformValues[numTransformValues++] = transform.name / mult; + transformValues[numTransformValues++] = transform.name; PROCESS_TRANSFORM_COMPONENTS; #undef PROCESS_TRANSFORM_COMPONENT varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache); numTransformValues = 0; -#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ +#define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ if (flags & (unsigned) flags_t::flag) \ - transform.name = transformValues[numTransformValues++] * mult; + transform.name = transformValues[numTransformValues++]; PROCESS_TRANSFORM_COMPONENTS; #undef PROCESS_TRANSFORM_COMPONENT } // Divide them by their divisors -#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ - if (flags & (unsigned) flags_t::flag) \ - { \ - HBINT16 int_v; \ - int_v = roundf (transform.name); \ - type typed_v = * (const type *) &int_v; \ - float float_v = (float) typed_v; \ - transform.name = float_v; \ - } +#define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ + if (shift && (flags & (unsigned) flags_t::flag)) \ + transform.name *= 1.f / (1 << shift); PROCESS_TRANSFORM_COMPONENTS; #undef PROCESS_TRANSFORM_COMPONENT if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y)) transform.scaleY = transform.scaleX; + transform.rotation *= HB_PI; + transform.skewX *= HB_PI; + transform.skewY *= HB_PI; + total_transform.transform (transform.to_transform ()); - total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f, - c.font->y_mult ? 1.f / c.font->y_multf : 0.f); bool same_coords = component_coords.length == coords.length && component_coords.arrayZ == coords.arrayZ; @@ -348,14 +343,18 @@ VARC::get_path_at (const hb_varc_context_t &c, { if (c.draw_session) { + hb_transform_t<> leaf_transform = transform; + leaf_transform.x0 *= c.font->x_multf; + leaf_transform.y0 *= c.font->y_multf; + // Build a transforming pen to apply the transform. hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs (); - hb_transforming_pen_context_t context {transform, + hb_transforming_pen_context_t context {leaf_transform, c.draw_session->funcs, c.draw_session->draw_data, &c.draw_session->st}; hb_draw_session_t transformer_session {transformer_funcs, &context}; - hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session; + hb_draw_session_t &shape_draw_session = leaf_transform.is_identity () ? *c.draw_session : transformer_session; if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true; #ifndef HB_NO_CFF @@ -375,7 +374,10 @@ VARC::get_path_at (const hb_varc_context_t &c, return false; hb_extents_t<> comp_extents (glyph_extents); - transform.transform_extents (comp_extents); + hb_transform_t<> leaf_transform = transform; + leaf_transform.x0 *= c.font->x_multf; + leaf_transform.y0 *= c.font->y_multf; + leaf_transform.transform_extents (comp_extents); c.extents->union_ (comp_extents); } return true; @@ -399,8 +401,6 @@ VARC::get_path_at (const hb_varc_context_t &c, parent_cache : (this+varStore).create_cache (&static_cache); - transform.scale (c.font->x_multf, c.font->y_multf); - VarCompositeGlyph::get_path_at (c, glyph, coords, transform, diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh index fb347770e6f..7243e180101 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh @@ -33,7 +33,7 @@ struct CompositeGlyphRecord }; public: - unsigned int get_size () const + size_t get_size () const { unsigned int size = min_size; /* glyphIndex is 24bit instead of 16bit */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh index 8f5287e9457..432b4dfe464 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh @@ -384,20 +384,24 @@ struct Glyph { #ifndef HB_NO_BEYOND_64K if (glyf_accelerator.GVAR->has_data ()) - glyf_accelerator.GVAR->apply_deltas_to_points (gid, - coords, - points.as_array ().sub_array (old_length), - scratch, - gvar_cache, - phantom_only && type == SIMPLE); + { + if (!glyf_accelerator.GVAR->apply_deltas_to_points (gid, + coords, + points.as_array ().sub_array (old_length), + scratch, + gvar_cache, + phantom_only && type == SIMPLE)) + return false; + } else #endif - glyf_accelerator.gvar->apply_deltas_to_points (gid, - coords, - points.as_array ().sub_array (old_length), - scratch, - gvar_cache, - phantom_only && type == SIMPLE); + if (!glyf_accelerator.gvar->apply_deltas_to_points (gid, + coords, + points.as_array ().sub_array (old_length), + scratch, + gvar_cache, + phantom_only && type == SIMPLE)) + return false; } #endif diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh index 507c94f7f3d..d94a2f3ddfe 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh @@ -186,6 +186,7 @@ struct SimpleGlyph /* One extra item at the end, for the instruction-count below. */ if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; + if (unlikely (num_points < (unsigned) num_contours)) return false; unsigned old_length = points.length; points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh index 3fe2506bec9..9f5f267f96a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh @@ -121,7 +121,7 @@ struct glyf if (!use_short_loca) { - padded_offsets.resize (0); + padded_offsets.clear (); for (auto &g : glyphs) padded_offsets.push (g.length ()); } @@ -226,7 +226,7 @@ struct glyf_accelerator_t if (gid >= num_glyphs) return false; auto &all_points = scratch.all_points; - all_points.resize (0); + all_points.clear (); bool phantom_only = !consumer.is_consuming_contour_points (); if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache))) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh b/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh index b440379afbe..50ec34d542a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh @@ -312,7 +312,7 @@ struct name { static constexpr hb_tag_t tableTag = HB_OT_TAG_name; - unsigned int get_size () const + size_t get_size () const { return min_size + count * nameRecordZ.item_size; } template { bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::ClassDefFormat1_3::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -48,7 +48,7 @@ struct ClassDefFormat2 : public OT::ClassDefFormat2_4 { bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::ClassDefFormat2_4::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -114,7 +114,7 @@ struct ClassDef : public OT::ClassDef bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::ClassDef::min_size) return false; hb_barrier (); switch (u.format.v) diff --git a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh index 46c703524d9..5778ee9e1d3 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh @@ -36,7 +36,7 @@ static bool sanitize ( const OT::Layout::Common::CoverageFormat1_3* thiz, graph_t::vertex_t& vertex ) { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -47,7 +47,7 @@ static bool sanitize ( const OT::Layout::Common::CoverageFormat2_4* thiz, graph_t::vertex_t& vertex ) { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -158,7 +158,7 @@ struct Coverage : public OT::Layout::Common::Coverage bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::Layout::Common::Coverage::min_size) return false; hb_barrier (); switch (u.format.v) diff --git a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh index 78ae1a9dd5b..9ca7434ca19 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh @@ -814,6 +814,11 @@ struct graph_t if (unlikely (!check_success (!connected_roots.in_error ()))) break; unsigned next_space = this->next_space (); + if (next_space >= HB_REPACKER_MAX_SPACES) + { + check_success (false); + break; + } num_roots_for_space_.push (0); for (unsigned root : connected_roots) { @@ -1062,6 +1067,12 @@ struct graph_t */ unsigned duplicate (unsigned node_idx) { + if (vertices_.length >= HB_REPACKER_MAX_VERTICES) + { + check_success (false); + return -1; + } + positions_invalid = true; distance_invalid = true; @@ -1221,6 +1232,12 @@ struct graph_t */ unsigned new_node (char* head, char* tail) { + if (vertices_.length >= HB_REPACKER_MAX_VERTICES) + { + check_success (false); + return -1; + } + positions_invalid = true; distance_invalid = true; @@ -1384,6 +1401,11 @@ struct graph_t void move_to_new_space (const hb_set_t& indices) { + if (num_roots_for_space_.length >= HB_REPACKER_MAX_SPACES) + { + check_success (false); + return; + } num_roots_for_space_.push (0); unsigned new_space = num_roots_for_space_.length - 1; diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh index ea6bcd239a0..73f4b15660f 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh @@ -52,7 +52,7 @@ struct ExtensionFormat1 : public OT::ExtensionFormat1 bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; return vertex_len >= OT::ExtensionFormat1::static_size; } @@ -76,7 +76,7 @@ struct Lookup : public OT::Lookup bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::Lookup::min_size) return false; hb_barrier (); return vertex_len >= this->get_size (); @@ -390,7 +390,7 @@ struct LookupList : public OT::LookupList { bool sanitize (const graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::LookupList::min_size) return false; hb_barrier (); return vertex_len >= OT::LookupList::item_size * this->len; @@ -424,7 +424,7 @@ struct GSTAR : public OT::GSUBGPOS bool sanitize (const graph_t::vertex_t& vertex) { - int64_t len = vertex.obj.tail - vertex.obj.head; + size_t len = vertex.obj.tail - vertex.obj.head; if (len < OT::GSUBGPOS::min_size) return false; hb_barrier (); return len >= get_size (); diff --git a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh index 6d1a3d4ae4b..a653f402ab1 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh @@ -38,7 +38,7 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix { bool sanitize (graph_t::vertex_t& vertex, unsigned class_count) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < AnchorMatrix::min_size) return false; hb_barrier (); @@ -126,7 +126,7 @@ struct MarkArray : public OT::Layout::GPOS_impl::MarkArray { bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; unsigned min_size = MarkArray::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -207,7 +207,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= MarkBasePosFormat1::static_size; } @@ -430,7 +430,6 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2baseCoverage), prime_id, base_coverage_id); - graph.duplicate (prime_id, base_coverage_id); auto mark_coverage = sc.c.graph.as_table (this_index, &markCoverage); @@ -493,7 +492,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < u.format.v.get_size ()) return false; hb_barrier (); diff --git a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh index 85950b63457..7c3b048195d 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh @@ -39,7 +39,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -422,7 +422,6 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4objidx = class_def_2_id; class_def_link->position = 10; graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id, false); - graph.duplicate (pair_pos_prime_id, class_def_2_id); return pair_pos_prime_id; } @@ -624,7 +623,7 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < u.format.v.get_size ()) return false; hb_barrier (); diff --git a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh index 37fac8909e5..4f89f1011d8 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh @@ -108,7 +108,7 @@ inline bool will_overflow (graph_t& graph, hb_vector_t* overflows = nullptr) { - if (overflows) overflows->resize (0); + if (overflows) overflows->clear (); graph.update_positions (); hb_hashmap_t record_set; 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 2a6b813972f..1186cad41f8 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 @@ -861,7 +861,7 @@ struct KerxSubTable { friend struct kerx; - unsigned int get_size () const { return u.header.length; } + size_t get_size () const { return u.header.length; } unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; } template 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 2cbb86c7566..fef21450b27 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 @@ -987,9 +987,16 @@ struct hb_aat_layout_chain_accelerator_t { unsigned count = chain.get_subtable_count (); - unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) - - HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) + - count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t); + unsigned product; + if (unlikely (hb_unsigned_mul_overflows (count, + sizeof (hb_accelerate_subtables_context_t::hb_applicable_t), &product))) + return nullptr; + + unsigned size; + if (unlikely (hb_unsigned_add_overflows (sizeof (hb_aat_layout_chain_accelerator_t) - + HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t), product, &size))) { + return nullptr; + } /* The following is a calloc because when we are collecting subtables, * some of them might be invalid and hence not collect; as a result, @@ -1026,7 +1033,7 @@ struct ChainSubtable template friend struct Chain; - unsigned int get_size () const { return length; } + size_t get_size () const { return length; } unsigned int get_type () const { return coverage & 0xFF; } unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); } @@ -1236,7 +1243,7 @@ struct Chain c->reverse_buffer (); } - unsigned int get_size () const { return length; } + size_t get_size () const { return length; } template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const diff --git a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh index 651ffcda01d..05053b1f858 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh @@ -89,7 +89,16 @@ static inline constexpr uint32_t hb_uint32_swap (uint32_t v) { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } template -struct __attribute__((packed)) hb_packed_t { Type v; }; +struct __attribute__((packed)) hb_packed_t +{ + hb_packed_t () = default; + constexpr hb_packed_t (Type V) : v (V) {} + operator Type () const { return v; } + hb_packed_t & operator = (Type V) { v = V; return *this; } + + private: + Type v; +}; #ifndef HB_FAST_NUM_ACCESS @@ -134,9 +143,9 @@ struct HBInt #if HB_FAST_NUM_ACCESS { if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - ((hb_packed_t *) v)->v = V; + *((hb_packed_t *) v) = V; else - ((hb_packed_t *) v)->v = __builtin_bswap16 (V); + *((hb_packed_t *) v) = __builtin_bswap16 (V); } #else : v {BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V ) & 0xFF), @@ -147,9 +156,9 @@ struct HBInt { #if HB_FAST_NUM_ACCESS return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? - ((const hb_packed_t *) v)->v + (uint16_t) *((const hb_packed_t *) v) : - __builtin_bswap16 (((const hb_packed_t *) v)->v) + __builtin_bswap16 ((uint16_t) *((const hb_packed_t *) v)) ; #else return (BE ? (v[0] << 8) : (v[0] )) @@ -186,9 +195,9 @@ struct HBInt #if HB_FAST_NUM_ACCESS { if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - ((hb_packed_t *) v)->v = V; + *((hb_packed_t *) v) = V; else - ((hb_packed_t *) v)->v = __builtin_bswap32 (V); + *((hb_packed_t *) v) = __builtin_bswap32 (V); } #else : v {BE ? uint8_t ((V >> 24) & 0xFF) : uint8_t ((V ) & 0xFF), @@ -200,9 +209,9 @@ struct HBInt constexpr operator Type () const { #if HB_FAST_NUM_ACCESS return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? - ((const hb_packed_t *) v)->v + (uint32_t) *((const hb_packed_t *) v) : - __builtin_bswap32 (((const hb_packed_t *) v)->v) + __builtin_bswap32 ((uint32_t) *((const hb_packed_t *) v)) ; #else return (BE ? (v[0] << 24) : (v[0] )) @@ -226,9 +235,9 @@ struct HBInt #if HB_FAST_NUM_ACCESS { if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - ((hb_packed_t *) v)->v = V; + *((hb_packed_t *) v) = V; else - ((hb_packed_t *) v)->v = __builtin_bswap64 (V); + *((hb_packed_t *) v) = __builtin_bswap64 (V); } #else : v {BE ? uint8_t ((V >> 56) & 0xFF) : uint8_t ((V ) & 0xFF), @@ -244,9 +253,9 @@ struct HBInt constexpr operator Type () const { #if HB_FAST_NUM_ACCESS return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? - ((const hb_packed_t *) v)->v + (uint64_t) *((const hb_packed_t *) v) : - __builtin_bswap64 (((const hb_packed_t *) v)->v) + __builtin_bswap64 ((uint64_t) *((const hb_packed_t *) v)) ; #else return (BE ? (uint64_t (v[0]) << 56) : (uint64_t (v[0]) )) @@ -276,12 +285,12 @@ struct HBFloat { #if HB_FAST_NUM_ACCESS { - if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - { - ((hb_packed_t *) v)->v = V; - return; - } - } + if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) + { + *((hb_packed_t *) v) = V; + return; + } + } #endif union { @@ -289,7 +298,7 @@ struct HBFloat hb_packed_t i; } u = {{V}}; - const HBInt I = u.i.v; + const HBInt I = (IntType) u.i; for (unsigned i = 0; i < Bytes; i++) v[i] = I.v[i]; } @@ -297,10 +306,10 @@ struct HBFloat /* c++14 constexpr */ operator Type () const { #if HB_FAST_NUM_ACCESS - { - if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - return ((const hb_packed_t *) v)->v; - } + { + if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) + return (Type) *((const hb_packed_t *) v); + } #endif HBInt I; @@ -312,7 +321,7 @@ struct HBFloat hb_packed_t f; } u = {{I}}; - return u.f.v; + return (Type) u.f; } private: uint8_t v[Bytes]; }; @@ -1191,6 +1200,21 @@ hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *resu return (size > 0) && (count >= ((unsigned int) -1) / size); } +static inline bool +hb_unsigned_add_overflows (unsigned int a, unsigned int b, unsigned *result = nullptr) +{ +#if hb_has_builtin(__builtin_add_overflow) + unsigned stack_result; + if (!result) + result = &stack_result; + return __builtin_add_overflow (a, b, result); +#endif + + if (result) + *result = a + b; + return b > (unsigned int) -1 - a; +} + /* * Sort and search. @@ -1315,15 +1339,12 @@ static inline void sort_r_swap(char *__restrict a, char *__restrict b, /* 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 +template 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) + Compar compar) { - if(compar(a, b, ds...) > 0) { + if(compar(a, b) > 0) { sort_r_swap(a, b, w); return 1; } @@ -1348,23 +1369,17 @@ static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb) /* Implement recursive quicksort ourselves */ /* Note: quicksort is not stable, equivalent values may be swapped */ -template +template 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) + Compar compar) { char *b = (char *)base, *end = b + nel*w; - /* for(size_t i=0; i b && sort_r_cmpswap(pj-w,pj,w,compar,ds...); pj -= w) {} + for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar); pj -= w) {} } } else @@ -1375,68 +1390,36 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w, 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) { + if(compar(l[0],l[1]) > 0) { SORT_R_SWAP(l[0], l[1], tmp); } + if(compar(l[1],l[2]) > 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); } + if(compar(l[0],l[1]) > 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...); + cmp = compar(pl, pivot); 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...); + pr -= w; + cmp = compar(pr, pivot); if(cmp == 0) { pre -= w; if(pr < pre) { sort_r_swap(pr, pre, w); } @@ -1449,22 +1432,13 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w, } } - pl = pr; /* pr may have gone below pl */ + pl = pr; - /* - 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 static inline void @@ -1664,6 +1624,13 @@ double solve_itp (func_t f, double min_y, double max_y, double &ya, double &yb, double &y) { + // Guard against degenerate interval + if (b - a <= 0.0) + { + y = ya; + return a; + } + unsigned n1_2 = (unsigned) (hb_max (ceil (log2 ((b - a) / epsilon)) - 1.0, 0.0)); const unsigned n0 = 1; // Hardwired const double k1 = 0.2 / (b - a); // Hardwired. @@ -1674,7 +1641,8 @@ double solve_itp (func_t f, { double x1_2 = 0.5 * (a + b); double r = scaled_epsilon - 0.5 * (b - a); - double xf = (yb * a - ya * b) / (yb - ya); + // Guard against yb == ya to prevent division by zero + double xf = (yb != ya) ? (yb * a - ya * b) / (yb - ya) : x1_2; double sigma = x1_2 - xf; double b_a = b - a; // This has k2 = 2 hardwired for efficiency. @@ -1705,4 +1673,51 @@ double solve_itp (func_t f, } +/* + * Scope guard: runs a callable at scope exit (RAII cleanup for + * non-HB-type resources — raw malloc'd buffers, paired init/end + * calls like inflateInit/inflateEnd, FT_Done_* handles, etc.). + * + * Prefer hb_unique_ptr_t etc. for HB types; this is + * for the long tail of cleanup that those wrappers don't cover. + * + * Usage: + * void *buf = hb_malloc (len); + * if (!buf) return false; + * HB_SCOPE_GUARD (hb_free (buf)); + * ... multiple fallible operations ... + * return true; // buf freed automatically on any return path + */ +template +struct hb_scope_guard_t +{ + explicit hb_scope_guard_t (F &&f) : f (std::move (f)), active (true) {} + hb_scope_guard_t (hb_scope_guard_t &&o) noexcept + : f (std::move (o.f)), active (o.active) { o.active = false; } + hb_scope_guard_t (const hb_scope_guard_t &) = delete; + hb_scope_guard_t &operator= (const hb_scope_guard_t &) = delete; + hb_scope_guard_t &operator= (hb_scope_guard_t &&) = delete; + ~hb_scope_guard_t () { if (active) f (); } + + /* Release: dismiss the guard so the cleanup does NOT run. Use + * when transferring ownership out of the scope. */ + void release () { active = false; } + + private: + F f; + bool active; +}; + +template +static inline hb_scope_guard_t hb_make_scope_guard (F &&f) +{ return hb_scope_guard_t (std::forward (f)); } + +#define HB_SCOPE_GUARD_NAME_(line) hb_scope_guard_##line +#define HB_SCOPE_GUARD_NAME(line) HB_SCOPE_GUARD_NAME_(line) +#define HB_SCOPE_GUARD(stmt) \ + auto HB_SCOPE_GUARD_NAME(__LINE__) = \ + hb_make_scope_guard ([&]() { stmt; }); \ + (void) HB_SCOPE_GUARD_NAME(__LINE__) + + #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 71d3bcdf1ea..dd3369307ef 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-array.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-array.hh @@ -32,6 +32,8 @@ #include "hb-iter.hh" #include "hb-null.hh" +#include + template struct hb_sorted_array_t; @@ -219,26 +221,54 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> return false; } - hb_sorted_array_t qsort (int (*cmp_)(const void*, const void*)) + hb_sorted_array_t qsort (int (*cmp)(const void*, const void*)) { - //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); if (likely (length)) - hb_qsort (arrayZ, length, this->get_item_size (), cmp_); + hb_qsort (arrayZ, length, this->get_item_size (), cmp); return hb_sorted_array_t (*this); } + /* std::sort wants a strict-weak `a < b` boolean, but our other + * qsort overload (and most existing call sites) follow the C + * qsort convention of returning negative / zero / positive ints. + * Adapt to either via overload resolution: bool passes through; + * any other arithmetic return type is treated as the int signed + * comparator. */ + template static bool _qsort_lt (T v) { return v < 0; } + static bool _qsort_lt (bool v) { return v; } + + template + hb_sorted_array_t qsort (Compar compar) + { + if (likely (length)) + std::sort (arrayZ, arrayZ + length, + [&] (const Type &a, const Type &b) + { return _qsort_lt (compar (a, b)); }); + return hb_sorted_array_t (*this); + } + + private: + template ::value)> + hb_sorted_array_t _qsort (hb_priority<1>) + { + return qsort ([] (const Type &a, const Type &b) { return Type::cmp (&a, &b) < 0; }); + } + hb_sorted_array_t _qsort (hb_priority<0>) + { + return qsort ((int(*)(const void*, const void*)) Type::cmp); + } + public: + hb_sorted_array_t qsort () { - //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); - if (likely (length)) - hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp); - return hb_sorted_array_t (*this); + return _qsort (hb_prioritize); } /* * Other methods. */ - unsigned int get_size () const { return length * this->get_item_size (); } + size_t get_size () const { return length * this->get_item_size (); } /* * Reverse the order of items in this array in the range [start, end). diff --git a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh index 05aaf5a155e..f95a3079475 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh @@ -193,6 +193,9 @@ struct hb_atomic_t T *get_acquire () const { return v.load (std::memory_order_acquire); } bool cmpexch (T *old, T *new_) { return v.compare_exchange_weak (old, new_, std::memory_order_acq_rel, std::memory_order_relaxed); } + hb_atomic_t &operator= (const hb_atomic_t& o) { set_relaxed (o.get_relaxed ()); return *this; } + hb_atomic_t &operator= (hb_atomic_t&& o){ set_relaxed (o.get_relaxed ()); o.set_relaxed ({}); return *this; } + operator bool () const { return get_acquire () != nullptr; } T *operator->() const { return get_acquire (); } template diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh index f9c0e8870ff..35aa9aa4e79 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh @@ -115,7 +115,7 @@ struct hb_inc_bimap_t void clear () { forw_map.clear (); - back_map.resize (0); + back_map.clear (); } /* Add a mapping from lhs to rhs with a unique value if lhs is unknown. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh index 4028dd63531..2c97f416fe6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh @@ -173,7 +173,14 @@ struct hb_bit_set_invertible_t bool is_subset (const hb_bit_set_invertible_t &larger_set) const { if (unlikely (inverted != larger_set.inverted)) - return hb_all (hb_iter (s) | hb_map (larger_set.s)); + { + if (inverted) + return hb_all (iter (), larger_set.s); + else + // larger set is inverted so larger_set.s is the set of things that are not present + // in larger_set, therefore if s has any of those it can't be a subset. + return !s.intersects (larger_set.s); + } else return unlikely (inverted) ? larger_set.s.is_subset (s) : s.is_subset (larger_set.s); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh index f86d5750854..9e29d2af323 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh @@ -117,9 +117,15 @@ struct hb_bit_set_t void clear () { - resize (0); - if (likely (successful)) - population = 0; + /* Early-out on already-empty. Protects the Null singleton + * (which is zero-initialized) from any writes. Any non-empty + * instance is a real heap object with writable storage, so + * clearing through the vector's always-safe clear() is fine + * even if we entered error state. */ + if (!pages.length && !population) return; + pages.clear (); + page_map.clear (); + population = 0; } bool is_empty () const { @@ -438,23 +444,31 @@ struct hb_bit_set_t return false; uint32_t spi = 0; - for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++) + uint32_t lpi = 0; + while (spi < page_map.length && lpi < larger_set.page_map.length) { uint32_t spm = page_map.arrayZ[spi].major; uint32_t lpm = larger_set.page_map.arrayZ[lpi].major; auto sp = page_at (spi); - if (spm < lpm && !sp.is_empty ()) - return false; - - if (lpm < spm) + if (spm < lpm) { + if (!sp.is_empty ()) + return false; + spi++; continue; + } + + if (lpm < spm) { + lpi++; + continue; + } auto lp = larger_set.page_at (lpi); if (!sp.is_subset (lp)) return false; spi++; + lpi++; } while (spi < page_map.length) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc index a19599fac09..e60259f52da 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc @@ -615,6 +615,160 @@ hb_blob_create_from_file (const char *file_name) return likely (blob) ? blob : hb_blob_get_empty (); } +#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) +static hb_blob_t * +_hb_blob_try_mmap (const char *file_name) +{ + hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); + if (unlikely (!file)) return nullptr; + auto file_guard = hb_make_scope_guard ([&]() { hb_free (file); }); + + int fd = open (file_name, O_RDONLY | O_BINARY, 0); + if (unlikely (fd == -1)) return nullptr; + auto fd_guard = hb_make_scope_guard ([&]() { close (fd); }); + + struct stat st; + if (unlikely (fstat (fd, &st) == -1)) return nullptr; + + 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); + if (unlikely (file->contents == MAP_FAILED)) return nullptr; + + file_guard.release (); + /* fd_guard closes fd on return (ownership ends after mmap). */ + return hb_blob_create_or_fail (file->contents, file->length, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, + (hb_destroy_func_t) _hb_mapped_file_destroy); +} +#elif defined(_WIN32) && !defined(HB_NO_MMAP) +static hb_blob_t * +_hb_blob_try_mmap (const char *file_name) +{ + hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); + if (unlikely (!file)) return nullptr; + auto file_guard = hb_make_scope_guard ([&]() { hb_free (file); }); + + unsigned int size = strlen (file_name) + 1; + wchar_t *wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); + if (unlikely (!wchar_file_name)) return nullptr; + + /* Assume file name is given in UTF-8 encoding */ + int conversion = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size); + if (conversion <= 0) + { + /* Conversion failed due to invalid UTF-8 characters, + Repeat conversion based on system code page */ + mbstowcs (wchar_file_name, file_name, size); + } + + HANDLE fd; +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + { + CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; + ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); + ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF; + ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000; + ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000; + ceparams.lpSecurityAttributes = nullptr; + ceparams.hTemplateFile = nullptr; + fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, + OPEN_EXISTING, &ceparams); + } +#else + fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, + nullptr); +#endif + hb_free (wchar_file_name); + + if (unlikely (fd == INVALID_HANDLE_VALUE)) return nullptr; + auto fd_guard = hb_make_scope_guard ([&]() { CloseHandle (fd); }); + +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + { + LARGE_INTEGER length; + GetFileSizeEx (fd, &length); + file->length = length.LowPart; + file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr); + } +#else + file->length = (unsigned long) GetFileSize (fd, nullptr); + file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); +#endif + if (unlikely (!file->mapping)) return nullptr; + +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + 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)) return nullptr; + + file_guard.release (); + /* fd_guard closes fd on return. */ + return hb_blob_create_or_fail (file->contents, file->length, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, + (hb_destroy_func_t) _hb_mapped_file_destroy); +} +#endif + +/* Read a file without knowing its size beforehand. Used as a fallback + * for systems without mmap or to read from pipes. */ +static hb_blob_t * +_hb_blob_read_file (const char *file_name) +{ + unsigned long len = 0, allocated = BUFSIZ * 16; + char *data = (char *) hb_malloc (allocated); + if (unlikely (!data)) return nullptr; + auto data_guard = hb_make_scope_guard ([&]() { hb_free (data); }); + + FILE *fp = fopen (file_name, "rb"); + if (unlikely (!fp)) return nullptr; + HB_SCOPE_GUARD (fclose (fp)); + + while (!feof (fp)) + { + if (allocated - len < BUFSIZ) + { + allocated *= 2; + /* Don't allocate and go more than ~536MB, our mmap reader still + can cover files like that but lets limit our fallback reader */ + if (unlikely (allocated > (2 << 28))) return nullptr; + char *new_data = (char *) hb_realloc (data, allocated); + if (unlikely (!new_data)) return nullptr; + data = new_data; + } + + unsigned long addition = fread (data + len, 1, allocated - len, fp); + + int err = ferror (fp); +#ifdef EINTR // armcc doesn't have it + if (unlikely (err == EINTR)) continue; +#endif + if (unlikely (err)) return nullptr; + + len += addition; + } + + data_guard.release (); + return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data, + (hb_destroy_func_t) hb_free); +} + /** * hb_blob_create_from_file_or_fail: * @file_name: A filename @@ -636,158 +790,10 @@ hb_blob_create_from_file_or_fail (const char *file_name) { /* Adopted from glib's gmappedfile.c with Matthias Clasen and Allison Lortie permission but changed a lot to suit our need. */ -#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) - hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); - if (unlikely (!file)) return nullptr; - - int fd = open (file_name, O_RDONLY | O_BINARY, 0); - if (unlikely (fd == -1)) goto fail_without_close; - - struct stat st; - 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; - } - } +#if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP) + if (hb_blob_t *blob = _hb_blob_try_mmap (file_name)) + return blob; #endif - - file->contents = (char *) mmap (nullptr, file->length, PROT_READ, - MAP_PRIVATE | MAP_NORESERVE, fd, 0); - - if (unlikely (file->contents == MAP_FAILED)) goto fail; - - close (fd); - - return hb_blob_create_or_fail (file->contents, file->length, - HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, - (hb_destroy_func_t) _hb_mapped_file_destroy); - -fail: - close (fd); -fail_without_close: - hb_free (file); - -#elif defined(_WIN32) && !defined(HB_NO_MMAP) - hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); - if (unlikely (!file)) return nullptr; - - HANDLE fd; - int conversion; - unsigned int size = strlen (file_name) + 1; - wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); - if (unlikely (!wchar_file_name)) goto fail_without_close; - - /* Assume file name is given in UTF-8 encoding */ - conversion = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size); - if (conversion <= 0) - { - /* Conversion failed due to invalid UTF-8 characters, - Repeat conversion based on system code page */ - mbstowcs(wchar_file_name, file_name, size); - } -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - { - CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; - ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); - ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF; - ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000; - ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000; - ceparams.lpSecurityAttributes = nullptr; - ceparams.hTemplateFile = nullptr; - fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, - OPEN_EXISTING, &ceparams); - } -#else - fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, - nullptr); -#endif - hb_free (wchar_file_name); - - if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; - -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - { - LARGE_INTEGER length; - GetFileSizeEx (fd, &length); - file->length = length.LowPart; - file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr); - } -#else - file->length = (unsigned long) GetFileSize (fd, nullptr); - file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); -#endif - if (unlikely (!file->mapping)) goto fail; - -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - 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)) goto fail; - - CloseHandle (fd); - return hb_blob_create_or_fail (file->contents, file->length, - HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, - (hb_destroy_func_t) _hb_mapped_file_destroy); - -fail: - CloseHandle (fd); -fail_without_close: - hb_free (file); - -#endif - - /* The following tries to read a file without knowing its size beforehand - 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 *) hb_malloc (allocated); - if (unlikely (!data)) return nullptr; - - FILE *fp = fopen (file_name, "rb"); - if (unlikely (!fp)) goto fread_fail_without_close; - - while (!feof (fp)) - { - if (allocated - len < BUFSIZ) - { - allocated *= 2; - /* Don't allocate and go more than ~536MB, our mmap reader still - can cover files like that but lets limit our fallback reader */ - if (unlikely (allocated > (2 << 28))) goto fread_fail; - char *new_data = (char *) hb_realloc (data, allocated); - if (unlikely (!new_data)) goto fread_fail; - data = new_data; - } - - unsigned long addition = fread (data + len, 1, allocated - len, fp); - - int err = ferror (fp); -#ifdef EINTR // armcc doesn't have it - if (unlikely (err == EINTR)) continue; -#endif - if (unlikely (err)) goto fread_fail; - - len += addition; - } - fclose (fp); - - return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data, - (hb_destroy_func_t) hb_free); - -fread_fail: - fclose (fp); -fread_fail_without_close: - hb_free (data); - return nullptr; + return _hb_blob_read_file (file_name); } #endif /* !HB_NO_OPEN */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.hh b/src/java.desktop/share/native/libharfbuzz/hb-blob.hh index b1b3b94d3dd..1703efa92b1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-blob.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.hh @@ -50,6 +50,21 @@ struct hb_blob_t } } + void replace_buffer (const char *new_data, + unsigned new_length, + hb_memory_mode_t new_mode, + void *new_user_data, + hb_destroy_func_t new_destroy) + { + if (new_data != data) + destroy_user_data (); + data = new_data; + length = new_length; + mode = new_mode; + user_data = new_user_data; + destroy = new_destroy; + } + HB_INTERNAL bool try_make_writable (); HB_INTERNAL bool try_make_writable_inplace (); HB_INTERNAL bool try_make_writable_inplace_unix (); @@ -67,6 +82,149 @@ struct hb_blob_t void *user_data = nullptr; hb_destroy_func_t destroy = nullptr; + + /* + * Blob-recycling helpers. + * + * Encoders that produce a sized byte buffer and wrap it as an + * hb_blob_t can amortize malloc/blob-allocation across repeated + * renders by handing the output blob back via a recycle slot. On + * the next encode these helpers reuse (or realloc) the buffer and + * the same hb_blob_t handle is returned, skipping malloc/free + * and blob-handle churn across glyph-by-glyph encoding loops. + * + * Blobs managed by this machinery are identified by the address + * of recycle_data_destroy. + */ + + struct recycle_data_t + { + char *buf; + unsigned capacity; + }; + + static inline void recycle_data_destroy (void *user_data) + { + auto *bd = (recycle_data_t *) user_data; + hb_free (bd->buf); + hb_free (bd); + } + + /* Acquire a buffer of at least @needed bytes. If @recycled is + * one of our blobs, reuse its buffer (or realloc it). + * *@out_capacity receives the actual capacity (>= @needed). + * *@out_replaced_buf is set to the recycled buf when realloc + * fails and a fresh buffer was allocated instead -- the caller + * must hb_free() that buf after recycle_finalize() runs. Returns + * nullptr on allocation failure. */ + static inline char * + recycle_acquire (hb_blob_t *recycled, + unsigned needed, + unsigned *out_capacity, + char **out_replaced_buf) + { + *out_replaced_buf = nullptr; + + if (recycled && recycled->destroy == recycle_data_destroy) + { + auto *bd = (recycle_data_t *) recycled->user_data; + if (bd->capacity >= needed) + { + *out_capacity = bd->capacity; + return bd->buf; + } + /* Grow with a 1.5x ramp to amortize repeated growth. */ + unsigned alloc_bytes = needed; + if (unlikely (hb_unsigned_add_overflows (needed, needed / 2, + &alloc_bytes))) + alloc_bytes = needed; + char *new_buf = (char *) hb_realloc (bd->buf, alloc_bytes); + if (new_buf) + { + bd->buf = new_buf; + bd->capacity = alloc_bytes; + *out_capacity = alloc_bytes; + return new_buf; + } + /* Realloc failed. Fall through to a fresh hb_malloc and stash + * the old buf for the caller to free after recycle_finalize. */ + *out_replaced_buf = bd->buf; + } + + char *buf = (char *) hb_malloc (needed); + if (unlikely (!buf)) + return nullptr; + *out_capacity = needed; + return buf; + } + + /* Wrap @buf (of @capacity, with @length used) into an hb_blob_t. + * If @recycled is one of our blobs, update and return it (cheap); + * otherwise create a new blob. Pass @replaced_recycled_buf from + * recycle_acquire(). */ + static inline hb_blob_t * + recycle_finalize (char *buf, + unsigned capacity, + unsigned length, + hb_blob_t *recycled, + char *replaced_recycled_buf) + { + if (recycled && recycled->destroy == recycle_data_destroy) + { + auto *bd = (recycle_data_t *) recycled->user_data; + if (replaced_recycled_buf && replaced_recycled_buf != buf) + hb_free (replaced_recycled_buf); + bd->buf = buf; + bd->capacity = capacity; + recycled->data = (const char *) buf; + recycled->length = length; + return recycled; + } + + /* No recycled blob to update -- create a fresh one with our + * destroy closure so the next recycle round can reuse it. */ + recycle_data_t *bd = (recycle_data_t *) hb_malloc (sizeof (*bd)); + if (unlikely (!bd)) + { + hb_free (buf); + return nullptr; + } + bd->buf = buf; + bd->capacity = capacity; + + return hb_blob_create ((const char *) buf, length, + HB_MEMORY_MODE_WRITABLE, + bd, recycle_data_destroy); + } + + /* Discard @buf returned by recycle_acquire without committing to + * a blob. Frees @buf if it was a fresh allocation; leaves any + * recycled buffer untouched. */ + static inline void + recycle_abort (char *buf, hb_blob_t *recycled) + { + if (!buf) return; + if (recycled && recycled->destroy == recycle_data_destroy) + { + auto *bd = (recycle_data_t *) recycled->user_data; + if (buf == bd->buf) return; /* owned by the recycled blob */ + } + hb_free (buf); + } + + /* Stash @blob in @slot as the recycled output for the next + * encode. Destroys any previously stashed blob. Safe to call + * with @blob = nullptr or the empty-singleton blob (treated as + * "drop"). */ + static inline void + recycle_stash (hb_blob_t **slot, hb_blob_t *blob) + { + hb_blob_destroy (*slot); + *slot = nullptr; + if (!blob || blob == hb_blob_get_empty ()) + return; + *slot = blob; + } }; 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 6787da6f65f..b3190ffc8ef 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc @@ -114,6 +114,17 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, *buf_consumed = 0; hb_position_t x = 0, y = 0; + + /* Calculate the advance of the previous glyphs */ + if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) + { + for (unsigned int i = 0; i < start; i++) + { + x += pos[i].x_advance; + y += pos[i].y_advance; + } + } + for (unsigned int i = start; i < end; i++) { char b[1024]; @@ -151,7 +162,7 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster)); } - if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) + if (pos && !(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) { 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)); @@ -272,6 +283,17 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, *buf_consumed = 0; hb_position_t x = 0, y = 0; + + /* Calculate the advance of the previous glyphs */ + if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) + { + for (unsigned int i = 0; i < start; i++) + { + x += pos[i].x_advance; + y += pos[i].y_advance; + } + } + for (unsigned int i = start; i < end; i++) { char b[1024]; @@ -297,7 +319,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster)); } - if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) + if (pos && !(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) { if (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)); @@ -417,9 +439,9 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, * A human-readable, plain text format. * The serialized glyphs will look something like: * - * ``` + * |[ * [uni0651=0@518,0+0|uni0628=0+1897] - * ``` + * ]| * * - The serialized glyphs are delimited with `[` and `]`. * - Glyphs are separated with `|` @@ -435,10 +457,10 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, * A machine-readable, structured format. * The serialized glyphs will look something like: * - * ``` + * |[ * [{"g":"uni0651","cl":0,"dx":518,"dy":0,"ax":0,"ay":0}, - * {"g":"uni0628","cl":0,"dx":0,"dy":0,"ax":1897,"ay":0}] - * ``` + * {"g":"uni0628","cl":0,"dx":0,"dy":0,"ax":1897,"ay":0}] + * ]| * * Each glyph is a JSON object, with the following properties: * - `g`: the glyph name or glyph index if @@ -530,9 +552,9 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, * A human-readable, plain text format. * The serialized codepoints will look something like: * - * ``` + * |[ *   - * ``` + * ]| * * - Glyphs are separated with `|` * - Unicode codepoints are expressed as zero-padded four (or more) @@ -550,9 +572,9 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, * * For example: * - * ``` + * |[ * [{u:1617,cl:0},{u:1576,cl:1}] - * ``` + * ]| * * Return value: * The number of serialized items. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc index 0c9190bf6f8..647c270c02a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc @@ -101,9 +101,9 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, /* Check that breaking up shaping at safe-to-break is indeed safe. */ - hb_buffer_t *fragment = hb_buffer_create_similar (buffer); + hb_unique_ptr_t fragment (hb_buffer_create_similar (buffer)); hb_buffer_set_flags (fragment, (hb_buffer_flags_t (hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY))); - hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); + hb_unique_ptr_t reconstruction (hb_buffer_create_similar (buffer)); hb_buffer_set_flags (reconstruction, (hb_buffer_flags_t (hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY))); unsigned int num_glyphs; @@ -164,11 +164,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, hb_buffer_append (fragment, text_buffer, text_start, text_end); if (!hb_shape_full (font, fragment, features, num_features, shapers) || fragment->successful) - { - hb_buffer_destroy (reconstruction); - hb_buffer_destroy (fragment); return true; - } hb_buffer_append (reconstruction, fragment, 0, -1); start = end; @@ -193,9 +189,6 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, } } - hb_buffer_destroy (reconstruction); - hb_buffer_destroy (fragment); - return ret; } @@ -238,11 +231,13 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, * the one from original buffer in step 1. */ - hb_buffer_t *fragments[2] {hb_buffer_create_similar (buffer), - hb_buffer_create_similar (buffer)}; + hb_unique_ptr_t fragments[2] { + hb_unique_ptr_t (hb_buffer_create_similar (buffer)), + hb_unique_ptr_t (hb_buffer_create_similar (buffer)), + }; hb_buffer_set_flags (fragments[0], (hb_buffer_flags_t (hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY))); hb_buffer_set_flags (fragments[1], (hb_buffer_flags_t (hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY))); - hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); + hb_unique_ptr_t reconstruction (hb_buffer_create_similar (buffer)); hb_buffer_set_flags (reconstruction, (hb_buffer_flags_t (hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY))); hb_segment_properties_t props; hb_buffer_get_segment_properties (buffer, &props); @@ -308,17 +303,16 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, } bool ret = true; - hb_buffer_diff_flags_t diff; /* * Shape the two fragment streams. */ if (!hb_shape_full (font, fragments[0], features, num_features, shapers) || !fragments[0]->successful) - goto out; + return ret; if (!hb_shape_full (font, fragments[1], features, num_features, shapers) || !fragments[1]->successful) - goto out; + return ret; if (!forward) { @@ -363,7 +357,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, /* * Diff results. */ - diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) { buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); @@ -375,11 +369,6 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, } } -out: - hb_buffer_destroy (reconstruction); - hb_buffer_destroy (fragments[0]); - hb_buffer_destroy (fragments[1]); - return ret; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc index 8f6da312cdd..f4eb6040de7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc @@ -547,12 +547,6 @@ void hb_buffer_t::merge_clusters_impl (unsigned int start, unsigned int end) { - if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level)) - { - unsafe_to_break (start, end); - return; - } - max_ops -= end - start; if (unlikely (max_ops < 0)) successful = false; @@ -581,15 +575,9 @@ hb_buffer_t::merge_clusters_impl (unsigned int start, set_cluster (info[i], cluster); } void -hb_buffer_t::merge_out_clusters (unsigned int start, - unsigned int end) +hb_buffer_t::merge_out_clusters_impl (unsigned int start, + unsigned int end) { - if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level)) - return; - - if (unlikely (end - start < 2)) - return; - max_ops -= end - start; if (unlikely (max_ops < 0)) successful = false; @@ -972,6 +960,9 @@ void hb_buffer_set_content_type (hb_buffer_t *buffer, hb_buffer_content_type_t content_type) { + if (unlikely (hb_object_is_immutable (buffer))) + return; + buffer->content_type = content_type; } @@ -1822,6 +1813,9 @@ hb_buffer_add_utf (hb_buffer_t *buffer, if (item_length == -1) item_length = text_length - item_offset; + item_offset = hb_min (item_offset, (unsigned) text_length); + item_length = hb_clamp (item_length, 0, text_length - (int) item_offset); + if (unlikely (item_length < 0 || item_length > INT_MAX / 8 || !buffer->ensure (buffer->len + item_length * sizeof (T) / 4))) @@ -2290,6 +2284,22 @@ hb_buffer_diff (hb_buffer_t *buffer, * Debugging. */ +void +hb_buffer_t::changed () +{ +#ifdef HB_NO_BUFFER_MESSAGE + return; +#else + if (!message_depth) + return; + + if (changed_func) + changed_func (this, changed_data); + else + update_digest (); +#endif +} + #ifndef HB_NO_BUFFER_MESSAGE /** * hb_buffer_set_message_func: @@ -2307,7 +2317,8 @@ hb_buffer_set_message_func (hb_buffer_t *buffer, hb_buffer_message_func_t func, void *user_data, hb_destroy_func_t destroy) { - if (unlikely (hb_object_is_immutable (buffer))) + if (unlikely (hb_object_is_immutable (buffer)) || + unlikely (buffer->message_depth)) { if (destroy) destroy (user_data); @@ -2327,6 +2338,23 @@ hb_buffer_set_message_func (hb_buffer_t *buffer, buffer->message_destroy = nullptr; } } +/** + * hb_buffer_changed: + * @buffer: An #hb_buffer_t + * + * Called by a message callback after modifying buffer glyph indices, + * to update internal caches. + * + * If not called from inside a message callback, does nothing. + * + * Since: 13.0.0 + **/ +void +hb_buffer_changed (hb_buffer_t *buffer) +{ + buffer->changed (); +} + bool hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap) { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h index 332001ef171..a06b823ccee 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h @@ -495,7 +495,7 @@ typedef enum { (1u << HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES)))) /** - * HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS + * HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS: * @level: #hb_buffer_cluster_level_t to test * * Tests whether a cluster level does not group cluster values by graphemes. @@ -505,7 +505,7 @@ typedef enum { */ #define HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS(level) \ ((bool) ((1u << (unsigned) (level)) & \ - ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARCATERS) | \ + ((1u << HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) | \ (1u << HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)))) HB_EXTERN void @@ -672,7 +672,12 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer); * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents. * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS: serialize glyph flags. Since: 1.5.0 * @HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES: do not serialize glyph advances, - * glyph offsets will reflect absolute glyph positions. Since: 1.8.0 + * glyph offsets will reflect absolute glyph positions. Since: 1.8.0. + * Note: when this flag is used with a partial range of the buffer (i.e. + * @start is not 0), calculating the absolute positions has a cost + * proportional to @start. If the buffer is serialized in many small + * chunks, this can lead to quadratic behavior. It is recommended to + * use a larger @buf_size to minimize this cost. * @HB_BUFFER_SERIALIZE_FLAG_DEFINED: All currently defined flags. Since: 4.4.0 * * Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs(). @@ -865,6 +870,9 @@ hb_buffer_set_message_func (hb_buffer_t *buffer, hb_buffer_message_func_t func, void *user_data, hb_destroy_func_t destroy); +HB_EXTERN void +hb_buffer_changed (hb_buffer_t *buffer); + HB_END_DECLS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh index 1c46981cc9c..32eca7021f8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh @@ -130,9 +130,13 @@ struct hb_buffer_t */ #ifndef HB_NO_BUFFER_MESSAGE + typedef void (*changed_func_t) (hb_buffer_t *buffer, void *user_data); + hb_buffer_message_func_t message_func; void *message_data; hb_destroy_func_t message_destroy; + changed_func_t changed_func; + void *changed_data; unsigned message_depth; /* How deeply are we inside a message callback? */ #else static constexpr unsigned message_depth = 0u; @@ -398,10 +402,42 @@ struct hb_buffer_t { if (end - start < 2) return; + if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level)) + { + unsafe_to_break (start, end); + return; + } + merge_clusters_impl (start, end); + } + void merge_grapheme_clusters (unsigned int start, unsigned int end) + { + if (end - start < 2) + return; + if (!HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (cluster_level)) + { + unsafe_to_break (start, end); + return; + } merge_clusters_impl (start, end); } HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end); - HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end); + void merge_out_clusters (unsigned int start, unsigned int end) + { + if (end - start < 2) + return; + if (!HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE (cluster_level)) + return; + merge_out_clusters_impl (start, end); + } + void merge_out_grapheme_clusters (unsigned int start, unsigned int end) + { + if (end - start < 2) + return; + if (!HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (cluster_level)) + return; + merge_out_clusters_impl (start, end); + } + HB_INTERNAL void merge_out_clusters_impl (unsigned int start, unsigned int end); /* Merge clusters for deleting current glyph, and skip it. */ HB_INTERNAL void delete_glyph (); HB_INTERNAL void delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info)); @@ -605,6 +641,7 @@ struct hb_buffer_t #endif } HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0); + HB_INTERNAL void changed (); static void set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0) 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 79d7c4c7133..a053940d057 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 @@ -344,25 +344,25 @@ struct cff_stack_t { ELEM& operator [] (unsigned int i) { - if (unlikely (i >= count)) + if (unlikely (i >= length)) { set_error (); return Crap (ELEM); } - return elements[i]; + return arrayZ[i]; } void push (const ELEM &v) { - if (likely (count < LIMIT)) - elements[count++] = v; + if (likely (length < LIMIT)) + arrayZ[length++] = v; else set_error (); } ELEM &push () { - if (likely (count < LIMIT)) - return elements[count++]; + if (likely (length < LIMIT)) + return arrayZ[length++]; else { set_error (); @@ -372,8 +372,8 @@ struct cff_stack_t ELEM& pop () { - if (likely (count > 0)) - return elements[--count]; + if (likely (length > 0)) + return arrayZ[--length]; else { set_error (); @@ -382,45 +382,44 @@ struct cff_stack_t } void pop (unsigned int n) { - if (likely (count >= n)) - count -= n; + if (likely (length >= n)) + length -= n; else set_error (); } const ELEM& peek () { - if (unlikely (count == 0)) + if (unlikely (length == 0)) { set_error (); return Null (ELEM); } - return elements[count - 1]; + return arrayZ[length - 1]; } void unpop () { - if (likely (count < LIMIT)) - count++; + if (likely (length < LIMIT)) + length++; else set_error (); } - void clear () { count = 0; } + void clear () { length = 0; } bool in_error () const { return (error); } void set_error () { error = true; } - unsigned int get_count () const { return count; } - bool is_empty () const { return !count; } + unsigned int get_count () const { return length; } + bool is_empty () const { return !length; } hb_array_t sub_array (unsigned start, unsigned length) const - { return hb_array_t (elements).sub_array (start, length); } + { return hb_array_t (arrayZ).sub_array (start, length); } - private: bool error = false; - unsigned int count = 0; - ELEM elements[LIMIT]; + unsigned int length = 0; + ELEM arrayZ[LIMIT]; }; /* argument stack */ 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 ed4586dc437..a4aa005d82c 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 @@ -55,7 +55,7 @@ struct blend_arg_t : number_t void reset_blends () { numValues = valueIndex = 0; - deltas.shrink (0); + deltas.clear (); } unsigned int numValues; @@ -281,17 +281,18 @@ struct cff2_cs_opset_t : cs_opset_t, PAR k = env.get_region_count (); n = env.argStack.pop_uint (); /* copy the blend values into blend array of the default values */ - unsigned int start = env.argStack.get_count () - ((k+1) * n); - /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */ - if (unlikely (start > env.argStack.get_count ())) + unsigned int count = env.argStack.get_count (); + unsigned int total; + if (unlikely (hb_unsigned_mul_overflows (k + 1, n, &total) || total > count)) { env.set_error (); return; } + unsigned int start = count - total; for (unsigned int i = 0; i < n; i++) { const hb_array_t blends = env.argStack.sub_array (start + n + (i * k), k); - process_arg_blend (env, env.argStack[start + i], blends, n, i); + process_arg_blend (env, env.argStack.arrayZ[start + i], blends, n, i); } /* pop off blend values leaving default values now adorned with blend values */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-config.hh b/src/java.desktop/share/native/libharfbuzz/hb-config.hh index c522eeea2ea..62e0d2022e3 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-config.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-config.hh @@ -43,6 +43,7 @@ #ifdef HB_TINY #define HB_LEAN #define HB_MINI +#define HB_NO_SVG #define HB_OPTIMIZE_SIZE #define HB_OPTIMIZE_SIZE_MORE #define HB_MINIMIZE_MEMORY_USAGE @@ -60,9 +61,6 @@ #define HB_NO_BUFFER_SERIALIZE #define HB_NO_BUFFER_VERIFY #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 @@ -78,13 +76,17 @@ #define HB_NO_NAME #define HB_NO_OPEN #define HB_NO_OT_FONT_GLYPH_NAMES -#define HB_NO_OT_SHAPE_FRACTIONS -#define HB_NO_PAINT #define HB_NO_SETLOCALE #define HB_NO_STYLE -#define HB_NO_SUBSET_LAYOUT #define HB_NO_VERTICAL #define HB_NO_VAR + +#if !(defined(HB_HAS_CAIRO) || defined(HB_HAS_RASTER) || defined(HB_HAS_VECTOR) || defined(HB_HAS_GPU)) +#define HB_NO_COLOR +#define HB_NO_DRAW +#define HB_NO_PAINT +#endif + #endif #ifdef HB_MINI @@ -92,8 +94,6 @@ #define HB_NO_LEGACY #define HB_NO_BEYOND_64K #define HB_NO_CUBIC_GLYF -#define HB_NO_VAR_COMPOSITES -#define HB_NO_VAR_HVF #endif #ifdef __OPTIMIZE_SIZE__ @@ -135,16 +135,17 @@ #define HB_NO_OT_FONT_BITMAP #endif +#ifdef HB_NO_DRAW +#define HB_NO_CFF +#define HB_NO_OUTLINE +#define HB_NO_PAINT +#endif + #ifdef HB_NO_CFF #define HB_NO_OT_FONT_CFF #define HB_NO_SUBSET_CFF #endif -#ifdef HB_NO_DRAW -#define HB_NO_OUTLINE -#define HB_NO_PAINT -#endif - #ifdef HB_NO_LEGACY #define HB_NO_CMAP_LEGACY_SUBTABLES #define HB_NO_FALLBACK_SHAPE diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cplusplus.hh b/src/java.desktop/share/native/libharfbuzz/hb-cplusplus.hh index 82d39741527..d08e21c58e5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cplusplus.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cplusplus.hh @@ -138,52 +138,64 @@ struct vtable_t static constexpr auto get_user_data = _get_user_data; }; -#define HB_DEFINE_VTABLE(name) \ +#define HB_DEFINE_VTABLE(name, empty) \ template<> \ struct vtable \ : vtable_t {} -HB_DEFINE_VTABLE (buffer); -HB_DEFINE_VTABLE (blob); -HB_DEFINE_VTABLE (face); -HB_DEFINE_VTABLE (font); -HB_DEFINE_VTABLE (font_funcs); -HB_DEFINE_VTABLE (map); -HB_DEFINE_VTABLE (set); -HB_DEFINE_VTABLE (shape_plan); -HB_DEFINE_VTABLE (unicode_funcs); -HB_DEFINE_VTABLE (draw_funcs); -HB_DEFINE_VTABLE (paint_funcs); - -#undef HB_DEFINE_VTABLE +HB_DEFINE_VTABLE (buffer, &hb_buffer_get_empty); +HB_DEFINE_VTABLE (blob, &hb_blob_get_empty); +HB_DEFINE_VTABLE (face, &hb_face_get_empty); +HB_DEFINE_VTABLE (font, &hb_font_get_empty); +HB_DEFINE_VTABLE (font_funcs, &hb_font_funcs_get_empty); +HB_DEFINE_VTABLE (map, &hb_map_get_empty); +HB_DEFINE_VTABLE (set, &hb_set_get_empty); +HB_DEFINE_VTABLE (shape_plan, &hb_shape_plan_get_empty); +HB_DEFINE_VTABLE (unicode_funcs, &hb_unicode_funcs_get_empty); +HB_DEFINE_VTABLE (draw_funcs, &hb_draw_funcs_get_empty); +HB_DEFINE_VTABLE (paint_funcs, &hb_paint_funcs_get_empty); #ifdef HB_SUBSET_H -#define HB_DEFINE_VTABLE(name) \ - template<> \ - struct vtable \ - : vtable_t {} - - -HB_DEFINE_VTABLE (subset_input); -HB_DEFINE_VTABLE (subset_plan); - -#undef HB_DEFINE_VTABLE +HB_DEFINE_VTABLE (subset_input, nullptr); +HB_DEFINE_VTABLE (subset_plan, nullptr); #endif +#ifdef HB_RASTER_H + +HB_DEFINE_VTABLE (raster_image, nullptr); +HB_DEFINE_VTABLE (raster_draw, nullptr); +HB_DEFINE_VTABLE (raster_paint, nullptr); + +#endif + + +#ifdef HB_VECTOR_H + +HB_DEFINE_VTABLE (vector_draw, nullptr); +HB_DEFINE_VTABLE (vector_paint, nullptr); + +#endif + + +#ifdef HB_GPU_H + +HB_DEFINE_VTABLE (gpu_draw, nullptr); + +#endif + +/* HB_DEFINE_VTABLE stays available for subsystem headers' paired tail + * blocks (see hb-raster.h, hb-vector.h, hb-gpu.h, hb-subset.h). */ + + } // namespace hb /* Workaround for GCC < 7, see: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc index c243d12f7ae..a9d00f695ce 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc @@ -32,6 +32,8 @@ #include "hb-machinery.hh" +#include + /** * SECTION:hb-draw @@ -116,25 +118,25 @@ _hb_draw_funcs_set_middle (hb_draw_funcs_t *dfuncs, void *user_data, hb_destroy_func_t destroy) { + auto destroy_guard = hb_make_scope_guard ([&]() { + if (destroy) destroy (user_data); + }); + if (user_data && !dfuncs->user_data) { dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); if (unlikely (!dfuncs->user_data)) - goto fail; + return false; } if (destroy && !dfuncs->destroy) { dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); if (unlikely (!dfuncs->destroy)) - goto fail; + return false; } + destroy_guard.release (); return true; - -fail: - if (destroy) - (destroy) (user_data); - return false; } #define HB_DRAW_FUNC_IMPLEMENT(name) \ @@ -460,6 +462,268 @@ hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data, } +/** + * hb_draw_line: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @x0: start X coordinate + * @y0: start Y coordinate + * @w0: stroke width at the start + * @x1: end X coordinate + * @y1: end Y coordinate + * @w1: stroke width at the end + * @cap: end-cap shape (butt or square) + * + * Emits a tapered line segment as a filled trapezoid. @w0 and + * @w1 are the full stroke widths at the start and end points + * respectively; they may differ for a tapered stroke or match + * for a uniform one. Pass `NaN` for @w1 to use @w0 (uniform + * stroke) without repeating the value. + * + * With #HB_DRAW_LINE_CAP_SQUARE each endpoint is extended along + * the line direction by half its local stroke width, so four + * `hb_draw_line()` calls form a closed rectangle without gaps + * at the corners. + * + * Since: 14.2.0 + **/ +void +hb_draw_line (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x0, float y0, float w0, + float x1, float y1, float w1, + hb_draw_line_cap_t cap) +{ + if (std::isnan (w1)) w1 = w0; + float dx = x1 - x0, dy = y1 - y0; + float len = sqrtf (dx * dx + dy * dy); + if (len <= 0.f) + return; + /* Unit tangent and normal to the line direction. */ + float tx = dx / len; + float ty = dy / len; + float nx = -ty; + float ny = tx; + float h0 = 0.5f * w0; + float h1 = 0.5f * w1; + /* Square caps: extend each endpoint outward along the line + * tangent by half its local stroke width. */ + if (cap == HB_DRAW_LINE_CAP_SQUARE) + { + x0 -= tx * h0; y0 -= ty * h0; + x1 += tx * h1; y1 += ty * h1; + } + /* Trapezoid corners (counter-clockwise). */ + float ax = x0 + nx * h0, ay = y0 + ny * h0; + float bx = x1 + nx * h1, by = y1 + ny * h1; + float cx = x1 - nx * h1, cy = y1 - ny * h1; + float dx_ = x0 - nx * h0, dy_ = y0 - ny * h0; + + hb_draw_move_to (dfuncs, draw_data, st, ax, ay); + hb_draw_line_to (dfuncs, draw_data, st, bx, by); + hb_draw_line_to (dfuncs, draw_data, st, cx, cy); + hb_draw_line_to (dfuncs, draw_data, st, dx_, dy_); + hb_draw_close_path (dfuncs, draw_data, st); +} + +/* Emit an axis-aligned rectangle as a single closed contour. + * @ccw picks the winding direction (useful for cutting a hole + * out of another rectangle in a stroked rect). */ +static void +_hb_draw_rect_contour (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x, float y, float w, float h, + bool ccw) +{ + hb_draw_move_to (dfuncs, draw_data, st, x, y); + if (ccw) + { + hb_draw_line_to (dfuncs, draw_data, st, x + w, y); + hb_draw_line_to (dfuncs, draw_data, st, x + w, y + h); + hb_draw_line_to (dfuncs, draw_data, st, x, y + h); + } + else + { + hb_draw_line_to (dfuncs, draw_data, st, x, y + h); + hb_draw_line_to (dfuncs, draw_data, st, x + w, y + h); + hb_draw_line_to (dfuncs, draw_data, st, x + w, y); + } + hb_draw_close_path (dfuncs, draw_data, st); +} + +/** + * hb_draw_rectangle: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @x: top-left X coordinate + * @y: top-left Y coordinate + * @w: width (may be negative) + * @h: height (may be negative) + * @stroke_width: stroke width, or `NaN` for a filled rectangle + * + * Emits an axis-aligned rectangle. If @stroke_width is a finite + * positive value, the rectangle is rendered as an outlined ring + * of that thickness centered on the edges; if @stroke_width is + * `NaN`, the rectangle is rendered filled. + * + * Note: stroked rectangles produce a bounding box covering the + * full outer rectangle, so if the pen is a GPU fragment-shader + * backend, the shader runs for every interior pixel even though + * only the outline contributes coverage. For very thin + * outlines where the interior is much larger than the stroke, + * emitting four hb_draw_line() segments (one per edge) is + * considerably cheaper per frame. + * + * Since: 14.2.0 + **/ +void +hb_draw_rectangle (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x, float y, + float w, float h, + float stroke_width) +{ + if (std::isnan (stroke_width)) + { + /* Filled rectangle with zero area is nothing to draw. */ + if (w == 0.f || h == 0.f) + return; + _hb_draw_rect_contour (dfuncs, draw_data, st, x, y, w, h, /*ccw*/ true); + return; + } + + if (stroke_width <= 0.f || !std::isfinite (stroke_width)) + return; + + /* Normalize to non-negative width/height so the stroke math + * below (outer grows by sw, inner shrinks by sw) produces the + * expected outer-contains-inner ring regardless of w/h signs. */ + if (w < 0.f) { x += w; w = -w; } + if (h < 0.f) { y += h; h = -h; } + /* w or h == 0 is still meaningful when stroking: a stroked + * zero-height rect is a horizontal line of length w; zero + * width is a vertical line. Both degenerate to a single + * outer contour because the inner hole collapses. */ + + /* Stroke is centered on the edge: outer contour grows by + * stroke_width/2, inner contour shrinks by the same. */ + float s = 0.5f * stroke_width; + /* Outer rectangle (CCW = adds coverage). */ + _hb_draw_rect_contour (dfuncs, draw_data, st, + x - s, y - s, + w + stroke_width, h + stroke_width, + /*ccw*/ true); + /* Inner rectangle (CW = removes coverage for the hole). */ + float iw = w - stroke_width; + float ih = h - stroke_width; + if (iw > 0.f && ih > 0.f) + _hb_draw_rect_contour (dfuncs, draw_data, st, + x + s, y + s, iw, ih, + /*ccw*/ false); +} + +/* Circle approximated by 4 cubic Beziers, one per quadrant. + * The magic constant 0.5522847498307936 is + * (4/3) * (sqrt(2) - 1) + * and minimizes the max radial error to ~2.7e-4 of r. */ +static void +_hb_draw_circle_contour (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float cx, float cy, float r, + bool ccw) +{ + static const float k = 0.5522847498307936f; + float ck = r * k; + + hb_draw_move_to (dfuncs, draw_data, st, cx + r, cy); + if (ccw) + { + hb_draw_cubic_to (dfuncs, draw_data, st, + cx + r, cy + ck, + cx + ck, cy + r, + cx, cy + r); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx - ck, cy + r, + cx - r, cy + ck, + cx - r, cy); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx - r, cy - ck, + cx - ck, cy - r, + cx, cy - r); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx + ck, cy - r, + cx + r, cy - ck, + cx + r, cy); + } + else + { + hb_draw_cubic_to (dfuncs, draw_data, st, + cx + r, cy - ck, + cx + ck, cy - r, + cx, cy - r); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx - ck, cy - r, + cx - r, cy - ck, + cx - r, cy); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx - r, cy + ck, + cx - ck, cy + r, + cx, cy + r); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx + ck, cy + r, + cx + r, cy + ck, + cx + r, cy); + } + hb_draw_close_path (dfuncs, draw_data, st); +} + +/** + * hb_draw_circle: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @cx: center X coordinate + * @cy: center Y coordinate + * @r: radius + * @stroke_width: stroke width, or `NaN` for a filled disc + * + * Emits a circle approximated by four cubic Bezier curves. If + * @stroke_width is a finite positive value, the circle is + * rendered as an outlined ring of that thickness centered on + * the nominal radius; if @stroke_width is `NaN`, the circle is + * rendered as a filled disc. + * + * Since: 14.2.0 + **/ +void +hb_draw_circle (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float cx, float cy, + float r, + float stroke_width) +{ + if (r <= 0.f) + return; + + if (std::isnan (stroke_width)) + { + _hb_draw_circle_contour (dfuncs, draw_data, st, cx, cy, r, /*ccw*/ true); + return; + } + + if (stroke_width <= 0.f || !std::isfinite (stroke_width)) + return; + + float s = 0.5f * stroke_width; + _hb_draw_circle_contour (dfuncs, draw_data, st, cx, cy, r + s, /*ccw*/ true); + float ir = r - s; + if (ir > 0.f) + _hb_draw_circle_contour (dfuncs, draw_data, st, cx, cy, ir, /*ccw*/ false); +} + + static void hb_draw_extents_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, void *data, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.h b/src/java.desktop/share/native/libharfbuzz/hb-draw.h index 06299e17a78..7c3358beed8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-draw.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.h @@ -335,6 +335,58 @@ hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st); +/* Shape helpers. + * + * Emit common primitives (tapered line, rectangle, circle) into + * any pen. The helpers are thin wrappers over the individual + * move_to / line_to / cubic_to / close_path calls: callers can + * always hand-roll the same shapes if they need a variation. + * + * For rect / circle the @stroke_width parameter selects between + * filled and stroked: a positive finite value is the stroke + * width of the outline; NaN means "filled" (no stroke). + */ + +/** + * hb_draw_line_cap_t: + * @HB_DRAW_LINE_CAP_BUTT: No cap; the line ends exactly at + * its endpoint. + * @HB_DRAW_LINE_CAP_SQUARE: Square cap; the line is extended + * past its endpoint by half the local stroke width. Useful + * for composing closed shapes from line segments (e.g. a + * rectangle made from four lines). + * + * End-cap shape for hb_draw_line(). + * + * Since: 14.2.0 + **/ +typedef enum { + HB_DRAW_LINE_CAP_BUTT = 0, + HB_DRAW_LINE_CAP_SQUARE = 1, +} hb_draw_line_cap_t; + +HB_EXTERN void +hb_draw_line (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x0, float y0, float w0, + float x1, float y1, float w1, + hb_draw_line_cap_t cap); + +HB_EXTERN void +hb_draw_rectangle (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x, float y, + float w, float h, + float stroke_width); + +HB_EXTERN void +hb_draw_circle (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float cx, float cy, + float r, + float stroke_width); + + HB_END_DECLS #endif /* HB_DRAW_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc index c1feaac6280..d660063716f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc @@ -180,10 +180,8 @@ _hb_face_builder_get_table_tags (const hb_face_t *face HB_UNUSED, { // Not much to do... } - sorted_tags.qsort ([] (const void* a, const void* b) { - return * (hb_tag_t *) a < * (hb_tag_t *) b ? -1 : - * (hb_tag_t *) a == * (hb_tag_t *) b ? 0 : - +1; + sorted_tags.qsort ([] (const hb_tag_t &a, const hb_tag_t &b) { + return a < b; }); auto array = sorted_tags.as_array ().sub_array (start_offset, table_count); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-font.cc index 6c636e23567..c8ddbd00765 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.cc @@ -406,14 +406,15 @@ hb_font_get_glyph_h_origins_default (hb_font_t *font HB_UNUSED, { if (font->has_glyph_h_origin_func_set ()) { + hb_bool_t ret = true; for (unsigned int i = 0; i < count; i++) { - font->get_glyph_h_origin (*first_glyph, first_x, first_y, false); + ret &= font->get_glyph_h_origin (*first_glyph, first_x, first_y, false); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_x = &StructAtOffsetUnaligned (first_x, x_stride); first_y = &StructAtOffsetUnaligned (first_y, y_stride); } - return true; + return ret; } hb_bool_t ret = font->parent->get_glyph_h_origins (count, @@ -448,14 +449,15 @@ hb_font_get_glyph_v_origins_default (hb_font_t *font HB_UNUSED, { if (font->has_glyph_v_origin_func_set ()) { + hb_bool_t ret = true; for (unsigned int i = 0; i < count; i++) { - font->get_glyph_v_origin (*first_glyph, first_x, first_y, false); + ret &= font->get_glyph_v_origin (*first_glyph, first_x, first_y, false); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_x = &StructAtOffsetUnaligned (first_x, x_stride); first_y = &StructAtOffsetUnaligned (first_y, y_stride); } - return true; + return ret; } hb_bool_t ret = font->parent->get_glyph_v_origins (count, @@ -1001,25 +1003,25 @@ _hb_font_funcs_set_middle (hb_font_funcs_t *ffuncs, void *user_data, hb_destroy_func_t destroy) { + auto destroy_guard = hb_make_scope_guard ([&]() { + if (destroy) destroy (user_data); + }); + if (user_data && !ffuncs->user_data) { ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); if (unlikely (!ffuncs->user_data)) - goto fail; + return false; } if (destroy && !ffuncs->destroy) { ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); if (unlikely (!ffuncs->destroy)) - goto fail; + return false; } + destroy_guard.release (); return true; - -fail: - if (destroy) - (destroy) (user_data); - return false; } #define HB_FONT_FUNC_IMPLEMENT(get_,name) \ @@ -1625,11 +1627,12 @@ hb_font_draw_glyph_or_fail (hb_font_t *font, * * Paints a color glyph. * - * This function is similar to, but lower-level than, - * hb_font_paint_glyph(). It is suitable for clients that - * need more control. If there are no color glyphs available, - * it will return `false`. The client can then fall back to - * hb_font_draw_glyph_or_fail() for the monochrome outline glyph. + * Succeeds if @glyph has color paint layers (COLRv0), + * a color paint graph (COLRv1), or a bitmap image that the + * font's callbacks render successfully. Returns `false` if + * the font has no color data for @glyph; the client can then + * fall back to hb_font_draw_glyph_or_fail() for the monochrome + * outline. * * The painting instructions are returned by way of calls to * the callbacks of the @funcs object, with @paint_data passed @@ -2414,6 +2417,10 @@ hb_font_set_parent (hb_font_t *font, if (!parent) parent = hb_font_get_empty (); + for (hb_font_t *p = parent; p && p != hb_font_get_empty(); p = p->parent) + if (p == font) + return; /* Would create a cycle - reject */ + hb_font_t *old = font->parent; font->parent = hb_font_reference (parent); @@ -3183,7 +3190,7 @@ hb_font_set_var_coords_design (hb_font_t *font, for (unsigned int i = input_coords_length; i < coords_length; i++) design_coords[i] = axes[i].get_default (); - hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized); + hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.hh b/src/java.desktop/share/native/libharfbuzz/hb-font.hh index 9dd54466d7f..a89b5db8cbc 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.hh @@ -172,13 +172,13 @@ struct hb_font_t /* Convert from parent-font user-space to our user-space */ hb_position_t parent_scale_x_distance (hb_position_t v) { - if (unlikely (parent && parent->x_scale != x_scale)) + if (unlikely (parent && parent->x_scale && parent->x_scale != x_scale)) return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale); return v; } hb_position_t parent_scale_y_distance (hb_position_t v) { - if (unlikely (parent && parent->y_scale != y_scale)) + if (unlikely (parent && parent->y_scale && parent->y_scale != y_scale)) return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale); return v; } @@ -903,15 +903,11 @@ struct hb_font_t } else { - for (unsigned j = 0; j < n; j++) - { - origins[j].x = 0; - origins[j].y = 0; - } + mult = 0; /* Indicates all origins[].x and origins[].y values are 0, therefore we can skip adjusting offsets below */ } } - assert (mult == -1 || mult == +1); + assert (mult == -1 || mult == +1 || mult == 0); if (mult == +1) for (unsigned j = 0; j < n; j++) { @@ -919,13 +915,14 @@ struct hb_font_t add_offset (&pos->x_offset, &pos->y_offset, origins[j].x, origins[j].y); } - else /* mult == -1 */ + else if (mult == -1) for (unsigned j = 0; j < n; j++) { hb_glyph_position_t *pos = &buf->pos[offset + j]; subtract_offset (&pos->x_offset, &pos->y_offset, origins[j].x, origins[j].y); } + /* else if (mult == 0) --> Do nothing */ offset += n; } @@ -970,15 +967,11 @@ struct hb_font_t } else { - for (unsigned j = 0; j < n; j++) - { - origins[j].x = 0; - origins[j].y = 0; - } + mult = 0; /* Indicates all origins[].x and origins[].y values are 0, therefore we can skip adjusting offsets below */ } } - assert (mult == -1 || mult == +1); + assert (mult == -1 || mult == +1 || mult == 0); if (mult == +1) for (unsigned j = 0; j < n; j++) { @@ -986,13 +979,14 @@ struct hb_font_t add_offset (&pos->x_offset, &pos->y_offset, origins[j].x, origins[j].y); } - else /* mult == -1 */ + else if (mult == -1) for (unsigned j = 0; j < n; j++) { hb_glyph_position_t *pos = &buf->pos[offset + j]; subtract_offset (&pos->x_offset, &pos->y_offset, origins[j].x, origins[j].y); } + /* else if (mult == 0) --> Do nothing */ offset += n; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc index b90f966c57c..f02069f0c0c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc @@ -766,6 +766,12 @@ hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + if (!size) + { + char buf[128]; + return !FT_Get_Glyph_Name (ft_face, glyph, buf, sizeof (buf)) && *buf; + } + hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); if (ret && (size && !*name)) ret = false; @@ -1117,14 +1123,13 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data buffer = (FT_Byte *) hb_malloc (length); if (!buffer) return nullptr; + auto buffer_guard = hb_make_scope_guard ([&]() { hb_free (buffer); }); error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); if (error) - { - hb_free (buffer); return nullptr; - } + buffer_guard.release (); return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, hb_free); @@ -1693,6 +1698,13 @@ _release_blob (void *arg) void hb_ft_font_set_funcs (hb_font_t *font) { + int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + if (font->destroy == (hb_destroy_func_t) _hb_ft_font_destroy && font->user_data) + { + const hb_ft_font_t *existing_ft_font = (const hb_ft_font_t *) font->user_data; + load_flags = existing_ft_font->load_flags; + } + // In case of failure... hb_font_set_funcs (font, hb_font_funcs_get_empty (), @@ -1740,7 +1752,7 @@ hb_ft_font_set_funcs (hb_font_t *font) } _hb_ft_font_set_funcs (font, ft_face, true); - hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); + hb_ft_font_set_load_flags (font, load_flags); _hb_ft_hb_font_changed (font, ft_face); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh b/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh index 0de062df68e..548561b0e2c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-geometry.hh @@ -28,16 +28,25 @@ #include "hb-algs.hh" +#include + template struct hb_extents_t { hb_extents_t () {} - hb_extents_t (const hb_glyph_extents_t &extents) : - xmin (hb_min (extents.x_bearing, extents.x_bearing + extents.width)), - ymin (hb_min (extents.y_bearing, extents.y_bearing + extents.height)), - xmax (hb_max (extents.x_bearing, extents.x_bearing + extents.width)), - ymax (hb_max (extents.y_bearing, extents.y_bearing + extents.height)) {} + hb_extents_t (const hb_glyph_extents_t &extents) + { + double x0 = (double) extents.x_bearing; + double y0 = (double) extents.y_bearing; + double x1 = x0 + (double) extents.width; + double y1 = y0 + (double) extents.height; + + xmin = (Float) hb_min (x0, x1); + ymin = (Float) hb_min (y0, y1); + xmax = (Float) hb_max (x0, x1); + ymax = (Float) hb_max (y0, y1); + } hb_extents_t (Float xmin, Float ymin, Float xmax, Float ymax) : xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {} @@ -90,20 +99,37 @@ struct hb_extents_t hb_glyph_extents_t to_glyph_extents (bool xneg = false, bool yneg = false) const { - hb_position_t x0 = (hb_position_t) roundf (xmin); - hb_position_t y0 = (hb_position_t) roundf (ymin); - hb_position_t x1 = (hb_position_t) roundf (xmax); - hb_position_t y1 = (hb_position_t) roundf (ymax); - return hb_glyph_extents_t {xneg ? x1 : x0, - yneg ? y0 : y1, - xneg ? x0 - x1 : x1 - x0, - yneg ? y1 - y0 : y0 - y1}; + double x0 = round ((double) xmin); + double y0 = round ((double) ymin); + double x1 = round ((double) xmax); + double y1 = round ((double) ymax); + + if (unlikely (!std::isfinite (x0) || + !std::isfinite (y0) || + !std::isfinite (x1) || + !std::isfinite (y1))) + return hb_glyph_extents_t {0, 0, 0, 0}; + + return hb_glyph_extents_t { + clamp_to_hb_position (xneg ? x1 : x0), + clamp_to_hb_position (yneg ? y0 : y1), + clamp_to_hb_position (xneg ? x0 - x1 : x1 - x0), + clamp_to_hb_position (yneg ? y1 - y0 : y0 - y1) + }; } Float xmin = 0; Float ymin = 0; Float xmax = -1; Float ymax = -1; + + static hb_position_t + clamp_to_hb_position (double v) + { + return (hb_position_t) hb_clamp (v, + (double) hb_int_min (hb_position_t), + (double) hb_int_max (hb_position_t)); + } }; template diff --git a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh index 857e183737f..9d6c7ec6822 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh @@ -108,5 +108,34 @@ #define HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH 64 #endif +#ifndef HB_SVG_MAX_PATH_SEGMENTS +#define HB_SVG_MAX_PATH_SEGMENTS 262144 +#endif + +#ifndef HB_GPU_DRAW_MAX_CURVES +#define HB_GPU_DRAW_MAX_CURVES 65536 +#endif + +#ifndef HB_SVG_MAX_DOCUMENT_SIZE +#define HB_SVG_MAX_DOCUMENT_SIZE ((size_t) 16 << 20) +#endif + +#ifndef HB_RASTER_MAX_BUFFER_SIZE +#define HB_RASTER_MAX_BUFFER_SIZE ((size_t) 1 << 30) +#endif + + +#ifndef HB_REPACKER_MAX_ITERATIONS +#define HB_REPACKER_MAX_ITERATIONS 500 +#endif + +#ifndef HB_REPACKER_MAX_VERTICES +#define HB_REPACKER_MAX_VERTICES 100000 +#endif + +#ifndef HB_REPACKER_MAX_SPACES +#define HB_REPACKER_MAX_SPACES 1024 +#endif + #endif /* HB_LIMITS_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh index 8fa32ea8eaa..8685ac29306 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh @@ -110,7 +110,7 @@ static inline auto StructAfter(TObject &X, Ts... args) HB_AUTO_RETURN(( #define DEFINE_SIZE_STATIC(size) \ DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \ - unsigned int get_size () const { return (size); } \ + size_t get_size () const { return (size); } \ static constexpr unsigned null_size = (size); \ static constexpr unsigned min_size = (size); \ static constexpr unsigned static_size = (size) @@ -137,7 +137,7 @@ static inline auto StructAfter(TObject &X, Ts... args) HB_AUTO_RETURN(( static constexpr unsigned min_size = (size) #define DEFINE_SIZE_ARRAY_SIZED(size, array) \ - unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \ + size_t get_size () const { return (size - (array).min_size + (array).get_size ()); } \ DEFINE_SIZE_ARRAY(size, array) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-map.hh index 4c76622df7a..ae35e715d54 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-map.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-map.hh @@ -379,7 +379,11 @@ struct hb_hashmap_t void clear () { - if (unlikely (!successful)) return; + /* Early-out on already-empty. Protects the Null singleton + * (zero-initialized) from any writes. Any non-empty hashmap + * is a real heap instance with writable items, so clearing + * under !successful is safe. */ + if (!population && !occupancy) return; for (auto &_ : hb_iter (items, size ())) { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number.cc b/src/java.desktop/share/native/libharfbuzz/hb-number.cc index 37bc8b87399..f09366760fa 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-number.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-number.cc @@ -23,6 +23,10 @@ * */ +#ifndef HB_NUMBER_CC +#define HB_NUMBER_CC +#ifdef HB_NUMBER_CC /* Pacify -Wunused-macros. */ + #include "hb.hh" #include "hb-number.hh" #include "hb-number-parser.hh" @@ -77,3 +81,6 @@ hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer *pp = pend; return !whole_buffer || end == pend; } + +#endif /* HB_NUMBER_CC pacify */ +#endif /* HB_NUMBER_CC guard */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-object.hh b/src/java.desktop/share/native/libharfbuzz/hb-object.hh index fa9a249b2e2..76de679c8c7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-object.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-object.hh @@ -272,6 +272,8 @@ static inline void hb_object_make_immutable (const Type *obj) obj->header.writable = false; } template +static inline void hb_object_fini (Type *obj); +template static inline Type *hb_object_reference (Type *obj) { hb_object_trace (obj, HB_FUNC); @@ -282,7 +284,7 @@ static inline Type *hb_object_reference (Type *obj) return obj; } template -static inline bool hb_object_destroy (Type *obj) +static inline bool hb_object_should_destroy (Type *obj) { hb_object_trace (obj, HB_FUNC); if (unlikely (!obj || obj->header.is_inert ())) @@ -290,12 +292,25 @@ static inline bool hb_object_destroy (Type *obj) assert (hb_object_is_valid (obj)); if (obj->header.ref_count.dec () != 1) return false; + return true; +} +template +static inline void hb_object_actually_destroy (Type *obj) +{ hb_object_fini (obj); if (!std::is_trivially_destructible::value) obj->~Type (); +} +template +static inline bool hb_object_destroy (Type *obj) +{ + if (!hb_object_should_destroy (obj)) + return false; + + hb_object_actually_destroy (obj); return true; } template 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 ad831b66d56..29fc201ba04 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh @@ -148,7 +148,7 @@ struct HBUINT15 : HBUINT16 /* 32-bit unsigned integer with variable encoding. */ struct HBUINT32VAR { - unsigned get_size () const + size_t get_size () const { unsigned b0 = v[0]; if (b0 < 0x80) @@ -163,7 +163,7 @@ struct HBUINT32VAR return 5; } - static unsigned get_size (uint32_t v) + static size_t get_size (uint32_t v) { if (v < 0x80) return 1; @@ -563,7 +563,7 @@ struct UnsizedArrayOf return arrayZ[i]; } - static unsigned int get_size (unsigned int len) + static size_t get_size (unsigned int len) { return len * Type::static_size; } template operator T * () { return arrayZ; } @@ -725,7 +725,7 @@ struct ArrayOf return arrayZ[i]; } - unsigned int get_size () const + size_t get_size () const { return len.static_size + len * Type::static_size; } explicit operator bool () const { return len; } @@ -909,7 +909,7 @@ struct HeadlessArrayOf hb_barrier (); return arrayZ[i-1]; } - unsigned int get_size () const + size_t get_size () const { return lenP1.static_size + get_length () * Type::static_size; } unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } @@ -1003,7 +1003,7 @@ struct ArrayOfM1 hb_barrier (); return arrayZ[i]; } - unsigned int get_size () const + size_t get_size () const { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } template @@ -1197,7 +1197,7 @@ struct VarSizedBinSearchArrayOf } unsigned int get_length () const { return header.nUnits - last_is_terminator (); } - unsigned int get_size () const + size_t get_size () const { return header.static_size + header.nUnits * header.unitSize; } template @@ -1275,11 +1275,22 @@ struct CFFIndex if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false); unsigned char *ret = c->allocate_size (data_size, false); if (unlikely (!ret)) return_trace (false); + unsigned remaining = data_size; for (const auto &_ : +it) { unsigned len = _.length; + if (!len) continue; + + if (unlikely (len > remaining)) { + // We have more bytes to write then the computed data size, so the size calculation + // must have encountered overflow. + return_trace (c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + + remaining -= len; + if (len <= 1) { *ret++ = *_.arrayZ; @@ -1450,7 +1461,7 @@ struct CFFIndex return hb_ubytes_t (data_base () + offset0, offset1 - offset0); } - unsigned int get_size () const + size_t get_size () const { if (count) return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); @@ -1948,6 +1959,7 @@ struct TupleValues return true; } + public: void skip (unsigned n) { while (n) @@ -1961,6 +1973,7 @@ struct TupleValues } } + private: template void _add_to (hb_array_t out, float scale = 1.0f) { @@ -2035,14 +2048,6 @@ struct TupleValues public: void add_to (hb_array_t out, float scale = 1.0f) { - unsigned n = out.length; - - if (scale == 0.0f) - { - skip (n); - return; - } - #ifndef HB_OPTIMIZE_SIZE // The following branch is supposed to speed things up by avoiding // the multiplication in _add_to<> if scale is 1.0f. @@ -2077,7 +2082,7 @@ struct TupleList : CFF2Index template struct Align { - unsigned get_size (const void *base) const + size_t get_size (const void *base) const { unsigned offset = (const char *) this - (const char *) base; return (alignment - offset) & (alignment - 1); 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 ec018efe645..8db85e4f08c 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 @@ -201,7 +201,7 @@ struct FDSelect0 { hb_pair_t get_fd_range (hb_codepoint_t glyph) const { return {fds[glyph], glyph + 1}; } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { return HBUINT8::static_size * num_glyphs; } HBUINT8 fds[HB_VAR_ARRAY]; @@ -229,7 +229,7 @@ struct FDSelect3_4_Range template struct FDSelect3_4 { - unsigned int get_size () const + size_t get_size () const { return GID_TYPE::static_size * 2 + ranges.get_size (); } bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const @@ -304,7 +304,7 @@ struct FDSelect return_trace (true); } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { switch (format) { 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 b06936f94c8..d0e078bffdb 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,6 +24,10 @@ * Adobe Author(s): Michiharu Ariza */ +#ifndef HB_OT_CFF1_TABLE_CC +#define HB_OT_CFF1_TABLE_CC +#ifdef HB_OT_CFF1_TABLE_CC /* Pacify -Wunused-macros. */ + #include "hb.hh" #ifndef HB_NO_CFF @@ -609,3 +613,6 @@ bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, #endif + +#endif /* HB_OT_CFF1_TABLE_CC pacify */ +#endif /* HB_OT_CFF1_TABLE_CC guard */ 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 778167eeb23..92163ac8bd3 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 @@ -234,7 +234,7 @@ struct Encoding return_trace (true); } - unsigned int get_size () const + size_t get_size () const { unsigned int size = min_size; switch (table_format ()) @@ -262,7 +262,7 @@ struct Encoding void get_supplement_codes (hb_codepoint_t sid, hb_vector_t &codes) const { - codes.resize (0); + codes.clear (); if (has_supplement ()) suppEncData().get_codes (sid, codes); } @@ -344,7 +344,7 @@ struct Charset0 return 0; } - static unsigned int get_size (unsigned int num_glyphs) + static size_t get_size (unsigned int num_glyphs) { assert (num_glyphs > 0); return UnsizedArrayOf::get_size (num_glyphs - 1); @@ -459,7 +459,7 @@ struct Charset1_2 { return 0; } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { int glyph = (int) num_glyphs; unsigned num_ranges = 0; @@ -475,7 +475,7 @@ struct Charset1_2 { return get_size_for_ranges (num_ranges); } - static unsigned int get_size_for_ranges (unsigned int num_ranges) + static size_t get_size_for_ranges (unsigned int num_ranges) { return UnsizedArrayOf >::get_size (num_ranges); } @@ -563,7 +563,7 @@ struct Charset return_trace (true); } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { switch (format) { 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 499bd942cde..94d768a0308 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,6 +24,10 @@ * Adobe Author(s): Michiharu Ariza */ +#ifndef HB_OT_CFF2_TABLE_CC +#define HB_OT_CFF2_TABLE_CC +#ifdef HB_OT_CFF2_TABLE_CC /* Pacify -Wunused-macros. */ + #include "hb.hh" #ifndef HB_NO_OT_FONT_CFF @@ -228,3 +232,6 @@ bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph } #endif + +#endif /* HB_OT_CFF2_TABLE_CC pacify */ +#endif /* HB_OT_CFF2_TABLE_CC guard */ 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 7e94e38e115..84c593362cf 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 @@ -58,7 +58,7 @@ struct CFF2FDSelect return_trace (true); } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { switch (format) { @@ -130,7 +130,7 @@ struct CFF2ItemVariationStore return_trace (true); } - unsigned int get_size () const { return HBUINT16::static_size + size; } + size_t get_size () const { return HBUINT16::static_size + size; } HBUINT16 size; ItemVariationStore varStore; 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 93e9c0a2697..a3e75abef1d 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 @@ -237,8 +237,6 @@ struct CmapSubtableFormat0 struct CmapSubtableFormat4 { - - template @@ -521,9 +519,10 @@ struct CmapSubtableFormat4 struct accelerator_t { accelerator_t () {} - accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); } + accelerator_t (const CmapSubtableFormat4 *subtable) = delete; - void init (const CmapSubtableFormat4 *subtable) + void init (const CmapSubtableFormat4 *subtable, + unsigned int subtable_data_size) { segCount = subtable->segCountX2 / 2; endCount = subtable->values.arrayZ; @@ -531,7 +530,11 @@ struct CmapSubtableFormat4 idDelta = startCount + segCount; idRangeOffset = idDelta + segCount; glyphIdArray = idRangeOffset + segCount; - glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; + + unsigned int values_offset = 16 + 8 * segCount; + glyphIdArrayLength = subtable_data_size > values_offset + ? (subtable_data_size - values_offset) / 2 + : 0; } bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const @@ -671,23 +674,36 @@ struct CmapSubtableFormat4 unsigned int glyphIdArrayLength; }; - bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph, + unsigned int subtable_data_size) const { - accelerator_t accel (this); + accelerator_t accel; + accel.init (this, subtable_data_size); return accel.get_glyph_func (&accel, codepoint, glyph); } - void collect_unicodes (hb_set_t *out) const + bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + { return false; } + + void collect_unicodes (hb_set_t *out, unsigned int subtable_data_size) const { - accelerator_t accel (this); + accelerator_t accel; + accel.init (this, subtable_data_size); accel.collect_unicodes (out); } + void collect_unicodes (hb_set_t *out) const + { collect_unicodes (out, length); } void collect_mapping (hb_set_t *unicodes, /* OUT */ - hb_map_t *mapping /* OUT */) const + hb_map_t *mapping, /* OUT */ + unsigned int subtable_data_size) const { - accelerator_t accel (this); + accelerator_t accel; + accel.init (this, subtable_data_size); accel.collect_mapping (unicodes, mapping); } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { collect_mapping (unicodes, mapping, length); } bool sanitize (hb_sanitize_context_t *c) const { @@ -696,14 +712,9 @@ struct CmapSubtableFormat4 return_trace (false); hb_barrier (); - if (unlikely (!c->check_range (this, length))) - return_trace (false); - - return_trace (16 + 4 * (unsigned int) segCountX2 <= length); + return_trace (c->check_range (values, 2 + 4 * segCountX2)); } - - protected: HBUINT16 format; /* Format number is set to 4. */ HBUINT16 length; /* This is the length in bytes of the @@ -1485,11 +1496,14 @@ struct CmapSubtable /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ bool get_glyph (hb_codepoint_t codepoint, - hb_codepoint_t *glyph) const + hb_codepoint_t *glyph, + unsigned int subtable_data_size = 0) const { switch (u.format.v) { case 0: hb_barrier (); return u.format0 .get_glyph (codepoint, glyph); - case 4: hb_barrier (); return u.format4 .get_glyph (codepoint, glyph); + case 4: hb_barrier (); return subtable_data_size + ? u.format4.get_glyph (codepoint, glyph, subtable_data_size) + : false; case 6: hb_barrier (); return u.format6 .get_glyph (codepoint, glyph); case 10: hb_barrier (); return u.format10.get_glyph (codepoint, glyph); case 12: hb_barrier (); return u.format12.get_glyph (codepoint, glyph); @@ -1498,11 +1512,17 @@ struct CmapSubtable default: return false; } } - void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const + void collect_unicodes (hb_set_t *out, + unsigned int num_glyphs = UINT_MAX, + unsigned int subtable_data_size = 0) const { switch (u.format.v) { case 0: hb_barrier (); u.format0 .collect_unicodes (out); return; - case 4: hb_barrier (); u.format4 .collect_unicodes (out); return; + case 4: hb_barrier (); if (subtable_data_size) + u.format4.collect_unicodes (out, subtable_data_size); + else + u.format4.collect_unicodes (out); + return; case 6: hb_barrier (); u.format6 .collect_unicodes (out); return; case 10: hb_barrier (); u.format10.collect_unicodes (out); return; case 12: hb_barrier (); u.format12.collect_unicodes (out, num_glyphs); return; @@ -1514,11 +1534,16 @@ struct CmapSubtable void collect_mapping (hb_set_t *unicodes, /* OUT */ hb_map_t *mapping, /* OUT */ - unsigned num_glyphs = UINT_MAX) const + unsigned num_glyphs = UINT_MAX, + unsigned int subtable_data_size = 0) const { switch (u.format.v) { case 0: hb_barrier (); u.format0 .collect_mapping (unicodes, mapping); return; - case 4: hb_barrier (); u.format4 .collect_mapping (unicodes, mapping); return; + case 4: hb_barrier (); if (subtable_data_size) + u.format4.collect_mapping (unicodes, mapping, subtable_data_size); + else + u.format4.collect_mapping (unicodes, mapping); + return; case 6: hb_barrier (); u.format6 .collect_mapping (unicodes, mapping); return; case 10: hb_barrier (); u.format10.collect_mapping (unicodes, mapping); return; case 12: hb_barrier (); u.format12.collect_mapping (unicodes, mapping, num_glyphs); return; @@ -1633,7 +1658,7 @@ struct EncodingRecord CmapSubtable *cmapsubtable = c->push (); unsigned origin_length = c->length (); cmapsubtable->serialize (c, it, format, plan, &(base+subtable)); - if (c->length () - origin_length > 0 && !c->in_error()) *objidx = c->pop_pack (); + if (c->length () > origin_length && !c->in_error()) *objidx = c->pop_pack (); else c->pop_discard (); } @@ -1662,6 +1687,7 @@ struct SubtableUnicodesCache { private: hb_blob_ptr_t base_blob; const char* base; + unsigned int table_length; hb_hashmap_t> cached_unicodes; public: @@ -1686,15 +1712,18 @@ struct SubtableUnicodesCache { hb_free (cache); } - SubtableUnicodesCache(const void* cmap_base) + SubtableUnicodesCache(const void* cmap_base, + unsigned int table_length_ = 0) : base_blob(), base ((const char*) cmap_base), + table_length (table_length_), cached_unicodes () {} SubtableUnicodesCache(hb_blob_ptr_t base_blob_) : base_blob(base_blob_), base ((const char *) base_blob.get()), + table_length (base_blob.get_length ()), cached_unicodes () {} @@ -1725,7 +1754,10 @@ struct SubtableUnicodesCache { if (unlikely (s->in_error ())) return hb_set_get_empty (); - (base+record->subtable).collect_unicodes (s); + unsigned int subtable_data_size = record->subtable < table_length + ? table_length - (unsigned int) record->subtable + : 0; + (base+record->subtable).collect_unicodes (s, UINT_MAX, subtable_data_size); if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr {s}))) return hb_set_get_empty (); @@ -1737,7 +1769,7 @@ struct SubtableUnicodesCache { }; -static inline uint_fast16_t +static inline uint16_t _hb_symbol_pua_map (unsigned codepoint) { if (codepoint <= 0x00FFu) @@ -1784,7 +1816,8 @@ struct cmap EncodingRecIter encodingrec_iter, const void *base, hb_subset_plan_t *plan, - bool drop_format_4 = false) + bool drop_format_4 = false, + unsigned int source_table_length = 0) { if (unlikely (!c->extend_min ((*this)))) return false; this->version = 0; @@ -1792,7 +1825,7 @@ struct cmap unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; auto snap = c->snapshot (); - SubtableUnicodesCache local_unicodes_cache (base); + SubtableUnicodesCache local_unicodes_cache (base, source_table_length); const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache; if (plan->accelerator && @@ -1821,7 +1854,8 @@ struct cmap encodingrec_iter, base, plan, - true); + true, + source_table_length); } } @@ -1838,9 +1872,11 @@ struct cmap } else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); } - c->check_assign(this->encodingRecord.len, - (c->length () - cmap::min_size)/EncodingRecord::static_size, - HB_SERIALIZE_ERROR_INT_OVERFLOW); + unsigned length = c->length (); + unsigned available = length > cmap::min_size ? length - cmap::min_size : 0; + c->check_assign(this->encodingRecord.len, + available / EncodingRecord::static_size, + HB_SERIALIZE_ERROR_INT_OVERFLOW); // Fail if format 4 was dropped and there is no cmap12. return !drop_format_4 || format12objidx; @@ -1955,7 +1991,9 @@ struct cmap it, encodingrec_iter, this, - c->plan)); + c->plan, + false, + c->source_blob->length)); } const CmapSubtable *find_best_subtable (bool *symbol = nullptr, @@ -2034,32 +2072,60 @@ struct cmap this->get_glyph_data = subtable; #ifndef HB_NO_CMAP_LEGACY_SUBTABLES + bool is_format4 = subtable->u.format.v == 4; + auto set_format4_getter = [this] (bool (*func) (const void *, + hb_codepoint_t, + hb_codepoint_t *)) + { + this->format4_accel.init (&this->subtable->u.format4, + get_subtable_data_size (this->subtable)); + this->get_glyph_data = &this->format4_accel; + this->get_glyph_funcZ = func; + }; if (unlikely (symbol)) { switch ((unsigned) face->table.OS2->get_font_page ()) { case OS2::font_page_t::FONT_PAGE_NONE: - this->get_glyph_funcZ = get_glyph_from_symbol; + if (is_format4) + set_format4_getter (get_glyph_from_symbol); + else + this->get_glyph_funcZ = get_glyph_from_symbol; break; #ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC: - this->get_glyph_funcZ = get_glyph_from_symbol; + if (is_format4) + set_format4_getter (get_glyph_from_symbol); + else + this->get_glyph_funcZ = get_glyph_from_symbol; break; case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC: - this->get_glyph_funcZ = get_glyph_from_symbol; + if (is_format4) + set_format4_getter (get_glyph_from_symbol); + else + this->get_glyph_funcZ = get_glyph_from_symbol; break; #endif default: - this->get_glyph_funcZ = get_glyph_from; + if (is_format4) + set_format4_getter (get_glyph_from); + else + this->get_glyph_funcZ = get_glyph_from; break; } } else if (unlikely (macroman)) { - this->get_glyph_funcZ = get_glyph_from_macroman; + if (is_format4) + set_format4_getter (get_glyph_from_macroman); + else + this->get_glyph_funcZ = get_glyph_from_macroman; } else if (unlikely (mac)) { - this->get_glyph_funcZ = get_glyph_from_ascii; + if (is_format4) + set_format4_getter (get_glyph_from_ascii); + else + this->get_glyph_funcZ = get_glyph_from_ascii; } else #endif @@ -2074,7 +2140,8 @@ struct cmap break; case 4: { - this->format4_accel.init (&subtable->u.format4); + this->format4_accel.init (&subtable->u.format4, + get_subtable_data_size (subtable)); this->get_glyph_data = &this->format4_accel; this->get_glyph_funcZ = this->format4_accel.get_glyph_func; break; @@ -2155,10 +2222,10 @@ struct cmap } void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const - { subtable->collect_unicodes (out, num_glyphs); } + { subtable->collect_unicodes (out, num_glyphs, get_subtable_data_size (subtable)); } void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping, unsigned num_glyphs = UINT_MAX) const - { subtable->collect_mapping (unicodes, mapping, num_glyphs); } + { subtable->collect_mapping (unicodes, mapping, num_glyphs, get_subtable_data_size (subtable)); } void collect_variation_selectors (hb_set_t *out) const { subtable_uvs->collect_variation_selectors (out); } void collect_variation_unicodes (hb_codepoint_t variation_selector, @@ -2169,7 +2236,7 @@ struct cmap typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph); - typedef uint_fast16_t (*hb_pua_remap_func_t) (unsigned); + typedef uint16_t (*hb_pua_remap_func_t) (unsigned); template HB_INTERNAL static bool get_glyph_from (const void *obj, @@ -2217,6 +2284,21 @@ struct cmap return c && typed_obj->get_glyph (c, glyph); } + unsigned int get_subtable_data_size (const CmapSubtable *subtable) const + { + unsigned int table_length = this->table.get_length (); + uintptr_t table_start = (uintptr_t) (const void *) this->table.get (); + uintptr_t subtable_addr = (uintptr_t) (const void *) subtable; + if (unlikely (subtable_addr < table_start)) + return 0; + + uintptr_t subtable_offset = subtable_addr - table_start; + if (unlikely (subtable_offset >= table_length)) + return 0; + + return table_length - (unsigned int) subtable_offset; + } + private: hb_nonnull_ptr_t subtable; hb_nonnull_ptr_t subtable_uvs; 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 2d9b8e7cad2..29f038a472d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc @@ -35,7 +35,9 @@ #include "OT/Color/COLR/COLR.hh" #include "OT/Color/CPAL/CPAL.hh" #include "OT/Color/sbix/sbix.hh" +#ifndef HB_NO_SVG #include "OT/Color/svg/svg.hh" +#endif /** @@ -274,6 +276,7 @@ hb_ot_color_glyph_get_layers (hb_face_t *face, * SVG */ +#ifndef HB_NO_SVG /** * hb_ot_color_has_svg: * @face: #hb_face_t to work upon. @@ -290,6 +293,70 @@ hb_ot_color_has_svg (hb_face_t *face) return face->table.SVG->has_data (); } +/** + * hb_ot_color_get_svg_document_count: + * @face: #hb_face_t to work upon. + * + * Gets the number of SVG documents in the face `SVG` table. + * + * Return value: number of SVG documents in the face. + * + * Since: 12.1.0 + */ +unsigned int +hb_ot_color_get_svg_document_count (hb_face_t *face) +{ + return face->table.SVG->get_document_count (); +} + +/** + * hb_ot_color_glyph_get_svg_document_index: + * @face: #hb_face_t to work upon. + * @glyph: glyph ID to query. + * @svg_document_index: (out) (nullable): output SVG document index. + * + * Gets the `SVG`-table document index associated with a glyph. + * + * Return value: `true` if @glyph maps to an SVG document, `false` otherwise. + * + * Since: 12.1.0 + */ +hb_bool_t +hb_ot_color_glyph_get_svg_document_index (hb_face_t *face, + hb_codepoint_t glyph, + unsigned int *svg_document_index) +{ + unsigned doc_index = 0; + hb_bool_t ret = face->table.SVG->get_glyph_document_index (glyph, &doc_index); + if (ret && svg_document_index) + *svg_document_index = doc_index; + return ret; +} + +/** + * hb_ot_color_get_svg_document_glyph_range: + * @face: #hb_face_t to work upon. + * @svg_document_index: SVG document index. + * @start_glyph_id: (out) (nullable): output start glyph ID. + * @end_glyph_id: (out) (nullable): output end glyph ID. + * + * Gets the glyph range covered by an `SVG`-table document index. + * + * Return value: `true` if @svg_document_index is valid, `false` otherwise. + * + * Since: 13.0.0 + */ +hb_bool_t +hb_ot_color_get_svg_document_glyph_range (hb_face_t *face, + unsigned int svg_document_index, + hb_codepoint_t *start_glyph_id, + hb_codepoint_t *end_glyph_id) +{ + return face->table.SVG->get_document_glyph_range (svg_document_index, + start_glyph_id, + end_glyph_id); +} + /** * hb_ot_color_glyph_reference_svg: * @face: #hb_face_t to work upon @@ -308,6 +375,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph) { return face->table.SVG->reference_blob_for_glyph (glyph); } +#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 7fa810bd96f..ed898eb44df 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h @@ -136,6 +136,20 @@ hb_ot_color_glyph_has_paint (hb_face_t *face, HB_EXTERN hb_bool_t hb_ot_color_has_svg (hb_face_t *face); +HB_EXTERN unsigned int +hb_ot_color_get_svg_document_count (hb_face_t *face); + +HB_EXTERN hb_bool_t +hb_ot_color_glyph_get_svg_document_index (hb_face_t *face, + hb_codepoint_t glyph, + unsigned int *svg_document_index /* OUT */); + +HB_EXTERN hb_bool_t +hb_ot_color_get_svg_document_glyph_range (hb_face_t *face, + unsigned int svg_document_index, + hb_codepoint_t *start_glyph_id, /* OUT */ + hb_codepoint_t *end_glyph_id /* OUT */); + HB_EXTERN hb_blob_t * hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph); 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 index afc8aa476e2..9047b2880ab 100644 --- 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 @@ -140,8 +140,10 @@ HB_OT_ACCELERATOR (OT, COLR) HB_OT_CORE_TABLE (OT, CPAL) HB_OT_ACCELERATOR (OT, CBDT) HB_OT_ACCELERATOR (OT, sbix) +#ifndef HB_NO_SVG HB_OT_ACCELERATOR (OT, SVG) #endif +#endif /* OpenType math. */ #ifndef HB_NO_MATH 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 8add9209f37..997fbe5be04 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc @@ -897,31 +897,29 @@ hb_ot_draw_glyph_or_fail (hb_font_t *font, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; hb_draw_session_t draw_session {draw_funcs, draw_data}; - bool ret = false; OT::hb_scalar_cache_t *gvar_cache = nullptr; +#ifndef HB_NO_VAR if (font->num_coords) { ot_font->check_serial (font); gvar_cache = ot_font->draw.acquire_gvar_cache (*ot_font->ot_face->gvar); } +#endif + HB_SCOPE_GUARD (ot_font->draw.release_gvar_cache (gvar_cache)); #ifndef HB_NO_VAR_COMPOSITES - if (font->face->table.VARC->get_path (font, glyph, draw_session)) { ret = true; goto done; } + if (font->face->table.VARC->get_path (font, glyph, draw_session)) return true; #endif // Keep the following in synch with VARC::get_path_at() - if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) { ret = true; goto done; } + if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) return true; #ifndef HB_NO_CFF - if (font->face->table.cff2->get_path (font, glyph, draw_session)) { ret = true; goto done; } - if (font->face->table.cff1->get_path (font, glyph, draw_session)) { ret = true; goto done; } + if (font->face->table.cff2->get_path (font, glyph, draw_session)) return true; + if (font->face->table.cff1->get_path (font, glyph, draw_session)) return true; #endif -done: - - ot_font->draw.release_gvar_cache (gvar_cache); - - return ret; + return false; } #endif @@ -937,7 +935,9 @@ hb_ot_paint_glyph_or_fail (hb_font_t *font, { #ifndef HB_NO_COLOR if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return true; +#ifndef HB_NO_SVG if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; +#endif #ifndef HB_NO_OT_FONT_BITMAP if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; 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 918cf32dcb5..77c2894bbc8 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,7 +41,7 @@ namespace OT { struct DeviceRecord { - static unsigned int get_size (unsigned count) + static size_t get_size (unsigned count) { return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); } template struct KernSubTable { - unsigned int get_size () const { return u.header.length; } + size_t get_size () const { return u.header.length; } unsigned int get_type () const { return u.header.format; } int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const 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 6b62732bf54..cc1bceac4c6 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 @@ -637,7 +637,7 @@ struct FeatureParamsCharacterVariants return characters.len; } - unsigned get_size () const + size_t get_size () const { return min_size + characters.len * HBUINT24::static_size; } void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const @@ -1272,7 +1272,7 @@ struct Lookup TSubTable& get_subtable (unsigned int i) { return this+get_subtables ()[i]; } - unsigned int get_size () const + size_t get_size () const { const HBUINT16 &markFilteringSet = StructAfter (subTable); if (lookupFlag & LookupFlag::UseMarkFilteringSet) @@ -2543,13 +2543,13 @@ struct SparseVarRegionAxis struct hb_scalar_cache_t { private: - static constexpr unsigned STATIC_LENGTH = 16; + static constexpr unsigned STATIC_LENGTH = 128; static constexpr int INVALID = INT_MIN; static constexpr float MULTIPLIER = 1 << ((sizeof (int) * 8) - 2); static constexpr float DIVISOR = 1.f / MULTIPLIER; public: - hb_scalar_cache_t () : length (STATIC_LENGTH) { clear (); } + hb_scalar_cache_t () {} hb_scalar_cache_t (const hb_scalar_cache_t&) = delete; hb_scalar_cache_t (hb_scalar_cache_t&&) = delete; @@ -2561,8 +2561,9 @@ struct hb_scalar_cache_t { if (!count) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t); - if (scratch_cache && count <= scratch_cache->length) + if (scratch_cache && count <= STATIC_LENGTH) { + scratch_cache->length = count; scratch_cache->clear (); return scratch_cache; } @@ -2790,7 +2791,7 @@ struct VarRegionList return !regions.in_error (); } - unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; } + size_t get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; } public: HBUINT16 axisCount; @@ -2870,7 +2871,7 @@ struct VarData unsigned int get_row_size () const { return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); } - unsigned int get_size () const + size_t get_size () const { return min_size - regionIndices.min_size + regionIndices.get_size () + itemCount * get_row_size (); @@ -2970,7 +2971,9 @@ struct VarData } if (unlikely (!c->extend_min (this))) return_trace (false); - itemCount = row_count; + if (unlikely (!c->check_assign (itemCount, row_count, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); int min_threshold = has_long ? -65536 : -128; int max_threshold = has_long ? +65535 : +127; @@ -3240,7 +3243,7 @@ struct VarData struct MultiVarData { - unsigned int get_size () const + size_t get_size () const { return min_size - regionIndices.min_size + regionIndices.get_size () + StructAfter (regionIndices).get_size (); @@ -3256,12 +3259,24 @@ struct MultiVarData auto values_iter = deltaSets.fetcher (inner); unsigned regionCount = regionIndices.len; + unsigned skip = 0; for (unsigned regionIndex = 0; regionIndex < regionCount; regionIndex++) { float scalar = regions.evaluate (regionIndices.arrayZ[regionIndex], coords, coord_count, cache); - values_iter.add_to (out, scalar); + // We skip lazily. Helps with the tail end. + if (scalar == 0.0f) + skip += out.length; + else + { + if (skip) + { + values_iter.skip (skip); + skip = 0; + } + values_iter.add_to (out, scalar); + } } } @@ -3623,7 +3638,7 @@ struct DeltaSetIndexMapFormat01 { friend struct DeltaSetIndexMap; - unsigned get_size () const + size_t get_size () const { return min_size + mapCount * get_width (); } private: @@ -4041,7 +4056,7 @@ struct ConditionValue bool evaluate (const int *coords, unsigned int coord_len, Instancer *instancer) const { - signed value = defaultValue; + float value = defaultValue; value += (*instancer)[varIdx]; return value > 0; } @@ -4789,7 +4804,7 @@ struct HintingDevice public: - unsigned int get_size () const + size_t get_size () const { unsigned int f = deltaFormat; if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * HBUINT16::static_size; 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 05bbf3395bf..a2a45af9e76 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 @@ -743,6 +743,10 @@ struct hb_ot_apply_context_t : hb_vector_t match_positions; uint32_t stack_match_positions[8]; +#ifndef HB_NO_BUFFER_MESSAGE + hb_buffer_t::changed_func_t orig_changed_func = nullptr; + void *orig_changed_data = nullptr; +#endif hb_ot_apply_context_t (unsigned int table_index_, hb_font_t *font_, @@ -773,6 +777,30 @@ struct hb_ot_apply_context_t : { init_iters (); match_positions.set_storage (stack_match_positions); + +#ifndef HB_NO_BUFFER_MESSAGE + if (buffer->messaging ()) + { + assert (buffer->changed_func == nullptr || + buffer->changed_func == buffer_changed_trampoline); + orig_changed_func = buffer->changed_func; + orig_changed_data = buffer->changed_data; + buffer->changed_func = buffer_changed_trampoline; + buffer->changed_data = this; + } +#endif + } + ~hb_ot_apply_context_t () + { +#ifndef HB_NO_BUFFER_MESSAGE + if (buffer->messaging ()) + { + assert (buffer->changed_func == buffer_changed_trampoline); + assert (buffer->changed_data == this); + buffer->changed_func = orig_changed_func; + buffer->changed_data = orig_changed_data; + } +#endif } void init_iters () @@ -801,6 +829,18 @@ struct hb_ot_apply_context_t : return buffer->random_state; } + static void buffer_changed_trampoline (hb_buffer_t *buffer HB_UNUSED, void *user_data) + { + ((hb_ot_apply_context_t *) user_data)->buffer_changed (); + } + void buffer_changed () + { + buffer->update_digest (); + if (likely (has_glyph_classes)) + for (unsigned i = 0; i < buffer->len; i++) + _set_glyph_class_props (buffer->info[i]); + } + HB_ALWAYS_INLINE HB_HOT bool match_properties_mark (const hb_glyph_info_t *info, @@ -870,8 +910,7 @@ struct hb_ot_apply_context_t : props |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; if (likely (has_glyph_classes)) { - props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; - _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef_accel.get_glyph_props (glyph_index)); + _set_glyph_class_props (buffer->cur(), props, glyph_index); } else if (class_guess) { @@ -881,6 +920,19 @@ struct hb_ot_apply_context_t : else _hb_glyph_info_set_glyph_props (&buffer->cur(), props); } + void _set_glyph_class_props (hb_glyph_info_t &info, + unsigned int props, + hb_codepoint_t glyph_index) + { + props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; + _hb_glyph_info_set_glyph_props (&info, props | gdef_accel.get_glyph_props (glyph_index)); + } + void _set_glyph_class_props (hb_glyph_info_t &info) + { + _set_glyph_class_props (info, + _hb_glyph_info_get_glyph_props (&info), + info.codepoint); + } void replace_glyph (hb_codepoint_t glyph_index) { @@ -1813,23 +1865,25 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, if (buffer->have_output) c->buffer->sync_so_far (); c->buffer->message (c->font, - "recursing to lookup %u at %u", + "start recursing to lookup %u at %u", (unsigned) lookupRecord[i].lookupListIndex, buffer->idx); } - if (!c->recurse (lookupRecord[i].lookupListIndex)) - continue; + bool ret = c->recurse (lookupRecord[i].lookupListIndex); if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { if (buffer->have_output) c->buffer->sync_so_far (); c->buffer->message (c->font, - "recursed to lookup %u", + "end recursing to lookup %u", (unsigned) lookupRecord[i].lookupListIndex); } + if (!ret) + continue; + unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len (); int delta = new_len - orig_len; @@ -4590,7 +4644,7 @@ struct GSUBGPOSVersion1_2 public: DEFINE_SIZE_MIN (4 + 3 * Types::size); - unsigned int get_size () const + size_t get_size () const { return min_size + (version.to_int () >= 0x00010001u ? featureVars.static_size : 0); @@ -4672,7 +4726,7 @@ struct GSUBGPOSVersion1_2 struct GSUBGPOS { - unsigned int get_size () const + size_t get_size () const { switch (u.version.major) { case 1: hb_barrier (); return u.version1.get_size (); 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 c73e4dc4b6d..5f0bd1bce84 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc @@ -2072,21 +2072,25 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, 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); + char tag[5] = {0}; + hb_tag_to_string (chosen_script[0], tag); if (buffer->messaging () && - !buffer->message (font, "start table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0]))) return; + !buffer->message (font, "start table GSUB script tag '%s'", tag)) return; apply (proxy, plan, font, buffer); if (buffer->messaging ()) - (void) buffer->message (font, "end table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0])); + (void) buffer->message (font, "end table GSUB script tag '%s'", tag); } 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); + char tag[5] = {0}; + hb_tag_to_string (chosen_script[0], tag); if (buffer->messaging () && - !buffer->message (font, "start table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1]))) return; + !buffer->message (font, "start table GPOS script tag '%s'", tag)) return; apply (proxy, plan, font, buffer); if (buffer->messaging ()) - (void) buffer->message (font, "end table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1])); + (void) buffer->message (font, "end table GPOS script tag '%s'", tag); } void 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 24e9c970353..a044b7f9c0c 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 @@ -344,7 +344,7 @@ struct OS2 font_page_t get_font_page () const { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); } - unsigned get_size () const + size_t get_size () const { unsigned result = min_size; if (version >= 1) result += v1X.get_size (); 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 2c4c6c04663..1de8864c488 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 @@ -194,7 +194,11 @@ struct post for (unsigned int i = 0; i < count; i++) gids[i] = i; - hb_qsort (gids, count, sizeof (gids[0]), cmp_gids, (void *) this); + auto thiz = this; + hb_array_t (gids, count) + .qsort ([thiz] (const uint16_t &a, const uint16_t &b) { + return thiz->find_glyph_name (a).cmp (thiz->find_glyph_name (b)) > 0; + }); if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids))) { @@ -235,14 +239,6 @@ struct post return 0; } - static int cmp_gids (const void *pa, const void *pb, void *arg) - { - const accelerator_t *thiz = (const accelerator_t *) arg; - uint16_t a = * (const uint16_t *) pa; - uint16_t b = * (const uint16_t *) pb; - return thiz->find_glyph_name (b).cmp (thiz->find_glyph_name (a)); - } - static int cmp_key (const void *pk, const void *po, void *arg) { const accelerator_t *thiz = (const accelerator_t *) arg; 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 508ed6a5076..e97507480a4 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 @@ -322,6 +322,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, /* First round, decompose */ bool all_simple = true; + if (buffer->message (font, "start decompose")) { buffer->clear_output (); count = buffer->len; @@ -364,6 +365,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, } while (buffer->idx < count && buffer->successful); buffer->sync (); + (void) buffer->message (font, "end decompose"); } @@ -420,7 +422,8 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, if (!all_simple && buffer->successful && (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS || - mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT)) + mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT) && + buffer->message (font, "start compose")) { /* As noted in the comment earlier, we don't try to combine * ccc=0 chars with their previous Starter. */ @@ -470,6 +473,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, starter = buffer->out_len - 1; } buffer->sync (); + (void) buffer->message (font, "end compose"); } } 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 69b188f7aa3..9d792cc7f11 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc @@ -580,12 +580,8 @@ hb_form_clusters (hb_buffer_t *buffer) if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS)) return; - if (HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES (buffer->cluster_level)) - foreach_grapheme (buffer, start, end) - buffer->merge_clusters (start, end); - else - foreach_grapheme (buffer, start, end) - buffer->unsafe_to_break (start, end); + foreach_grapheme (buffer, start, end) + buffer->merge_grapheme_clusters (start, end); } static void @@ -1332,4 +1328,20 @@ hb_ot_shape_glyphs_closure (hb_font_t *font, } +/** + * hb_ot_shape_get_buffer_format_serial: + * + * Returns the serial number of the current internal buffer format. + * See #HB_OT_SHAPE_BUFFER_FORMAT_SERIAL for more information. + * + * Return value: The current buffer-format serial number. + * + * Since: 13.2.0 + **/ +unsigned int +hb_ot_shape_get_buffer_format_serial (void) +{ + return HB_OT_SHAPE_BUFFER_FORMAT_SERIAL; +} + #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.h index 1732831b132..7aaf5ed5c9c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.h @@ -54,6 +54,21 @@ hb_ot_shape_plan_get_feature_tags (hb_shape_plan_t *shape_plan, unsigned int *tag_count, /* IN/OUT */ hb_tag_t *tags /* OUT */); +/** + * HB_OT_SHAPE_BUFFER_FORMAT_SERIAL: + * + * The serial number of the current internal buffer format. + * + * The serial number will increase when internal #hb_glyph_info_t and + * #hb_glyph_position_t members change their format. + * + * Since: 13.2.0 + */ +#define HB_OT_SHAPE_BUFFER_FORMAT_SERIAL 1 + +HB_EXTERN unsigned int +hb_ot_shape_get_buffer_format_serial (void); + HB_END_DECLS #endif /* HB_OT_SHAPE_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-pua.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-pua.hh index ba86772f849..7464e5d8a3b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-pua.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-pua.hh @@ -9,41 +9,43 @@ #ifndef HB_OT_SHAPER_ARABIC_PUA_HH #define HB_OT_SHAPER_ARABIC_PUA_HH -static const uint8_t -_hb_arabic_u8[464] = +#include "hb.hh" + +#include + +static const uint8_t _hb_arabic_pua_u8[453]= { - 84, 86, 85, 85, 85, 85, 85,213, 16, 34, 34, 34, 34, 34, 35, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 36, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 82, 16, 0, 0, 0, 0, 1, 2, 3, 4, - 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 7, - 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 0, 0, 0, 22, 0, 23, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 16, 34, 34, 34, 35, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 66, 16, 50, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68,101, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 71, 68, 68, 68, 68, 68, 68, 68,152,186, 76, 77, 68,254, 16, 50, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 5, 6, - 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 10, 0, - 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 3, 0, + 4, 0, 0, 0, 0, 0, 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, 13, 0, 0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 23, 23, 29, 30, 31, 32, 33, 0, 0, 0, 0, - 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 36, 37, 38, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 40, - 41, 42, 0, 43, 44, 0, 0, 45, 46, 0, 47, 48, 49, 0, 0, 0, - 0, 50, 0, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 0, 0, 0, - 0, 0, 59, 60, 61, 62, 63, 64, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 66, - 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 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, + 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, 7, 0, 0, 8, 0, 0, 0, 9, 0, 0, + 10, 0, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, + 22, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 33, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, + 0, 0, 0, 0, 0, 0, 0, 33, 67, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,101, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,152, + 186, 12, 13, 0,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, + 5, 0, 0, 6, 7, 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, 10, + 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, + 0, 0, 13, 0, 0, 0, 0, 0, 14, 0, 0, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 1, 24, 25, 26, 27, 28, 1, 1, 29, 30, 31, 32, + 33, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, 0, 0, 0, 0, 0, 0, + 0, 39, 0, 0, 40, 41, 42, 0, 43, 44, 0, 0, 45, 46, 0, 47, + 48, 49, 0, 0, 0, 0, 50, 0, 0, 51, 52, 0, 53, 54, 55, 56, + 57, 58, 0, 0, 0, 0, 0, 59, 60, 61, 62, 63, 64, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 65, 0, 0, 66, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 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, }; -static const uint16_t -_hb_arabic_u16[720] = +static const uint16_t _hb_arabic_pua_u16[717]= { 0, 0, 0, 0, 0, 0, 0, 0,61728,61729,61730, 0, 0,61733, 0, 0, 61736,61737,61738,61739,61790,61741,61742,61743,61872,61873,61874,61875,61876,61877,61878,61879, @@ -65,52 +67,46 @@ _hb_arabic_u16[720] = 61808,61813,61813,61811,61812,61816,61816,61814,61815,61818,61818,61817,61817,61820,61820,61819, 61819,61822,61822,61821,61821,61921,61921,61823,61823,61860,61859,61857,61858,61861,61861,61868, 61867,61864,61863,61862,61862,61888,61889,61886,61887,61890,61891,61885,61884, 0, 0, 0, - 0, 0, 0, 0,61984,61985,61986, 0, 0,61989, 0, 0,61992,61993,61994,61995, - 62046,61997,61998,61999, 0, 0,62010,62011, 0,62013, 0,62015, 0, 0, 0,62043, - 0,62045, 0, 0, 0, 0, 0,61987, 0, 0, 0,61988, 0, 0, 0,61990, - 0, 0, 0,61991,61996, 0, 0, 0, 0, 0, 0,62011, 0, 0, 0,62015, - 0,62165,62021,62019,62170,62023,62169,62017,62028,62161,62032,62036,62040,62048,62052,62053, - 62055,62057,62059,62064,62068,62072,62078,62114,62115,62122,62126,61952,61952,61952,61952,61952, - 62047,62130,62134,62138,62142,62146,62150,62154,62155,62164,62160,62183,62184,62187,62180,62181, - 62186,62185,62182,61952,61952,61952,61952, 0,62000,62001,62002,62003,62004,62005,62006,62007, - 62008,62009, 0,62046,62046, 0, 0, 0,61964,61965,61966,61967,62012,62014, 0, 0, - 61954, 0,61981, 0, 0, 0,61955, 0,61982, 0,61956, 0, 0, 0,62111, 0, - 0, 0, 0,61970,61971,61972,61957, 0,61980, 0, 0, 0, 0, 0,61958, 0, - 61983, 0, 0, 0, 0, 0,62191, 0,62188,62189,62192, 0, 0, 0,61973, 0, - 0,62098, 0, 0,61974, 0, 0,62099, 0, 0,62101, 0, 0,61975, 0, 0, - 62100, 0, 0, 0,62080,62081,62082,62102, 0,62083,62084,62085,62103, 0, 0, 0, - 62106, 0,62107, 0,62108, 0, 0, 0,61976, 0, 0, 0, 0,62086,62087,62088, - 62109,61978,62089,62090,62091,62110,62093,62094, 0,62104, 0, 0, 0, 0,62095,62096, - 62097,62105, 0, 0,61977, 0, 0, 0, 0, 0,62075,62077,61968, 0, 0, 0, - 0,62021,62022,62019,62020,62170,62171,62023,62024,62169,62168,62166,62167,62017,62018,62028, - 62027,62025,62026,62161,62162,62032,62031,62029,62030,62036,62035,62033,62034,62040,62039,62037, - 62038,62048,62044,62041,62042,62052,62051,62049,62050,62053,62054,62055,62056,62057,62058,62059, - 62060,62064,62063,62061,62062,62068,62067,62065,62066,62072,62071,62069,62070,62078,62076,62073, - 62074,62114,62113,62079,62193,62118,62117,62115,62116,62122,62121,62119,62120,62126,62125,62123, - 62124,62130,62129,62127,62128,62134,62133,62131,62132,62138,62137,62135,62136,62142,62141,62139, - 62140,62146,62145,62143,62144,62150,62149,62147,62148,62154,62153,62151,62152,62155,62156,62164, - 62163,62160,62159,62157,62158,62176,62177,62174,62175,62178,62179,62172,62173, 0, 0, 0, + 0,61952,61952,61952,61952,61984,61985,61986, 0, 0,61989, 0, 0,61992,61993,61994, + 61995,62046,61997,61998,61999, 0, 0,62010,62011, 0,62013, 0,62015, 0, 0, 0, + 62043, 0,62045, 0, 0, 0, 0, 0,61987, 0, 0, 0,61988, 0, 0, 0, + 61990, 0, 0, 0,61991,61996, 0, 0, 0, 0, 0, 0,62011, 0, 0, 0, + 62015, 0,62165,62021,62019,62170,62023,62169,62017,62028,62161,62032,62036,62040,62048,62052, + 62053,62055,62057,62059,62064,62068,62072,62078,62114,62115,62122,62126,61952,62047,62130,62134, + 62138,62142,62146,62150,62154,62155,62164,62160,62183,62184,62187,62180,62181,62186,62185,62182, + 61952,61952,61952,61952, 0,62000,62001,62002,62003,62004,62005,62006,62007,62008,62009, 0, + 62046,62046, 0, 0, 0,61964,61965,61966,61967,62012,62014, 0, 0,61954, 0,61981, + 0, 0, 0,61955, 0,61982, 0,61956, 0, 0, 0,62111, 0, 0, 0, 0, + 61970,61971,61972,61957, 0,61980, 0, 0, 0, 0, 0,61958, 0,61983, 0, 0, + 0, 0, 0,62191, 0,62188,62189,62192, 0, 0, 0,61973, 0, 0,62098, 0, + 0,61974, 0, 0,62099, 0, 0,62101, 0, 0,61975, 0, 0,62100, 0, 0, + 0,62080,62081,62082,62102, 0,62083,62084,62085,62103, 0, 0, 0,62106, 0,62107, + 0,62108, 0, 0, 0,61976, 0, 0, 0, 0,62086,62087,62088,62109,61978,62089, + 62090,62091,62110,62093,62094, 0,62104, 0, 0, 0, 0,62095,62096,62097,62105, 0, + 0,61977, 0, 0, 0, 0, 0,62075,62077,61968, 0, 0, 0, 0,62021,62022, + 62019,62020,62170,62171,62023,62024,62169,62168,62166,62167,62017,62018,62028,62027,62025,62026, + 62161,62162,62032,62031,62029,62030,62036,62035,62033,62034,62040,62039,62037,62038,62048,62044, + 62041,62042,62052,62051,62049,62050,62053,62054,62055,62056,62057,62058,62059,62060,62064,62063, + 62061,62062,62068,62067,62065,62066,62072,62071,62069,62070,62078,62076,62073,62074,62114,62113, + 62079,62193,62118,62117,62115,62116,62122,62121,62119,62120,62126,62125,62123,62124,62130,62129, + 62127,62128,62134,62133,62131,62132,62138,62137,62135,62136,62142,62141,62139,62140,62146,62145, + 62143,62144,62150,62149,62147,62148,62154,62153,62151,62152,62155,62156,62164,62163,62160,62159, + 62157,62158,62176,62177,62174,62175,62178,62179,62172,62173, 0, 0, 0, }; -static inline unsigned -_hb_arabic_b2 (const uint8_t* a, unsigned i) +static inline uint8_t _hb_arabic_pua_b4 (const uint8_t* a, unsigned i) { - return (a[i>>2]>>((i&3u)<<1))&3u; + return (a[i>>1]>>((i&1)<<2))&15; } -static inline unsigned -_hb_arabic_b4 (const uint8_t* a, unsigned i) +static inline uint16_t _hb_arabic_pua_simp_map (unsigned u) { - return (a[i>>1]>>((i&1u)<<2))&15u; + /* packtab: [2^2,2^4,2^4,2^3] */ + return u<65277u ? (uint16_t)(_hb_arabic_pua_u16[((_hb_arabic_pua_u8[31u+((_hb_arabic_pua_b4(_hb_arabic_pua_u8,((((13835058055282164225ULL>>((((((((u)>>3))>>4))>>4))<<1))&3))<<4)+((((((u)>>3))>>4))&15)))<<4)+((((u)>>3))&15)])<<3)+((u)&7)]) : 0; } -static inline uint_fast16_t -_hb_arabic_pua_simp_map (unsigned u) +static inline uint16_t _hb_arabic_pua_trad_map (unsigned u) { - return u<65277u?_hb_arabic_u16[((_hb_arabic_u8[40+(((_hb_arabic_b4(8+_hb_arabic_u8,((_hb_arabic_b2(_hb_arabic_u8,u>>3>>4>>4))<<4)+((u>>3>>4)&15u)))<<4)+((u>>3)&15u))])<<3)+((u)&7u)]:0; -} -static inline uint_fast16_t -_hb_arabic_pua_trad_map (unsigned u) -{ - return u<65277u?_hb_arabic_u16[320+(((_hb_arabic_u8[208+(((_hb_arabic_b4(168+_hb_arabic_u8,((_hb_arabic_b4(136+_hb_arabic_u8,u>>2>>4>>4))<<4)+((u>>2>>4)&15u)))<<4)+((u>>2)&15u))])<<2)+((u)&3u))]:0; + /* packtab: [2^4,2^4,2^4,2^2] */ + return u<65277u ? (uint16_t)(_hb_arabic_pua_u16[317u+((_hb_arabic_pua_u8[197u+((_hb_arabic_pua_b4(_hb_arabic_pua_u8+159u,((_hb_arabic_pua_b4(_hb_arabic_pua_u8+127u,((((((u)>>2))>>4))>>4)))<<4)+((((((u)>>2))>>4))&15)))<<4)+((((u)>>2))&15)])<<2)+((u)&3)]) : 0; } #endif /* HB_OT_SHAPER_ARABIC_PUA_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh index 5f87995ea9c..81c84cf1962 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic-table.hh @@ -16,222 +16,77 @@ #ifndef HB_OT_SHAPER_ARABIC_TABLE_HH #define HB_OT_SHAPER_ARABIC_TABLE_HH +#include "hb.hh" -#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 X JOINING_TYPE_X +#include -static const uint8_t joining_table[] = +static const uint8_t _hb_arabic_joining_u8[737]= { + 0, 16, 2, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 96,135, 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, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 16, 24, 32, 40, 48, 0, 56, 0, 64, 72, 80, 0, + 0, 0, 0, 88, 96,104, 0, 0, 0, 0, 0,112,120, 0, 0, 0, + 0, 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0,136, 0, + 0,144, 0, 0, 0, 0, 0,152, 0, 0, 0, 0, 0, 0,160,168, + 176,184,192, 0, 0,200,208, 0, 0, 0, 0, 0, 0, 0, 0,216, + 224, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 10, 11, 12, + 1, 1, 13, 0, 0, 0, 14, 15, 1, 1, 2, 2, 4, 1, 1, 1, + 1, 16, 17, 18, 3, 0, 19, 0, 20, 0, 21, 22, 23, 1, 24, 0, + 0, 0, 25, 1, 26, 1, 27, 28, 4, 0, 29, 1, 1, 1, 30, 0, + 31, 32, 5, 33, 34, 35, 36, 2, 2, 37, 38, 6, 0, 1, 39, 40, + 5, 1, 7, 0, 0, 41, 0, 0, 0, 42, 43, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 7, 44, 1, 1, 1, 1, 45, 0, + 0, 0, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48, 6, 0, + 0, 1, 1, 1, 1, 1, 1, 49, 0, 50, 51, 52, 53, 54, 55, 0, + 0, 56, 57, 58, 0, 0, 59, 0, 0, 60, 1, 1, 1, 61, 0, 0, + 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, + 1, 64, 0, 65, 0, 0, 0, 66, 1, 67, 0, 0, 0, 0, 0, 68, + 69, 70, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 72, 73, 0, 0, 0, 0, 0, 0,119,119,119,119, 51, 51, 51, + 51, 34, 34, 34, 34,119,119, 7,119, 34, 51, 51, 51, 35, 51, 51, + 51, 0,119,119,119,115,119,119,119, 0, 0, 0,119,112, 7,119, + 119, 3, 34, 34, 35, 35, 51, 51, 35, 34, 50, 51, 51, 50,115,119, + 119,119,119,119, 51, 39, 34, 32, 34, 50, 35, 34, 34, 34, 34, 35, + 35, 51, 34, 39,119,119,119,119, 34,119, 51,115, 55,119,119,119, + 103,116, 51, 83, 37, 34, 51, 51, 50, 50, 53, 50, 83,119,119, 39, + 51, 35, 34, 51, 51, 51, 35, 50, 51, 35, 35, 50, 51,119, 51, 51, + 51, 51,115,119,119,119,115,119,119, 50, 51, 51, 34, 51, 51, 50, + 34,114,119,119,119, 3, 51, 51, 32, 35,114,119,119, 34, 50, 51, + 3, 48, 51, 51, 50, 51, 34, 2, 50, 35, 50, 51, 51,119,112,119, + 119,119,119,119, 48,119,115,119,112, 0, 0, 96, 54,115,115,119, + 119,119,119, 48,119,119,119,119, 7,119,119,119, 0, 51, 1,119, + 119, 51, 51, 35, 32, 32, 2, 16, 34, 34, 50, 51, 19, 51, 51, 35, + 51, 35, 0,114,119,119, 55, 51, 35, 35, 35, 34, 51, 35, 51, 50, + 34, 35,119,119,119, 39, 34, 50, 3, 49, 51, 51, 51, 51, 50,119, + 119,119, 50,115, 51, 51, 35, 51, 51, 51, 51, 3,119, 55, 51,114, + 119, 51, 51, 34, 51, 51,119,119,119, 3, 51, 34, 2, 35, 50, 35, + 51, 48, 34, 3, 0, 32, 19,119,119, 51, 51,119,119,119,103,119, + 119, +}; -#define joining_offset_0x0600u 0 - - /* Arabic */ - - /* 0600 */ U,U,U,U,U,U,X,X,U,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - /* 0620 */ D,U,R,R,R,R,D,R,D,R,D,D,D,D,D,R,R,R,R,D,D,D,D,D,D,D,D,D,D,D,D,D, - /* 0640 */ C,D,D,D,D,D,D,D,R,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - /* 0660 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,D,D,X,R,R,R,U,R,R,R,D,D,D,D,D,D,D,D, - /* 0680 */ D,D,D,D,D,D,D,D,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,D,D,D,D,D,D, - /* 06A0 */ 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, - /* 06C0 */ R,D,D,R,R,R,R,R,R,R,R,R,D,R,D,R,D,D,R,R,X,R,X,X,X,X,X,X,X,U,X,X, - /* 06E0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,R,R,X,X,X,X,X,X,X,X,X,X,D,D,D,X,X,D, - - /* Syriac */ - - /* 0700 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,T,A,X,D,D,D,DR,DR,R,R,R,D,D,D,D,R,D, - /* 0720 */ D,D,D,D,D,D,D,D,R,D,DR,D,R,D,D,DR,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - /* 0740 */ X,X,X,X,X,X,X,X,X,X,X,X,X,R,D,D, - - /* Arabic Supplement */ - - /* 0740 */ D,D,D,D,D,D,D,D,D,R,R,R,D,D,D,D, - /* 0760 */ D,D,D,D,D,D,D,D,D,D,D,R,R,D,D,D,D,R,D,R,R,D,D,D,R,R,D,D,D,D,D,D, - - /* FILLER */ - - /* 0780 */ 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, - /* 07A0 */ 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, - - /* NKo */ - - /* 07C0 */ X,X,X,X,X,X,X,X,X,X,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D, - /* 07E0 */ D,D,D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,C,X,X,X,X,X, - - /* FILLER */ - - /* 0800 */ 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, - /* 0820 */ 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, - - /* Mandaic */ - - /* 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 */ - - /* 0860 */ D,U,D,D,D,D,U,R,D,R,R,X,X,X,X,X, - - /* Arabic Extended-B */ - - /* 0860 */ R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R, - /* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,D,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - - /* 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,D,D,D,D,R,D,D,D,D,D,D, - /* 08C0 */ D,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, - /* 08E0 */ X,X,U, - -#define joining_offset_0x1806u 739 - - /* Mongolian */ - - /* 1800 */ U,D,X,X,C,X,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - /* 1820 */ 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, - /* 1840 */ 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, - /* 1860 */ 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,X,X,X,X,X,X,X, - /* 1880 */ U,U,U,U,U,T,T,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D, - /* 18A0 */ D,D,D,D,D,D,D,D,D,X,D, - -#define joining_offset_0x200cu 904 - - /* General Punctuation */ - - /* 2000 */ U,C,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - /* 2020 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - /* 2040 */ 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, - /* 2060 */ X,X,X,X,X,X,U,U,U,U, - -#define joining_offset_0xa840u 998 - - /* Phags-pa */ - - /* A840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D, - /* A860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,L,U, - -#define joining_offset_0x10ac0u 1050 - - /* Manichaean */ - - /* 10AC0 */ D,D,D,D,D,R,U,R,U,R,R,U,U,L,R,R,R,R,R,D,D,D,D,L,D,D,D,D,D,R,D,D, - /* 10AE0 */ D,R,U,U,R,X,X,X,X,X,X,D,D,D,D,R, - -#define joining_offset_0x10b80u 1098 - - /* Psalter Pahlavi */ - - /* 10B80 */ D,R,D,R,R,R,D,D,D,R,D,D,R,D,R,R,D,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - /* 10BA0 */ X,X,X,X,X,X,X,X,X,R,R,R,R,D,D,U, - -#define joining_offset_0x10d00u 1146 - - /* Hanifi Rohingya */ - - /* 10D00 */ L,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, - /* 10D20 */ D,D,R,D, - -#define joining_offset_0x10ec2u 1182 - - /* Arabic Extended-C */ - - /* 10EC0 */ R,D,D,X,D,D, - -#define joining_offset_0x10f30u 1188 - - /* Sogdian */ - - /* 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,X,X,X,X,X,X,X,X,X,X,X, - /* 10F60 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - - /* Old Uyghur */ - - /* 10F60 */ D,D,D,D,R,R,D,D,D,D,D,D,D,D,D,D, - /* 10F80 */ 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,X,X,X,X,X,X, - /* 10FA0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, - - /* 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 1344 - - /* Kaithi */ - - /* 110A0 */ U,X,X, - /* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U, - -#define joining_offset_0x1e900u 1361 - - /* 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,X,X,X,X,X,X,X,T, - -}; /* Table items: 1437; occupancy: 58% */ - +static inline uint8_t _hb_arabic_joining_b4 (const uint8_t* a, unsigned i) +{ + return (a[i>>1]>>((i&1)<<2))&15; +} +static inline uint8_t _hb_arabic_joining_joining_type (unsigned u) +{ + /* packtab: [2^4,2^3,2^3,2^3] */ + return u<125260u ? (uint8_t)(_hb_arabic_joining_b4(_hb_arabic_joining_u8+441u,((_hb_arabic_joining_u8[209u+_hb_arabic_joining_u8[123u+((_hb_arabic_joining_b4(_hb_arabic_joining_u8,((((((u)>>3))>>3))>>3)))<<3)+((((((u)>>3))>>3))&7)]+((((u)>>3))&7)])<<3)+((u)&7))) : 7; +} static unsigned int joining_type (hb_codepoint_t u) { - switch (u >> 12) - { - case 0x0u: - if (hb_in_range (u, 0x0600u, 0x08E2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u]; - break; - - case 0x1u: - if (hb_in_range (u, 0x1806u, 0x18AAu)) return joining_table[u - 0x1806u + joining_offset_0x1806u]; - break; - - case 0x2u: - if (hb_in_range (u, 0x200Cu, 0x2069u)) return joining_table[u - 0x200Cu + joining_offset_0x200cu]; - break; - - case 0xAu: - if (hb_in_range (u, 0xA840u, 0xA873u)) return joining_table[u - 0xA840u + joining_offset_0xa840u]; - break; - - case 0x10u: - if (hb_in_range (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u]; - if (hb_in_range (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u]; - if (hb_in_range (u, 0x10D00u, 0x10D23u)) return joining_table[u - 0x10D00u + joining_offset_0x10d00u]; - if (hb_in_range (u, 0x10EC2u, 0x10EC7u)) return joining_table[u - 0x10EC2u + joining_offset_0x10ec2u]; - if (hb_in_range (u, 0x10F30u, 0x10FCBu)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u]; - break; - - case 0x11u: - if (hb_in_range (u, 0x110BDu, 0x110CDu)) return joining_table[u - 0x110BDu + joining_offset_0x110bdu]; - break; - - case 0x1Eu: - if (hb_in_range (u, 0x1E900u, 0x1E94Bu)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u]; - break; - - default: - break; - } - return X; + return _hb_arabic_joining_joining_type (u); } -#undef A -#undef DR -#undef C -#undef D -#undef L -#undef R -#undef T -#undef U -#undef X - static const uint16_t shaping_table[][4] = { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc index 981c0f9224b..611aa262f40 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-arabic.cc @@ -77,8 +77,8 @@ enum hb_arabic_joining_type_t { JOINING_GROUP_DALATH_RISH = 5, NUM_STATE_MACHINE_COLS = 6, - JOINING_TYPE_T = 7, - JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */ + JOINING_TYPE_T = 6, + JOINING_TYPE_X = 7 /* means: use general-category to choose between U or T. */ }; #include "hb-ot-shaper-arabic-table.hh" @@ -561,20 +561,29 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%" PRId32, n_fixed, w_fixed); DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%" PRId32, n_repeating, w_repeating); - /* Number of additional times to repeat each repeating tile. */ - int n_copies = 0; + static constexpr unsigned STCH_MAX_GLYPHS = 256; - hb_position_t w_remaining = w_total - w_fixed; - if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0) - n_copies = (sign * w_remaining) / (sign * w_repeating) - 1; + /* Number of additional times to repeat each repeating tile. */ + unsigned int n_copies = 0; + + int64_t w_remaining_signed = (int64_t) w_total - w_fixed; + int64_t w_repeating_signed = w_repeating; + if (sign < 0) + { + w_remaining_signed = -w_remaining_signed; + w_repeating_signed = -w_repeating_signed; + } + hb_position_t w_remaining = (hb_position_t) (w_total - w_fixed); + if (w_remaining_signed > w_repeating_signed && w_repeating_signed > 0) + n_copies = w_remaining_signed / w_repeating_signed - 1; /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */ hb_position_t extra_repeat_overlap = 0; - hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1); + int64_t shortfall = w_remaining_signed - w_repeating_signed * (n_copies + 1); if (shortfall > 0 && n_repeating > 0) { ++n_copies; - hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining; + int64_t excess = (n_copies + 1) * w_repeating_signed - w_remaining_signed; if (excess > 0) { extra_repeat_overlap = excess / (n_copies * n_repeating); @@ -582,10 +591,25 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, } } + unsigned int max_copies = 0; + if (n_repeating > 0) + { + unsigned int base_glyphs = n_fixed + n_repeating; + if (base_glyphs < STCH_MAX_GLYPHS) + max_copies = (STCH_MAX_GLYPHS - base_glyphs) / n_repeating; + } + n_copies = hb_min (n_copies, max_copies); + if (step == MEASURE) { - extra_glyphs_needed += n_copies * n_repeating; - DEBUG_MSG (ARABIC, nullptr, "will add extra %d copies of repeating tiles", n_copies); + unsigned int added_glyphs = 0; + if (unlikely (hb_unsigned_mul_overflows (n_copies, n_repeating, &added_glyphs) || + hb_unsigned_add_overflows (extra_glyphs_needed, added_glyphs, &extra_glyphs_needed))) + { + extra_glyphs_needed = UINT_MAX; + break; + } + DEBUG_MSG (ARABIC, nullptr, "will add extra %u copies of repeating tiles", n_copies); } else { @@ -629,7 +653,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, if (step == MEASURE) { - if (unlikely (!buffer->ensure (count + extra_glyphs_needed))) + unsigned int total_glyphs = 0; + if (unlikely (hb_unsigned_add_overflows (count, extra_glyphs_needed, &total_glyphs) || + !buffer->ensure (total_glyphs))) break; } else diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc index 5f15aff8b7c..1430d142d14 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-hangul.cc @@ -298,7 +298,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED, end = start + 2; if (unlikely (!buffer->successful)) break; - buffer->merge_out_clusters (start, end); + buffer->merge_out_grapheme_clusters (start, end); continue; } } @@ -371,7 +371,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED, if (i < end) info[i++].hangul_shaping_feature() = TJMO; - buffer->merge_out_clusters (start, end); + buffer->merge_out_grapheme_clusters (start, end); continue; } else if ((!tindex && buffer->idx + 1 < count && isT (buffer->cur(+1).codepoint))) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc index bf27efee21b..74fe5efa3b7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-indic-table.cc @@ -77,9 +77,9 @@ static_assert (OT_VPst == M_Cat(VPst), ""); #define _OT_A OT_A /* 53 chars; A */ #define _OT_As OT_As /* 1 chars; As */ -#define _OT_C OT_C /* 478 chars; C */ +#define _OT_C OT_C /* 476 chars; C */ #define _OT_CM OT_CM /* 1 chars; CM */ -#define _OT_CS OT_CS /* 2 chars; CS */ +#define _OT_CS OT_CS /* 4 chars; CS */ #define _OT_DC OT_DOTTEDCIRCLE /* 1 chars; DOTTEDCIRCLE */ #define _OT_H OT_H /* 11 chars; H */ #define _OT_M OT_M /* 142 chars; M */ @@ -130,392 +130,112 @@ static_assert (OT_VPst == M_Cat(VPst), ""); #define _(S,M) INDIC_COMBINE_CATEGORIES (_OT_##S, _POS_##M) -static const uint16_t indic_table[] = { - - -#define indic_offset_0x0028u 0 - - - /* Basic Latin */ - - /* 0028 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(X,X), _(X,X), - /* 0030 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0038 */ _(GB,C), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - -#define indic_offset_0x00b0u 24 - - - /* Latin-1 Supplement */ - - /* 00B0 */ _(X,X), _(X,X),_(SP,SM),_(SP,SM), _(X,X), _(X,X), _(X,X), _(X,X), - /* 00B8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 00C0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 00C8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 00D0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), - -#define indic_offset_0x0900u 64 - - - /* Devanagari */ - - /* 0900 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(V,C), _(V,C), _(V,C), _(V,C), - /* 0908 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), - /* 0910 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), - /* 0918 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0920 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0928 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0930 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0938 */ _(C,C), _(C,C), _(M,AS), _(M,AS), _(N,X), _(S,SM), _(M,AS), _(M,LM), - /* 0940 */ _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), - /* 0948 */ _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(H,B), _(M,LM), _(M,AS), - /* 0950 */ _(X,X), _(A,SM), _(A,SM),_(SM,SM),_(SM,SM), _(M,AS), _(M,AS), _(M,AS), - /* 0958 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0960 */ _(V,C), _(V,C), _(M,AS), _(M,AS), _(X,X), _(X,X), _(GB,C), _(GB,C), - /* 0968 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0970 */ _(X,X), _(X,X), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), - /* 0978 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - - /* Bengali */ - - /* 0980 */ _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), - /* 0988 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(V,C), - /* 0990 */ _(V,C), _(X,X), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), - /* 0998 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 09A0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 09A8 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 09B0 */ _(R,C), _(X,X), _(C,C), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), - /* 09B8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,AP), _(M,LM), - /* 09C0 */ _(M,AP), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(X,X), _(X,X), _(M,LM), - /* 09C8 */ _(M,LM), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(C,C), _(X,X), - /* 09D0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP), - /* 09D8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), - /* 09E0 */ _(V,C), _(V,C), _(M,AS), _(M,AS), _(X,X), _(X,X), _(GB,C), _(GB,C), - /* 09E8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 09F0 */ _(R,C), _(C,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 09F8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(X,X),_(SM,SM), _(X,X), - - /* Gurmukhi */ - - /* 0A00 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), - /* 0A08 */ _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(X,X), _(X,X), _(V,C), - /* 0A10 */ _(V,C), _(X,X), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), - /* 0A18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0A20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0A28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0A30 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(X,X), - /* 0A38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(X,X), _(M,AP), _(M,LM), - /* 0A40 */_(MP,AP), _(M,AP), _(M,AP), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP), - /* 0A48 */ _(M,AP), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X), - /* 0A50 */ _(X,X), _(M,B), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0A58 */ _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(X,X), _(C,C), _(X,X), - /* 0A60 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(GB,C), - /* 0A68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0A70 */_(SM,SM),_(SM,SM), _(C,C), _(C,C), _(X,X), _(CM,C), _(X,X), _(X,X), - /* 0A78 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - - /* Gujarati */ - - /* 0A80 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), - /* 0A88 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), - /* 0A90 */ _(V,C), _(V,C), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), - /* 0A98 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0AA0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0AA8 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0AB0 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), - /* 0AB8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,AP), _(M,LM), - /* 0AC0 */ _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AS), _(X,X), _(M,AS), - /* 0AC8 */ _(M,AS), _(M,AP), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X), - /* 0AD0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0AD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0AE0 */ _(V,C), _(V,C), _(M,AP), _(M,AP), _(X,X), _(X,X), _(GB,C), _(GB,C), - /* 0AE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0AF0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0AF8 */ _(X,X), _(C,C), _(A,SM), _(N,X), _(A,SM), _(N,X), _(N,X), _(N,X), - - /* Oriya */ - - /* 0B00 */ _(X,X),_(SM,BS),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), - /* 0B08 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(V,C), - /* 0B10 */ _(V,C), _(X,X), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), - /* 0B18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0B20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0B28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0B30 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), - /* 0B38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,AP), _(M,A), - /* 0B40 */ _(M,AP), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(X,X), _(X,X), _(M,LM), - /* 0B48 */ _(M,A), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X), - /* 0B50 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(N,X), _(M,A), _(M,AP), - /* 0B58 */ _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), - /* 0B60 */ _(V,C), _(V,C), _(M,AS), _(M,AS), _(X,X), _(X,X), _(GB,C), _(GB,C), - /* 0B68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0B70 */ _(X,X), _(C,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0B78 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - - /* Tamil */ - - /* 0B80 */ _(X,X), _(X,X),_(SM,SM), _(X,X), _(X,X), _(V,C), _(V,C), _(V,C), - /* 0B88 */ _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(X,X), _(V,C), _(V,C), - /* 0B90 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(X,X), _(X,X), - /* 0B98 */ _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(X,X), _(C,C), _(C,C), - /* 0BA0 */ _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), _(X,X), _(X,X), - /* 0BA8 */ _(C,C), _(C,C), _(C,C), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), - /* 0BB0 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0BB8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP), _(M,AP), - /* 0BC0 */ _(M,AS), _(M,AP), _(M,AP), _(X,X), _(X,X), _(X,X), _(M,LM), _(M,LM), - /* 0BC8 */ _(M,LM), _(X,X), _(M,AP), _(M,AP), _(M,AP), _(H,T), _(X,X), _(X,X), - /* 0BD0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP), - /* 0BD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0BE0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(GB,C), - /* 0BE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0BF0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0BF8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - - /* Telugu */ - - /* 0C00 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(V,C), _(V,C), _(V,C), - /* 0C08 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), _(V,C), - /* 0C10 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), - /* 0C18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0C20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0C28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0C30 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0C38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,BS), _(M,BS), - /* 0C40 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS), _(X,X), _(M,BS), _(M,BS), - /* 0C48 */ _(M,BS), _(X,X), _(M,BS), _(M,BS), _(M,BS), _(H,T), _(X,X), _(X,X), - /* 0C50 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,BS), _(M,BS), _(X,X), - /* 0C58 */ _(C,C), _(C,C), _(C,C), _(X,X), _(X,X), _(C,C), _(X,X), _(X,X), - /* 0C60 */ _(V,C), _(V,C), _(M,BS), _(M,BS), _(X,X), _(X,X), _(GB,C), _(GB,C), - /* 0C68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0C70 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0C78 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - - /* Kannada */ - - /* 0C80 */ _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), - /* 0C88 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), _(V,C), - /* 0C90 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), - /* 0C98 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0CA0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0CA8 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0CB0 */ _(R,C), _(C,C), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), - /* 0CB8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,BS), _(M,BS), - /* 0CC0 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS), _(X,X), _(M,BS), _(M,AS), - /* 0CC8 */ _(M,AS), _(X,X), _(M,AS), _(M,AS), _(M,BS), _(H,T), _(X,X), _(X,X), - /* 0CD0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AS), _(M,AS), _(X,X), - /* 0CD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), - /* 0CE0 */ _(V,C), _(V,C), _(M,BS), _(M,BS), _(X,X), _(X,X), _(GB,C), _(GB,C), - /* 0CE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0CF0 */ _(X,X), _(CS,C), _(CS,C),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0CF8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - - /* Malayalam */ - - /* 0D00 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(GB,C), _(V,C), _(V,C), _(V,C), - /* 0D08 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), _(V,C), - /* 0D10 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), - /* 0D18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0D20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0D28 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0D30 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 0D38 */ _(C,C), _(C,C), _(C,C), _(M,AS), _(M,AS), _(S,SM), _(M,AP), _(M,AP), - /* 0D40 */ _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(X,X), _(M,LM), _(M,LM), - /* 0D48 */ _(M,LM), _(X,X), _(M,AP), _(M,AP), _(M,AP), _(H,T), _(Rf,X), _(X,X), - /* 0D50 */ _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(C,C), _(M,AP), - /* 0D58 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(V,C), - /* 0D60 */ _(V,C), _(V,C), _(M,AP), _(M,AP), _(X,X), _(X,X), _(GB,C), _(GB,C), - /* 0D68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 0D70 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 0D78 */ _(X,X), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - -#define indic_offset_0x1000u 1216 - - - /* Myanmar */ - - /* 1000 */ _(C,C), _(C,C), _(C,C), _(C,C), _(R,C), _(C,C), _(C,C), _(C,C), - /* 1008 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 1010 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 1018 */ _(C,C), _(C,C), _(C,C), _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 1020 */ _(C,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), - /* 1028 */ _(V,C), _(V,C), _(V,C), _(VR,R), _(VR,R), _(VA,T), _(VA,T), _(VB,B), - /* 1030 */ _(VB,B), _(VL,L), _(A,SM), _(VA,T), _(VA,T), _(VA,T), _(A,SM), _(N,X), - /* 1038 */_(SM,SM), _(H,X), _(As,X), _(MY,X), _(MR,X), _(MW,X), _(MH,X), _(C,C), - /* 1040 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 1048 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), _(X,X), _(C,C), _(X,X), - /* 1050 */ _(C,C), _(C,C), _(V,C), _(V,C), _(V,C), _(V,C), _(VR,R), _(VR,R), - /* 1058 */ _(VB,B), _(VB,B), _(R,C), _(C,C), _(C,C), _(C,C), _(MY,X), _(MY,X), - /* 1060 */ _(ML,X), _(C,C), _(VR,R), _(PT,X), _(PT,X), _(C,C), _(C,C), _(VR,R), - /* 1068 */ _(VR,R), _(PT,X), _(PT,X), _(PT,X), _(PT,X), _(PT,X), _(C,C), _(C,C), - /* 1070 */ _(C,C), _(VA,T), _(VA,T), _(VA,T), _(VA,T), _(C,C), _(C,C), _(C,C), - /* 1078 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 1080 */ _(C,C), _(C,C), _(MW,X), _(VR,R), _(VL,L), _(VA,T), _(VA,T),_(SM,SM), - /* 1088 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(C,C),_(SM,SM), - /* 1090 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 1098 */ _(GB,C), _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(VA,T), _(X,X), _(X,X), - -#define indic_offset_0x1780u 1376 - - - /* Khmer */ - - /* 1780 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 1788 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 1790 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 1798 */ _(C,C), _(C,C), _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* 17A0 */ _(C,C), _(C,C), _(C,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), - /* 17A8 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), - /* 17B0 */ _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(VR,R), _(VA,T), - /* 17B8 */ _(VA,T), _(VA,T), _(VA,T), _(VB,B), _(VB,B), _(VB,B), _(VA,T), _(VR,R), - /* 17C0 */ _(VR,R), _(VL,L), _(VL,L), _(VL,L), _(VR,R), _(VR,R), _(Xg,X), _(Yg,X), - /* 17C8 */ _(Yg,X), _(Rt,X), _(Rt,X), _(Xg,X), _(Rt,X), _(Xg,X), _(Xg,X), _(Xg,X), - /* 17D0 */ _(Xg,X), _(Xg,X), _(H,X), _(Yg,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 17D8 */ _(X,X), _(GB,C), _(X,X), _(X,X), _(S,SM), _(Yg,X), _(X,X), _(X,X), - /* 17E0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 17E8 */ _(GB,C), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - -#define indic_offset_0x1cd0u 1488 - - - /* Vedic Extensions */ - - /* 1CD0 */ _(A,SM), _(A,SM), _(A,SM), _(X,X), _(A,SM), _(A,SM), _(A,SM), _(A,SM), - /* 1CD8 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), - /* 1CE0 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), - /* 1CE8 */ _(A,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(A,SM), _(S,SM), _(S,SM), - /* 1CF0 */ _(S,SM), _(S,SM), _(C,C), _(C,C), _(A,SM), _(C,C), _(C,C), _(A,SM), - /* 1CF8 */ _(A,SM), _(A,SM), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - -#define indic_offset_0x2008u 1536 - - - /* General Punctuation */ - - /* 2008 */ _(X,X), _(X,X), _(X,X), _(X,X),_(ZWNJ,X),_(ZWJ,X), _(X,X), _(X,X), - /* 2010 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), _(X,X), - /* 2018 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 2020 */ _(X,X), _(X,X), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - -#define indic_offset_0x2070u 1568 - - - /* Superscripts and Subscripts */ - - /* 2070 */ _(X,X), _(X,X), _(X,X), _(X,X),_(SP,SM), _(X,X), _(X,X), _(X,X), - /* 2078 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), - /* 2080 */ _(X,X), _(X,X),_(SP,SM),_(SP,SM),_(SP,SM), _(X,X), _(X,X), _(X,X), - -#define indic_offset_0x25f8u 1592 - - - /* Geometric Shapes */ - - /* 25F8 */ _(X,X), _(X,X), _(X,X), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), - -#define indic_offset_0xa8e0u 1600 - - - /* Devanagari Extended */ - - /* A8E0 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), - /* A8E8 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), - /* A8F0 */ _(A,SM), _(A,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), - /* A8F8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(V,C), _(M,AS), - -#define indic_offset_0xa9e0u 1632 - - - /* Myanmar Extended-B */ - - /* A9E0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(VA,T), _(X,X), _(C,C), - /* A9E8 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* A9F0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* A9F8 */ _(GB,C), _(GB,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(X,X), - -#define indic_offset_0xaa60u 1664 - - - /* Myanmar Extended-A */ - - /* AA60 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* AA68 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), - /* AA70 */ _(X,X), _(C,C), _(C,C), _(C,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), - /* AA78 */ _(X,X), _(X,X), _(C,C), _(PT,X), _(N,X), _(N,X), _(C,C), _(C,C), - -#define indic_offset_0xfe00u 1696 - - - /* Variation Selectors */ - - /* FE00 */ _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), - /* FE08 */ _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), - -#define indic_offset_0x11300u 1712 - - - /* Grantha */ - - /* 11300 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X), - -#define indic_offset_0x11338u 1720 - - /* 11338 */ _(X,X), _(X,X), _(X,X), _(N,X), _(N,X), _(X,X), _(X,X), _(X,X), - -#define indic_offset_0x116d0u 1728 - - - /* Myanmar Extended-C */ - - /* 116D0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 116D8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), - /* 116E0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), - -}; /* Table items: 1752; occupancy: 71% */ +#include + +static const uint16_t _hb_indic_values[42]= +{ + _(A,SM), _(As,X), _(C,C), _(CM,C), _(CS,C), _(DC,C), _(GB,C), _(H,B), + _(H,T), _(H,X), _(M,A), _(M,AP), _(M,AS), _(M,B), _(M,BS), _(M,LM), + _(MH,X), _(ML,X), _(MP,AP), _(MR,X), _(MW,X), _(MY,X), _(N,X), _(PT,X), + _(R,C), _(Rf,X), _(Rt,X), _(S,SM), _(SM,BS), _(SM,SM), _(SP,SM), _(V,C), + _(VA,T), _(VB,B), _(VL,L), _(VR,R), _(VS,X), _(X,X), _(Xg,X), _(Yg,X), + _(ZWJ,X),_(ZWNJ,X), +}; +static const uint8_t _hb_indic_u8[1220]= +{ + 1, 0, 50, 4, 5, 96, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,186, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192, + 0, 0, 0, 0,208,224, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 22, 23, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, 0, 0, + 0, 27, 0, 0, 0, 0, 28, 29, 30, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 31, 0, 0, 0, 32, 0, 0, 0, 33, 0, 34, + 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 36, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 25, 2, 10, 0, 0, 0, 0, 26, 0, + 27, 0, 0, 0, 28, 0, 0, 0, 0, 0, 29, 11, 30, 1, 1, 1, + 4, 31, 32, 33, 34, 1, 6, 2, 35, 1, 12, 13, 7, 1, 1, 3, + 36, 14, 15, 37, 16, 17, 6, 2, 38, 39, 18, 40, 7, 1, 1, 3, + 41, 42, 43, 44, 45, 46, 19, 2, 47, 0, 18, 48, 49, 1, 1, 3, + 20, 14, 50, 51, 0, 0, 21, 2, 0, 52, 53, 13, 7, 1, 1, 3, + 20, 54, 15, 55, 56, 17, 6, 2, 57, 0, 58, 59, 60, 61, 62, 63, + 4, 64, 65, 66, 16, 0, 19, 2, 0, 0, 67, 8, 9, 1, 1, 3, + 4, 22, 68, 69, 70, 71, 23, 2, 0, 0, 12, 8, 9, 1, 1, 3, + 72, 22, 73, 74, 75, 76, 23, 2, 77, 0, 78, 8, 9, 1, 1, 1, + 4, 79, 80, 81, 82, 83, 21, 2, 0, 84, 85, 1, 1, 86, 87, 88, + 89, 90, 2, 91, 92, 93, 94, 95, 96, 1, 97, 98, 2, 99, 0, 0, + 0, 0, 1, 1, 1,100,101, 11,102,103,104,105,106,107, 2, 10, + 0, 0, 0, 0,108, 5, 5,109,110,111, 0,112,113, 0,114, 0, + 0, 0, 0, 0, 0, 0, 0, 0,115, 0,116, 0, 0, 0, 0, 0, + 0, 0, 0,117, 0, 0, 0, 0, 0,118, 0, 0, 0, 0, 5, 5, + 119,120, 0, 0, 0, 0,121, 1, 2,122, 0, 0, 0, 0, 1, 1, + 123,124, 24, 24, 0, 0, 0, 0, 0, 0,125, 0, 0, 0, 0, 0, + 0,126, 0, 0, 2, 2, 2, 10, 0, 0, 0, 0, 2, 2, 2, 2, + 4, 4, 4, 4, 10, 2, 2, 2, 26, 2, 2, 2, 8, 8, 8, 8, + 6, 18, 0, 4, 20, 14, 24, 2, 6, 6, 20, 6, 20, 6, 24, 2, + 4, 0, 0, 0, 6, 6, 6, 6, 66, 12, 14, 6, 6, 6, 20, 14, + 2, 0, 36, 50, 52, 18, 38, 68, 0, 0, 0, 32, 0, 0, 2, 16, + 56, 12, 14, 6, 0, 0, 0, 4, 44, 2, 16, 2, 6, 22, 0, 4, + 2, 0, 36, 28, 6, 28, 0, 4, 30, 30, 30, 30, 0, 0, 42, 0, + 34, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 42, 12, 12, 6, 6, + 6, 6, 24, 2, 2, 18, 36,112, 18, 18, 18, 18, 18, 18,114,116, + 118,120,122, 18, 0, 6, 6, 6, 44, 10, 0, 2, 54, 32, 46, 10, + 26, 0, 0, 0, 0, 0, 34, 70, 6, 20, 0, 14, 44, 2, 16, 10, + 2, 0, 72, 50,124, 48, 0, 32, 48, 32, 46, 0,126, 0, 0, 0, + 16, 2, 10, 10, 12, 2,128, 0, 6, 6, 6, 14, 6, 14, 24, 2, + 22, 22, 52, 74, 76, 32, 46, 0, 16, 58, 58, 78,130, 12, 14, 6, + 2, 0, 36,132,134, 32, 46, 0, 0, 0, 80,136, 16, 0, 0, 0, + 0, 70, 14, 6, 6, 20, 0, 6, 20, 6, 24, 0, 16, 10, 10, 2, + 0, 16, 10, 0, 2, 10, 0, 2, 2, 0, 0, 22, 76, 48, 0, 82, + 54, 22, 84, 0, 12, 12,138, 6, 28, 60, 38, 28, 86, 28, 88, 0, + 0, 0,140, 86, 2, 10, 16, 0, 26, 2, 16, 2, 28, 60, 38, 60, + 38, 18, 88, 0, 0, 0, 74, 38, 0, 0, 16, 10,142,144, 0, 0, + 12, 12,146, 6, 2,148,150, 22, 22, 22, 48, 82, 54, 22, 84,152, + 0, 0, 2,154, 0, 0, 0, 14, 0, 2, 2, 2, 2, 2, 26, 2, + 2,156, 2, 2, 90, 6, 6, 6, 6,158, 92, 94,160,162, 62, 58, + 164,166,168,170, 4, 4, 0, 10, 2, 6, 6, 96, 98, 26, 2,172, + 174,100,176,178,100,102,102, 2,104, 62,180, 2, 2,182,184,186, + 12, 12, 12,188, 4, 12,190, 0, 2, 26, 2, 2, 2, 90, 6, 6, + 6, 6, 0, 92, 62, 94, 98,192,194,196, 96,198,200,106,106,108, + 108,202, 0, 0, 42, 0,204, 0, 8,206, 8, 8,208, 40,210, 40, + 40, 2,212,214, 8, 34, 0, 0, 0, 0,216, 0, 4, 4, 4, 0, + 0, 34, 0, 0, 0, 0,110, 0, 0, 64,110, 0, 0, 0,218, 0, + 0, 42, 4, 34, 8, 40, 40, 40, 0, 0, 0,220, 2, 2,104, 16, + 4, 2, 2, 10, 16, 2, 4, 34, 0,222, 78, 2, 56, 12, 0, 0, + 0, 80, 72, 0, 37, 37, 2, 2, 6, 6, 31, 31, 0, 0, 2, 37, + 29, 29, 37, 31, 37, 2, 12, 12, 31, 37, 11, 11, 31, 2, 24, 2, + 14, 14, 36, 36, 37, 11, 6, 37, 22, 27, 12, 37, 27, 27, 37, 6, + 24, 37, 11, 7, 11, 37, 11, 15, 11, 12, 15, 37, 37, 29, 0, 22, + 14, 12, 32, 32, 30, 30, 6, 29, 37, 15, 29, 37, 22, 37, 37, 12, + 12, 11, 22, 22, 37, 22, 15, 15, 11, 8, 14, 37, 14, 8, 2, 31, + 35, 32, 32, 33, 35, 35, 33, 33, 35, 23, 23, 23, 2, 32, 26, 38, + 38, 38, 30, 37, 12, 15, 12, 7, 15, 12, 37, 0, 0, 29, 29, 12, + 18, 11, 37, 13, 37, 3, 37, 28, 11, 10, 10, 37, 10, 11, 29, 31, + 37, 14, 37, 4, 4, 29, 6, 31, 2, 12, 12, 27, 25, 37, 2, 11, + 2, 24, 31, 35, 33, 34, 0, 32, 29, 9, 1, 21, 19, 20, 16, 2, + 21, 21, 17, 2, 23, 2, 2, 35, 32, 2, 20, 35, 34, 32, 32, 29, + 2, 29, 29, 32, 32, 35, 35, 34, 34, 34, 38, 39, 39, 26, 9, 39, + 27, 39, 0, 37, 0, 27, 27, 0, 0, 4, 4, 0, 41, 40, 5, 37, + 31, 12, 2, 23, +}; + +static inline uint8_t _hb_indic_b4 (const uint8_t* a, unsigned i) +{ + return (a[i>>1]>>((i&1)<<2))&15; +} +static inline uint8_t _hb_indic_get_categories_index (unsigned u) +{ + /* packtab: [2^4,2^3,2^3,2^2,2^1] */ + return u<71396u ? (uint8_t)(_hb_indic_u8[996u+_hb_indic_u8[488u+((_hb_indic_u8[186u+((_hb_indic_u8[70u+((_hb_indic_b4(_hb_indic_u8,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)])<<3)+((((((u)>>1))>>2))&7)])<<2)+((((u)>>1))&3)]+((u)&1)]) : 37; +} uint16_t hb_indic_get_categories (hb_codepoint_t u) { - switch (u >> 12) - { - case 0x0u: - if (unlikely (u == 0x00A0u)) return _(GB,C); - if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u]; - if (hb_in_range (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u]; - if (hb_in_range (u, 0x0900u, 0x0D7Fu)) return indic_table[u - 0x0900u + indic_offset_0x0900u]; - break; - - case 0x1u: - if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u]; - if (hb_in_range (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u]; - if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u]; - break; - - case 0x2u: - if (unlikely (u == 0x25CCu)) return _(DC,C); - if (hb_in_range (u, 0x2008u, 0x2027u)) return indic_table[u - 0x2008u + indic_offset_0x2008u]; - if (hb_in_range (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u]; - if (hb_in_range (u, 0x25F8u, 0x25FFu)) return indic_table[u - 0x25F8u + indic_offset_0x25f8u]; - break; - - case 0xAu: - if (hb_in_range (u, 0xA8E0u, 0xA8FFu)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u]; - if (hb_in_range (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u]; - if (hb_in_range (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u]; - break; - - case 0xFu: - if (hb_in_range (u, 0xFE00u, 0xFE0Fu)) return indic_table[u - 0xFE00u + indic_offset_0xfe00u]; - break; - - case 0x11u: - if (hb_in_range (u, 0x11300u, 0x11307u)) return indic_table[u - 0x11300u + indic_offset_0x11300u]; - if (hb_in_range (u, 0x11338u, 0x1133Fu)) return indic_table[u - 0x11338u + indic_offset_0x11338u]; - if (hb_in_range (u, 0x116D0u, 0x116E7u)) return indic_table[u - 0x116D0u + indic_offset_0x116d0u]; - break; - - default: - break; - } - return _(X,X); + return _hb_indic_values[_hb_indic_get_categories_index (u)]; } #undef _ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc index 42fc4bbcc44..92fc20e968d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-thai.cc @@ -356,13 +356,11 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, sizeof (buffer->out_info[0]) * (end - start - 2)); buffer->out_info[start] = t; } - else - { - /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the - * previous cluster. */ - if (start) - buffer->merge_out_clusters (start - 1, end); - } + + /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the + * previous cluster. */ + if (start) + buffer->merge_out_grapheme_clusters (start - 1, end); } buffer->sync (); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh index a69abefdd01..0b038ba2201 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-use-table.hh @@ -2,7 +2,7 @@ /* * The following table is generated by running: * - * ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt + * gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt * * on files with these headers: * @@ -105,272 +105,272 @@ static const uint8_t hb_use_u8[3343]= { - 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 57, 58, 59, 195, 211, 62, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 15, 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 4, 2, 2, - 5, 6, 2, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 2, 2, 17, - 18, 19, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 2, 33, 2, 2, 2, - 2, 34, 35, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 2, 2, 2, - 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 38, 2, 39, 2, 2, + 33, 3, 0, 0, 0, 4, 0, 80, 118, 128, 9, 10, 11, 192, 208, 14, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 5, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 7, 0, 0, + 8, 9, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 20, + 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 36, 0, 0, 0, + 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, + 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 42, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 43, 44, 45, 46, 47, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, + 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 0, 0, 0, + 0, 0, 0, 0, 0, 55, 56, 0, 57, 0, 0, 58, 59, 0, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 0, 73, 74, 75, 76, + 0, 77, 0, 78, 79, 80, 81, 82, 0, 83, 84, 85, 86, 0, 87, 88, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 89, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 90, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 92, 93, 0, 0, 0, 94, 0, 0, 0, 95, + 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 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, 0, 0, 0, 98, 99, 0, 0, 0, 0, 0, + 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 101, 0, 0, 102, 0, 0, 0, 103, 0, 104, 0, 0, 0, + 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 106, 107, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 40, 41, 42, 43, 44, 45, 2, 46, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 48, 2, - 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 50, 51, 2, 2, 2, - 2, 2, 2, 2, 2, 52, 53, 2, 54, 2, 2, 55, 56, 2, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 2, 70, 71, 72, 73, - 2, 74, 2, 75, 76, 77, 78, 79, 2, 80, 81, 82, 83, 2, 84, 85, - 2, 86, 86, 86, 86, 86, 86, 86, 86, 87, 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, 88, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 90, 91, 2, 2, 2, 92, 2, 2, 2, 93, - 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 95, 95, 95, 96, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 98, 2, 2, 2, 2, 2, - 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 100, 2, 2, 101, 2, 2, 2, 102, 2, 103, 2, 2, 2, - 2, 2, 2, 104, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 105, 105, 106, 107, 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, - 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, - 0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 7, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 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, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 11, - 11, 11, 11, 0, 0, 0, 9, 12, 0, 2, 2, 2, 2, 13, 14, 0, - 0, 11, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 17, - 18, 19, 20, 21, 22, 16, 23, 24, 25, 12, 26, 27, 20, 2, 2, 2, - 2, 2, 20, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, - 2, 28, 29, 30, 2, 2, 2, 9, 30, 9, 30, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 9, 0, 2, 2, 0, 17, - 18, 19, 20, 31, 32, 33, 32, 34, 0, 0, 0, 0, 35, 0, 0, 2, - 30, 2, 0, 0, 0, 0, 0, 9, 36, 12, 15, 30, 2, 2, 9, 0, - 30, 9, 2, 30, 9, 2, 0, 37, 18, 19, 31, 0, 27, 38, 27, 39, - 0, 40, 0, 0, 0, 30, 2, 9, 9, 0, 0, 0, 2, 2, 2, 2, - 2, 41, 42, 43, 0, 0, 0, 0, 0, 12, 15, 30, 2, 2, 2, 2, - 30, 2, 30, 2, 2, 2, 2, 2, 2, 9, 2, 30, 2, 2, 0, 17, - 18, 19, 20, 21, 27, 22, 35, 24, 0, 0, 0, 0, 0, 30, 41, 41, - 44, 12, 29, 30, 2, 2, 2, 9, 30, 9, 2, 30, 2, 2, 0, 17, - 45, 0, 0, 27, 22, 0, 0, 2, 30, 30, 0, 0, 0, 0, 0, 0, - 0, 0, 46, 30, 2, 2, 9, 0, 2, 9, 2, 2, 0, 30, 9, 9, - 2, 0, 30, 9, 0, 2, 9, 0, 2, 2, 2, 2, 2, 2, 0, 0, - 23, 16, 47, 0, 48, 33, 48, 34, 0, 0, 0, 0, 35, 0, 0, 0, - 0, 15, 29, 49, 2, 2, 2, 9, 2, 9, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 0, 17, 22, 16, 23, 47, 22, 38, 22, 39, - 0, 0, 0, 27, 31, 2, 9, 0, 0, 10, 29, 30, 2, 2, 2, 9, - 2, 2, 2, 30, 2, 2, 0, 17, 45, 0, 0, 35, 47, 0, 0, 0, - 9, 50, 51, 0, 0, 0, 0, 0, 0, 11, 29, 2, 2, 2, 2, 9, - 2, 2, 2, 2, 2, 2, 52, 53, 23, 19, 20, 31, 48, 33, 48, 34, - 54, 0, 0, 0, 35, 0, 0, 0, 30, 12, 29, 30, 2, 2, 2, 2, - 2, 2, 2, 2, 9, 0, 2, 2, 2, 2, 30, 2, 2, 2, 2, 30, - 0, 2, 2, 2, 9, 0, 55, 0, 35, 23, 22, 31, 31, 18, 48, 48, - 25, 0, 23, 0, 0, 0, 0, 0, 0, 2, 0, 2, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 2, 56, 56, 57, 0, 0, - 18, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, - 0, 58, 21, 59, 22, 22, 20, 20, 46, 21, 11, 31, 11, 2, 2, 60, - 61, 61, 61, 61, 61, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 63, 0, 0, 0, 0, 64, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 65, 45, 59, 66, 22, 22, 67, 68, 69, 70, - 71, 2, 2, 2, 2, 2, 1, 0, 5, 2, 2, 2, 23, 20, 2, 2, - 72, 71, 73, 74, 65, 73, 29, 29, 2, 52, 22, 53, 2, 2, 2, 2, - 2, 2, 75, 76, 77, 29, 29, 78, 79, 2, 2, 2, 2, 2, 29, 45, - 0, 2, 59, 80, 0, 0, 0, 0, 30, 2, 59, 47, 0, 0, 0, 0, - 0, 2, 59, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 9, - 2, 9, 59, 0, 0, 0, 0, 0, 0, 2, 2, 81, 45, 22, 59, 20, - 48, 48, 48, 48, 15, 82, 83, 84, 85, 86, 87, 0, 0, 0, 0, 88, - 0, 9, 0, 0, 30, 0, 89, 81, 90, 2, 2, 2, 2, 9, 0, 0, - 0, 42, 42, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 13, 9, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 9, 22, 80, 45, 22, 93, 61, 0, - 0, 94, 95, 94, 94, 96, 97, 0, 0, 2, 2, 2, 2, 2, 2, 2, - 0, 2, 2, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, - 0, 2, 2, 2, 2, 29, 0, 0, 0, 2, 2, 2, 2, 2, 9, 0, - 0, 2, 2, 2, 52, 98, 45, 0, 0, 2, 2, 99, 100, 101, 102, 61, - 63, 103, 16, 45, 22, 59, 21, 80, 48, 48, 76, 11, 11, 11, 104, 46, - 40, 11, 105, 74, 2, 2, 2, 2, 2, 2, 2, 106, 22, 20, 20, 22, - 48, 48, 22, 107, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 108, 109, - 109, 109, 109, 0, 0, 0, 0, 0, 0, 105, 74, 2, 2, 2, 2, 2, - 2, 60, 61, 59, 25, 22, 110, 61, 2, 2, 2, 2, 106, 22, 23, 45, - 45, 101, 111, 0, 0, 0, 0, 0, 0, 2, 2, 61, 18, 48, 23, 112, - 101, 101, 101, 113, 114, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 30, - 2, 11, 46, 115, 115, 115, 11, 115, 115, 15, 115, 115, 115, 26, 0, 40, - 0, 0, 0, 116, 51, 11, 5, 0, 0, 0, 0, 0, 0, 0, 117, 0, - 0, 0, 0, 0, 0, 0, 6, 118, 119, 42, 42, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119, - 119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 7, 121, 0, 0, 0, 0, - 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, - 0, 0, 0, 0, 122, 122, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, - 30, 0, 0, 0, 0, 0, 0, 0, 123, 0, 122, 122, 0, 0, 0, 0, - 0, 2, 53, 2, 107, 2, 10, 2, 2, 2, 65, 19, 16, 0, 0, 31, - 0, 2, 2, 0, 0, 0, 0, 0, 0, 29, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 124, 23, 23, 23, 23, 23, 23, 23, 125, 0, 0, 0, 0, - 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 0, 0, 0, 0, 0, - 52, 2, 2, 2, 22, 22, 126, 115, 0, 2, 2, 2, 127, 20, 59, 20, - 112, 101, 128, 0, 0, 0, 0, 0, 0, 11, 129, 2, 2, 2, 2, 2, - 2, 2, 130, 23, 22, 20, 48, 131, 132, 133, 0, 0, 0, 0, 0, 0, - 0, 2, 2, 52, 30, 2, 2, 2, 2, 2, 2, 2, 2, 10, 22, 59, - 98, 76, 134, 135, 136, 0, 0, 0, 0, 2, 137, 2, 2, 2, 2, 138, - 0, 30, 2, 42, 5, 0, 79, 15, 2, 139, 20, 53, 127, 139, 2, 2, - 140, 10, 9, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 141, 21, - 25, 0, 0, 142, 143, 0, 0, 0, 0, 2, 65, 45, 23, 80, 47, 144, - 0, 81, 81, 81, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 0, 0, - 6, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 9, 2, - 2, 2, 9, 2, 30, 2, 2, 2, 2, 2, 30, 2, 2, 2, 30, 9, - 0, 127, 20, 27, 31, 0, 0, 145, 146, 2, 2, 30, 2, 30, 2, 2, - 2, 2, 2, 2, 0, 14, 37, 0, 147, 2, 2, 13, 37, 0, 30, 2, - 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 2, 2, - 9, 2, 2, 11, 41, 0, 0, 0, 0, 2, 2, 2, 0, 27, 22, 22, - 30, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 27, 38, - 0, 2, 2, 2, 115, 115, 115, 115, 115, 148, 2, 9, 0, 0, 0, 0, - 0, 2, 14, 14, 0, 0, 0, 0, 0, 9, 2, 2, 9, 2, 2, 2, - 2, 30, 2, 9, 0, 30, 2, 0, 0, 149, 150, 151, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 22, 22, 20, 20, 20, 22, 22, 133, 0, 0, 0, - 0, 0, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 2, 2, 2, 2, - 2, 53, 52, 53, 0, 0, 0, 0, 153, 11, 74, 2, 2, 2, 2, 2, - 2, 18, 19, 21, 16, 24, 37, 0, 0, 0, 31, 0, 0, 0, 0, 0, - 0, 11, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 127, 20, 22, 154, - 22, 21, 155, 156, 2, 2, 2, 2, 2, 0, 0, 65, 157, 0, 0, 0, - 0, 2, 13, 0, 0, 0, 0, 0, 0, 2, 65, 25, 20, 20, 20, 22, - 22, 107, 158, 0, 0, 56, 159, 31, 160, 30, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 23, 19, 22, 22, 161, 44, 0, 0, 0, - 49, 127, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 9, 2, 2, - 30, 2, 2, 2, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, - 10, 18, 19, 21, 22, 162, 31, 0, 0, 11, 11, 30, 2, 2, 2, 9, - 30, 9, 2, 30, 2, 2, 58, 17, 23, 16, 23, 47, 32, 33, 32, 34, - 0, 0, 0, 0, 35, 0, 0, 0, 2, 2, 23, 0, 11, 11, 11, 46, - 0, 11, 11, 46, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 30, 0, - 9, 2, 2, 2, 30, 45, 59, 20, 20, 31, 33, 32, 32, 25, 163, 29, - 164, 165, 37, 0, 0, 0, 0, 0, 0, 12, 26, 0, 0, 0, 0, 0, - 0, 2, 2, 65, 25, 20, 20, 20, 22, 23, 125, 15, 17, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 0, 0, 166, 167, 0, 0, 0, 0, 0, 0, - 0, 18, 19, 20, 20, 66, 98, 25, 160, 11, 168, 9, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 65, 25, 20, 20, 0, 48, 48, 11, - 169, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20, - 0, 23, 19, 20, 20, 21, 16, 82, 169, 38, 0, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 10, 170, 25, 20, 22, 22, 168, 9, 0, 0, - 0, 2, 2, 2, 2, 2, 9, 43, 135, 23, 22, 20, 76, 21, 22, 0, - 0, 2, 2, 2, 9, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 18, - 19, 20, 21, 22, 104, 169, 37, 0, 0, 2, 2, 2, 9, 30, 0, 2, - 2, 2, 2, 30, 9, 2, 2, 2, 2, 23, 23, 18, 32, 33, 12, 171, - 165, 172, 173, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, - 2, 65, 25, 20, 20, 0, 22, 23, 29, 107, 0, 33, 0, 0, 0, 0, - 0, 52, 20, 22, 22, 22, 139, 2, 2, 2, 174, 140, 11, 15, 175, 61, - 176, 0, 0, 1, 147, 0, 0, 0, 0, 52, 20, 22, 16, 19, 20, 2, - 2, 2, 2, 158, 158, 158, 177, 177, 177, 177, 177, 177, 15, 178, 0, 30, - 0, 16, 20, 16, 16, 0, 0, 0, 0, 22, 20, 20, 31, 22, 22, 11, - 169, 0, 61, 61, 61, 61, 61, 61, 61, 66, 21, 82, 46, 0, 0, 0, - 0, 2, 2, 2, 9, 2, 30, 2, 2, 52, 22, 22, 31, 0, 38, 22, - 27, 11, 159, 179, 180, 0, 0, 0, 0, 2, 2, 2, 30, 9, 2, 2, - 2, 2, 2, 2, 2, 2, 23, 23, 47, 22, 35, 82, 68, 0, 0, 0, - 0, 2, 181, 66, 47, 0, 0, 0, 0, 11, 182, 2, 2, 2, 2, 2, - 2, 2, 2, 23, 22, 20, 31, 0, 48, 16, 143, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 156, 0, 0, 183, 183, 183, 183, 183, 183, 183, - 183, 184, 184, 184, 185, 186, 184, 183, 183, 187, 183, 183, 188, 189, 189, 189, - 189, 189, 189, 189, 0, 0, 0, 0, 0, 183, 183, 183, 183, 183, 190, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 191, 192, - 193, 11, 11, 11, 46, 0, 0, 0, 0, 29, 74, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 65, 47, 0, 2, 2, 2, 2, 2, 9, 0, - 58, 194, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 0, 0, 0, 40, 115, 26, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 30, 2, 2, 2, 2, 2, 0, 58, 37, 0, 6, 119, 119, 119, 120, 0, - 0, 11, 11, 11, 49, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 46, 2, 2, 2, 2, 2, 2, 11, - 11, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, - 20, 2, 2, 44, 44, 44, 92, 0, 0, O, O, O, GB, B, B, O, - SB, O, SE, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv, - VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, - VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, - VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, - VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, - MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS, - VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, - VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv, - VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, - VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv, - FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB, - CMAbv,CMAbv, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, - MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, - B, O,SMAbv,SMAbv,SMAbv, VPst, IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw, - VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, SB, SE, O, - H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, - MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, - B, VBlw,VMAbv, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, - IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, - IS,CMAbv, O, VPst, B, R, R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,VMPst, - O,VMAbv,CMBlw, IS, R,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, - VPst, MPst, R, MPst,CMBlw, B,FMBlw, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv, IS, VBlw, - IS, R, MBlw, GB, VAbv, R,VMPst, G, G, J, J, J, SB, SE, J, HR, - G, G, HM, HM, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 5, 2, 2, 2, 2, 6, 0, 2, 2, 2, 2, + 2, 5, 8, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, + 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, + 0, 2, 2, 2, 2, 5, 0, 0, 0, 2, 2, 2, 2, 2, 5, 0, + 0, 2, 8, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 74, 75, + 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 2, 2, 2, 2, 2, 2, 2, 17, 6, 13, 29, 33, 29, 45, + 0, 15, 11, 27, 7, 38, 7, 68, 0, 2, 2, 2, 2, 8, 2, 2, + 2, 10, 10, 10, 10, 80, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, + 5, 2, 2, 5, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, + 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 5, 2, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, + 0, 9, 41, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 23, 6, 6, 6, 6, 6, 6, 6, + 6, 0, 0, 0, 0, 0, 0, 48, 0, 44, 0, 0, 0, 0, 0, 49, + 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 103, 2, 2, 2, 2, 2, 36, 9, + 9, 9, 9, 0, 0, 0, 5, 31, 0, 2, 2, 2, 2, 50, 51, 0, + 0, 9, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 32, + 19, 17, 6, 18, 7, 15, 11, 67, 22, 31, 52, 25, 6, 2, 2, 2, + 2, 104, 14, 8, 2, 2, 2, 5, 8, 5, 5, 0, 2, 2, 0, 32, + 19, 0, 0, 0, 34, 0, 0, 2, 8, 2, 0, 0, 0, 0, 0, 5, + 105, 31, 24, 8, 2, 2, 5, 0, 8, 5, 2, 8, 5, 2, 0, 35, + 19, 17, 13, 0, 25, 38, 25, 68, 0, 53, 0, 0, 0, 8, 2, 5, + 5, 54, 39, 77, 0, 0, 0, 0, 0, 31, 24, 8, 2, 2, 2, 2, + 8, 5, 2, 8, 2, 2, 0, 32, 19, 17, 6, 18, 25, 7, 34, 67, + 0, 0, 0, 0, 0, 8, 54, 54, 46, 31, 14, 8, 2, 2, 2, 5, + 8, 5, 2, 8, 2, 2, 0, 32, 20, 0, 0, 25, 7, 0, 0, 2, + 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 26, 8, 2, 2, 5, 0, + 2, 5, 2, 2, 0, 8, 5, 5, 2, 0, 8, 5, 0, 2, 5, 0, + 2, 2, 2, 2, 2, 2, 0, 0, 11, 15, 27, 0, 12, 33, 12, 45, + 0, 0, 0, 0, 34, 0, 0, 0, 0, 24, 14, 55, 2, 2, 2, 5, + 2, 2, 2, 2, 2, 2, 0, 32, 7, 0, 0, 25, 13, 2, 5, 0, + 0, 36, 14, 8, 2, 2, 2, 5, 2, 2, 2, 8, 2, 2, 0, 32, + 20, 0, 0, 34, 27, 0, 0, 0, 5, 106, 78, 0, 0, 0, 0, 0, + 0, 9, 14, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 30, 40, + 11, 17, 6, 13, 12, 33, 12, 45, 107, 0, 0, 0, 34, 0, 0, 0, + 8, 31, 14, 8, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, + 2, 2, 8, 2, 2, 2, 2, 8, 0, 2, 2, 2, 5, 0, 108, 0, + 34, 11, 7, 13, 13, 19, 12, 12, 22, 0, 11, 0, 0, 0, 0, 0, + 0, 2, 0, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, + 0, 2, 2, 69, 69, 109, 0, 0, 19, 56, 18, 21, 7, 7, 6, 6, + 26, 18, 9, 13, 9, 2, 2, 79, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 81, 0, 0, 0, 0, 110, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 23, 20, 21, 57, 7, 7, 111, 82, 112, 113, + 83, 2, 2, 2, 2, 2, 48, 0, 44, 2, 2, 2, 11, 6, 2, 2, + 114, 83, 84, 41, 23, 84, 14, 14, 2, 30, 7, 40, 2, 2, 2, 2, + 2, 2, 115, 58, 116, 14, 14, 117, 85, 2, 2, 2, 2, 2, 14, 20, + 0, 2, 21, 59, 0, 0, 0, 0, 8, 2, 21, 27, 0, 0, 0, 0, + 0, 2, 21, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, + 2, 5, 21, 0, 0, 0, 0, 0, 0, 2, 2, 4, 20, 7, 21, 6, + 12, 12, 12, 12, 24, 60, 118, 119, 120, 121, 122, 0, 0, 0, 0, 123, + 0, 5, 0, 0, 8, 0, 124, 4, 125, 39, 39, 126, 86, 2, 2, 2, + 2, 2, 2, 2, 2, 50, 5, 0, 0, 7, 59, 20, 7, 127, 10, 0, + 0, 70, 128, 70, 70, 129, 130, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 2, 2, 14, 0, 0, 0, 2, 2, 2, 30, 71, 20, 0, + 0, 2, 2, 131, 132, 42, 133, 10, 81, 134, 15, 20, 7, 21, 18, 59, + 12, 12, 58, 9, 9, 9, 87, 26, 53, 9, 88, 41, 2, 2, 2, 2, + 2, 2, 2, 89, 7, 6, 6, 7, 12, 12, 7, 61, 2, 2, 2, 5, + 0, 0, 0, 0, 0, 0, 135, 62, 62, 62, 62, 0, 0, 0, 0, 0, + 0, 88, 41, 2, 2, 2, 2, 2, 2, 79, 10, 21, 22, 7, 136, 10, + 2, 2, 2, 2, 89, 7, 11, 20, 20, 42, 137, 0, 0, 0, 0, 0, + 0, 2, 2, 10, 19, 12, 11, 90, 42, 42, 42, 138, 139, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 0, 8, 2, 9, 26, 16, 16, 16, 9, 16, + 16, 24, 16, 16, 16, 52, 0, 53, 0, 0, 0, 140, 78, 9, 44, 0, + 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 49, 142, + 3, 39, 39, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, + 72, 0, 0, 91, 0, 0, 0, 0, 0, 0, 76, 91, 0, 0, 0, 0, + 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 0, 0, 0, 0, 63, 63, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, 143, 0, 63, 63, 0, 0, 0, 0, + 0, 2, 40, 2, 61, 2, 36, 2, 2, 2, 23, 17, 15, 0, 0, 13, + 0, 14, 2, 2, 2, 2, 2, 2, 2, 2, 2, 144, 11, 11, 11, 11, + 11, 11, 11, 92, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 2, 0, 0, 0, 0, 0, 30, 2, 2, 2, 7, 7, 145, 16, + 0, 2, 2, 2, 47, 6, 21, 6, 90, 42, 146, 0, 0, 0, 0, 0, + 0, 9, 147, 2, 2, 2, 2, 2, 2, 2, 148, 11, 7, 6, 12, 149, + 150, 93, 0, 0, 0, 0, 0, 0, 0, 2, 2, 30, 8, 2, 2, 2, + 2, 2, 2, 2, 2, 36, 7, 21, 71, 58, 151, 94, 152, 0, 0, 0, + 0, 2, 153, 2, 2, 2, 2, 154, 0, 8, 2, 39, 44, 0, 85, 24, + 2, 73, 6, 40, 47, 73, 2, 2, 95, 36, 5, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 155, 18, 22, 0, 0, 156, 96, 0, 0, 0, + 0, 2, 23, 20, 11, 59, 27, 157, 0, 0, 0, 0, 0, 0, 0, 0, + 49, 3, 3, 3, 3, 72, 0, 0, 0, 2, 5, 2, 8, 2, 2, 2, + 2, 2, 8, 2, 2, 2, 8, 5, 0, 47, 6, 25, 13, 0, 0, 158, + 159, 2, 2, 8, 2, 8, 2, 2, 2, 2, 2, 2, 0, 51, 35, 0, + 97, 2, 2, 50, 35, 0, 8, 2, 2, 0, 0, 0, 0, 8, 2, 2, + 5, 2, 2, 9, 54, 0, 0, 0, 0, 2, 2, 2, 0, 25, 7, 7, + 8, 2, 2, 2, 2, 2, 25, 38, 0, 2, 2, 2, 16, 16, 16, 16, + 16, 160, 2, 5, 0, 0, 0, 0, 0, 2, 51, 51, 0, 0, 0, 0, + 0, 5, 2, 2, 5, 2, 2, 2, 2, 8, 2, 5, 0, 8, 2, 0, + 0, 161, 162, 163, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 6, + 6, 6, 7, 7, 93, 0, 0, 0, 0, 0, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 2, 2, 2, 2, 2, 40, 30, 40, 0, 0, 0, 0, + 164, 19, 17, 18, 15, 67, 35, 0, 0, 0, 13, 0, 0, 0, 0, 0, + 0, 9, 55, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 6, 7, 165, + 7, 18, 166, 98, 2, 2, 2, 2, 2, 0, 0, 23, 167, 0, 0, 0, + 0, 2, 50, 0, 0, 0, 0, 0, 0, 2, 23, 22, 6, 6, 6, 7, + 7, 61, 64, 0, 0, 69, 99, 13, 100, 2, 2, 2, 2, 2, 2, 11, + 17, 7, 7, 168, 46, 0, 0, 0, 55, 47, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 5, 5, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, + 8, 2, 2, 2, 2, 2, 2, 2, 36, 19, 17, 18, 7, 169, 13, 0, + 0, 9, 9, 8, 2, 2, 2, 5, 8, 5, 2, 8, 2, 2, 56, 32, + 11, 15, 11, 27, 29, 33, 29, 45, 0, 0, 0, 0, 34, 0, 0, 0, + 2, 2, 11, 0, 9, 9, 9, 26, 0, 9, 9, 26, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 8, 0, 5, 2, 2, 2, 8, 20, 21, 6, + 6, 13, 33, 29, 29, 22, 170, 14, 171, 101, 35, 0, 0, 0, 0, 0, + 0, 31, 52, 0, 0, 0, 0, 0, 0, 2, 2, 23, 22, 6, 6, 6, + 7, 11, 92, 24, 32, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, + 172, 173, 0, 0, 0, 0, 0, 0, 0, 19, 17, 6, 6, 57, 71, 22, + 100, 9, 102, 5, 0, 0, 0, 0, 0, 22, 6, 6, 0, 12, 12, 9, + 65, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 6, + 0, 11, 17, 6, 6, 18, 15, 60, 65, 38, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 36, 174, 22, 6, 7, 7, 102, 5, 0, 0, + 0, 2, 2, 2, 2, 2, 5, 77, 94, 11, 7, 6, 58, 18, 7, 0, + 0, 2, 2, 2, 5, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 19, + 17, 6, 18, 7, 87, 65, 35, 0, 0, 2, 2, 2, 5, 8, 0, 2, + 2, 2, 2, 8, 5, 2, 2, 2, 2, 11, 11, 19, 29, 33, 31, 175, + 101, 176, 177, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, + 2, 23, 22, 6, 6, 0, 7, 11, 14, 61, 0, 33, 0, 0, 0, 0, + 0, 30, 6, 7, 7, 7, 73, 2, 2, 2, 178, 95, 9, 24, 179, 10, + 180, 0, 0, 48, 97, 0, 0, 0, 0, 30, 6, 7, 15, 17, 6, 2, + 2, 2, 2, 64, 64, 64, 43, 43, 43, 43, 43, 43, 24, 181, 0, 8, + 0, 15, 6, 15, 15, 0, 0, 0, 0, 7, 6, 6, 13, 7, 7, 9, + 65, 0, 10, 10, 10, 10, 10, 10, 10, 57, 18, 60, 26, 0, 0, 0, + 0, 2, 2, 2, 5, 2, 8, 2, 2, 30, 7, 7, 13, 0, 38, 7, + 25, 9, 99, 182, 183, 0, 0, 0, 0, 2, 2, 2, 8, 5, 2, 2, + 2, 2, 2, 2, 2, 2, 11, 11, 27, 7, 34, 60, 82, 0, 0, 0, + 0, 2, 184, 57, 27, 0, 0, 0, 0, 9, 185, 2, 2, 2, 2, 2, + 2, 2, 2, 11, 7, 6, 13, 0, 12, 15, 96, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 98, 0, 0, 66, 66, 66, 186, 187, 66, 1, + 1, 188, 1, 1, 189, 37, 37, 37, 37, 37, 37, 37, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 190, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 191, 192, 193, 9, 9, 9, 26, 0, 0, 0, + 0, 14, 41, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 27, + 0, 2, 2, 2, 2, 2, 5, 0, 56, 194, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 0, 0, 0, 53, 16, 52, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 2, 2, 2, 2, 2, 0, 56, 35, 0, 49, 3, 3, 3, 72, 0, + 0, 9, 9, 9, 55, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 9, + 9, 2, 2, 2, 2, 2, 2, 7, 7, 2, 2, 2, 2, 2, 2, 2, + 6, 2, 2, 46, 46, 46, 86, 0, 0, O, O, G, G, B, B, WJ, + WJ, CGJ, CGJ, B, O, VBlw, VBlw, VAbv, VAbv, O, B,VMAbv,VMAbv, SUB, SUB, VPst, + VPst, VPre, VPre, VBlw, O,VMPst,VMPst, VAbv, VPst,VMBlw,VMBlw, VPst, VBlw, VBlw, VAbv, VPst, + VPre, VPst, VAbv, VAbv, VBlw, VPre, VPst, B, VPst,VMAbv,VMPst, O, VAbv,VMAbv, O, VPst, + O, N, N, O, VPre, B, VAbv, O,VMAbv,CMBlw, B, VPre, O, O, VPst,CMBlw, + O, B,VMAbv, HM, HM, VAbv, O, GB, GB, VAbv, B,VMPst, B, FAbv, FAbv, FBlw, + FBlw, GB, O, VPre, H,CMAbv,CMAbv, B, VBlw, O, GB, O, WJ, B,CMBlw,CMBlw, + CMBlw,VMBlw, O, O,VMBlw,VMAbv,CMAbv,VMAbv, B, O,CMBlw, VBlw, VPre, VPre, VAbv, VBlw, + VPst, VPst,VMAbv, H, B,SMAbv,SMAbv, SB, SE, R, R,VMPst, H, J, J, VPst, + H, VAbv, H, O,FMBlw, FPst, FPst, VAbv, VPre, WJ, O, VBlw, B, O, SB, O, + SE,FMPst,FMPst, O, MBlw, CS,VMPst, B, SUB, O, SUB, SUB, O,VMPst, IS, MBlw, + B, VPst,VMPst, B,VMPst,CMAbv, B, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, VBlw, FAbv,FMPst, + O, H,VMAbv, H, O, MPre, MAbv, VBlw,VMAbv, IS, O, O, IS,CMAbv, O,CMBlw, + VAbv, VPre,VMAbv, IS, R, H,CMBlw, O, CGJ, GB,VMAbv,FMAbv, O, O, CS, R, + O, HVM, O, O,CMAbv,FMBlw, O,VMAbv,VMBlw, VAbv, MPst, MPre, MBlw, MBlw, MBlw, MBlw, + VPst, VAbv,VMPst,VMPst,VMBlw,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B, + FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv, VAbv, SUB,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, B, + MPre, MBlw, SUB, MAbv, SUB, Sk, VPst, O,SMAbv, VPst, IS, RK, RK,VMPre,VMPre,FMAbv, + CMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, O, H, MPst, VPst, VAbv,VMBlw, FPst, VPst, FAbv, + VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, VBlw, MPst, MBlw, O, B, FAbv, FAbv, FPst, B, + VPre, O,VMPst,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, + B, O, HN, VPre, VBlw, VAbv, IS, VPst, B,VMAbv, H, VAbv,CMBlw,VMPst, O,VMAbv, + CMBlw,FMAbv, B, CS, CS,VMPst, VAbv,VMAbv, VPst, MPst, R, MPst,CMBlw, B,FMBlw, CS, + SUB, SUB, GB,CMAbv, IS, VBlw, IS, R, MBlw, GB, VAbv, R,VMPst, J, SB, SE, + J, HR, G, G, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw, }; static const uint16_t hb_use_u16[864]= { - 0, 0, 1, 2, 0, 3, 0, 3, 0, 0, 4, 5, 0, 6, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, - 0, 0, 0, 0, 10, 13, 0, 0, 14, 10, 10, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 18, 26, 27, 21, 22, 28, 29, 30, 31, 32, - 33, 34, 22, 35, 36, 0, 18, 37, 38, 21, 22, 39, 24, 40, 18, 41, - 42, 43, 44, 45, 46, 47, 31, 0, 48, 49, 22, 50, 51, 52, 18, 0, - 53, 49, 22, 54, 51, 55, 18, 56, 57, 49, 10, 58, 59, 60, 18, 0, - 61, 62, 10, 63, 64, 65, 31, 66, 67, 68, 10, 69, 70, 10, 71, 72, - 73, 74, 75, 76, 77, 0, 0, 0, 10, 10, 78, 79, 80, 81, 82, 83, - 84, 85, 0, 0, 0, 0, 0, 0, 10, 86, 10, 87, 10, 88, 89, 90, - 10, 10, 10, 91, 92, 93, 2, 0, 94, 0, 10, 10, 10, 10, 10, 95, - 96, 10, 97, 0, 0, 0, 0, 0, 10, 98, 99,100, 31, 10,101,102, - 10, 10,103, 10,104,105, 0, 0, 10,106, 10, 10, 10,107,108,109, - 2, 2, 0, 0, 0, 0, 0, 0,110, 10, 10,111,112, 2,113,114, - 115, 10,116, 10, 10, 10,117,118, 10, 10,119,120,121, 0, 0, 0, - 0, 0, 0, 0, 0,122,123,124, 0, 0, 0, 0, 0, 0, 0,125, - 126,127,128, 0, 0, 0,129,130,131, 0, 0, 0, 0, 0, 0,132, - 0, 0, 0, 0,133, 0, 0, 0, 0, 0, 0, 0, 0, 0,134, 0, - 0, 0, 0, 10, 10, 10,135,136, 0, 0,137, 0, 0, 0, 0, 0, - 138, 10,139, 0, 10, 10, 10,140,141, 10, 10,142,143, 2,144,145, - 10, 10,146, 10,147,148, 0, 0,149, 10, 10,150,151, 2,152, 98, - 10, 10,153,154,155, 2, 10,156, 10, 10, 10,157,158, 0,159,160, - 0, 0, 0, 0, 10, 10,161, 2,162, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 0, 0, 0, 0, 0,164, - 0, 0, 0, 0, 0, 0, 0,165,165,166, 34,167, 0, 0, 0, 0, - 168,169, 10,170, 95, 0, 0, 0, 0, 0, 0, 0, 70, 10,171, 0, - 10,172,173, 0, 0, 0, 0, 0, 10, 10,174, 2, 9, 10,175, 10, - 176, 0, 0, 0, 0, 0, 0, 0, 10, 10,177,172, 0, 0, 0, 0, - 0, 0, 0, 10,178,179, 0, 10,180, 0, 0,181,182, 0, 0, 0, - 183, 10, 10,184,185,186,187,188,189, 10, 10,190,191, 0, 0, 0, - 192, 10,193,194,195, 10, 10,196,189, 10, 10,197,198,105,199,102, - 10, 34,200,201,202, 0, 0, 0,203,204, 95, 10, 10,205,206, 2, - 207, 21, 22,208,209,210,211,212,213, 10, 10,214,215,216,217, 0, - 10, 10, 10,218,219,220,221, 0,199, 10, 10,222,223, 2, 0, 0, - 10, 10,224,225,226,227, 0, 0, 10, 10, 10,228,229, 2, 0, 0, - 10, 10,230,231, 2, 10,140, 0, 10,232,233,103,234, 0, 0, 0, - 10, 10,235,236, 0, 0, 0, 0,237,238, 10,239,240, 2, 0, 0, - 0, 0,241, 10, 10,242,243, 0,244, 10, 10,245,246,247, 10, 10, - 248,249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,250, 0, - 22, 10,224,251, 8, 10, 71, 19, 10,252, 74,253, 0, 0, 0, 0, - 254, 10, 10,255,256, 2,257, 10,258,259, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 10,260,261, 49, 10,262,263,264, 0, 0, - 265,265,265,265,265,265,265,265,265,265,265,266,267,268,265,265, - 265,265,265,265,265,265,265,269, 10,270,271, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 0, 0, 0, 10, 10, 10,272, 0, 0, 0, 0, - 0, 0, 0, 0,273, 10,274, 2, 10, 10, 10, 10,275,276,277,277, - 278,279, 0, 0, 0, 0,280, 0, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10,176, 0,281, 10, 10, 10, 10, 10, 10,105, 71, - 95,282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,283, - 10, 10, 71,284,285, 0, 0, 0, 0, 10,286, 0, 10, 10,287, 2, - 0, 0, 0, 0, 0, 10,288, 2, 0, 0, 0, 0, 0, 10,289,105, - 10, 10, 10, 10,290, 2, 0, 0,129,129,129,129,129,129,129,129, - 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,129, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 0, 0, 272, 32, 0, 120, 0, 120, 0, 0, 280, 288, 0, 296, 0, 0, + 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, + 0, 0, 0, 0, 136, 24, 312, 320, 0, 0, 0, 0, 24, 328, 0, 0, + 336, 24, 24, 344, 352, 360, 56, 144, 368, 64, 48, 376, 152, 384, 56, 392, + 400, 64, 48, 408, 416, 424, 72, 432, 440, 112, 48, 448, 456, 0, 56, 464, + 472, 64, 48, 480, 152, 488, 56, 496, 504, 512, 520, 528, 536, 544, 72, 0, + 552, 80, 48, 560, 160, 568, 56, 0, 576, 80, 48, 584, 160, 592, 56, 600, + 608, 80, 24, 616, 624, 632, 56, 0, 640, 648, 24, 656, 664, 672, 72, 680, + 688, 696, 24, 704, 168, 24, 88, 712, 720, 176, 728, 736, 744, 0, 0, 0, + 24, 24, 752, 760, 768, 776, 784, 792, 800, 808, 0, 0, 0, 0, 0, 0, + 24, 816, 24, 824, 24, 832, 840, 848, 24, 24, 24, 856, 864, 872, 32, 0, + 880, 0, 24, 24, 24, 24, 24, 96, 888, 24, 896, 0, 0, 0, 0, 0, + 24, 184, 904, 912, 72, 24, 920, 192, 24, 24, 200, 24, 928, 104, 0, 0, + 24, 936, 24, 24, 24, 944, 952, 960, 32, 32, 0, 0, 0, 0, 0, 0, + 968, 24, 24, 976, 984, 32, 992,1000,1008, 24,1016, 24, 24, 24,1024,1032, + 24, 24,1040,1048,1056, 0, 0, 0, 0, 0, 0, 0, 0,1064,1072,1080, + 0, 0, 0, 0, 0, 0, 0,1088,1096,1104,1112, 0, 0, 0, 16,1120, + 1128, 0, 0, 0, 0, 0, 0,1136, 0, 0, 0, 0,1144, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1152, 0, 0, 0, 0, 24, 24, 24,1160,1168, + 0, 0,1176, 0, 0, 0, 0, 0,1184, 24,1192, 0, 24, 24, 24, 208, + 1200, 24, 24,1208,1216, 32,1224,1232, 24, 24,1240, 24,1248,1256, 0, 0, + 1264, 24, 24,1272,1280, 32,1288, 184, 24, 24,1296,1304,1312, 32, 24,1320, + 24, 24, 24,1328,1336, 0,1344,1352, 0, 0, 0, 0, 24, 24,1360, 32, + 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1368, + 0, 0, 0, 0, 0, 0, 0,1376, 0, 0, 0, 0, 0, 0, 0, 216, + 216,1384, 112,1392, 0, 0, 0, 0,1400,1408, 24,1416, 96, 0, 0, 0, + 0, 0, 0, 0, 168, 24,1424, 0, 24, 224,1432, 0, 0, 0, 0, 0, + 24, 24,1440, 32, 136, 24,1448, 24, 232, 0, 0, 0, 0, 0, 0, 0, + 24, 24,1456, 224, 0, 0, 0, 0, 0, 0, 0, 24,1464,1472, 0, 24, + 1480, 0, 0,1488,1496, 0, 0, 0,1504, 24, 24,1512,1520,1528,1536,1544, + 240, 24, 24,1552,1560, 0, 0, 0,1568, 24,1576,1584,1592, 24, 24,1600, + 240, 24, 24,1608,1616, 104, 248, 192, 24, 112,1624,1632,1640, 0, 0, 0, + 1648,1656, 96, 24, 24,1664,1672, 32,1680, 64, 48,1688,1696,1704,1712,1720, + 1728, 24, 24,1736,1744,1752,1760, 0, 24, 24, 24,1768,1776,1784,1792, 0, + 248, 24, 24,1800,1808, 32, 0, 0, 24, 24, 256,1816,1824,1832, 0, 0, + 24, 24, 24,1840,1848, 32, 0, 0, 24, 24,1856,1864, 32, 24, 208, 0, + 24,1872,1880, 200,1888, 0, 0, 0, 24, 24,1896,1904, 0, 0, 0, 0, + 1912,1920, 24,1928,1936, 32, 0, 0, 0, 0,1944, 24, 24,1952,1960, 0, + 1968, 24, 24,1976,1984,1992, 24, 24,2000,2008, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,2016, 0, 48, 24, 256,2024, 128, 24, 88, 144, + 24,2032, 176,2040, 0, 0, 0, 0,2048, 24, 24,2056,2064, 32,2072, 24, + 2080,2088, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24,2096, + 2104, 80, 24,2112,2120,2128, 0, 0, 8, 8, 8,2136,2144,2152, 8, 8, + 8, 8, 8, 8, 8, 8, 8,2160, 24,2168,2176, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 0, 0, 0, 24, 24, 24,2184, 0, 0, 0, 0, + 0, 0, 0, 0,2192, 24,2200, 32, 24, 24, 24, 24,2208,2216, 264, 264, + 2224,2232, 0, 0, 0, 0,2240, 0, 24, 24, 24, 24, 24, 232, 0,2248, + 24, 24, 24, 24, 24, 24, 104, 88, 96,2256, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,2264, 24, 24, 88,2272,2280, 0, 0, 0, + 0, 24,2288, 0, 24, 24,2296, 32, 0, 0, 0, 0, 0, 24,2304, 32, + 0, 0, 0, 0, 0, 24,2312, 104, 24, 24, 24, 24,2320, 32, 0, 0, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 16, }; static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i) @@ -379,7 +379,8 @@ static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i) } static inline uint8_t hb_use_get_category (unsigned u) { - return u<921600 ? hb_use_u8[2953u+((hb_use_u8[625u+((hb_use_u16[((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((u)>>1))>>3))>>3))>>5)))<<5)+((((((((u)>>1))>>3))>>3))&31)])<<3)+((((((u)>>1))>>3))&7)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : O; + /* packtab: [2^4,2^5,2^3,2^3,2^1] */ + return u<921600u ? (uint8_t)(hb_use_u8[2953u+((hb_use_u8[625u+hb_use_u16[((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((u)>>1))>>3))>>3))>>5)))<<5)+((((((((u)>>1))>>3))>>3))&31)])<<3)+((((((u)>>1))>>3))&7)]+((((u)>>1))&7)])<<1)+((u)&1)]) : O; } @@ -389,269 +390,269 @@ static inline uint8_t hb_use_get_category (unsigned u) static const uint8_t hb_use_u8[3663]= { - 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 57, 58, 59, 195, 211, 62, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 15, 0, 1, 1, 2, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 1, - 11, 12, 1, 1, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 19, 1, - 1, 20, 1, 1, 1, 1, 21, 1, 22, 1, 1, 1, 1, 1, 23, 24, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 26, 27, 28, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 29, - 30, 1, 1, 1, 1, 1, 31, 1, 1, 1, 1, 32, 33, 1, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 53, 53, 53, 54, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 56, 1, 1, 1, 1, 1, 1, 1, 1, 57, 58, 1, 59, 1, - 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 61, 62, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 63, 1, 1, - 1, 1, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 65, 66, 1, 67, 68, 1, 1, 1, 69, 1, 1, 1, 1, 1, - 1, 70, 71, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 0, 1, 2, 2, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 9, 0, 0, 0, 0, - 0, 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, 37, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 0, 56, 57, 58, 59, 60, 0, 0, 0, 61, 62, 63, 64, 56, 65, 66, - 67, 68, 56, 56, 69, 70, 71, 0, 0, 72, 73, 74, 75, 56, 76, 77, - 0, 78, 56, 79, 80, 81, 0, 0, 0, 82, 83, 84, 85, 86, 87, 56, - 88, 56, 89, 90, 0, 0, 0, 91, 92, 0, 0, 0, 0, 0, 0, 0, - 93, 94, 95, 0, 96, 97, 0, 0, 98, 0, 0, 0, 0, 0, 0, 99, - 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 101, 56, 102, 0, 0, 0, - 0, 0, 103, 0, 0, 0, 0, 0, 0, 104, 105, 56, 106, 107, 108, 109, - 110, 56, 111, 112, 0, 113, 114, 115, 116, 56, 117, 118, 119, 56, 120, 121, - 122, 0, 0, 0, 0, 0, 0, 56, 123, 124, 0, 0, 0, 0, 0, 0, - 125, 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 127, 128, 129, 0, - 0, 130, 131, 132, 0, 0, 0, 51, 133, 0, 0, 0, 0, 134, 135, 0, - 0, 56, 136, 7, 137, 138, 0, 0, 0, 0, 0, 0, 0, 56, 139, 0, - 0, 0, 101, 140, 101, 141, 142, 143, 0, 144, 145, 146, 147, 148, 149, 150, - 0, 151, 152, 153, 154, 148, 155, 156, 157, 158, 159, 160, 0, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 56, 173, 174, 175, 176, 177, 178, - 0, 0, 0, 0, 0, 56, 179, 180, 0, 56, 181, 182, 0, 56, 183, 184, - 185, 186, 187, 188, 0, 0, 0, 0, 0, 56, 189, 0, 0, 0, 0, 0, - 0, 190, 191, 192, 0, 0, 193, 194, 195, 196, 197, 198, 56, 199, 0, 0, - 0, 0, 0, 0, 200, 0, 0, 0, 0, 201, 202, 203, 204, 205, 206, 0, - 0, 207, 208, 209, 210, 211, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 212, 213, 214, 215, 0, 0, 0, 0, 0, 216, 216, 216, 216, 216, 216, 216, - 216, 216, 217, 218, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, - 219, 220, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, - 0, 56, 222, 0, 0, 0, 0, 0, 0, 0, 0, 223, 224, 0, 0, 0, - 0, 56, 56, 225, 226, 227, 0, 0, 228, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 229, 230, 56, 56, 56, 231, 232, 0, 0, - 0, 0, 0, 0, 233, 0, 0, 0, 0, 56, 234, 235, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 101, 236, 56, 237, 0, 0, 0, 0, 0, 0, 101, - 238, 0, 0, 0, 0, 0, 0, 101, 239, 56, 56, 240, 0, 0, 0, 0, - 0, 241, 241, 241, 241, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, - 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, - 0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 7, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 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, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 11, - 11, 11, 11, 0, 0, 0, 9, 12, 0, 2, 2, 2, 2, 13, 14, 0, - 0, 11, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 17, - 18, 19, 20, 21, 22, 16, 23, 24, 25, 12, 26, 27, 20, 2, 2, 2, - 2, 2, 20, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, - 2, 28, 29, 30, 2, 2, 2, 9, 30, 9, 30, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 9, 0, 2, 2, 0, 17, - 18, 19, 20, 31, 32, 33, 32, 34, 0, 0, 0, 0, 35, 0, 0, 2, - 30, 2, 0, 0, 0, 0, 0, 9, 36, 12, 15, 30, 2, 2, 9, 0, - 30, 9, 2, 30, 9, 2, 0, 37, 18, 19, 31, 0, 27, 38, 27, 39, - 0, 40, 0, 0, 0, 30, 2, 9, 9, 0, 0, 0, 2, 2, 2, 2, - 2, 41, 42, 43, 0, 0, 0, 0, 0, 12, 15, 30, 2, 2, 2, 2, - 30, 2, 30, 2, 2, 2, 2, 2, 2, 9, 2, 30, 2, 2, 0, 17, - 18, 19, 20, 21, 27, 22, 35, 24, 0, 0, 0, 0, 0, 30, 41, 41, - 44, 12, 29, 30, 2, 2, 2, 9, 30, 9, 2, 30, 2, 2, 0, 17, - 45, 0, 0, 27, 22, 0, 0, 2, 30, 30, 0, 0, 0, 0, 0, 0, - 0, 0, 46, 30, 2, 2, 9, 0, 2, 9, 2, 2, 0, 30, 9, 9, - 2, 0, 30, 9, 0, 2, 9, 0, 2, 2, 2, 2, 2, 2, 0, 0, - 23, 16, 47, 0, 48, 33, 48, 34, 0, 0, 0, 0, 35, 0, 0, 0, - 0, 15, 29, 49, 2, 2, 2, 9, 2, 9, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 0, 17, 22, 16, 23, 47, 22, 38, 22, 39, - 0, 0, 0, 27, 31, 2, 9, 0, 0, 10, 29, 30, 2, 2, 2, 9, - 2, 2, 2, 30, 2, 2, 0, 17, 45, 0, 0, 35, 47, 0, 0, 0, - 9, 50, 51, 0, 0, 0, 0, 0, 0, 11, 29, 2, 2, 2, 2, 9, - 2, 2, 2, 2, 2, 2, 52, 53, 23, 19, 20, 31, 48, 33, 48, 34, - 54, 0, 0, 0, 35, 0, 0, 0, 30, 12, 29, 30, 2, 2, 2, 2, - 2, 2, 2, 2, 9, 0, 2, 2, 2, 2, 30, 2, 2, 2, 2, 30, - 0, 2, 2, 2, 9, 0, 55, 0, 35, 23, 22, 31, 31, 18, 48, 48, - 25, 0, 23, 0, 0, 0, 0, 0, 0, 2, 0, 2, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 2, 56, 56, 57, 0, 0, - 18, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, - 0, 58, 21, 59, 22, 22, 20, 20, 46, 21, 11, 31, 11, 2, 2, 60, - 61, 61, 61, 61, 61, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 63, 0, 0, 0, 0, 64, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 65, 45, 59, 66, 22, 22, 67, 68, 69, 70, - 71, 2, 2, 2, 2, 2, 1, 0, 5, 2, 2, 2, 23, 20, 2, 2, - 72, 71, 73, 74, 65, 73, 29, 29, 2, 52, 22, 53, 2, 2, 2, 2, - 2, 2, 75, 76, 77, 29, 29, 78, 79, 2, 2, 2, 2, 2, 29, 45, - 0, 2, 59, 80, 0, 0, 0, 0, 30, 2, 59, 47, 0, 0, 0, 0, - 0, 2, 59, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 9, - 2, 9, 59, 0, 0, 0, 0, 0, 0, 2, 2, 81, 45, 22, 59, 20, - 48, 48, 48, 48, 15, 82, 83, 84, 85, 86, 87, 0, 0, 0, 0, 88, - 0, 9, 0, 0, 30, 0, 89, 81, 90, 2, 2, 2, 2, 9, 0, 0, - 0, 42, 42, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 13, 9, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 9, 22, 80, 45, 22, 93, 61, 0, - 0, 94, 95, 94, 94, 96, 97, 0, 0, 2, 2, 2, 2, 2, 2, 2, - 0, 2, 2, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, - 0, 2, 2, 2, 2, 29, 0, 0, 0, 2, 2, 2, 2, 2, 9, 0, - 0, 2, 2, 2, 52, 98, 45, 0, 0, 2, 2, 99, 100, 101, 102, 61, - 63, 103, 16, 45, 22, 59, 21, 80, 48, 48, 76, 11, 11, 11, 104, 46, - 40, 11, 105, 74, 2, 2, 2, 2, 2, 2, 2, 106, 22, 20, 20, 22, - 48, 48, 22, 107, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 108, 109, - 109, 109, 109, 0, 0, 0, 0, 0, 0, 105, 74, 2, 2, 2, 2, 2, - 2, 60, 61, 59, 25, 22, 110, 61, 2, 2, 2, 2, 106, 22, 23, 45, - 45, 101, 111, 0, 0, 0, 0, 0, 0, 2, 2, 61, 18, 48, 23, 112, - 101, 101, 101, 113, 114, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 30, - 2, 11, 46, 115, 115, 115, 11, 115, 115, 15, 115, 115, 115, 26, 0, 40, - 0, 0, 0, 116, 51, 11, 5, 0, 0, 0, 0, 0, 0, 0, 117, 0, - 0, 0, 0, 0, 0, 0, 6, 118, 119, 42, 42, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119, - 119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 7, 121, 0, 0, 0, 0, - 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, - 0, 0, 0, 0, 122, 122, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, - 30, 0, 0, 0, 0, 0, 0, 0, 123, 0, 122, 122, 0, 0, 0, 0, - 0, 2, 53, 2, 107, 2, 10, 2, 2, 2, 65, 19, 16, 0, 0, 31, - 0, 2, 2, 0, 0, 0, 0, 0, 0, 29, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 124, 23, 23, 23, 23, 23, 23, 23, 125, 0, 0, 0, 0, - 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 0, 0, 0, 0, 0, - 52, 2, 2, 2, 22, 22, 126, 115, 0, 2, 2, 2, 127, 20, 59, 20, - 112, 101, 128, 0, 0, 0, 0, 0, 0, 11, 129, 2, 2, 2, 2, 2, - 2, 2, 130, 23, 22, 20, 48, 131, 132, 133, 0, 0, 0, 0, 0, 0, - 0, 2, 2, 52, 30, 2, 2, 2, 2, 2, 2, 2, 2, 10, 22, 59, - 98, 76, 134, 135, 136, 0, 0, 0, 0, 2, 137, 2, 2, 2, 2, 138, - 0, 30, 2, 42, 5, 0, 79, 15, 2, 139, 20, 53, 127, 139, 2, 2, - 140, 10, 9, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 141, 21, - 25, 0, 0, 142, 143, 0, 0, 0, 0, 2, 65, 45, 23, 80, 47, 144, - 0, 81, 81, 81, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 0, 0, - 6, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 9, 2, - 2, 2, 9, 2, 30, 2, 2, 2, 2, 2, 30, 2, 2, 2, 30, 9, - 0, 127, 20, 27, 31, 0, 0, 145, 146, 2, 2, 30, 2, 30, 2, 2, - 2, 2, 2, 2, 0, 14, 37, 0, 147, 2, 2, 13, 37, 0, 30, 2, - 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 2, 2, - 9, 2, 2, 11, 41, 0, 0, 0, 0, 2, 2, 2, 0, 27, 22, 22, - 30, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 27, 38, - 0, 2, 2, 2, 115, 115, 115, 115, 115, 148, 2, 9, 0, 0, 0, 0, - 0, 2, 14, 14, 0, 0, 0, 0, 0, 9, 2, 2, 9, 2, 2, 2, - 2, 30, 2, 9, 0, 30, 2, 0, 0, 149, 150, 151, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 22, 22, 20, 20, 20, 22, 22, 133, 0, 0, 0, - 0, 0, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 2, 2, 2, 2, - 2, 53, 52, 53, 0, 0, 0, 0, 153, 11, 74, 2, 2, 2, 2, 2, - 2, 18, 19, 21, 16, 24, 37, 0, 0, 0, 31, 0, 0, 0, 0, 0, - 0, 11, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 127, 20, 22, 154, - 22, 21, 155, 156, 2, 2, 2, 2, 2, 0, 0, 65, 157, 0, 0, 0, - 0, 2, 13, 0, 0, 0, 0, 0, 0, 2, 65, 25, 20, 20, 20, 22, - 22, 107, 158, 0, 0, 56, 159, 31, 160, 30, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 23, 19, 22, 22, 161, 44, 0, 0, 0, - 49, 127, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 9, 2, 2, - 30, 2, 2, 2, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, - 10, 18, 19, 21, 22, 162, 31, 0, 0, 11, 11, 30, 2, 2, 2, 9, - 30, 9, 2, 30, 2, 2, 58, 17, 23, 16, 23, 47, 32, 33, 32, 34, - 0, 0, 0, 0, 35, 0, 0, 0, 2, 2, 23, 0, 11, 11, 11, 46, - 0, 11, 11, 46, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 30, 0, - 9, 2, 2, 2, 30, 45, 59, 20, 20, 31, 33, 32, 32, 25, 163, 29, - 164, 165, 37, 0, 0, 0, 0, 0, 0, 12, 26, 0, 0, 0, 0, 0, - 0, 2, 2, 65, 25, 20, 20, 20, 22, 23, 125, 15, 17, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 0, 0, 166, 167, 0, 0, 0, 0, 0, 0, - 0, 18, 19, 20, 20, 66, 98, 25, 160, 11, 168, 9, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 65, 25, 20, 20, 0, 48, 48, 11, - 169, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20, - 0, 23, 19, 20, 20, 21, 16, 82, 169, 38, 0, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 10, 170, 25, 20, 22, 22, 168, 9, 0, 0, - 0, 2, 2, 2, 2, 2, 9, 43, 135, 23, 22, 20, 76, 21, 22, 0, - 0, 2, 2, 2, 9, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 18, - 19, 20, 21, 22, 104, 169, 37, 0, 0, 2, 2, 2, 9, 30, 0, 2, - 2, 2, 2, 30, 9, 2, 2, 2, 2, 23, 23, 18, 32, 33, 12, 171, - 165, 172, 173, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, - 2, 65, 25, 20, 20, 0, 22, 23, 29, 107, 0, 33, 0, 0, 0, 0, - 0, 52, 20, 22, 22, 22, 139, 2, 2, 2, 174, 140, 11, 15, 175, 61, - 176, 0, 0, 1, 147, 0, 0, 0, 0, 52, 20, 22, 16, 19, 20, 2, - 2, 2, 2, 158, 158, 158, 177, 177, 177, 177, 177, 177, 15, 178, 0, 30, - 0, 16, 20, 16, 16, 0, 0, 0, 0, 22, 20, 20, 31, 22, 22, 11, - 169, 0, 61, 61, 61, 61, 61, 61, 61, 66, 21, 82, 46, 0, 0, 0, - 0, 2, 2, 2, 9, 2, 30, 2, 2, 52, 22, 22, 31, 0, 38, 22, - 27, 11, 159, 179, 180, 0, 0, 0, 0, 2, 2, 2, 30, 9, 2, 2, - 2, 2, 2, 2, 2, 2, 23, 23, 47, 22, 35, 82, 68, 0, 0, 0, - 0, 2, 181, 66, 47, 0, 0, 0, 0, 11, 182, 2, 2, 2, 2, 2, - 2, 2, 2, 23, 22, 20, 31, 0, 48, 16, 143, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 156, 0, 0, 183, 183, 183, 183, 183, 183, 183, - 183, 184, 184, 184, 185, 186, 184, 183, 183, 187, 183, 183, 188, 189, 189, 189, - 189, 189, 189, 189, 0, 0, 0, 0, 0, 183, 183, 183, 183, 183, 190, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 191, 192, - 193, 11, 11, 11, 46, 0, 0, 0, 0, 29, 74, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 65, 47, 0, 2, 2, 2, 2, 2, 9, 0, - 58, 194, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 0, 0, 0, 40, 115, 26, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 30, 2, 2, 2, 2, 2, 0, 58, 37, 0, 6, 119, 119, 119, 120, 0, - 0, 11, 11, 11, 49, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 46, 2, 2, 2, 2, 2, 2, 11, - 11, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, - 20, 2, 2, 44, 44, 44, 92, 0, 0, O, O, O, GB, B, B, O, - SB, O, SE, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv, - VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, - VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, - VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, - VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, - MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS, - VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, - VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv, - VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, - VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv, - FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB, - CMAbv,CMAbv, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, - MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, - B, O,SMAbv,SMAbv,SMAbv, VPst, IS, RK, RK, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw, - VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, SB, SE, O, - H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, - MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, - B, VBlw,VMAbv, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, - IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, - IS,CMAbv, O, VPst, B, R, R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,VMPst, - O,VMAbv,CMBlw, IS, R,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, - VPst, MPst, R, MPst,CMBlw, B,FMBlw, CS, SUB, SUB, GB, FBlw, FBlw,CMAbv, IS, VBlw, - IS, R, MBlw, GB, VAbv, R,VMPst, G, G, J, J, J, SB, SE, J, HR, - G, G, HM, HM, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw, + 33, 3, 0, 0, 0, 4, 0, 80, 118, 128, 9, 10, 11, 192, 208, 14, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 0, 0, 4, 0, 0, 5, 6, 7, 8, 9, 10, 11, 12, 0, + 13, 14, 0, 0, 0, 0, 0, 0, 15, 16, 17, 18, 19, 20, 21, 0, + 0, 22, 0, 0, 0, 0, 23, 0, 24, 0, 0, 0, 0, 0, 25, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, + 32, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 34, 35, 0, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 1, 1, 1, 1, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 0, 60, 0, + 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, + 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 66, 67, 0, 68, 69, 0, 0, 0, 70, 0, 0, 0, 0, 0, + 0, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 12, 7, 7, 0, 13, 14, + 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 8, 17, 0, 0, 18, 0, 0, 0, 0, + 0, 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, 9, 46, 47, 48, + 49, 50, 51, 52, 9, 53, 54, 55, 56, 57, 58, 10, 59, 60, 61, 62, + 0, 3, 63, 64, 65, 66, 0, 0, 0, 67, 68, 69, 70, 3, 71, 72, + 6, 73, 3, 3, 74, 75, 76, 0, 0, 77, 78, 79, 80, 3, 81, 82, + 0, 83, 3, 84, 85, 86, 0, 0, 0, 87, 88, 89, 90, 91, 92, 3, + 93, 3, 94, 95, 0, 0, 0, 96, 97, 0, 0, 0, 0, 0, 0, 0, + 98, 99, 100, 0, 101, 102, 0, 0, 103, 0, 0, 0, 0, 0, 0, 104, + 0, 0, 0, 0, 0, 0, 0, 0, 105, 0, 5, 3, 106, 0, 0, 0, + 0, 0, 107, 0, 0, 0, 0, 0, 0, 108, 109, 3, 110, 111, 112, 113, + 114, 3, 115, 116, 0, 117, 118, 119, 120, 3, 121, 122, 123, 3, 124, 125, + 126, 0, 0, 0, 0, 0, 0, 3, 127, 128, 0, 0, 0, 0, 0, 0, + 129, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 131, 132, 133, 0, + 0, 134, 135, 136, 0, 0, 0, 10, 137, 0, 0, 0, 0, 138, 139, 0, + 0, 3, 140, 8, 141, 142, 0, 0, 0, 0, 0, 0, 0, 3, 143, 0, + 0, 0, 5, 144, 5, 145, 146, 147, 0, 148, 149, 150, 151, 11, 152, 153, + 0, 154, 155, 156, 157, 11, 158, 159, 160, 161, 162, 163, 0, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 3, 176, 177, 178, 179, 180, 181, + 0, 0, 0, 0, 0, 3, 182, 183, 0, 3, 184, 185, 0, 3, 186, 187, + 188, 189, 190, 191, 0, 0, 0, 0, 0, 3, 192, 0, 0, 0, 0, 0, + 0, 193, 194, 195, 0, 0, 196, 197, 198, 199, 200, 201, 3, 202, 0, 0, + 0, 0, 0, 0, 203, 0, 0, 0, 0, 204, 205, 206, 207, 208, 209, 0, + 0, 210, 211, 212, 213, 214, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 215, 216, 217, 218, 0, 0, 0, 0, 0, 1, 219, 220, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 221, 222, 223, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 224, 0, 0, 0, 0, 0, + 0, 0, 0, 225, 226, 0, 0, 0, 0, 3, 3, 227, 228, 229, 0, 0, + 230, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 231, + 232, 3, 3, 3, 233, 234, 0, 0, 0, 0, 0, 0, 235, 0, 0, 0, + 0, 3, 236, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 238, 3, + 239, 0, 0, 0, 0, 0, 0, 5, 240, 0, 0, 0, 0, 0, 0, 5, + 241, 3, 3, 242, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, + 243, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 5, 2, 2, 2, 2, 6, 0, 2, 2, 2, 2, + 2, 5, 8, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, + 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, + 0, 2, 2, 2, 2, 5, 0, 0, 0, 2, 2, 2, 2, 2, 5, 0, + 0, 2, 8, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 74, 75, + 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 2, 2, 2, 2, 2, 2, 2, 17, 6, 13, 29, 33, 29, 45, + 0, 15, 11, 27, 7, 38, 7, 68, 0, 2, 2, 2, 2, 8, 2, 2, + 2, 10, 10, 10, 10, 80, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, + 5, 2, 2, 5, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, + 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 5, 2, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, + 0, 9, 41, 2, 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 23, 6, 6, 6, 6, 6, 6, 6, + 6, 0, 0, 0, 0, 0, 0, 48, 0, 44, 0, 0, 0, 0, 0, 49, + 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 103, 2, 2, 2, 2, 2, 36, 9, + 9, 9, 9, 0, 0, 0, 5, 31, 0, 2, 2, 2, 2, 50, 51, 0, + 0, 9, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 32, + 19, 17, 6, 18, 7, 15, 11, 67, 22, 31, 52, 25, 6, 2, 2, 2, + 2, 104, 14, 8, 2, 2, 2, 5, 8, 5, 5, 0, 2, 2, 0, 32, + 19, 0, 0, 0, 34, 0, 0, 2, 8, 2, 0, 0, 0, 0, 0, 5, + 105, 31, 24, 8, 2, 2, 5, 0, 8, 5, 2, 8, 5, 2, 0, 35, + 19, 17, 13, 0, 25, 38, 25, 68, 0, 53, 0, 0, 0, 8, 2, 5, + 5, 54, 39, 77, 0, 0, 0, 0, 0, 31, 24, 8, 2, 2, 2, 2, + 8, 5, 2, 8, 2, 2, 0, 32, 19, 17, 6, 18, 25, 7, 34, 67, + 0, 0, 0, 0, 0, 8, 54, 54, 46, 31, 14, 8, 2, 2, 2, 5, + 8, 5, 2, 8, 2, 2, 0, 32, 20, 0, 0, 25, 7, 0, 0, 2, + 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 26, 8, 2, 2, 5, 0, + 2, 5, 2, 2, 0, 8, 5, 5, 2, 0, 8, 5, 0, 2, 5, 0, + 2, 2, 2, 2, 2, 2, 0, 0, 11, 15, 27, 0, 12, 33, 12, 45, + 0, 0, 0, 0, 34, 0, 0, 0, 0, 24, 14, 55, 2, 2, 2, 5, + 2, 2, 2, 2, 2, 2, 0, 32, 7, 0, 0, 25, 13, 2, 5, 0, + 0, 36, 14, 8, 2, 2, 2, 5, 2, 2, 2, 8, 2, 2, 0, 32, + 20, 0, 0, 34, 27, 0, 0, 0, 5, 106, 78, 0, 0, 0, 0, 0, + 0, 9, 14, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 30, 40, + 11, 17, 6, 13, 12, 33, 12, 45, 107, 0, 0, 0, 34, 0, 0, 0, + 8, 31, 14, 8, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, + 2, 2, 8, 2, 2, 2, 2, 8, 0, 2, 2, 2, 5, 0, 108, 0, + 34, 11, 7, 13, 13, 19, 12, 12, 22, 0, 11, 0, 0, 0, 0, 0, + 0, 2, 0, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, + 0, 2, 2, 69, 69, 109, 0, 0, 19, 56, 18, 21, 7, 7, 6, 6, + 26, 18, 9, 13, 9, 2, 2, 79, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 81, 0, 0, 0, 0, 110, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 23, 20, 21, 57, 7, 7, 111, 82, 112, 113, + 83, 2, 2, 2, 2, 2, 48, 0, 44, 2, 2, 2, 11, 6, 2, 2, + 114, 83, 84, 41, 23, 84, 14, 14, 2, 30, 7, 40, 2, 2, 2, 2, + 2, 2, 115, 58, 116, 14, 14, 117, 85, 2, 2, 2, 2, 2, 14, 20, + 0, 2, 21, 59, 0, 0, 0, 0, 8, 2, 21, 27, 0, 0, 0, 0, + 0, 2, 21, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, + 2, 5, 21, 0, 0, 0, 0, 0, 0, 2, 2, 4, 20, 7, 21, 6, + 12, 12, 12, 12, 24, 60, 118, 119, 120, 121, 122, 0, 0, 0, 0, 123, + 0, 5, 0, 0, 8, 0, 124, 4, 125, 39, 39, 126, 86, 2, 2, 2, + 2, 2, 2, 2, 2, 50, 5, 0, 0, 7, 59, 20, 7, 127, 10, 0, + 0, 70, 128, 70, 70, 129, 130, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 2, 2, 14, 0, 0, 0, 2, 2, 2, 30, 71, 20, 0, + 0, 2, 2, 131, 132, 42, 133, 10, 81, 134, 15, 20, 7, 21, 18, 59, + 12, 12, 58, 9, 9, 9, 87, 26, 53, 9, 88, 41, 2, 2, 2, 2, + 2, 2, 2, 89, 7, 6, 6, 7, 12, 12, 7, 61, 2, 2, 2, 5, + 0, 0, 0, 0, 0, 0, 135, 62, 62, 62, 62, 0, 0, 0, 0, 0, + 0, 88, 41, 2, 2, 2, 2, 2, 2, 79, 10, 21, 22, 7, 136, 10, + 2, 2, 2, 2, 89, 7, 11, 20, 20, 42, 137, 0, 0, 0, 0, 0, + 0, 2, 2, 10, 19, 12, 11, 90, 42, 42, 42, 138, 139, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 0, 8, 2, 9, 26, 16, 16, 16, 9, 16, + 16, 24, 16, 16, 16, 52, 0, 53, 0, 0, 0, 140, 78, 9, 44, 0, + 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 49, 142, + 3, 39, 39, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, + 72, 0, 0, 91, 0, 0, 0, 0, 0, 0, 76, 91, 0, 0, 0, 0, + 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 0, 0, 0, 0, 63, 63, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, 143, 0, 63, 63, 0, 0, 0, 0, + 0, 2, 40, 2, 61, 2, 36, 2, 2, 2, 23, 17, 15, 0, 0, 13, + 0, 14, 2, 2, 2, 2, 2, 2, 2, 2, 2, 144, 11, 11, 11, 11, + 11, 11, 11, 92, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 2, 0, 0, 0, 0, 0, 30, 2, 2, 2, 7, 7, 145, 16, + 0, 2, 2, 2, 47, 6, 21, 6, 90, 42, 146, 0, 0, 0, 0, 0, + 0, 9, 147, 2, 2, 2, 2, 2, 2, 2, 148, 11, 7, 6, 12, 149, + 150, 93, 0, 0, 0, 0, 0, 0, 0, 2, 2, 30, 8, 2, 2, 2, + 2, 2, 2, 2, 2, 36, 7, 21, 71, 58, 151, 94, 152, 0, 0, 0, + 0, 2, 153, 2, 2, 2, 2, 154, 0, 8, 2, 39, 44, 0, 85, 24, + 2, 73, 6, 40, 47, 73, 2, 2, 95, 36, 5, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 155, 18, 22, 0, 0, 156, 96, 0, 0, 0, + 0, 2, 23, 20, 11, 59, 27, 157, 0, 0, 0, 0, 0, 0, 0, 0, + 49, 3, 3, 3, 3, 72, 0, 0, 0, 2, 5, 2, 8, 2, 2, 2, + 2, 2, 8, 2, 2, 2, 8, 5, 0, 47, 6, 25, 13, 0, 0, 158, + 159, 2, 2, 8, 2, 8, 2, 2, 2, 2, 2, 2, 0, 51, 35, 0, + 97, 2, 2, 50, 35, 0, 8, 2, 2, 0, 0, 0, 0, 8, 2, 2, + 5, 2, 2, 9, 54, 0, 0, 0, 0, 2, 2, 2, 0, 25, 7, 7, + 8, 2, 2, 2, 2, 2, 25, 38, 0, 2, 2, 2, 16, 16, 16, 16, + 16, 160, 2, 5, 0, 0, 0, 0, 0, 2, 51, 51, 0, 0, 0, 0, + 0, 5, 2, 2, 5, 2, 2, 2, 2, 8, 2, 5, 0, 8, 2, 0, + 0, 161, 162, 163, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 6, + 6, 6, 7, 7, 93, 0, 0, 0, 0, 0, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 2, 2, 2, 2, 2, 40, 30, 40, 0, 0, 0, 0, + 164, 19, 17, 18, 15, 67, 35, 0, 0, 0, 13, 0, 0, 0, 0, 0, + 0, 9, 55, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 6, 7, 165, + 7, 18, 166, 98, 2, 2, 2, 2, 2, 0, 0, 23, 167, 0, 0, 0, + 0, 2, 50, 0, 0, 0, 0, 0, 0, 2, 23, 22, 6, 6, 6, 7, + 7, 61, 64, 0, 0, 69, 99, 13, 100, 2, 2, 2, 2, 2, 2, 11, + 17, 7, 7, 168, 46, 0, 0, 0, 55, 47, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 5, 5, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, + 8, 2, 2, 2, 2, 2, 2, 2, 36, 19, 17, 18, 7, 169, 13, 0, + 0, 9, 9, 8, 2, 2, 2, 5, 8, 5, 2, 8, 2, 2, 56, 32, + 11, 15, 11, 27, 29, 33, 29, 45, 0, 0, 0, 0, 34, 0, 0, 0, + 2, 2, 11, 0, 9, 9, 9, 26, 0, 9, 9, 26, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 8, 0, 5, 2, 2, 2, 8, 20, 21, 6, + 6, 13, 33, 29, 29, 22, 170, 14, 171, 101, 35, 0, 0, 0, 0, 0, + 0, 31, 52, 0, 0, 0, 0, 0, 0, 2, 2, 23, 22, 6, 6, 6, + 7, 11, 92, 24, 32, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, + 172, 173, 0, 0, 0, 0, 0, 0, 0, 19, 17, 6, 6, 57, 71, 22, + 100, 9, 102, 5, 0, 0, 0, 0, 0, 22, 6, 6, 0, 12, 12, 9, + 65, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 6, + 0, 11, 17, 6, 6, 18, 15, 60, 65, 38, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 36, 174, 22, 6, 7, 7, 102, 5, 0, 0, + 0, 2, 2, 2, 2, 2, 5, 77, 94, 11, 7, 6, 58, 18, 7, 0, + 0, 2, 2, 2, 5, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 19, + 17, 6, 18, 7, 87, 65, 35, 0, 0, 2, 2, 2, 5, 8, 0, 2, + 2, 2, 2, 8, 5, 2, 2, 2, 2, 11, 11, 19, 29, 33, 31, 175, + 101, 176, 177, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, + 2, 23, 22, 6, 6, 0, 7, 11, 14, 61, 0, 33, 0, 0, 0, 0, + 0, 30, 6, 7, 7, 7, 73, 2, 2, 2, 178, 95, 9, 24, 179, 10, + 180, 0, 0, 48, 97, 0, 0, 0, 0, 30, 6, 7, 15, 17, 6, 2, + 2, 2, 2, 64, 64, 64, 43, 43, 43, 43, 43, 43, 24, 181, 0, 8, + 0, 15, 6, 15, 15, 0, 0, 0, 0, 7, 6, 6, 13, 7, 7, 9, + 65, 0, 10, 10, 10, 10, 10, 10, 10, 57, 18, 60, 26, 0, 0, 0, + 0, 2, 2, 2, 5, 2, 8, 2, 2, 30, 7, 7, 13, 0, 38, 7, + 25, 9, 99, 182, 183, 0, 0, 0, 0, 2, 2, 2, 8, 5, 2, 2, + 2, 2, 2, 2, 2, 2, 11, 11, 27, 7, 34, 60, 82, 0, 0, 0, + 0, 2, 184, 57, 27, 0, 0, 0, 0, 9, 185, 2, 2, 2, 2, 2, + 2, 2, 2, 11, 7, 6, 13, 0, 12, 15, 96, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 98, 0, 0, 66, 66, 66, 186, 187, 66, 1, + 1, 188, 1, 1, 189, 37, 37, 37, 37, 37, 37, 37, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 190, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 191, 192, 193, 9, 9, 9, 26, 0, 0, 0, + 0, 14, 41, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 27, + 0, 2, 2, 2, 2, 2, 5, 0, 56, 194, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 0, 0, 0, 53, 16, 52, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 2, 2, 2, 2, 2, 0, 56, 35, 0, 49, 3, 3, 3, 72, 0, + 0, 9, 9, 9, 55, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 9, + 9, 2, 2, 2, 2, 2, 2, 7, 7, 2, 2, 2, 2, 2, 2, 2, + 6, 2, 2, 46, 46, 46, 86, 0, 0, O, O, G, G, B, B, WJ, + WJ, CGJ, CGJ, B, O, VBlw, VBlw, VAbv, VAbv, O, B,VMAbv,VMAbv, SUB, SUB, VPst, + VPst, VPre, VPre, VBlw, O,VMPst,VMPst, VAbv, VPst,VMBlw,VMBlw, VPst, VBlw, VBlw, VAbv, VPst, + VPre, VPst, VAbv, VAbv, VBlw, VPre, VPst, B, VPst,VMAbv,VMPst, O, VAbv,VMAbv, O, VPst, + O, N, N, O, VPre, B, VAbv, O,VMAbv,CMBlw, B, VPre, O, O, VPst,CMBlw, + O, B,VMAbv, HM, HM, VAbv, O, GB, GB, VAbv, B,VMPst, B, FAbv, FAbv, FBlw, + FBlw, GB, O, VPre, H,CMAbv,CMAbv, B, VBlw, O, GB, O, WJ, B,CMBlw,CMBlw, + CMBlw,VMBlw, O, O,VMBlw,VMAbv,CMAbv,VMAbv, B, O,CMBlw, VBlw, VPre, VPre, VAbv, VBlw, + VPst, VPst,VMAbv, H, B,SMAbv,SMAbv, SB, SE, R, R,VMPst, H, J, J, VPst, + H, VAbv, H, O,FMBlw, FPst, FPst, VAbv, VPre, WJ, O, VBlw, B, O, SB, O, + SE,FMPst,FMPst, O, MBlw, CS,VMPst, B, SUB, O, SUB, SUB, O,VMPst, IS, MBlw, + B, VPst,VMPst, B,VMPst,CMAbv, B, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, VBlw, FAbv,FMPst, + O, H,VMAbv, H, O, MPre, MAbv, VBlw,VMAbv, IS, O, O, IS,CMAbv, O,CMBlw, + VAbv, VPre,VMAbv, IS, R, H,CMBlw, O, CGJ, GB,VMAbv,FMAbv, O, O, CS, R, + O, HVM, O, O,CMAbv,FMBlw, O,VMAbv,VMBlw, VAbv, MPst, MPre, MBlw, MBlw, MBlw, MBlw, + VPst, VAbv,VMPst,VMPst,VMBlw,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B, + FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv, VAbv, SUB,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, B, + MPre, MBlw, SUB, MAbv, SUB, Sk, VPst, O,SMAbv, VPst, IS, RK, RK,VMPre,VMPre,FMAbv, + CMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, O, H, MPst, VPst, VAbv,VMBlw, FPst, VPst, FAbv, + VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, VBlw, MPst, MBlw, O, B, FAbv, FAbv, FPst, B, + VPre, O,VMPst,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, + B, O, HN, VPre, VBlw, VAbv, IS, VPst, B,VMAbv, H, VAbv,CMBlw,VMPst, O,VMAbv, + CMBlw,FMAbv, B, CS, CS,VMPst, VAbv,VMAbv, VPst, MPst, R, MPst,CMBlw, B,FMBlw, CS, + SUB, SUB, GB,CMAbv, IS, VBlw, IS, R, MBlw, GB, VAbv, R,VMPst, J, SB, SE, + J, HR, G, G, HM, G, O, MPre, MPre, MPst,VMAbv, MBlw, VBlw, O, VBlw, }; static const uint16_t hb_use_u16[488]= { - 0, 0, 1, 2, 0, 3, 4, 5, 0, 6, 7, 0, 8, 0, 9, 10, - 11, 12, 10, 13, 14, 10, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 18, 26, 27, 21, 22, 28, 29, 30, 31, 32, 33, 34, 22, 35, - 36, 0, 18, 37, 38, 21, 22, 39, 24, 40, 18, 41, 42, 43, 44, 45, - 46, 47, 31, 0, 48, 49, 22, 50, 51, 52, 18, 0, 53, 49, 22, 54, - 51, 55, 18, 56, 57, 49, 10, 58, 59, 60, 61, 62, 10, 63, 64, 65, - 31, 66, 67, 68, 10, 69, 70, 10, 71, 72, 73, 74, 75, 76, 77, 0, - 10, 10, 78, 79, 80, 81, 82, 83, 84, 85, 10, 86, 10, 87, 10, 88, - 89, 90, 10, 91, 92, 93, 2, 0, 94, 0, 10, 95, 96, 10, 97, 0, - 10, 98, 99,100, 31, 10,101,102,103, 10,104,105, 10,106, 10,107, - 108,109, 2, 2,110, 10, 10,111,112, 2,113,114,115, 10,116, 10, - 117,118,119,120,121, 0, 0,122,123,124, 0,125,126,127,128, 0, - 129,130,131, 0, 0,132,133, 0,134, 0, 0, 10,135,136,137, 0, - 138, 10,139, 0, 10,140,141, 10, 10,142,143, 2,144,145,146, 10, - 147,148,149, 10, 10,150,151, 2,152, 98,153,154,155, 2, 10,156, - 10,157,158, 0,159,160,161, 2,162, 0, 0,163, 0,164, 0,165, - 165,166, 34,167,168,169, 10,170, 95, 0,171, 0, 10,172,173, 0, - 174, 2,175, 10,176, 0,177,172,178,179,180, 0, 0,181,182, 0, - 183, 10, 10,184,185,186,187,188,189, 10, 10,190,191, 0,192, 10, - 193,194,195, 10, 10,196, 10,197,198,105,199,102, 10, 34,200,201, - 202, 0,203,204, 95, 10, 10,205,206, 2,207, 21, 22,208,209,210, - 211,212,213, 10, 10,214,215,216,217, 0, 10,218,219,220,221, 0, - 199, 10, 10,222,223, 2,224,225,226,227, 10,228,229, 2,230,231, - 2, 10,140, 0, 10,232,233,103,234, 0,235,236,237,238, 10,239, - 240, 2,241, 10, 10,242,243, 0,244, 10, 10,245,246,247,248,249, - 250, 0, 22, 10,224,251, 8, 10, 71, 19, 10,252, 74,253,254, 10, - 10,255,256, 2,257, 10,258,259, 10,260,261, 49, 10,262,263,264, - 265,265,265,266,267,268,265,269, 10,270,271, 2, 10,272,273, 10, - 274, 2,275,276,277,277,278,279,280, 0, 10,176, 0,281,105, 71, - 95,282, 0,283, 71,284,285, 0,286, 0,287, 2,288, 2,289,105, - 290, 2,129,129,162,162,162,129, + 0, 0, 8, 8, 16, 16, 24, 24, 40, 40, 0, 24, 32, 0, 0, 120, + 136, 24, 56, 0, 168, 24, 240, 24, 272, 32, 280, 288, 0, 296, 304, 0, + 128, 0, 312, 320, 24, 328, 336, 24, 24, 344, 352, 360, 56, 144, 368, 64, + 48, 376, 152, 384, 56, 392, 400, 64, 48, 408, 416, 424, 72, 432, 440, 112, + 48, 448, 456, 0, 56, 464, 472, 64, 48, 480, 152, 488, 56, 496, 504, 512, + 520, 528, 536, 544, 72, 0, 552, 80, 48, 560, 160, 568, 576, 80, 48, 584, + 160, 592, 56, 600, 608, 80, 24, 616, 624, 632, 640, 648, 24, 656, 664, 672, + 72, 680, 688, 696, 24, 704, 88, 712, 720, 176, 728, 736, 744, 0, 752, 760, + 768, 776, 784, 792, 800, 808, 24, 816, 24, 824, 24, 832, 840, 848, 24, 856, + 864, 872, 880, 0, 24, 96, 888, 24, 896, 0, 24, 184, 904, 912, 72, 24, + 920, 192, 200, 24, 928, 104, 24, 936, 24, 944, 952, 960, 32, 32, 968, 24, + 24, 976, 984, 32, 992,1000,1008, 24,1016, 24,1024,1032,1040,1048,1056, 0, + 0,1064,1072,1080, 0,1088,1096,1104,1112, 0, 16,1120,1128, 0, 0,1136, + 1144, 0,1152, 0,1160,1168,1176, 0,1184, 24,1192, 0, 24, 208,1200, 24, + 24,1208,1216, 32,1224,1232,1240, 24,1248,1256,1264, 24, 24,1272,1280, 32, + 1288, 184,1296,1304,1312, 32, 24,1320, 24,1328,1336, 0,1344,1352,1360, 32, + 40, 0, 0,1368, 0,1376, 0, 216, 216,1384, 112,1392,1400,1408, 24,1416, + 96, 0,1424, 0, 24, 224,1432, 0,1440, 32,1448, 24, 232, 0,1456, 224, + 1464,1472,1480, 0, 0,1488,1496, 0,1504, 24, 24,1512,1520,1528,1536,1544, + 24,1552,1560, 0,1568, 24,1576,1584,1592, 24, 24,1600, 24,1608,1616, 104, + 248, 192, 24, 112,1624,1632,1640, 0,1648,1656, 96, 24, 24,1664,1672, 32, + 1680, 64, 48,1688,1696,1704,1712,1720,1728, 24, 24,1736,1744,1752,1760, 0, + 24,1768,1776,1784,1792, 0, 248, 24, 24,1800,1808, 32, 256,1816,1824,1832, + 24,1840,1848, 32,1856,1864, 32, 24, 208, 0, 24,1872,1880, 200,1888, 0, + 1896,1904,1912,1920, 24,1928,1936, 32,1944, 24, 24,1952,1960, 0,1968, 24, + 24,1976,1984,1992,2000,2008,2016, 0, 48, 24, 256,2024, 128, 24, 88, 144, + 24,2032, 176,2040,2048, 24, 24,2056,2064, 32,2072, 24,2080,2088, 24,2096, + 2104, 80, 24,2112,2120,2128, 8,2136,2144,2152, 8,2160, 24,2168,2176, 32, + 24,2184,2192, 24,2200, 32,2208,2216, 264, 264,2224,2232,2240, 0, 24, 232, + 0,2248, 104, 88, 96,2256, 0,2264, 88,2272,2280, 0,2288, 0,2296, 32, + 2304, 32,2312, 104,2320, 32, 40, 16, }; static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i) @@ -660,7 +661,8 @@ static inline uint8_t hb_use_b4 (const uint8_t* a, unsigned i) } static inline uint8_t hb_use_get_category (unsigned u) { - return u<921600 ? hb_use_u8[3273u+((hb_use_u8[945u+((hb_use_u16[((hb_use_u8[369u+((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((((u)>>1))>>3))>>1))>>3))>>4)))<<4)+((((((((((u)>>1))>>3))>>1))>>3))&15)])<<3)+((((((((u)>>1))>>3))>>1))&7)])<<1)+((((((u)>>1))>>3))&1)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : O; + /* packtab: [2^4,2^4,2^3,2^1,2^3,2^1] */ + return u<921600u ? (uint8_t)(hb_use_u8[3273u+((hb_use_u8[945u+hb_use_u16[((hb_use_u8[369u+((hb_use_u8[113u+((hb_use_b4(hb_use_u8,((((((((((u)>>1))>>3))>>1))>>3))>>4)))<<4)+((((((((((u)>>1))>>3))>>1))>>3))&15)])<<3)+((((((((u)>>1))>>3))>>1))&7)])<<1)+((((((u)>>1))>>3))&1)]+((((u)>>1))&7)])<<1)+((u)&1)]) : O; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc index bb586a68ce5..f834752c51a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shaper-vowel-constraints.cc @@ -2,7 +2,7 @@ /* * The following functions are generated by running: * - * ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt + * gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt * * on files with these headers: * 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 4933e661371..30e106554d6 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 @@ -2,7 +2,7 @@ /* * The following table is generated by running: * - * ./gen-tag-table.py languagetags language-subtag-registry + * gen-tag-table.py languagetags language-subtag-registry * * on files with these headers: * @@ -221,55 +221,201 @@ static const LangTag ot_languages2[] = { }; #ifndef HB_NO_LANGUAGE_LONG +static const hb_tag_t ot_languages3_blocked[] = { + HB_TAG('a','b','a',' '), /* Abé != Abaza */ + HB_TAG('a','f','k',' '), /* Nanubae != Afrikaans */ + HB_TAG('a','g','w',' '), /* Kahua != Agaw */ + HB_TAG('a','r','i',' '), /* Arikara != Aari */ + HB_TAG('a','r','k',' '), /* Arikapú != Rakhine */ + HB_TAG('b','a','g',' '), /* Tuki != Baghelkhandi */ + HB_TAG('b','a','u',' '), /* Bada (Nigeria) != Baulé */ + HB_TAG('b','b','r',' '), /* Girawa != Berber */ + HB_TAG('b','c','h',' '), /* Bariai != Bench */ + HB_TAG('b','i','l',' '), /* Bile != Bilen */ + HB_TAG('b','k','f',' '), /* Beeke != Blackfoot */ + HB_TAG('b','l','i',' '), /* Bolia != Baluchi */ + HB_TAG('b','l','t',' '), /* Tai Dam != Balti */ + HB_TAG('b','m','b',' '), /* Bembe != Bambara (Bamanankan) */ + HB_TAG('b','m','l',' '), /* Bomboli != Bamileke */ + HB_TAG('b','r','i',' '), /* Mokpwe != Braj Bhasha */ + HB_TAG('b','r','m',' '), /* Barambu != Burmese */ + HB_TAG('b','s','h',' '), /* Kati != Bashkir */ + HB_TAG('b','t','i',' '), /* Burate != Beti */ + HB_TAG('c','h','g',' '), /* Chagatai != Chaha Gurage */ + HB_TAG('c','h','h',' '), /* Chinook != Chattisgarhi */ + HB_TAG('c','r','r',' '), /* Carolina Algonquian != Carrier */ + HB_TAG('c','r','t',' '), /* Iyojwa'ja Chorote != Crimean Tatar */ + HB_TAG('c','s','l',' '), /* Chinese Sign Language != Church Slavonic */ + HB_TAG('d','h','v',' '), /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */ + HB_TAG('d','n','k',' '), /* Dengka != Dinka */ + HB_TAG('d','r','i',' '), /* C'Lela != Dari */ + HB_TAG('d','u','n',' '), /* Dusun Deyah != Dungan */ + HB_TAG('d','z','n',' '), /* Dzando != Dzongkha */ + HB_TAG('e','c','r',' '), /* Eteocretan != Eastern Cree */ + HB_TAG('e','u','q',' '), /* Basque [collection] != Basque */ + HB_TAG('f','a','r',' '), /* Fataleka != Persian */ + HB_TAG('f','o','s',' '), /* Siraya != Faroese */ + HB_TAG('g','a','d',' '), /* Gaddang != Ga */ + HB_TAG('g','a','e',' '), /* Guarequena != Scottish Gaelic */ + HB_TAG('g','a','l',' '), /* Galolen != Galician */ + HB_TAG('g','a','r',' '), /* Galeya != Garshuni */ + HB_TAG('g','a','w',' '), /* Nobonob != Garhwali */ + HB_TAG('g','m','z',' '), /* Mgbolizhia != Gumuz */ + HB_TAG('g','r','o',' '), /* Groma != Garo */ + HB_TAG('g','u','a',' '), /* Shiki != Guarani */ + HB_TAG('h','a','l',' '), /* Halang != Halam (Falam Chin) */ + HB_TAG('h','b','n',' '), /* Heiban != Hammer-Banna */ + HB_TAG('i','r','i',' '), /* Rigwe != Irish */ + HB_TAG('i','s','m',' '), /* Masimasi != Inari Sami */ + HB_TAG('j','a','n',' '), /* Jandai != Japanese */ + HB_TAG('j','i','i',' '), /* Jiiddu != Yiddish */ + HB_TAG('j','u','d',' '), /* Worodougou != Ladino */ + HB_TAG('j','u','l',' '), /* Jirel != Jula */ + HB_TAG('k','a','c',' '), /* Kachin != Kachchi */ + HB_TAG('k','e','b',' '), /* Kélé != Kebena */ + HB_TAG('k','g','e',' '), /* Komering != Khutsuri Georgian */ + HB_TAG('k','h','n',' '), /* Khandesi != Khamti Shan (Microsoft fonts) */ + HB_TAG('k','h','s',' '), /* Kasua != Khanty-Shurishkar */ + HB_TAG('k','h','v',' '), /* Khvarshi != Khanty-Vakhi */ + HB_TAG('k','i','s',' '), /* Kis != Kisii */ + HB_TAG('k','k','n',' '), /* Kon Keu != Kokni */ + HB_TAG('k','l','m',' '), /* Migum != Kalmyk */ + HB_TAG('k','m','n',' '), /* Awtuw != Kumaoni */ + HB_TAG('k','m','o',' '), /* Kwoma != Komo */ + HB_TAG('k','m','s',' '), /* Kamasau != Komso */ + HB_TAG('k','n','r',' '), /* Kaningra != Kanuri */ + HB_TAG('k','o','d',' '), /* Kodi != Kodagu */ + HB_TAG('k','o','h',' '), /* Koyo != Korean Old Hangul */ + HB_TAG('k','o','p',' '), /* Waube != Komi-Permyak */ + HB_TAG('k','o','z',' '), /* Korak != Komi-Zyrian */ + HB_TAG('k','p','l',' '), /* Kpala != Kpelle */ + HB_TAG('k','r','k',' '), /* Kerek != Karakalpak */ + HB_TAG('k','r','m',' '), /* Krim (retired code) != Karaim */ + HB_TAG('k','r','n',' '), /* Sapo != Karen */ + HB_TAG('k','s','i',' '), /* Krisa != Khasi */ + HB_TAG('k','s','m',' '), /* Kumba != Kildin Sami */ + HB_TAG('k','u','i',' '), /* Kuikúro-Kalapálo != Kui */ + HB_TAG('k','u','l',' '), /* Kulere != Kulvi */ + HB_TAG('k','u','y',' '), /* Kuuku-Ya'u != Kuy */ + HB_TAG('k','y','k',' '), /* Kamayo != Koryak */ + HB_TAG('l','a','h',' '), /* Lahnda [macrolanguage] != Lahuli */ + HB_TAG('l','a','k',' '), /* Laka (Nigeria) (retired code) != Lak */ + HB_TAG('l','a','m',' '), /* Lamba != Lambani */ + HB_TAG('l','a','z',' '), /* Aribwatsa != Laz */ + HB_TAG('l','d','k',' '), /* Leelau != Ladakhi */ + HB_TAG('l','m','a',' '), /* East Limba != Low Mari */ + HB_TAG('l','m','b',' '), /* Merei != Limbu */ + HB_TAG('l','m','w',' '), /* Lake Miwok != Lomwe */ + HB_TAG('l','s','b',' '), /* Burundian Sign Language != Lower Sorbian */ + HB_TAG('l','t','h',' '), /* Thur != Lithuanian */ + HB_TAG('l','v','i',' '), /* Lavi != Latvian */ + HB_TAG('m','a','j',' '), /* Jalapa De Díaz Mazatec != Majang */ + HB_TAG('m','a','p',' '), /* Austronesian [collection] != Mapudungun */ + HB_TAG('m','a','w',' '), /* Mampruli != Marwari */ + HB_TAG('m','b','n',' '), /* Macaguán != Mbundu */ + HB_TAG('m','c','h',' '), /* Maquiritari != Manchu */ + HB_TAG('m','c','r',' '), /* Menya != Moose Cree */ + HB_TAG('m','d','e',' '), /* Maba (Chad) != Mende */ + HB_TAG('m','i','z',' '), /* Coatzospan Mixtec != Mizo */ + HB_TAG('m','k','r',' '), /* Malas != Makasar */ + HB_TAG('m','l','e',' '), /* Manambu != Male */ + HB_TAG('m','l','n',' '), /* Malango != Malinke */ + HB_TAG('m','l','r',' '), /* Vame != Malayalam Reformed */ + HB_TAG('m','n','d',' '), /* Mondé != Mandinka */ + HB_TAG('m','n','g',' '), /* Eastern Mnong != Mongolian */ + HB_TAG('m','n','x',' '), /* Manikion != Manx */ + HB_TAG('m','o','k',' '), /* Morori != Moksha */ + HB_TAG('m','o','r',' '), /* Moro != Moroccan */ + HB_TAG('m','t','h',' '), /* Munggui != Maithili */ + HB_TAG('m','t','s',' '), /* Yora != Maltese */ + HB_TAG('m','u','n',' '), /* Munda [collection] != Mundari */ + HB_TAG('n','a','s',' '), /* Naasioi != Naskapi */ + HB_TAG('n','c','r',' '), /* Ncane != N-Cree */ + HB_TAG('n','d','b',' '), /* Kenswei Nsei != Ndebele */ + HB_TAG('n','d','g',' '), /* Ndengereko != Ndonga */ + HB_TAG('n','g','r',' '), /* Engdewu != Nagari */ + HB_TAG('n','i','s',' '), /* Nimi != Nisi */ + HB_TAG('n','k','o',' '), /* Nkonya != N’Ko */ + HB_TAG('n','s','m',' '), /* Sumi Naga != Northern Sami */ + HB_TAG('n','t','o',' '), /* Ntomba != Esperanto */ + HB_TAG('o','r','o',' '), /* Orokolo != Oromo */ + HB_TAG('p','a','a',' '), /* Papuan [collection] != Palestinian Aramaic */ + HB_TAG('p','a','l',' '), /* Pahlavi != Pali */ + HB_TAG('p','a','s',' '), /* Papasena != Pashto */ + HB_TAG('p','i','l',' '), /* Yom != Filipino */ + HB_TAG('p','l','k',' '), /* Kohistani Shina != Polish */ + HB_TAG('r','m','s',' '), /* Romanian Sign Language != Romansh */ + HB_TAG('s','a','d',' '), /* Sandawe != Sadri */ + HB_TAG('s','a','y',' '), /* Saya != Sayisi */ + HB_TAG('s','g','o',' '), /* Songa (retired code) != Sango */ + HB_TAG('s','i','b',' '), /* Sebop != Sibe */ + HB_TAG('s','i','g',' '), /* Paasaal != Silte Gurage */ + HB_TAG('s','k','s',' '), /* Maia != Skolt Sami */ + HB_TAG('s','k','y',' '), /* Sikaiana != Slovak */ + HB_TAG('s','l','a',' '), /* Slavic [collection] != Slavey */ + HB_TAG('s','m','l',' '), /* Central Sama != Somali */ + HB_TAG('s','n','h',' '), /* Shinabo (retired code) != Sinhala (Sinhalese) */ + HB_TAG('s','o','g',' '), /* Sogdian != Sodo Gurage */ + HB_TAG('s','r','b',' '), /* Sora != Serbian */ + HB_TAG('s','r','k',' '), /* Serudung Murut != Saraiki */ + HB_TAG('s','s','l',' '), /* Western Sisaala != South Slavey */ + HB_TAG('s','s','m',' '), /* Semnam != Southern Sami */ + HB_TAG('s','u','r',' '), /* Mwaghavul != Suri */ + HB_TAG('s','v','e',' '), /* Serili != Swedish */ + HB_TAG('s','w','k',' '), /* Malawi Sena != Swahili */ + HB_TAG('t','a','j',' '), /* Eastern Tamang != Tajiki */ + HB_TAG('t','g','n',' '), /* Tandaganon != Tongan */ + HB_TAG('t','g','r',' '), /* Tareng != Tigre */ + HB_TAG('t','g','y',' '), /* Togoyo != Tigrinya */ + HB_TAG('t','k','m',' '), /* Takelma != Turkmen */ + HB_TAG('t','m','n',' '), /* Taman (Indonesia) != Temne */ + HB_TAG('t','n','a',' '), /* Tacana != Tswana */ + HB_TAG('t','n','e',' '), /* Tinoc Kallahan (retired code) != Tundra Enets */ + HB_TAG('t','n','g',' '), /* Tobanga != Tonga */ + HB_TAG('t','r','k',' '), /* Turkic [collection] != Turkish */ + HB_TAG('t','s','g',' '), /* Tausug != Tsonga */ + HB_TAG('t','u','a',' '), /* Wiarumus != Turoyo Aramaic */ + HB_TAG('t','u','l',' '), /* Tula != Tulu */ + HB_TAG('t','u','v',' '), /* Turkana != Tuvin */ + HB_TAG('v','i','t',' '), /* Viti != Vietnamese */ + HB_TAG('w','a','g',' '), /* Wa'ema != Wagdi */ + HB_TAG('x','b','d',' '), /* Bindal != Lü */ + HB_TAG('y','a','k',' '), /* Yakama != Sakha */ + HB_TAG('y','b','a',' '), /* Yala != Yoruba */ + HB_TAG('y','i','m',' '), /* Yimchungru Naga != Yi Modern */ + HB_TAG('z','n','d',' '), /* Zande [collection] != Zande */ +}; + static const LangTag ot_languages3[] = { {HB_TAG('a','a','e',' '), HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */ {HB_TAG('a','a','o',' '), HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */ -/*{HB_TAG('a','a','q',' '), HB_TAG('A','A','Q',' ')},*/ /* Eastern Abnaki -> Eastern Abenaki */ {HB_TAG('a','a','t',' '), HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */ - {HB_TAG('a','b','a',' '), HB_TAG_NONE }, /* Abé != Abaza */ {HB_TAG('a','b','h',' '), HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */ {HB_TAG('a','b','q',' '), HB_TAG('A','B','A',' ')}, /* Abaza */ {HB_TAG('a','b','s',' '), HB_TAG('C','P','P',' ')}, /* Ambonese Malay -> Creoles */ {HB_TAG('a','b','v',' '), HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */ - {HB_TAG('a','c','f',' '), HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */ - {HB_TAG('a','c','f',' '), HB_TAG('C','P','P',' ')}, /* Saint Lucian Creole French -> Creoles */ -/*{HB_TAG('a','c','h',' '), HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */ {HB_TAG('a','c','m',' '), HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */ {HB_TAG('a','c','q',' '), HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */ - {HB_TAG('a','c','r',' '), HB_TAG('A','C','R',' ')}, /* Achi */ - {HB_TAG('a','c','r',' '), HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */ {HB_TAG('a','c','w',' '), HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */ {HB_TAG('a','c','x',' '), HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */ - {HB_TAG('a','c','y',' '), HB_TAG('A','C','Y',' ')}, /* Cypriot Arabic */ - {HB_TAG('a','c','y',' '), HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */ {HB_TAG('a','d','a',' '), HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */ {HB_TAG('a','d','f',' '), HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */ {HB_TAG('a','d','p',' '), HB_TAG('D','Z','N',' ')}, /* Adap (retired code) -> Dzongkha */ -/*{HB_TAG('a','d','y',' '), HB_TAG('A','D','Y',' ')},*/ /* Adyghe */ {HB_TAG('a','e','b',' '), HB_TAG('A','R','A',' ')}, /* Tunisian Arabic -> Arabic */ {HB_TAG('a','e','c',' '), HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */ {HB_TAG('a','f','b',' '), HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */ - {HB_TAG('a','f','k',' '), HB_TAG_NONE }, /* Nanubae != Afrikaans */ {HB_TAG('a','f','s',' '), HB_TAG('C','P','P',' ')}, /* Afro-Seminole Creole -> Creoles */ {HB_TAG('a','g','u',' '), HB_TAG('M','Y','N',' ')}, /* Aguacateco -> Mayan */ - {HB_TAG('a','g','w',' '), HB_TAG_NONE }, /* Kahua != Agaw */ {HB_TAG('a','h','g',' '), HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */ {HB_TAG('a','h','t',' '), HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */ {HB_TAG('a','i','g',' '), HB_TAG('C','P','P',' ')}, /* Antigua and Barbuda Creole English -> Creoles */ - {HB_TAG('a','i','i',' '), HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ - {HB_TAG('a','i','i',' '), HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */ -/*{HB_TAG('a','i','o',' '), HB_TAG('A','I','O',' ')},*/ /* Aiton */ {HB_TAG('a','i','w',' '), HB_TAG('A','R','I',' ')}, /* Aari */ {HB_TAG('a','j','p',' '), HB_TAG('A','R','A',' ')}, /* South Levantine Arabic (retired code) -> Arabic */ {HB_TAG('a','j','t',' '), HB_TAG('A','R','A',' ')}, /* Judeo-Tunisian Arabic (retired code) -> Arabic */ - {HB_TAG('a','k','b',' '), HB_TAG('A','K','B',' ')}, /* Batak Angkola */ - {HB_TAG('a','k','b',' '), HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */ {HB_TAG('a','l','n',' '), HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */ {HB_TAG('a','l','s',' '), HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */ -/*{HB_TAG('a','l','t',' '), HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */ {HB_TAG('a','m','f',' '), HB_TAG('H','B','N',' ')}, /* Hamer-Banna -> Hammer-Banna */ {HB_TAG('a','m','w',' '), HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */ -/*{HB_TAG('a','n','g',' '), HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ {HB_TAG('a','o','a',' '), HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */ {HB_TAG('a','p','a',' '), HB_TAG('A','T','H',' ')}, /* Apache [collection] -> Athapaskan */ {HB_TAG('a','p','c',' '), HB_TAG('A','R','A',' ')}, /* Levantine Arabic -> Arabic */ @@ -280,61 +426,39 @@ static const LangTag ot_languages3[] = { {HB_TAG('a','p','m',' '), HB_TAG('A','T','H',' ')}, /* Mescalero-Chiricahua Apache -> Athapaskan */ {HB_TAG('a','p','w',' '), HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */ {HB_TAG('a','r','b',' '), HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */ - {HB_TAG('a','r','i',' '), HB_TAG_NONE }, /* Arikara != Aari */ - {HB_TAG('a','r','k',' '), HB_TAG_NONE }, /* Arikapú != Rakhine */ {HB_TAG('a','r','n',' '), HB_TAG('M','A','P',' ')}, /* Mapudungun */ {HB_TAG('a','r','q',' '), HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */ {HB_TAG('a','r','s',' '), HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */ - {HB_TAG('a','r','y',' '), HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */ - {HB_TAG('a','r','y',' '), HB_TAG('A','R','A',' ')}, /* Moroccan Arabic -> Arabic */ {HB_TAG('a','r','z',' '), HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ -/*{HB_TAG('a','s','t',' '), HB_TAG('A','S','T',' ')},*/ /* Asturian */ -/*{HB_TAG('a','t','h',' '), HB_TAG('A','T','H',' ')},*/ /* Athapascan [collection] -> Athapaskan */ {HB_TAG('a','t','j',' '), HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ -/*{HB_TAG('a','t','s',' '), HB_TAG('A','T','S',' ')},*/ /* Gros Ventre (Atsina) */ {HB_TAG('a','t','v',' '), HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ {HB_TAG('a','u','j',' '), HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */ {HB_TAG('a','u','z',' '), HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */ {HB_TAG('a','v','l',' '), HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ -/*{HB_TAG('a','v','n',' '), HB_TAG('A','V','N',' ')},*/ /* Avatime */ -/*{HB_TAG('a','w','a',' '), HB_TAG('A','W','A',' ')},*/ /* Awadhi */ {HB_TAG('a','y','c',' '), HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */ {HB_TAG('a','y','h',' '), HB_TAG('A','R','A',' ')}, /* Hadrami Arabic -> Arabic */ {HB_TAG('a','y','l',' '), HB_TAG('A','R','A',' ')}, /* Libyan Arabic -> Arabic */ {HB_TAG('a','y','n',' '), HB_TAG('A','R','A',' ')}, /* Sanaani Arabic -> Arabic */ {HB_TAG('a','y','p',' '), HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */ {HB_TAG('a','y','r',' '), HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */ - {HB_TAG('a','z','b',' '), HB_TAG('A','Z','B',' ')}, /* South Azerbaijani -> Torki */ - {HB_TAG('a','z','b',' '), HB_TAG('A','Z','E',' ')}, /* South Azerbaijani -> Azerbaijani */ {HB_TAG('a','z','d',' '), HB_TAG('N','A','H',' ')}, /* Eastern Durango Nahuatl -> Nahuatl */ {HB_TAG('a','z','j',' '), HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */ {HB_TAG('a','z','n',' '), HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */ {HB_TAG('a','z','z',' '), HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */ {HB_TAG('b','a','d',' '), HB_TAG('B','A','D','0')}, /* Banda [collection] */ - {HB_TAG('b','a','g',' '), HB_TAG_NONE }, /* Tuki != Baghelkhandi */ {HB_TAG('b','a','h',' '), HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */ {HB_TAG('b','a','i',' '), HB_TAG('B','M','L',' ')}, /* Bamileke [collection] */ {HB_TAG('b','a','l',' '), HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ -/*{HB_TAG('b','a','n',' '), HB_TAG('B','A','N',' ')},*/ /* Balinese */ -/*{HB_TAG('b','a','r',' '), HB_TAG('B','A','R',' ')},*/ /* Bavarian */ - {HB_TAG('b','a','u',' '), HB_TAG_NONE }, /* Bada (Nigeria) != Baulé */ - {HB_TAG('b','b','c',' '), HB_TAG('B','B','C',' ')}, /* Batak Toba */ - {HB_TAG('b','b','c',' '), HB_TAG('B','T','K',' ')}, /* Batak Toba -> Batak */ {HB_TAG('b','b','j',' '), HB_TAG('B','M','L',' ')}, /* Ghomálá' -> Bamileke */ {HB_TAG('b','b','p',' '), HB_TAG('B','A','D','0')}, /* West Central Banda -> Banda */ - {HB_TAG('b','b','r',' '), HB_TAG_NONE }, /* Girawa != Berber */ {HB_TAG('b','b','z',' '), HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */ {HB_TAG('b','c','c',' '), HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */ - {HB_TAG('b','c','h',' '), HB_TAG_NONE }, /* Bariai != Bench */ {HB_TAG('b','c','i',' '), HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */ {HB_TAG('b','c','l',' '), HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */ {HB_TAG('b','c','q',' '), HB_TAG('B','C','H',' ')}, /* Bench */ {HB_TAG('b','c','r',' '), HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */ -/*{HB_TAG('b','d','c',' '), HB_TAG('B','D','C',' ')},*/ /* Emberá-Baudó */ -/*{HB_TAG('b','d','y',' '), HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */ {HB_TAG('b','e','a',' '), HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */ {HB_TAG('b','e','b',' '), HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ -/*{HB_TAG('b','e','m',' '), HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ {HB_TAG('b','e','r',' '), HB_TAG('B','B','R',' ')}, /* Berber [collection] */ {HB_TAG('b','e','w',' '), HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */ {HB_TAG('b','f','l',' '), HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */ @@ -342,70 +466,35 @@ static const LangTag ot_languages3[] = { {HB_TAG('b','f','t',' '), HB_TAG('B','L','T',' ')}, /* Balti */ {HB_TAG('b','f','u',' '), HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */ {HB_TAG('b','f','y',' '), HB_TAG('B','A','G',' ')}, /* Bagheli -> Baghelkhandi */ -/*{HB_TAG('b','g','c',' '), HB_TAG('B','G','C',' ')},*/ /* Haryanvi */ {HB_TAG('b','g','n',' '), HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */ {HB_TAG('b','g','p',' '), HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */ - {HB_TAG('b','g','q',' '), HB_TAG('B','G','Q',' ')}, /* Bagri */ - {HB_TAG('b','g','q',' '), HB_TAG('R','A','J',' ')}, /* Bagri -> Rajasthani */ {HB_TAG('b','g','r',' '), HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */ {HB_TAG('b','h','b',' '), HB_TAG('B','H','I',' ')}, /* Bhili */ -/*{HB_TAG('b','h','i',' '), HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */ {HB_TAG('b','h','k',' '), HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) -> Bikol */ -/*{HB_TAG('b','h','o',' '), HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */ {HB_TAG('b','h','r',' '), HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */ -/*{HB_TAG('b','i','k',' '), HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */ - {HB_TAG('b','i','l',' '), HB_TAG_NONE }, /* Bile != Bilen */ {HB_TAG('b','i','n',' '), HB_TAG('E','D','O',' ')}, /* Edo */ {HB_TAG('b','i','u',' '), HB_TAG('Q','I','N',' ')}, /* Biete -> Chin */ -/*{HB_TAG('b','j','j',' '), HB_TAG('B','J','J',' ')},*/ /* Kanauji */ {HB_TAG('b','j','n',' '), HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */ {HB_TAG('b','j','o',' '), HB_TAG('B','A','D','0')}, /* Mid-Southern Banda -> Banda */ {HB_TAG('b','j','q',' '), HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ {HB_TAG('b','j','s',' '), HB_TAG('C','P','P',' ')}, /* Bajan -> Creoles */ {HB_TAG('b','j','t',' '), HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */ - {HB_TAG('b','k','f',' '), HB_TAG_NONE }, /* Beeke != Blackfoot */ {HB_TAG('b','k','o',' '), HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */ {HB_TAG('b','l','a',' '), HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */ {HB_TAG('b','l','e',' '), HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */ {HB_TAG('b','l','g',' '), HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */ - {HB_TAG('b','l','i',' '), HB_TAG_NONE }, /* Bolia != Baluchi */ - {HB_TAG('b','l','k',' '), HB_TAG('B','L','K',' ')}, /* Pa’o Karen */ - {HB_TAG('b','l','k',' '), HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */ {HB_TAG('b','l','n',' '), HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */ - {HB_TAG('b','l','t',' '), HB_TAG_NONE }, /* Tai Dam != Balti */ - {HB_TAG('b','m','b',' '), HB_TAG_NONE }, /* Bembe != Bambara (Bamanankan) */ - {HB_TAG('b','m','l',' '), HB_TAG_NONE }, /* Bomboli != Bamileke */ {HB_TAG('b','m','m',' '), HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */ {HB_TAG('b','p','d',' '), HB_TAG('B','A','D','0')}, /* Banda-Banda -> Banda */ {HB_TAG('b','p','l',' '), HB_TAG('C','P','P',' ')}, /* Broome Pearling Lugger Pidgin -> Creoles */ {HB_TAG('b','p','q',' '), HB_TAG('C','P','P',' ')}, /* Banda Malay -> Creoles */ -/*{HB_TAG('b','p','y',' '), HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */ {HB_TAG('b','q','i',' '), HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */ {HB_TAG('b','q','k',' '), HB_TAG('B','A','D','0')}, /* Banda-Mbrès -> Banda */ {HB_TAG('b','r','a',' '), HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */ {HB_TAG('b','r','c',' '), HB_TAG('C','P','P',' ')}, /* Berbice Creole Dutch -> Creoles */ -/*{HB_TAG('b','r','h',' '), HB_TAG('B','R','H',' ')},*/ /* Brahui */ - {HB_TAG('b','r','i',' '), HB_TAG_NONE }, /* Mokpwe != Braj Bhasha */ - {HB_TAG('b','r','m',' '), HB_TAG_NONE }, /* Barambu != Burmese */ -/*{HB_TAG('b','r','x',' '), HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */ - {HB_TAG('b','s','h',' '), HB_TAG_NONE }, /* Kati != Bashkir */ -/*{HB_TAG('b','s','k',' '), HB_TAG('B','S','K',' ')},*/ /* Burushaski */ {HB_TAG('b','t','b',' '), HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */ - {HB_TAG('b','t','d',' '), HB_TAG('B','T','D',' ')}, /* Batak Dairi (Pakpak) */ - {HB_TAG('b','t','d',' '), HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */ - {HB_TAG('b','t','i',' '), HB_TAG_NONE }, /* Burate != Beti */ {HB_TAG('b','t','j',' '), HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ -/*{HB_TAG('b','t','k',' '), HB_TAG('B','T','K',' ')},*/ /* Batak [collection] */ - {HB_TAG('b','t','m',' '), HB_TAG('B','T','M',' ')}, /* Batak Mandailing */ - {HB_TAG('b','t','m',' '), HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */ {HB_TAG('b','t','o',' '), HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ - {HB_TAG('b','t','s',' '), HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ - {HB_TAG('b','t','s',' '), HB_TAG('B','T','K',' ')}, /* Batak Simalungun -> Batak */ - {HB_TAG('b','t','x',' '), HB_TAG('B','T','X',' ')}, /* Batak Karo */ - {HB_TAG('b','t','x',' '), HB_TAG('B','T','K',' ')}, /* Batak Karo -> Batak */ - {HB_TAG('b','t','z',' '), HB_TAG('B','T','Z',' ')}, /* Batak Alas-Kluet */ - {HB_TAG('b','t','z',' '), HB_TAG('B','T','K',' ')}, /* Batak Alas-Kluet -> Batak */ -/*{HB_TAG('b','u','g',' '), HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */ {HB_TAG('b','u','m',' '), HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */ {HB_TAG('b','v','e',' '), HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */ {HB_TAG('b','v','u',' '), HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */ @@ -415,52 +504,26 @@ static const LangTag ot_languages3[] = { {HB_TAG('b','x','p',' '), HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */ {HB_TAG('b','x','r',' '), HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */ {HB_TAG('b','y','n',' '), HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */ - {HB_TAG('b','y','v',' '), HB_TAG('B','Y','V',' ')}, /* Medumba */ - {HB_TAG('b','y','v',' '), HB_TAG('B','M','L',' ')}, /* Medumba -> Bamileke */ {HB_TAG('b','z','c',' '), HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */ {HB_TAG('b','z','j',' '), HB_TAG('C','P','P',' ')}, /* Belize Kriol English -> Creoles */ {HB_TAG('b','z','k',' '), HB_TAG('C','P','P',' ')}, /* Nicaragua Creole English -> Creoles */ {HB_TAG('c','a','a',' '), HB_TAG('M','Y','N',' ')}, /* Chortí -> Mayan */ {HB_TAG('c','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Chuj -> Mayan */ - {HB_TAG('c','a','f',' '), HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */ - {HB_TAG('c','a','f',' '), HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */ - {HB_TAG('c','a','k',' '), HB_TAG('C','A','K',' ')}, /* Kaqchikel */ - {HB_TAG('c','a','k',' '), HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */ -/*{HB_TAG('c','a','y',' '), HB_TAG('C','A','Y',' ')},*/ /* Cayuga */ -/*{HB_TAG('c','b','g',' '), HB_TAG('C','B','G',' ')},*/ /* Chimila */ - {HB_TAG('c','b','k',' '), HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */ - {HB_TAG('c','b','k',' '), HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */ {HB_TAG('c','b','l',' '), HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */ {HB_TAG('c','c','l',' '), HB_TAG('C','P','P',' ')}, /* Cutchi-Swahili -> Creoles */ {HB_TAG('c','c','m',' '), HB_TAG('C','P','P',' ')}, /* Malaccan Creole Malay -> Creoles */ {HB_TAG('c','c','o',' '), HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */ {HB_TAG('c','c','q',' '), HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */ {HB_TAG('c','d','o',' '), HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese, Simplified */ -/*{HB_TAG('c','e','b',' '), HB_TAG('C','E','B',' ')},*/ /* Cebuano */ {HB_TAG('c','e','k',' '), HB_TAG('Q','I','N',' ')}, /* Eastern Khumi Chin -> Chin */ {HB_TAG('c','e','y',' '), HB_TAG('Q','I','N',' ')}, /* Ekai Chin -> Chin */ - {HB_TAG('c','f','m',' '), HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */ - {HB_TAG('c','f','m',' '), HB_TAG('Q','I','N',' ')}, /* Falam Chin -> Chin */ -/*{HB_TAG('c','g','g',' '), HB_TAG('C','G','G',' ')},*/ /* Chiga */ {HB_TAG('c','h','f',' '), HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */ - {HB_TAG('c','h','g',' '), HB_TAG_NONE }, /* Chagatai != Chaha Gurage */ - {HB_TAG('c','h','h',' '), HB_TAG_NONE }, /* Chinook != Chattisgarhi */ {HB_TAG('c','h','j',' '), HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ {HB_TAG('c','h','k',' '), HB_TAG('C','H','K','0')}, /* Chuukese */ - {HB_TAG('c','h','m',' '), HB_TAG('H','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> High Mari */ - {HB_TAG('c','h','m',' '), HB_TAG('L','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> Low Mari */ {HB_TAG('c','h','n',' '), HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */ -/*{HB_TAG('c','h','o',' '), HB_TAG('C','H','O',' ')},*/ /* Choctaw */ - {HB_TAG('c','h','p',' '), HB_TAG('C','H','P',' ')}, /* Chipewyan */ - {HB_TAG('c','h','p',' '), HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */ - {HB_TAG('c','h','p',' '), HB_TAG('A','T','H',' ')}, /* Chipewyan -> Athapaskan */ {HB_TAG('c','h','q',' '), HB_TAG('C','C','H','N')}, /* Quiotepec Chinantec -> Chinantec */ -/*{HB_TAG('c','h','r',' '), HB_TAG('C','H','R',' ')},*/ /* Cherokee */ -/*{HB_TAG('c','h','y',' '), HB_TAG('C','H','Y',' ')},*/ /* Cheyenne */ {HB_TAG('c','h','z',' '), HB_TAG('C','C','H','N')}, /* Ozumacín Chinantec -> Chinantec */ {HB_TAG('c','i','w',' '), HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */ -/*{HB_TAG('c','j','a',' '), HB_TAG('C','J','A',' ')},*/ /* Western Cham */ -/*{HB_TAG('c','j','m',' '), HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */ {HB_TAG('c','j','y',' '), HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese, Simplified */ {HB_TAG('c','k','a',' '), HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */ {HB_TAG('c','k','b',' '), HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */ @@ -474,7 +537,6 @@ static const LangTag ot_languages3[] = { {HB_TAG('c','l','j',' '), HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */ {HB_TAG('c','l','s',' '), HB_TAG('S','A','N',' ')}, /* Classical Sanskrit -> Sanskrit */ {HB_TAG('c','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */ -/*{HB_TAG('c','m','i',' '), HB_TAG('C','M','I',' ')},*/ /* Emberá-Chamí */ {HB_TAG('c','m','n',' '), HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */ {HB_TAG('c','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */ {HB_TAG('c','n','b',' '), HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */ @@ -488,120 +550,63 @@ static const LangTag ot_languages3[] = { {HB_TAG('c','n','w',' '), HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */ {HB_TAG('c','o','a',' '), HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */ {HB_TAG('c','o','b',' '), HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */ -/*{HB_TAG('c','o','o',' '), HB_TAG('C','O','O',' ')},*/ /* Comox */ -/*{HB_TAG('c','o','p',' '), HB_TAG('C','O','P',' ')},*/ /* Coptic */ {HB_TAG('c','o','q',' '), HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ {HB_TAG('c','p','a',' '), HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ {HB_TAG('c','p','e',' '), HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [collection] -> Creoles */ {HB_TAG('c','p','f',' '), HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [collection] -> Creoles */ {HB_TAG('c','p','i',' '), HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */ -/*{HB_TAG('c','p','p',' '), HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [collection] -> Creoles */ {HB_TAG('c','p','x',' '), HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */ {HB_TAG('c','q','d',' '), HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ - {HB_TAG('c','q','u',' '), HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ - {HB_TAG('c','q','u',' '), HB_TAG('Q','U','Z',' ')}, /* Chilean Quechua (retired code) -> Quechua */ {HB_TAG('c','r','h',' '), HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ {HB_TAG('c','r','i',' '), HB_TAG('C','P','P',' ')}, /* Sãotomense -> Creoles */ - {HB_TAG('c','r','j',' '), HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */ - {HB_TAG('c','r','j',' '), HB_TAG('Y','C','R',' ')}, /* Southern East Cree -> Y-Cree */ - {HB_TAG('c','r','j',' '), HB_TAG('C','R','E',' ')}, /* Southern East Cree -> Cree */ - {HB_TAG('c','r','k',' '), HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */ - {HB_TAG('c','r','k',' '), HB_TAG('Y','C','R',' ')}, /* Plains Cree -> Y-Cree */ - {HB_TAG('c','r','k',' '), HB_TAG('C','R','E',' ')}, /* Plains Cree -> Cree */ - {HB_TAG('c','r','l',' '), HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */ - {HB_TAG('c','r','l',' '), HB_TAG('Y','C','R',' ')}, /* Northern East Cree -> Y-Cree */ - {HB_TAG('c','r','l',' '), HB_TAG('C','R','E',' ')}, /* Northern East Cree -> Cree */ - {HB_TAG('c','r','m',' '), HB_TAG('M','C','R',' ')}, /* Moose Cree */ - {HB_TAG('c','r','m',' '), HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ - {HB_TAG('c','r','m',' '), HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */ {HB_TAG('c','r','p',' '), HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [collection] -> Creoles */ - {HB_TAG('c','r','r',' '), HB_TAG_NONE }, /* Carolina Algonquian != Carrier */ {HB_TAG('c','r','s',' '), HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */ - {HB_TAG('c','r','t',' '), HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */ - {HB_TAG('c','r','x',' '), HB_TAG('C','R','R',' ')}, /* Carrier */ - {HB_TAG('c','r','x',' '), HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */ {HB_TAG('c','s','a',' '), HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */ -/*{HB_TAG('c','s','b',' '), HB_TAG('C','S','B',' ')},*/ /* Kashubian */ {HB_TAG('c','s','h',' '), HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */ {HB_TAG('c','s','j',' '), HB_TAG('Q','I','N',' ')}, /* Songlai Chin -> Chin */ - {HB_TAG('c','s','l',' '), HB_TAG_NONE }, /* Chinese Sign Language != Church Slavonic */ {HB_TAG('c','s','o',' '), HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */ {HB_TAG('c','s','p',' '), HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese, Simplified */ {HB_TAG('c','s','v',' '), HB_TAG('Q','I','N',' ')}, /* Sumtu Chin -> Chin */ - {HB_TAG('c','s','w',' '), HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */ - {HB_TAG('c','s','w',' '), HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */ - {HB_TAG('c','s','w',' '), HB_TAG('C','R','E',' ')}, /* Swampy Cree -> Cree */ {HB_TAG('c','s','y',' '), HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */ {HB_TAG('c','t','c',' '), HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */ {HB_TAG('c','t','d',' '), HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */ {HB_TAG('c','t','e',' '), HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */ -/*{HB_TAG('c','t','g',' '), HB_TAG('C','T','G',' ')},*/ /* Chittagonian */ {HB_TAG('c','t','h',' '), HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */ {HB_TAG('c','t','l',' '), HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */ -/*{HB_TAG('c','t','o',' '), HB_TAG('C','T','O',' ')},*/ /* Emberá-Catío */ {HB_TAG('c','t','s',' '), HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */ -/*{HB_TAG('c','t','t',' '), HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */ {HB_TAG('c','t','u',' '), HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */ {HB_TAG('c','u','c',' '), HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */ -/*{HB_TAG('c','u','k',' '), HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */ {HB_TAG('c','v','n',' '), HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */ - {HB_TAG('c','w','d',' '), HB_TAG('D','C','R',' ')}, /* Woods Cree */ - {HB_TAG('c','w','d',' '), HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */ - {HB_TAG('c','w','d',' '), HB_TAG('C','R','E',' ')}, /* Woods Cree -> Cree */ {HB_TAG('c','z','h',' '), HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese, Simplified */ {HB_TAG('c','z','o',' '), HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */ {HB_TAG('c','z','t',' '), HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */ -/*{HB_TAG('d','a','g',' '), HB_TAG('D','A','G',' ')},*/ /* Dagbani */ {HB_TAG('d','a','o',' '), HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */ {HB_TAG('d','a','p',' '), HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */ -/*{HB_TAG('d','a','r',' '), HB_TAG('D','A','R',' ')},*/ /* Dargwa */ -/*{HB_TAG('d','a','x',' '), HB_TAG('D','A','X',' ')},*/ /* Dayi */ {HB_TAG('d','c','r',' '), HB_TAG('C','P','P',' ')}, /* Negerhollands -> Creoles */ - {HB_TAG('d','e','n',' '), HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ - {HB_TAG('d','e','n',' '), HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ {HB_TAG('d','e','p',' '), HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */ - {HB_TAG('d','g','o',' '), HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */ - {HB_TAG('d','g','o',' '), HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */ {HB_TAG('d','g','r',' '), HB_TAG('A','T','H',' ')}, /* Tlicho -> Athapaskan */ {HB_TAG('d','h','d',' '), HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */ -/*{HB_TAG('d','h','g',' '), HB_TAG('D','H','G',' ')},*/ /* Dhangu */ - {HB_TAG('d','h','v',' '), HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */ {HB_TAG('d','i','b',' '), HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */ {HB_TAG('d','i','k',' '), HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */ {HB_TAG('d','i','n',' '), HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ {HB_TAG('d','i','p',' '), HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */ - {HB_TAG('d','i','q',' '), HB_TAG('D','I','Q',' ')}, /* Dimli */ - {HB_TAG('d','i','q',' '), HB_TAG('Z','Z','A',' ')}, /* Dimli -> Zazaki */ {HB_TAG('d','i','w',' '), HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */ {HB_TAG('d','j','e',' '), HB_TAG('D','J','R',' ')}, /* Zarma */ {HB_TAG('d','j','k',' '), HB_TAG('C','P','P',' ')}, /* Eastern Maroon Creole -> Creoles */ {HB_TAG('d','j','r',' '), HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ {HB_TAG('d','k','s',' '), HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */ {HB_TAG('d','n','g',' '), HB_TAG('D','U','N',' ')}, /* Dungan */ -/*{HB_TAG('d','n','j',' '), HB_TAG('D','N','J',' ')},*/ /* Dan */ - {HB_TAG('d','n','k',' '), HB_TAG_NONE }, /* Dengka != Dinka */ {HB_TAG('d','o','i',' '), HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) [macrolanguage] */ {HB_TAG('d','r','h',' '), HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */ - {HB_TAG('d','r','i',' '), HB_TAG_NONE }, /* C'Lela != Dari */ - {HB_TAG('d','r','w',' '), HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */ - {HB_TAG('d','r','w',' '), HB_TAG('F','A','R',' ')}, /* Darwazi (retired code) -> Persian */ {HB_TAG('d','s','b',' '), HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ {HB_TAG('d','t','y',' '), HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */ -/*{HB_TAG('d','u','j',' '), HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */ - {HB_TAG('d','u','n',' '), HB_TAG_NONE }, /* Dusun Deyah != Dungan */ {HB_TAG('d','u','p',' '), HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */ {HB_TAG('d','w','k',' '), HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */ {HB_TAG('d','w','u',' '), HB_TAG('D','U','J',' ')}, /* Dhuwal */ {HB_TAG('d','w','y',' '), HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */ {HB_TAG('d','y','u',' '), HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */ - {HB_TAG('d','z','n',' '), HB_TAG_NONE }, /* Dzando != Dzongkha */ - {HB_TAG('e','c','r',' '), HB_TAG_NONE }, /* Eteocretan != Eastern Cree */ -/*{HB_TAG('e','f','i',' '), HB_TAG('E','F','I',' ')},*/ /* Efik */ {HB_TAG('e','k','k',' '), HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */ {HB_TAG('e','k','y',' '), HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */ - {HB_TAG('e','m','k',' '), HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */ - {HB_TAG('e','m','k',' '), HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */ -/*{HB_TAG('e','m','p',' '), HB_TAG('E','M','P',' ')},*/ /* Northern Emberá */ {HB_TAG('e','m','y',' '), HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */ {HB_TAG('e','n','b',' '), HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */ {HB_TAG('e','n','f',' '), HB_TAG('F','N','E',' ')}, /* Forest Enets */ @@ -609,52 +614,27 @@ static const LangTag ot_languages3[] = { {HB_TAG('e','s','g',' '), HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */ {HB_TAG('e','s','i',' '), HB_TAG('I','P','K',' ')}, /* North Alaskan Inupiatun -> Inupiat */ {HB_TAG('e','s','k',' '), HB_TAG('I','P','K',' ')}, /* Northwest Alaska Inupiatun -> Inupiat */ -/*{HB_TAG('e','s','u',' '), HB_TAG('E','S','U',' ')},*/ /* Central Yupik */ {HB_TAG('e','t','o',' '), HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ - {HB_TAG('e','u','q',' '), HB_TAG_NONE }, /* Basque [collection] != Basque */ {HB_TAG('e','v','e',' '), HB_TAG('E','V','N',' ')}, /* Even */ {HB_TAG('e','v','n',' '), HB_TAG('E','V','K',' ')}, /* Evenki */ {HB_TAG('e','w','o',' '), HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ {HB_TAG('e','y','o',' '), HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */ {HB_TAG('f','a','b',' '), HB_TAG('C','P','P',' ')}, /* Fa d'Ambu -> Creoles */ - {HB_TAG('f','a','n',' '), HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */ - {HB_TAG('f','a','n',' '), HB_TAG('B','T','I',' ')}, /* Fang (Equatorial Guinea) -> Beti */ - {HB_TAG('f','a','r',' '), HB_TAG_NONE }, /* Fataleka != Persian */ - {HB_TAG('f','a','t',' '), HB_TAG('F','A','T',' ')}, /* Fanti */ - {HB_TAG('f','a','t',' '), HB_TAG('A','K','A',' ')}, /* Fanti -> Akan */ {HB_TAG('f','b','l',' '), HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */ {HB_TAG('f','f','m',' '), HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */ {HB_TAG('f','i','l',' '), HB_TAG('P','I','L',' ')}, /* Filipino */ - {HB_TAG('f','l','m',' '), HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */ - {HB_TAG('f','l','m',' '), HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */ - {HB_TAG('f','m','p',' '), HB_TAG('F','M','P',' ')}, /* Fe’fe’ */ - {HB_TAG('f','m','p',' '), HB_TAG('B','M','L',' ')}, /* Fe'fe' -> Bamileke */ {HB_TAG('f','n','g',' '), HB_TAG('C','P','P',' ')}, /* Fanagalo -> Creoles */ -/*{HB_TAG('f','o','n',' '), HB_TAG('F','O','N',' ')},*/ /* Fon */ - {HB_TAG('f','o','s',' '), HB_TAG_NONE }, /* Siraya != Faroese */ {HB_TAG('f','p','e',' '), HB_TAG('C','P','P',' ')}, /* Fernando Po Creole English -> Creoles */ -/*{HB_TAG('f','r','c',' '), HB_TAG('F','R','C',' ')},*/ /* Cajun French */ -/*{HB_TAG('f','r','p',' '), HB_TAG('F','R','P',' ')},*/ /* Arpitan */ {HB_TAG('f','u','b',' '), HB_TAG('F','U','L',' ')}, /* Adamawa Fulfulde -> Fulah */ {HB_TAG('f','u','c',' '), HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */ {HB_TAG('f','u','e',' '), HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */ - {HB_TAG('f','u','f',' '), HB_TAG('F','T','A',' ')}, /* Pular -> Futa */ - {HB_TAG('f','u','f',' '), HB_TAG('F','U','L',' ')}, /* Pular -> Fulah */ {HB_TAG('f','u','h',' '), HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */ {HB_TAG('f','u','i',' '), HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */ {HB_TAG('f','u','q',' '), HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */ {HB_TAG('f','u','r',' '), HB_TAG('F','R','L',' ')}, /* Friulian */ - {HB_TAG('f','u','v',' '), HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ - {HB_TAG('f','u','v',' '), HB_TAG('F','U','L',' ')}, /* Nigerian Fulfulde -> Fulah */ {HB_TAG('g','a','a',' '), HB_TAG('G','A','D',' ')}, /* Ga */ {HB_TAG('g','a','c',' '), HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */ - {HB_TAG('g','a','d',' '), HB_TAG_NONE }, /* Gaddang != Ga */ - {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic */ -/*{HB_TAG('g','a','g',' '), HB_TAG('G','A','G',' ')},*/ /* Gagauz */ - {HB_TAG('g','a','l',' '), HB_TAG_NONE }, /* Galolen != Galician */ {HB_TAG('g','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */ - {HB_TAG('g','a','r',' '), HB_TAG_NONE }, /* Galeya != Garshuni */ - {HB_TAG('g','a','w',' '), HB_TAG_NONE }, /* Nobonob != Garhwali */ {HB_TAG('g','a','x',' '), HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */ {HB_TAG('g','a','z',' '), HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */ {HB_TAG('g','b','m',' '), HB_TAG('G','A','W',' ')}, /* Garhwali */ @@ -663,69 +643,46 @@ static const LangTag ot_languages3[] = { {HB_TAG('g','c','l',' '), HB_TAG('C','P','P',' ')}, /* Grenadian Creole English -> Creoles */ {HB_TAG('g','c','r',' '), HB_TAG('C','P','P',' ')}, /* Guianese Creole French -> Creoles */ {HB_TAG('g','d','a',' '), HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */ -/*{HB_TAG('g','e','z',' '), HB_TAG('G','E','Z',' ')},*/ /* Geez */ {HB_TAG('g','g','o',' '), HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */ {HB_TAG('g','h','a',' '), HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */ {HB_TAG('g','h','c',' '), HB_TAG('I','R','T',' ')}, /* Hiberno-Scottish Gaelic -> Irish Traditional */ {HB_TAG('g','h','k',' '), HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */ {HB_TAG('g','h','o',' '), HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */ {HB_TAG('g','i','b',' '), HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */ -/*{HB_TAG('g','i','h',' '), HB_TAG('G','I','H',' ')},*/ /* Githabul */ {HB_TAG('g','i','l',' '), HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ {HB_TAG('g','j','u',' '), HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */ - {HB_TAG('g','k','p',' '), HB_TAG('G','K','P',' ')}, /* Guinea Kpelle -> Kpelle (Guinea) */ - {HB_TAG('g','k','p',' '), HB_TAG('K','P','L',' ')}, /* Guinea Kpelle -> Kpelle */ {HB_TAG('g','l','d',' '), HB_TAG('N','A','N',' ')}, /* Nanai */ -/*{HB_TAG('g','l','k',' '), HB_TAG('G','L','K',' ')},*/ /* Gilaki */ - {HB_TAG('g','m','z',' '), HB_TAG_NONE }, /* Mgbolizhia != Gumuz */ {HB_TAG('g','n','b',' '), HB_TAG('Q','I','N',' ')}, /* Gangte -> Chin */ -/*{HB_TAG('g','n','n',' '), HB_TAG('G','N','N',' ')},*/ /* Gumatj */ {HB_TAG('g','n','o',' '), HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */ {HB_TAG('g','n','w',' '), HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaraní -> Guarani */ -/*{HB_TAG('g','o','g',' '), HB_TAG('G','O','G',' ')},*/ /* Gogo */ {HB_TAG('g','o','m',' '), HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */ -/*{HB_TAG('g','o','n',' '), HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */ {HB_TAG('g','o','q',' '), HB_TAG('C','P','P',' ')}, /* Gorap -> Creoles */ {HB_TAG('g','o','x',' '), HB_TAG('B','A','D','0')}, /* Gobu -> Banda */ {HB_TAG('g','p','e',' '), HB_TAG('C','P','P',' ')}, /* Ghanaian Pidgin English -> Creoles */ - {HB_TAG('g','r','o',' '), HB_TAG_NONE }, /* Groma != Garo */ {HB_TAG('g','r','r',' '), HB_TAG('B','B','R',' ')}, /* Taznatit -> Berber */ {HB_TAG('g','r','t',' '), HB_TAG('G','R','O',' ')}, /* Garo */ {HB_TAG('g','r','u',' '), HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */ {HB_TAG('g','s','w',' '), HB_TAG('A','L','S',' ')}, /* Alsatian */ - {HB_TAG('g','u','a',' '), HB_TAG_NONE }, /* Shiki != Guarani */ -/*{HB_TAG('g','u','c',' '), HB_TAG('G','U','C',' ')},*/ /* Wayuu */ -/*{HB_TAG('g','u','f',' '), HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */ {HB_TAG('g','u','g',' '), HB_TAG('G','U','A',' ')}, /* Paraguayan Guaraní -> Guarani */ {HB_TAG('g','u','i',' '), HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaraní -> Guarani */ {HB_TAG('g','u','k',' '), HB_TAG('G','M','Z',' ')}, /* Gumuz */ {HB_TAG('g','u','l',' '), HB_TAG('C','P','P',' ')}, /* Sea Island Creole English -> Creoles */ {HB_TAG('g','u','n',' '), HB_TAG('G','U','A',' ')}, /* Mbyá Guaraní -> Guarani */ -/*{HB_TAG('g','u','z',' '), HB_TAG('G','U','Z',' ')},*/ /* Gusii */ {HB_TAG('g','w','i',' '), HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ {HB_TAG('g','y','n',' '), HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */ {HB_TAG('h','a','a',' '), HB_TAG('A','T','H',' ')}, /* Hän -> Athapaskan */ {HB_TAG('h','a','e',' '), HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ {HB_TAG('h','a','i',' '), HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */ {HB_TAG('h','a','k',' '), HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */ - {HB_TAG('h','a','l',' '), HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */ {HB_TAG('h','a','r',' '), HB_TAG('H','R','I',' ')}, /* Harari */ -/*{HB_TAG('h','a','w',' '), HB_TAG('H','A','W',' ')},*/ /* Hawaiian */ {HB_TAG('h','a','x',' '), HB_TAG('H','A','I','0')}, /* Southern Haida -> Haida */ -/*{HB_TAG('h','a','y',' '), HB_TAG('H','A','Y',' ')},*/ /* Haya */ -/*{HB_TAG('h','a','z',' '), HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */ - {HB_TAG('h','b','n',' '), HB_TAG_NONE }, /* Heiban != Hammer-Banna */ {HB_TAG('h','c','a',' '), HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */ {HB_TAG('h','d','n',' '), HB_TAG('H','A','I','0')}, /* Northern Haida -> Haida */ {HB_TAG('h','e','a',' '), HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */ -/*{HB_TAG('h','e','i',' '), HB_TAG('H','E','I',' ')},*/ /* Heiltsuk */ -/*{HB_TAG('h','i','l',' '), HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */ {HB_TAG('h','j','i',' '), HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */ {HB_TAG('h','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */ {HB_TAG('h','m','a',' '), HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */ {HB_TAG('h','m','c',' '), HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */ - {HB_TAG('h','m','d',' '), HB_TAG('H','M','D',' ')}, /* Large Flowery Miao -> A-Hmao */ - {HB_TAG('h','m','d',' '), HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */ {HB_TAG('h','m','e',' '), HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */ {HB_TAG('h','m','g',' '), HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */ {HB_TAG('h','m','h',' '), HB_TAG('H','M','N',' ')}, /* Southwestern Huishui Hmong -> Hmong */ @@ -733,36 +690,27 @@ static const LangTag ot_languages3[] = { {HB_TAG('h','m','j',' '), HB_TAG('H','M','N',' ')}, /* Ge -> Hmong */ {HB_TAG('h','m','l',' '), HB_TAG('H','M','N',' ')}, /* Luopohe Hmong -> Hmong */ {HB_TAG('h','m','m',' '), HB_TAG('H','M','N',' ')}, /* Central Mashan Hmong -> Hmong */ -/*{HB_TAG('h','m','n',' '), HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */ {HB_TAG('h','m','p',' '), HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */ {HB_TAG('h','m','q',' '), HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */ {HB_TAG('h','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Hmar -> Chin */ {HB_TAG('h','m','s',' '), HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */ {HB_TAG('h','m','w',' '), HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */ {HB_TAG('h','m','y',' '), HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */ - {HB_TAG('h','m','z',' '), HB_TAG('H','M','Z',' ')}, /* Hmong Shua -> Hmong Shuat */ - {HB_TAG('h','m','z',' '), HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */ -/*{HB_TAG('h','n','d',' '), HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */ {HB_TAG('h','n','e',' '), HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */ {HB_TAG('h','n','j',' '), HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ {HB_TAG('h','n','m',' '), HB_TAG('Z','H','S',' ')}, /* Hainanese -> Chinese, Simplified */ {HB_TAG('h','n','o',' '), HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ {HB_TAG('h','o','c',' '), HB_TAG('H','O',' ',' ')}, /* Ho */ {HB_TAG('h','o','i',' '), HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ - {HB_TAG('h','o','j',' '), HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */ - {HB_TAG('h','o','j',' '), HB_TAG('R','A','J',' ')}, /* Hadothi -> Rajasthani */ {HB_TAG('h','r','a',' '), HB_TAG('Q','I','N',' ')}, /* Hrangkhol -> Chin */ {HB_TAG('h','r','m',' '), HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */ {HB_TAG('h','s','b',' '), HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ {HB_TAG('h','s','n',' '), HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */ {HB_TAG('h','u','j',' '), HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */ {HB_TAG('h','u','p',' '), HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */ -/*{HB_TAG('h','u','r',' '), HB_TAG('H','U','R',' ')},*/ /* Halkomelem */ {HB_TAG('h','u','s',' '), HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */ {HB_TAG('h','w','c',' '), HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */ {HB_TAG('h','y','w',' '), HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */ -/*{HB_TAG('i','b','a',' '), HB_TAG('I','B','A',' ')},*/ /* Iban */ -/*{HB_TAG('i','b','b',' '), HB_TAG('I','B','B',' ')},*/ /* Ibibio */ {HB_TAG('i','b','y',' '), HB_TAG('I','J','O',' ')}, /* Ibani -> Ijo */ {HB_TAG('i','c','r',' '), HB_TAG('C','P','P',' ')}, /* Islander Creole English -> Creoles */ {HB_TAG('i','d','a',' '), HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */ @@ -772,156 +720,71 @@ static const LangTag ot_languages3[] = { {HB_TAG('i','j','c',' '), HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ {HB_TAG('i','j','e',' '), HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */ {HB_TAG('i','j','n',' '), HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */ -/*{HB_TAG('i','j','o',' '), HB_TAG('I','J','O',' ')},*/ /* Ijo [collection] */ {HB_TAG('i','j','s',' '), HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */ - {HB_TAG('i','k','e',' '), HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ - {HB_TAG('i','k','e',' '), HB_TAG('I','N','U','K')}, /* Eastern Canadian Inuktitut -> Nunavik Inuktitut */ {HB_TAG('i','k','t',' '), HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ -/*{HB_TAG('i','l','o',' '), HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ {HB_TAG('i','n','g',' '), HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */ {HB_TAG('i','n','h',' '), HB_TAG('I','N','G',' ')}, /* Ingush */ - {HB_TAG('i','r','i',' '), HB_TAG_NONE }, /* Rigwe != Irish */ -/*{HB_TAG('i','r','u',' '), HB_TAG('I','R','U',' ')},*/ /* Irula */ - {HB_TAG('i','s','m',' '), HB_TAG_NONE }, /* Masimasi != Inari Sami */ {HB_TAG('i','t','z',' '), HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */ {HB_TAG('i','x','l',' '), HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */ {HB_TAG('j','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Popti' -> Mayan */ {HB_TAG('j','a','k',' '), HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */ - {HB_TAG('j','a','m',' '), HB_TAG('J','A','M',' ')}, /* Jamaican Creole English -> Jamaican Creole */ - {HB_TAG('j','a','m',' '), HB_TAG('C','P','P',' ')}, /* Jamaican Creole English -> Creoles */ - {HB_TAG('j','a','n',' '), HB_TAG_NONE }, /* Jandai != Japanese */ {HB_TAG('j','a','x',' '), HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */ {HB_TAG('j','b','e',' '), HB_TAG('B','B','R',' ')}, /* Judeo-Berber -> Berber */ {HB_TAG('j','b','n',' '), HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */ -/*{HB_TAG('j','b','o',' '), HB_TAG('J','B','O',' ')},*/ /* Lojban */ -/*{HB_TAG('j','c','t',' '), HB_TAG('J','C','T',' ')},*/ /* Krymchak */ -/*{HB_TAG('j','d','t',' '), HB_TAG('J','D','T',' ')},*/ /* Judeo-Tat */ {HB_TAG('j','g','o',' '), HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */ - {HB_TAG('j','i','i',' '), HB_TAG_NONE }, /* Jiiddu != Yiddish */ {HB_TAG('j','k','m',' '), HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */ {HB_TAG('j','k','p',' '), HB_TAG('K','R','N',' ')}, /* Paku Karen -> Karen */ - {HB_TAG('j','u','d',' '), HB_TAG_NONE }, /* Worodougou != Ladino */ - {HB_TAG('j','u','l',' '), HB_TAG_NONE }, /* Jirel != Jula */ {HB_TAG('j','v','d',' '), HB_TAG('C','P','P',' ')}, /* Javindo -> Creoles */ {HB_TAG('k','a','a',' '), HB_TAG('K','R','K',' ')}, /* Karakalpak */ - {HB_TAG('k','a','b',' '), HB_TAG('K','A','B','0')}, /* Kabyle */ - {HB_TAG('k','a','b',' '), HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */ - {HB_TAG('k','a','c',' '), HB_TAG_NONE }, /* Kachin != Kachchi */ {HB_TAG('k','a','m',' '), HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ {HB_TAG('k','a','r',' '), HB_TAG('K','R','N',' ')}, /* Karen [collection] */ -/*{HB_TAG('k','a','w',' '), HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */ -/*{HB_TAG('k','b','c',' '), HB_TAG('K','B','C',' ')},*/ /* Kadiwéu */ {HB_TAG('k','b','d',' '), HB_TAG('K','A','B',' ')}, /* Kabardian */ {HB_TAG('k','b','y',' '), HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */ - {HB_TAG('k','c','a',' '), HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */ - {HB_TAG('k','c','a',' '), HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */ - {HB_TAG('k','c','a',' '), HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */ {HB_TAG('k','c','n',' '), HB_TAG('C','P','P',' ')}, /* Nubi -> Creoles */ -/*{HB_TAG('k','d','e',' '), HB_TAG('K','D','E',' ')},*/ /* Makonde */ {HB_TAG('k','d','r',' '), HB_TAG('K','R','M',' ')}, /* Karaim */ {HB_TAG('k','d','t',' '), HB_TAG('K','U','Y',' ')}, /* Kuy */ - {HB_TAG('k','e','a',' '), HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ - {HB_TAG('k','e','a',' '), HB_TAG('C','P','P',' ')}, /* Kabuverdianu -> Creoles */ - {HB_TAG('k','e','b',' '), HB_TAG_NONE }, /* Kélé != Kebena */ - {HB_TAG('k','e','k',' '), HB_TAG('K','E','K',' ')}, /* Kekchi */ - {HB_TAG('k','e','k',' '), HB_TAG('M','Y','N',' ')}, /* Kekchí -> Mayan */ {HB_TAG('k','e','x',' '), HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */ {HB_TAG('k','f','a',' '), HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */ {HB_TAG('k','f','r',' '), HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */ {HB_TAG('k','f','x',' '), HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */ {HB_TAG('k','f','y',' '), HB_TAG('K','M','N',' ')}, /* Kumaoni */ - {HB_TAG('k','g','e',' '), HB_TAG_NONE }, /* Komering != Khutsuri Georgian */ -/*{HB_TAG('k','g','f',' '), HB_TAG('K','G','F',' ')},*/ /* Kube */ {HB_TAG('k','h','a',' '), HB_TAG('K','S','I',' ')}, /* Khasi */ {HB_TAG('k','h','b',' '), HB_TAG('X','B','D',' ')}, /* Lü */ {HB_TAG('k','h','k',' '), HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */ - {HB_TAG('k','h','n',' '), HB_TAG_NONE }, /* Khandesi != Khamti Shan (Microsoft fonts) */ - {HB_TAG('k','h','s',' '), HB_TAG_NONE }, /* Kasua != Khanty-Shurishkar */ - {HB_TAG('k','h','t',' '), HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan */ - {HB_TAG('k','h','t',' '), HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */ - {HB_TAG('k','h','v',' '), HB_TAG_NONE }, /* Khvarshi != Khanty-Vakhi */ -/*{HB_TAG('k','h','w',' '), HB_TAG('K','H','W',' ')},*/ /* Khowar */ - {HB_TAG('k','i','s',' '), HB_TAG_NONE }, /* Kis != Kisii */ - {HB_TAG('k','i','u',' '), HB_TAG('K','I','U',' ')}, /* Kirmanjki */ - {HB_TAG('k','i','u',' '), HB_TAG('Z','Z','A',' ')}, /* Kirmanjki -> Zazaki */ {HB_TAG('k','j','b',' '), HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */ -/*{HB_TAG('k','j','d',' '), HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */ {HB_TAG('k','j','h',' '), HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */ -/*{HB_TAG('k','j','j',' '), HB_TAG('K','J','J',' ')},*/ /* Khinalugh -> Khinalug */ - {HB_TAG('k','j','p',' '), HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ - {HB_TAG('k','j','p',' '), HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */ {HB_TAG('k','j','t',' '), HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */ -/*{HB_TAG('k','j','z',' '), HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */ - {HB_TAG('k','k','n',' '), HB_TAG_NONE }, /* Kon Keu != Kokni */ {HB_TAG('k','k','z',' '), HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */ - {HB_TAG('k','l','m',' '), HB_TAG_NONE }, /* Migum != Kalmyk */ {HB_TAG('k','l','n',' '), HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */ {HB_TAG('k','m','b',' '), HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */ -/*{HB_TAG('k','m','g',' '), HB_TAG('K','M','G',' ')},*/ /* Kâte */ - {HB_TAG('k','m','n',' '), HB_TAG_NONE }, /* Awtuw != Kumaoni */ - {HB_TAG('k','m','o',' '), HB_TAG_NONE }, /* Kwoma != Komo */ {HB_TAG('k','m','r',' '), HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */ - {HB_TAG('k','m','s',' '), HB_TAG_NONE }, /* Kamasau != Komso */ {HB_TAG('k','m','v',' '), HB_TAG('C','P','P',' ')}, /* Karipúna Creole French -> Creoles */ {HB_TAG('k','m','w',' '), HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ -/*{HB_TAG('k','m','z',' '), HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */ {HB_TAG('k','n','c',' '), HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */ {HB_TAG('k','n','g',' '), HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */ {HB_TAG('k','n','j',' '), HB_TAG('M','Y','N',' ')}, /* Western Kanjobal -> Mayan */ {HB_TAG('k','n','n',' '), HB_TAG('K','O','K',' ')}, /* Konkani */ - {HB_TAG('k','n','r',' '), HB_TAG_NONE }, /* Kaningra != Kanuri */ - {HB_TAG('k','o','d',' '), HB_TAG_NONE }, /* Kodi != Kodagu */ - {HB_TAG('k','o','h',' '), HB_TAG_NONE }, /* Koyo != Korean Old Hangul */ - {HB_TAG('k','o','i',' '), HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ - {HB_TAG('k','o','i',' '), HB_TAG('K','O','M',' ')}, /* Komi-Permyak -> Komi */ -/*{HB_TAG('k','o','k',' '), HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */ - {HB_TAG('k','o','p',' '), HB_TAG_NONE }, /* Waube != Komi-Permyak */ -/*{HB_TAG('k','o','s',' '), HB_TAG('K','O','S',' ')},*/ /* Kosraean */ {HB_TAG('k','o','y',' '), HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */ - {HB_TAG('k','o','z',' '), HB_TAG_NONE }, /* Korak != Komi-Zyrian */ {HB_TAG('k','p','e',' '), HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ - {HB_TAG('k','p','l',' '), HB_TAG_NONE }, /* Kpala != Kpelle */ {HB_TAG('k','p','p',' '), HB_TAG('K','R','N',' ')}, /* Paku Karen (retired code) -> Karen */ - {HB_TAG('k','p','v',' '), HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ - {HB_TAG('k','p','v',' '), HB_TAG('K','O','M',' ')}, /* Komi-Zyrian -> Komi */ {HB_TAG('k','p','y',' '), HB_TAG('K','Y','K',' ')}, /* Koryak */ {HB_TAG('k','q','s',' '), HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */ {HB_TAG('k','q','y',' '), HB_TAG('K','R','T',' ')}, /* Koorete */ - {HB_TAG('k','r','c',' '), HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */ - {HB_TAG('k','r','c',' '), HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */ - {HB_TAG('k','r','i',' '), HB_TAG('K','R','I',' ')}, /* Krio */ - {HB_TAG('k','r','i',' '), HB_TAG('C','P','P',' ')}, /* Krio -> Creoles */ - {HB_TAG('k','r','k',' '), HB_TAG_NONE }, /* Kerek != Karakalpak */ -/*{HB_TAG('k','r','l',' '), HB_TAG('K','R','L',' ')},*/ /* Karelian */ - {HB_TAG('k','r','m',' '), HB_TAG_NONE }, /* Krim (retired code) != Karaim */ - {HB_TAG('k','r','n',' '), HB_TAG_NONE }, /* Sapo != Karen */ {HB_TAG('k','r','t',' '), HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */ {HB_TAG('k','r','u',' '), HB_TAG('K','U','U',' ')}, /* Kurukh */ {HB_TAG('k','s','h',' '), HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */ - {HB_TAG('k','s','i',' '), HB_TAG_NONE }, /* Krisa != Khasi */ - {HB_TAG('k','s','m',' '), HB_TAG_NONE }, /* Kumba != Kildin Sami */ {HB_TAG('k','s','s',' '), HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */ -/*{HB_TAG('k','s','u',' '), HB_TAG('K','S','U',' ')},*/ /* Khamyang */ - {HB_TAG('k','s','w',' '), HB_TAG('K','S','W',' ')}, /* S’gaw Karen */ - {HB_TAG('k','s','w',' '), HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */ {HB_TAG('k','t','b',' '), HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */ {HB_TAG('k','t','u',' '), HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ {HB_TAG('k','t','w',' '), HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */ - {HB_TAG('k','u','i',' '), HB_TAG_NONE }, /* Kuikúro-Kalapálo != Kui */ - {HB_TAG('k','u','l',' '), HB_TAG_NONE }, /* Kulere != Kulvi */ -/*{HB_TAG('k','u','m',' '), HB_TAG('K','U','M',' ')},*/ /* Kumyk */ {HB_TAG('k','u','u',' '), HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */ {HB_TAG('k','u','w',' '), HB_TAG('B','A','D','0')}, /* Kpagua -> Banda */ - {HB_TAG('k','u','y',' '), HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */ {HB_TAG('k','v','b',' '), HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */ {HB_TAG('k','v','l',' '), HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */ - {HB_TAG('k','v','q',' '), HB_TAG('K','V','Q',' ')}, /* Geba Karen */ - {HB_TAG('k','v','q',' '), HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */ {HB_TAG('k','v','r',' '), HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */ {HB_TAG('k','v','t',' '), HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */ {HB_TAG('k','v','u',' '), HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */ {HB_TAG('k','v','y',' '), HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */ -/*{HB_TAG('k','w','k',' '), HB_TAG('K','W','K',' ')},*/ /* Kwakʼwala */ {HB_TAG('k','w','w',' '), HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */ {HB_TAG('k','w','y',' '), HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ {HB_TAG('k','x','c',' '), HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ @@ -930,195 +793,98 @@ static const LangTag ot_languages3[] = { {HB_TAG('k','x','k',' '), HB_TAG('K','R','N',' ')}, /* Zayein Karen -> Karen */ {HB_TAG('k','x','l',' '), HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */ {HB_TAG('k','x','u',' '), HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */ - {HB_TAG('k','y','k',' '), HB_TAG_NONE }, /* Kamayo != Koryak */ - {HB_TAG('k','y','u',' '), HB_TAG('K','Y','U',' ')}, /* Western Kayah */ - {HB_TAG('k','y','u',' '), HB_TAG('K','R','N',' ')}, /* Western Kayah -> Karen */ {HB_TAG('l','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Lacandon -> Mayan */ {HB_TAG('l','a','d',' '), HB_TAG('J','U','D',' ')}, /* Ladino */ - {HB_TAG('l','a','h',' '), HB_TAG_NONE }, /* Lahnda [macrolanguage] != Lahuli */ - {HB_TAG('l','a','k',' '), HB_TAG_NONE }, /* Laka (Nigeria) (retired code) != Lak */ - {HB_TAG('l','a','m',' '), HB_TAG_NONE }, /* Lamba != Lambani */ - {HB_TAG('l','a','z',' '), HB_TAG_NONE }, /* Aribwatsa != Laz */ {HB_TAG('l','b','e',' '), HB_TAG('L','A','K',' ')}, /* Lak */ {HB_TAG('l','b','j',' '), HB_TAG('L','D','K',' ')}, /* Ladakhi */ {HB_TAG('l','b','l',' '), HB_TAG('B','I','K',' ')}, /* Libon Bikol -> Bikol */ {HB_TAG('l','c','e',' '), HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */ {HB_TAG('l','c','f',' '), HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */ {HB_TAG('l','d','i',' '), HB_TAG('K','O','N','0')}, /* Laari -> Kongo */ - {HB_TAG('l','d','k',' '), HB_TAG_NONE }, /* Leelau != Ladakhi */ -/*{HB_TAG('l','e','f',' '), HB_TAG('L','E','F',' ')},*/ /* Lelemi */ -/*{HB_TAG('l','e','z',' '), HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */ {HB_TAG('l','i','f',' '), HB_TAG('L','M','B',' ')}, /* Limbu */ -/*{HB_TAG('l','i','j',' '), HB_TAG('L','I','J',' ')},*/ /* Ligurian */ {HB_TAG('l','i','r',' '), HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */ -/*{HB_TAG('l','i','s',' '), HB_TAG('L','I','S',' ')},*/ /* Lisu */ -/*{HB_TAG('l','i','v',' '), HB_TAG('L','I','V',' ')},*/ /* Liv */ {HB_TAG('l','i','w',' '), HB_TAG('M','L','Y',' ')}, /* Col -> Malay */ {HB_TAG('l','i','y',' '), HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */ -/*{HB_TAG('l','j','p',' '), HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */ {HB_TAG('l','k','b',' '), HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */ -/*{HB_TAG('l','k','i',' '), HB_TAG('L','K','I',' ')},*/ /* Laki */ {HB_TAG('l','k','o',' '), HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */ {HB_TAG('l','k','s',' '), HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */ {HB_TAG('l','l','d',' '), HB_TAG('L','A','D',' ')}, /* Ladin */ - {HB_TAG('l','m','a',' '), HB_TAG_NONE }, /* East Limba != Low Mari */ - {HB_TAG('l','m','b',' '), HB_TAG_NONE }, /* Merei != Limbu */ {HB_TAG('l','m','n',' '), HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */ -/*{HB_TAG('l','m','o',' '), HB_TAG('L','M','O',' ')},*/ /* Lombard */ - {HB_TAG('l','m','w',' '), HB_TAG_NONE }, /* Lake Miwok != Lomwe */ {HB_TAG('l','n','a',' '), HB_TAG('B','A','D','0')}, /* Langbashe -> Banda */ {HB_TAG('l','n','l',' '), HB_TAG('B','A','D','0')}, /* South Central Banda -> Banda */ -/*{HB_TAG('l','o','m',' '), HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */ {HB_TAG('l','o','u',' '), HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */ -/*{HB_TAG('l','p','o',' '), HB_TAG('L','P','O',' ')},*/ /* Lipo */ -/*{HB_TAG('l','r','c',' '), HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */ {HB_TAG('l','r','i',' '), HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */ {HB_TAG('l','r','m',' '), HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */ {HB_TAG('l','r','t',' '), HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */ - {HB_TAG('l','s','b',' '), HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */ {HB_TAG('l','s','m',' '), HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */ {HB_TAG('l','t','g',' '), HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */ - {HB_TAG('l','t','h',' '), HB_TAG_NONE }, /* Thur != Lithuanian */ {HB_TAG('l','t','o',' '), HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ {HB_TAG('l','t','s',' '), HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ -/*{HB_TAG('l','u','a',' '), HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ {HB_TAG('l','u','h',' '), HB_TAG('Z','H','S',' ')}, /* Leizhou Chinese -> Chinese, Simplified */ -/*{HB_TAG('l','u','o',' '), HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ - {HB_TAG('l','u','s',' '), HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ - {HB_TAG('l','u','s',' '), HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */ -/*{HB_TAG('l','u','t',' '), HB_TAG('L','U','T',' ')},*/ /* Lushootseed */ {HB_TAG('l','u','y',' '), HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ {HB_TAG('l','u','z',' '), HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ - {HB_TAG('l','v','i',' '), HB_TAG_NONE }, /* Lavi != Latvian */ {HB_TAG('l','v','s',' '), HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */ {HB_TAG('l','w','g',' '), HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */ {HB_TAG('l','z','h',' '), HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese, Traditional */ {HB_TAG('l','z','z',' '), HB_TAG('L','A','Z',' ')}, /* Laz */ -/*{HB_TAG('m','a','d',' '), HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */ -/*{HB_TAG('m','a','g',' '), HB_TAG('M','A','G',' ')},*/ /* Magahi */ {HB_TAG('m','a','i',' '), HB_TAG('M','T','H',' ')}, /* Maithili */ - {HB_TAG('m','a','j',' '), HB_TAG_NONE }, /* Jalapa De Díaz Mazatec != Majang */ {HB_TAG('m','a','k',' '), HB_TAG('M','K','R',' ')}, /* Makasar */ - {HB_TAG('m','a','m',' '), HB_TAG('M','A','M',' ')}, /* Mam */ - {HB_TAG('m','a','m',' '), HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */ {HB_TAG('m','a','n',' '), HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ - {HB_TAG('m','a','p',' '), HB_TAG_NONE }, /* Austronesian [collection] != Mapudungun */ - {HB_TAG('m','a','w',' '), HB_TAG_NONE }, /* Mampruli != Marwari */ - {HB_TAG('m','a','x',' '), HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ - {HB_TAG('m','a','x',' '), HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */ {HB_TAG('m','b','f',' '), HB_TAG('C','P','P',' ')}, /* Baba Malay -> Creoles */ - {HB_TAG('m','b','n',' '), HB_TAG_NONE }, /* Macaguán != Mbundu */ -/*{HB_TAG('m','b','o',' '), HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */ - {HB_TAG('m','c','h',' '), HB_TAG_NONE }, /* Maquiritari != Manchu */ {HB_TAG('m','c','m',' '), HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */ - {HB_TAG('m','c','r',' '), HB_TAG_NONE }, /* Menya != Moose Cree */ {HB_TAG('m','c','t',' '), HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ - {HB_TAG('m','d','e',' '), HB_TAG_NONE }, /* Maba (Chad) != Mende */ {HB_TAG('m','d','f',' '), HB_TAG('M','O','K',' ')}, /* Moksha */ -/*{HB_TAG('m','d','r',' '), HB_TAG('M','D','R',' ')},*/ /* Mandar */ {HB_TAG('m','d','y',' '), HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ {HB_TAG('m','e','n',' '), HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ {HB_TAG('m','e','o',' '), HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */ -/*{HB_TAG('m','e','r',' '), HB_TAG('M','E','R',' ')},*/ /* Meru */ -/*{HB_TAG('m','e','v',' '), HB_TAG('M','E','V',' ')},*/ /* Mano */ - {HB_TAG('m','f','a',' '), HB_TAG('M','F','A',' ')}, /* Pattani Malay */ - {HB_TAG('m','f','a',' '), HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */ {HB_TAG('m','f','b',' '), HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ - {HB_TAG('m','f','e',' '), HB_TAG('M','F','E',' ')}, /* Morisyen */ - {HB_TAG('m','f','e',' '), HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */ {HB_TAG('m','f','p',' '), HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */ {HB_TAG('m','g','a',' '), HB_TAG('S','G','A',' ')}, /* Middle Irish (900-1200) -> Old Irish */ {HB_TAG('m','h','c',' '), HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */ {HB_TAG('m','h','r',' '), HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */ {HB_TAG('m','h','v',' '), HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */ - {HB_TAG('m','i','n',' '), HB_TAG('M','I','N',' ')}, /* Minangkabau */ - {HB_TAG('m','i','n',' '), HB_TAG('M','L','Y',' ')}, /* Minangkabau -> Malay */ - {HB_TAG('m','i','z',' '), HB_TAG_NONE }, /* Coatzospan Mixtec != Mizo */ {HB_TAG('m','k','n',' '), HB_TAG('C','P','P',' ')}, /* Kupang Malay -> Creoles */ - {HB_TAG('m','k','r',' '), HB_TAG_NONE }, /* Malas != Makasar */ {HB_TAG('m','k','u',' '), HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */ -/*{HB_TAG('m','k','w',' '), HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */ - {HB_TAG('m','l','e',' '), HB_TAG_NONE }, /* Manambu != Male */ - {HB_TAG('m','l','n',' '), HB_TAG_NONE }, /* Malango != Malinke */ - {HB_TAG('m','l','q',' '), HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */ - {HB_TAG('m','l','q',' '), HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */ - {HB_TAG('m','l','r',' '), HB_TAG_NONE }, /* Vame != Malayalam Reformed */ {HB_TAG('m','m','r',' '), HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */ {HB_TAG('m','n','c',' '), HB_TAG('M','C','H',' ')}, /* Manchu */ - {HB_TAG('m','n','d',' '), HB_TAG_NONE }, /* Mondé != Mandinka */ - {HB_TAG('m','n','g',' '), HB_TAG_NONE }, /* Eastern Mnong != Mongolian */ {HB_TAG('m','n','h',' '), HB_TAG('B','A','D','0')}, /* Mono (Democratic Republic of Congo) -> Banda */ -/*{HB_TAG('m','n','i',' '), HB_TAG('M','N','I',' ')},*/ /* Manipuri */ - {HB_TAG('m','n','k',' '), HB_TAG('M','N','D',' ')}, /* Mandinka */ - {HB_TAG('m','n','k',' '), HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */ {HB_TAG('m','n','p',' '), HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */ {HB_TAG('m','n','s',' '), HB_TAG('M','A','N',' ')}, /* Mansi */ - {HB_TAG('m','n','w',' '), HB_TAG('M','O','N',' ')}, /* Mon */ - {HB_TAG('m','n','w',' '), HB_TAG('M','O','N','T')}, /* Mon -> Thailand Mon */ - {HB_TAG('m','n','x',' '), HB_TAG_NONE }, /* Manikion != Manx */ {HB_TAG('m','o','d',' '), HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */ -/*{HB_TAG('m','o','h',' '), HB_TAG('M','O','H',' ')},*/ /* Mohawk */ - {HB_TAG('m','o','k',' '), HB_TAG_NONE }, /* Morori != Moksha */ {HB_TAG('m','o','p',' '), HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */ - {HB_TAG('m','o','r',' '), HB_TAG_NONE }, /* Moro != Moroccan */ -/*{HB_TAG('m','o','s',' '), HB_TAG('M','O','S',' ')},*/ /* Mossi */ {HB_TAG('m','p','e',' '), HB_TAG('M','A','J',' ')}, /* Majang */ {HB_TAG('m','q','g',' '), HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */ {HB_TAG('m','r','h',' '), HB_TAG('Q','I','N',' ')}, /* Mara Chin -> Chin */ {HB_TAG('m','r','j',' '), HB_TAG('H','M','A',' ')}, /* Western Mari -> High Mari */ {HB_TAG('m','s','c',' '), HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */ {HB_TAG('m','s','h',' '), HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */ - {HB_TAG('m','s','i',' '), HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */ - {HB_TAG('m','s','i',' '), HB_TAG('C','P','P',' ')}, /* Sabah Malay -> Creoles */ - {HB_TAG('m','t','h',' '), HB_TAG_NONE }, /* Munggui != Maithili */ {HB_TAG('m','t','r',' '), HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */ - {HB_TAG('m','t','s',' '), HB_TAG_NONE }, /* Yora != Maltese */ {HB_TAG('m','u','d',' '), HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */ {HB_TAG('m','u','i',' '), HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ - {HB_TAG('m','u','n',' '), HB_TAG_NONE }, /* Munda [collection] != Mundari */ {HB_TAG('m','u','p',' '), HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ {HB_TAG('m','u','q',' '), HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ -/*{HB_TAG('m','u','s',' '), HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ {HB_TAG('m','v','b',' '), HB_TAG('A','T','H',' ')}, /* Mattole -> Athapaskan */ {HB_TAG('m','v','e',' '), HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ {HB_TAG('m','v','f',' '), HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */ {HB_TAG('m','w','k',' '), HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */ -/*{HB_TAG('m','w','l',' '), HB_TAG('M','W','L',' ')},*/ /* Mirandese */ {HB_TAG('m','w','q',' '), HB_TAG('Q','I','N',' ')}, /* Mün Chin -> Chin */ {HB_TAG('m','w','r',' '), HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ - {HB_TAG('m','w','w',' '), HB_TAG('M','W','W',' ')}, /* Hmong Daw */ - {HB_TAG('m','w','w',' '), HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */ {HB_TAG('m','y','m',' '), HB_TAG('M','E','N',' ')}, /* Me’en */ -/*{HB_TAG('m','y','n',' '), HB_TAG('M','Y','N',' ')},*/ /* Mayan [collection] */ {HB_TAG('m','y','q',' '), HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ {HB_TAG('m','y','v',' '), HB_TAG('E','R','Z',' ')}, /* Erzya */ {HB_TAG('m','z','b',' '), HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */ -/*{HB_TAG('m','z','n',' '), HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */ {HB_TAG('m','z','s',' '), HB_TAG('C','P','P',' ')}, /* Macanese -> Creoles */ - {HB_TAG('n','a','g',' '), HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */ - {HB_TAG('n','a','g',' '), HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */ -/*{HB_TAG('n','a','h',' '), HB_TAG('N','A','H',' ')},*/ /* Nahuatl [collection] */ {HB_TAG('n','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */ -/*{HB_TAG('n','a','p',' '), HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ - {HB_TAG('n','a','s',' '), HB_TAG_NONE }, /* Naasioi != Naskapi */ {HB_TAG('n','a','z',' '), HB_TAG('N','A','H',' ')}, /* Coatepec Nahuatl -> Nahuatl */ {HB_TAG('n','c','h',' '), HB_TAG('N','A','H',' ')}, /* Central Huasteca Nahuatl -> Nahuatl */ {HB_TAG('n','c','i',' '), HB_TAG('N','A','H',' ')}, /* Classical Nahuatl -> Nahuatl */ {HB_TAG('n','c','j',' '), HB_TAG('N','A','H',' ')}, /* Northern Puebla Nahuatl -> Nahuatl */ {HB_TAG('n','c','l',' '), HB_TAG('N','A','H',' ')}, /* Michoacán Nahuatl -> Nahuatl */ - {HB_TAG('n','c','r',' '), HB_TAG_NONE }, /* Ncane != N-Cree */ {HB_TAG('n','c','x',' '), HB_TAG('N','A','H',' ')}, /* Central Puebla Nahuatl -> Nahuatl */ - {HB_TAG('n','d','b',' '), HB_TAG_NONE }, /* Kenswei Nsei != Ndebele */ -/*{HB_TAG('n','d','c',' '), HB_TAG('N','D','C',' ')},*/ /* Ndau */ - {HB_TAG('n','d','g',' '), HB_TAG_NONE }, /* Ndengereko != Ndonga */ -/*{HB_TAG('n','d','s',' '), HB_TAG('N','D','S',' ')},*/ /* Low Saxon */ {HB_TAG('n','e','f',' '), HB_TAG('C','P','P',' ')}, /* Nefamese -> Creoles */ -/*{HB_TAG('n','e','w',' '), HB_TAG('N','E','W',' ')},*/ /* Newari */ -/*{HB_TAG('n','g','a',' '), HB_TAG('N','G','A',' ')},*/ /* Ngbaka */ {HB_TAG('n','g','l',' '), HB_TAG('L','M','W',' ')}, /* Lomwe */ {HB_TAG('n','g','m',' '), HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */ {HB_TAG('n','g','o',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */ - {HB_TAG('n','g','r',' '), HB_TAG_NONE }, /* Engdewu != Nagari */ {HB_TAG('n','g','u',' '), HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */ {HB_TAG('n','h','c',' '), HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */ {HB_TAG('n','h','d',' '), HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */ @@ -1137,12 +903,9 @@ static const LangTag ot_languages3[] = { {HB_TAG('n','h','y',' '), HB_TAG('N','A','H',' ')}, /* Northern Oaxaca Nahuatl -> Nahuatl */ {HB_TAG('n','h','z',' '), HB_TAG('N','A','H',' ')}, /* Santa María La Alta Nahuatl -> Nahuatl */ {HB_TAG('n','i','q',' '), HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */ - {HB_TAG('n','i','s',' '), HB_TAG_NONE }, /* Nimi != Nisi */ -/*{HB_TAG('n','i','u',' '), HB_TAG('N','I','U',' ')},*/ /* Niuean */ {HB_TAG('n','i','v',' '), HB_TAG('G','I','L',' ')}, /* Gilyak */ {HB_TAG('n','j','t',' '), HB_TAG('C','P','P',' ')}, /* Ndyuka-Trio Pidgin -> Creoles */ {HB_TAG('n','j','z',' '), HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */ - {HB_TAG('n','k','o',' '), HB_TAG_NONE }, /* Nkonya != N’Ko */ {HB_TAG('n','k','x',' '), HB_TAG('I','J','O',' ')}, /* Nkoroo -> Ijo */ {HB_TAG('n','l','a',' '), HB_TAG('B','M','L',' ')}, /* Ngombale -> Bamileke */ {HB_TAG('n','l','e',' '), HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */ @@ -1151,329 +914,147 @@ static const LangTag ot_languages3[] = { {HB_TAG('n','n','h',' '), HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */ {HB_TAG('n','n','z',' '), HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */ {HB_TAG('n','o','d',' '), HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */ -/*{HB_TAG('n','o','e',' '), HB_TAG('N','O','E',' ')},*/ /* Nimadi */ -/*{HB_TAG('n','o','g',' '), HB_TAG('N','O','G',' ')},*/ /* Nogai */ -/*{HB_TAG('n','o','p',' '), HB_TAG('N','O','P',' ')},*/ /* Numanggang */ -/*{HB_TAG('n','o','v',' '), HB_TAG('N','O','V',' ')},*/ /* Novial */ {HB_TAG('n','p','i',' '), HB_TAG('N','E','P',' ')}, /* Nepali */ {HB_TAG('n','p','l',' '), HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */ {HB_TAG('n','q','o',' '), HB_TAG('N','K','O',' ')}, /* N’Ko */ {HB_TAG('n','s','k',' '), HB_TAG('N','A','S',' ')}, /* Naskapi */ - {HB_TAG('n','s','m',' '), HB_TAG_NONE }, /* Sumi Naga != Northern Sami */ -/*{HB_TAG('n','s','o',' '), HB_TAG('N','S','O',' ')},*/ /* Northern Sotho */ {HB_TAG('n','s','u',' '), HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */ - {HB_TAG('n','t','o',' '), HB_TAG_NONE }, /* Ntomba != Esperanto */ {HB_TAG('n','u','e',' '), HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */ -/*{HB_TAG('n','u','k',' '), HB_TAG('N','U','K',' ')},*/ /* Nuu-chah-nulth */ {HB_TAG('n','u','u',' '), HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */ {HB_TAG('n','u','z',' '), HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */ {HB_TAG('n','w','e',' '), HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */ {HB_TAG('n','y','d',' '), HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */ -/*{HB_TAG('n','y','m',' '), HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */ {HB_TAG('n','y','n',' '), HB_TAG('N','K','L',' ')}, /* Nyankole */ -/*{HB_TAG('n','z','a',' '), HB_TAG('N','Z','A',' ')},*/ /* Tigon Mbembe -> Mbembe Tigon */ -/*{HB_TAG('o','j','b',' '), HB_TAG('O','J','B',' ')},*/ /* Northwestern Ojibwa -> Ojibway */ {HB_TAG('o','j','c',' '), HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */ {HB_TAG('o','j','g',' '), HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */ - {HB_TAG('o','j','s',' '), HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */ - {HB_TAG('o','j','s',' '), HB_TAG('O','J','B',' ')}, /* Severn Ojibwa -> Ojibway */ {HB_TAG('o','j','w',' '), HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */ {HB_TAG('o','k','d',' '), HB_TAG('I','J','O',' ')}, /* Okodia -> Ijo */ {HB_TAG('o','k','i',' '), HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */ {HB_TAG('o','k','m',' '), HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ {HB_TAG('o','k','r',' '), HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */ -/*{HB_TAG('o','n','e',' '), HB_TAG('O','N','E',' ')},*/ /* Oneida */ -/*{HB_TAG('o','n','o',' '), HB_TAG('O','N','O',' ')},*/ /* Onondaga */ {HB_TAG('o','n','x',' '), HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */ {HB_TAG('o','o','r',' '), HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */ {HB_TAG('o','r','c',' '), HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */ {HB_TAG('o','r','n',' '), HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */ - {HB_TAG('o','r','o',' '), HB_TAG_NONE }, /* Orokolo != Oromo */ {HB_TAG('o','r','r',' '), HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */ {HB_TAG('o','r','s',' '), HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */ {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia */ {HB_TAG('o','t','w',' '), HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ {HB_TAG('o','u','a',' '), HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */ - {HB_TAG('p','a','a',' '), HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */ -/*{HB_TAG('p','a','g',' '), HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ - {HB_TAG('p','a','l',' '), HB_TAG_NONE }, /* Pahlavi != Pali */ -/*{HB_TAG('p','a','m',' '), HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ - {HB_TAG('p','a','p',' '), HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */ - {HB_TAG('p','a','p',' '), HB_TAG('C','P','P',' ')}, /* Papiamento -> Creoles */ - {HB_TAG('p','a','s',' '), HB_TAG_NONE }, /* Papasena != Pashto */ -/*{HB_TAG('p','a','u',' '), HB_TAG('P','A','U',' ')},*/ /* Palauan */ {HB_TAG('p','b','t',' '), HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */ {HB_TAG('p','b','u',' '), HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */ -/*{HB_TAG('p','c','c',' '), HB_TAG('P','C','C',' ')},*/ /* Bouyei */ -/*{HB_TAG('p','c','d',' '), HB_TAG('P','C','D',' ')},*/ /* Picard */ {HB_TAG('p','c','e',' '), HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */ {HB_TAG('p','c','k',' '), HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */ {HB_TAG('p','c','m',' '), HB_TAG('C','P','P',' ')}, /* Nigerian Pidgin -> Creoles */ -/*{HB_TAG('p','d','c',' '), HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */ {HB_TAG('p','d','u',' '), HB_TAG('K','R','N',' ')}, /* Kayan -> Karen */ {HB_TAG('p','e','a',' '), HB_TAG('C','P','P',' ')}, /* Peranakan Indonesian -> Creoles */ {HB_TAG('p','e','l',' '), HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */ {HB_TAG('p','e','s',' '), HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */ {HB_TAG('p','e','y',' '), HB_TAG('C','P','P',' ')}, /* Petjo -> Creoles */ - {HB_TAG('p','g','a',' '), HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */ - {HB_TAG('p','g','a',' '), HB_TAG('C','P','P',' ')}, /* Sudanese Creole Arabic -> Creoles */ -/*{HB_TAG('p','h','k',' '), HB_TAG('P','H','K',' ')},*/ /* Phake */ - {HB_TAG('p','i','h',' '), HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk -> Norfolk */ - {HB_TAG('p','i','h',' '), HB_TAG('C','P','P',' ')}, /* Pitcairn-Norfolk -> Creoles */ - {HB_TAG('p','i','l',' '), HB_TAG_NONE }, /* Yom != Filipino */ {HB_TAG('p','i','s',' '), HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */ {HB_TAG('p','k','h',' '), HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */ {HB_TAG('p','k','o',' '), HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */ {HB_TAG('p','l','g',' '), HB_TAG('P','L','G','0')}, /* Pilagá */ - {HB_TAG('p','l','k',' '), HB_TAG_NONE }, /* Kohistani Shina != Polish */ {HB_TAG('p','l','l',' '), HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */ {HB_TAG('p','l','n',' '), HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */ {HB_TAG('p','l','p',' '), HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */ {HB_TAG('p','l','t',' '), HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */ {HB_TAG('p','m','l',' '), HB_TAG('C','P','P',' ')}, /* Lingua Franca -> Creoles */ -/*{HB_TAG('p','m','s',' '), HB_TAG('P','M','S',' ')},*/ /* Piemontese */ {HB_TAG('p','m','y',' '), HB_TAG('C','P','P',' ')}, /* Papuan Malay -> Creoles */ -/*{HB_TAG('p','n','b',' '), HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */ {HB_TAG('p','o','c',' '), HB_TAG('M','Y','N',' ')}, /* Poqomam -> Mayan */ - {HB_TAG('p','o','h',' '), HB_TAG('P','O','H',' ')}, /* Poqomchi' -> Pocomchi */ - {HB_TAG('p','o','h',' '), HB_TAG('M','Y','N',' ')}, /* Poqomchi' -> Mayan */ -/*{HB_TAG('p','o','n',' '), HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */ {HB_TAG('p','o','v',' '), HB_TAG('C','P','P',' ')}, /* Upper Guinea Crioulo -> Creoles */ {HB_TAG('p','p','a',' '), HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */ {HB_TAG('p','r','e',' '), HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */ -/*{HB_TAG('p','r','o',' '), HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */ {HB_TAG('p','r','p',' '), HB_TAG('G','U','J',' ')}, /* Parsi (retired code) -> Gujarati */ - {HB_TAG('p','r','s',' '), HB_TAG('D','R','I',' ')}, /* Dari */ - {HB_TAG('p','r','s',' '), HB_TAG('F','A','R',' ')}, /* Dari -> Persian */ {HB_TAG('p','s','e',' '), HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */ {HB_TAG('p','s','t',' '), HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */ {HB_TAG('p','u','b',' '), HB_TAG('Q','I','N',' ')}, /* Purum -> Chin */ {HB_TAG('p','u','z',' '), HB_TAG('Q','I','N',' ')}, /* Purum Naga (retired code) -> Chin */ - {HB_TAG('p','w','o',' '), HB_TAG('P','W','O',' ')}, /* Pwo Western Karen -> Western Pwo Karen */ - {HB_TAG('p','w','o',' '), HB_TAG('K','R','N',' ')}, /* Pwo Western Karen -> Karen */ {HB_TAG('p','w','w',' '), HB_TAG('K','R','N',' ')}, /* Pwo Northern Karen -> Karen */ - {HB_TAG('q','u','b',' '), HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ - {HB_TAG('q','u','b',' '), HB_TAG('Q','U','Z',' ')}, /* Huallaga Huánuco Quechua -> Quechua */ - {HB_TAG('q','u','c',' '), HB_TAG('Q','U','C',' ')}, /* K’iche’ */ - {HB_TAG('q','u','c',' '), HB_TAG('M','Y','N',' ')}, /* K'iche' -> Mayan */ - {HB_TAG('q','u','d',' '), HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ - {HB_TAG('q','u','d',' '), HB_TAG('Q','U','Z',' ')}, /* Calderón Highland Quichua -> Quechua */ {HB_TAG('q','u','f',' '), HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */ - {HB_TAG('q','u','g',' '), HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ - {HB_TAG('q','u','g',' '), HB_TAG('Q','U','Z',' ')}, /* Chimborazo Highland Quichua -> Quechua */ - {HB_TAG('q','u','h',' '), HB_TAG('Q','U','H',' ')}, /* South Bolivian Quechua -> Quechua (Bolivia) */ - {HB_TAG('q','u','h',' '), HB_TAG('Q','U','Z',' ')}, /* South Bolivian Quechua -> Quechua */ {HB_TAG('q','u','k',' '), HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */ - {HB_TAG('q','u','l',' '), HB_TAG('Q','U','H',' ')}, /* North Bolivian Quechua -> Quechua (Bolivia) */ - {HB_TAG('q','u','l',' '), HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */ {HB_TAG('q','u','m',' '), HB_TAG('M','Y','N',' ')}, /* Sipacapense -> Mayan */ - {HB_TAG('q','u','p',' '), HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ - {HB_TAG('q','u','p',' '), HB_TAG('Q','U','Z',' ')}, /* Southern Pastaza Quechua -> Quechua */ - {HB_TAG('q','u','r',' '), HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ - {HB_TAG('q','u','r',' '), HB_TAG('Q','U','Z',' ')}, /* Yanahuanca Pasco Quechua -> Quechua */ - {HB_TAG('q','u','s',' '), HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ - {HB_TAG('q','u','s',' '), HB_TAG('Q','U','Z',' ')}, /* Santiago del Estero Quichua -> Quechua */ {HB_TAG('q','u','v',' '), HB_TAG('M','Y','N',' ')}, /* Sacapulteco -> Mayan */ - {HB_TAG('q','u','w',' '), HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ - {HB_TAG('q','u','w',' '), HB_TAG('Q','U','Z',' ')}, /* Tena Lowland Quichua -> Quechua */ - {HB_TAG('q','u','x',' '), HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */ - {HB_TAG('q','u','x',' '), HB_TAG('Q','U','Z',' ')}, /* Yauyos Quechua -> Quechua */ {HB_TAG('q','u','y',' '), HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */ -/*{HB_TAG('q','u','z',' '), HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */ - {HB_TAG('q','v','a',' '), HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ - {HB_TAG('q','v','a',' '), HB_TAG('Q','U','Z',' ')}, /* Ambo-Pasco Quechua -> Quechua */ {HB_TAG('q','v','c',' '), HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */ {HB_TAG('q','v','e',' '), HB_TAG('Q','U','Z',' ')}, /* Eastern Apurímac Quechua -> Quechua */ - {HB_TAG('q','v','h',' '), HB_TAG('Q','W','H',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ - {HB_TAG('q','v','h',' '), HB_TAG('Q','U','Z',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */ - {HB_TAG('q','v','i',' '), HB_TAG('Q','V','I',' ')}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ - {HB_TAG('q','v','i',' '), HB_TAG('Q','U','Z',' ')}, /* Imbabura Highland Quichua -> Quechua */ - {HB_TAG('q','v','j',' '), HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */ - {HB_TAG('q','v','j',' '), HB_TAG('Q','U','Z',' ')}, /* Loja Highland Quichua -> Quechua */ - {HB_TAG('q','v','l',' '), HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ - {HB_TAG('q','v','l',' '), HB_TAG('Q','U','Z',' ')}, /* Cajatambo North Lima Quechua -> Quechua */ - {HB_TAG('q','v','m',' '), HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ - {HB_TAG('q','v','m',' '), HB_TAG('Q','U','Z',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */ - {HB_TAG('q','v','n',' '), HB_TAG('Q','W','H',' ')}, /* North Junín Quechua -> Quechua (Peru) */ - {HB_TAG('q','v','n',' '), HB_TAG('Q','U','Z',' ')}, /* North Junín Quechua -> Quechua */ - {HB_TAG('q','v','o',' '), HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ - {HB_TAG('q','v','o',' '), HB_TAG('Q','U','Z',' ')}, /* Napo Lowland Quechua -> Quechua */ - {HB_TAG('q','v','p',' '), HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */ - {HB_TAG('q','v','p',' '), HB_TAG('Q','U','Z',' ')}, /* Pacaraos Quechua -> Quechua */ {HB_TAG('q','v','s',' '), HB_TAG('Q','U','Z',' ')}, /* San Martín Quechua -> Quechua */ - {HB_TAG('q','v','w',' '), HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ - {HB_TAG('q','v','w',' '), HB_TAG('Q','U','Z',' ')}, /* Huaylla Wanca Quechua -> Quechua */ - {HB_TAG('q','v','z',' '), HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ - {HB_TAG('q','v','z',' '), HB_TAG('Q','U','Z',' ')}, /* Northern Pastaza Quichua -> Quechua */ - {HB_TAG('q','w','a',' '), HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */ - {HB_TAG('q','w','a',' '), HB_TAG('Q','U','Z',' ')}, /* Corongo Ancash Quechua -> Quechua */ {HB_TAG('q','w','c',' '), HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */ - {HB_TAG('q','w','h',' '), HB_TAG('Q','W','H',' ')}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ - {HB_TAG('q','w','h',' '), HB_TAG('Q','U','Z',' ')}, /* Huaylas Ancash Quechua -> Quechua */ - {HB_TAG('q','w','s',' '), HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ - {HB_TAG('q','w','s',' '), HB_TAG('Q','U','Z',' ')}, /* Sihuas Ancash Quechua -> Quechua */ {HB_TAG('q','w','t',' '), HB_TAG('A','T','H',' ')}, /* Kwalhioqua-Tlatskanai -> Athapaskan */ - {HB_TAG('q','x','a',' '), HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ - {HB_TAG('q','x','a',' '), HB_TAG('Q','U','Z',' ')}, /* Chiquián Ancash Quechua -> Quechua */ - {HB_TAG('q','x','c',' '), HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */ - {HB_TAG('q','x','c',' '), HB_TAG('Q','U','Z',' ')}, /* Chincha Quechua -> Quechua */ - {HB_TAG('q','x','h',' '), HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */ - {HB_TAG('q','x','h',' '), HB_TAG('Q','U','Z',' ')}, /* Panao Huánuco Quechua -> Quechua */ - {HB_TAG('q','x','l',' '), HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ - {HB_TAG('q','x','l',' '), HB_TAG('Q','U','Z',' ')}, /* Salasaca Highland Quichua -> Quechua */ - {HB_TAG('q','x','n',' '), HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ - {HB_TAG('q','x','n',' '), HB_TAG('Q','U','Z',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua */ - {HB_TAG('q','x','o',' '), HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ - {HB_TAG('q','x','o',' '), HB_TAG('Q','U','Z',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua */ {HB_TAG('q','x','p',' '), HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */ - {HB_TAG('q','x','r',' '), HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ - {HB_TAG('q','x','r',' '), HB_TAG('Q','U','Z',' ')}, /* Cañar Highland Quichua -> Quechua */ - {HB_TAG('q','x','t',' '), HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ - {HB_TAG('q','x','t',' '), HB_TAG('Q','U','Z',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua */ {HB_TAG('q','x','u',' '), HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */ - {HB_TAG('q','x','w',' '), HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */ - {HB_TAG('q','x','w',' '), HB_TAG('Q','U','Z',' ')}, /* Jauja Wanca Quechua -> Quechua */ {HB_TAG('r','a','g',' '), HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */ -/*{HB_TAG('r','a','j',' '), HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */ {HB_TAG('r','a','l',' '), HB_TAG('Q','I','N',' ')}, /* Ralte -> Chin */ -/*{HB_TAG('r','a','r',' '), HB_TAG('R','A','R',' ')},*/ /* Rarotongan */ {HB_TAG('r','b','b',' '), HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */ {HB_TAG('r','b','l',' '), HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */ {HB_TAG('r','c','f',' '), HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */ -/*{HB_TAG('r','e','j',' '), HB_TAG('R','E','J',' ')},*/ /* Rejang */ -/*{HB_TAG('r','h','g',' '), HB_TAG('R','H','G',' ')},*/ /* Rohingya */ -/*{HB_TAG('r','i','a',' '), HB_TAG('R','I','A',' ')},*/ /* Riang (India) */ - {HB_TAG('r','i','f',' '), HB_TAG('R','I','F',' ')}, /* Tarifit */ - {HB_TAG('r','i','f',' '), HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */ -/*{HB_TAG('r','i','t',' '), HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */ {HB_TAG('r','k','i',' '), HB_TAG('A','R','K',' ')}, /* Rakhine */ -/*{HB_TAG('r','k','w',' '), HB_TAG('R','K','W',' ')},*/ /* Arakwal */ {HB_TAG('r','m','c',' '), HB_TAG('R','O','Y',' ')}, /* Carpathian Romani -> Romany */ {HB_TAG('r','m','f',' '), HB_TAG('R','O','Y',' ')}, /* Kalo Finnish Romani -> Romany */ {HB_TAG('r','m','l',' '), HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */ {HB_TAG('r','m','n',' '), HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */ {HB_TAG('r','m','o',' '), HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */ - {HB_TAG('r','m','s',' '), HB_TAG_NONE }, /* Romanian Sign Language != Romansh */ {HB_TAG('r','m','w',' '), HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */ - {HB_TAG('r','m','y',' '), HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ - {HB_TAG('r','m','y',' '), HB_TAG('R','O','Y',' ')}, /* Vlax Romani -> Romany */ {HB_TAG('r','m','z',' '), HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */ {HB_TAG('r','o','m',' '), HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ {HB_TAG('r','o','p',' '), HB_TAG('C','P','P',' ')}, /* Kriol -> Creoles */ {HB_TAG('r','t','c',' '), HB_TAG('Q','I','N',' ')}, /* Rungtu Chin -> Chin */ -/*{HB_TAG('r','t','m',' '), HB_TAG('R','T','M',' ')},*/ /* Rotuman */ {HB_TAG('r','u','e',' '), HB_TAG('R','S','Y',' ')}, /* Rusyn */ -/*{HB_TAG('r','u','p',' '), HB_TAG('R','U','P',' ')},*/ /* Aromanian */ {HB_TAG('r','w','r',' '), HB_TAG('M','A','W',' ')}, /* Marwari (India) */ - {HB_TAG('s','a','d',' '), HB_TAG_NONE }, /* Sandawe != Sadri */ {HB_TAG('s','a','h',' '), HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */ {HB_TAG('s','a','m',' '), HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */ -/*{HB_TAG('s','a','s',' '), HB_TAG('S','A','S',' ')},*/ /* Sasak */ -/*{HB_TAG('s','a','t',' '), HB_TAG('S','A','T',' ')},*/ /* Santali */ - {HB_TAG('s','a','y',' '), HB_TAG_NONE }, /* Saya != Sayisi */ {HB_TAG('s','c','f',' '), HB_TAG('C','P','P',' ')}, /* San Miguel Creole French -> Creoles */ {HB_TAG('s','c','h',' '), HB_TAG('Q','I','N',' ')}, /* Sakachep -> Chin */ {HB_TAG('s','c','i',' '), HB_TAG('C','P','P',' ')}, /* Sri Lankan Creole Malay -> Creoles */ {HB_TAG('s','c','k',' '), HB_TAG('S','A','D',' ')}, /* Sadri */ -/*{HB_TAG('s','c','n',' '), HB_TAG('S','C','N',' ')},*/ /* Sicilian */ -/*{HB_TAG('s','c','o',' '), HB_TAG('S','C','O',' ')},*/ /* Scots */ - {HB_TAG('s','c','s',' '), HB_TAG('S','C','S',' ')}, /* North Slavey */ - {HB_TAG('s','c','s',' '), HB_TAG('S','L','A',' ')}, /* North Slavey -> Slavey */ - {HB_TAG('s','c','s',' '), HB_TAG('A','T','H',' ')}, /* North Slavey -> Athapaskan */ {HB_TAG('s','d','c',' '), HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */ {HB_TAG('s','d','h',' '), HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */ {HB_TAG('s','d','n',' '), HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */ {HB_TAG('s','d','s',' '), HB_TAG('B','B','R',' ')}, /* Sened -> Berber */ -/*{HB_TAG('s','e','e',' '), HB_TAG('S','E','E',' ')},*/ /* Seneca */ {HB_TAG('s','e','h',' '), HB_TAG('S','N','A',' ')}, /* Sena */ {HB_TAG('s','e','k',' '), HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */ -/*{HB_TAG('s','e','l',' '), HB_TAG('S','E','L',' ')},*/ /* Selkup */ {HB_TAG('s','e','z',' '), HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */ - {HB_TAG('s','f','m',' '), HB_TAG('S','F','M',' ')}, /* Small Flowery Miao */ - {HB_TAG('s','f','m',' '), HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */ -/*{HB_TAG('s','g','a',' '), HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */ {HB_TAG('s','g','c',' '), HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ - {HB_TAG('s','g','o',' '), HB_TAG_NONE }, /* Songa (retired code) != Sango */ -/*{HB_TAG('s','g','s',' '), HB_TAG('S','G','S',' ')},*/ /* Samogitian */ {HB_TAG('s','g','w',' '), HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ - {HB_TAG('s','h','i',' '), HB_TAG('S','H','I',' ')}, /* Tachelhit */ - {HB_TAG('s','h','i',' '), HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */ {HB_TAG('s','h','l',' '), HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ -/*{HB_TAG('s','h','n',' '), HB_TAG('S','H','N',' ')},*/ /* Shan */ {HB_TAG('s','h','u',' '), HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */ {HB_TAG('s','h','y',' '), HB_TAG('B','B','R',' ')}, /* Tachawit -> Berber */ - {HB_TAG('s','i','b',' '), HB_TAG_NONE }, /* Sebop != Sibe */ -/*{HB_TAG('s','i','d',' '), HB_TAG('S','I','D',' ')},*/ /* Sidamo */ - {HB_TAG('s','i','g',' '), HB_TAG_NONE }, /* Paasaal != Silte Gurage */ {HB_TAG('s','i','z',' '), HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ -/*{HB_TAG('s','j','a',' '), HB_TAG('S','J','A',' ')},*/ /* Epena */ {HB_TAG('s','j','c',' '), HB_TAG('Z','H','S',' ')}, /* Shaojiang Chinese -> Chinese, Simplified */ {HB_TAG('s','j','d',' '), HB_TAG('K','S','M',' ')}, /* Kildin Sami */ -/*{HB_TAG('s','j','e',' '), HB_TAG('S','J','E',' ')},*/ /* Pite Sami */ {HB_TAG('s','j','o',' '), HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ {HB_TAG('s','j','s',' '), HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */ -/*{HB_TAG('s','j','u',' '), HB_TAG('S','J','U',' ')},*/ /* Ume Sami */ {HB_TAG('s','k','g',' '), HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */ {HB_TAG('s','k','r',' '), HB_TAG('S','R','K',' ')}, /* Saraiki */ - {HB_TAG('s','k','s',' '), HB_TAG_NONE }, /* Maia != Skolt Sami */ {HB_TAG('s','k','w',' '), HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */ - {HB_TAG('s','k','y',' '), HB_TAG_NONE }, /* Sikaiana != Slovak */ - {HB_TAG('s','l','a',' '), HB_TAG_NONE }, /* Slavic [collection] != Slavey */ {HB_TAG('s','m','a',' '), HB_TAG('S','S','M',' ')}, /* Southern Sami */ {HB_TAG('s','m','d',' '), HB_TAG('M','B','N',' ')}, /* Sama (retired code) -> Mbundu */ {HB_TAG('s','m','j',' '), HB_TAG('L','S','M',' ')}, /* Lule Sami */ - {HB_TAG('s','m','l',' '), HB_TAG_NONE }, /* Central Sama != Somali */ {HB_TAG('s','m','n',' '), HB_TAG('I','S','M',' ')}, /* Inari Sami */ {HB_TAG('s','m','s',' '), HB_TAG('S','K','S',' ')}, /* Skolt Sami */ {HB_TAG('s','m','t',' '), HB_TAG('Q','I','N',' ')}, /* Simte -> Chin */ {HB_TAG('s','n','b',' '), HB_TAG('I','B','A',' ')}, /* Sebuyau (retired code) -> Iban */ - {HB_TAG('s','n','h',' '), HB_TAG_NONE }, /* Shinabo (retired code) != Sinhala (Sinhalese) */ -/*{HB_TAG('s','n','k',' '), HB_TAG('S','N','K',' ')},*/ /* Soninke */ - {HB_TAG('s','o','g',' '), HB_TAG_NONE }, /* Sogdian != Sodo Gurage */ -/*{HB_TAG('s','o','p',' '), HB_TAG('S','O','P',' ')},*/ /* Songe */ {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia */ {HB_TAG('s','p','y',' '), HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */ - {HB_TAG('s','r','b',' '), HB_TAG_NONE }, /* Sora != Serbian */ {HB_TAG('s','r','c',' '), HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */ - {HB_TAG('s','r','k',' '), HB_TAG_NONE }, /* Serudung Murut != Saraiki */ {HB_TAG('s','r','m',' '), HB_TAG('C','P','P',' ')}, /* Saramaccan -> Creoles */ {HB_TAG('s','r','n',' '), HB_TAG('C','P','P',' ')}, /* Sranan Tongo -> Creoles */ {HB_TAG('s','r','o',' '), HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */ -/*{HB_TAG('s','r','r',' '), HB_TAG('S','R','R',' ')},*/ /* Serer */ {HB_TAG('s','r','s',' '), HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ {HB_TAG('s','s','h',' '), HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ - {HB_TAG('s','s','l',' '), HB_TAG_NONE }, /* Western Sisaala != South Slavey */ - {HB_TAG('s','s','m',' '), HB_TAG_NONE }, /* Semnam != Southern Sami */ {HB_TAG('s','t','a',' '), HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */ -/*{HB_TAG('s','t','q',' '), HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */ -/*{HB_TAG('s','t','r',' '), HB_TAG('S','T','R',' ')},*/ /* Straits Salish */ {HB_TAG('s','t','v',' '), HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ -/*{HB_TAG('s','u','k',' '), HB_TAG('S','U','K',' ')},*/ /* Sukuma */ {HB_TAG('s','u','q',' '), HB_TAG('S','U','R',' ')}, /* Suri */ - {HB_TAG('s','u','r',' '), HB_TAG_NONE }, /* Mwaghavul != Suri */ -/*{HB_TAG('s','v','a',' '), HB_TAG('S','V','A',' ')},*/ /* Svan */ {HB_TAG('s','v','c',' '), HB_TAG('C','P','P',' ')}, /* Vincentian Creole English -> Creoles */ - {HB_TAG('s','v','e',' '), HB_TAG_NONE }, /* Serili != Swedish */ {HB_TAG('s','w','b',' '), HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */ {HB_TAG('s','w','c',' '), HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */ {HB_TAG('s','w','h',' '), HB_TAG('S','W','K',' ')}, /* Swahili */ - {HB_TAG('s','w','k',' '), HB_TAG_NONE }, /* Malawi Sena != Swahili */ {HB_TAG('s','w','n',' '), HB_TAG('B','B','R',' ')}, /* Sawknah -> Berber */ {HB_TAG('s','w','v',' '), HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */ -/*{HB_TAG('s','x','u',' '), HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */ {HB_TAG('s','y','c',' '), HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */ -/*{HB_TAG('s','y','l',' '), HB_TAG('S','Y','L',' ')},*/ /* Sylheti */ -/*{HB_TAG('s','y','r',' '), HB_TAG('S','Y','R',' ')},*/ /* Syriac [macrolanguage] */ -/*{HB_TAG('s','z','l',' '), HB_TAG('S','Z','L',' ')},*/ /* Silesian */ {HB_TAG('t','a','a',' '), HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */ -/*{HB_TAG('t','a','b',' '), HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */ - {HB_TAG('t','a','j',' '), HB_TAG_NONE }, /* Eastern Tamang != Tajiki */ - {HB_TAG('t','a','q',' '), HB_TAG('T','A','Q',' ')}, /* Tamasheq */ - {HB_TAG('t','a','q',' '), HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */ - {HB_TAG('t','a','q',' '), HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */ {HB_TAG('t','a','s',' '), HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */ {HB_TAG('t','a','u',' '), HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */ -/*{HB_TAG('t','b','v',' '), HB_TAG('T','B','V',' ')},*/ /* Tobo */ {HB_TAG('t','c','b',' '), HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */ {HB_TAG('t','c','e',' '), HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */ {HB_TAG('t','c','h',' '), HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */ @@ -1481,115 +1062,54 @@ static const LangTag ot_languages3[] = { {HB_TAG('t','c','s',' '), HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */ {HB_TAG('t','c','y',' '), HB_TAG('T','U','L',' ')}, /* Tulu */ {HB_TAG('t','c','z',' '), HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */ -/*{HB_TAG('t','d','c',' '), HB_TAG('T','D','C',' ')},*/ /* Emberá-Tadó */ -/*{HB_TAG('t','d','d',' '), HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */ {HB_TAG('t','d','x',' '), HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ {HB_TAG('t','e','c',' '), HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */ {HB_TAG('t','e','m',' '), HB_TAG('T','M','N',' ')}, /* Timne -> Temne */ -/*{HB_TAG('t','e','t',' '), HB_TAG('T','E','T',' ')},*/ /* Tetum */ {HB_TAG('t','e','z',' '), HB_TAG('B','B','R',' ')}, /* Tetserret -> Berber */ {HB_TAG('t','f','n',' '), HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */ {HB_TAG('t','g','h',' '), HB_TAG('C','P','P',' ')}, /* Tobagonian Creole English -> Creoles */ {HB_TAG('t','g','j',' '), HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */ - {HB_TAG('t','g','n',' '), HB_TAG_NONE }, /* Tandaganon != Tongan */ - {HB_TAG('t','g','r',' '), HB_TAG_NONE }, /* Tareng != Tigre */ {HB_TAG('t','g','x',' '), HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */ - {HB_TAG('t','g','y',' '), HB_TAG_NONE }, /* Togoyo != Tigrinya */ -/*{HB_TAG('t','h','p',' '), HB_TAG('T','H','P',' ')},*/ /* Thompson */ {HB_TAG('t','h','t',' '), HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */ - {HB_TAG('t','h','v',' '), HB_TAG('T','H','V',' ')}, /* Tahaggart Tamahaq */ - {HB_TAG('t','h','v',' '), HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */ - {HB_TAG('t','h','v',' '), HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */ - {HB_TAG('t','h','z',' '), HB_TAG('T','H','Z',' ')}, /* Tayart Tamajeq */ - {HB_TAG('t','h','z',' '), HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */ - {HB_TAG('t','h','z',' '), HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */ {HB_TAG('t','i','a',' '), HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */ {HB_TAG('t','i','g',' '), HB_TAG('T','G','R',' ')}, /* Tigre */ -/*{HB_TAG('t','i','v',' '), HB_TAG('T','I','V',' ')},*/ /* Tiv */ -/*{HB_TAG('t','j','l',' '), HB_TAG('T','J','L',' ')},*/ /* Tai Laing */ {HB_TAG('t','j','o',' '), HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */ {HB_TAG('t','k','g',' '), HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ - {HB_TAG('t','k','m',' '), HB_TAG_NONE }, /* Takelma != Turkmen */ -/*{HB_TAG('t','l','i',' '), HB_TAG('T','L','I',' ')},*/ /* Tlingit */ -/*{HB_TAG('t','l','y',' '), HB_TAG('T','L','Y',' ')},*/ /* Talysh */ {HB_TAG('t','m','g',' '), HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */ - {HB_TAG('t','m','h',' '), HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */ - {HB_TAG('t','m','h',' '), HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */ - {HB_TAG('t','m','n',' '), HB_TAG_NONE }, /* Taman (Indonesia) != Temne */ {HB_TAG('t','m','w',' '), HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */ - {HB_TAG('t','n','a',' '), HB_TAG_NONE }, /* Tacana != Tswana */ - {HB_TAG('t','n','e',' '), HB_TAG_NONE }, /* Tinoc Kallahan (retired code) != Tundra Enets */ - {HB_TAG('t','n','f',' '), HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */ - {HB_TAG('t','n','f',' '), HB_TAG('F','A','R',' ')}, /* Tangshewi (retired code) -> Persian */ - {HB_TAG('t','n','g',' '), HB_TAG_NONE }, /* Tobanga != Tonga */ {HB_TAG('t','o','d',' '), HB_TAG('T','O','D','0')}, /* Toma */ {HB_TAG('t','o','i',' '), HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ {HB_TAG('t','o','j',' '), HB_TAG('M','Y','N',' ')}, /* Tojolabal -> Mayan */ {HB_TAG('t','o','l',' '), HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */ {HB_TAG('t','o','r',' '), HB_TAG('B','A','D','0')}, /* Togbo-Vara Banda -> Banda */ - {HB_TAG('t','p','i',' '), HB_TAG('T','P','I',' ')}, /* Tok Pisin */ - {HB_TAG('t','p','i',' '), HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */ {HB_TAG('t','r','f',' '), HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */ - {HB_TAG('t','r','k',' '), HB_TAG_NONE }, /* Turkic [collection] != Turkish */ - {HB_TAG('t','r','u',' '), HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ - {HB_TAG('t','r','u',' '), HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ - {HB_TAG('t','s','g',' '), HB_TAG_NONE }, /* Tausug != Tsonga */ -/*{HB_TAG('t','s','j',' '), HB_TAG('T','S','J',' ')},*/ /* Tshangla */ {HB_TAG('t','t','c',' '), HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */ {HB_TAG('t','t','m',' '), HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */ - {HB_TAG('t','t','q',' '), HB_TAG('T','T','Q',' ')}, /* Tawallammat Tamajaq */ - {HB_TAG('t','t','q',' '), HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */ - {HB_TAG('t','t','q',' '), HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */ - {HB_TAG('t','u','a',' '), HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */ - {HB_TAG('t','u','l',' '), HB_TAG_NONE }, /* Tula != Tulu */ -/*{HB_TAG('t','u','m',' '), HB_TAG('T','U','M',' ')},*/ /* Tumbuka */ -/*{HB_TAG('t','u','s',' '), HB_TAG('T','U','S',' ')},*/ /* Tuscarora */ {HB_TAG('t','u','u',' '), HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */ - {HB_TAG('t','u','v',' '), HB_TAG_NONE }, /* Turkana != Tuvin */ {HB_TAG('t','u','y',' '), HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */ -/*{HB_TAG('t','v','l',' '), HB_TAG('T','V','L',' ')},*/ /* Tuvalu */ {HB_TAG('t','v','y',' '), HB_TAG('C','P','P',' ')}, /* Timor Pidgin -> Creoles */ {HB_TAG('t','x','c',' '), HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */ {HB_TAG('t','x','y',' '), HB_TAG('M','L','G',' ')}, /* Tanosy Malagasy -> Malagasy */ {HB_TAG('t','y','v',' '), HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */ -/*{HB_TAG('t','y','z',' '), HB_TAG('T','Y','Z',' ')},*/ /* Tày */ {HB_TAG('t','z','h',' '), HB_TAG('M','Y','N',' ')}, /* Tzeltal -> Mayan */ {HB_TAG('t','z','j',' '), HB_TAG('M','Y','N',' ')}, /* Tz'utujil -> Mayan */ - {HB_TAG('t','z','m',' '), HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight -> Tamazight */ - {HB_TAG('t','z','m',' '), HB_TAG('B','B','R',' ')}, /* Central Atlas Tamazight -> Berber */ - {HB_TAG('t','z','o',' '), HB_TAG('T','Z','O',' ')}, /* Tzotzil */ - {HB_TAG('t','z','o',' '), HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */ {HB_TAG('u','b','l',' '), HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */ -/*{HB_TAG('u','d','i',' '), HB_TAG('U','D','I',' ')},*/ /* Udi */ -/*{HB_TAG('u','d','m',' '), HB_TAG('U','D','M',' ')},*/ /* Udmurt */ {HB_TAG('u','k','i',' '), HB_TAG('K','U','I',' ')}, /* Kui (India) */ {HB_TAG('u','l','n',' '), HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */ -/*{HB_TAG('u','m','b',' '), HB_TAG('U','M','B',' ')},*/ /* Umbundu */ {HB_TAG('u','n','r',' '), HB_TAG('M','U','N',' ')}, /* Mundari */ {HB_TAG('u','r','k',' '), HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */ {HB_TAG('u','s','p',' '), HB_TAG('M','Y','N',' ')}, /* Uspanteco -> Mayan */ {HB_TAG('u','z','n',' '), HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */ {HB_TAG('u','z','s',' '), HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */ {HB_TAG('v','a','p',' '), HB_TAG('Q','I','N',' ')}, /* Vaiphei -> Chin */ -/*{HB_TAG('v','e','c',' '), HB_TAG('V','E','C',' ')},*/ /* Venetian */ {HB_TAG('v','i','c',' '), HB_TAG('C','P','P',' ')}, /* Virgin Islands Creole English -> Creoles */ - {HB_TAG('v','i','t',' '), HB_TAG_NONE }, /* Viti != Vietnamese */ {HB_TAG('v','k','k',' '), HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */ {HB_TAG('v','k','p',' '), HB_TAG('C','P','P',' ')}, /* Korlai Creole Portuguese -> Creoles */ {HB_TAG('v','k','t',' '), HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */ {HB_TAG('v','l','s',' '), HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */ {HB_TAG('v','m','w',' '), HB_TAG('M','A','K',' ')}, /* Makhuwa */ - {HB_TAG('v','r','o',' '), HB_TAG('V','R','O',' ')}, /* Võro */ - {HB_TAG('v','r','o',' '), HB_TAG('E','T','I',' ')}, /* Võro -> Estonian */ {HB_TAG('v','s','n',' '), HB_TAG('S','A','N',' ')}, /* Vedic Sanskrit -> Sanskrit */ - {HB_TAG('w','a','g',' '), HB_TAG_NONE }, /* Wa'ema != Wagdi */ -/*{HB_TAG('w','a','r',' '), HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */ -/*{HB_TAG('w','b','l',' '), HB_TAG('W','B','L',' ')},*/ /* Wakhi */ {HB_TAG('w','b','m',' '), HB_TAG('W','A',' ',' ')}, /* Wa */ - {HB_TAG('w','b','r',' '), HB_TAG('W','A','G',' ')}, /* Wagdi */ - {HB_TAG('w','b','r',' '), HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */ -/*{HB_TAG('w','c','i',' '), HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */ -/*{HB_TAG('w','d','t',' '), HB_TAG('W','D','T',' ')},*/ /* Wendat */ {HB_TAG('w','e','a',' '), HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */ {HB_TAG('w','e','s',' '), HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */ {HB_TAG('w','e','u',' '), HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */ @@ -1599,62 +1119,31 @@ static const LangTag ot_languages3[] = { {HB_TAG('w','n','i',' '), HB_TAG('C','M','R',' ')}, /* Ndzwani Comorian -> Comorian */ {HB_TAG('w','r','y',' '), HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */ {HB_TAG('w','s','g',' '), HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */ -/*{HB_TAG('w','t','m',' '), HB_TAG('W','T','M',' ')},*/ /* Mewati */ {HB_TAG('w','u','u',' '), HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */ - {HB_TAG('w','y','a',' '), HB_TAG('W','D','T',' ')}, /* Wyandot (retired code) -> Wendat */ - {HB_TAG('w','y','a',' '), HB_TAG('W','Y','N',' ')}, /* Wyandot (retired code) */ -/*{HB_TAG('w','y','n',' '), HB_TAG('W','Y','N',' ')},*/ /* Wyandot */ - {HB_TAG('x','a','l',' '), HB_TAG('K','L','M',' ')}, /* Kalmyk */ - {HB_TAG('x','a','l',' '), HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */ {HB_TAG('x','a','n',' '), HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */ - {HB_TAG('x','b','d',' '), HB_TAG_NONE }, /* Bindal != Lü */ -/*{HB_TAG('x','j','b',' '), HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */ -/*{HB_TAG('x','k','f',' '), HB_TAG('X','K','F',' ')},*/ /* Khengkha */ {HB_TAG('x','m','g',' '), HB_TAG('B','M','L',' ')}, /* Mengaka -> Bamileke */ - {HB_TAG('x','m','m',' '), HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */ - {HB_TAG('x','m','m',' '), HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */ {HB_TAG('x','m','v',' '), HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */ {HB_TAG('x','m','w',' '), HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */ {HB_TAG('x','n','j',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */ {HB_TAG('x','n','q',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */ {HB_TAG('x','n','r',' '), HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */ -/*{HB_TAG('x','o','g',' '), HB_TAG('X','O','G',' ')},*/ /* Soga */ - {HB_TAG('x','p','e',' '), HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */ - {HB_TAG('x','p','e',' '), HB_TAG('K','P','L',' ')}, /* Liberia Kpelle -> Kpelle */ - {HB_TAG('x','s','l',' '), HB_TAG('S','S','L',' ')}, /* South Slavey */ - {HB_TAG('x','s','l',' '), HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */ - {HB_TAG('x','s','l',' '), HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */ {HB_TAG('x','s','t',' '), HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */ -/*{HB_TAG('x','u','b',' '), HB_TAG('X','U','B',' ')},*/ /* Betta Kurumba -> Bette Kuruma */ -/*{HB_TAG('x','u','j',' '), HB_TAG('X','U','J',' ')},*/ /* Jennu Kurumba -> Jennu Kuruma */ {HB_TAG('x','u','p',' '), HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */ {HB_TAG('x','w','o',' '), HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */ {HB_TAG('y','a','j',' '), HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */ - {HB_TAG('y','a','k',' '), HB_TAG_NONE }, /* Yakama != Sakha */ -/*{HB_TAG('y','a','o',' '), HB_TAG('Y','A','O',' ')},*/ /* Yao */ -/*{HB_TAG('y','a','p',' '), HB_TAG('Y','A','P',' ')},*/ /* Yapese */ - {HB_TAG('y','b','a',' '), HB_TAG_NONE }, /* Yala != Yoruba */ {HB_TAG('y','b','b',' '), HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */ {HB_TAG('y','b','d',' '), HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */ {HB_TAG('y','c','r',' '), HB_TAG('C','P','P',' ')}, /* Yilan Creole -> Creoles */ {HB_TAG('y','d','d',' '), HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */ -/*{HB_TAG('y','g','p',' '), HB_TAG('Y','G','P',' ')},*/ /* Gepo */ {HB_TAG('y','i','h',' '), HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */ - {HB_TAG('y','i','m',' '), HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */ -/*{HB_TAG('y','n','a',' '), HB_TAG('Y','N','A',' ')},*/ /* Aluo */ {HB_TAG('y','o','s',' '), HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */ {HB_TAG('y','u','a',' '), HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */ {HB_TAG('y','u','e',' '), HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */ -/*{HB_TAG('y','u','f',' '), HB_TAG('Y','U','F',' ')},*/ /* Havasupai-Walapai-Yavapai */ -/*{HB_TAG('y','w','q',' '), HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */ {HB_TAG('z','c','h',' '), HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */ {HB_TAG('z','d','j',' '), HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */ -/*{HB_TAG('z','e','a',' '), HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */ {HB_TAG('z','e','h',' '), HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */ {HB_TAG('z','e','n',' '), HB_TAG('B','B','R',' ')}, /* Zenaga -> Berber */ {HB_TAG('z','g','b',' '), HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */ - {HB_TAG('z','g','h',' '), HB_TAG('Z','G','H',' ')}, /* Standard Moroccan Tamazight */ - {HB_TAG('z','g','h',' '), HB_TAG('B','B','R',' ')}, /* Standard Moroccan Tamazight -> Berber */ {HB_TAG('z','g','m',' '), HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */ {HB_TAG('z','g','n',' '), HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */ {HB_TAG('z','h','d',' '), HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */ @@ -1666,7 +1155,6 @@ static const LangTag ot_languages3[] = { {HB_TAG('z','l','q',' '), HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ {HB_TAG('z','m','i',' '), HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ {HB_TAG('z','m','z',' '), HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */ - {HB_TAG('z','n','d',' '), HB_TAG_NONE }, /* Zande [collection] != Zande */ {HB_TAG('z','n','e',' '), HB_TAG('Z','N','D',' ')}, /* Zande */ {HB_TAG('z','o','m',' '), HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ {HB_TAG('z','q','e',' '), HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ @@ -1677,9 +1165,439 @@ static const LangTag ot_languages3[] = { {HB_TAG('z','y','j',' '), HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */ {HB_TAG('z','y','n',' '), HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */ {HB_TAG('z','y','p',' '), HB_TAG('Q','I','N',' ')}, /* Zyphe Chin -> Chin */ -/*{HB_TAG('z','z','a',' '), HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */ {HB_TAG('z','z','j',' '), HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */ }; + +static const hb_tag_t ot_languages3_multi_values[] = { + HB_TAG('F','A','N',' '), /* Saint Lucian Creole French -> French Antillean */ + HB_TAG('C','P','P',' '), /* Saint Lucian Creole French -> Creoles */ + HB_TAG('A','C','R',' '), /* Achi */ + HB_TAG('M','Y','N',' '), /* Achi -> Mayan */ + HB_TAG('A','C','Y',' '), /* Cypriot Arabic */ + HB_TAG('A','R','A',' '), /* Cypriot Arabic -> Arabic */ + HB_TAG('S','W','A',' '), /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ + HB_TAG('S','Y','R',' '), /* Assyrian Neo-Aramaic -> Syriac */ + HB_TAG('A','K','B',' '), /* Batak Angkola */ + HB_TAG('B','T','K',' '), /* Batak Angkola -> Batak */ + HB_TAG('M','O','R',' '), /* Moroccan Arabic -> Moroccan */ + HB_TAG('A','R','A',' '), /* Moroccan Arabic -> Arabic */ + HB_TAG('A','Z','B',' '), /* South Azerbaijani -> Torki */ + HB_TAG('A','Z','E',' '), /* South Azerbaijani -> Azerbaijani */ + HB_TAG('B','B','C',' '), /* Batak Toba */ + HB_TAG('B','T','K',' '), /* Batak Toba -> Batak */ + HB_TAG('B','G','Q',' '), /* Bagri */ + HB_TAG('R','A','J',' '), /* Bagri -> Rajasthani */ + HB_TAG('B','L','K',' '), /* Pa’o Karen */ + HB_TAG('K','R','N',' '), /* Pa'o Karen -> Karen */ + HB_TAG('B','T','D',' '), /* Batak Dairi (Pakpak) */ + HB_TAG('B','T','K',' '), /* Batak Dairi -> Batak */ + HB_TAG('B','T','M',' '), /* Batak Mandailing */ + HB_TAG('B','T','K',' '), /* Batak Mandailing -> Batak */ + HB_TAG('B','T','S',' '), /* Batak Simalungun */ + HB_TAG('B','T','K',' '), /* Batak Simalungun -> Batak */ + HB_TAG('B','T','X',' '), /* Batak Karo */ + HB_TAG('B','T','K',' '), /* Batak Karo -> Batak */ + HB_TAG('B','T','Z',' '), /* Batak Alas-Kluet */ + HB_TAG('B','T','K',' '), /* Batak Alas-Kluet -> Batak */ + HB_TAG('B','Y','V',' '), /* Medumba */ + HB_TAG('B','M','L',' '), /* Medumba -> Bamileke */ + HB_TAG('C','R','R',' '), /* Southern Carrier -> Carrier */ + HB_TAG('A','T','H',' '), /* Southern Carrier -> Athapaskan */ + HB_TAG('C','A','K',' '), /* Kaqchikel */ + HB_TAG('M','Y','N',' '), /* Kaqchikel -> Mayan */ + HB_TAG('C','B','K',' '), /* Chavacano -> Zamboanga Chavacano */ + HB_TAG('C','P','P',' '), /* Chavacano -> Creoles */ + HB_TAG('H','A','L',' '), /* Halam (Falam Chin) */ + HB_TAG('Q','I','N',' '), /* Falam Chin -> Chin */ + HB_TAG('H','M','A',' '), /* Mari (Russia) [macrolanguage] -> High Mari */ + HB_TAG('L','M','A',' '), /* Mari (Russia) [macrolanguage] -> Low Mari */ + HB_TAG('C','H','P',' '), /* Chipewyan */ + HB_TAG('S','A','Y',' '), /* Chipewyan -> Sayisi */ + HB_TAG('A','T','H',' '), /* Chipewyan -> Athapaskan */ + HB_TAG('Q','U','H',' '), /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ + HB_TAG('Q','U','Z',' '), /* Chilean Quechua (retired code) -> Quechua */ + HB_TAG('E','C','R',' '), /* Southern East Cree -> Eastern Cree */ + HB_TAG('Y','C','R',' '), /* Southern East Cree -> Y-Cree */ + HB_TAG('C','R','E',' '), /* Southern East Cree -> Cree */ + HB_TAG('W','C','R',' '), /* Plains Cree -> West-Cree */ + HB_TAG('Y','C','R',' '), /* Plains Cree -> Y-Cree */ + HB_TAG('C','R','E',' '), /* Plains Cree -> Cree */ + HB_TAG('E','C','R',' '), /* Northern East Cree -> Eastern Cree */ + HB_TAG('Y','C','R',' '), /* Northern East Cree -> Y-Cree */ + HB_TAG('C','R','E',' '), /* Northern East Cree -> Cree */ + HB_TAG('M','C','R',' '), /* Moose Cree */ + HB_TAG('L','C','R',' '), /* Moose Cree -> L-Cree */ + HB_TAG('C','R','E',' '), /* Moose Cree -> Cree */ + HB_TAG('C','R','R',' '), /* Carrier */ + HB_TAG('A','T','H',' '), /* Carrier -> Athapaskan */ + HB_TAG('N','C','R',' '), /* Swampy Cree -> N-Cree */ + HB_TAG('N','H','C',' '), /* Swampy Cree -> Norway House Cree */ + HB_TAG('C','R','E',' '), /* Swampy Cree -> Cree */ + HB_TAG('D','C','R',' '), /* Woods Cree */ + HB_TAG('T','C','R',' '), /* Woods Cree -> TH-Cree */ + HB_TAG('C','R','E',' '), /* Woods Cree -> Cree */ + HB_TAG('S','L','A',' '), /* Slave (Athapascan) [macrolanguage] -> Slavey */ + HB_TAG('A','T','H',' '), /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ + HB_TAG('D','G','O',' '), /* Dogri (individual language) */ + HB_TAG('D','G','R',' '), /* Dogri (macrolanguage) */ + HB_TAG('D','I','Q',' '), /* Dimli */ + HB_TAG('Z','Z','A',' '), /* Dimli -> Zazaki */ + HB_TAG('D','R','I',' '), /* Darwazi (retired code) -> Dari */ + HB_TAG('F','A','R',' '), /* Darwazi (retired code) -> Persian */ + HB_TAG('E','M','K',' '), /* Eastern Maninkakan */ + HB_TAG('M','N','K',' '), /* Eastern Maninkakan -> Maninka */ + HB_TAG('F','A','N','0'), /* Fang (Equatorial Guinea) */ + HB_TAG('B','T','I',' '), /* Fang (Equatorial Guinea) -> Beti */ + HB_TAG('F','A','T',' '), /* Fanti */ + HB_TAG('A','K','A',' '), /* Fanti -> Akan */ + HB_TAG('H','A','L',' '), /* Halam (Falam Chin) (retired code) */ + HB_TAG('Q','I','N',' '), /* Falam Chin (retired code) -> Chin */ + HB_TAG('F','M','P',' '), /* Fe’fe’ */ + HB_TAG('B','M','L',' '), /* Fe'fe' -> Bamileke */ + HB_TAG('F','T','A',' '), /* Pular -> Futa */ + HB_TAG('F','U','L',' '), /* Pular -> Fulah */ + HB_TAG('F','U','V',' '), /* Nigerian Fulfulde */ + HB_TAG('F','U','L',' '), /* Nigerian Fulfulde -> Fulah */ + HB_TAG('G','K','P',' '), /* Guinea Kpelle -> Kpelle (Guinea) */ + HB_TAG('K','P','L',' '), /* Guinea Kpelle -> Kpelle */ + HB_TAG('H','M','D',' '), /* Large Flowery Miao -> A-Hmao */ + HB_TAG('H','M','N',' '), /* Large Flowery Miao -> Hmong */ + HB_TAG('H','M','Z',' '), /* Hmong Shua -> Hmong Shuat */ + HB_TAG('H','M','N',' '), /* Hmong Shua -> Hmong */ + HB_TAG('H','A','R',' '), /* Hadothi -> Harauti */ + HB_TAG('R','A','J',' '), /* Hadothi -> Rajasthani */ + HB_TAG('I','N','U',' '), /* Eastern Canadian Inuktitut -> Inuktitut */ + HB_TAG('I','N','U','K'), /* Eastern Canadian Inuktitut -> Nunavik Inuktitut */ + HB_TAG('J','A','M',' '), /* Jamaican Creole English -> Jamaican Creole */ + HB_TAG('C','P','P',' '), /* Jamaican Creole English -> Creoles */ + HB_TAG('K','A','B','0'), /* Kabyle */ + HB_TAG('B','B','R',' '), /* Kabyle -> Berber */ + HB_TAG('K','H','K',' '), /* Khanty -> Khanty-Kazim */ + HB_TAG('K','H','S',' '), /* Khanty -> Khanty-Shurishkar */ + HB_TAG('K','H','V',' '), /* Khanty -> Khanty-Vakhi */ + HB_TAG('K','E','A',' '), /* Kabuverdianu (Crioulo) */ + HB_TAG('C','P','P',' '), /* Kabuverdianu -> Creoles */ + HB_TAG('K','E','K',' '), /* Kekchi */ + HB_TAG('M','Y','N',' '), /* Kekchí -> Mayan */ + HB_TAG('K','H','T',' '), /* Khamti -> Khamti Shan */ + HB_TAG('K','H','N',' '), /* Khamti -> Khamti Shan (Microsoft fonts) */ + HB_TAG('K','I','U',' '), /* Kirmanjki */ + HB_TAG('Z','Z','A',' '), /* Kirmanjki -> Zazaki */ + HB_TAG('K','J','P',' '), /* Pwo Eastern Karen -> Eastern Pwo Karen */ + HB_TAG('K','R','N',' '), /* Pwo Eastern Karen -> Karen */ + HB_TAG('K','O','P',' '), /* Komi-Permyak */ + HB_TAG('K','O','M',' '), /* Komi-Permyak -> Komi */ + HB_TAG('K','O','Z',' '), /* Komi-Zyrian */ + HB_TAG('K','O','M',' '), /* Komi-Zyrian -> Komi */ + HB_TAG('K','A','R',' '), /* Karachay-Balkar -> Karachay */ + HB_TAG('B','A','L',' '), /* Karachay-Balkar -> Balkar */ + HB_TAG('K','R','I',' '), /* Krio */ + HB_TAG('C','P','P',' '), /* Krio -> Creoles */ + HB_TAG('K','S','W',' '), /* S’gaw Karen */ + HB_TAG('K','R','N',' '), /* S'gaw Karen -> Karen */ + HB_TAG('K','V','Q',' '), /* Geba Karen */ + HB_TAG('K','R','N',' '), /* Geba Karen -> Karen */ + HB_TAG('K','Y','U',' '), /* Western Kayah */ + HB_TAG('K','R','N',' '), /* Western Kayah -> Karen */ + HB_TAG('M','I','Z',' '), /* Lushai -> Mizo */ + HB_TAG('Q','I','N',' '), /* Lushai -> Chin */ + HB_TAG('M','A','M',' '), /* Mam */ + HB_TAG('M','Y','N',' '), /* Mam -> Mayan */ + HB_TAG('M','L','Y',' '), /* North Moluccan Malay -> Malay */ + HB_TAG('C','P','P',' '), /* North Moluccan Malay -> Creoles */ + HB_TAG('M','F','A',' '), /* Pattani Malay */ + HB_TAG('M','L','Y',' '), /* Pattani Malay -> Malay */ + HB_TAG('M','F','E',' '), /* Morisyen */ + HB_TAG('C','P','P',' '), /* Morisyen -> Creoles */ + HB_TAG('M','I','N',' '), /* Minangkabau */ + HB_TAG('M','L','Y',' '), /* Minangkabau -> Malay */ + HB_TAG('M','L','N',' '), /* Western Maninkakan -> Malinke */ + HB_TAG('M','N','K',' '), /* Western Maninkakan -> Maninka */ + HB_TAG('M','N','D',' '), /* Mandinka */ + HB_TAG('M','N','K',' '), /* Mandinka -> Maninka */ + HB_TAG('M','O','N',' '), /* Mon */ + HB_TAG('M','O','N','T'), /* Mon -> Thailand Mon */ + HB_TAG('M','L','Y',' '), /* Sabah Malay -> Malay */ + HB_TAG('C','P','P',' '), /* Sabah Malay -> Creoles */ + HB_TAG('M','W','W',' '), /* Hmong Daw */ + HB_TAG('H','M','N',' '), /* Hmong Daw -> Hmong */ + HB_TAG('N','A','G',' '), /* Naga Pidgin -> Naga-Assamese */ + HB_TAG('C','P','P',' '), /* Naga Pidgin -> Creoles */ + HB_TAG('O','C','R',' '), /* Severn Ojibwa -> Oji-Cree */ + HB_TAG('O','J','B',' '), /* Severn Ojibwa -> Ojibway */ + HB_TAG('P','A','P','0'), /* Papiamento -> Papiamentu */ + HB_TAG('C','P','P',' '), /* Papiamento -> Creoles */ + HB_TAG('A','R','A',' '), /* Sudanese Creole Arabic -> Arabic */ + HB_TAG('C','P','P',' '), /* Sudanese Creole Arabic -> Creoles */ + HB_TAG('P','I','H',' '), /* Pitcairn-Norfolk -> Norfolk */ + HB_TAG('C','P','P',' '), /* Pitcairn-Norfolk -> Creoles */ + HB_TAG('P','O','H',' '), /* Poqomchi' -> Pocomchi */ + HB_TAG('M','Y','N',' '), /* Poqomchi' -> Mayan */ + HB_TAG('D','R','I',' '), /* Dari */ + HB_TAG('F','A','R',' '), /* Dari -> Persian */ + HB_TAG('P','W','O',' '), /* Pwo Western Karen -> Western Pwo Karen */ + HB_TAG('K','R','N',' '), /* Pwo Western Karen -> Karen */ + HB_TAG('Q','W','H',' '), /* Huallaga Huánuco Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Huallaga Huánuco Quechua -> Quechua */ + HB_TAG('Q','U','C',' '), /* K’iche’ */ + HB_TAG('M','Y','N',' '), /* K'iche' -> Mayan */ + HB_TAG('Q','V','I',' '), /* Calderón Highland Quichua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Calderón Highland Quichua -> Quechua */ + HB_TAG('Q','V','I',' '), /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Chimborazo Highland Quichua -> Quechua */ + HB_TAG('Q','U','H',' '), /* South Bolivian Quechua -> Quechua (Bolivia) */ + HB_TAG('Q','U','Z',' '), /* South Bolivian Quechua -> Quechua */ + HB_TAG('Q','U','H',' '), /* North Bolivian Quechua -> Quechua (Bolivia) */ + HB_TAG('Q','U','Z',' '), /* North Bolivian Quechua -> Quechua */ + HB_TAG('Q','V','I',' '), /* Southern Pastaza Quechua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Southern Pastaza Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Yanahuanca Pasco Quechua -> Quechua */ + HB_TAG('Q','U','H',' '), /* Santiago del Estero Quichua -> Quechua (Bolivia) */ + HB_TAG('Q','U','Z',' '), /* Santiago del Estero Quichua -> Quechua */ + HB_TAG('Q','V','I',' '), /* Tena Lowland Quichua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Tena Lowland Quichua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Yauyos Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Yauyos Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Ambo-Pasco Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Ambo-Pasco Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */ + HB_TAG('Q','V','I',' '), /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Imbabura Highland Quichua -> Quechua */ + HB_TAG('Q','V','I',' '), /* Loja Highland Quichua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Loja Highland Quichua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Cajatambo North Lima Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Cajatambo North Lima Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* North Junín Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* North Junín Quechua -> Quechua */ + HB_TAG('Q','V','I',' '), /* Napo Lowland Quechua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Napo Lowland Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Pacaraos Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Pacaraos Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Huaylla Wanca Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Huaylla Wanca Quechua -> Quechua */ + HB_TAG('Q','V','I',' '), /* Northern Pastaza Quichua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Northern Pastaza Quichua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Corongo Ancash Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Corongo Ancash Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Huaylas Ancash Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Huaylas Ancash Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Sihuas Ancash Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Sihuas Ancash Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Chiquián Ancash Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Chiquián Ancash Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Chincha Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Chincha Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Panao Huánuco Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Panao Huánuco Quechua -> Quechua */ + HB_TAG('Q','V','I',' '), /* Salasaca Highland Quichua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Salasaca Highland Quichua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Northern Conchucos Ancash Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Southern Conchucos Ancash Quechua -> Quechua */ + HB_TAG('Q','V','I',' '), /* Cañar Highland Quichua -> Quechua (Ecuador) */ + HB_TAG('Q','U','Z',' '), /* Cañar Highland Quichua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Santa Ana de Tusi Pasco Quechua -> Quechua */ + HB_TAG('Q','W','H',' '), /* Jauja Wanca Quechua -> Quechua (Peru) */ + HB_TAG('Q','U','Z',' '), /* Jauja Wanca Quechua -> Quechua */ + HB_TAG('R','I','F',' '), /* Tarifit */ + HB_TAG('B','B','R',' '), /* Tarifit -> Berber */ + HB_TAG('R','M','Y',' '), /* Vlax Romani */ + HB_TAG('R','O','Y',' '), /* Vlax Romani -> Romany */ + HB_TAG('S','C','S',' '), /* North Slavey */ + HB_TAG('S','L','A',' '), /* North Slavey -> Slavey */ + HB_TAG('A','T','H',' '), /* North Slavey -> Athapaskan */ + HB_TAG('S','F','M',' '), /* Small Flowery Miao */ + HB_TAG('H','M','N',' '), /* Small Flowery Miao -> Hmong */ + HB_TAG('S','H','I',' '), /* Tachelhit */ + HB_TAG('B','B','R',' '), /* Tachelhit -> Berber */ + HB_TAG('T','A','Q',' '), /* Tamasheq */ + HB_TAG('T','M','H',' '), /* Tamasheq -> Tamashek */ + HB_TAG('B','B','R',' '), /* Tamasheq -> Berber */ + HB_TAG('T','H','V',' '), /* Tahaggart Tamahaq */ + HB_TAG('T','M','H',' '), /* Tahaggart Tamahaq -> Tamashek */ + HB_TAG('B','B','R',' '), /* Tahaggart Tamahaq -> Berber */ + HB_TAG('T','H','Z',' '), /* Tayart Tamajeq */ + HB_TAG('T','M','H',' '), /* Tayart Tamajeq -> Tamashek */ + HB_TAG('B','B','R',' '), /* Tayart Tamajeq -> Berber */ + HB_TAG('T','M','H',' '), /* Tamashek [macrolanguage] */ + HB_TAG('B','B','R',' '), /* Tamashek [macrolanguage] -> Berber */ + HB_TAG('D','R','I',' '), /* Tangshewi (retired code) -> Dari */ + HB_TAG('F','A','R',' '), /* Tangshewi (retired code) -> Persian */ + HB_TAG('T','P','I',' '), /* Tok Pisin */ + HB_TAG('C','P','P',' '), /* Tok Pisin -> Creoles */ + HB_TAG('T','U','A',' '), /* Turoyo -> Turoyo Aramaic */ + HB_TAG('S','Y','R',' '), /* Turoyo -> Syriac */ + HB_TAG('T','T','Q',' '), /* Tawallammat Tamajaq */ + HB_TAG('T','M','H',' '), /* Tawallammat Tamajaq -> Tamashek */ + HB_TAG('B','B','R',' '), /* Tawallammat Tamajaq -> Berber */ + HB_TAG('T','Z','M',' '), /* Central Atlas Tamazight -> Tamazight */ + HB_TAG('B','B','R',' '), /* Central Atlas Tamazight -> Berber */ + HB_TAG('T','Z','O',' '), /* Tzotzil */ + HB_TAG('M','Y','N',' '), /* Tzotzil -> Mayan */ + HB_TAG('V','R','O',' '), /* Võro */ + HB_TAG('E','T','I',' '), /* Võro -> Estonian */ + HB_TAG('W','A','G',' '), /* Wagdi */ + HB_TAG('R','A','J',' '), /* Wagdi -> Rajasthani */ + HB_TAG('W','D','T',' '), /* Wyandot (retired code) -> Wendat */ + HB_TAG('W','Y','N',' '), /* Wyandot (retired code) */ + HB_TAG('K','L','M',' '), /* Kalmyk */ + HB_TAG('T','O','D',' '), /* Kalmyk -> Todo */ + HB_TAG('M','L','Y',' '), /* Manado Malay -> Malay */ + HB_TAG('C','P','P',' '), /* Manado Malay -> Creoles */ + HB_TAG('X','P','E',' '), /* Liberia Kpelle -> Kpelle (Liberia) */ + HB_TAG('K','P','L',' '), /* Liberia Kpelle -> Kpelle */ + HB_TAG('S','S','L',' '), /* South Slavey */ + HB_TAG('S','L','A',' '), /* South Slavey -> Slavey */ + HB_TAG('A','T','H',' '), /* South Slavey -> Athapaskan */ + HB_TAG('Z','G','H',' '), /* Standard Moroccan Tamazight */ + HB_TAG('B','B','R',' '), /* Standard Moroccan Tamazight -> Berber */ +}; + +static const LangTagRange ot_languages3_multi[] = { + {HB_TAG('a','c','f',' '), 0, 2}, /* Saint Lucian Creole French -> French Antillean */ + {HB_TAG('a','c','r',' '), 2, 2}, /* Achi */ + {HB_TAG('a','c','y',' '), 4, 2}, /* Cypriot Arabic */ + {HB_TAG('a','i','i',' '), 6, 2}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ + {HB_TAG('a','k','b',' '), 8, 2}, /* Batak Angkola */ + {HB_TAG('a','r','y',' '), 10, 2}, /* Moroccan Arabic -> Moroccan */ + {HB_TAG('a','z','b',' '), 12, 2}, /* South Azerbaijani -> Torki */ + {HB_TAG('b','b','c',' '), 14, 2}, /* Batak Toba */ + {HB_TAG('b','g','q',' '), 16, 2}, /* Bagri */ + {HB_TAG('b','l','k',' '), 18, 2}, /* Pa’o Karen */ + {HB_TAG('b','t','d',' '), 20, 2}, /* Batak Dairi (Pakpak) */ + {HB_TAG('b','t','m',' '), 22, 2}, /* Batak Mandailing */ + {HB_TAG('b','t','s',' '), 24, 2}, /* Batak Simalungun */ + {HB_TAG('b','t','x',' '), 26, 2}, /* Batak Karo */ + {HB_TAG('b','t','z',' '), 28, 2}, /* Batak Alas-Kluet */ + {HB_TAG('b','y','v',' '), 30, 2}, /* Medumba */ + {HB_TAG('c','a','f',' '), 32, 2}, /* Southern Carrier -> Carrier */ + {HB_TAG('c','a','k',' '), 34, 2}, /* Kaqchikel */ + {HB_TAG('c','b','k',' '), 36, 2}, /* Chavacano -> Zamboanga Chavacano */ + {HB_TAG('c','f','m',' '), 38, 2}, /* Halam (Falam Chin) */ + {HB_TAG('c','h','m',' '), 40, 2}, /* Mari (Russia) [macrolanguage] -> High Mari */ + {HB_TAG('c','h','p',' '), 42, 3}, /* Chipewyan */ + {HB_TAG('c','q','u',' '), 45, 2}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ + {HB_TAG('c','r','j',' '), 47, 3}, /* Southern East Cree -> Eastern Cree */ + {HB_TAG('c','r','k',' '), 50, 3}, /* Plains Cree -> West-Cree */ + {HB_TAG('c','r','l',' '), 53, 3}, /* Northern East Cree -> Eastern Cree */ + {HB_TAG('c','r','m',' '), 56, 3}, /* Moose Cree */ + {HB_TAG('c','r','x',' '), 59, 2}, /* Carrier */ + {HB_TAG('c','s','w',' '), 61, 3}, /* Swampy Cree -> N-Cree */ + {HB_TAG('c','w','d',' '), 64, 3}, /* Woods Cree */ + {HB_TAG('d','e','n',' '), 67, 2}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ + {HB_TAG('d','g','o',' '), 69, 2}, /* Dogri (individual language) */ + {HB_TAG('d','i','q',' '), 71, 2}, /* Dimli */ + {HB_TAG('d','r','w',' '), 73, 2}, /* Darwazi (retired code) -> Dari */ + {HB_TAG('e','m','k',' '), 75, 2}, /* Eastern Maninkakan */ + {HB_TAG('f','a','n',' '), 77, 2}, /* Fang (Equatorial Guinea) */ + {HB_TAG('f','a','t',' '), 79, 2}, /* Fanti */ + {HB_TAG('f','l','m',' '), 81, 2}, /* Halam (Falam Chin) (retired code) */ + {HB_TAG('f','m','p',' '), 83, 2}, /* Fe’fe’ */ + {HB_TAG('f','u','f',' '), 85, 2}, /* Pular -> Futa */ + {HB_TAG('f','u','v',' '), 87, 2}, /* Nigerian Fulfulde */ + {HB_TAG('g','k','p',' '), 89, 2}, /* Guinea Kpelle -> Kpelle (Guinea) */ + {HB_TAG('h','m','d',' '), 91, 2}, /* Large Flowery Miao -> A-Hmao */ + {HB_TAG('h','m','z',' '), 93, 2}, /* Hmong Shua -> Hmong Shuat */ + {HB_TAG('h','o','j',' '), 95, 2}, /* Hadothi -> Harauti */ + {HB_TAG('i','k','e',' '), 97, 2}, /* Eastern Canadian Inuktitut -> Inuktitut */ + {HB_TAG('j','a','m',' '), 99, 2}, /* Jamaican Creole English -> Jamaican Creole */ + {HB_TAG('k','a','b',' '), 101, 2}, /* Kabyle */ + {HB_TAG('k','c','a',' '), 103, 3}, /* Khanty -> Khanty-Kazim */ + {HB_TAG('k','e','a',' '), 106, 2}, /* Kabuverdianu (Crioulo) */ + {HB_TAG('k','e','k',' '), 108, 2}, /* Kekchi */ + {HB_TAG('k','h','t',' '), 110, 2}, /* Khamti -> Khamti Shan */ + {HB_TAG('k','i','u',' '), 112, 2}, /* Kirmanjki */ + {HB_TAG('k','j','p',' '), 114, 2}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ + {HB_TAG('k','o','i',' '), 116, 2}, /* Komi-Permyak */ + {HB_TAG('k','p','v',' '), 118, 2}, /* Komi-Zyrian */ + {HB_TAG('k','r','c',' '), 120, 2}, /* Karachay-Balkar -> Karachay */ + {HB_TAG('k','r','i',' '), 122, 2}, /* Krio */ + {HB_TAG('k','s','w',' '), 124, 2}, /* S’gaw Karen */ + {HB_TAG('k','v','q',' '), 126, 2}, /* Geba Karen */ + {HB_TAG('k','y','u',' '), 128, 2}, /* Western Kayah */ + {HB_TAG('l','u','s',' '), 130, 2}, /* Lushai -> Mizo */ + {HB_TAG('m','a','m',' '), 132, 2}, /* Mam */ + {HB_TAG('m','a','x',' '), 134, 2}, /* North Moluccan Malay -> Malay */ + {HB_TAG('m','f','a',' '), 136, 2}, /* Pattani Malay */ + {HB_TAG('m','f','e',' '), 138, 2}, /* Morisyen */ + {HB_TAG('m','i','n',' '), 140, 2}, /* Minangkabau */ + {HB_TAG('m','l','q',' '), 142, 2}, /* Western Maninkakan -> Malinke */ + {HB_TAG('m','n','k',' '), 144, 2}, /* Mandinka */ + {HB_TAG('m','n','w',' '), 146, 2}, /* Mon */ + {HB_TAG('m','s','i',' '), 148, 2}, /* Sabah Malay -> Malay */ + {HB_TAG('m','w','w',' '), 150, 2}, /* Hmong Daw */ + {HB_TAG('n','a','g',' '), 152, 2}, /* Naga Pidgin -> Naga-Assamese */ + {HB_TAG('o','j','s',' '), 154, 2}, /* Severn Ojibwa -> Oji-Cree */ + {HB_TAG('p','a','p',' '), 156, 2}, /* Papiamento -> Papiamentu */ + {HB_TAG('p','g','a',' '), 158, 2}, /* Sudanese Creole Arabic -> Arabic */ + {HB_TAG('p','i','h',' '), 160, 2}, /* Pitcairn-Norfolk -> Norfolk */ + {HB_TAG('p','o','h',' '), 162, 2}, /* Poqomchi' -> Pocomchi */ + {HB_TAG('p','r','s',' '), 164, 2}, /* Dari */ + {HB_TAG('p','w','o',' '), 166, 2}, /* Pwo Western Karen -> Western Pwo Karen */ + {HB_TAG('q','u','b',' '), 168, 2}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','c',' '), 170, 2}, /* K’iche’ */ + {HB_TAG('q','u','d',' '), 172, 2}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','g',' '), 174, 2}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','h',' '), 176, 2}, /* South Bolivian Quechua -> Quechua (Bolivia) */ + {HB_TAG('q','u','l',' '), 178, 2}, /* North Bolivian Quechua -> Quechua (Bolivia) */ + {HB_TAG('q','u','p',' '), 180, 2}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ + {HB_TAG('q','u','r',' '), 182, 2}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','s',' '), 184, 2}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ + {HB_TAG('q','u','w',' '), 186, 2}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','x',' '), 188, 2}, /* Yauyos Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','a',' '), 190, 2}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','h',' '), 192, 2}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','i',' '), 194, 2}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','j',' '), 196, 2}, /* Loja Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','l',' '), 198, 2}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','m',' '), 200, 2}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','n',' '), 202, 2}, /* North Junín Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','o',' '), 204, 2}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ + {HB_TAG('q','v','p',' '), 206, 2}, /* Pacaraos Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','w',' '), 208, 2}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','z',' '), 210, 2}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','w','a',' '), 212, 2}, /* Corongo Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','h',' '), 214, 2}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','s',' '), 216, 2}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','a',' '), 218, 2}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','c',' '), 220, 2}, /* Chincha Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','h',' '), 222, 2}, /* Panao Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','l',' '), 224, 2}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','x','n',' '), 226, 2}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','o',' '), 228, 2}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','r',' '), 230, 2}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','x','t',' '), 232, 2}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','w',' '), 234, 2}, /* Jauja Wanca Quechua -> Quechua (Peru) */ + {HB_TAG('r','i','f',' '), 236, 2}, /* Tarifit */ + {HB_TAG('r','m','y',' '), 238, 2}, /* Vlax Romani */ + {HB_TAG('s','c','s',' '), 240, 3}, /* North Slavey */ + {HB_TAG('s','f','m',' '), 243, 2}, /* Small Flowery Miao */ + {HB_TAG('s','h','i',' '), 245, 2}, /* Tachelhit */ + {HB_TAG('t','a','q',' '), 247, 3}, /* Tamasheq */ + {HB_TAG('t','h','v',' '), 250, 3}, /* Tahaggart Tamahaq */ + {HB_TAG('t','h','z',' '), 253, 3}, /* Tayart Tamajeq */ + {HB_TAG('t','m','h',' '), 256, 2}, /* Tamashek [macrolanguage] */ + {HB_TAG('t','n','f',' '), 258, 2}, /* Tangshewi (retired code) -> Dari */ + {HB_TAG('t','p','i',' '), 260, 2}, /* Tok Pisin */ + {HB_TAG('t','r','u',' '), 262, 2}, /* Turoyo -> Turoyo Aramaic */ + {HB_TAG('t','t','q',' '), 264, 3}, /* Tawallammat Tamajaq */ + {HB_TAG('t','z','m',' '), 267, 2}, /* Central Atlas Tamazight -> Tamazight */ + {HB_TAG('t','z','o',' '), 269, 2}, /* Tzotzil */ + {HB_TAG('v','r','o',' '), 271, 2}, /* Võro */ + {HB_TAG('w','b','r',' '), 273, 2}, /* Wagdi */ + {HB_TAG('w','y','a',' '), 275, 2}, /* Wyandot (retired code) -> Wendat */ + {HB_TAG('x','a','l',' '), 277, 2}, /* Kalmyk */ + {HB_TAG('x','m','m',' '), 279, 2}, /* Manado Malay -> Malay */ + {HB_TAG('x','p','e',' '), 281, 2}, /* Liberia Kpelle -> Kpelle (Liberia) */ + {HB_TAG('x','s','l',' '), 283, 3}, /* South Slavey */ + {HB_TAG('z','g','h',' '), 286, 2}, /* Standard Moroccan Tamazight */ +}; #endif /** @@ -3205,7 +3123,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('Z','H','T','M'): /* Chinese, Traditional, Macao SAR */ return hb_language_from_string ("zh-MO", -1); /* Chinese [macrolanguage]; Macao */ case HB_TAG('Z','Z','A',' '): /* Zazaki */ - return hb_language_from_string ("zza", -1); /* Zazaki [macrolanguage] */ + return hb_language_from_string ("zza", -1); /* Zaza [macrolanguage] */ default: return HB_LANGUAGE_INVALID; } 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 786a220b6ec..79407dd6661 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc @@ -234,6 +234,29 @@ lang_matches (const char *lang_str, (lang_str[spec_len] == '\0' || lang_str[spec_len] == '-'); } +static bool +bfind_tag (const hb_tag_t *array, + unsigned len, + hb_tag_t key) +{ + unsigned min = 0; + unsigned max = len; + + while (min < max) + { + unsigned mid = min + (max - min) / 2; + hb_tag_t val = array[mid]; + if (key < val) + max = mid; + else if (key > val) + min = mid + 1; + else + return true; + } + + return false; +} + struct LangTag { hb_tag_t language; @@ -247,6 +270,20 @@ struct LangTag { return cmp (that->language); } }; +struct LangTagRange +{ + hb_tag_t language; + uint16_t offset; + uint8_t count; + + int cmp (hb_tag_t a) const + { + return a < this->language ? -1 : a > this->language ? +1 : 0; + } + int cmp (const LangTagRange *that) const + { return cmp (that->language); } +}; + #include "hb-ot-tag-table.hh" /* The corresponding languages IDs for the following IDs are unclear, @@ -307,46 +344,84 @@ hb_ot_tags_from_language (const char *lang_str, lang_str = s + 1; } #endif - const LangTag *ot_languages = nullptr; - unsigned ot_languages_len = 0; const char *dash = strchr (lang_str, '-'); unsigned first_len = dash ? dash - lang_str : limit - lang_str; + hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len); + if (first_len == 2) { - ot_languages = ot_languages2; - ot_languages_len = ARRAY_LENGTH (ot_languages2); + static hb_atomic_t last_tag_idx_2 = 0; /* Poor man's cache. */ + unsigned tag_idx = last_tag_idx_2; + + if (likely (tag_idx < ARRAY_LENGTH (ot_languages2) && + ot_languages2[tag_idx].language == lang_tag) || + hb_sorted_array (ot_languages2).bfind (lang_tag, &tag_idx)) + { + last_tag_idx_2 = tag_idx; + unsigned int i; + while (tag_idx != 0 && + ot_languages2[tag_idx].language == ot_languages2[tag_idx - 1].language) + tag_idx--; + for (i = 0; + i < *count && + tag_idx + i < ARRAY_LENGTH (ot_languages2) && + ot_languages2[tag_idx + i].tag != HB_TAG_NONE && + ot_languages2[tag_idx + i].language == ot_languages2[tag_idx].language; + i++) + tags[i] = ot_languages2[tag_idx + i].tag; + *count = i; + return; + } } #ifndef HB_NO_LANGUAGE_LONG else if (first_len == 3) { - ot_languages = ot_languages3; - ot_languages_len = ARRAY_LENGTH (ot_languages3); - } -#endif + static hb_atomic_t last_tag_idx_3 = 0; /* Poor man's cache. */ + unsigned tag_idx = last_tag_idx_3; - hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len); + if (likely (tag_idx < ARRAY_LENGTH (ot_languages3) && + ot_languages3[tag_idx].language == lang_tag) || + hb_sorted_array (ot_languages3).bfind (lang_tag, &tag_idx)) + { + last_tag_idx_3 = tag_idx; + if (*count) + { + tags[0] = ot_languages3[tag_idx].tag; + *count = 1; + } + else + *count = 0; + return; + } - static hb_atomic_t last_tag_idx = 0; /* Poor man's cache. */ - unsigned tag_idx = last_tag_idx; + static hb_atomic_t last_tag_idx_3_multi = 0; /* Poor man's cache. */ + unsigned multi_tag_idx = last_tag_idx_3_multi; - if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) || - hb_sorted_array (ot_languages, ot_languages_len).bfind (lang_tag, &tag_idx)) - { - last_tag_idx = tag_idx; - unsigned int i; - while (tag_idx != 0 && - ot_languages[tag_idx].language == ot_languages[tag_idx - 1].language) - tag_idx--; - for (i = 0; - i < *count && - tag_idx + i < ot_languages_len && - ot_languages[tag_idx + i].tag != HB_TAG_NONE && - ot_languages[tag_idx + i].language == ot_languages[tag_idx].language; - i++) - tags[i] = ot_languages[tag_idx + i].tag; - *count = i; + if (likely (multi_tag_idx < ARRAY_LENGTH (ot_languages3_multi) && + ot_languages3_multi[multi_tag_idx].language == lang_tag) || + hb_sorted_array (ot_languages3_multi).bfind (lang_tag, &multi_tag_idx)) + { + last_tag_idx_3_multi = multi_tag_idx; + const LangTagRange &range = ot_languages3_multi[multi_tag_idx]; + unsigned int i; + for (i = 0; i < *count && i < range.count; i++) + tags[i] = ot_languages3_multi_values[range.offset + i]; + *count = i; + return; + } + + if (bfind_tag (ot_languages3_blocked, ARRAY_LENGTH (ot_languages3_blocked), lang_tag)) + { + *count = 0; + return; + } + + /* Assume it's ISO-639-3 and upper-case and use it. */ + tags[0] = lang_tag & ~0x20202000u; + *count = 1; return; } +#endif } #ifndef HB_NO_LANGUAGE_LONG @@ -525,6 +600,13 @@ hb_ot_tag_to_language (hb_tag_t tag) hb_tag_to_string (ot_languages3[i].language, buf); return hb_language_from_string (buf, 3); } + for (i = 0; i < ARRAY_LENGTH (ot_languages3_multi); i++) + for (unsigned int j = 0; j < ot_languages3_multi[i].count; j++) + if (ot_languages3_multi_values[ot_languages3_multi[i].offset + j] == tag) + { + hb_tag_to_string (ot_languages3_multi[i].language, buf); + return hb_language_from_string (buf, 3); + } #endif /* Return a custom language in the form of "x-hbot-AABBCCDD". @@ -642,6 +724,23 @@ test_langs_sorted () abort(); } } + for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages3_multi); i++) + { + int c = ot_languages3_multi[i].cmp (&ot_languages3_multi[i - 1]); + if (c > 0) + { + fprintf (stderr, "ot_languages3_multi not sorted at index %u: %08x %d %08x\n", + i, ot_languages3_multi[i-1].language, c, ot_languages3_multi[i].language); + abort(); + } + } + for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages3_blocked); i++) + if (ot_languages3_blocked[i] < ot_languages3_blocked[i - 1]) + { + fprintf (stderr, "ot_languages3_blocked not sorted at index %u: %08x < %08x\n", + i, ot_languages3_blocked[i], ot_languages3_blocked[i - 1]); + abort(); + } #endif } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh index d0a4224c9b0..26c4d6cfec9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-common.hh @@ -40,7 +40,7 @@ using rebase_tent_result_scratch_t = hb_pair_tcheck_struct (this)); } - unsigned get_size (unsigned axis_count_times_2) const + size_t get_size (unsigned axis_count_times_2) const { unsigned total_size = min_size; unsigned count = tupleVarCount.get_count (); @@ -1700,6 +1707,16 @@ struct item_variations_t const hb_map_t& get_varidx_map () const { return varidx_map; } + bool add_vardata_encoding_for_testing (hb_vector_t*> &&rows, + unsigned num_cols) + { + encodings.push (delta_row_encoding_t (std::move (rows), num_cols)); + return !encodings.in_error (); + } + + bool compile_varidx_map_for_testing (const hb_hashmap_t*>& front_mapping) + { return compile_varidx_map (front_mapping); } + bool instantiate (const ItemVariationStore& varStore, const hb_subset_plan_t *plan, bool optimize=true, @@ -2046,27 +2063,46 @@ struct item_variations_t { /* full encoding_row -> new VarIdxes mapping */ hb_hashmap_t*, unsigned> back_mapping; + hb_vector_t split_encodings; - for (unsigned major = 0; major < encodings.length; major++) + for (unsigned i = 0; i < encodings.length; i++) { - delta_row_encoding_t& encoding = encodings[major]; + delta_row_encoding_t& encoding = encodings[i]; /* just sanity check, this shouldn't happen */ if (encoding.is_empty ()) return false; unsigned num_rows = encoding.items.length; + unsigned num_cols = encoding.chars.length; /* sort rows, make result deterministic */ encoding.items.qsort (_cmp_row); - /* compile old to new var_idxes mapping */ - for (unsigned minor = 0; minor < num_rows; minor++) + for (unsigned start = 0; start < num_rows; start += 0xFFFFu) { - unsigned new_varidx = (major << 16) + minor; - back_mapping.set (encoding.items.arrayZ[minor], new_varidx); + unsigned chunk_len = hb_min (num_rows - start, 0xFFFFu); + hb_vector_t*> rows; + + if (!rows.alloc (chunk_len)) + return false; + + unsigned major = split_encodings.length; + for (unsigned minor = 0; minor < chunk_len; minor++) + { + const hb_vector_t *row = encoding.items.arrayZ[start + minor]; + rows.push (row); + if (!back_mapping.set (row, (major << 16) + minor)) + return false; + } + + split_encodings.push (delta_row_encoding_t (std::move (rows), num_cols)); } } + encodings = std::move (split_encodings); + if (encodings.in_error () || back_mapping.in_error ()) + return false; + for (auto _ : front_mapping.iter ()) { unsigned old_varidx = _.first; 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 index 7c42f548456..ec24253b429 100644 --- 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 @@ -447,7 +447,7 @@ struct gvar_GVAR auto it = hb_iter (c->plan->new_to_old_gid_list); if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) it++; - unsigned int subset_data_size = 0; + size_t subset_data_size = 0; unsigned padding_size = 0; for (auto &_ : it) { @@ -634,6 +634,83 @@ struct gvar_GVAR static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end) { return (i >= end) ? start : (i + 1); } +#ifndef HB_OPTIMIZE_SIZE + template +#endif + static bool decompile_deltas_add_to_points (const HBUINT8 *&p /* IN/OUT */, + hb_array_t points, + float scalar, + const HBUINT8 *end, + unsigned start +#ifdef HB_OPTIMIZE_SIZE + , bool is_x +#endif + ) + { + unsigned i = 0; + unsigned count = points.length; + while (i < count) + { + if (unlikely (p + 1 > end)) return false; + unsigned control = *p++; + unsigned run_count = (control & TupleValues::VALUE_RUN_COUNT_MASK) + 1; + unsigned stop = i + run_count; + if (unlikely (stop > count)) return false; + + unsigned skip = i < start ? hb_min (start - i, run_count) : 0; + i += skip; + + switch (control & TupleValues::VALUES_SIZE_MASK) + { + case TupleValues::VALUES_ARE_ZEROS: + i = stop; + break; + case TupleValues::VALUES_ARE_WORDS: + { + if (unlikely (p + run_count * HBINT16::static_size > end)) return false; + p += skip * HBINT16::static_size; + const auto *pp = (const HBINT16 *) p; + for (; i < stop; i++) + { + float v = *pp++ * scalar; + if (is_x) points.arrayZ[i].x += v; + else points.arrayZ[i].y += v; + } + p = (const HBUINT8 *) pp; + } + break; + case TupleValues::VALUES_ARE_LONGS: + { + if (unlikely (p + run_count * HBINT32::static_size > end)) return false; + p += skip * HBINT32::static_size; + const auto *pp = (const HBINT32 *) p; + for (; i < stop; i++) + { + float v = *pp++ * scalar; + if (is_x) points.arrayZ[i].x += v; + else points.arrayZ[i].y += v; + } + p = (const HBUINT8 *) pp; + } + break; + case TupleValues::VALUES_ARE_BYTES: + { + if (unlikely (p + run_count > end)) return false; + p += skip * HBINT8::static_size; + const auto *pp = (const HBINT8 *) p; + for (; i < stop; i++) + { + float v = *pp++ * scalar; + if (is_x) points.arrayZ[i].x += v; + else points.arrayZ[i].y += v; + } + p = (const HBUINT8 *) pp; + } + break; + } + } + return true; + } public: bool apply_deltas_to_points (hb_codepoint_t glyph, hb_array_t coords, @@ -656,6 +733,9 @@ struct gvar_GVAR shared_indices, &iterator)) return true; /* so isn't applied at all */ + bool any_private_points = false; + bool private_points_checked = false; + /* Save original points for inferred delta calculation */ auto &orig_points_vec = scratch.orig_points; orig_points_vec.clear (); // Populated lazily @@ -682,6 +762,20 @@ struct gvar_GVAR gvar_cache); if (scalar == 0.f) continue; + + if (!private_points_checked) + { + auto scan = iterator; + do + { + if (scan.current_tuple->has_private_points ()) + { + any_private_points = true; + break; + } + } while (scan.move_to_next ()); + private_points_checked = true; + } 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))) @@ -706,6 +800,19 @@ struct gvar_GVAR bool apply_to_all = (indices.length == 0); unsigned num_deltas = apply_to_all ? points.length : indices.length; unsigned start_deltas = (apply_to_all && phantom_only && num_deltas >= 4 ? num_deltas - 4 : 0); + + if (apply_to_all && !any_private_points) + { +#ifdef HB_OPTIMIZE_SIZE + if (unlikely (!decompile_deltas_add_to_points (p, points, scalar, end, start_deltas, true))) return false; + if (unlikely (!decompile_deltas_add_to_points (p, points, scalar, end, start_deltas, false))) return false; +#else + if (unlikely (!decompile_deltas_add_to_points (p, points, scalar, end, start_deltas))) return false; + if (unlikely (!decompile_deltas_add_to_points (p, points, scalar, end, start_deltas))) return false; +#endif + continue; + } + if (unlikely (!x_deltas.resize_dirty (num_deltas))) return false; if (unlikely (!GlyphVariationData::decompile_deltas (p, x_deltas, end, false, start_deltas))) return false; if (unlikely (!y_deltas.resize_dirty (num_deltas))) return false; @@ -724,8 +831,6 @@ struct gvar_GVAR { for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++) points.arrayZ[i].translate (deltas.arrayZ[i]); - flush = false; - } hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0, (phantom_only ? 4 : count) * sizeof (deltas[0])); 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 652d738e7b5..5c0b415f4aa 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 @@ -180,7 +180,7 @@ struct index_map_subset_plan_t 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 + size_t get_size () const { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); } bool is_identity () const { return get_output_map ().length == 0; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-outline.hh b/src/java.desktop/share/native/libharfbuzz/hb-outline.hh index 9e394a68d9c..e23f5afa0a8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-outline.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-outline.hh @@ -65,7 +65,7 @@ struct hb_outline_vector_t struct hb_outline_t { - void reset () { points.shrink (0, false); contours.resize (0); } + void reset () { points.clear (); contours.clear (); } HB_INTERNAL void replay (hb_draw_funcs_t *pen, void *pen_data) const; HB_INTERNAL float control_area () const; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint.cc b/src/java.desktop/share/native/libharfbuzz/hb-paint.cc index 094597d6457..56e9c0901f1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint.cc @@ -71,6 +71,15 @@ hb_paint_push_clip_rectangle_nil (hb_paint_funcs_t *funcs, void *paint_data, float xmin, float ymin, float xmax, float ymax, void *user_data) {} +static hb_draw_funcs_t * +hb_paint_push_clip_path_start_nil (hb_paint_funcs_t *funcs, void *paint_data, + void **draw_data, + void *user_data) { if (draw_data) *draw_data = nullptr; return nullptr; } + +static void +hb_paint_push_clip_path_end_nil (hb_paint_funcs_t *funcs, void *paint_data, + void *user_data) {} + static void hb_paint_pop_clip_nil (hb_paint_funcs_t *funcs, void *paint_data, void *user_data) {} @@ -118,6 +127,14 @@ static void hb_paint_push_group_nil (hb_paint_funcs_t *funcs, void *paint_data, void *user_data) {} +static void +hb_paint_push_group_for_nil (hb_paint_funcs_t *funcs, void *paint_data, + hb_paint_composite_mode_t mode, + void *user_data) +{ + hb_paint_push_group (funcs, paint_data); +} + static void hb_paint_pop_group_nil (hb_paint_funcs_t *funcs, void *paint_data, hb_paint_composite_mode_t mode, @@ -158,25 +175,25 @@ _hb_paint_funcs_set_middle (hb_paint_funcs_t *funcs, void *user_data, hb_destroy_func_t destroy) { + auto destroy_guard = hb_make_scope_guard ([&]() { + if (destroy) destroy (user_data); + }); + if (user_data && !funcs->user_data) { funcs->user_data = (decltype (funcs->user_data)) hb_calloc (1, sizeof (*funcs->user_data)); if (unlikely (!funcs->user_data)) - goto fail; + return false; } if (destroy && !funcs->destroy) { funcs->destroy = (decltype (funcs->destroy)) hb_calloc (1, sizeof (*funcs->destroy)); if (unlikely (!funcs->destroy)) - goto fail; + return false; } + destroy_guard.release (); return true; - -fail: - if (destroy) - (destroy) (user_data); - return false; } #define HB_PAINT_FUNC_IMPLEMENT(name) \ @@ -573,6 +590,71 @@ hb_paint_push_clip_rectangle (hb_paint_funcs_t *funcs, void *paint_data, funcs->push_clip_rectangle (paint_data, xmin, ymin, xmax, ymax); } +/** + * hb_paint_push_clip_path_start: + * @funcs: paint functions + * @paint_data: associated data passed by the caller + * @draw_data: (out) (nullable): location to receive the draw data + * the caller should pass alongside the returned draw funcs. + * + * Begin clipping to an arbitrary path. Returns an + * #hb_draw_funcs_t owned by the backend (the caller must not + * free it) that the caller uses to emit the clip outline via + * hb_draw_*() calls, using the returned @draw_data as the + * draw data. The returned draw funcs and draw data are only + * valid until the matching hb_paint_push_clip_path_end() call; + * no other paint calls should be made between start and end + * except hb_draw_*() on the returned funcs. Finish the path + * with hb_paint_push_clip_path_end(); pop the clip later + * with hb_paint_pop_clip(). + * + * Usage: + * + * |[ + * hb_draw_funcs_t *df = hb_paint_push_clip_path_start (pf, pd, &dd); + * hb_draw_move_to (df, dd, NULL, ...); + * hb_draw_line_to (df, dd, NULL, ...); + * ... + * hb_draw_close_path (df, dd, NULL); + * hb_paint_push_clip_path_end (pf, pd); + * /* paint ops here are clipped to the emitted path */ + * hb_paint_pop_clip (pf, pd); + * ]| + * + * Return value: (transfer none): draw funcs that accumulate + * the clip path, or `NULL` if the backend does not implement + * arbitrary-path clipping. + * + * Since: 14.2.0 + */ +hb_draw_funcs_t * +hb_paint_push_clip_path_start (hb_paint_funcs_t *funcs, + void *paint_data, + void **draw_data) +{ + void *scratch = nullptr; + if (!draw_data) draw_data = &scratch; + return funcs->push_clip_path_start (paint_data, draw_data); +} + +/** + * hb_paint_push_clip_path_end: + * @funcs: paint functions + * @paint_data: associated data passed by the caller + * + * Signal that the arbitrary-clip path started by + * hb_paint_push_clip_path_start() is fully drawn. The + * accumulated path now acts as a clip on the paint context + * until a matching hb_paint_pop_clip() call. + * + * Since: 14.2.0 + */ +void +hb_paint_push_clip_path_end (hb_paint_funcs_t *funcs, void *paint_data) +{ + funcs->push_clip_path_end (paint_data); +} + /** * hb_paint_pop_clip: * @funcs: paint functions @@ -723,6 +805,25 @@ hb_paint_push_group (hb_paint_funcs_t *funcs, void *paint_data) funcs->push_group (paint_data); } +/** + * hb_paint_push_group_for: + * @funcs: paint functions + * @paint_data: associated data passed by the caller + * @mode: the compositing mode that will be used when the group is popped + * + * Perform a "push-group" paint operation, with the compositing + * mode known in advance. By default, this calls + * hb_paint_push_group(). + * + * Since: 14.2.0 + */ +void +hb_paint_push_group_for (hb_paint_funcs_t *funcs, void *paint_data, + hb_paint_composite_mode_t mode) +{ + funcs->push_group_for (paint_data, mode); +} + /** * hb_paint_pop_group: * @funcs: paint functions @@ -742,14 +843,14 @@ hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data, /** * hb_paint_custom_palette_color: - * @funcs: paint functions - * @paint_data: associated data passed by the caller - * @color_index: color index - * @color: (out): fetched color + * @funcs: paint functions. + * @paint_data: associated data passed by the caller. + * @color_index: color index to fetch. + * @color: (out): fetched color. * - * Gets the custom palette color for @color_index. + * Gets the custom palette override color for @color_index. * - * Return value: `true` if found, `false` otherwise + * Return value: `true` if a custom color is provided, `false` otherwise. * * Since: 7.0.0 */ @@ -761,4 +862,297 @@ hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data, return funcs->custom_palette_color (paint_data, color_index, color); } + +/** + * hb_paint_reduce_linear_anchors: + * @x0: x coordinate of P0 (color stop 0). + * @y0: y coordinate of P0 (color stop 0). + * @x1: x coordinate of P1 (color stop 1). + * @y1: y coordinate of P1 (color stop 1). + * @x2: x coordinate of P2 (rotation reference). + * @y2: y coordinate of P2 (rotation reference). + * @xx0: (out): x coordinate of the resulting axis start. + * @yy0: (out): y coordinate of the resulting axis start. + * @xx1: (out): x coordinate of the resulting axis end. + * @yy1: (out): y coordinate of the resulting axis end. + * + * Reduces a COLRv1 linear gradient's 3-anchor spec (P0=color + * stop 0, P1=color stop 1, P2=rotation reference) to the + * 2-point axis (P0, P1') used by SVG / cairo / most software + * renderers. P1' is the foot of P1 on the line through P0 + * perpendicular to (P2 - P0); the resulting axis is the + * gradient's actual direction (perpendicular to the rotation + * line). Degenerate (P0 == P2) passes through unchanged. + * + * Since: 14.2.0 + **/ +void +hb_paint_reduce_linear_anchors (float x0, float y0, + float x1, float y1, + float x2, float y2, + float *xx0, float *yy0, + float *xx1, float *yy1) +{ + float q2x = x2 - x0, q2y = y2 - y0; + float s = q2x * q2x + q2y * q2y; + if (s < 1e-6f) + { + *xx0 = x0; *yy0 = y0; + *xx1 = x1; *yy1 = y1; + return; + } + float q1x = x1 - x0, q1y = y1 - y0; + float k = (q2x * q1x + q2y * q1y) / s; + *xx0 = x0; + *yy0 = y0; + *xx1 = x1 - k * q2x; + *yy1 = y1 - k * q2y; +} + +/** + * hb_paint_normalize_color_line: + * @stops: (array length=len) (inout): color stops. + * @len: number of stops. + * @min: (out): original minimum offset. + * @max: (out): original maximum offset. + * + * Sorts @stops by offset and rescales offsets into [0, 1] in + * place. Writes the original (min, max) to @min / @max so the + * caller can shift the gradient geometry (axis endpoints for + * linear, centers+radii for radial, start+end angles for sweep) + * to keep the rendered gradient visually unchanged after the + * rescale. Empty input is safe: both out-parameters set to 0. + * + * Since: 14.2.0 + **/ +void +hb_paint_normalize_color_line (hb_color_stop_t *stops, + unsigned int len, + float *min, + float *max) +{ + if (unlikely (!len)) + { + *min = *max = 0.f; + return; + } + + hb_array_t (stops, len) + .qsort ([] (const hb_color_stop_t &a, const hb_color_stop_t &b) { + return a.offset < b.offset; + }); + + float mn = stops[0].offset, mx = stops[0].offset; + for (unsigned i = 1; i < len; i++) + { + mn = hb_min (mn, stops[i].offset); + mx = hb_max (mx, stops[i].offset); + } + if (mn != mx) + for (unsigned i = 0; i < len; i++) + stops[i].offset = (stops[i].offset - mn) / (mx - mn); + + *min = mn; + *max = mx; +} + +/** + * hb_paint_sweep_gradient_tiles: + * @stops: (array length=n_stops) (inout): color stops (sorted, offsets in [0,1]). + * @n_stops: number of stops. + * @extend: extend mode. + * @start_angle: sweep start angle, in radians. + * @end_angle: sweep end angle, in radians. + * @emit_patch: (scope call): callback invoked once per tile. + * @user_data: data passed to @emit_patch. + * + * Iterates the full 0..2π sweep produced by a color-stop list, + * invoking @emit_patch once per (start, end) angular segment. + * Handles #HB_PAINT_EXTEND_PAD, #HB_PAINT_EXTEND_REPEAT, and + * #HB_PAINT_EXTEND_REFLECT. Stops must be pre-sorted by + * offset; use hb_paint_normalize_color_line() first if they + * aren't. + * + * Since: 14.2.0 + **/ +void +hb_paint_sweep_gradient_tiles (hb_color_stop_t *stops, + unsigned int n_stops, + hb_paint_extend_t extend, + float start_angle, + float end_angle, + hb_paint_sweep_gradient_tile_func_t emit_patch, + void *user_data) +{ + if (!n_stops) return; + + if (start_angle == end_angle) + { + if (extend == HB_PAINT_EXTEND_PAD) + { + if (start_angle > 0.f) + emit_patch (0.f, stops[0].color, start_angle, stops[0].color, user_data); + if (end_angle < HB_2_PI) + emit_patch (end_angle, stops[n_stops - 1].color, HB_2_PI, stops[n_stops - 1].color, user_data); + } + return; + } + + if (end_angle < start_angle) + { + float tmp = start_angle; start_angle = end_angle; end_angle = tmp; + for (unsigned i = 0; i < n_stops - 1 - i; i++) + { + hb_color_stop_t t = stops[i]; + stops[i] = stops[n_stops - 1 - i]; + stops[n_stops - 1 - i] = t; + } + for (unsigned i = 0; i < n_stops; i++) + stops[i].offset = 1.f - stops[i].offset; + } + + /* Map stop offsets to angles. */ + float angles_buf[16]; + hb_color_t colors_buf[16]; + float *angles = angles_buf; + hb_color_t *colors = colors_buf; + bool dynamic = false; + + if (n_stops > 16) + { + angles = (float *) hb_malloc (sizeof (float) * n_stops); + colors = (hb_color_t *) hb_malloc (sizeof (hb_color_t) * n_stops); + if (!angles || !colors) + { + hb_free (angles); + hb_free (colors); + return; + } + dynamic = true; + } + + for (unsigned i = 0; i < n_stops; i++) + { + angles[i] = start_angle + stops[i].offset * (end_angle - start_angle); + colors[i] = stops[i].color; + } + + if (extend == HB_PAINT_EXTEND_PAD) + { + unsigned pos; + hb_color_t color0 = colors[0]; + for (pos = 0; pos < n_stops; pos++) + { + if (angles[pos] >= 0) + { + if (pos > 0) + { + float f = (0.f - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); + color0 = hb_color_lerp (colors[pos - 1], colors[pos], f); + } + break; + } + } + if (pos == n_stops) + { + color0 = colors[n_stops - 1]; + emit_patch (0.f, color0, HB_2_PI, color0, user_data); + goto done; + } + emit_patch (0.f, color0, angles[pos], colors[pos], user_data); + for (pos++; pos < n_stops; pos++) + { + if (angles[pos] <= HB_2_PI) + emit_patch (angles[pos - 1], colors[pos - 1], angles[pos], colors[pos], user_data); + else + { + float f = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); + hb_color_t color1 = hb_color_lerp (colors[pos - 1], colors[pos], f); + emit_patch (angles[pos - 1], colors[pos - 1], HB_2_PI, color1, user_data); + break; + } + } + if (pos == n_stops) + { + color0 = colors[n_stops - 1]; + emit_patch (angles[n_stops - 1], color0, HB_2_PI, color0, user_data); + goto done; + } + } + else + { + float span = angles[n_stops - 1] - angles[0]; + if (fabsf (span) < 1e-6f) + goto done; + + int k = 0; + if (angles[0] >= 0) + { + float ss = angles[0]; + while (ss > 0) + { + if (span > 0) { ss -= span; k--; } + else { ss += span; k++; } + } + } + else + { + float ee = angles[n_stops - 1]; + while (ee < 0) + { + if (span > 0) { ee += span; k++; } + else { ee -= span; k--; } + } + } + + span = fabsf (span); + for (int l = k; l < 1000; l++) + { + for (unsigned i = 1; i < n_stops; i++) + { + float a0_l, a1_l; + hb_color_t col0, col1; + if ((l % 2 != 0) && (extend == HB_PAINT_EXTEND_REFLECT)) + { + a0_l = angles[0] + angles[n_stops - 1] - angles[n_stops - i] + l * span; + a1_l = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span; + col0 = colors[n_stops - i]; + col1 = colors[n_stops - 1 - i]; + } + else + { + a0_l = angles[i - 1] + l * span; + a1_l = angles[i] + l * span; + col0 = colors[i - 1]; + col1 = colors[i]; + } + + if (a1_l < 0.f) continue; + if (a0_l < 0.f) + { + float f = (0.f - a0_l) / (a1_l - a0_l); + hb_color_t c = hb_color_lerp (col0, col1, f); + emit_patch (0.f, c, a1_l, col1, user_data); + } + else if (a1_l >= HB_2_PI) + { + float f = (HB_2_PI - a0_l) / (a1_l - a0_l); + hb_color_t c = hb_color_lerp (col0, col1, f); + emit_patch (a0_l, col0, HB_2_PI, c, user_data); + goto done; + } + else + emit_patch (a0_l, col0, a1_l, col1, user_data); + } + } + } + +done: + if (dynamic) + { + hb_free (angles); + hb_free (colors); + } +} + #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint.h b/src/java.desktop/share/native/libharfbuzz/hb-paint.h index 9827a02887b..e00d9b18732 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint.h @@ -30,6 +30,7 @@ #define HB_PAINT_H #include "hb-common.h" +#include "hb-draw.h" HB_BEGIN_DECLS @@ -212,6 +213,53 @@ typedef void (*hb_paint_push_clip_rectangle_func_t) (hb_paint_funcs_t *funcs, float xmax, float ymax, void *user_data); +/** + * hb_paint_push_clip_path_start_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph() + * @draw_data: (out): location to store the draw data the caller should + * pass alongside the returned draw funcs. + * @user_data: User data pointer passed to hb_paint_funcs_set_push_clip_path_start_func() + * + * A virtual method for the #hb_paint_funcs_t to begin clipping + * to an arbitrary path. The backend returns an + * #hb_draw_funcs_t it owns (the caller must not free it) + * that the caller feeds the clip outline to via hb_draw_*() + * calls, plus a @draw_data value to pass alongside those + * calls. Both are only valid until the matching + * #hb_paint_push_clip_path_end_func_t call; no other paint + * calls should be made in between. The clip remains + * in effect until a later #hb_paint_pop_clip_func_t call. + * + * Return value: (transfer none): draw funcs that accumulate + * the clip path, or `NULL` if arbitrary-path clipping is not + * supported. + * + * Since: 14.2.0 + */ +typedef hb_draw_funcs_t * (*hb_paint_push_clip_path_start_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + void **draw_data, + void *user_data); + +/** + * hb_paint_push_clip_path_end_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph() + * @user_data: User data pointer passed to hb_paint_funcs_set_push_clip_path_end_func() + * + * A virtual method for the #hb_paint_funcs_t to close the + * clip path started by the #hb_paint_push_clip_path_start_func_t + * vfunc. The emitted path is now active as a clip; subsequent + * paint ops are masked by it until a matching + * #hb_paint_pop_clip_func_t call. + * + * Since: 14.2.0 + */ +typedef void (*hb_paint_push_clip_path_end_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + void *user_data); + /** * hb_paint_pop_clip_func_t: * @funcs: paint functions object @@ -219,8 +267,9 @@ typedef void (*hb_paint_push_clip_rectangle_func_t) (hb_paint_funcs_t *funcs, * @user_data: User data pointer passed to hb_paint_funcs_set_pop_clip_func() * * A virtual method for the #hb_paint_funcs_t to undo - * the effect of a prior call to the #hb_paint_funcs_push_clip_glyph_func_t - * or #hb_paint_funcs_push_clip_rectangle_func_t vfuncs. + * the effect of a prior call to the #hb_paint_funcs_push_clip_glyph_func_t, + * #hb_paint_funcs_push_clip_rectangle_func_t, or + * #hb_paint_funcs_push_clip_path_end_func_t vfuncs. * * Since: 7.0.0 */ @@ -239,6 +288,23 @@ typedef void (*hb_paint_pop_clip_func_t) (hb_paint_funcs_t *funcs, * A virtual method for the #hb_paint_funcs_t to paint a * color everywhere within the current clip. * + * When @is_foreground is true, this color originates from the + * foreground-color sentinel in the font's color data. The + * @color parameter still carries a fully resolved RGBA value + * (with any paint-tree alpha already applied), so backends + * that do not need to distinguish the foreground can simply + * use @color directly. + * + * Backends that defer foreground resolution (e.g. to honor a + * CSS `currentColor` or a runtime uniform) should substitute + * their own foreground RGB when @is_foreground is true, but + * must combine the alpha from @color with their foreground + * alpha, since it encodes additional modulation from the + * paint tree. For this mode to work correctly, the caller + * should pass a fully-opaque foreground color to + * hb_font_paint_glyph(), so that the alpha in @color + * reflects only the paint-tree contribution. + * * Since: 7.0.0 */ typedef void (*hb_paint_color_func_t) (hb_paint_funcs_t *funcs, @@ -322,6 +388,9 @@ typedef hb_bool_t (*hb_paint_image_func_t) (hb_paint_funcs_t *funcs, * Color lines typically have offsets ranging between 0 and 1, * but that is not required. * + * The @is_foreground and @color fields have the same semantics + * as in #hb_paint_color_func_t. + * * Note: despite @color being unpremultiplied here, interpolation in * gradients shall happen in premultiplied space. See the OpenType spec * [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr) @@ -660,6 +729,28 @@ typedef void (*hb_paint_push_group_func_t) (hb_paint_funcs_t *funcs, void *paint_data, void *user_data); +/** + * hb_paint_push_group_for_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph() + * @mode: the compositing mode that will be used when the group is popped + * @user_data: User data pointer passed to hb_paint_funcs_set_push_group_for_func() + * + * A virtual method for the #hb_paint_funcs_t to use + * an intermediate surface for subsequent paint calls, + * with the compositing mode known in advance. + * + * This is like #hb_paint_push_group_func_t, but the + * compositing mode is provided at push time. By default + * this calls #hb_paint_push_group_func_t. + * + * Since: 14.2.0 + */ +typedef void (*hb_paint_push_group_for_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + hb_paint_composite_mode_t mode, + void *user_data); + /** * hb_paint_pop_group_func_t: * @funcs: paint functions object @@ -684,23 +775,24 @@ typedef void (*hb_paint_pop_group_func_t) (hb_paint_funcs_t *funcs, /** * hb_paint_custom_palette_color_func_t: - * @funcs: paint functions object - * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph() - * @color_index: the color index - * @color: (out): fetched color - * @user_data: User data pointer passed to hb_paint_funcs_set_pop_group_func() + * @funcs: paint functions object. + * @paint_data: data accompanying the paint functions in hb_font_paint_glyph(). + * @color_index: color index to fetch. + * @color: (out): fetched color. + * @user_data: user data pointer passed to hb_paint_funcs_set_custom_palette_color_func(). * - * A virtual method for the #hb_paint_funcs_t to fetch a color from the custom - * color palette. + * A virtual method for #hb_paint_funcs_t to fetch a custom palette override + * color for @color_index. * - * Custom palette colors override the colors from the fonts selected color - * palette. It is not necessary to override all palette entries; for entries - * that should be taken from the font palette, return `false`. + * Custom palette colors override colors from the font's selected color palette. + * It is not necessary to override all palette entries; return `false` for + * entries that should be taken from the font palette. * - * This function might get called multiple times, but the custom palette is - * expected to remain unchanged for duration of a hb_font_paint_glyph() call. + * This function might be called multiple times, but the custom palette is + * expected to remain unchanged for the duration of one + * hb_font_paint_glyph() call. * - * Return value: `true` if found, `false` otherwise + * Return value: `true` if a custom color is provided, `false` otherwise. * * Since: 7.0.0 */ @@ -796,6 +888,40 @@ hb_paint_funcs_set_push_clip_rectangle_func (hb_paint_funcs_t void *user_data, hb_destroy_func_t destroy); +/** + * hb_paint_funcs_set_push_clip_path_start_func: + * @funcs: A paint functions struct + * @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-path-start callback + * @user_data: Data to pass to @func + * @destroy: (nullable): Function to call when @user_data is no longer needed + * + * Sets the push-clip-path-start callback on the paint functions struct. + * + * Since: 14.2.0 + */ +HB_EXTERN void +hb_paint_funcs_set_push_clip_path_start_func (hb_paint_funcs_t *funcs, + hb_paint_push_clip_path_start_func_t func, + void *user_data, + hb_destroy_func_t destroy); + +/** + * hb_paint_funcs_set_push_clip_path_end_func: + * @funcs: A paint functions struct + * @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-path-end callback + * @user_data: Data to pass to @func + * @destroy: (nullable): Function to call when @user_data is no longer needed + * + * Sets the push-clip-path-end callback on the paint functions struct. + * + * Since: 14.2.0 + */ +HB_EXTERN void +hb_paint_funcs_set_push_clip_path_end_func (hb_paint_funcs_t *funcs, + hb_paint_push_clip_path_end_func_t func, + void *user_data, + hb_destroy_func_t destroy); + /** * hb_paint_funcs_set_pop_clip_func: * @funcs: A paint functions struct @@ -915,6 +1041,23 @@ hb_paint_funcs_set_push_group_func (hb_paint_funcs_t *funcs, void *user_data, hb_destroy_func_t destroy); +/** + * hb_paint_funcs_set_push_group_for_func: + * @funcs: A paint functions struct + * @func: (closure user_data) (destroy destroy) (scope notified): The push-group-for callback + * @user_data: Data to pass to @func + * @destroy: (nullable): Function to call when @user_data is no longer needed + * + * Sets the push-group-for callback on the paint functions struct. + * + * Since: 14.2.0 + */ +HB_EXTERN void +hb_paint_funcs_set_push_group_for_func (hb_paint_funcs_t *funcs, + hb_paint_push_group_for_func_t func, + void *user_data, + hb_destroy_func_t destroy); + /** * hb_paint_funcs_set_pop_group_func: * @funcs: A paint functions struct @@ -934,12 +1077,12 @@ hb_paint_funcs_set_pop_group_func (hb_paint_funcs_t *funcs, /** * hb_paint_funcs_set_custom_palette_color_func: - * @funcs: A paint functions struct - * @func: (closure user_data) (destroy destroy) (scope notified): The custom-palette-color callback - * @user_data: Data to pass to @func - * @destroy: (nullable): Function to call when @user_data is no longer needed + * @funcs: a paint functions struct. + * @func: (closure user_data) (destroy destroy) (scope notified): custom-palette-color callback. + * @user_data: data to pass to @func. + * @destroy: (nullable): function to call when @user_data is no longer needed. * - * Sets the custom-palette-color callback on the paint functions struct. + * Sets the custom-palette-color callback on @funcs. * * Since: 7.0.0 */ @@ -984,6 +1127,15 @@ hb_paint_push_clip_rectangle (hb_paint_funcs_t *funcs, void *paint_data, float xmin, float ymin, float xmax, float ymax); +HB_EXTERN hb_draw_funcs_t * +hb_paint_push_clip_path_start (hb_paint_funcs_t *funcs, + void *paint_data, + void **draw_data); + +HB_EXTERN void +hb_paint_push_clip_path_end (hb_paint_funcs_t *funcs, + void *paint_data); + HB_EXTERN void hb_paint_pop_clip (hb_paint_funcs_t *funcs, void *paint_data); @@ -1025,6 +1177,10 @@ hb_paint_sweep_gradient (hb_paint_funcs_t *funcs, void *paint_data, HB_EXTERN void hb_paint_push_group (hb_paint_funcs_t *funcs, void *paint_data); +HB_EXTERN void +hb_paint_push_group_for (hb_paint_funcs_t *funcs, void *paint_data, + hb_paint_composite_mode_t mode); + HB_EXTERN void hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data, hb_paint_composite_mode_t mode); @@ -1034,6 +1190,58 @@ hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data, unsigned int color_index, hb_color_t *color); + +/* + * Gradient helpers for paint backends. + * + * These are small, self-contained utilities that every COLRv1 + * renderer ends up reinventing. Exposed here so third-party + * paint backends can consume a single canonical implementation + * instead of forking one per project. + */ + +HB_EXTERN void +hb_paint_reduce_linear_anchors (float x0, float y0, + float x1, float y1, + float x2, float y2, + float *xx0, float *yy0, + float *xx1, float *yy1); + +HB_EXTERN void +hb_paint_normalize_color_line (hb_color_stop_t *stops, + unsigned int len, + float *min, + float *max); + +/** + * hb_paint_sweep_gradient_tile_func_t: + * @a0: segment start angle, in radians. + * @c0: segment start color. + * @a1: segment end angle, in radians. + * @c1: segment end color. + * @user_data: user data passed to hb_paint_sweep_gradient_tiles(). + * + * Callback invoked once per (a0, a1) sector of a sweep + * gradient tiling. See hb_paint_sweep_gradient_tiles(). + * + * Since: 14.2.0 + **/ +typedef void (*hb_paint_sweep_gradient_tile_func_t) (float a0, + hb_color_t c0, + float a1, + hb_color_t c1, + void *user_data); + +HB_EXTERN void +hb_paint_sweep_gradient_tiles (hb_color_stop_t *stops, + unsigned int n_stops, + hb_paint_extend_t extend, + float start_angle, + float end_angle, + hb_paint_sweep_gradient_tile_func_t emit_patch, + void *user_data); + + HB_END_DECLS #endif /* HB_PAINT_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-paint.hh b/src/java.desktop/share/native/libharfbuzz/hb-paint.hh index aedbcbdcbe2..df37e8bf6e9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-paint.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-paint.hh @@ -36,6 +36,8 @@ HB_PAINT_FUNC_IMPLEMENT (color_glyph) \ HB_PAINT_FUNC_IMPLEMENT (push_clip_glyph) \ HB_PAINT_FUNC_IMPLEMENT (push_clip_rectangle) \ + HB_PAINT_FUNC_IMPLEMENT (push_clip_path_start) \ + HB_PAINT_FUNC_IMPLEMENT (push_clip_path_end) \ HB_PAINT_FUNC_IMPLEMENT (pop_clip) \ HB_PAINT_FUNC_IMPLEMENT (color) \ HB_PAINT_FUNC_IMPLEMENT (image) \ @@ -43,6 +45,7 @@ HB_PAINT_FUNC_IMPLEMENT (radial_gradient) \ HB_PAINT_FUNC_IMPLEMENT (sweep_gradient) \ HB_PAINT_FUNC_IMPLEMENT (push_group) \ + HB_PAINT_FUNC_IMPLEMENT (push_group_for) \ HB_PAINT_FUNC_IMPLEMENT (pop_group) \ HB_PAINT_FUNC_IMPLEMENT (custom_palette_color) \ /* ^--- Add new callbacks here */ @@ -102,6 +105,13 @@ struct hb_paint_funcs_t { func.push_clip_rectangle (this, paint_data, xmin, ymin, xmax, ymax, !user_data ? nullptr : user_data->push_clip_rectangle); } + hb_draw_funcs_t *push_clip_path_start (void *paint_data, + void **draw_data) + { return func.push_clip_path_start (this, paint_data, draw_data, + !user_data ? nullptr : user_data->push_clip_path_start); } + void push_clip_path_end (void *paint_data) + { func.push_clip_path_end (this, paint_data, + !user_data ? nullptr : user_data->push_clip_path_end); } void pop_clip (void *paint_data) { func.pop_clip (this, paint_data, !user_data ? nullptr : user_data->pop_clip); } @@ -146,6 +156,11 @@ struct hb_paint_funcs_t void push_group (void *paint_data) { func.push_group (this, paint_data, !user_data ? nullptr : user_data->push_group); } + void push_group_for (void *paint_data, + hb_paint_composite_mode_t mode) + { func.push_group_for (this, paint_data, + mode, + !user_data ? nullptr : user_data->push_group_for); } void pop_group (void *paint_data, hb_paint_composite_mode_t mode) { func.pop_group (this, paint_data, @@ -245,4 +260,17 @@ struct hb_paint_funcs_t DECLARE_NULL_INSTANCE (hb_paint_funcs_t); +/* Linearly interpolate between two hb_color_t values, component-wise, + * in byte-channel space with rounding. */ +static inline hb_color_t +hb_color_lerp (hb_color_t c0, hb_color_t c1, float t) +{ + auto lerp = [&] (unsigned shift) -> unsigned { + unsigned v0 = (c0 >> shift) & 0xFF; + unsigned v1 = (c1 >> shift) & 0xFF; + return (unsigned) (v0 + t * ((float) v1 - (float) v0) + 0.5f); + }; + return HB_COLOR (lerp (0), lerp (8), lerp (16), lerp (24)); +} + #endif /* HB_PAINT_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh b/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh index 753e86b8ca6..8c32dabdd28 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-priority-queue.hh @@ -61,7 +61,7 @@ struct hb_priority_queue_t bubble_down (i); } - void reset () { heap.resize (0); } + void reset () { heap.clear (); } bool in_error () const { return heap.in_error (); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh b/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh index 7d118b52169..b5dfae19960 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-repacker.hh @@ -389,20 +389,21 @@ hb_resolve_graph_overflows (hb_tag_t table_tag, } unsigned round = 0; + unsigned total_iterations = 0; hb_vector_t overflows; // TODO(garretrieger): select a good limit for max rounds. while (!sorted_graph.in_error () && graph::will_overflow (sorted_graph, &overflows) - && round < max_rounds) { + && round < max_rounds + && total_iterations < HB_REPACKER_MAX_ITERATIONS) { DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %u ===", round); print_overflows (sorted_graph, overflows); + total_iterations++; hb_set_t priority_bumped_parents; if (!_try_isolating_subgraphs (overflows, sorted_graph)) { - // Don't count space isolation towards round limit. Only increment - // round counter if space isolation made no changes. round++; if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph)) { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-static.cc b/src/java.desktop/share/native/libharfbuzz/hb-static.cc index 06cc80b5f38..78713b22049 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-static.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-static.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HB_STATIC_CC +#define HB_STATIC_CC +#ifdef HB_STATIC_CC /* Pacify -Wunused-macros. */ + #include "hb.hh" #include "hb-open-type.hh" @@ -114,3 +118,6 @@ hb_face_t::load_upem () const } #endif + +#endif /* HB_STATIC_CC pacify */ +#endif /* HB_STATIC_CC guard */ 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 41b123609a9..e6d3ecccdbe 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 @@ -68,7 +68,6 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, /* use hb_set to determine the subset of font dicts */ hb_set_t set; hb_codepoint_t prev_fd = CFF_UNDEF_CODE; - hb_pair_t last_range {0, 0}; auto it = hb_iter (plan->new_to_old_gid_list); auto _ = *it; for (hb_codepoint_t gid = 0; gid < subset_num_glyphs; gid++) @@ -84,9 +83,8 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */ old_glyph = gid; } - if (old_glyph >= last_range.second) - last_range = src.get_fd_range (old_glyph); - unsigned fd = last_range.first; + auto fd_range = src.get_fd_range (old_glyph); + unsigned fd = fd_range.first; if (fd != prev_fd) { @@ -96,7 +94,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, fdselect_ranges.push (code_pair_t { fd, gid }); if (gid == old_glyph) - gid = hb_min (_.first - 1, last_range.second - 1); + gid = hb_min (_.first - 1, fd_range.second - 1); } } 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 843ad69f2f9..518b35466ff 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 @@ -321,11 +321,31 @@ struct cff_font_dict_op_serializer_t : op_serializer_t } }; +/* CharString command for specialization */ +struct cs_command_t +{ + hb_vector_t args; + hb_vector_t mask_bytes; /* For hintmask/cntrmask payload bytes. */ + op_code_t op; + + cs_command_t () : op (OpCode_Invalid) {} + cs_command_t (op_code_t op_) : op (op_) {} +}; + +typedef hb_vector_t *cs_command_vec_t; + struct flatten_param_t { + flatten_param_t (str_buff_t &flatStr_, + bool drop_hints_, + const hb_subset_plan_t *plan_, + cs_command_vec_t commands_ = nullptr) + : flatStr (flatStr_), drop_hints (drop_hints_), plan (plan_), commands (commands_) {} + str_buff_t &flatStr; bool drop_hints; const hb_subset_plan_t *plan; + cs_command_vec_t commands; /* Optional: capture parsed commands for specialization */ }; template @@ -335,7 +355,8 @@ struct subr_flattener_t const hb_subset_plan_t *plan_) : acc (acc_), plan (plan_) {} - bool flatten (str_buff_vec_t &flat_charstrings) + bool flatten (str_buff_vec_t &flat_charstrings, + hb_vector_t> *command_capture = nullptr) { unsigned count = plan->num_output_glyphs (); if (!flat_charstrings.resize_exact (count)) @@ -361,7 +382,8 @@ struct subr_flattener_t flatten_param_t param = { flat_charstrings.arrayZ[i], (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING), - plan + plan, + command_capture ? &(*command_capture)[i] : nullptr }; if (unlikely (!interp.interpret (param))) return false; 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 4938c048d6d..558b61121a7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc @@ -431,7 +431,8 @@ struct cff1_subset_plan unsigned code, last_code = CFF_UNDEF_CODE - 1; hb_vector_t supp_codes; - if (unlikely (!subset_enc_code_ranges.resize (0))) + subset_enc_code_ranges.clear (); + if (unlikely (subset_enc_code_ranges.in_error ())) { plan->check_success (false); return; @@ -496,7 +497,8 @@ struct cff1_subset_plan unsigned int size0, size_ranges; unsigned last_sid = CFF_UNDEF_CODE - 1; - if (unlikely (!subset_charset_ranges.resize (0))) + subset_charset_ranges.clear (); + if (unlikely (subset_charset_ranges.in_error ())) { plan->check_success (false); return false; 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 1074d240386..cce15bafe90 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc @@ -34,6 +34,7 @@ #include "hb-subset-plan.hh" #include "hb-subset-cff-common.hh" #include "hb-cff2-interp-cs.hh" +#include "hb-subset-cff2-to-cff1.hh" using namespace CFF; @@ -73,6 +74,56 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t &env, flatten_param_t& param) { + /* Optionally capture command for specialization (before flushing, to preserve args) */ + if (param.commands) + { + bool skip_command = false; + + switch (op) + { + case OpCode_return: + case OpCode_endchar: + skip_command = true; + break; + + case OpCode_hstem: + case OpCode_hstemhm: + case OpCode_vstem: + case OpCode_vstemhm: + case OpCode_hintmask: + case OpCode_cntrmask: + if (param.drop_hints) + skip_command = true; + break; + + default: + break; + } + + if (!skip_command) + { + cs_command_t cmd (op); + /* Capture resolved blend values */ + for (unsigned int i = 0; i < env.argStack.get_count ();) + { + const blend_arg_t &arg = env.argStack[i]; + if (arg.blending ()) + { + /* For blend args, capture only the resolved default value */ + cmd.args.push (arg); + /* Skip over the multiple blend values */ + i += arg.numValues; + } + else + { + cmd.args.push (arg); + i++; + } + } + param.commands->push (cmd); + } + } + switch (op) { case OpCode_return: @@ -167,6 +218,22 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t &env, flatten_param_t& param) { SUPER::flush_hintmask (op, env, param); + /* Preserve hintmask payload in captured commands for specializer re-encoding. */ + if (param.commands && !param.drop_hints && param.commands->length > 0) + { + auto &cmd = param.commands->tail (); + if (cmd.op == op) + { + cmd.mask_bytes.resize (env.hintmask_size); + if (unlikely (cmd.mask_bytes.in_error ())) + { + env.set_error (); + return; + } + for (unsigned int i = 0; i < env.hintmask_size; i++) + cmd.mask_bytes[i] = env.str_ref[i]; + } + } if (!param.drop_hints) { str_encoder_t encoder (param.flatStr); @@ -436,9 +503,15 @@ struct cff2_subset_plan drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING; pinned = (bool) plan->normalized_coords; + normalized_coords = plan->normalized_coords; + head_maxp_info = plan->head_maxp_info; + hmtx_map = &plan->hmtx_map; desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE || pinned; // For instancing we need this path + /* Enable command capture for CFF2→CFF1 conversion (for specialization) */ + capture_commands = pinned; + #ifdef HB_EXPERIMENTAL_API min_charstrings_off_size = (plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS) ? 4 : 0; #else @@ -450,8 +523,21 @@ struct cff2_subset_plan /* Flatten global & local subrs */ subr_flattener_t, cff2_cs_opset_flatten_t> flattener(acc, plan); - if (!flattener.flatten (subset_charstrings)) - return false; + + /* Enable command capture if requested (for specialization) */ + if (capture_commands) + { + if (!charstring_commands.resize_exact (num_glyphs)) + return false; + + if (!flattener.flatten (subset_charstrings, &charstring_commands)) + return false; + } + else + { + if (!flattener.flatten (subset_charstrings)) + return false; + } } else { @@ -518,9 +604,483 @@ struct cff2_subset_plan bool desubroutinize = false; unsigned min_charstrings_off_size = 0; + + hb_array_t normalized_coords; // For instantiation + head_maxp_info_t head_maxp_info; // For FontBBox + const hb_hashmap_t> *hmtx_map; // For widths + + // Width optimization results (for CFF1 conversion) + unsigned default_width = 0; + unsigned nominal_width = 0; + + // Command capture for specialization (CFF2→CFF1 conversion) + bool capture_commands = false; + hb_vector_t> charstring_commands; }; } // namespace OT +/* + * CFF2 to CFF1 Converter Implementation + */ + +#include "hb-cff-width-optimizer.hh" +#include "hb-cff-specializer.hh" + +/* Serialize charstrings using CFF1 format with widths */ +static bool +_serialize_cff1_charstrings (hb_serialize_context_t *c, + OT::cff2_subset_plan &plan, + unsigned default_width, + unsigned nominal_width) +{ + c->push (); + + // CFF1 requires: + // 1. Width at the beginning (if != defaultWidthX) + // 2. endchar at the end + str_buff_vec_t cff1_charstrings; + if (unlikely (!cff1_charstrings.resize (plan.subset_charstrings.length))) + { + c->pop_discard (); + return false; + } + + for (unsigned i = 0; i < plan.subset_charstrings.length; i++) + { + // Get width for this glyph from hmtx_map + unsigned width = 0; + if (plan.hmtx_map->has (i)) + width = plan.hmtx_map->get (i).first; + + // Encode width if different from default + str_encoder_t encoder (cff1_charstrings[i]); + if (width != default_width) + { + int delta = (int) width - (int) nominal_width; + encoder.encode_int (delta); + } + + // Use specialized commands if available, otherwise use binary + if (plan.capture_commands && i < plan.charstring_commands.length && + plan.charstring_commands[i].length > 0) + { + // Specialize and encode commands + auto &commands = plan.charstring_commands[i]; + CFF::specialize_commands (commands, 48); /* maxstack=48 for CFF1 */ + if (unlikely (!CFF::encode_commands (commands, cff1_charstrings[i]))) + { + c->pop_discard (); + return false; + } + } + else + { + // Use binary CharString + const str_buff_t &cs = plan.subset_charstrings[i]; + for (unsigned j = 0; j < cs.length; j++) + cff1_charstrings[i].push (cs[j]); + } + + // Check if it already ends with endchar (0x0e) or return (0x0b) + if (cff1_charstrings[i].length == 0 || + (cff1_charstrings[i].tail () != 0x0e && cff1_charstrings[i].tail () != 0x0b)) + { + // Append endchar operator + if (unlikely (!cff1_charstrings[i].push_or_fail (0x0e))) + { + c->pop_discard (); + return false; + } + } + } + + unsigned data_size = 0; + unsigned total_size = CFF1CharStrings::total_size (cff1_charstrings, &data_size); + if (unlikely (!c->start_zerocopy (total_size))) + { + c->pop_discard (); + return false; + } + + auto *cs = c->start_embed (); + if (unlikely (!cs->serialize (c, cff1_charstrings))) + { + c->pop_discard (); + return false; + } + + plan.info.char_strings_link = c->pop_pack (false); + return true; +} + +/* Serialize CID Charset (format 2 range: gid 0-N -> cid 0-N) */ +static bool +_serialize_cff1_charset (hb_serialize_context_t *c, + unsigned int num_glyphs, + objidx_t &charset_link) +{ + // For CID fonts, create a simple identity charset + // Format 2: one range covering all glyphs (except .notdef) + c->push (); + + auto *charset = c->start_embed (); + if (unlikely (!charset)) + { + c->pop_discard (); + return false; + } + + // Create a single range for CID 1 to num_glyphs-1 + hb_vector_t ranges; + if (num_glyphs > 1) + { + code_pair_t range; + range.code = 1; // first CID + range.glyph = num_glyphs - 2; // nLeft (covers glyphs 1 to num_glyphs-1) + ranges.push (range); + } + + if (unlikely (!charset->serialize (c, 2, num_glyphs, ranges))) + { + c->pop_discard (); + return false; + } + + charset_link = c->pop_pack (); + return true; +} + +/* CFF2 to CFF1 serialization */ +namespace CFF { + +bool +serialize_cff2_to_cff1 (hb_serialize_context_t *c, + OT::cff2_subset_plan &plan, + const cff2_top_dict_values_t &cff2_topDict, + const OT::cff2::accelerator_subset_t &acc) +{ + TRACE_SERIALIZE (this); + + /* + * CFF1 Serialization Order (reverse, as HarfBuzz packs from end): + * 1. CharStrings + * 2. Private DICs & Local Subrs + * 3. FDArray + * 4. FDSelect + * 5. Charset + * 6. Global Subrs + * 7. String INDEX + * 8. Top DICT INDEX + * 9. Name INDEX + * 10. Header + */ + + // 0. Optimize width encoding (for all FDs) + { + // Collect widths from hmtx_map + hb_vector_t widths; + widths.alloc (plan.num_glyphs); + + for (unsigned gid = 0; gid < plan.num_glyphs; gid++) + { + unsigned width = 0; + if (plan.hmtx_map->has (gid)) + width = plan.hmtx_map->get (gid).first; + widths.push (width); + } + + // Optimize defaultWidthX and nominalWidthX + CFF::optimize_widths (widths, plan.default_width, plan.nominal_width); + } + + // 1. CharStrings (with widths prepended) + if (!_serialize_cff1_charstrings (c, plan, plan.default_width, plan.nominal_width)) + return_trace (false); + + // 2. Private DICs & Local Subrs (same as CFF2) + hb_vector_t private_dict_infos; + if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) + return_trace (false); + + for (int i = (int)acc.privateDicts.length; --i >= 0;) + { + if (plan.fdmap.has (i)) + { + objidx_t subrs_link = 0; + + if (plan.subset_localsubrs[i].length > 0) + { + auto *dest = c->push (); + if (likely (dest->serialize (c, plan.subset_localsubrs[i]))) + subrs_link = c->pop_pack (false); + else + { + c->pop_discard (); + return_trace (false); + } + } + + auto *pd = c->push (); + // Use the CFF2 Private DICT serializer which instantiates blends when pinned=true + cff2_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints, plan.pinned, + acc.varStore, plan.normalized_coords); + if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link))) + { + // Add defaultWidthX and nominalWidthX for CFF1 + str_buff_t width_ops; + str_encoder_t encoder (width_ops); + encoder.encode_int (plan.default_width); + encoder.encode_op (OpCode_defaultWidthX); + encoder.encode_int (plan.nominal_width); + encoder.encode_op (OpCode_nominalWidthX); + + if (!encoder.in_error () && c->embed (width_ops.as_bytes ().arrayZ, width_ops.length)) + { + 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_trace (false); + } + } + else + { + c->pop_discard (); + return_trace (false); + } + } + } + + // 3. FDArray - serialize CFF2 font dicts as CFF1 + { + auto *fda = c->push> (); + 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)) + ; + // Explicitly specify template parameters: DICTVAL, INFO + bool success = fda->serialize (c, it, fontSzr); + if (success) + plan.info.fd_array_link = c->pop_pack (false); + else + { + c->pop_discard (); + return_trace (false); + } + } + + // 4. FDSelect (required in CFF1 CID-keyed fonts) + // CFF1 requires FDSelect for all CID-keyed fonts, even with just one FD + // CFF2 makes it optional when there's only one FD + if (acc.fdSelect != &Null (CFF2FDSelect)) + { + c->push (); + if (likely (hb_serialize_cff_fdselect (c, plan.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 + { + c->pop_discard (); + return_trace (false); + } + } + else + { + // Create a range-based FDSelect3 mapping all glyphs to FD 0 + // Format: format(1) + nRanges(2) + range(3) + sentinel(2) = 8 bytes + c->push (); + + // Format byte + HBUINT8 format; + format = 3; + if (unlikely (!c->embed (format))) + { + c->pop_discard (); + return_trace (false); + } + + // nRanges + HBUINT16 nRanges; + nRanges = 1; + if (unlikely (!c->embed (nRanges))) + { + c->pop_discard (); + return_trace (false); + } + + // Single range: {first: 0, fd: 0} + FDSelect3_Range range; + range.first = 0; + range.fd = 0; + if (unlikely (!c->embed (range))) + { + c->pop_discard (); + return_trace (false); + } + + // Sentinel (number of glyphs) + HBUINT16 sentinel; + sentinel = plan.num_glyphs; + if (unlikely (!c->embed (sentinel))) + { + c->pop_discard (); + return_trace (false); + } + + plan.info.fd_select.link = c->pop_pack (); + } + + // 5. Charset (CID charset for identity mapping) + objidx_t charset_link; + if (!_serialize_cff1_charset (c, plan.num_glyphs, charset_link)) + return_trace (false); + + // 6. Global Subrs + { + auto *dest = c->push (); + if (likely (dest->serialize (c, plan.subset_globalsubrs))) + c->pop_pack (false); + else + { + c->pop_discard (); + return_trace (false); + } + } + + // 7. String INDEX - Add "Adobe" and "Identity" for ROS operator + { + const char *adobe_str = "Adobe"; + const char *identity_str = "Identity"; + unsigned adobe_len = 5; // strlen("Adobe") + unsigned identity_len = 8; // strlen("Identity") + + // Build strings array + hb_vector_t strings; + strings.alloc (2); + strings.push (hb_ubytes_t ((const unsigned char *) adobe_str, adobe_len)); + strings.push (hb_ubytes_t ((const unsigned char *) identity_str, identity_len)); + + // Serialize as CFF INDEX + auto *dest = c->push (); + if (likely (dest->serialize (c, strings))) + c->pop_pack (false); + else + { + c->pop_discard (); + return_trace (false); + } + } + + // 8. CFF Header + OT::cff1 *cff = c->allocate_min (); + if (unlikely (!cff)) return_trace (false); + + /* header */ + cff->version.major = 0x01; + cff->version.minor = 0x00; + cff->nameIndex = cff->min_size; + cff->offSize = 4; /* unused? */ + + // 9. Name INDEX (single entry) + { + unsigned name_len = strlen (CFF1_DEFAULT_FONT_NAME); + + CFF1Index *idx = c->start_embed (); + if (unlikely (!idx)) return_trace (false); + + if (unlikely (!idx->serialize_header (c, hb_iter (&name_len, 1), name_len))) + return_trace (false); + + if (unlikely (!c->embed (CFF1_DEFAULT_FONT_NAME, name_len))) + return_trace (false); + } + + // 10. Top DICT INDEX + { + // Serialize the Top DICT data first + c->push (); + cff1_from_cff2_top_dict_op_serializer_t topSzr; + + // Serialize ROS first + if (unlikely (!topSzr.serialize_ros (c))) + { + c->pop_discard (); + return_trace (false); + } + + // Serialize FontBBox from head table + { + str_buff_t bbox_buff; + str_encoder_t encoder (bbox_buff); + + encoder.encode_int (plan.head_maxp_info.xMin); + encoder.encode_int (plan.head_maxp_info.yMin); + encoder.encode_int (plan.head_maxp_info.xMax); + encoder.encode_int (plan.head_maxp_info.yMax); + encoder.encode_op (OpCode_FontBBox); + + if (encoder.in_error () || !c->embed (bbox_buff.as_bytes ().arrayZ, bbox_buff.length)) + { + c->pop_discard (); + return_trace (false); + } + } + + // Serialize charset operator + if (charset_link && unlikely (!FontDict::serialize_link4_op (c, OpCode_charset, charset_link, whence_t::Absolute))) + { + c->pop_discard (); + return_trace (false); + } + + // Serialize FDSelect operator (required for CID-keyed CFF1 fonts) + if (plan.info.fd_select.link && unlikely (!FontDict::serialize_link4_op (c, OpCode_FDSelect, plan.info.fd_select.link, whence_t::Absolute))) + { + c->pop_discard (); + return_trace (false); + } + + // Serialize FDArray operator (required for CID-keyed CFF1 fonts) + if (plan.info.fd_array_link && unlikely (!FontDict::serialize_link4_op (c, OpCode_FDArray, plan.info.fd_array_link, whence_t::Absolute))) + { + c->pop_discard (); + return_trace (false); + } + + // Serialize other operators from CFF2 TopDict + for (const auto &opstr : cff2_topDict.values) + { + if (unlikely (!topSzr.serialize (c, opstr, plan.info))) + { + c->pop_discard (); + return_trace (false); + } + } + + unsigned top_size = c->length (); + c->pop_pack (false); + + // Serialize INDEX header + auto *dest = c->start_embed (); + if (unlikely (!dest->serialize_header (c, hb_iter (&top_size, 1), top_size))) + return_trace (false); + } + + return_trace (true); +} + +} /* namespace CFF */ + static bool _serialize_cff2_charstrings (hb_serialize_context_t *c, cff2_subset_plan &plan, const OT::cff2::accelerator_subset_t &acc) @@ -669,6 +1229,38 @@ OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const cff2_subset_plan cff2_plan; if (unlikely (!cff2_plan.create (*this, c->plan))) return false; + + // If instantiating (pinned) and downgrade flag is set, convert to CFF1 + if (cff2_plan.pinned && (c->plan->flags & HB_SUBSET_FLAGS_DOWNGRADE_CFF2)) + { + // Serialize CFF1 to the subsetter's serializer + // If we run out of room, returning true will cause subsetter to retry with larger buffer + bool result = CFF::serialize_cff2_to_cff1 (c->serializer, cff2_plan, topDict, *this); + + if (c->serializer->ran_out_of_room ()) + return true; // Subsetter will retry with larger buffer + + if (result && !c->serializer->in_error ()) + { + // Success - end serialization to resolve links + c->serializer->end_serialize (); + + // Copy the serialized CFF1 data and add as CFF table + hb_blob_t *cff_blob = c->serializer->copy_blob (); + if (cff_blob) + { + c->plan->add_table (HB_TAG('C','F','F',' '), cff_blob); + hb_blob_destroy (cff_blob); + + // Return false to signal CFF2 table is not needed + return false; + } + } + + // Conversion failed - don't fall back, fail hard for debugging + return false; + } + return serialize (c->serializer, cff2_plan, c->plan->normalized_coords.as_array ()); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc index 15227bdab48..78aab09c651 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-instancer-solver.cc @@ -370,7 +370,8 @@ double renormalizeValue (double v, const Triple &triple, const TripleDistances &triple_distances, bool extrapolate) { double lower = triple.minimum, def = triple.middle, upper = triple.maximum; - assert (lower <= def && def <= upper); + if (unlikely (!(lower <= def && def <= upper))) + return hb_clamp (v, -1.0, +1.0); if (!extrapolate) v = hb_clamp (v, lower, upper); @@ -384,14 +385,26 @@ double renormalizeValue (double v, const Triple &triple, /* default >= 0 and v != default */ if (v > def) - return (v - def) / (upper - def); + { + double positive_range = upper - def; + if (unlikely (!positive_range)) + return +1.0; + return (v - def) / positive_range; + } /* v < def */ if (lower >= 0.0) - return (v - def) / (def - lower); + { + double negative_range = def - lower; + if (unlikely (!negative_range)) + return -1.0; + return (v - def) / negative_range; + } /* lower < 0 and v < default */ double total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def; + if (unlikely (!total_distance)) + return 0.0; double v_distance; if (v >= 0.0) @@ -407,9 +420,19 @@ rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distance rebase_tent_result_t &out, rebase_tent_result_t &scratch) { - assert (-1.0 <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.0); - assert (-2.0 <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.0); - assert (tent.middle != 0.0); + if (unlikely (!(-1.0 <= axisLimit.minimum && + axisLimit.minimum <= axisLimit.middle && + axisLimit.middle <= axisLimit.maximum && + axisLimit.maximum <= +1.0) || + !(-2.0 <= tent.minimum && + tent.minimum <= tent.middle && + tent.middle <= tent.maximum && + tent.maximum <= +2.0) || + tent.middle == 0.0)) + { + out.reset (); + return; + } rebase_tent_result_t &sols = scratch; _solve (tent, axisLimit, sols); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.h b/src/java.desktop/share/native/libharfbuzz/hb-subset.h index fd2908e8308..edc13121825 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.h @@ -84,6 +84,9 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; * HB_SUBSET_FLAGS_RETAIN_GIDS then the number of glyphs in the font won't * be reduced as a result of subsetting. If necessary empty glyphs will be * included at the end of the font to keep the number of glyphs unchanged. + * @HB_SUBSET_FLAGS_DOWNGRADE_CFF2: If set and instantiating a variable font, + * convert the output CFF2 table to CFF1. This enables compatibility with older + * renderers that don't support CFF2. Since: 13.0.0 * * List of boolean properties that can be configured on the subset input. * @@ -107,6 +110,7 @@ typedef enum { /*< flags >*/ HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00001000u, HB_SUBSET_FLAGS_RETAIN_NUM_GLYPHS = 0x00002000u, #endif + HB_SUBSET_FLAGS_DOWNGRADE_CFF2 = 0x00004000u, } hb_subset_flags_t; /** @@ -239,13 +243,13 @@ hb_subset_input_override_name_table (hb_subset_input_t *input, */ HB_EXTERN hb_blob_t* -hb_subset_cff_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph_index); +hb_subset_cff_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph); HB_EXTERN hb_blob_t* hb_subset_cff_get_charstrings_index (hb_face_t* face); HB_EXTERN hb_blob_t* -hb_subset_cff2_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph_index); +hb_subset_cff2_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph); HB_EXTERN hb_blob_t* hb_subset_cff2_get_charstrings_index (hb_face_t* face); @@ -294,4 +298,12 @@ hb_subset_plan_get_user_data (const hb_subset_plan_t *plan, HB_END_DECLS + +#if defined(__cplusplus) && defined(HB_CPLUSPLUS_HH) +namespace hb { +HB_DEFINE_VTABLE (subset_input, nullptr); +HB_DEFINE_VTABLE (subset_plan, nullptr); +} // namespace hb +#endif + #endif /* HB_SUBSET_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh index 868428ab1e7..d2d23cf59b8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh @@ -763,1716 +763,1712 @@ static const uint64_t _hb_ucd_dm2_u64_map[408]= #include -static const uint8_t _hb_ucd_u8[19868]= +static const uint8_t _hb_ucd_u8[19845]= { - 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, 26, - 28, 26, 29, 30, 31, 32, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 33, 34, 34, 34, 34, - 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, - 26, 56, 57, 58, 58, 58, 58, 59, 26, 26, 60, 26, 26, 26, 26, 26, - 26, 61, 26, 62, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 63, 58, 58, 58, 26, 64, 65, 66, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 67, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 68, 69, 70, 58, 58, 58, 58, 71, 58, - 58, 58, 58, 58, 58, 58, 72, 73, 74, 75, 76, 77, 78, 79, 58, 80, - 81, 82, 83, 84, 85, 58, 86, 87, 88, 89, 78, 90, 91, 92, 58, 58, - 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, 93, 26, 26, 26, 26, 26, 26, 26, 26, 94, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 95, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 96, 26, 97, 58, 58, 58, 58, 26, 98, 58, 58, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 99, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,100, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 101, 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, 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, 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, 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, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,102, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,103, - 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, 36, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 40, 40, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, - 39, 39, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40, - 42, 42, 42, 42, 42, 42, 42, 42, 32, 32, 41, 32, 43, 44, 16, 10, - 43, 43, 40, 45, 11, 46, 46, 11, 34, 11, 11, 11, 11, 11, 11, 11, - 11, 47, 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, 48, 34, 32, 34, 11, - 32, 49, 42, 42, 50, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, - 47, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 46, 51, 2, 2, 2, - 16, 16, 16, 16, 52, 53, 54, 55, 56, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 57, 58, 59, 42, 58, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 61, - 36, 62, 63, 43, 43, 43, 43, 43, 64, 64, 64, 8, 9, 65, 2, 66, - 42, 42, 42, 42, 42, 59, 67, 2, 68, 36, 36, 36, 36, 69, 42, 42, - 7, 7, 7, 7, 7, 2, 2, 36, 70, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 71, 42, 42, 42, 72, 49, 42, 42, 73, 74, 75, 42, 42, 36, - 7, 7, 7, 7, 7, 36, 76, 77, 2, 2, 2, 2, 2, 2, 2, 78, - 69, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 79, 61, 36, - 36, 36, 36, 42, 42, 42, 42, 42, 70, 43, 43, 43, 43, 43, 43, 43, - 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, - 42, 42, 39, 21, 2, 80, 56, 20, 36, 36, 36, 42, 42, 74, 42, 42, - 42, 42, 74, 42, 74, 42, 42, 43, 2, 2, 2, 2, 2, 2, 2, 63, - 36, 36, 36, 36, 69, 42, 43, 63, 36, 36, 36, 36, 36, 60, 43, 43, - 36, 36, 36, 36, 81, 36, 36, 36, 64, 43, 43, 56, 42, 42, 42, 42, - 36, 36, 36, 36, 82, 42, 42, 42, 42, 83, 42, 42, 42, 42, 42, 42, - 42, 84, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84, 70, 85, - 86, 42, 42, 42, 84, 85, 86, 85, 69, 42, 42, 42, 36, 36, 36, 36, - 36, 42, 2, 7, 7, 7, 7, 7, 87, 36, 36, 36, 36, 36, 36, 36, - 69, 85, 61, 36, 36, 36, 60, 61, 60, 61, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 60, 36, 36, 36, 60, 60, 43, 36, 36, 43, 70, 85, - 86, 42, 79, 88, 89, 88, 86, 60, 43, 43, 43, 88, 43, 43, 36, 61, - 36, 42, 43, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 55, 62, 79, - 56, 84, 61, 36, 36, 60, 43, 61, 60, 36, 61, 60, 36, 43, 79, 85, - 86, 79, 43, 56, 79, 56, 42, 43, 56, 43, 43, 43, 61, 36, 60, 60, - 43, 43, 43, 7, 7, 7, 7, 7, 42, 36, 69, 63, 43, 43, 43, 43, - 56, 84, 61, 36, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, - 60, 36, 61, 36, 36, 43, 70, 85, 86, 42, 42, 56, 84, 88, 86, 43, - 60, 43, 43, 43, 43, 43, 43, 43, 65, 43, 43, 43, 61, 42, 42, 42, - 56, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 43, 70, 86, - 86, 42, 79, 88, 89, 88, 86, 43, 43, 43, 56, 84, 43, 43, 36, 61, - 77, 27, 27, 27, 43, 43, 43, 43, 43, 70, 61, 36, 36, 60, 43, 36, - 60, 36, 36, 43, 61, 60, 60, 36, 43, 61, 60, 43, 36, 60, 43, 36, - 36, 36, 36, 36, 36, 43, 43, 85, 84, 89, 43, 85, 89, 85, 86, 43, - 60, 43, 43, 88, 43, 43, 43, 43, 27, 90, 66, 66, 55, 91, 43, 43, - 84, 85, 70, 36, 36, 36, 60, 36, 60, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 43, 70, 42, 84, 85, 89, 42, 79, 42, 42, 43, - 43, 43, 56, 79, 36, 60, 36, 43, 43, 43, 43, 92, 27, 27, 27, 90, - 69, 85, 71, 36, 36, 36, 60, 36, 36, 36, 61, 36, 36, 43, 70, 86, - 85, 85, 89, 84, 89, 85, 42, 43, 43, 43, 88, 89, 43, 43, 36, 60, - 61, 93, 43, 43, 43, 43, 43, 43, 42, 85, 36, 36, 36, 36, 60, 36, - 36, 36, 36, 36, 36, 69, 70, 85, 86, 42, 79, 85, 89, 85, 86, 76, - 43, 43, 36, 93, 27, 27, 27, 94, 27, 27, 27, 27, 90, 36, 36, 36, - 56, 85, 61, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 36, 36, 36, - 36, 61, 36, 36, 36, 36, 61, 43, 36, 36, 36, 60, 43, 79, 43, 88, - 85, 42, 79, 79, 85, 85, 85, 85, 43, 85, 63, 43, 43, 43, 43, 43, - 61, 36, 36, 36, 36, 36, 36, 36, 69, 36, 42, 42, 42, 79, 43, 95, - 36, 36, 36, 74, 42, 42, 42, 59, 7, 7, 7, 7, 7, 2, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 61, 60, 60, 36, 36, 60, 36, 36, - 36, 36, 61, 61, 36, 36, 36, 36, 69, 36, 42, 42, 42, 42, 70, 43, - 36, 36, 60, 80, 42, 42, 42, 79, 7, 7, 7, 7, 7, 43, 36, 36, - 76, 66, 2, 2, 2, 2, 2, 2, 2, 96, 96, 66, 42, 66, 66, 66, - 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 49, 49, 49, 4, 4, 85, - 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, - 56, 42, 42, 42, 42, 42, 42, 84, 42, 42, 59, 42, 36, 36, 69, 42, - 42, 42, 42, 42, 56, 42, 42, 42, 42, 42, 42, 42, 42, 42, 79, 66, - 66, 66, 66, 75, 66, 66, 91, 66, 2, 2, 96, 66, 21, 63, 43, 43, - 36, 36, 36, 36, 36, 93, 86, 42, 84, 42, 42, 42, 86, 84, 86, 70, - 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 85, 42, 36, 36, 42, - 70, 85, 97, 93, 85, 85, 85, 36, 69, 42, 70, 36, 36, 36, 36, 36, - 36, 84, 86, 84, 85, 85, 86, 93, 7, 7, 7, 7, 7, 85, 86, 66, - 11, 11, 11, 47, 43, 43, 47, 43, 16, 16, 16, 16, 16, 52, 44, 16, - 36, 36, 36, 36, 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, - 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, 36, 36, 36, 36, - 36, 36, 36, 60, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 56, 42, - 2, 2, 2, 2, 98, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, - 66, 66, 66, 66, 66, 43, 43, 43, 11, 11, 11, 43, 16, 16, 16, 43, - 100, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 76, 71, - 101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,102,103, 43, - 36, 36, 36, 36, 36, 62, 2,104,105, 36, 36, 36, 60, 43, 43, 43, - 36, 42, 84, 43, 43, 43, 43, 61, 36, 42,106, 63, 43, 43, 43, 43, - 36, 42, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 60, 36, - 60, 42, 43, 43, 43, 43, 43, 43, 36, 36, 42, 86, 42, 42, 42, 85, - 85, 85, 85, 84, 86, 42, 42, 42, 42, 42, 2, 87, 2, 65, 69, 43, - 7, 7, 7, 7, 7, 43, 43, 43, 27, 27, 27, 27, 27, 43, 43, 43, - 2, 2, 2,107, 2, 58, 42, 83, 36, 82, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 60, 43, 43, 43, 36, 36, 69, 70, 36, 36, 36, 36, - 36, 36, 36, 36, 69, 60, 43, 43, 36, 36, 36, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 60, 42, 84, 85, 86, 84, 85, 43, 43, - 85, 84, 85, 85, 86, 42, 43, 43, 91, 43, 2, 7, 7, 7, 7, 7, - 36, 36, 36, 36, 36, 36, 36, 43, 36, 36, 60, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 43, 43, 36, 36, 36, 36, 36, 43, 43, 43, - 7, 7, 7, 7, 7, 99, 43, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 36, 36, 36, 69, 84, 86, 43, 2, 36, 36, 93, 84, 42, 42, 42, 79, - 84, 84, 86, 42, 42, 42, 84, 85, 85, 86, 42, 42, 42, 42, 79, 56, - 2, 2, 2, 87, 2, 2, 2, 43, 42, 42, 42, 42, 42, 42, 42,108, - 42, 42, 42, 42, 42, 42, 42, 43, 42, 42, 42, 42, 42, 42, 43, 43, - 42, 42, 97, 36, 36, 36, 36, 36, 36, 36, 84, 42, 42, 84, 84, 85, - 85, 84, 97, 36, 36, 36, 60, 2, 96, 66, 66, 66, 66, 49, 42, 42, - 42, 42, 66, 66, 66, 66, 21, 2, 42, 97, 36, 36, 36, 36, 36, 36, - 93, 42, 42, 85, 42, 86, 42, 36, 36, 36, 36, 84, 42, 85, 86, 86, - 42, 85, 43, 43, 43, 43, 2, 2, 36, 36, 85, 85, 85, 85, 42, 42, - 42, 42, 85, 42, 43, 92, 2, 2, 7, 7, 7, 7, 7, 43, 61, 36, - 36, 36, 36, 36, 39, 39, 39, 2, 16, 16, 16, 16, 34,109, 43, 43, - 11, 11, 11, 11, 11, 46, 47, 11, 2, 2, 2, 2, 43, 43, 43, 43, - 42, 59, 42, 42, 42, 42, 42, 42, 84, 42, 42, 42, 70, 36, 69, 36, - 36, 36, 70, 93, 42, 60, 43, 43, 16, 16, 16, 16, 16, 16, 39, 39, - 39, 39, 39, 39, 39, 44, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, - 16, 16, 16, 16, 16,110, 39, 39, 32, 32, 32, 16, 16, 16, 16, 32, - 16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 43, 11, 11, 11, 43, - 16, 16, 16, 16, 47, 47, 47, 47, 16, 16, 16, 16, 16, 16, 16, 43, - 16, 16, 16, 16,111,111,111,111, 16, 16,109, 16, 11, 11,112,113, - 40, 16,109, 16, 11, 11,112, 40, 16, 16, 43, 16, 11, 11,114, 40, - 16, 16, 16, 16, 11, 11,115, 40, 43, 16,109, 16, 11, 11,112,116, - 117,117,117,117,117,118, 64, 64,119,119,119, 2,120,121,120,121, - 2, 2, 2, 2,122, 64, 64,123, 2, 2, 2, 2,124,125, 2,126, - 127, 2,128,129, 2, 2, 2, 2, 2, 9,127, 2, 2, 2, 2,130, - 64, 64,131, 64, 64, 64, 64, 64,132, 43, 27, 27, 27, 8,128,133, - 27, 27, 27, 27, 27, 8,128,103, 39, 39, 39, 39, 39, 39, 80, 43, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43, 43, - 42, 42, 42, 42, 42, 42,134, 50,108, 50,108, 42, 42, 42, 42, 42, - 79, 43, 43, 43, 43, 43, 43, 43, 66,135, 66,136, 66, 34, 11, 16, - 11, 32,136, 66, 48, 11, 11, 66, 66, 66,135,135,135, 11, 11,137, - 11, 11, 35, 36,138, 66, 16, 11, 8, 8, 48, 16, 16, 26, 66,139, - 27, 27, 27, 27, 27, 27, 27, 27,104,104,104,104,104,104,104,104, - 104,140,141,104,142, 66, 43, 43, 8, 8,143, 66, 66, 8, 66, 66, - 143, 26, 66,143, 66, 66, 66,143, 66, 66, 66, 66, 66, 66, 66, 8, - 66,143,143, 66, 66, 66, 66, 66, 66, 66, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 66, 66, 66, 66, 4, 4, 66, 66, - 8, 66, 66, 66,144,145, 66, 66, 66, 66, 66, 66, 66, 66,143, 66, - 66, 66, 66, 66, 66, 26, 8, 8, 8, 8, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 8, 8, 8, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 91, 43, 43, 27, 27, 27, 27, 27, 27, 66, 66, - 66, 66, 66, 66, 66, 27, 27, 27, 66, 66, 66, 26, 66, 66, 66, 66, - 26, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 8, 8, 8, 8, - 66, 66, 66, 66, 66, 66, 66, 26, 66, 66, 66, 66, 4, 4, 4, 4, - 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, - 8, 8,128,146, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, - 8,128,147,147,147,147,147,147,147,147,147,147,146, 8, 8, 8, - 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, - 8, 8,143, 26, 8, 8,143, 66, 66, 66, 43, 66, 66, 66, 66, 66, - 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 39, 11, - 32, 32,139, 66, 66,136, 34,148, 42, 32, 43, 43, 92, 2, 98, 2, - 16, 16, 16,149, 43, 43,149, 43, 36, 36, 36, 36, 43, 43, 43, 51, - 63, 43, 43, 43, 43, 43, 43, 56, 36, 36, 36, 60, 43, 43, 43, 43, - 36, 36, 36, 60, 36, 36, 36, 60, 2,120,120, 2,124,125,120, 2, - 2, 2, 2, 6, 2,107,120, 2,120, 4, 4, 4, 4, 2, 2, 87, - 2, 2, 2, 2, 2,119, 2, 2,107,150, 2, 2, 2, 2, 2, 2, - 66, 2,151,147,147,147,152, 43, 66, 66, 66, 66, 66, 54, 66, 66, - 66, 66, 43, 43, 43, 43, 43, 43, 66, 66, 66, 43, 43, 43, 43, 43, - 1, 2,153,154, 4, 4, 4, 4, 4, 66, 4, 4, 4, 4,155,156, - 157,104,104,104,104, 42, 42, 85,158, 39, 39, 66,104,159, 62, 66, - 36, 36, 36, 60, 56,160,161, 68, 36, 36, 36, 36, 36, 62, 39, 68, - 43, 43, 61, 36, 36, 36, 36, 36, 66, 27, 27, 66, 66, 66, 66, 66, - 66, 66, 66, 43, 43, 43, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, - 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, - 162, 27, 27, 27, 27, 27, 27, 27, 36, 36, 82, 36, 36, 36, 36, 36, - 66, 66, 66, 91, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,163, 2, - 7, 7, 7, 7, 7, 36, 43, 43, 32, 32, 32, 32, 32, 32, 32, 69, - 50,164, 42, 42, 42, 42, 42, 87, 32, 32, 32, 32, 32, 32, 39, 42, - 36, 36, 36,104,104,104,104,104, 42, 2, 2, 2, 43, 43, 43, 43, - 40, 40, 40,161, 39, 39, 39, 39, 40, 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, 41,165, 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, - 32, 32, 11, 11, 34, 34, 32, 32, 32, 32, 32, 32, 32, 32, 46, 43, - 51, 39,166, 35, 39, 35, 36, 36, 36, 70, 36, 70, 36, 69, 36, 36, - 36, 93, 86, 84, 66, 66, 79, 43, 27, 27, 27, 66,167, 43, 43, 43, - 36, 36, 2, 2, 43, 43, 43, 43, 85, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 85, 85, 85, 85, 85, 85, 85, 85, 42, 43, 43, 43, 43, 2, - 42, 36, 36, 36, 2, 71, 71, 69, 36, 36, 36, 42, 42, 42, 42, 2, - 36, 36, 36, 69, 42, 42, 42, 42, 42, 85, 43, 43, 43, 43, 43, 92, - 36, 69, 85, 42, 42, 85, 42, 85,106, 2, 2, 2, 2, 2, 2, 51, - 7, 7, 7, 7, 7, 43, 43, 2, 36, 36, 69, 68, 36, 36, 36, 36, - 7, 7, 7, 7, 7, 36, 36, 60, 36, 36, 36, 36, 69, 42, 42, 84, - 86, 84, 86, 79, 43, 43, 43, 43, 36, 69, 36, 36, 36, 36, 84, 43, - 7, 7, 7, 7, 7, 43, 2, 2, 68, 36, 36, 76, 66, 93, 84, 36, - 70, 42, 70, 69, 70, 36, 36, 42, 69, 60, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 61, 82, 2, 36, 36, 36, 36, 36, 93, 42, 85, - 2, 82,168, 79, 43, 43, 43, 43, 61, 36, 36, 60, 61, 36, 36, 60, - 61, 36, 36, 60, 43, 43, 43, 43, 16, 16, 16, 16, 16,113, 39, 39, - 16, 16, 16, 16,110, 40, 43, 43, 36, 93, 86, 85, 84,106, 86, 43, - 36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 43, 61, 36, 36, - 169,169,169,169,169,169,169,169,170,170,170,170,170,170,170,170, - 16, 16, 16,109, 43, 43, 43, 43, 43,149, 16, 16, 43, 43, 61, 70, - 36, 36, 36, 36,171, 36, 36, 36, 36, 36, 36, 60, 36, 36, 60, 60, - 36, 61, 60, 36, 36, 36, 36, 36, 36, 40, 40, 40, 40, 40, 40, 40, - 40, 22, 66, 66, 66, 66, 66, 66, 66, 77, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36,147, 66, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 66, 66, 66, 66, 36, 36, 36, 36, 36, 36,167, 66, - 2, 2, 2,151,129, 43, 43, 43, 6,172,173,147,147,147,147,147, - 147,147,129,151,129, 2,126,174, 2, 63, 2, 2,155,147,147,129, - 2,175, 8,176, 65, 2, 43, 43, 36, 36, 60, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 60, 78, 92, 2, 3, 2, 4, 5, 6, 2, - 16, 16, 16, 16, 16, 17, 18,128,129, 4, 2, 36, 36, 36, 36, 36, - 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 39, - 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 60, 43, - 20,177, 55,178, 26, 8,143, 91, 43, 43, 43, 43, 78, 64, 66, 43, - 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 60, 36, 61, - 2, 63, 43,179, 27, 27, 27, 27, 27, 27, 43, 54, 66, 66, 66, 66, - 104,104,142, 27, 90, 66, 66, 66, 66, 66, 66, 66, 66, 27, 66, 91, - 66, 66, 66, 66, 66, 66, 91, 43, 91, 43, 43, 43, 43, 43, 43, 43, - 66, 66, 66, 66, 66, 66, 49, 43,180, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 43, 43, 27, 27, 43, 43, 43, 43, 61, 36, - 154, 36, 36, 36, 36,181, 43, 43, 36, 36, 36, 42, 42, 79, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 92, 36, 36, 43, 43, 36, 36, 36, 36, - 182,104,104, 43, 43, 43, 43, 43, 11, 11, 11, 11, 16, 16, 16, 16, - 11, 11, 43, 43, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 43, 43, - 36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, 43, 92, - 11, 11, 11, 11, 11, 46, 11, 11, 11, 46, 11,149, 16, 16, 16, 16, - 16,149, 16, 16, 16, 16, 16, 16, 16,149, 16, 16, 16,149,109, 43, - 39, 39, 39, 51, 39, 39, 39, 39, 80, 39, 39, 39, 39, 80, 43, 43, - 36, 36, 36, 43, 60, 36, 36, 36, 36, 36, 36, 61, 60, 43, 60, 61, - 36, 36, 36, 92, 27, 27, 27, 27, 36, 36, 36, 76,162, 27, 27, 27, - 43, 43, 43,179, 27, 27, 27, 27, 36, 60, 36, 43, 43,179, 27, 27, - 36, 36, 36, 27, 27, 27, 43, 92, 36, 36, 36, 36, 36, 43, 43, 92, - 36, 36, 36, 36, 43, 43, 27, 36, 43, 27, 27, 27, 27, 27, 27, 27, - 69, 42, 56, 79, 43, 43, 42, 42, 36, 36, 61, 36, 61, 36, 36, 36, - 36, 36, 36, 43, 42, 79, 43, 56, 27, 27, 27, 27, 99, 43, 43, 43, - 2, 2, 2, 2, 63, 43, 43, 43, 36, 36, 36, 36, 36, 36,183, 30, - 36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 77, 36, 36, 36, - 36, 36, 69, 79, 43,179, 27, 27, 2, 2, 2, 63, 43, 43, 43, 43, - 36, 36, 36, 43, 92, 2, 2, 2, 36, 36, 36, 43, 27, 27, 27, 27, - 36, 60, 43, 43, 27, 27, 27, 27, 36, 43, 43, 43, 92, 2, 63, 43, - 43, 43, 43, 43,179, 27, 27, 27, 11, 46, 43, 43, 43, 43, 43, 43, - 16,109, 43, 43, 43, 27, 27, 27, 36, 36, 42, 42, 43, 43, 43, 43, - 7, 7, 7, 7, 7, 36, 36, 68, 11, 11, 11, 43, 56, 42, 42,158, - 16, 16, 16, 43, 43, 43, 43, 8, 27, 27, 27, 27, 27, 27, 27, 99, - 36, 36, 36, 36, 36, 56,184, 43, 36, 43, 43, 43, 43, 43, 43, 43, - 43, 36, 82, 36, 43, 43, 43, 43, 96, 66, 66, 66, 91, 43, 43, 43, - 43, 43, 43, 43, 43, 42, 42, 42, 27, 27, 27, 94, 43, 43, 43, 43, - 180, 27, 30, 2, 2, 43, 43, 43, 36, 42, 42, 2, 2, 43, 43, 43, - 36, 36,183, 27, 27, 27, 43, 43, 86, 97, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 42, 59, 2, 2, 2, 43, - 27, 27, 27, 7, 7, 7, 7, 7, 70, 69, 70, 43, 43, 43, 43, 56, - 85, 86, 42, 84, 86, 59,185, 2, 2, 79, 43, 43, 43, 43, 78, 43, - 42, 70, 36, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, 86, 42, - 42, 42, 79, 7, 7, 7, 7, 7, 2, 2, 93, 97, 43, 43, 43, 43, - 36, 69, 2, 60, 43, 43, 43, 43, 36, 93, 85, 42, 42, 42, 42, 84, - 97, 36, 62, 2, 58, 42, 59, 86, 7, 7, 7, 7, 7, 62, 62, 2, - 179, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 85, 86, 42, 85, 84, 42, 2, 2, 2, 70, - 69, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 60, 36, 36, 61, - 36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 62, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 69, 85, 86, 42, 42, 42, 79, 43, 43, - 42, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 56, 70, 85, - 84, 85, 89, 88, 89, 88, 85, 43, 60, 43, 43, 88, 43, 43, 61, 36, - 36, 85, 43, 42, 42, 42, 79, 43, 42, 42, 79, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 61, 43, 60, 36, 36, 36, 61, 85, 86, 42, 42, - 79, 89, 88, 88, 85, 89, 85, 84, 70, 70, 2, 92, 63, 43, 43, 43, - 56, 79, 43, 43, 43, 43, 43, 43, 36, 36, 93, 85, 42, 42, 42, 42, - 85, 42, 84, 70, 36, 62, 2, 2, 7, 7, 7, 7, 7, 2, 92, 70, - 85, 86, 42, 42, 84, 84, 85, 86, 84, 42, 36, 71, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 93, 85, 42, 42, 43, 85, 85, 42, 86, - 59, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 42, 43, - 85, 86, 42, 42, 42, 84, 86, 86, 59, 2, 60, 43, 43, 43, 43, 43, - 2, 2, 2, 2, 2, 2, 63, 43, 36, 36, 36, 36, 36, 69, 86, 85, - 42, 42, 42, 86, 62, 43, 43, 43, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 56, 86, - 85, 42, 42, 86, 42, 42, 43, 43, 7, 7, 7, 7, 7, 27, 2, 96, - 42, 42, 42, 42, 86, 59, 43, 43, 27, 99, 43, 43, 43, 43, 43, 61, - 36, 36, 36, 60, 61, 43, 36, 36, 36, 36, 61, 60, 36, 36, 36, 36, - 85, 85, 85, 88, 89, 56, 84, 70, 97, 86, 2, 63, 43, 43, 43, 43, - 36, 36, 36, 36, 43, 36, 36, 36, 93, 85, 42, 42, 43, 42, 85, 85, - 70, 71, 89, 43, 43, 43, 43, 43, 69, 42, 42, 42, 42, 70, 36, 36, - 36, 69, 42, 42, 84, 69, 42, 59, 2, 2, 2, 58, 43, 43, 43, 43, - 69, 42, 42, 84, 86, 42, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, - 42, 42, 42, 84, 42, 2, 71, 2, 2, 63, 43, 43, 43, 43, 43, 43, - 2, 2, 2, 2, 2, 43, 43, 43, 84, 42, 84, 84, 43, 43, 43, 43, - 62, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 42, 42, 42, 86, - 62, 2, 2, 43, 43, 43, 43, 43, 2, 36, 36, 36, 36, 36, 36, 36, - 43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 88, 42, 42, 42, - 84, 42, 86, 79, 43, 43, 43, 43, 36, 36, 36, 60, 36, 61, 36, 36, - 69, 42, 42, 79, 43, 79, 42, 56, 42, 42, 42, 69, 43, 43, 43, 43, - 36, 36, 36, 61, 60, 36, 36, 36, 36, 36, 36, 36, 36, 85, 85, 89, - 42, 88, 86, 86, 60, 43, 43, 43, 36, 36, 36, 36, 82, 36, 43, 43, - 36, 69, 84,106, 63, 43, 43, 43, 42, 93, 36, 36, 36, 36, 36, 36, - 36, 36, 85, 42, 42, 79, 43, 85, 84, 59, 2, 2, 2, 2, 2, 2, - 7, 7, 7, 7, 7, 79, 43, 43, 27, 27, 90, 66, 66, 66, 55, 20, - 167, 66, 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 43, 43, 92, - 104,104,104,104,104,104,104,181, 2, 2, 63, 43, 43, 43, 43, 43, - 62, 63, 43, 43, 43, 43, 43, 43, 64, 64, 64, 64, 64, 64, 64, 64, - 70, 36, 36, 69, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 85, 86, 42, - 42, 42, 59, 43, 43, 43, 43, 43, 42, 42, 42, 59, 2, 2, 66, 66, - 39, 39, 96, 43, 43, 43, 43, 43, 7, 7, 7, 7, 7,179, 27, 27, - 27, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 61, 36, - 39, 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 82,163, 2, - 27, 27, 27, 30, 2, 63, 43, 43, 11, 11, 11, 11, 46,149, 16, 16, - 16, 16, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 43, 56, - 93, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 43, 43, 43, 56, 42, 73, 39, 39, 39, 39, 39, 39, - 39, 87, 79, 43, 43, 43, 43, 43, 85, 39,104,181, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 61, 36, 60, 43, 43, 43, 43, 43, 43, - 39, 39, 51, 39, 39, 39, 51, 80, 43, 60, 43, 43, 43, 43, 43, 43, - 36, 60, 61, 43, 43, 43, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 43, 49, 59, 64, 64, 43, 43, 43, 43, 43, 43, - 7, 7, 7, 7, 7, 66, 91, 43, 66, 66, 43, 43, 43, 66, 66, 66, - 176, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 43, 43, 43, 43, - 66, 66, 66, 91, 54, 66, 66, 66, 66, 66,186, 86, 42, 66,186, 85, - 85,187, 64, 64, 64, 83, 42, 42, 42, 75, 49, 42, 42, 42, 66, 66, - 66, 66, 66, 66, 66, 42, 42, 66, 66, 42, 75, 43, 43, 43, 43, 43, - 27, 27, 43, 43, 43, 43, 43, 43, 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,109, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 46, 11, 43, 46, 47, 46, 47, 11, 46, 11, - 11, 11, 11, 16, 16,149,149, 16, 16, 16,149, 16, 16, 16, 16, 16, - 16, 16, 11, 47, 11, 46, 47, 11, 11, 11, 46, 11, 11, 11, 46, 16, - 16, 16, 16, 16, 11, 47, 11, 46, 11, 11, 46, 46, 43, 11, 11, 11, - 46, 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, 43, 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, 43, 7, - 42, 42, 42, 75, 66, 49, 42, 42, 42, 42, 42, 42, 42, 42, 75, 66, - 66, 66, 49, 66, 66, 66, 66, 66, 66, 66, 75, 21, 2, 2, 43, 43, - 43, 43, 43, 43, 43, 56, 42, 42, 16, 16, 16, 16, 16,138, 16, 16, - 16, 16, 16, 16, 16, 16, 16,109, 43, 43,149, 16, 16,109, 43, 43, - 42, 42, 42, 79, 42, 42, 42, 42, 42, 42, 42, 42, 79, 56, 42, 42, - 42, 56, 79, 42, 42, 79, 43, 43, 39, 39, 39, 39, 39, 39, 39, 43, - 43, 43, 43, 43, 43, 43, 43, 56, 42, 42, 42, 73, 39, 39, 39, 43, - 7, 7, 7, 7, 7, 43, 43, 76, 36, 36, 36, 36, 36, 36, 36, 79, - 36, 36, 36, 36, 36, 36, 42, 42, 7, 7, 7, 7, 7, 43, 43, 95, - 36, 36, 36, 36, 36, 82, 42, 42,188, 7, 7, 7, 7,189, 43, 92, - 36, 69, 36, 70, 36, 36, 36, 42, 36, 36, 69, 43, 43, 43, 43, 82, - 36, 36, 36, 60, 36, 36, 61, 60, 36, 36, 60,179, 27, 27, 27, 27, - 16, 16, 42, 42, 42, 73, 43, 43, 27, 27, 27, 27, 27, 27,162, 27, - 190, 27, 99, 43, 43, 43, 43, 43, 27, 27, 27, 27, 27, 27, 27,162, - 27, 27, 27, 27, 27, 27, 27, 43, 36, 36, 61, 36, 36, 36, 36, 36, - 61, 60, 60, 61, 61, 36, 36, 36, 36, 60, 36, 36, 61, 61, 43, 43, - 43, 60, 43, 61, 61, 61, 61, 36, 61, 60, 60, 61, 61, 61, 61, 61, - 61, 60, 60, 61, 36, 60, 36, 36, 36, 60, 36, 36, 61, 36, 60, 60, - 36, 36, 36, 36, 36, 61, 36, 36, 61, 36, 61, 36, 36, 61, 36, 36, - 8, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 66, 43, 43, - 54, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, 27, 27, 90, 66, - 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 66, 66, 66, 66, 66, - 66, 91, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 91, 43, 43, 43, - 66, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 25, 40, 40, - 66, 66, 66, 66, 91, 43, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, - 8, 8, 8, 8,176, 43, 43, 43, 66, 66, 66, 66, 66, 91, 43, 66, - 66, 66, 66, 91, 91, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, 54, - 66, 66, 66, 66, 66, 91, 43, 54, 66, 91, 66, 66, 66, 66, 66, 66, - 7, 7, 7, 7, 7, 91, 43, 43, 78, 43, 43, 43, 43, 43, 43, 43, - 170,170,170,170,170,170,170, 43,170,170,170,170,170,170,170, 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, 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, 21, 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, 24, 7, 7, 6, 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, 10, 21, 17, 21, 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, 1, 2, 15, 6, 18, 6, 12, 11, 9, 26, - 26, 9, 26, 5, 7, 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, 21, 22, - 18, 17, 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, 6, 9, 23, 26, - 6, 10, 4, 4, 3, 3, 7, 25, 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, 7, 13, 13, 2, 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, + 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, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 32, 2, 33, 34, 35, 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 2, 58, 59, 0, 0, 0, 0, 60, 2, 2, 61, 2, 2, 2, 2, 2, + 2, 62, 2, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 2, 65, 66, 67, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 69, 70, 71, 0, 0, 0, 0, 72, 0, + 0, 0, 0, 0, 0, 0, 73, 74, 75, 76, 77, 78, 4, 79, 0, 80, + 81, 82, 83, 84, 85, 0, 86, 87, 88, 89, 4, 90, 91, 92, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 93, 2, 2, 2, 2, 2, 2, 2, 2, 94, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 96, 2, 97, 0, 0, 0, 0, 2, 98, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, - 0, 0, 0, 36, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, - 43, 44, 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, 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, 21, 0, 22, 23, 0, 24, 25, 0, - 0, 24, 26, 27, 0, 24, 26, 0, 0, 24, 26, 0, 0, 24, 26, 0, - 0, 0, 26, 0, 0, 24, 28, 0, 0, 24, 26, 0, 0, 29, 26, 0, - 0, 0, 30, 0, 0, 31, 32, 0, 0, 33, 34, 0, 35, 36, 0, 37, - 38, 0, 39, 0, 0, 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, 42, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, - 0, 0, 45, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 47, 0, 0, - 0, 0, 0, 0, 48, 0, 0, 49, 0, 50, 51, 52, 0, 53, 54, 55, - 0, 56, 0, 57, 0, 58, 0, 0, 0, 0, 59, 60, 0, 0, 0, 0, - 0, 0, 61, 62, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 66, - 0, 0, 0, 67, 0, 68, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 70, 71, 0, 0, 72, 0, 0, 0, 0, - 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, 54, 75, 0, 76, 77, 0, - 0, 78, 79, 0, 0, 0, 0, 0, 0, 80, 81, 82, 0, 0, 0, 0, - 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, - 0, 0, 0, 0, 0, 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, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 87, - 0, 0, 0, 0, 88, 89, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 92, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 94, 0, 0, 95, 0, - 96, 0, 0, 0, 0, 0, 73, 97, 0, 98, 0, 0, 99,100, 0, 78, - 0, 0,101, 0, 0,102, 0, 0, 0, 0, 0,103, 0,104, 26,105, - 0, 0,106, 0, 0, 0,107, 0, 0, 0,108, 0, 0, 0, 0, 0, - 0, 66,109, 0, 0, 66, 0, 0, 0,110, 0, 0, 0,111, 0, 0, - 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0,112,113, 0, - 0, 0, 0, 79, 0, 44,114, 0,115, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0,116, 0, - 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118, 0, - 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,120, 0,121, 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,123, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, - 125,126, 0, 0, 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,128,129, 0, 0,130, 0, 0, 0, 0,121, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,131, 0,132, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,133, 0, 0, 0, 0, - 0, 0, 0,134, 0, 0, 0, 0, 0, 0, 0,135, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,136, 0, 0, 0,137, 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, - 0, 19, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, - 54, 21, 35, 1, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 56, - 57, 58, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 59, 0, 0, 0, 56, 0, 60, 0, 0, 0, 0, 0, 0, - 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 68, 0, 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, 0, 0, - 71, 72, 73, 74, 75, 76, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, - 0, 80, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, - 63, 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, 62, 0, 0, 0, - 0, 49, 1, 85, 0, 0, 0, 0, 1, 52, 15, 86, 36, 10, 21, 1, - 1, 1, 1, 41, 1, 21, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 55, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 19, 10, - 1, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 89, 0, 0, - 88, 0, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, - 90, 9, 12, 4, 91, 8, 92, 47, 0, 58, 50, 0, 21, 1, 21, 93, - 94, 1, 1, 1, 1, 1, 1, 1, 1, 95, 96, 97, 0, 0, 0, 0, - 98, 1, 99, 58, 81,100,101, 4, 58, 0, 0, 0, 0, 0, 0, 19, - 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0,102,103, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,104, 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, 63, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 1, 1, 1, 1, - 50, 0, 0, 0, 0, 0,105, 68, 0, 0, 0, 0, 0, 0, 0, 0, - 61, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 62, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,106,107, 58, 38, 81, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, - 0, 0, 0,108, 1, 14, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 47, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 38, 90, 0, 0, 0, 0,109, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,110, 61, 0,111, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 49, 50, 0, 0, 0, 0, 0, 0, 19, 58, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112, 51, 0,112, 14, 52, - 84, 0, 0, 0,113, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 62, 0, 0, 61, 0, 0, 0, 0, 0, 0,114, 0, 90, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,114, 0, 0, 0, 0,115, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 55, 0, 38, 1, 58, - 1, 58, 0, 0, 0, 0, 0, 88, 62, 0, 0, 0, 63, 89, 0, 0, - 0, 0, 0, 59,116, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,116, 0, 0, 0, 0, 61, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 78, 0, 0, 0, - 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 56, 0, 89, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 61, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 92, 0, 0, 0, 0, 0, 0, - 1, 90, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,118, 0,119,120,121,122, 0,105, 4,123, 49, 23, 0, - 0, 0, 0, 0, 0, 0, 38, 50, 0, 0, 0, 0, 38, 58, 0, 0, - 0, 0, 0, 0, 1, 90, 1, 1, 1, 1, 39, 1, 48,106, 90, 0, - 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 59, - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,124, - 0, 0, 0, 0, 0, 0, 0,113, 0, 0, 0, 0, 19, 59, 0, 38, - 0, 81, 0, 0, 0, 0, 0, 0, 4,123, 0, 0, 0, 1,125, 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,230,220,220,220,230,230, 0,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, 9, 9, 0, 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, - 230,230,230,234, 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,218,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, 0, 0, 0,220,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, 0,230,220, 0, 9, 7, 0, - 0, 7, 9, 0, 0, 0, 9, 7, 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,232,232,220,230,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, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41, - 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, 0, 0, 0, 26, 34, 9, 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, 7, 9, 10, 11, 11, 11, 11, 12, 13, - 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 13, 13, 13, - 24, 25, 26, 26, 26, 27, 13, 13, 13, 28, 29, 30, 13, 31, 32, 33, - 34, 35, 36, 37, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 38, 7, 7, 39, 7, 40, 7, 7, - 7, 41, 13, 42, 7, 7, 43, 7, 7, 7, 44, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 13, 13, 13, - 13, 13, 13, 13, 45, 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, 59, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 59, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 78, 69, 69, 69, 69, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80, - 81, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 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, 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 69, 69, 96, 97, 98, 99, 99, 99, - 100,101,102,103,104,105,106,107,108,109, 95,110,111,112,113,114, - 115,116,117,117,118,119,120,121,122,123,124,125,126,127,128,129, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,102, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, + 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, + 11, 11, 11, 11, 11, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, + 13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 16, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 14, + 1, 1, 1, 1, 14, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, + 1, 5, 0, 11, 11, 11, 11, 11, 1, 1, 1, 1, 1, 1, 14, 0, + 1, 1, 1, 1, 14, 0, 0, 0, 6, 6, 6, 6, 7, 7, 7, 7, + 1, 1, 1, 1, 1, 14, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 14, 0, 0, 0, 0, + 1, 1, 1, 14, 1, 1, 1, 14, 3, 3, 3, 3, 3, 3, 0, 0, + 28, 28, 28, 28, 28, 28, 28, 28, 11, 11, 11, 11, 11, 1, 1, 1, + 14, 17, 1, 1, 1, 1, 1, 1, 14, 0, 0, 0, 0, 0, 0, 0, + 14, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 0, 0, 0, + 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 29, 0, + 11, 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 6, 6, 6, + 0, 0, 0, 11, 11, 11, 11, 11, 17, 1, 1, 1, 1, 1, 1, 1, + 11, 11, 11, 11, 11, 10, 10, 10, 1, 1, 1, 0, 0, 0, 0, 0, + 5, 46, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 41, 41, 41, 41, + 3, 3, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 0, 0, 12, + 1, 1, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, + 49, 10, 10, 10, 10, 10, 10, 10, 7, 6, 6, 6, 6, 6, 6, 6, + 44, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, + 3, 3, 3, 3, 0, 0, 0, 0, 11, 11, 11, 11, 11, 12, 9, 77, + 88, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,102,103,104, + 89, 6, 6, 6, 6, 6, 6, 6, 22, 22, 22, 22, 22, 22, 22, 22, + 26, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 5, 5, 5, 5, 5, + 5, 20, 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, + 11, 11, 11, 11, 11, 12, 12, 12, 1, 1, 1, 1, 14, 1, 1, 0, + 14, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 14, 1, 1, 1, 1, + 10, 10, 10, 10, 10, 10, 51, 0,115, 1, 1, 1, 1, 1, 1, 1, + 5, 5, 5, 5, 5, 5, 5, 0, 1, 1, 1, 1, 13, 13, 13, 12, + 6, 6, 6, 0, 7, 7, 7, 0, 30, 30, 30, 30, 30, 30, 30, 30, + 3, 3, 3, 3, 3, 29, 0, 0, 3, 3, 3, 3, 3, 3, 3, 29, + 10, 10, 10, 10, 10, 3, 3, 3, 75, 10, 10, 10, 10, 10, 10, 10, + 3, 3, 3, 29, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 32, 7, 7, 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 51, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 10, + 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 15, 19, + 1, 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 5, + 15, 15, 15, 15, 15, 15, 15, 15, 1, 14, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 23, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, + 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 3, 3, 3, 3, 29, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 87, 12,100, 12, 27,101, 76, 12, 6, 6, 6, 6, 6,105,106,135, + 87, 30, 30, 66,107,136,137,108, 50, 10, 89, 12,138,139, 10, 78, + 7, 7, 7, 59, 7, 7, 7, 8, 6, 6, 6, 60, 6, 6, 6, 6, + 8, 8, 8, 8, 21, 21, 21, 21, 21, 21, 21, 21, 6, 8, 8, 8, + 8, 8, 8, 8, 7, 21, 21, 6, 21, 8, 8, 7, 21, 7, 6, 7, + 7, 21, 8, 7, 8, 6, 7, 21, 8, 8, 8, 7, 21, 6, 8, 7, + 21, 7, 21, 21, 8, 67, 8, 6, 1, 1,109, 21,110,109, 21, 21, + 21, 21, 21, 21, 21, 21, 6, 8, 21,110, 8, 7, 8, 8, 8, 8, + 8, 8, 6, 6, 6, 7, 21, 8, 21, 21, 7, 8, 8, 8, 8, 8, + 6, 6, 1, 6, 6, 6, 6, 6, 13, 22, 22, 13, 13, 13, 13, 13, + 13, 22, 22, 22, 22, 22, 22, 22, 13, 13, 68, 22, 22, 22, 68, 68, + 8, 8, 68, 8, 0, 69, 6, 88, 0, 0, 22,140, 7, 32, 32, 7, + 21, 7, 7, 7, 7, 7, 7, 7, 7, 39, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 21, 6, 7, 8, 6, 8, 8, 8, 8, + 6, 6, 8, 90, 21, 8, 21, 7, 8, 43, 5, 5, 79, 8, 8, 8, + 7, 21, 21, 21, 21, 21, 21, 6, 39, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 32, 54, 12, 12, 12, 6, 6, 6, 6,111,141, 44, 70, + 5, 5, 5, 5, 5, 5, 5,142, 71, 36, 5, 71, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 14, 0, 17, 1, 40, 33, 0, 0, 0, 0, 0, + 18, 18, 18, 9, 77, 80, 12, 3, 5, 5, 5, 5, 5, 36,143, 12, + 52, 1, 1, 1, 1, 24, 5, 5, 11, 11, 11, 11, 11, 12, 12, 1, + 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 53, 5, 5, 5,144, 43, + 5, 5, 81, 72, 55, 5, 5, 1, 11, 11, 11, 11, 11, 1, 56, 82, + 12, 12, 12, 12, 12, 12, 12, 73, 24, 1, 1, 1, 1, 1, 1, 1, + 5, 5, 5, 5, 5, 23, 17, 1, 25, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 24, 5, 5, 5, 5, 13, 66, 12, 61, 26, 30, + 1, 1, 1, 5, 5, 72, 5, 5, 5, 5, 72, 5, 72, 5, 5, 0, + 12, 12, 12, 12, 12, 12, 12, 33, 1, 1, 1, 1, 24, 5, 0, 33, + 1, 1, 1, 1,145, 1, 1, 1, 18, 0, 0, 26, 5, 5, 5, 5, + 1, 1, 1, 1, 45, 5, 5, 5, 5, 91, 5, 5, 5, 5, 5, 5, + 1, 1, 1, 1, 1, 20, 25, 15, 19, 5, 5, 5, 20, 15, 19, 15, + 24, 5, 5, 5, 1, 1, 1, 1, 1, 5, 12, 11, 11, 11, 11, 11, + 62, 1, 1, 1, 1, 1, 1, 1, 24, 15, 17, 1, 1, 1, 14, 17, + 14, 14, 0, 1, 1, 0, 25, 15, 19, 5, 23, 35, 37, 35, 19, 14, + 0, 0, 0, 35, 0, 0, 1, 17, 1, 30, 10, 10, 10, 70, 40, 23, + 26, 20, 17, 1, 1, 14, 0, 17, 14, 1, 17, 14, 1, 0, 23, 15, + 19, 23, 0, 26, 23, 26, 5, 0, 26, 0, 0, 0, 17, 1, 14, 14, + 5, 1, 24, 33, 0, 0, 0, 0, 26, 20, 17, 1, 1, 1, 1, 17, + 14, 1, 17, 1, 1, 0, 25, 15, 19, 5, 5, 26, 20, 35, 19, 0, + 80, 0, 0, 0, 17, 5, 5, 5, 26, 15, 17, 1, 1, 1, 14, 17, + 14, 1, 17, 1, 1, 0, 25, 19, 19, 5, 23, 35, 37, 35, 19, 0, + 0, 0, 26, 20, 0, 0, 1, 17, 82, 10, 10, 10, 0, 0, 0, 0, + 0, 25, 17, 1, 1, 14, 0, 1, 14, 1, 1, 0, 17, 14, 14, 1, + 0, 17, 14, 0, 1, 14, 0, 1, 1, 1, 1, 1, 1, 0, 0, 15, + 20, 37, 0, 15, 37, 15, 19, 0, 14, 0, 0, 35, 0, 0, 0, 0, + 10, 63, 3, 3, 70, 29, 0, 0, 20, 15, 25, 1, 1, 1, 14, 1, + 1, 1, 1, 1, 1, 0, 25, 5, 20, 15, 37, 5, 23, 5, 5, 0, + 0, 0, 26, 23, 1, 14, 1, 0, 0, 0, 0, 38, 10, 10, 10, 63, + 24, 15, 53, 1, 1, 1, 14, 1, 1, 1, 17, 1, 1, 0, 25, 19, + 15, 15, 37, 20, 37, 15, 5, 0, 0, 0, 35, 37, 0, 0, 1, 14, + 17, 34, 0, 0, 0, 0, 0, 0, 5, 15, 1, 1, 1, 1, 14, 1, + 1, 1, 1, 1, 1, 24, 25, 15, 19, 5, 23, 15, 37, 15, 19, 56, + 0, 0, 1, 34, 10, 10, 10,112, 10, 10, 10, 10, 63, 1, 1, 1, + 26, 15, 17, 1, 1, 1, 1, 1, 1, 1, 1, 14, 0, 1, 1, 1, + 1, 17, 1, 1, 1, 1, 17, 0, 1, 1, 1, 14, 0, 23, 0, 35, + 15, 5, 23, 23, 15, 15, 15, 15, 0, 15, 33, 0, 0, 0, 0, 0, + 24, 1, 5, 5, 5, 23, 0,113, 1, 1, 1, 72, 5, 5, 5, 36, + 11, 11, 11, 11, 11, 12, 0, 0, 17, 14, 14, 1, 1, 14, 1, 1, + 1, 1, 17, 17, 1, 1, 1, 1, 24, 1, 5, 5, 5, 5, 25, 0, + 1, 1, 14, 61, 5, 5, 5, 23, 11, 11, 11, 11, 11, 0, 1, 1, + 56, 3, 12, 12, 12, 12, 12, 12, 12, 57, 57, 3, 5, 3, 3, 3, + 10, 10, 43, 43, 43, 27, 27, 15, 1, 1, 1, 1, 17, 1, 1, 1, + 26, 5, 5, 5, 5, 5, 5, 20, 5, 5, 36, 5, 1, 1, 24, 5, + 5, 5, 5, 5, 26, 5, 5, 5, 5, 5, 5, 5, 5, 5, 23, 3, + 3, 3, 3, 55, 3, 3, 29, 3, 12, 12, 57, 3, 66, 33, 0, 0, + 1, 1, 1, 1, 1, 34, 19, 5, 20, 5, 5, 5, 19, 20, 19, 25, + 1, 1, 1, 15, 5, 1, 1, 5, 25, 15, 46, 34, 15, 15, 15, 1, + 24, 5, 25, 1, 1, 1, 1, 1, 1, 20, 19, 20, 15, 15, 19, 34, + 11, 11, 11, 11, 11, 15, 19, 3, 7, 7, 7, 39, 0, 0, 39, 0, + 6, 6, 6, 6, 6,111, 69, 6, 1, 1, 1, 14, 14, 1, 1, 0, + 14, 1, 1, 0, 1, 1, 1, 14, 1, 1, 1, 1, 1, 14, 26, 5, + 12, 12, 12, 12,114, 10, 10, 10, 7, 7, 7, 0, 6, 6, 6, 0, + 1, 1, 1, 1, 1, 1, 56, 53,146, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1,147,116, 0, 1, 1, 1, 1, 1, 40, 12, 16, + 148, 1, 1, 1, 14, 0, 0, 0, 1, 5, 20, 0, 0, 0, 0, 17, + 1, 5, 83, 33, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 14, 1, 14, 5, 0, 0, 0, 0, 0, 0, + 1, 1, 5, 19, 5, 5, 5, 15, 15, 15, 15, 20, 19, 5, 5, 5, + 5, 5, 12, 62, 12, 80, 24, 0, 10, 10, 10, 10, 10, 0, 0, 0, + 12, 12, 12, 92, 12, 71, 5, 91, 1, 45, 1, 1, 1, 1, 1, 1, + 1, 1, 24, 25, 1, 1, 1, 1, 1, 1, 1, 1, 24, 14, 0, 0, + 5, 20, 15, 19, 20, 15, 0, 0, 15, 20, 15, 15, 19, 5, 0, 0, + 29, 0, 12, 11, 11, 11, 11, 11, 1, 1, 14, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 51, 0, 3, 1, 1, 1, 24, 20, 19, 0, 12, + 1, 1, 34, 20, 5, 5, 5, 23, 20, 20, 19, 5, 5, 5, 20, 15, + 15, 19, 5, 5, 5, 5, 23, 26, 12, 12, 12, 62, 12, 12, 12, 0, + 5, 5, 5, 5, 5, 5, 5, 93, 5, 5, 5, 5, 5, 5, 0, 0, + 5, 5, 46, 1, 1, 1, 1, 1, 1, 1, 20, 5, 5, 20, 20, 15, + 15, 20, 46, 1, 1, 1, 14, 12, 57, 3, 3, 3, 3, 43, 5, 5, + 5, 5, 3, 3, 3, 3, 66, 12, 34, 5, 5, 15, 5, 19, 5, 1, + 1, 1, 1, 20, 5, 15, 19, 19, 5, 15, 0, 0, 0, 0, 12, 12, + 1, 1, 15, 15, 15, 15, 5, 5, 5, 5, 15, 5, 0, 38, 12, 12, + 11, 11, 11, 11, 11, 0, 17, 1, 6, 6, 6, 6, 21, 47, 0, 0, + 7, 7, 7, 7, 7, 32, 39, 7, 12, 12, 12, 12, 0, 0, 0, 0, + 5, 36, 5, 5, 5, 5, 5, 5, 20, 5, 5, 5, 25, 1, 24, 1, + 1, 1, 25, 34, 5, 14, 0, 0, 6, 6, 6, 6, 6, 6, 13, 13, + 13, 13, 13, 13, 13, 69, 6, 6, 6, 6, 6, 6, 69, 6, 6, 6, + 6, 6, 6, 6, 6,117, 13, 13, 8, 8, 8, 6, 6, 6, 6, 8, + 6, 6, 6, 6, 39, 39, 39, 39, 6, 6, 6, 6, 6, 6, 6, 0, + 6, 6, 47, 6, 7, 7, 94,118, 22, 6, 47, 6, 7, 7, 94, 22, + 6, 6, 0, 6, 7, 7,149, 22, 6, 6, 6, 6, 7, 7,150, 22, + 0, 6, 47, 6, 7, 7, 94,151, 74, 74, 74, 74, 74,152, 18, 18, + 84, 84, 84, 12, 58,119, 58,119, 12, 12, 12, 12,153, 18, 18,154, + 12, 12, 12, 12,120,121, 12,122,123, 12, 64, 65, 12, 12, 12, 12, + 12, 77,123, 12, 12, 12, 12,155, 18, 18,156, 18, 18, 18, 18, 18, + 157, 0, 10, 10, 10, 9, 64,158, 10, 10, 10, 10, 10, 9, 64,116, + 13, 13, 13, 13, 13, 13, 61, 0, 30, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5,159, 79, 93, 79, 93, 5, 5, 5, 5, 5, + 23, 0, 0, 0, 0, 0, 0, 0, 3, 85, 3, 95, 3, 21, 7, 6, + 7, 8, 95, 3, 90, 7, 7, 3, 3, 3, 85, 85, 85, 7, 7,160, + 7, 7, 67, 1,124, 3, 6, 7, 9, 9, 90, 6, 6, 50, 3,125, + 16,161,162, 16,126, 3, 0, 0, 9, 9, 48, 3, 3, 9, 3, 3, + 48, 50, 3, 48, 3, 3, 3, 48, 3, 3, 3, 3, 3, 3, 3, 9, + 3, 48, 48, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, + 3, 3, 3, 3, 27, 27, 3, 3, 9, 3, 3, 3,163,164, 3, 3, + 3, 3, 3, 3, 3, 3, 48, 3, 3, 3, 3, 3, 3, 50, 9, 9, + 9, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, + 9, 3, 3, 3, 3, 3, 3, 3, 10, 10, 10, 10, 10, 10, 3, 3, + 3, 3, 3, 3, 3, 10, 10, 10, 3, 3, 3, 50, 3, 3, 3, 3, + 50, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, + 3, 3, 3, 3, 3, 3, 3, 50, 3, 3, 3, 3, 27, 27, 27, 27, + 27, 27, 27, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, + 9, 9, 64,127, 9, 9, 9, 9, 9, 9, 9, 27, 27, 27, 27, 27, + 9, 64, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,127, 9, 9, 9, + 9, 9, 9, 9, 27, 27, 9, 9, 9, 9, 9, 9, 9, 9, 27, 9, + 9, 9, 48, 50, 9, 9, 48, 3, 3, 3, 0, 3, 3, 3, 3, 3, + 8, 7, 8, 21, 21, 21, 21, 7, 8, 8, 21, 6, 6, 6, 13, 7, + 8, 8,125, 3, 3, 95, 21,165, 5, 8, 0, 0, 38, 12,114, 12, + 6, 6, 6, 42, 0, 0, 42, 0, 1, 1, 1, 1, 0, 0, 0, 54, + 33, 0, 0, 0, 0, 0, 0, 26, 12, 58, 58, 12,120,121, 58, 12, + 12, 12, 12, 76, 12, 92, 58, 12, 58, 27, 27, 27, 27, 12, 12, 62, + 12, 12, 12, 12, 12, 84, 12, 12, 92,166, 12, 12, 12, 12, 12, 12, + 3, 12, 96, 31, 31, 31,167, 0, 3, 3, 3, 3, 3, 44, 3, 3, + 87, 12,168,128, 27, 27, 27, 27, 27, 3, 27, 27, 27, 27,129,169, + 170, 16, 16, 16, 16, 5, 5, 15,130, 13, 13, 3, 16,171, 40, 3, + 1, 1, 1, 14, 26,172,131, 52, 1, 1, 1, 1, 1, 40, 13, 52, + 0, 0, 17, 1, 1, 1, 1, 1, 3, 10, 10, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 0, 0, 0, 44, 3, 3, 3, 3, 10, 10, 10, 10, + 1, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,132, 12, + 11, 11, 11, 11, 11, 1, 0, 0, 8, 8, 8, 8, 8, 8, 8, 24, + 79,173, 5, 5, 5, 5, 5, 62, 8, 8, 8, 8, 8, 8, 13, 5, + 1, 1, 1, 16, 16, 16, 16, 16, 5, 12, 12, 12, 0, 0, 0, 0, + 22, 22, 22,131, 13, 13, 13, 13, 22, 8, 8, 8, 8, 8, 8, 8, + 6, 8, 8, 8, 8, 8, 8, 8, 69, 6, 6, 6, 21, 21, 21, 8, + 8, 8, 8, 8, 68,174, 21, 67, 8, 8, 6, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 7, 7, 8, 7, 7, 8, 8, 8, 8, 8, 8, + 8, 8, 7, 7, 21, 21, 8, 8, 8, 8, 8, 8, 8, 8, 32, 0, + 54, 13,175, 67, 13, 67, 1, 1, 1, 25, 1, 25, 1, 24, 1, 1, + 1, 34, 19, 20, 3, 3, 23, 0, 10, 10, 10, 3, 97, 0, 0, 0, + 1, 1, 12, 12, 0, 0, 0, 0, 15, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 5, 0, 0, 0, 0, 12, + 5, 1, 1, 1, 12, 53, 53, 24, 1, 1, 1, 5, 5, 5, 5, 12, + 1, 1, 1, 24, 5, 5, 5, 5, 5, 15, 0, 0, 0, 0, 0, 38, + 1, 24, 15, 5, 5, 15, 5, 15, 83, 12, 12, 12, 12, 12, 12, 54, + 1, 1, 24, 52, 1, 1, 1, 1, 11, 11, 11, 11, 11, 1, 1, 14, + 1, 1, 1, 1, 24, 5, 5, 20, 19, 20, 19, 23, 0, 0, 0, 0, + 1, 24, 1, 1, 1, 1, 20, 0, 11, 11, 11, 11, 11, 0, 12, 12, + 52, 1, 1, 56, 3, 34, 20, 1, 25, 5, 25, 24, 25, 1, 1, 5, + 24, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 45, 12, + 1, 1, 1, 1, 1, 34, 5, 15, 12, 45,176, 23, 0, 0, 0, 0, + 17, 1, 1, 14, 17, 1, 1, 14, 17, 1, 1, 14, 0, 0, 0, 0, + 6, 6, 6, 6, 6,118, 13, 13, 6, 6, 6, 6,117, 22, 0, 0, + 1, 34, 19, 15, 20, 83, 19, 0, 1, 1, 1, 14, 0, 17, 1, 1, + 6, 6, 6, 47, 0, 0, 0, 0, 0, 42, 6, 6, 0, 0, 17, 25, + 1, 1, 1, 1,177, 1, 1, 1, 1, 1, 1, 14, 1, 1, 14, 14, + 1, 17, 14, 1, 1, 1, 1, 1, 1, 22, 22, 22, 22, 22, 22, 22, + 22,107, 3, 3, 3, 3, 3, 3, 3, 82, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 31, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 97, 3, + 12, 12, 12, 96, 65, 0, 0, 0, 76,178,179, 31, 31, 31, 31, 31, + 31, 31, 65, 96, 65, 12,122,180, 12, 33, 12, 12,129, 31, 31, 65, + 12,181, 9, 98, 80, 12, 0, 0, 1, 1, 14, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 14, 73, 38, 12,100, 12, 27,101, 76, 12, + 6, 6, 6, 6, 6,105,106, 64, 65, 27, 12, 1, 1, 1, 1, 1, + 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 14, 0, + 30,182, 70,183, 50, 9, 48, 29, 0, 0, 0, 0, 73, 18, 3, 0, + 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, 14, 1, 17, + 12, 33, 0, 49, 10, 10, 10, 10, 10, 10, 0, 44, 3, 3, 3, 3, + 16, 16,126, 10, 63, 3, 3, 3, 3, 3, 3, 3, 3, 10, 3, 29, + 3, 3, 3, 3, 3, 3, 43, 0,133, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, 10, 10, 0, 0, 0, 0, 17, 1, + 128, 1, 1, 1, 1, 99, 0, 0, 1, 1, 1, 5, 5, 23, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 38, 1, 1, 0, 0, 1, 1, 1, 1, + 184, 16, 16, 0, 0, 0, 0, 0, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 38, 7, 32, 7, 42, 6, 6, 6, 6, + 6, 42, 6, 6, 6, 6, 6, 6, 6, 42, 6, 6, 6, 42, 47, 0, + 13, 13, 13, 54, 13, 13, 13, 13, 61, 13, 13, 13, 13, 61, 0, 0, + 1, 1, 1, 0, 14, 1, 1, 1, 1, 1, 1, 17, 14, 0, 14, 17, + 1, 1, 1, 38, 10, 10, 10, 10, 1, 1, 1, 56, 75, 10, 10, 10, + 0, 0, 0, 49, 10, 10, 10, 10, 1, 14, 1, 0, 0, 49, 10, 10, + 1, 1, 1, 10, 10, 10, 0, 38, 1, 1, 1, 1, 1, 0, 0, 38, + 1, 1, 1, 1, 0, 0, 10, 1, 24, 5, 26, 23, 0, 0, 5, 5, + 1, 1, 17, 1, 17, 1, 1, 1, 1, 1, 1, 0, 5, 23, 0, 26, + 12, 12, 12, 12, 33, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 78, + 1, 1, 1, 1, 82, 1, 1, 1, 1, 1, 24, 23, 0, 49, 10, 10, + 12, 12, 12, 33, 0, 0, 0, 0, 1, 1, 1, 0, 38, 12, 12, 12, + 1, 1, 1, 0, 10, 10, 10, 10, 1, 14, 0, 0, 10, 10, 10, 10, + 1, 0, 0, 0, 38, 12, 33, 0, 0, 0, 0, 0, 49, 10, 10, 10, + 7, 32, 0, 0, 0, 0, 0, 0, 6, 47, 0, 0, 0, 10, 10, 10, + 1, 1, 5, 5, 0, 0, 0, 0, 11, 11, 11, 11, 11, 1, 1, 52, + 7, 7, 7, 0, 26, 5, 5,130, 6, 6, 6, 0, 0, 0, 0, 9, + 10, 10, 10, 10, 10, 10, 10, 51, 1, 1, 1, 1, 1, 26,185, 0, + 0, 1, 45, 1, 0, 0, 0, 0, 57, 3, 3, 3, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 5, 5, 10, 10, 10,112, 0, 0, 0, 0, + 133, 10, 78, 12, 12, 0, 0, 0, 1, 5, 5, 12, 12, 0, 0, 0, + 1, 1, 86, 10, 10, 10, 0, 0, 19, 46, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 36, 12, 12, 12, 0, + 10, 10, 10, 11, 11, 11, 11, 11, 25, 24, 25, 0, 0, 0, 0, 26, + 15, 19, 5, 20, 19, 36,186, 12, 12, 23, 0, 0, 0, 0, 73, 0, + 5, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24, 5, 5, 19, 5, + 5, 5, 23, 11, 11, 11, 11, 11, 12, 12, 34, 46, 0, 0, 0, 0, + 1, 24, 12, 14, 0, 0, 0, 0, 1, 34, 15, 5, 5, 5, 5, 20, + 46, 1, 40, 12, 71, 5, 36, 19, 11, 11, 11, 11, 11, 40, 40, 12, + 10, 10, 51, 0, 0, 0, 0, 0, 5, 15, 20, 5, 12, 12, 12, 25, + 24, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 14, 14, 1, 1, 17, + 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 40, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 24, 15, 19, 5, 5, 5, 23, 0, 0, + 5, 15, 17, 1, 1, 1, 14, 17, 14, 1, 17, 1, 1, 26, 25, 15, + 20, 15, 37, 35, 37, 35, 15, 0, 14, 0, 0, 35, 0, 0, 17, 1, + 1, 15, 0, 5, 5, 5, 23, 0, 5, 5, 23, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 17, 0, 14, 1, 1, 1, 17, 15, 19, 5, 5, + 23, 37, 35, 35, 15, 37, 15, 20, 25, 25, 12, 38, 33, 0, 0, 0, + 26, 23, 0, 0, 0, 0, 0, 0, 1, 1, 34, 15, 5, 5, 5, 5, + 15, 5, 20, 25, 1, 40, 12, 12, 11, 11, 11, 11, 11, 12, 38, 25, + 15, 19, 5, 5, 20, 20, 15, 19, 20, 5, 1, 53, 0, 0, 0, 0, + 15, 5, 5, 0, 15, 15, 5, 19, 36, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 1, 1, 5, 0, 15, 19, 5, 5, 5, 20, 19, 19, + 36, 12, 14, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 33, 0, + 1, 1, 1, 1, 1, 24, 19, 15, 5, 5, 5, 19, 40, 0, 0, 0, + 11, 11, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14, 26, 19, + 15, 5, 5, 19, 5, 5, 0, 0, 11, 11, 11, 11, 11, 10, 12, 57, + 5, 5, 5, 5, 19, 36, 0, 0, 10, 51, 0, 0, 0, 0, 0, 17, + 1, 1, 1, 14, 17, 0, 1, 1, 1, 1, 17, 14, 1, 1, 1, 1, + 15, 15, 15, 35, 37, 26, 20, 25, 46, 19, 12, 33, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 1, 1, 1, 34, 15, 5, 5, 0, 5, 15, 15, + 25, 53, 37, 0, 0, 0, 0, 0, 24, 5, 5, 5, 5, 25, 1, 1, + 1, 24, 5, 5, 20, 24, 5, 36, 12, 12, 12, 71, 0, 0, 0, 0, + 24, 5, 5, 20, 19, 5, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, + 5, 5, 5, 20, 5, 12, 53, 12, 12, 33, 0, 0, 0, 0, 0, 0, + 12, 12, 12, 12, 12, 0, 0, 0, 20, 5, 20, 20, 0, 0, 0, 0, + 40, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 23, 5, 5, 5, 19, + 40, 12, 12, 0, 0, 0, 0, 0, 12, 1, 1, 1, 1, 1, 1, 1, + 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 35, 5, 5, 5, + 20, 5, 19, 23, 0, 0, 0, 0, 1, 1, 1, 14, 1, 17, 1, 1, + 24, 5, 5, 23, 0, 23, 5, 26, 5, 5, 5, 24, 0, 0, 0, 0, + 1, 1, 1, 17, 14, 1, 1, 1, 1, 1, 1, 1, 1, 15, 15, 37, + 5, 35, 19, 19, 14, 0, 0, 0, 1, 1, 1, 1, 45, 1, 0, 0, + 1, 24, 20, 83, 33, 0, 0, 0, 5, 34, 1, 1, 1, 1, 1, 1, + 1, 1, 15, 5, 5, 23, 0, 15, 20, 36, 12, 12, 12, 12, 12, 12, + 11, 11, 11, 11, 11, 23, 0, 0, 10, 10, 63, 3, 3, 3, 70, 30, + 97, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 38, + 16, 16, 16, 16, 16, 16, 16, 99, 12, 12, 33, 0, 0, 0, 0, 0, + 40, 33, 0, 0, 0, 0, 0, 0, 25, 1, 1, 24, 5, 5, 5, 5, + 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 15, 19, 5, + 5, 5, 36, 0, 0, 0, 0, 0, 5, 5, 5, 36, 12, 12, 3, 3, + 13, 13, 57, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 49, 10, 10, + 10, 17, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 17, 1, + 13, 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45,132, 12, + 10, 10, 10, 78, 12, 33, 0, 0, 7, 7, 7, 7, 32, 42, 6, 6, + 6, 6, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14, 0, 26, + 34, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 26, + 5, 81, 13, 13, 13, 13, 13, 13, 13, 62, 23, 0, 0, 0, 0, 0, + 15, 13, 16, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, + 13, 13, 54, 13, 13, 13, 54, 61, 0, 14, 0, 0, 0, 0, 0, 0, + 1, 14, 17, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 43, 36, 18, 18, 0, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 3, 29, 0, 3, 3, 0, 0, 0, 3, 3, 3, + 98, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 29, 44, 3, 3, 3, + 3, 3,134, 19, 5, 3,134, 15, 15,187, 18, 18, 18, 91, 5, 5, + 5, 55, 43, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, + 3, 5, 55, 0, 0, 0, 0, 0, 6, 6, 47, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 32, 7, 0, 32, 39, 32, 39, 7, 32, 7, + 7, 7, 7, 6, 6, 42, 42, 6, 6, 6, 42, 6, 6, 6, 6, 6, + 6, 6, 7, 39, 7, 32, 39, 7, 7, 7, 32, 7, 7, 7, 32, 6, + 6, 6, 6, 6, 7, 39, 7, 32, 7, 7, 32, 32, 0, 7, 7, 7, + 32, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 7, 7, 7, 7, + 59, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 60, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 59, 6, 6, + 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 59, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, + 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, 8, 0, 11, + 5, 5, 5, 55, 3, 43, 5, 5, 5, 5, 5, 5, 5, 5, 55, 3, + 3, 3, 43, 3, 3, 3, 3, 3, 3, 3, 55, 66, 12, 12, 0, 0, + 0, 0, 0, 0, 0, 26, 5, 5, 6, 6, 6, 6, 6,124, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 47, 0, 0, 42, 6, 6, 47, 0, 0, + 5, 5, 5, 23, 5, 5, 5, 5, 5, 5, 5, 5, 23, 26, 5, 5, + 5, 26, 23, 5, 5, 23, 0, 0, 13, 13, 13, 13, 13, 13, 13, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 5, 5, 5, 81, 13, 13, 13, 0, + 11, 11, 11, 11, 11, 0, 0, 56, 1, 1, 1, 1, 1, 1, 1, 23, + 1, 1, 1, 1, 1, 1, 5, 5, 11, 11, 11, 11, 11, 0, 0,113, + 1, 1, 1, 1, 1, 45, 5, 5,188, 11, 11, 11, 11,189, 0, 38, + 1, 24, 1, 25, 1, 1, 1, 5, 1, 1, 24, 0, 0, 0, 0, 45, + 1, 1, 1, 14, 1, 1, 17, 14, 1, 1, 14, 49, 10, 10, 10, 10, + 6, 6, 5, 5, 5, 81, 0, 0, 10, 10, 10, 10, 10, 10, 75, 10, + 190, 10, 51, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 75, + 10, 10, 10, 10, 10, 10, 10, 0, 1, 1, 17, 1, 1, 1, 1, 1, + 17, 14, 14, 17, 17, 1, 1, 1, 1, 14, 1, 1, 17, 17, 0, 0, + 0, 14, 0, 17, 17, 17, 17, 1, 17, 14, 14, 17, 17, 17, 17, 17, + 17, 14, 14, 17, 1, 14, 1, 1, 1, 14, 1, 1, 17, 1, 14, 14, + 1, 1, 1, 1, 1, 17, 1, 1, 17, 1, 17, 1, 1, 17, 1, 1, + 9, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 63, 3, + 0, 0, 0, 3, 3, 3, 3, 3, 3, 29, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3,108, 22, 22, 3, 3, 3, 3, 29, 0, 3, 3, + 9, 9, 9, 9, 98, 0, 0, 0, 3, 3, 3, 3, 3, 29, 0, 3, + 3, 3, 3, 29, 29, 0, 44, 3, 3, 3, 3, 3, 3, 3, 29, 44, + 3, 3, 3, 3, 3, 29, 0, 44, 3, 29, 3, 3, 3, 3, 3, 3, + 11, 11, 11, 11, 11, 29, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 7, 7, 3, 3, 26, 26, + 4, 4, 12, 12, 5, 5, 9, 9, 9, 5, 25, 25, 15, 15, 13, 13, + 21, 21, 6, 6, 7, 2, 10, 10, 14, 14, 2, 7, 1, 1, 10, 12, + 12, 10, 5, 9, 24, 24, 12, 2, 7, 12, 12, 7, 2, 12, 22, 18, + 0, 0, 26, 2, 23, 23, 18, 22, 9, 2, 21, 2, 7, 10, 2, 10, + 12, 21, 10, 2, 2, 21, 2, 9, 7, 21, 8, 8, 2, 5, 26, 12, + 2, 26, 7, 6, 10, 7, 5, 2, 25, 26, 2, 15, 26, 25, 15, 2, + 6, 7, 21, 7, 2, 6, 12, 26, 7, 26, 21, 26, 20, 19, 9, 25, + 5, 25, 6, 2, 21, 6, 15, 26, 25, 22, 18, 21, 26, 21, 5, 7, + 6, 24, 6, 5, 26, 23, 21, 12, 6, 12, 2, 1, 29, 29, 26, 15, + 21, 17, 25, 21, 15, 21, 11, 11, 21, 23, 12, 6, 26, 7, 10, 21, + 17, 17, 9, 26, 7, 15, 29, 21, 21, 9, 24, 5, 25, 9, 1, 12, + 17, 21, 11, 12, 8, 24, 26, 9, 21, 22, 23, 26, 25, 2, 14, 2, + 23, 21, 21, 25, 9, 22, 21, 18, 24, 16, 5, 22, 25, 18, 24, 26, + 26, 24, 9, 8, 8, 5, 5, 21, 15, 7, 2, 23, 21, 15, 17, 7, + 18, 2, 5, 6, 5, 24, 22, 20, 21, 20, 19, 21, 21, 16, 16, 21, + 7, 5, 5, 26, 14, 15, 18, 25, 7, 14, 17, 22, 17, 6, 24, 6, + 6, 21, 12, 15, 26, 10, 25, 0, 7, 20, 25, 1, 24, 15, 7, 19, + 9, 21, 17, 2, 17, 12, 1, 21, 12, 1, 24, 7, 29, 7, 7, 22, + 14, 7, 2, 24, 9, 24, 24, 2, 29, 1, 27, 28, 1, 29, 21, 29, + 1, 2, 15, 6, 18, 6, 12, 11, 26, 5, 14, 9, 5, 14, 26, 22, + 18, 26, 5, 12, 22, 21, 18, 17, 26, 6, 18, 18, 26, 14, 14, 6, + 12, 24, 11, 21, 24, 9, 6, 9, 6, 10, 7, 25, 17, 16, 16, 22, + 16, 16, 25, 17, 25, 24, 23, 2, 21, 14, 12, 17, 21, 1, 10, 1, + 7, 13, 13, 2, 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, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, 0, 37, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, + 0, 0, 0, 0, 0, 0, 41, 42, 43, 44, 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, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 15, + 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 0, 19, 0, 20, 21, 0, + 0, 22, 23, 24, 25, 26, 0, 0, 0, 0, 27, 28, 29, 30, 0, 31, + 0, 32, 33, 0, 2, 34, 0, 0, 2, 1, 35, 0, 2, 1, 0, 0, + 2, 1, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 2, 36, 0, 0, + 2, 1, 0, 0, 37, 1, 0, 0, 0, 38, 0, 0, 39, 40, 0, 0, + 41, 42, 0, 43, 44, 0, 45, 46, 0, 47, 0, 0, 48, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 51, 4, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, + 53, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 55, 0, 0, 56, 0, + 57, 58, 59, 0, 60, 5, 61, 0, 62, 0, 63, 0, 64, 0, 0, 0, + 0, 65, 66, 0, 0, 0, 0, 0, 0, 67, 68, 0, 0, 0, 0, 0, + 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 71, 0, 0, 0, 3, 0, 0, 0, 72, 0, 73, 0, 0, 74, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 76, + 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 6, 78, 0, 0, 0, + 0, 5, 79, 0, 80, 81, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, + 82, 83, 84, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, + 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, 0, 90, 91, 0, 0, 0, + 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 93, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 95, 0, 96, 0, 0, 97, 0, 98, 0, 0, 0, 0, 0, 6, 99, 0, + 9, 0, 0,100,101, 0, 7, 0, 0,102, 0, 0,103, 0, 0, 0, + 0, 0,104, 0,105, 1,106, 0, 0,107, 0, 0, 0,108, 0, 0, + 0,109, 0, 0, 0, 0, 0, 0, 3,110, 0, 0, 3, 0, 0, 0, + 111, 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, + 0, 0, 0, 0,113,114, 0, 0, 0, 0, 8, 0, 4,115, 0,116, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0,117, 0,118, 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, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,121, 0, 10, 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,123, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,124,125,126, 0, 0, 0, 0,127, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129, 0, 0,130, + 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 131, 0,132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,133, 0, 0, 0, 0, 0, 0, 0,134, 0, 0, 0, 0, 0, + 0, 0,135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,136, 0, 0, 0,137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 1, 12, 0, 0, 1, 1, + 1, 1, 1, 49, 50, 5, 51, 52, 53, 5, 5, 22, 32, 23, 1, 54, + 24, 55, 16, 33, 56, 57, 58, 1, 1, 1, 0, 0, 0, 0, 6, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 7, 60, 1, 34, 5, + 7, 61, 62, 63, 64, 65, 66, 67, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 68, 0, 0, 0, 69, 70, 71, 35, 1, 25, 0, 0, + 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 8, 1, 26, 16, 26, + 73, 27, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, + 0, 0, 36, 25, 75, 37, 7, 37, 76, 0, 0, 0, 0, 0, 0, 0, + 6, 1, 7, 0, 0, 17, 0, 0, 0, 0, 0, 8, 38, 1, 1, 13, + 13, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, + 0, 0, 0, 6, 18, 1, 0, 0, 8, 16, 5, 1, 1, 1, 77, 7, + 36, 18, 78, 7, 35, 1, 0, 0, 0, 4, 79, 10, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, 0, 4, 0, 80, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 3, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 81, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 83, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 85, 86, 0, 0, 0, + 0, 0, 87, 88, 89, 90, 91, 92, 0, 0, 0, 0, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 28, 0, 0, 0, + 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, + 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 14, 0, 0, 20, 0, 0, + 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, + 0, 0, 0, 6, 29, 0, 3, 0, 0, 0, 0, 13, 1, 96, 0, 0, + 0, 0, 1, 18, 33, 97, 25, 23, 7, 1, 1, 1, 1, 27, 1, 7, + 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, + 6, 23, 1, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 21, + 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, + 0, 0, 12, 32, 24, 5, 99, 22, 42, 17, 0, 10, 11, 0, 7, 1, + 7,100,101, 1, 1, 1, 1, 1, 1, 1, 1,102,103,104, 0, 0, + 0, 0,105, 1,106, 10, 20,107,108, 5, 10, 0, 0, 0, 0, 0, + 0, 6, 11, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 109,110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 0, 0, 0, + 0, 6, 0, 1, 1, 11, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 0, 11, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, + 1, 1, 11, 0, 0, 0, 0, 0, 43, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 44,112, 10, 8, 20, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, + 0, 0, 0, 0, 0,113, 1, 16, 5, 24, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 12, 0, 0, 0, 0,114, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,115, 2, 0,116, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 13, 11, 0, 0, 0, 0, 0, 0, + 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 39, 0, 45, + 16, 18, 29, 0, 0, 0, 46, 27, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 3, 0, 0, 3, 0, 21, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 31, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 15, 9, 0, 8, 1, 10, 1, 10, 0, 0, 0, 0, + 0, 30, 3, 0, 0, 0, 14, 21, 0, 0, 0, 0, 0, 19, 47, 0, + 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 47, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 28, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 21, 41, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 22, 42, 0, 0, 0, 0, 0, 0,118, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,119, 0,120,121,122,123, 0, 43, 5, 48, 13, + 34, 0, 0, 0, 0, 0, 0, 0, 8, 11, 0, 0, 0, 0, 8, 10, + 0, 0, 0, 0, 0, 0, 1, 12, 1, 1, 1, 1, 26, 1, 38, 44, + 12, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, + 0, 19, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0,124, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 6, 19, + 0, 8, 0, 20, 0, 0, 0, 0, 0, 0, 5, 48, 0, 0, 0, 1, + 125, 0, 0, 0, 0, 0,230,230,230,230, 0, 0, 0, 9, 9, 0, + 0, 0, 0, 9, 0, 0,220,220,220,220, 0, 0, 0,230,230,230, + 220,230, 0, 0,230,230, 7, 0, 0, 0,230, 0, 0, 0,230,230, + 0, 0,230,230,230, 0, 0,230,230,230, 0, 0, 9, 0, 0, 0, + 0, 7,230,230,230,220, 0,220, 0, 0,230,220,220,220, 0, 0, + 230, 0, 0,230, 0, 0, 0, 0, 7, 0, 1, 1, 1, 1,220,230, + 230,230,220,220,230,230,220,230,230,220,230, 0, 0,230,230,220, + 0, 0, 0, 9, 9, 0,220, 0, 0, 0, 0, 0, 9, 9, 0, 9, + 7, 0, 1,220,220,220,220,220,220,230,230,230,220,220,230,220, + 220,230,230,220,230,230,220,230,220,230,230,230, 0,230, 0,220, + 220,220,220,220, 0, 0, 9, 9, 0, 0, 1, 0, 0, 0, 0, 0, + 0,220,230, 0,230,230, 0, 0,220,220, 0, 0,230,220, 0, 0, + 9, 7,220,220,220, 0,230,232,220,220,220,220,232,216,220,202, + 202,220,220,220,220,202,202,220,220,220,230,240,230,220,230,220, + 220, 0,232,220,220,230,233,234,234,233,234,234,233,230, 0,220, + 230,230,230,230,222,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, 35, 0, 0, 0,230, 0,220,230, 0, 36, 0, 0,220,220, + 230,220,220,230,230, 0,230,230, 0,220, 27, 28, 29,230, 0,230, + 220,230, 0, 84, 91, 0,103,103, 9, 0,107,107,107,107,118,118, + 9, 0,122,122,122,122, 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,228, 0, 0, 0,222, + 230,220,230, 0, 0,220,230,220, 0,220,230,230,230,234,230, 0, + 1, 1,230,234,214,220,202,230,230,230,230,230,232,228,228,220, + 218,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,220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1, + 220, 0, 0,230,220, 0, 0, 7, 9, 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,232,232,220,230,230,230, 7, 0, 1, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 3, 0, 0, 0, 0, 4,101, 0,112,128,169, + 0, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 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, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 1, 1, 0, 3, 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, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 2, 1, 40, 41, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 36, 0, 0, + 8, 0, 0, 0, 0, 44, 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, + 0, 0, 0, 0, 16, 8, 0, 0, 0, 0, 0, 0, 24, 48, 0, 0, + 0, 0, 0, 0, 28, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 28, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, + 60, 64, 0, 68, 0, 72, 76, 80, 0, 0, 0, 0, 0, 8, 84, 88, + 0, 92, 16, 8, 0, 0, 0, 4, 4, 16, 4, 4, 4, 4, 4, 4, + 4, 24, 20, 0, 96, 0, 16,100,104, 0, 4, 4,108, 0, 0, 0, + 40,112, 8, 16, 4, 4, 4, 4, 4, 8,116,120,124,128, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 8, 0, 0, 24, 20,132, 36, 0, 28, 0,136, 16, 4, + 4, 4, 0, 0, 0, 0, 24, 12, 12,140,144, 12,148, 0,152, 8, + 4, 4, 0, 0,156, 0, 8, 8, 0, 24, 20, 8, 4, 0, 0, 0, + 8, 0, 0,160, 8, 8, 0, 0, 24, 20, 0, 8, 0, 8, 0, 8, + 0, 0, 0, 0, 40, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 16, + 4,164, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 0,168,172,176, + 0,180, 0, 24, 20, 0, 0, 0, 0, 0, 0, 0, 0,184, 16, 8, + 28, 8, 0, 0, 0, 8, 4, 4, 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 40, 12, 48, 0, 0, 4, 4, 8, 4, 4, 0, 0, 0, + 0, 0, 0, 0, 40, 20, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32,188,192, 0, 0, 0, 0, 0, 0, 0, 4, 5, + 6, 7, 8, 9, 10, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 12, 13, 2, 2, 2, 2, 14, 0, 0, 0, 0, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 25, 26, 3, 3, 3, 27, + 0, 0, 0, 28, 29, 30, 0, 31, 32, 33, 34, 35, 36, 37, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 38, 1, 1, 39, 1, 40, 1, 1, 1, 41, 0, 42, 1, 1, + 43, 1, 1, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 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, 3, 3, 20, + 21, 8, 8, 8, 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, 2, 2, 51, 52, 53, 54, 9, 9, 9, 9, 9, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 8, 8, 70, 71, 72, + 73, 74, 75, 5, 5, 5, 5, 76, 5, 5, 5, 5, 5, 5, 5, 15, + 15, 5, 5, 5, 5, 77, 5, 78, 79, 80, 81, 82, 83, 1, 84, 85, + 86, 87, 88, 89, 90, 91, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 92, 1, 1, 1, 1, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 93, 16, 16, 94, 95, 96, 97, 98, + 99,100,101,102,103,104,105, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,106, 0, + 0, 1, 1,107,108,109, 13, 13, 13,110,111,112,113,114,115,116, + 117,118,119, 0,120,121,122,123,124,125,126, 17, 17,127,128,129, 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145, - 95,146,147,148,149, 95,150,151,152,153,154,155,156,157,158,159, - 160,161, 95,162,163,164,165,165,165,165,165,165,165,166,167,165, - 168, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95,169,170,170,170,170,170,170,170,170,171,170, - 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, - 170,170,170,170,170,170,170,170,170,170,170,170,170,172,173,173, - 173,173,174, 95, 95, 95, 95, 95,175, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95,176,176,176,176,177,178,179,180, 95, 95, - 181, 95,182,183,184,185,186,186,186,186,186,186,186,186,186,186, - 186,186,186,186,186,186,186,186,186,186,186,186,187,187,187,188, - 189,190, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95,191,192,193,194,195,195,196, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,197,198, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 59,199, - 59, 59, 59,200,201,202, 59,203,204,205,206,207,208, 95,209,210, - 211, 59, 59,212, 59,213,214,214,214,214,214,215, 95, 95, 95, 95, - 95, 95, 95, 95,216, 95,217,218,219, 95, 95,220, 95, 95, 95,221, - 95,222, 95,223, 95,224,225,226,227, 95, 95, 95, 95, 95,228,229, - 230, 95,231,232, 95, 95,233,234, 59,235,236, 95, 59, 59, 59, 59, - 59, 59, 59,237, 59,238,239,240, 59, 59,241,242, 59,243, 95, 95, - 95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69,244, 69, 69,245, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69,246, 69, 69, 69, 69, 69, 69, 69, 69, 69,247, 69, 69, - 69, 69,248, 95, 95, 95, 69, 69, 69, 69,249, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69,250, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,251, 95, - 95, 95, 95, 95, 95, 95,252, 95,253,254, 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, 3, 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, 2, 2, 2, 2, 2, 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, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2, - 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 23, 23, 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, 16, 16, 16, 2, 16, 16, - 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 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, 18, 18, 18, 18, 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, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 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, 32, 32, 32, - 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 32, 32, - 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 2, 48, 48, - 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52, - 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, 2, 2, 58, 58, - 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, - 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91, - 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 2, 2, 1, 1, - 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 2, 62, 62, 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, 6, - 6, 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, 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, 2, 2, 2, 2, 2, 2, 1, 2, - 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, - 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0, - 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27, - 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 56, 56, - 56, 56, 56, 56, 56, 56, 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, 0, 0, - 0, 0, 0, 0, 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, 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, 2, 2, - 2, 2, 2, 2, 2, 0, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, - 17, 17, 17, 17, 17, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86, - 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, - 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 2, 19, - 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 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, - 3, 3, 3, 3, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 2, 3, 3, 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,161,161,161,161,161,161,161,161,161,161, - 161, 2,161,161,161,161,161,161,161, 2,161,161, 2,161,161,161, - 2,161,161,161,161,161,161,161, 2,161,161, 2, 2, 2,170,170, - 170,170,170,170,170,170,170,170,170,170, 2, 2, 2, 2,110,110, - 110,110,110,110,110,110,110,110,110,110,110,110,110, 2,110,110, - 110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 2, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 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, 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,173,173, - 173,173,173,173,173,173,173,173, 2, 2, 2, 2, 2, 2, 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,165,165,165,165,165,165,165,165,165,165, - 165,165,165,165, 2, 2, 2,165,165,165,165,165,165,165, 2, 2, - 2, 2, 2, 2,165,165, 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, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, - 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,158,158, - 158,158,158,158,158,158,158,158, 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, 85, 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, 2, 2, 2, 2, 2, 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,171,171, - 171,171,171,171,171,171,171,171, 2,171, 2, 2,171, 2,171,171, - 171,171,171,171, 2,171,171, 2,171, 2, 2,171, 2,171,171,171, - 171, 2,171,171,171,171,171, 2, 2, 2, 2, 2, 2, 2, 2,171, - 171, 2, 2, 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,102, 2, 2, 2, 2, 2, 2, 33, 33, - 33, 33, 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,126,126, - 126,126,126,126,126, 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, 7, 7, 2, 2, 2, 2, 2, 2,169,169, - 169,169,169,169,169,169,169,169, 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,175,175,175,175,175,175,175,175,175,175, - 175,175, 2, 2, 2, 2,175,175, 2, 2, 2, 2, 2, 2,145,145, - 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2,163,163, - 163,163,163,163,163,163,163, 2,163,163,163,163,163,163,163,163, - 163, 2, 2, 2,163,163,163,163,163, 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,157,157, - 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 2, 80, 80, - 80, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127, - 127,127,127,127,127, 2,166,166,166,166,166,166,166,166,166,166, - 2, 2, 2, 2, 2, 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,159,159,159,159,159,159,159,159,159,159, - 159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,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,167,167, - 167,167,167,167,167,167,167,167, 2, 2, 2, 2, 2, 2,146,146, - 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2,172,172, - 172,172,172,172,172,172,172, 2, 2,172,172,172,172,172,172,172, - 172,172, 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, - 13, 13,155, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 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, 2, 2, 2, 2, 2, 2, 2,155,136,136, - 136,136,136,136,136, 2,136,136,136, 2, 2, 2, 2, 2, 17, 17, - 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15, - 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 2, 2, - 15, 2, 2, 2, 2, 2, 15, 15, 15, 2, 2, 17, 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, 2, 2, - 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1, 1, - 1, 1, 1, 1, 1, 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, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0, - 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, - 0, 0, 0, 2, 0, 2, 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, 2, 2, - 2, 2, 2, 19, 19, 19, 56, 56, 56, 56, 56, 56, 56, 2, 56, 2, - 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56, - 56, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 6,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,160,160,160,160,160,160,160,160,160,160, - 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152, - 2, 2, 2, 2, 2,152,164,164,164,164,164,164,164,164,164,164, - 2, 2, 2, 2, 2, 2,168,168,168,168,168,168,168,168,168,168, - 168, 2, 2, 2, 2,168,174,174,174,174,174,174,174,174,174,174, - 174,174,174,174,174, 2,174,174,174,174,174,174, 2, 2, 2, 2, - 2, 2, 2, 2,174,174, 30, 30, 30, 30, 2, 30, 30, 2,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, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0, - 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, - 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 2, 0, 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, - 18, 9, 9, 9, 9, 9, 19, 20, 21, 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, 23, 9, - 9, 9, 9, 9, 24, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 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, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 26, 27, 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, + 146,147,148,149,150,151,152,153,154, 0,155,156,157,158, 0,159, + 160,161,162,163,164,165,166,167,168,169,170, 0,171,172,173, 7, + 7, 7, 7, 7, 7, 7,174,175, 7,176, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,177, 4, + 4, 4, 4, 4, 4, 4, 4,178, 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,179, 11, 11, 11, 11,180, 0, 0, 0, 0, + 0,181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, + 12, 12, 12,182,183,184,185, 0, 0,186, 0,187,188,189,190, 3, + 3, 3, 3, 3, 3, 14, 14, 14,191,192,193, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,194,195, + 196,197, 18, 18,198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,199,200, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5,201, 5, 5, 5,202,203,204, 5, + 205,206,207,208,209,210, 0,211,212,213, 5, 5,214, 5,215, 10, + 10, 10, 10, 10,216, 0, 0, 0, 0, 0, 0, 0, 0,217, 0,218, + 219,220, 0, 0,221, 0, 0, 0,222, 0,223, 0,224, 0,225,226, + 227,228, 0, 0, 0, 0, 0,229,230,231, 0,232,233, 0, 0,234, + 235, 5,236,237, 0, 5, 5, 5, 5, 5, 5, 5,238, 5,239,240, + 241, 5, 5,242,243, 5,244, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,245, 1, 1,246, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,247, 1, 1, 1, + 1, 1, 1, 1, 1, 1,248, 1, 1, 1, 1,249, 0, 0, 0, 1, + 1, 1, 1,250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1,251, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1,252, 0, 0, 0, 0, 0, 0, 0,253, + 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 12, + 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0,136, + 136,136,136,136,136,136,136, 80, 80, 80, 80, 80, 80, 80, 80, 19, + 19, 19, 19, 19, 19, 19, 19, 3, 3, 3, 3, 3, 3, 3, 3, 63, + 63, 63, 63, 63, 63, 63, 63, 39, 39, 39, 39, 39, 39, 39, 39, 28, + 28, 28, 28, 28, 28, 28, 28, 79, 79, 79, 79, 79, 79, 79, 79,131, + 131,131,131,131,131,131,131, 1, 1, 1, 1, 1, 1, 1, 1,127, + 127,127,127,127,127,127,127, 6, 6, 6, 6, 6, 6, 6, 6,155, + 155,155,155,155,155,155,155,139,139,139,139,139,139,139,139, 9, + 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 15, 15, 15, 30, + 30, 30, 30, 30, 30, 30, 30,110,110,110,110,110,110,110,110, 77, + 77, 77, 77, 77, 77, 77, 77, 17, 17, 17, 17, 17, 17, 17, 17, 27, + 27, 27, 27, 27, 27, 27, 27, 33, 33, 33, 33, 33, 33, 33, 33,113, + 113,113,113,113,113,113,113, 49, 49, 49, 49, 49, 49, 49, 49, 25, + 25, 25, 25, 25, 25, 25, 25, 29, 29, 29, 29, 29, 29, 29, 29, 7, + 7, 7, 7, 7, 7, 7, 7, 32, 32, 32, 32, 32, 32, 32, 32, 8, + 8, 8, 8, 8, 8, 8, 8, 99, 99, 99, 99, 99, 99, 99, 99, 31, + 31, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30, 30, 2,105, + 105,105,105,105,105,105,105, 55, 55, 55, 55, 55, 55, 55, 55, 62, + 62, 62, 62, 62, 62, 62, 62, 56, 56, 56, 56, 56, 56, 56, 56, 91, + 91, 91, 91, 91, 91, 91, 91, 0, 0, 0, 0, 2, 2, 2, 2,100, + 100,100,100,100,100,100,100,119,119,119,119,119,119,119,119, 14, + 14, 14, 14, 14, 14, 14, 14,130,130,130,130,130,130,130,130, 94, + 94, 94, 94, 94, 94, 94, 94,157,157,157,157,157,157,157,157,137, + 137,137,137,137,137,137,137,146,146,146,146,146,146,146,146, 20, + 20, 20, 20, 20, 20, 20, 20, 35, 35, 35, 35, 35, 35, 35, 35, 0, + 0, 0, 0, 0, 0, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 40, + 40, 40, 40, 40, 40, 40, 40, 97, 97, 97, 97, 97, 97, 97, 97,124, + 124,124,124,124,124,124,124,123,123,123,123,123,123,123,123,125, + 125,125,125,125,125,125,125,140,140,140,140,140,140,140,140,159, + 159,159,159,159,159,159,159,132,132,132,132,132,132,132,132, 37, + 37, 37, 37, 37, 37, 37, 37, 22, 22, 22, 22, 22, 22, 22, 22, 24, + 24, 24, 24, 24, 24, 24, 24, 58, 58, 58, 58, 58, 58, 58, 58, 76, + 76, 76, 76, 76, 76, 76, 76, 26, 26, 26, 26, 26, 26, 26, 26, 75, + 75, 75, 75, 75, 75, 75, 75, 89, 89, 89, 89, 89, 89, 89, 89,114, + 114,114,114,114,114,114,114,141,141,141,141,141,141,141,141,133, + 133,133,133,133,133,133,133,163,163,163,163,163,163,163,163, 4, + 4, 4, 4, 4, 4, 4, 4, 70, 70, 70, 70, 70, 70, 70, 70, 0, + 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2, 68, + 68, 68, 68, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 87, + 87, 87, 87, 87, 87, 87, 87,135,135,135,135,135,135,135,135, 85, + 85, 85, 85, 85, 85, 85, 85, 96, 96, 96, 96, 96, 96, 96, 96,109, + 109,109,109,109,109,109,109,102,102,102,102,102,102,102,102, 64, + 64, 64, 64, 64, 64, 64, 64, 61, 61, 61, 61, 61, 61, 61, 61, 65, + 65, 65, 65, 65, 65, 65, 65, 2, 0, 0, 0, 0, 0, 0, 0,108, + 108,108,108,108,108,108,108,142,142,142,142,142,142,142,142,121, + 121,121,121,121,121,121,121,166,166,166,166,166,166,166,166,167, + 167,167,167,167,167,167,167, 0, 2, 2, 2, 2, 2, 2, 2,151, + 151,151,151,151,151,151,151,152,152,152,152,152,152,152,152, 38, + 38, 38, 38, 38, 38, 38, 38, 90, 90, 90, 90, 90, 90, 90, 90, 23, + 23, 23, 23, 23, 23, 23, 23, 36, 36, 36, 36, 36, 36, 36, 36, 30, + 2, 30, 30, 30, 30, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 93, + 93, 93, 93, 93, 93, 93, 93, 73, 73, 73, 73, 73, 73, 73, 73, 9, + 9, 9, 9, 9, 9, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 86, + 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, 0, 0, 2, 2, 2, 67, + 67, 67, 67, 67, 67, 67, 67, 51, 51, 51, 51, 51, 51, 51, 51,104, + 104,104,104,104,104,104,104,170,170,170,170,170,170,170,170, 78, + 78, 78, 78, 78, 78, 78, 78,144,144,144,144,144,144,144,144,165, + 165,165,165,165,165,165,165,171,171,171,171,171,171,171,171,126, + 126,126,126,126,126,126,126,150,150,150,150,150,150,150,150,134, + 134,134,134,134,134,134,134,138,138,138,138,138,138,138,138,175, + 175,175,175,175,175,175,175, 18, 18, 18, 18, 18, 18, 18, 18, 0, + 0, 0, 0, 0, 2, 0, 0, 60, 60, 60, 60, 60, 60, 60, 60, 69, + 69, 69, 69, 69, 69, 69, 69,118,118,118,118,118,118,118,118, 59, + 59, 59, 59, 59, 59, 59, 59,106,106,106,106,106,106,106,106,156, + 156,156,156,156,156,156,156,147,147,147,147,147,147,147,147,148, + 148,148,148,148,148,148,148,169,169,169,169,169,169,169,169,172, + 172,172,172,172,172,172,172,164,164,164,164,164,164,164,164,168, + 168,168,168,168,168,168,168,174,174,174,174,174,174,174,174, 0, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 5, + 5, 5, 5, 5, 5, 5, 5, 21, 21, 21, 21, 21, 21, 21, 21, 16, + 16, 16, 16, 16, 16, 16, 16, 12, 12, 12, 12, 12, 12, 12, 2, 74, + 74, 74, 74, 74, 74, 74, 74, 42, 42, 42, 42, 42, 42, 42, 42, 50, + 50, 50, 50, 50, 50, 50, 50,161,161,161,161,161,161,161,161, 47, + 47, 47, 47, 47, 47, 47, 47,120,120,120,120,120,120,120,120,116, + 116,116,116,116,116,116,116, 98, 98, 98, 98, 98, 98, 98, 98, 57, + 57, 57, 57, 57, 57, 57, 57, 88, 88, 88, 88, 88, 88, 88, 88,117, + 117,117,117,117,117,117,117,112,112,112,112,112,112,112,112,101, + 101,101,101,101,101,101,101,111,111,111,111,111,111,111,111,154, + 154,154,154,154,154,154,154,143,143,143,143,143,143,143,143,115, + 115,115,115,115,115,115,115, 0, 0, 19, 0, 0, 0, 0, 0, 95, + 95, 95, 95, 95, 95, 95, 95, 11, 11, 11, 11, 11, 11, 11, 11, 10, + 10, 10, 10, 10, 10, 10, 10, 22, 22, 22, 2, 2, 2, 22, 22, 2, + 25, 25, 25, 25, 25, 25, 25, 34, 34, 34, 34, 34, 34, 34, 34, 52, + 52, 52, 52, 52, 52, 52, 52, 54, 54, 54, 54, 54, 54, 54, 54, 0, + 0, 0, 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, + 2, 12, 12, 12, 12, 12, 12, 71, 71, 71, 71, 71, 71, 71, 71, 41, + 41, 41, 41, 41, 41, 41, 41, 53, 53, 53, 53, 53, 53, 53, 53, 81, + 81, 81, 81, 81, 81, 81, 81, 66, 66, 66, 66, 66, 66, 66, 66, 72, + 72, 72, 72, 72, 72, 72, 72,173,173,173,173,173,173,173,173, 83, + 83, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, 82,158, + 158,158,158,158,158,158,158,153,153,153,153,153,153,153,153,145, + 145,145,145,145,145,145,145,103,103,103,103,103,103,103,103,160, + 160,160,160,160,160,160,160, 2, 3, 3, 2, 3, 2, 2, 3, 3, + 3, 3, 2, 3, 3, 3, 3, 19, 19, 19, 19, 19, 19, 19, 0, 2, + 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 0, 3, 3, 5, + 5, 5, 5, 5, 2, 2, 5, 11, 11, 11, 2, 2, 2, 2, 11, 10, + 10, 10, 10, 10, 10, 2, 10, 21, 21, 21, 21, 21, 2, 2, 21, 22, + 2, 22, 22, 22, 22, 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, + 2, 23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, 2, 16, 16, 16, + 2, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 2, 20, 20, 20, + 2, 20, 20, 20, 20, 20, 20, 36, 36, 36, 36, 36, 36, 36, 2, 25, + 25, 25, 25, 25, 2, 25, 25, 8, 8, 8, 8, 8, 8, 2, 8, 2, + 2, 2, 2, 2, 8, 2, 2, 29, 29, 29, 29, 29, 29, 2, 2, 45, + 45, 45, 45, 45, 45, 45, 45, 44, 44, 44, 44, 44, 44, 44, 44, 43, + 43, 43, 43, 43, 43, 43, 43, 31, 31, 2, 2, 2, 2, 2, 2, 48, + 48, 48, 48, 2, 2, 2, 2, 91, 91, 2, 2, 2, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 2, 2, 9, 9, 9, 9, 9, 2, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, + 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 61, 0, + 17, 17, 17, 17, 17, 17, 17, 12, 12, 12, 12, 2, 2, 2, 2, 13, + 13, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 0, + 0, 0, 2, 0, 0, 0, 0, 49, 49, 49, 49, 49, 49, 2, 2, 0, + 0, 0, 2, 2, 2, 2, 0,135,135,135,135, 2, 2, 2, 2,161, + 161,161, 2,161,161,161,161,161,161, 2,161,161,161,161,161, 19, + 19, 19, 2, 2, 2, 2, 2,128,128,128,128,128,128,128,128, 57, + 2, 2, 2, 2, 2, 2, 2,112,112,112,112,112,112,112, 2,122, + 122,122,122,122,122,122,122,130,130,130, 2, 2, 2, 2, 2,165, + 165,165,165,165,165, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,149, + 149,149,149,149,149,149,149, 94, 94, 94, 94, 94, 94, 2, 2,129, + 129,129,129,129,129,129,129,107,107,107,107,107, 2, 2,107,107, + 107,107,107,107,107,107,107,107,107,107,107,107, 2, 2, 2,171, + 171,171,171,171,171, 2,171,123,123,123,123,123,123, 2, 2,102, + 102, 2, 2, 2, 2, 2, 2,154,154,154,154,154,154,154, 2, 2, + 2,150,150,150,150,150,150,169,169, 2, 2, 2, 2, 2, 2,138, + 138,138,138,138,138,138, 2,103,103,103,103,103,103, 2, 2,119, + 119, 2,119,119,119,119,119, 2, 2, 0, 0, 0, 0, 0, 0, 3, + 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 19, + 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 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, 2, 9, 9, 9, 9, 9, 9, + 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 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, 2, 2, 2, 2, 14, 14, + 14, 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 0, 3, 3, 3, 3, + 3, 3, 0, 3, 3, 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, 2, 37, 37, + 37, 37, 2, 2, 37, 37, 37, 38, 38, 2, 2, 2, 2, 2, 2, 64, + 64, 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 2, 2, 90, + 90, 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 2, 2, 95, 2, 37, + 37, 37, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, + 3, 0, 3, 3, 3, 3, 3, 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, + 2, 2, 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, + 2, 2, 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, 2, 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, + 2, 2, 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, 2, 22, 22, 2, 22, 2, 22, 22, 2, + 2, 2, 22, 22, 2, 2, 2, 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, 2, 2, 23, 23, 23, 23, 23, + 2, 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, + 23, 23, 2, 23, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, + 2, 2, 2, 2, 2, 2, 23, 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, 16, 16, 16, 2, 16, + 16, 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 2, + 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, + 36, 36, 36, 2, 36, 36, 36, 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, 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, 2, 18, 2, 18, 18, + 18, 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, + 18, 18, 18, 18, 18, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, + 25, 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 0, 0, 0, 0, + 25, 25, 2, 2, 2, 2, 2, 8, 8, 8, 0, 8, 8, 8, 8, 30, + 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, + 30, 2, 2, 2, 2, 2, 2, 34, 34, 34, 34, 34, 2, 2, 2, 35, + 35, 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, + 45, 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 44, + 44, 44, 44, 44, 0, 0, 2, 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, 2, 2, 32, + 32, 0, 0, 32, 0, 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, 2, 48, + 2, 2, 2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 2, 2, 52, + 52, 52, 52, 52, 2, 2, 2, 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, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 2, 91, + 91, 91, 91, 91, 2, 2, 91, 91, 91, 91, 91, 91, 91, 2, 2, 1, + 1, 1, 1, 2, 2, 2, 2, 62, 62, 62, 62, 62, 2, 62, 62, 93, + 93, 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 2, + 2, 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 6, + 6, 6, 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, 2, + 9, 2, 9, 2, 9, 2, 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, 0, + 0, 0, 0, 1, 1, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 19, 1, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 55, + 55, 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, + 2, 2, 2, 2, 2, 2, 2, 13, 13, 2, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 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, 2, 2, 1, 1, 0, 0, 15, 15, 15, 17, + 17, 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 2, + 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 0, 12, + 12, 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, + 39, 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 77, + 77, 77, 77, 2, 2, 2, 2, 0, 0, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 19, 19, 19, 19, 19, 2, 19, 19, 19, 19, 19, 19, 19, 60, + 60, 60, 60, 60, 2, 2, 2, 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, 0, 69, 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, 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, 2, 68, + 68, 68, 68, 68, 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, + 92, 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, + 87, 87, 87, 87, 87, 87, 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, 2, + 2, 2, 12, 12, 12, 12, 12, 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, 3, 3, 3, 3, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 3, + 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, + 2, 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 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, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 2, 2, 2, 0, 9, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 2, 2, 2, 67, + 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 42, + 42, 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, + 41, 41, 2, 2, 2, 2, 2,118,118,118, 2, 2, 2, 2, 2, 53, + 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 2, 2, 2, 2, 59, + 59, 59, 59, 59, 59, 2, 2, 50, 50, 50, 50, 50, 50, 2, 2, 50, + 50, 2, 2, 2, 2, 2, 2,104,104,104,104, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,104,161,161,161, 2,161,161, 2,161,161, + 161, 2,161,161, 2, 2, 2,170,170,170,170, 2, 2, 2, 2,110, + 110,110,110,110,110,110, 2,110,110,110,110,110,110, 2, 2, 19, + 19, 19, 19, 19, 19, 2, 19, 19, 2, 19, 19, 19, 19, 19, 19, 47, + 47, 47, 47, 47, 47, 2, 2, 47, 2, 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, 2, 81,116,116,116,116,116,116,116, 2, 2, + 2, 2, 2, 2, 2, 2,116,128,128,128, 2,128,128, 2, 2, 2, + 2, 2,128,128,128,128,128, 66, 66, 66, 66, 2, 2, 2, 66, 72, + 72, 2, 2, 2, 2, 2, 72,173,173, 2, 2, 2, 2, 2, 2, 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, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 2, + 2, 2,112,112,112,112,112, 78, 78, 78, 78, 78, 78, 2, 2, 2, + 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 2, 2, 82, + 82, 82, 2, 2, 2, 2, 2,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, + 2, 2, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144, + 144, 2, 2, 2, 2, 2, 2, 2,165,165,165,165,165,165,165, 2, + 2, 2, 2, 2, 2,165,165, 3, 3, 3, 3, 3, 3, 3, 2,156, + 156, 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 3, + 2, 2, 2, 2, 2, 2, 2,148,148, 2, 2, 2, 2, 2, 2,158, + 158, 2, 2, 2, 2, 2, 2,153,153,153,153, 2, 2, 2, 2,149, + 149,149,149,149,149,149, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, + 2, 2, 2, 2, 2, 2, 94, 85, 85, 85, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 85, 2, 2,101, 2, 2, 2, 2, 2, 2, 2,101, + 101, 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 2, 96, 96,111, + 111,111,111,111,111,111, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 2, 2, 2,108,108, 2,108,108,108,108,108,108, + 108, 2, 2, 2, 2, 2, 2,129,129,129,129,129,129,129, 2,129, + 2,129,129,129,129, 2,129,129,129,129,129,129,129, 2,129,129, + 129, 2, 2, 2, 2, 2, 2,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, + 2, 2,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,171, + 171, 2,171, 2, 2,171, 2,171, 2,171, 2, 2,171, 2,171,171, + 171,171, 2,171,171,171,171,171, 2, 2, 2, 2, 2, 2, 2, 2, + 171,171, 2, 2, 2, 2, 2,137,137,137,137, 2,137,137,137,137, + 137, 2, 2, 2, 2, 2, 2,124,124, 2, 2, 2, 2, 2, 2,114, + 114,114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, + 32, 32, 32, 32, 2, 2, 2, 33, 33, 33, 33, 2, 2, 2, 2,126, + 126,126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,126, + 126,126,126,126,126,126, 2,142,142,142,142, 2, 2, 2, 2,125, + 125,125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125, 2, + 154, 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,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, 2, 2, 2,140, + 140,140, 2, 2, 2, 2, 2,121, 2, 2, 2, 2, 2, 2, 2, 7, + 7, 2, 2, 2, 2, 2, 2,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, 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, 2,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, 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,175,175,175,175, 2, 2, 2, 2,175, + 175, 2, 2, 2, 2, 2, 2,145, 2, 2, 2, 2, 2, 2, 2,163, + 2,163,163,163,163,163,163,163,163,163, 2, 2, 2,163,163,163, + 163,163, 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, 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,157, + 157,157, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 2, 2, 80, + 80, 80, 2, 2, 2, 2, 2,127,127,127,127,127,127,127, 2,166, + 166, 2, 2, 2, 2, 2, 2, 79, 2, 2, 2, 2, 2, 2, 2,115, + 115,115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159, + 159,159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,119, + 119,119,119,119,119, 2, 2, 2, 2, 2, 2, 2,119,119,119,167, + 167, 2, 2, 2, 2, 2, 2,146,146,146, 2, 2, 2, 2, 2,172, + 2, 2,172,172,172,172,172,172,172,172,172, 2, 2, 2, 2, 99, + 99, 99, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 99,136, + 139, 13, 13,155, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 2,155, + 155,155,155,155,155, 2, 2, 2, 2, 2, 2, 2, 2, 2,155,136, + 136,136,136,136,136,136, 2,136,136,136, 2, 2, 2, 2, 2, 17, + 17, 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, + 15, 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 2, + 2, 15, 2, 2, 2, 2, 2, 15, 15, 15, 2, 2, 17, 2, 2, 2, + 2, 2, 2, 17, 17, 17, 17,139,139,139,139, 2, 2, 2, 2,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, 1, + 1, 1, 1, 1, 1, 1, 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, 2, 2, 0, 2, 2, 0, 0, 2, 2, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0,131, + 131,131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2, + 131,131,131,131,131,131,131, 2, 2, 2, 2, 2, 19, 19, 19, 56, + 56, 56, 56, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 56, 56, 56, + 56, 2, 56, 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2, 6, + 6, 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,151, + 151,151,151,151, 2, 2, 2,151,151,151,151,151,151, 2, 2,151, + 151, 2, 2, 2, 2,151,151,160,160,160,160,160,160,160, 2,152, + 152, 2, 2, 2, 2, 2,152,164,164, 2, 2, 2, 2, 2, 2,168, + 168,168, 2, 2, 2, 2,168,174,174,174,174,174,174,174, 2,174, + 174,174,174,174,174, 2, 2, 2, 2, 2, 2, 2, 2,174,174, 30, + 30, 30, 30, 2, 30, 30, 2,113,113,113,113,113, 2, 2,113,113, + 113,113,113,113,113,113, 2,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, 3, 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, 2, + 3, 3, 3, 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 0, + 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, + 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 13, + 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 0, 0, 0, 10, 0, 11, 12, 13, 0, 0, 0, 14, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,162, 0,163, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,164,165, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 167, 0, 0, 0,168,169, 0, 0,170, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,171, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,172, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,173, + 0, 0, 0, 16, 17, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 19, + 20, 21, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,174, 0, + 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,176,177, 0, 0, 0, 0,178,179, 0, 0, 0,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,207,208,209,210,211,212,213, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 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, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,162, 0,163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,164,165, + 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0,168,169, 0, + 0,170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,175, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,176,177, 0, 0, 0, 0, + 178,179, 0, 0, 0,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, + 207,208,209,210,211,212,213, 0, 0, 0, 0, 0, 0, 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 uint16_t _hb_ucd_u16[10832]= +static const uint16_t _hb_ucd_u16[10784]= { - 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, 48, 72, 73, 48, 48, 74, 32, 75, 32, - 76, 48, 48, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 83, 84, 91, 92, 93, 94, 95, 96, 97, 84, 98, 99, 100, 88, 101, - 102, 83, 84, 103, 104, 105, 88, 106, 107, 108, 109, 110, 111, 112, 94, 113, - 114, 115, 84, 116, 117, 118, 88, 119, 120, 115, 84, 121, 122, 123, 88, 124, - 125, 115, 48, 126, 127, 128, 88, 129, 130, 131, 48, 132, 133, 134, 94, 135, - 136, 48, 48, 137, 138, 139, 140, 140, 141, 48, 142, 143, 144, 145, 140, 140, - 146, 147, 148, 149, 150, 48, 151, 152, 153, 154, 32, 155, 156, 157, 140, 140, - 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, - 48, 184, 48, 185, 48, 186, 187, 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, 32, 216, 217, 140, - 218, 48, 48, 219, 220, 160, 221, 222, 223, 48, 224, 64, 48, 48, 225, 226, - 48, 48, 227, 228, 229, 64, 48, 230, 231, 9, 9, 232, 233, 234, 235, 236, - 11, 11, 237, 27, 27, 27, 238, 239, 11, 240, 27, 27, 32, 32, 32, 32, - 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, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 273, 274, 275, 276, 209, 277, 278, 209, 279, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 281, 209, 282, 209, 209, 209, 209, 283, 209, 284, 280, 285, 209, 286, 287, 209, - 209, 209, 176, 140, 288, 140, 272, 272, 272, 289, 209, 209, 209, 209, 290, 272, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 291, 292, 209, 209, 293, - 209, 209, 209, 209, 209, 209, 294, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 295, 296, 272, 297, 209, 209, 298, 280, 299, 280, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 280, 280, 280, 280, 280, 280, 280, 280, 300, 301, 280, 280, 280, 302, 280, 303, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 209, 209, 209, 280, 304, 209, 209, 305, 209, 209, 209, 209, 209, 209, 209, 209, - 9, 9, 9, 11, 11, 11, 306, 307, 13, 13, 13, 13, 13, 13, 308, 309, - 11, 11, 310, 48, 48, 48, 311, 312, 48, 313, 314, 314, 314, 314, 32, 32, - 315, 316, 317, 318, 319, 320, 140, 140, 209, 321, 209, 209, 209, 209, 209, 322, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 323, 140, 209, - 324, 325, 326, 327, 136, 48, 48, 48, 48, 328, 178, 48, 48, 48, 48, 329, - 330, 48, 48, 136, 48, 48, 48, 48, 200, 331, 48, 48, 209, 209, 332, 48, - 209, 333, 334, 209, 335, 336, 209, 209, 334, 209, 209, 336, 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, 337, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 338, 48, 48, 230, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 339, 48, 340, 140, 13, 13, 341, 342, 13, 343, 48, 48, 48, 48, 344, 345, - 31, 346, 347, 348, 13, 13, 13, 349, 350, 351, 352, 353, 354, 355, 140, 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, 76, 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, 314, 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, 140, 140, - 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, 209, 48, 48, 48, 48, 401, 48, 48, 402, 140, 140, 403, - 32, 404, 32, 405, 406, 407, 408, 409, 48, 48, 48, 48, 48, 48, 48, 410, - 411, 2, 3, 4, 5, 412, 413, 414, 48, 415, 48, 200, 416, 417, 418, 419, - 420, 48, 172, 421, 204, 204, 140, 140, 48, 48, 48, 48, 48, 48, 48, 71, - 422, 272, 272, 423, 273, 273, 273, 424, 425, 426, 427, 140, 140, 209, 209, 428, - 140, 140, 140, 140, 140, 140, 140, 140, 48, 151, 48, 48, 48, 100, 429, 430, - 48, 48, 431, 48, 432, 48, 48, 433, 48, 434, 48, 48, 435, 436, 140, 140, - 9, 9, 437, 11, 11, 48, 48, 48, 48, 204, 192, 9, 9, 438, 11, 439, - 48, 48, 440, 48, 48, 48, 441, 442, 442, 443, 444, 445, 48, 48, 48, 388, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 313, 48, 199, 440, 140, 446, 27, 27, 447, 140, 140, 140, 140, - 448, 48, 48, 449, 48, 450, 48, 451, 48, 200, 452, 140, 140, 140, 48, 453, - 48, 454, 48, 455, 48, 207, 140, 140, 48, 48, 48, 456, 272, 457, 272, 272, - 458, 459, 48, 460, 461, 462, 48, 463, 48, 464, 140, 140, 465, 48, 466, 467, - 48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474, - 48, 48, 475, 192, 476, 9, 477, 11, 478, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 272, 479, 48, 48, 480, 481, 482, 483, 140, 484, - 48, 464, 485, 48, 62, 486, 140, 48, 487, 140, 140, 48, 488, 140, 48, 313, - 489, 48, 48, 490, 491, 457, 492, 493, 223, 48, 48, 494, 495, 48, 196, 192, - 496, 48, 497, 498, 499, 48, 48, 500, 223, 48, 48, 501, 502, 503, 504, 505, - 48, 97, 506, 507, 508, 140, 140, 140, 509, 510, 511, 48, 48, 512, 513, 192, - 514, 83, 84, 515, 516, 517, 518, 519, 520, 48, 48, 521, 522, 523, 524, 140, - 48, 48, 48, 525, 526, 527, 481, 140, 48, 48, 48, 528, 529, 192, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 530, 531, 532, 533, 140, 140, - 48, 48, 48, 534, 535, 192, 536, 140, 48, 48, 537, 538, 192, 539, 540, 140, - 48, 541, 542, 543, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 506, 544, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 545, - 546, 547, 48, 548, 549, 192, 140, 140, 140, 140, 550, 48, 48, 551, 552, 140, - 553, 48, 48, 554, 555, 556, 48, 48, 557, 558, 559, 48, 48, 48, 48, 196, - 560, 140, 140, 140, 140, 140, 561, 140, 140, 140, 140, 140, 48, 48, 562, 192, - 84, 48, 530, 563, 564, 148, 175, 565, 48, 566, 567, 568, 140, 140, 140, 140, - 569, 48, 48, 570, 571, 192, 572, 48, 573, 574, 192, 48, 48, 575, 192, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 576, - 577, 115, 48, 578, 579, 580, 140, 140, 140, 140, 140, 100, 272, 581, 582, 583, - 48, 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, 140, 140, 140, 140, 140, 140, - 273, 273, 273, 273, 273, 273, 584, 585, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 388, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 586, - 48, 48, 48, 587, 588, 589, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 71, - 48, 48, 48, 48, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 590, 591, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 592, - 48, 48, 48, 593, 594, 595, 596, 597, 48, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 598, 48, 599, 192, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 9, 9, 11, 11, 272, 600, 9, 601, 11, 602, 140, 140, - 48, 48, 48, 48, 603, 604, 605, 605, 606, 607, 140, 140, 140, 140, 608, 609, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 140, 610, - 48, 200, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 48, 611, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 612, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 611, 613, 140, 614, 615, 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, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 48, 48, 71, 151, 196, 616, 617, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 618, - 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, 619, 209, 427, 209, 620, - 32, 32, 216, 32, 621, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 323, - 209, 209, 622, 209, 209, 209, 623, 624, 625, 209, 626, 209, 209, 209, 288, 140, - 209, 209, 209, 209, 627, 140, 140, 140, 140, 140, 140, 140, 272, 628, 272, 628, - 209, 209, 209, 209, 209, 338, 272, 461, 140, 140, 140, 140, 140, 140, 140, 140, - 9, 629, 11, 630, 631, 632, 242, 9, 633, 634, 635, 636, 637, 9, 629, 11, - 638, 639, 11, 640, 641, 642, 643, 9, 644, 11, 9, 629, 11, 630, 631, 11, - 242, 9, 633, 643, 9, 644, 11, 9, 629, 11, 645, 9, 646, 647, 648, 649, - 11, 650, 9, 651, 652, 653, 654, 11, 655, 9, 656, 11, 657, 539, 539, 539, - 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, 658, 32, 32, 659, 660, 661, 662, 45, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 663, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 666, 667, 668, 27, 27, 27, 669, 140, 670, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 151, 671, 672, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 673, 140, 48, 48, 674, 675, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 676, 192, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 590, 677, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 200, 678, 679, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 680, 200, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 681, 621, 140, 140, - 9, 9, 633, 11, 682, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 504, 272, 272, 683, 684, 140, 140, 140, 140, - 504, 272, 685, 686, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 687, 48, 688, 689, 690, 691, 692, 693, 694, 206, 695, 206, 140, 140, 140, 696, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 209, 209, 697, 209, 209, 209, 209, 209, 209, 322, 333, 698, 698, 698, 209, 323, - 699, 209, 209, 209, 209, 209, 209, 209, 209, 209, 700, 140, 140, 140, 701, 209, - 702, 209, 209, 697, 703, 704, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 705, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 706, 426, 426, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 176, 697, 427, - 697, 209, 209, 209, 707, 176, 209, 209, 707, 209, 700, 697, 704, 708, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 707, 700, 426, 709, 209, 209, 209, 710, 711, 712, 703, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 713, 209, 209, 209, 209, 209, 714, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 140, 140, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 100, 48, - 48, 48, 48, 48, 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 207, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 715, 140, 587, 587, 587, 587, 587, 587, 140, 140, 140, 140, 140, 140, 140, 140, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140, - 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, 716, - 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, 717, - 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, 31, 31, - 31, 31, 50, 31, 31, 31, 31, 31, 31, 31, 31, 31, 51, 31, 31, 31, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 52, 54, 52, 52, 52, - 55, 56, 57, 58, 58, 59, 60, 61, 56, 62, 63, 64, 65, 58, 58, 66, - 67, 68, 69, 70, 70, 71, 72, 73, 68, 74, 75, 76, 77, 70, 78, 26, - 79, 80, 81, 82, 82, 83, 84, 85, 80, 86, 87, 26, 88, 82, 89, 90, - 91, 92, 93, 94, 94, 95, 96, 97, 92, 98, 99, 100, 101, 94, 94, 26, - 102, 103, 104, 105, 106, 103, 107, 108, 103, 104, 109, 26, 110, 107, 107, 111, - 112, 113, 114, 112, 112, 114, 112, 115, 113, 116, 117, 118, 119, 112, 120, 112, - 121, 122, 123, 121, 121, 123, 124, 125, 122, 126, 127, 128, 129, 121, 130, 26, - 131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131, - 136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26, - 146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26, - 150, 151, 152, 152, 153, 152, 152, 154, 155, 156, 152, 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, 184, 185, 186, 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, 198, 199, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 200, - 198, 198, 198, 198, 198, 201, 178, 178, 178, 178, 178, 178, 178, 178, 202, 26, - 203, 203, 203, 204, 203, 205, 203, 205, 206, 203, 207, 207, 207, 208, 209, 26, - 210, 210, 210, 210, 210, 211, 210, 210, 210, 212, 210, 213, 194, 194, 194, 194, - 214, 214, 214, 215, 216, 216, 216, 216, 216, 216, 216, 217, 216, 216, 216, 218, - 216, 219, 216, 219, 216, 220, 9, 9, 9, 9, 9, 221, 9, 222, 26, 26, - 223, 223, 223, 223, 223, 223, 223, 223, 223, 224, 223, 223, 223, 223, 223, 223, - 225, 225, 225, 225, 225, 225, 225, 225, 226, 226, 226, 226, 226, 226, 227, 228, - 229, 229, 229, 229, 229, 229, 229, 230, 229, 231, 232, 232, 232, 232, 232, 232, - 18, 233, 165, 165, 165, 165, 165, 234, 225, 26, 235, 9, 236, 237, 238, 239, - 2, 2, 2, 2, 240, 241, 2, 2, 2, 2, 2, 242, 243, 244, 2, 245, - 2, 2, 2, 2, 2, 2, 2, 246, 9, 9, 9, 9, 9, 9, 9, 9, - 14, 14, 247, 247, 14, 14, 14, 14, 247, 247, 14, 248, 14, 14, 14, 247, - 14, 14, 14, 14, 14, 14, 249, 14, 249, 14, 250, 251, 14, 14, 252, 253, - 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 256, 257, - 0, 258, 2, 259, 0, 0, 0, 0, 260, 26, 9, 9, 9, 9, 261, 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, 0, 260, 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, - 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 2, 2, 2, 2, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 270, 271, - 165, 165, 165, 165, 166, 167, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273, - 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, 0, 275, 26, 26, 26, 26, - 276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278, 26, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 0, 0, - 280, 0, 0, 0, 281, 282, 0, 283, 284, 285, 285, 285, 285, 285, 285, 285, - 285, 285, 286, 287, 288, 289, 289, 289, 289, 289, 289, 289, 289, 289, 289, 290, - 291, 292, 292, 292, 292, 292, 293, 169, 169, 169, 169, 169, 169, 169, 169, 169, - 169, 294, 0, 0, 292, 292, 292, 292, 0, 0, 0, 0, 275, 295, 289, 289, - 169, 169, 169, 294, 0, 0, 0, 0, 0, 0, 0, 0, 169, 169, 169, 296, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 289, 289, 289, 289, 289, 297, - 289, 289, 289, 289, 289, 289, 289, 289, 289, 289, 289, 0, 0, 0, 0, 0, - 276, 276, 276, 276, 276, 276, 276, 276, 0, 0, 0, 0, 0, 0, 0, 0, - 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, - 298, 299, 298, 298, 298, 298, 298, 298, 300, 26, 301, 301, 301, 301, 301, 301, - 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, - 302, 302, 302, 302, 302, 303, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 26, - 0, 0, 0, 0, 305, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 306, 2, 2, 2, 2, 2, 2, 2, 2, 2, 259, 26, 26, 307, 2, - 308, 308, 308, 308, 308, 309, 0, 260, 310, 310, 310, 310, 310, 310, 310, 26, - 311, 311, 311, 311, 311, 311, 311, 311, 312, 313, 311, 314, 52, 52, 52, 52, - 315, 315, 315, 315, 315, 316, 317, 317, 317, 317, 318, 319, 169, 169, 169, 320, - 321, 321, 321, 321, 321, 321, 321, 321, 321, 322, 321, 323, 164, 164, 164, 324, - 325, 325, 325, 325, 325, 325, 326, 26, 325, 327, 325, 328, 164, 164, 164, 164, - 329, 329, 329, 329, 329, 329, 329, 329, 330, 26, 26, 331, 332, 332, 333, 26, - 334, 334, 334, 26, 172, 172, 2, 2, 2, 2, 2, 335, 336, 337, 176, 176, - 176, 176, 176, 176, 176, 176, 176, 176, 332, 332, 332, 332, 332, 338, 332, 339, - 169, 169, 169, 169, 340, 26, 169, 169, 294, 341, 169, 169, 169, 169, 169, 340, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 342, 26, 26, 26, 26, - 343, 26, 344, 345, 25, 25, 346, 347, 348, 25, 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, 349, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 26, 26, 26, 26, 31, 31, - 9, 9, 0, 260, 9, 350, 0, 0, 0, 0, 351, 0, 258, 352, 353, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 354, - 355, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 356, 289, 288, 289, - 289, 289, 289, 357, 169, 169, 169, 294, 358, 358, 358, 359, 258, 258, 26, 360, - 361, 362, 361, 361, 363, 361, 361, 364, 361, 365, 361, 365, 26, 26, 26, 26, - 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 366, - 367, 0, 0, 0, 0, 0, 368, 0, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 253, 0, 369, 370, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 371, - 372, 372, 372, 373, 374, 374, 374, 374, 374, 374, 375, 26, 376, 0, 0, 352, - 377, 377, 377, 377, 378, 379, 380, 380, 380, 381, 382, 382, 382, 382, 382, 383, - 384, 384, 384, 385, 386, 386, 386, 386, 387, 386, 388, 26, 26, 26, 26, 26, - 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 390, 390, 390, 390, 390, 390, - 391, 391, 391, 392, 391, 393, 394, 394, 394, 394, 395, 394, 394, 394, 394, 395, - 396, 396, 396, 396, 396, 26, 397, 397, 397, 397, 397, 397, 398, 399, 400, 401, - 400, 401, 402, 400, 403, 400, 403, 404, 405, 405, 405, 405, 405, 405, 406, 26, - 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, - 407, 407, 407, 407, 407, 407, 408, 26, 407, 407, 409, 26, 407, 26, 26, 26, - 410, 2, 2, 2, 2, 2, 411, 412, 26, 26, 26, 26, 26, 26, 26, 26, - 413, 414, 415, 415, 415, 415, 416, 417, 418, 418, 419, 418, 420, 420, 420, 420, - 421, 421, 421, 422, 423, 421, 26, 26, 26, 26, 26, 26, 424, 424, 425, 426, - 427, 427, 427, 428, 429, 429, 429, 430, 431, 431, 431, 432, 26, 26, 26, 26, - 433, 433, 433, 433, 434, 434, 434, 435, 434, 434, 436, 434, 434, 434, 434, 434, - 437, 438, 439, 440, 441, 441, 442, 443, 441, 444, 441, 444, 445, 445, 445, 445, - 446, 446, 446, 446, 26, 26, 26, 26, 447, 447, 447, 447, 448, 449, 448, 26, - 450, 450, 450, 450, 450, 450, 451, 452, 453, 453, 454, 453, 455, 455, 456, 455, - 457, 457, 458, 459, 26, 460, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 461, 461, 461, 461, 461, 461, 461, 461, 461, 462, 26, 26, 26, 26, 26, 26, - 463, 463, 463, 463, 463, 463, 464, 26, 463, 463, 463, 463, 463, 463, 464, 465, - 466, 466, 466, 466, 466, 26, 466, 467, 468, 468, 468, 468, 469, 470, 468, 468, - 469, 471, 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, 31, 31, 31, 472, - 473, 473, 473, 473, 473, 474, 475, 26, 476, 26, 31, 477, 26, 26, 26, 476, - 478, 478, 478, 478, 478, 26, 479, 479, 479, 479, 479, 480, 26, 26, 481, 481, - 481, 482, 26, 26, 26, 26, 483, 483, 483, 484, 26, 26, 485, 485, 486, 26, - 487, 487, 487, 487, 487, 487, 487, 487, 487, 488, 489, 487, 487, 487, 488, 490, - 491, 491, 491, 491, 491, 491, 491, 491, 492, 493, 494, 494, 494, 495, 494, 496, - 497, 497, 497, 497, 497, 497, 498, 497, 497, 26, 499, 499, 499, 499, 500, 26, - 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 502, 137, 503, 26, - 504, 504, 505, 504, 504, 504, 504, 504, 506, 26, 26, 26, 26, 26, 26, 26, - 507, 508, 509, 510, 509, 511, 512, 512, 512, 512, 512, 512, 512, 513, 512, 514, - 515, 516, 517, 518, 518, 519, 520, 521, 516, 522, 523, 524, 525, 526, 526, 26, - 527, 528, 527, 527, 527, 527, 529, 527, 530, 531, 529, 532, 533, 26, 26, 26, - 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 535, 536, 26, 26, 26, - 537, 537, 537, 537, 537, 537, 537, 537, 537, 26, 537, 538, 26, 26, 26, 26, - 539, 539, 539, 539, 539, 539, 540, 539, 539, 539, 539, 540, 26, 26, 26, 26, - 541, 541, 541, 541, 541, 541, 541, 541, 542, 26, 541, 543, 198, 544, 26, 26, - 545, 545, 545, 545, 545, 545, 545, 546, 545, 546, 164, 164, 547, 26, 26, 26, - 548, 548, 548, 549, 548, 550, 548, 548, 551, 26, 26, 26, 26, 26, 26, 26, - 552, 552, 552, 552, 552, 552, 552, 553, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 555, 556, - 557, 558, 559, 560, 560, 560, 561, 562, 557, 26, 560, 563, 26, 26, 26, 26, - 26, 26, 26, 26, 564, 565, 564, 564, 564, 564, 564, 565, 566, 26, 26, 26, - 567, 567, 567, 567, 567, 567, 567, 567, 567, 26, 568, 568, 568, 568, 568, 568, - 568, 568, 568, 568, 569, 26, 178, 178, 570, 570, 570, 570, 570, 570, 570, 571, - 52, 572, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 501, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 573, 573, 573, 573, 574, 26, 573, 574, - 575, 576, 575, 575, 575, 575, 577, 575, 578, 26, 575, 575, 575, 579, 580, 580, - 580, 580, 581, 580, 580, 582, 583, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 584, 585, 586, 586, 586, 586, 584, 587, 586, 26, 586, 588, 589, 590, 591, 591, - 591, 592, 593, 594, 591, 595, 596, 596, 596, 596, 596, 597, 596, 598, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 599, 599, 599, 600, - 601, 601, 602, 601, 601, 601, 601, 603, 601, 601, 601, 604, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 605, 26, 107, 107, 107, 107, 107, 107, 606, 607, - 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, - 608, 608, 608, 609, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 610, 611, 26, - 608, 608, 608, 608, 608, 608, 608, 608, 612, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 613, 614, 26, - 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, - 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 616, 26, 615, 615, 615, 615, - 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 617, - 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, - 618, 618, 618, 618, 618, 618, 618, 618, 619, 26, 26, 26, 26, 26, 26, 26, - 620, 620, 620, 620, 620, 620, 620, 621, 26, 26, 26, 26, 26, 26, 26, 26, - 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, - 304, 304, 304, 304, 304, 304, 304, 622, 623, 623, 623, 624, 623, 625, 626, 626, - 626, 626, 626, 626, 626, 626, 626, 627, 626, 628, 629, 629, 629, 630, 630, 26, - 631, 631, 631, 631, 631, 631, 631, 631, 632, 26, 631, 633, 633, 631, 631, 634, - 631, 631, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 635, 635, 635, 635, 635, 635, 635, 636, - 26, 26, 26, 26, 26, 26, 26, 26, 637, 637, 637, 637, 637, 637, 637, 637, - 637, 637, 637, 638, 639, 639, 639, 640, 639, 639, 641, 26, 26, 26, 26, 26, - 642, 642, 642, 642, 642, 642, 642, 642, 642, 643, 642, 642, 642, 642, 642, 642, - 642, 644, 642, 642, 26, 26, 26, 26, 26, 26, 26, 26, 645, 26, 646, 26, - 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, - 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, - 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 649, 26, 26, 26, 26, 650, - 647, 647, 647, 651, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 652, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 653, 654, - 655, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, - 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, - 285, 285, 285, 285, 656, 26, 657, 26, 26, 26, 658, 26, 659, 26, 660, 660, - 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, - 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 661, - 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, 663, 662, 664, - 662, 665, 662, 666, 352, 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, 0, 369, - 0, 0, 0, 0, 0, 0, 352, 667, 0, 0, 668, 26, 0, 0, 668, 26, - 9, 9, 9, 9, 9, 221, 9, 9, 669, 26, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 352, 26, 26, 26, 26, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, - 0, 0, 0, 0, 258, 355, 0, 0, 0, 0, 0, 0, 670, 671, 0, 672, - 673, 674, 0, 0, 0, 675, 0, 0, 0, 0, 0, 0, 0, 266, 26, 26, - 14, 14, 14, 14, 14, 14, 14, 14, 247, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 352, 26, 0, 0, 352, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 0, 0, 0, 668, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, - 0, 0, 0, 255, 676, 677, 0, 678, 679, 0, 0, 0, 0, 0, 0, 0, - 680, 681, 255, 255, 0, 0, 0, 682, 683, 667, 684, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 275, 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, - 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, - 685, 686, 26, 687, 688, 685, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 2, 2, 2, 343, 689, 412, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 690, 269, 269, 691, 692, 693, 18, 18, 18, 18, 18, 18, 18, 694, 26, 26, - 26, 695, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 696, 696, 696, 696, 696, 697, 696, 698, 696, 699, 26, 26, 26, 26, 26, 26, - 26, 26, 700, 700, 700, 701, 26, 26, 702, 702, 702, 702, 702, 702, 702, 703, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 704, 704, 704, 704, 704, 705, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 706, 706, 706, 706, 706, 707, - 26, 26, 26, 26, 26, 26, 26, 26, 708, 708, 708, 709, 708, 708, 710, 711, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 172, 712, 170, 172, - 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, - 713, 713, 713, 713, 713, 713, 713, 713, 714, 713, 715, 26, 26, 26, 26, 26, - 716, 716, 716, 716, 716, 716, 716, 716, 716, 717, 716, 718, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 355, 0, - 0, 0, 0, 0, 0, 0, 369, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 355, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 26, 26, - 719, 31, 31, 31, 720, 721, 722, 723, 724, 725, 720, 726, 720, 722, 722, 727, - 31, 728, 31, 729, 730, 728, 31, 729, 26, 26, 26, 26, 26, 26, 731, 26, - 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 352, 26, 0, 258, 355, 0, 355, 0, 355, 0, 0, 0, 275, 26, - 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 732, 0, 0, 0, - 733, 26, 0, 0, 0, 0, 0, 352, 0, 668, 260, 26, 275, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 734, 0, 369, 0, 369, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 260, 0, 352, 668, 26, - 0, 352, 0, 0, 0, 0, 0, 0, 0, 26, 0, 260, 0, 0, 0, 0, - 0, 26, 0, 0, 0, 275, 0, 352, 260, 26, 0, 668, 26, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 275, 0, 369, - 0, 735, 0, 0, 0, 0, 0, 0, 258, 736, 0, 737, 0, 367, 0, 668, - 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 266, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 26, 26, 26, 26, - 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 738, 26, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 26, - 276, 276, 276, 279, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 739, 276, 276, 276, 276, 276, 276, - 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 342, - 740, 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, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 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, + 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, + 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, + 224, 224, 768, 424, 432, 440, 448, 776, 224, 224, 784, 792, 72, 800, 40, 808, + 48, 48, 48, 816, 824, 48, 48, 832, 840, 848, 856, 864, 872, 880, 48, 888, + 48, 48, 48, 896, 904, 40, 40, 40, 40, 912, 40, 96, 920, 928, 936, 456, + 64, 64, 64, 64, 64, 64, 64, 944, 952, 960, 968, 40, 976, 984, 48, 992, + 72, 72, 72, 40, 40, 40, 48, 48,1000, 48, 48, 48,1008, 48, 48, 48, + 48, 48, 48,1016, 72,1024, 40, 40,1032, 464, 64,1040,1048, 8,1056,1064, + 1072,1080, 8, 8,1088, 64,1096,1104, 8, 8, 8, 8, 8,1112,1120,1128, + 1136,1144, 8, 64,1152, 8, 8, 8, 8, 8, 472,1160, 232, 8,1168,1176, + 8,1184,1192,1200, 8,1208, 176, 8,1216,1224, 8, 8,1232, 64,1240, 64, + 480, 8, 8,1248,1256,1264,1272,1280,1288, 240, 128,1296,1304,1312, 144,1320, + 1328, 240, 128,1336,1344,1352, 304,1360,1368, 488, 128,1376,1384, 248, 144,1392, + 1400, 240, 128,1408,1416,1424, 144,1432,1440,1448,1456,1464,1472,1480, 304,1488, + 1496, 256, 128,1504,1512,1520, 144,1528,1536, 256, 128,1544,1552,1560, 144,1568, + 1576, 256, 8,1584,1592,1600, 144,1608,1616,1624, 8,1632,1640,1648, 304,1656, + 312, 8, 8,1664,1672,1680, 0, 0,1688, 8,1696,1704,1712,1720, 0, 0, + 1728,1736, 320,1744,1752, 8, 152,1760,1768,1776, 64,1784,1792,1800, 0, 0, + 8, 8,1808,1816, 496,1824,1832,1840,1848,1856, 72, 72,1864, 40, 40,1872, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 504,1880, 8, 8, 504, 8, 8,1888, 512, 520, 8, 8, + 8, 512, 8, 8, 8,1896,1904, 528, 8, 264, 72, 72, 72, 72, 72,1912, + 536, 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, 8, 8, 8, 8, 8,1920, 8,1928,1936, 8, 8, 8, 8,1944,1952, + 8,1960, 8,1968, 8,1976,1984,1992, 8, 8, 8,2000,2008,2016, 80,2024, + 2032, 80, 8, 8,2040, 8, 8, 160,2048, 8,2056, 8, 8, 8, 8, 328, + 8, 120,2064,2072,2080, 8, 112,2088, 8, 8, 184, 8, 192,2096, 24, 24, + 8,2104, 8, 8, 8,2112,2120,2128, 80, 80,2136,2144, 64, 544,2152, 0, + 2160, 8, 8,2168,2176, 496,2184,2192, 336, 8,2200, 232, 8, 8,2208,2216, + 8, 8,2224,2232,2240, 232, 8, 552,2248, 72, 72,2256,2264,2272,2280,2288, + 40, 40,2296, 96, 96, 96,2304,2312, 40,2320, 96, 96, 64, 64, 64, 64, + 48, 48, 48, 48, 48, 48, 48, 48, 48,2328, 48, 48, 48, 48, 48, 48, + 168, 560, 168, 168, 560,2336, 168,2344, 344, 344, 344,2352,2360,2368,2376,2384, + 2392,2400,2408,2416,2424,2432,2440,2448,2456,2464, 568, 568,2472,2480,2488,2496, + 2504,2512,2520,2528,2536, 88, 104, 104,2544,2552,2560, 24,2568,2576, 24,2584, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 2592, 24,2600, 24, 24, 24, 24,2608, 24,2616, 56,2624, 24,2632,2640, 24, + 24, 24, 264, 0, 576, 0, 88, 88, 88,2648, 24, 24, 24, 24,2656, 88, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,2664,2672, 24, 24,2680, + 24, 24, 24, 24, 24, 24,2688, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24,2696,2704, 88,2712, 24, 24,2720, 56,2728, 56, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 56, 56, 56, 56, 56, 56, 56, 56,2736,2744, 56, 56, 56,2752, 56,2760, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 24, 24, 24, 56,2768, 24, 24,2776, 24, 24, 24, 24, 24, 24, 24, 24, + 72, 72, 72, 40, 40, 40,2784,2792, 48, 48, 48, 48, 48, 48,2800,2808, + 40, 40,2816, 8, 8, 8,2824,2832, 8, 200, 208, 208, 208, 208, 64, 64, + 2840,2848,2856,2864,2872,2880, 0, 0, 24,2888, 24, 24, 24, 24, 24, 352, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 272, 0, 24, + 2896,2904,2912,2920, 312, 8, 8, 8, 8,2928, 536, 8, 8, 8, 8,2936, + 2944, 8, 8, 312, 8, 8, 8, 8, 120,2952, 8, 8, 24, 24,2960, 8, + 24, 584, 592, 24,2968, 600, 24, 24, 592, 24, 24, 600, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 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, 24, 24, 24, 24, + 8,2976, 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, 8, 8, 8, 8, 8, 8, 152, 24, 24, 24, 608, 8, 8, 552, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 2984, 8,2992, 0, 48, 48,3000,3008, 48,3016, 8, 8, 8, 8,3024,3032, + 456,3040,3048,3056, 48, 48, 48,3064,3072,3080,3088,3096,3104,3112, 0,3120, + 3128, 8,3136,3144, 8, 8, 8,3152,3160, 8, 8,3168,3176, 80, 64,3184, + 232, 8,3192, 8,3200,3208, 8, 152, 480, 8, 8,3216,3224, 360,3232,3240, + 8, 8,3248,3256,3264,3272, 8,3280, 8, 8, 8,3288,3296,3304,3312,3320, + 3328,3336, 208, 40, 40,3344,3352, 40, 40, 40, 40, 40, 8, 8,3360, 80, + 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, 368, 8,3368, 8, 8, 184, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 112, 8, 8, 8, 8, 8, 8, 192, 0, 0, + 3376,3384,3392,3400,3408, 8, 8, 8, 8, 8, 8,3416,3424,3432, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8,3440, 24, 8, 8, 8, 8,3448, 8, 8,3456, 0, 0,3464, + 64,3472, 64,3480,3488,3496,3504,3512, 8, 8, 8, 8, 8, 8, 8,3520, + 3528, 424, 432, 440, 448,3536,3544,3552, 8,3560, 8, 120,3568,3576,3584,3592, + 3600, 8, 520,3608, 112, 112, 0, 0, 8, 8, 8, 8, 8, 8, 8, 176, + 3616, 88, 88,3624, 104, 104, 104,3632,3640, 280, 376, 0, 0, 24, 24,3648, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 152, 8, 8, 8, 248,3656,3664, + 8, 8,3672, 8,3680, 8, 8,3688, 8,3696, 8, 8,3704,3712, 0, 0, + 72, 72,3720, 40, 40, 8, 8, 8, 8, 112, 80, 72, 72,3728, 40,3736, + 8, 8, 616, 8, 8, 8,3744, 624, 624,3752,3760,3768, 8, 8, 8, 368, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 200, 8, 328, 616, 0,3776, 96, 96,3784, 0, 0, 0, 0, + 3792, 8, 8,3800, 8,3808, 8,3816, 8, 120,3824, 0, 0, 0, 8,3832, + 8,3840, 8,3848, 8, 192, 0, 0, 8, 8, 8,3856, 88, 632, 88, 88, + 3864,3872, 8,3880, 640,3888, 8,3896, 8, 648, 0, 0,3904, 8,3912,3920, + 8, 8, 8,3928, 8,3936, 8,3944, 8,3952,3960, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 160, 0, 0, 0, 72, 72, 72,3968, 40, 40, 40,3976, + 8, 8,3984, 80,3992, 72,4000, 40,4008, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 88,4016, 8, 8,4024, 656,4032,4040, 0,4048, + 8, 648,4056, 8, 472,4064, 0, 8,4072, 0, 0, 8,4080, 0, 8, 200, + 4088, 8, 8,4096,4104, 632,4112,4120, 336, 8, 8,4128,4136, 8, 160, 80, + 4144, 8,4152,4160,4168, 8, 8,4176, 336, 8, 8,4184,4192,4200, 384,4208, + 8, 488, 664,4216,4224, 0, 0, 0,4232,4240,4248, 8, 8,4256,4264, 80, + 4272, 240, 128,4280,4288,4296,4304,4312,4320, 8, 8,4328,4336,4344,4352, 0, + 8, 8, 8,4360,4368,4376, 656, 0, 8, 8, 8,4384,4392, 80, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 672,4400,4408,4416, 0, 0, + 8, 8, 8,4424,4432, 80,4440, 0, 8, 8,4448,4456, 80, 288,4464, 0, + 8,4472,4480,4488, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 664,4496, 0, 0, 0, 0, 0, 0, 72, 72, 40, 40, 320,4504, + 4512,4520, 8,4528,4536, 80, 0, 0, 0, 0,4544, 8, 8,4552,4560, 0, + 4568, 8, 8,4576,4584,4592, 8, 8,4600,4608,4616, 8, 8, 8, 8, 160, + 4624, 0, 0, 0, 0, 0,4632, 0, 0, 0, 0, 0, 8, 8,4640, 80, + 128, 8, 672,4648,4656, 320, 528,4664, 8,4672,4680,4688, 0, 0, 0, 0, + 4696, 8, 8,4704,4712, 80,4720, 8,4728,4736, 80, 8, 8,4744, 80, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,4752, + 4760, 256, 8,4768,4776,4784, 0, 0, 0, 0, 0, 248, 88,4792,4800,4808, + 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, 192, 0, 0, 0, 0, 0, 0, + 104, 104, 104, 104, 104, 104,4816,4824, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 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, 8, 8, 8, 8, 8,4832, + 8, 8, 8, 136,4840,4848, 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, 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, 176, + 8, 8, 8, 8, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 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, 680,4856, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 160, 8, 120, 360, 8, 8, 8, 8, 120, 80, 8, 112,4864, + 8, 8, 8,4872,4880,4888,4896,4904, 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,4912, 8,4920, 80, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 72, 72, 40, 40, 88,4928, 72,4936, 40,4944, 0, 0, + 8, 8, 8, 8,4952,4960, 688, 688,4968,4976, 0, 0, 0, 0,4984,4992, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 328, 0,5000, + 8, 120, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 696, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5008, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 696,5016, 0,5024,5032, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 184, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 176, 152, 160,5040,5048, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5056, + 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,5064, 24, 376, 24,5072, + 64, 64, 544, 64, 704, 24, 24, 24, 24, 24, 24, 24, 352, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 272, + 24, 24,5080, 24, 24, 24,5088,5096,5104, 24,5112, 24, 24, 24, 576, 0, + 24, 24, 24, 24,5120, 0, 0, 0, 0, 0, 0, 0, 88, 712, 88, 712, + 24, 24, 24, 24, 24, 608, 88, 640, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 296, 40, 720, 728,5128, 168, 72, 392,5136,5144,5152,5160, 72, 296, 40, + 5168,5176, 40,5184,5192,5200, 736, 72, 744, 40, 72, 296, 40, 720, 728, 40, + 168, 72, 392, 736, 72, 744, 40, 72, 296, 40,5208, 72,5216,5224,5232,5240, + 40,5248, 72,5256,5264,5272,5280, 40,5288, 72,5296, 40,5304, 288, 288, 288, + 64, 64, 64,5312, 64, 64,5320,5328,5336,5344, 464, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5352,5360,5368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5376,5384,5392, 96, 96, 96,5400, 0,5408, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 152,5416,5424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5432, 0, 8, 8,5440,5448, + 0, 0, 0, 0, 0, 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,5456, 80, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 680,5464, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120,5472,5480, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5488, 120, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,5496, 704, 0, 0, + 72, 72, 392, 40,5504, 360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 384, 88, 88,5512,5520, 0, 0, 0, 0, + 384, 88,5528,5536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5544, 8,5552,5560,5568,5576,5584,5592,5600, 184,5608, 184, 0, 0, 0,5616, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 216, 24, 24, 24, 24, 24, 24, 352, 584, 400, 400, 400, 24, 272, + 5624, 24, 24, 24, 24, 24, 24, 24, 24, 24, 408, 0, 0, 0,5632, 24, + 5640, 24, 24, 216, 752, 760, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5648, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5656, 280, 280, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 264, 216, 376, + 216, 24, 24, 24, 416, 264, 24, 24, 416, 24, 408, 216, 760,5664, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 416, 408, 280,5672, 24, 24, 24,5680,5688,5696, 752, + 24, 24, 24, 24, 24, 24, 24, 24, 24,5704, 24, 24, 24, 24, 24,5712, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 112, 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, 8, 8, 8, 8, 8, 8, 8, 8, 112, 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, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 248, 8, + 8, 8, 8, 8, 8, 112, 0, 0, 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, 112, 0, 0, 0, 0, 0, 0, 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, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 176, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 192, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5720, 0, 136, 136, 136, 136, 136, 136, 0, 0, 0, 0, 0, 0, 0, 0, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,5728, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, + 24, 24, 24, 24, 24, 24, 24, 24,1104, 48, 48,1112,1104, 48, 48,1112, + 24, 24, 24, 24, 24,1288, 24,1288, 48, 48,1512, 48, 48, 48,1512, 48, + 48, 48, 48, 48, 48, 48, 48,2048, 24, 24, 24, 24,2056,2064, 24, 24, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,2072,2080, + 2088,2096, 144, 144,2104, 144, 144, 144, 144, 144, 144, 144,2112, 296, 144, 144, + 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, + 2120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 120, 120,1520, 592, 592, 592,2128,1520, 592, 592, 592, 592, + 592,2136,2144, 352, 352, 352, 352, 352, 352, 0, 352, 352, 352,2152,2160, 0, + 1528,2168, 56,2176, 56, 56, 56, 56,2184,2192,2200, 56, 56, 56,2208, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,1528, 56, 56, 56, 56, + 496,2216, 496, 496, 496, 496, 496, 496, 496,2224, 56, 56, 56, 56, 56, 56, + 784, 784, 784, 784, 784, 784,2232, 0, 688, 688, 688, 688, 688, 688, 688,2240, + 792, 792, 792, 792, 792,2248, 792,2256,1296,1296,1296,2264, 496,2272, 56, 56, + 56, 56,2280, 56, 56, 56, 56, 56, 56, 56, 56, 56,2288, 56, 56, 56, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,2296, 240,2304, 240, 240, 240, + 2312,1536,2320,1120,1120,2328,2336,2344,1536,2352,2360,2368,2376,1120,1120,2384, + 2392,1544,2400,1304,1304,2408,2416,2424,1544,2432,2440,2448,2456,1304,2464, 0, + 2472,1552,2480,1312,1312,2488,2496,2504,1552,2512,2520, 0,2528,1312,2536,2544, + 2552,1560,2560,1128,1128,2568,2576,2584,1560,2592,2600,2608,2616,1128,1128, 0, + 2624,1320,1568,2632,2640,1320, 504,2648,1320,1568,2656, 0,2664, 504, 504,2672, + 800,1576,1584, 800, 800,1584, 800,2680,1576,2688,2696,2704,2712, 800,2720, 800, + 1136,1592,1600,1136,1136,1600,2728,2736,1592,2744,2752,2760,2768,1136,2776, 0, + 400,1608,1616, 400, 400, 400, 400, 400,1608,1616,2784, 400,2792, 400, 400, 400, + 2800, 808,1624,2808, 808, 808,2816,2824,1624,2832,2840, 808,2848, 808,2856, 0, + 2864, 512, 512, 512, 512, 512, 512,2872, 512, 512, 512,2880, 0, 0, 0, 0, + 2888,2896, 984, 984,2904, 984, 984,2912,2920,2928, 984,2936, 0, 0, 0, 0, + 224, 224, 224, 224, 224, 224, 224, 224, 224,1328, 224, 224, 224,2944,1328, 224, + 224, 224, 224,1328, 224, 224, 224,1632, 224,1632,2952,2960, 0, 0, 0, 0, + 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, + 200, 200, 200, 200, 256, 256, 256, 256,1640,1648, 256, 256, 256, 256, 256,2968, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 816, 280, 816, 160, 160, 160, 160, + 160, 816, 160, 160, 160, 160, 816, 280, 816, 160, 280, 160, 160, 160, 160, 160, + 160, 160, 816, 160, 160, 160, 160, 160, 160, 160, 160,2976, 160, 160, 160,2984, + 160, 160, 160,2992, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,1656,1656, + 1336,1336,1336,3000, 408, 408, 408, 408, 408, 408, 408, 408, 408,3008, 408,3016, + 1664,1664,3024,3032,1672,1672,3040, 0,1680,1680,3048, 0,3056,3064,3072, 0, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272,3080, 272,1688, 272,1688, + 3088, 248, 248,3096, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,3104, + 248, 248, 248, 248, 248,3112, 80, 80, 80, 80, 80, 80, 80, 80,3120, 0, + 824, 824, 824,3128, 824,1696, 824,1696,3136, 824,1344,1344,1344,3144,3152, 0, + 520, 520, 520, 520, 520,3160, 520, 520, 520,3168, 520,3176, 272, 272, 272, 272, + 1352,1352,1352,3184, 320, 320, 320, 320, 320, 320, 320,3192, 320, 320, 320,3200, + 320,1704, 320,1704, 320,3208, 104, 104, 104, 104, 104,1712, 104,3216, 0, 0, + 304, 304, 304, 304, 304, 304, 304, 304, 304,3224, 304, 304, 304, 304, 304, 304, + 528, 528, 528, 528, 528, 528, 528, 528, 832, 832, 832, 832, 832, 832,3232,3240, + 600, 600, 600, 600, 600, 600, 600,3248, 600,3256, 840, 840, 840, 840, 840, 840, + 120,3264, 256, 256, 256, 256, 256,3272, 528, 0,3280, 104,3288,3296,3304,3312, + 48, 48, 48, 48,3320,3328, 48, 48, 48, 48, 48,3336,3344,3352, 48,3360, + 48, 48, 48, 48, 48, 48, 48,3368, 104, 104, 104, 104, 104, 104, 104, 104, + 144, 144, 848, 848, 144, 144, 144, 144, 848, 848, 144,3376, 144, 144, 144, 848, + 144, 144, 144, 144, 144, 144,1720, 144,1720, 144,3384,3392, 144, 144,3400,1728, + 24,3408, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 992, 24,3416,3424, + 24, 608, 48,1736, 24, 24, 24, 24, 616, 0, 104, 104, 104, 104,3432, 0, + 24, 24, 24, 24,3440,3448,1288, 24, 24,3456, 24, 24, 48, 48, 48, 48, + 48,3464, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 616, 0, 0, 24,1360, 0, 0, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,1744, 24, + 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 48, 48, 48, 48, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296,3472,3480, + 256, 256, 256, 256,1640,1648, 696, 696, 696, 696, 696, 696, 696,1752,3488,1752, + 160, 160, 280, 0, 280, 280, 280, 280, 280, 280, 280, 280, 120, 120, 120, 120, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 416, 0, 0, 0, 0, + 8, 8, 8,3496, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,3504, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 856, 0, 0, 0, 24, 24, + 3512, 24, 24, 24,3520,3528, 24,3536,3544, 152, 152, 152, 152, 152, 152, 152, + 152, 152,3552,3560,1760, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,3568, + 3576, 536, 536, 536, 536, 536,3584, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16,1144, 24, 24, 536, 536, 536, 536, 24, 24, 24, 24, 416,3592, 184, 184, + 16, 16, 16,1144, 24, 24, 24, 24, 24, 24, 24, 24, 16, 16, 16,3600, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 184, 184, 184, 184, 184,3608, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 24, 24, 24, 24, 24, + 8, 8, 8, 8, 8, 8, 8, 8, 24, 24, 24, 24, 24, 24, 24, 24, + 72,3616, 72, 72, 72, 72, 72, 72,3624, 0, 864, 864, 864, 864, 864, 864, + 176, 176, 176, 176, 176,3632, 0, 0, 120, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 0, + 24, 24, 24, 24,3640, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48,3648, 48, 48, 48, 48, 48, 48, 48, 48, 48,1736, 0, 0,3656, 48, + 1000,1000,1000,1000,1000,3664, 24, 616, 704, 704, 704, 704, 704, 704, 704, 0, + 544, 544, 544, 544, 544, 544, 544, 544,3672,3680, 544,3688, 240, 240, 240, 240, + 1008,1008,1008,1008,1008,3696,1152,1152,1152,1152,3704,3712, 16, 16, 16,3720, + 424, 424, 424, 424, 424, 424, 424, 424, 424,3728, 424,3736, 200, 200, 200,3744, + 624, 624, 624, 624, 624, 624,3752, 0, 624,3760, 624,3768, 200, 200, 200, 200, + 632, 632, 632, 632, 632, 632, 632, 632,3776, 0, 0,3784, 640, 640,3792, 0, + 1368,1368,1368, 0, 280, 280, 48, 48, 48, 48, 48,3800,3808,3816, 232, 232, + 232, 232, 232, 232, 232, 232, 232, 232, 640, 640, 640, 640, 640,3824, 640,3832, + 16, 16, 16, 16,1768, 0, 16, 16,1144,3840, 16, 16, 16, 16, 16,1768, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 856, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,1776, 0, 0, 0, 0, + 1784, 0,3848,3856, 352, 352,3864,3872,3880, 352, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56,3888, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 0, 0, 0, 0, 56, 56, + 104, 104, 24, 616, 104,3896, 24, 24, 24, 24,1792, 24, 608, 328,3904, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,3912, + 712, 24, 24, 24,1104, 48, 48,1112,1104, 48, 48,1112,3920, 184,1760, 184, + 184, 184, 184,3928, 16, 16, 16,1144,1376,1376,1376,3936, 608, 608, 0,3944, + 216,3952, 216, 216,3960, 216, 216,3968, 216,1800, 216,1800, 0, 0, 0, 0, + 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216,3976, + 1808, 24, 24, 24, 24, 24,3984, 24, 144, 144, 144, 144, 144, 144, 144, 144, + 144,1728, 24, 872,3992, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24,4000, + 1384,1384,1384,4008, 880, 880, 880, 880, 880, 880,4016, 0,4024, 24, 24, 328, + 1160,1160,1160,1160,4032,4040,1392,1392,1392,4048,1016,1016,1016,1016,1016,4056, + 1400,1400,1400,4064,1024,1024,1024,1024,4072,1024,4080, 0, 0, 0, 0, 0, + 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 888, 888, 888, 888, 888, 888, + 1168,1168,1168,4088,1168,4096, 648, 648, 648, 648,1816, 648, 648, 648, 648,1816, + 1032,1032,1032,1032,1032, 0, 896, 896, 896, 896, 896, 896,4104,4112,1176,1824, + 1176,1824,4120,1176,1832,1176,1832,4128, 904, 904, 904, 904, 904, 904,4136, 0, + 168, 168, 168, 168, 168, 168,4144, 0, 168, 168,4152, 0, 168, 0, 0, 0, + 4160, 48, 48, 48, 48, 48,4168,1840, 0, 0, 0, 0, 0, 0, 0, 0, + 4176,4184,1184,1184,1184,1184,4192,4200,1408,1408,4208,1408,1192,1192,1192,1192, + 1200,1200,1200,4216,4224,1200, 0, 0, 0, 0, 0, 0,1848,1848,4232,4240, + 1416,1416,1416,4248,1424,1424,1424,4256,1432,1432,1432,4264, 0, 0, 0, 0, + 1208,1208,1208,1208, 440, 440, 440,4272, 440, 440,4280, 440, 440, 440, 440, 440, + 4288,4296,4304,4312,1216,1216,4320,4328,1216,1856,1216,1856,1224,1224,1224,1224, + 1232,1232,1232,1232, 0, 0, 0, 0,1240,1240,1240,1240,1864,4336,1864, 0, + 912, 912, 912, 912, 912, 912,4344,4352,1440,1440,4360,1440,1448,1448,4368,1448, + 1872,1872,4376,4384, 0,4392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 552, 552, 552, 552, 552, 552, 552, 552,4400, 0, 0, 0, 0, 0, 0, + 360, 360, 360, 360, 360, 360,1880, 0, 360, 360, 360, 360, 360, 360,1880,4408, + 920, 920, 920, 920, 920, 0, 920,4416, 928, 928, 928, 928,1888,4424, 928, 928, + 1888,4432, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 56, 56,4440, + 1040,1040,1040,1040,1040,4448,4456, 0,1896, 0, 56,4464, 0, 0, 0,1896, + 1048,1048,1048,1048,1048, 0,1056,1056,1056,1056,1056,4472, 0, 0,1456,1456, + 1456,4480, 0, 0, 0, 0,1464,1464,1464,4488, 0, 0,1904,1904,4496, 0, + 368, 368, 368, 368, 368, 368, 368, 368, 368,1912,4504, 368, 368, 368,1912,4512, + 656, 656, 656, 656, 656, 656, 656, 656,4520,4528,1248,1248,1248,4536,1248,4544, + 664, 664, 664, 664, 664, 664,4552, 664, 664, 0,1256,1256,1256,1256,4560, 0, + 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336,4568, 808,4576, 0, + 720, 720,4584, 720, 720, 720, 720, 720,4592, 0, 0, 0, 0, 0, 0, 0, + 4600,4608,1920,4616,1920,4624, 672, 672, 672, 672, 672, 672, 672,4632, 672,4640, + 4648,1928,4656,1936,1936,4664,4672,4680,1928,4688,4696,4704,4712,1944,1944, 0, + 936,4720, 936, 936, 936, 936,1952, 936,4728,4736,1952,4744,4752, 0, 0, 0, + 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,4760,4768, 0, 0, 0, + 448, 448, 448, 448, 448, 448, 448, 448, 448, 0, 448,4776, 0, 0, 0, 0, + 456, 456, 456, 456, 456, 456,1960, 456, 456, 456, 456,1960, 0, 0, 0, 0, + 560, 560, 560, 560, 560, 560, 560, 560,4784, 0, 560,4792, 248,4800, 0, 0, + 680, 680, 680, 680, 680, 680, 680,1968, 680,1968, 200, 200,4808, 0, 0, 0, + 944, 944, 944,4816, 944,4824, 944, 944,4832, 0, 0, 0, 0, 0, 0, 0, + 728, 728, 728, 728, 728, 728, 728,4840, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 464, 464, 464, 464, 464, 464, 464, 464, 464, 464,4848,4856, + 1976,4864,4872,1264,1264,1264,4880,4888,1976, 0,1264,4896, 0, 0, 0, 0, + 0, 0, 0, 0, 952,1984, 952, 952, 952, 952, 952,1984,4904, 0, 0, 0, + 568, 568, 568, 568, 568, 568, 568, 568, 568, 0, 472, 472, 472, 472, 472, 472, + 472, 472, 472, 472,4912, 0, 80, 80, 736, 736, 736, 736, 736, 736, 736,4920, + 240,4928, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 336, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1064,1064,1064,1064,1992, 0,1064,1992, + 576,4936, 576, 576, 576, 576,4944, 576,4952, 0, 576, 576, 576,4960, 960, 960, + 960, 960,4968, 960, 960,4976,4984, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2000,4992, 968, 968, 968, 968,2000,5000, 968, 0, 968,5008,5016,5024,1272,1272, + 1272,5032,5040,5048,1272,5056, 976, 976, 976, 976, 976,5064, 976,5072, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1472,1472,1472,5080, + 584, 584,5088, 584, 584, 584, 584,5096, 584, 584, 584,5104, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,5112, 0, 504, 504, 504, 504, 504, 504,5120,5128, + 64, 64, 64,5136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,5144,5152, 0, + 64, 64, 64, 64, 64, 64, 64, 64,5160, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376,5168, 0, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,5176, 0, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,5184, + 112, 112, 112, 112, 112, 112, 112, 112,5192, 0, 0, 0, 0, 0, 0, 0, + 744, 744, 744, 744, 744, 744, 744,5200, 0, 0, 0, 0, 0, 0, 0, 0, + 88, 88, 88, 88, 88, 88, 88,5208,1280,1280,1280,5216,1280,5224, 480, 480, + 480, 480, 480, 480, 480, 480, 480,5232, 480,5240,1480,1480,1480,2008,2008, 0, + 344, 344, 344, 344, 344, 344, 344, 344,5248, 0, 344,2016,2016, 344, 344,5256, + 344, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 752, 752, 752, 752, 752, 752, 752,5264, + 0, 0, 0, 0, 0, 0, 0, 0, 392, 392, 392, 392, 392, 392, 392, 392, + 392, 392, 392,5272,1072,1072,1072,5280,1072,1072,5288, 0, 0, 0, 0, 0, + 264, 264, 264, 264, 264, 264, 264, 264, 264,5296, 264, 264, 264, 264, 264, 264, + 264,5304, 264, 264, 0, 0, 0, 0, 0, 0, 0, 0,5312, 0,5320, 0, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,5328, 0, 0, 0, 0,5336, + 32, 32, 32,5344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,5352, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5360,5368, + 5376, 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, 152, 152, 152, 152, 152, + 152, 152, 152, 152,5384, 0,5392, 0, 0, 0,5400, 0,5408, 0, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136,5416, + 288, 288, 288, 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,5424, 288,5432, + 288,5440, 288,5448, 328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 872, + 24, 24, 24, 24, 24, 24, 328,2024, 24, 24, 760, 0, 24, 24, 760, 0, + 104, 104, 104, 104, 104,1712, 104, 104,5456, 0, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 328, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 416, 0, + 24, 24, 24, 24, 608, 712, 24, 24, 24, 24, 24, 24,5464,5472, 24,5480, + 5488,5496, 24, 24, 24,5504, 24, 24, 24, 24, 24, 24, 24,1360, 0, 0, + 144, 144, 144, 144, 144, 144, 144, 144, 848, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 328, 0, 24, 24, 328, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 608, 0, 24, 24, 24, 760, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 992, 24, 24, 24, 24, 24, + 24, 24, 24, 992,5512,5520, 24,5528,5536, 24, 24, 24, 24, 24, 24, 24, + 5544,5552, 992, 992, 24, 24, 24,5560,5568,2024,5576, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 416, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24,1744, 24, 24, 24, 24, 24, 24, + 96,5584, 0,5592,5600, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48,1784,5608,1840, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5616, 312, 312,5624,5632,5640, 120, 120, 120, 120, 120, 120, 120,5648, 0, 0, + 0,5656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 768, 768, 768, 768, 768,5664, 768,5672, 768,5680, 0, 0, 0, 0, 0, 0, + 0, 0,1488,1488,1488,5688, 0, 0, 776, 776, 776, 776, 776, 776, 776,5696, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1080,1080,1080,1080,1080,5704, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1088,1088,1088,1088,1088,5712, + 0, 0, 0, 0, 0, 0, 0, 0,1096,1096,1096,5720,1096,1096,5728,5736, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280,5744, 160, 280, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208,5752, 208,5760, 0, 0, 0, 0, 0, + 488, 488, 488, 488, 488, 488, 488, 488, 488,5768, 488,5776, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 712, 24, + 24, 24, 24, 24, 24, 24, 872, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 712, 24, 24, 24, 24, 24, 24, 416, 0, 0, 0, 0, 0, 0, 0, 0, + 5784, 56, 56, 56,1496,5792,1504,5800,5808,5816,1496,5824,1496,1504,1504,5832, + 56,2032, 56,2040,5840,2032, 56,2040, 0, 0, 0, 0, 0, 0,5848, 0, + 24, 24, 24, 24, 24, 328, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 328, 0, 24, 608, 712, 24, 712, 24, 712, 24, 24, 24, 416, 0, + 24, 24, 24, 24, 24, 416, 0, 0, 0, 0, 0, 0,5856, 24, 24, 24, + 5864, 0, 24, 24, 24, 24, 24, 328, 24, 760, 616, 0, 416, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5872, 24, 872, 24, 872, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 616, 24, 328, 760, 0, + 24, 328, 24, 24, 24, 24, 24, 24, 24, 0, 24, 616, 24, 24, 24, 24, + 24, 0, 24, 24, 24, 416, 24, 328, 616, 0, 24, 760, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 24, 416, 24, 872, + 24,5880, 24, 24, 24, 24, 24, 24, 608,5888, 24,5896, 24,1808, 24, 760, + 24, 24,1792, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,1360, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, + 8, 8, 8, 856, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 856, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,5904, 0, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 856, 0, 0, 0, 0, + 8, 8, 8, 856, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8,5912, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,1776, + 5920, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 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, @@ -2690,15 +2686,15 @@ static const uint16_t _hb_ucd_u16[10832]= }; 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, + 0, 0, 0, 0, 1, -1, 1, -1, 1, -1, 0, 0, -1, 1, -1, 1, + 0, 0, 1, -1, -1, 1, -1, 0, 0, 0, 0, 1, 0, 1, -1, 0, + 0, 0, 0, 2, 0, -2, 0, 0, 0, 1, -1, 1, 2, 0, -2, 0, + -1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 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, + 1824, 0, 0, 0, 0, 0, 2104, 0, 2108, 2106, 0, 2106, 1316, 0, 0, 0, + -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, 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, @@ -2707,11 +2703,13 @@ static const int16_t _hb_ucd_i16[196]= static inline uint8_t _hb_ucd_gc (unsigned u) { - return u<1114110 ? _hb_ucd_u8[7920u+((_hb_ucd_u8[2176u+((_hb_ucd_u16[((_hb_ucd_u8[((((((u)>>1))>>3))>>5)])<<5)+((((((u)>>1))>>3))&31)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : 2; + /* packtab: [2^8,2^5,2^3,2^1] */ + return u<1114110u ? (uint8_t)(_hb_ucd_u8[7912u+((_hb_ucd_u8[2176u+_hb_ucd_u16[((_hb_ucd_u8[((((((u)>>1))>>3))>>5)])<<5)+((((((u)>>1))>>3))&31)]+((((u)>>1))&7)])<<1)+((u)&1)]) : 2; } static inline uint8_t _hb_ucd_ccc (unsigned u) { - return u<125259 ? _hb_ucd_u8[10388u+((_hb_ucd_u8[9284u+((_hb_ucd_u8[8548u+((_hb_ucd_u8[8302u+((((((u)>>2))>>3))>>4)])<<4)+((((((u)>>2))>>3))&15)])<<3)+((((u)>>2))&7)])<<2)+((u)&3)] : 0; + /* packtab: [2^8,2^4,2^3,2^2] */ + return u<125259u ? (uint8_t)(_hb_ucd_u8[10370u+((_hb_ucd_u8[9270u+((_hb_ucd_u8[8539u+((_hb_ucd_u8[8294u+((((((u)>>2))>>3))>>4)])<<4)+((((((u)>>2))>>3))&15)])<<3)+((((u)>>2))&7)])<<2)+((u)&3)]) : 0; } static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) { @@ -2719,15 +2717,18 @@ static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) } static inline int16_t _hb_ucd_bmg (unsigned u) { - return u<65380 ? _hb_ucd_i16[((_hb_ucd_u8[11140u+((_hb_ucd_u8[11020u+((_hb_ucd_b4(_hb_ucd_u8+10892u,((((((u)>>2))>>3))>>3)))<<3)+((((((u)>>2))>>3))&7)])<<3)+((((u)>>2))&7)])<<2)+((u)&3)] : 0; + /* packtab: [2^4,2^3,2^3,2^2] */ + return u<65380u ? (int16_t)(_hb_ucd_i16[_hb_ucd_u8[11118u+((_hb_ucd_u8[11002u+((_hb_ucd_b4(_hb_ucd_u8+10874u,((((((u)>>2))>>3))>>3)))<<3)+((((((u)>>2))>>3))&7)])<<3)+((((u)>>2))&7)]+((u)&3)]) : 0; } static inline uint8_t _hb_ucd_sc (unsigned u) { - return u<918000 ? _hb_ucd_u8[12662u+((_hb_ucd_u16[3328u+((_hb_ucd_u8[11926u+((_hb_ucd_u8[11476u+((((((u)>>3))>>4))>>4)])<<4)+((((((u)>>3))>>4))&15)])<<4)+((((u)>>3))&15)])<<3)+((u)&7)] : 2; + /* packtab: [2^8,2^4,2^4,2^3] */ + return u<918000u ? (uint8_t)(_hb_ucd_u8[12639u+_hb_ucd_u16[3296u+((_hb_ucd_u8[11903u+((_hb_ucd_u8[11454u+((((((u)>>3))>>4))>>4)])<<4)+((((((u)>>3))>>4))&15)])<<4)+((((u)>>3))&15)]+((u)&7)]) : 2; } static inline uint16_t _hb_ucd_dm (unsigned u) { - return u<195102 ? _hb_ucd_u16[7408u+((_hb_ucd_u8[18972u+((_hb_ucd_u8[18590u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)] : 0; + /* packtab: [2^8,2^5,2^4] */ + return u<195102u ? (uint16_t)(_hb_ucd_u16[7360u+((_hb_ucd_u8[18949u+((_hb_ucd_u8[18567u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)]) : 0; } @@ -2735,1624 +2736,1620 @@ static inline uint16_t _hb_ucd_dm (unsigned u) #include -static const uint8_t _hb_ucd_u8[14800]= +static const uint8_t _hb_ucd_u8[14763]= { - 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, 18, 19, 20, 21, 22, 23, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 24, 25, 26, 5, 27, 28, - 5, 29, 5, 30, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 31, 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, 32, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 33, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 17, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 33, 41, 42, 43, 44, 45, - 46, 47, 48, 39, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 49, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 50, 17, 17, 17, 51, 17, 52, 53, 54, 55, 56, 57, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 58, 59, 59, 59, 59, 59, 59, 59, 59, - 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, 17, 61, 62, 17, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 17, 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, - 17, 17, 17, 97, 98, 99,100,100,100,100,100,100,100,100,100,101, - 17, 17, 17, 17,102, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17,103, 17, 17,104,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,105,100,100,100,100,100,100, 17, 17,106,107,100,108,109,110, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,111,112,100,100, - 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,113, - 17,114,115,100,100,100,100,100,100,100,100,100,116,100,100,100, - 100,100,100,100,100,100,100,100,100,100,100,100,117, 39,118,119, - 120,121,122,123,124,125,126,127, 39, 39,128,100,100,100,100,129, - 130,131,132,100,133,134,135,136,137,138,100,100,139,140,141,100, - 142,143,144,145, 39, 39,146,147,148, 39,149,150,100,100,100,100, - 17, 17, 17, 17, 17, 17,151, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17,152, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,153, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,154, 17, 17,155,100, - 100,100,100,100,100,100,100,100, 17, 17,156,100,100,100,100,100, - 17, 17, 17,157, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17,158,100,100,100,100,100,100,100,100,100,100,100, - 159,160,100,100,100,100,100,100,100,100,100,100,100,100,100,100, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,161, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,162, - 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, 36, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 40, 40, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, - 39, 39, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40, - 42, 42, 42, 42, 42, 42, 42, 42, 32, 32, 41, 32, 43, 44, 16, 10, - 43, 43, 40, 45, 11, 46, 46, 11, 34, 11, 11, 11, 11, 11, 11, 11, - 11, 47, 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, 48, 34, 32, 34, 11, - 32, 49, 42, 42, 50, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, - 47, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 46, 51, 2, 2, 2, - 16, 16, 16, 16, 52, 53, 54, 55, 56, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 57, 58, 59, 42, 58, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 61, - 36, 62, 63, 43, 43, 43, 43, 43, 64, 64, 64, 8, 9, 65, 2, 66, - 42, 42, 42, 42, 42, 59, 67, 2, 68, 36, 36, 36, 36, 69, 42, 42, - 7, 7, 7, 7, 7, 2, 2, 36, 70, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 71, 42, 42, 42, 72, 49, 42, 42, 73, 74, 75, 42, 42, 36, - 7, 7, 7, 7, 7, 36, 76, 77, 2, 2, 2, 2, 2, 2, 2, 78, - 69, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 79, 61, 36, - 36, 36, 36, 42, 42, 42, 42, 42, 70, 43, 43, 43, 43, 43, 43, 43, - 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, - 42, 42, 39, 21, 2, 80, 56, 20, 36, 36, 36, 42, 42, 74, 42, 42, - 42, 42, 74, 42, 74, 42, 42, 43, 2, 2, 2, 2, 2, 2, 2, 63, - 36, 36, 36, 36, 69, 42, 43, 63, 36, 36, 36, 36, 36, 60, 43, 43, - 36, 36, 36, 36, 81, 36, 36, 36, 64, 43, 43, 56, 42, 42, 42, 42, - 36, 36, 36, 36, 82, 42, 42, 42, 42, 83, 42, 42, 42, 42, 42, 42, - 42, 84, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84, 70, 85, - 86, 42, 42, 42, 84, 85, 86, 85, 69, 42, 42, 42, 36, 36, 36, 36, - 36, 42, 2, 7, 7, 7, 7, 7, 87, 36, 36, 36, 36, 36, 36, 36, - 69, 85, 61, 36, 36, 36, 60, 61, 60, 61, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 60, 36, 36, 36, 60, 60, 43, 36, 36, 43, 70, 85, - 86, 42, 79, 88, 89, 88, 86, 60, 43, 43, 43, 88, 43, 43, 36, 61, - 36, 42, 43, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 55, 62, 79, - 56, 84, 61, 36, 36, 60, 43, 61, 60, 36, 61, 60, 36, 43, 79, 85, - 86, 79, 43, 56, 79, 56, 42, 43, 56, 43, 43, 43, 61, 36, 60, 60, - 43, 43, 43, 7, 7, 7, 7, 7, 42, 36, 69, 63, 43, 43, 43, 43, - 56, 84, 61, 36, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, - 60, 36, 61, 36, 36, 43, 70, 85, 86, 42, 42, 56, 84, 88, 86, 43, - 60, 43, 43, 43, 43, 43, 43, 43, 65, 43, 43, 43, 61, 42, 42, 42, - 56, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 43, 70, 86, - 86, 42, 79, 88, 89, 88, 86, 43, 43, 43, 56, 84, 43, 43, 36, 61, - 77, 27, 27, 27, 43, 43, 43, 43, 43, 70, 61, 36, 36, 60, 43, 36, - 60, 36, 36, 43, 61, 60, 60, 36, 43, 61, 60, 43, 36, 60, 43, 36, - 36, 36, 36, 36, 36, 43, 43, 85, 84, 89, 43, 85, 89, 85, 86, 43, - 60, 43, 43, 88, 43, 43, 43, 43, 27, 90, 66, 66, 55, 91, 43, 43, - 84, 85, 70, 36, 36, 36, 60, 36, 60, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 43, 70, 42, 84, 85, 89, 42, 79, 42, 42, 43, - 43, 43, 56, 79, 36, 60, 36, 43, 43, 43, 43, 92, 27, 27, 27, 90, - 69, 85, 71, 36, 36, 36, 60, 36, 36, 36, 61, 36, 36, 43, 70, 86, - 85, 85, 89, 84, 89, 85, 42, 43, 43, 43, 88, 89, 43, 43, 36, 60, - 61, 93, 43, 43, 43, 43, 43, 43, 42, 85, 36, 36, 36, 36, 60, 36, - 36, 36, 36, 36, 36, 69, 70, 85, 86, 42, 79, 85, 89, 85, 86, 76, - 43, 43, 36, 93, 27, 27, 27, 94, 27, 27, 27, 27, 90, 36, 36, 36, - 56, 85, 61, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, 36, 36, 36, - 36, 61, 36, 36, 36, 36, 61, 43, 36, 36, 36, 60, 43, 79, 43, 88, - 85, 42, 79, 79, 85, 85, 85, 85, 43, 85, 63, 43, 43, 43, 43, 43, - 61, 36, 36, 36, 36, 36, 36, 36, 69, 36, 42, 42, 42, 79, 43, 95, - 36, 36, 36, 74, 42, 42, 42, 59, 7, 7, 7, 7, 7, 2, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 61, 60, 60, 36, 36, 60, 36, 36, - 36, 36, 61, 61, 36, 36, 36, 36, 69, 36, 42, 42, 42, 42, 70, 43, - 36, 36, 60, 80, 42, 42, 42, 79, 7, 7, 7, 7, 7, 43, 36, 36, - 76, 66, 2, 2, 2, 2, 2, 2, 2, 96, 96, 66, 42, 66, 66, 66, - 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 49, 49, 49, 4, 4, 85, - 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 43, - 56, 42, 42, 42, 42, 42, 42, 84, 42, 42, 59, 42, 36, 36, 69, 42, - 42, 42, 42, 42, 56, 42, 42, 42, 42, 42, 42, 42, 42, 42, 79, 66, - 66, 66, 66, 75, 66, 66, 91, 66, 2, 2, 96, 66, 21, 63, 43, 43, - 36, 36, 36, 36, 36, 93, 86, 42, 84, 42, 42, 42, 86, 84, 86, 70, - 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 85, 42, 36, 36, 42, - 70, 85, 97, 93, 85, 85, 85, 36, 69, 42, 70, 36, 36, 36, 36, 36, - 36, 84, 86, 84, 85, 85, 86, 93, 7, 7, 7, 7, 7, 85, 86, 66, - 11, 11, 11, 47, 43, 43, 47, 43, 16, 16, 16, 16, 16, 52, 44, 16, - 36, 36, 36, 36, 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, - 60, 36, 36, 43, 36, 36, 36, 60, 60, 36, 36, 43, 36, 36, 36, 36, - 36, 36, 36, 60, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 56, 42, - 2, 2, 2, 2, 98, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, - 66, 66, 66, 66, 66, 43, 43, 43, 11, 11, 11, 43, 16, 16, 16, 43, - 100, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 76, 71, - 101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,102,103, 43, - 36, 36, 36, 36, 36, 62, 2,104,105, 36, 36, 36, 60, 43, 43, 43, - 36, 42, 84, 43, 43, 43, 43, 61, 36, 42,106, 63, 43, 43, 43, 43, - 36, 42, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 60, 36, - 60, 42, 43, 43, 43, 43, 43, 43, 36, 36, 42, 86, 42, 42, 42, 85, - 85, 85, 85, 84, 86, 42, 42, 42, 42, 42, 2, 87, 2, 65, 69, 43, - 7, 7, 7, 7, 7, 43, 43, 43, 27, 27, 27, 27, 27, 43, 43, 43, - 2, 2, 2,107, 2, 58, 42, 83, 36, 82, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 60, 43, 43, 43, 36, 36, 69, 70, 36, 36, 36, 36, - 36, 36, 36, 36, 69, 60, 43, 43, 36, 36, 36, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 60, 42, 84, 85, 86, 84, 85, 43, 43, - 85, 84, 85, 85, 86, 42, 43, 43, 91, 43, 2, 7, 7, 7, 7, 7, - 36, 36, 36, 36, 36, 36, 36, 43, 36, 36, 60, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 43, 43, 36, 36, 36, 36, 36, 43, 43, 43, - 7, 7, 7, 7, 7, 99, 43, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 36, 36, 36, 69, 84, 86, 43, 2, 36, 36, 93, 84, 42, 42, 42, 79, - 84, 84, 86, 42, 42, 42, 84, 85, 85, 86, 42, 42, 42, 42, 79, 56, - 2, 2, 2, 87, 2, 2, 2, 43, 42, 42, 42, 42, 42, 42, 42,108, - 42, 42, 42, 42, 42, 42, 42, 43, 42, 42, 42, 42, 42, 42, 43, 43, - 42, 42, 97, 36, 36, 36, 36, 36, 36, 36, 84, 42, 42, 84, 84, 85, - 85, 84, 97, 36, 36, 36, 60, 2, 96, 66, 66, 66, 66, 49, 42, 42, - 42, 42, 66, 66, 66, 66, 21, 2, 42, 97, 36, 36, 36, 36, 36, 36, - 93, 42, 42, 85, 42, 86, 42, 36, 36, 36, 36, 84, 42, 85, 86, 86, - 42, 85, 43, 43, 43, 43, 2, 2, 36, 36, 85, 85, 85, 85, 42, 42, - 42, 42, 85, 42, 43, 92, 2, 2, 7, 7, 7, 7, 7, 43, 61, 36, - 36, 36, 36, 36, 39, 39, 39, 2, 16, 16, 16, 16, 34,109, 43, 43, - 11, 11, 11, 11, 11, 46, 47, 11, 2, 2, 2, 2, 43, 43, 43, 43, - 42, 59, 42, 42, 42, 42, 42, 42, 84, 42, 42, 42, 70, 36, 69, 36, - 36, 36, 70, 93, 42, 60, 43, 43, 16, 16, 16, 16, 16, 16, 39, 39, - 39, 39, 39, 39, 39, 44, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, - 16, 16, 16, 16, 16,110, 39, 39, 32, 32, 32, 16, 16, 16, 16, 32, - 16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 43, 11, 11, 11, 43, - 16, 16, 16, 16, 47, 47, 47, 47, 16, 16, 16, 16, 16, 16, 16, 43, - 16, 16, 16, 16,111,111,111,111, 16, 16,109, 16, 11, 11,112,113, - 40, 16,109, 16, 11, 11,112, 40, 16, 16, 43, 16, 11, 11,114, 40, - 16, 16, 16, 16, 11, 11,115, 40, 43, 16,109, 16, 11, 11,112,116, - 117,117,117,117,117,118, 64, 64,119,119,119, 2,120,121,120,121, - 2, 2, 2, 2,122, 64, 64,123, 2, 2, 2, 2,124,125, 2,126, - 127, 2,128,129, 2, 2, 2, 2, 2, 9,127, 2, 2, 2, 2,130, - 64, 64,131, 64, 64, 64, 64, 64,132, 43, 27, 27, 27, 8,128,133, - 27, 27, 27, 27, 27, 8,128,103, 39, 39, 39, 39, 39, 39, 80, 43, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43, 43, - 42, 42, 42, 42, 42, 42,134, 50,108, 50,108, 42, 42, 42, 42, 42, - 79, 43, 43, 43, 43, 43, 43, 43, 66,135, 66,136, 66, 34, 11, 16, - 11, 32,136, 66, 48, 11, 11, 66, 66, 66,135,135,135, 11, 11,137, - 11, 11, 35, 36,138, 66, 16, 11, 8, 8, 48, 16, 16, 26, 66,139, - 27, 27, 27, 27, 27, 27, 27, 27,104,104,104,104,104,104,104,104, - 104,140,141,104,142, 66, 43, 43, 8, 8,143, 66, 66, 8, 66, 66, - 143, 26, 66,143, 66, 66, 66,143, 66, 66, 66, 66, 66, 66, 66, 8, - 66,143,143, 66, 66, 66, 66, 66, 66, 66, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 66, 66, 66, 66, 4, 4, 66, 66, - 8, 66, 66, 66,144,145, 66, 66, 66, 66, 66, 66, 66, 66,143, 66, - 66, 66, 66, 66, 66, 26, 8, 8, 8, 8, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 8, 8, 8, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 91, 43, 43, 27, 27, 27, 27, 27, 27, 66, 66, - 66, 66, 66, 66, 66, 27, 27, 27, 66, 66, 66, 26, 66, 66, 66, 66, - 26, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 8, 8, 8, 8, - 66, 66, 66, 66, 66, 66, 66, 26, 66, 66, 66, 66, 4, 4, 4, 4, - 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, - 8, 8,128,146, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, - 8,128,147,147,147,147,147,147,147,147,147,147,146, 8, 8, 8, - 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, - 8, 8,143, 26, 8, 8,143, 66, 66, 66, 43, 66, 66, 66, 66, 66, - 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 39, 11, - 32, 32,139, 66, 66,136, 34,148, 42, 32, 43, 43, 92, 2, 98, 2, - 16, 16, 16,149, 43, 43,149, 43, 36, 36, 36, 36, 43, 43, 43, 51, - 63, 43, 43, 43, 43, 43, 43, 56, 36, 36, 36, 60, 43, 43, 43, 43, - 36, 36, 36, 60, 36, 36, 36, 60, 2,120,120, 2,124,125,120, 2, - 2, 2, 2, 6, 2,107,120, 2,120, 4, 4, 4, 4, 2, 2, 87, - 2, 2, 2, 2, 2,119, 2, 2,107,150, 2, 2, 2, 2, 2, 2, - 66, 2,151,147,147,147,152, 43, 66, 66, 66, 66, 66, 54, 66, 66, - 66, 66, 43, 43, 43, 43, 43, 43, 66, 66, 66, 43, 43, 43, 43, 43, - 1, 2,153,154, 4, 4, 4, 4, 4, 66, 4, 4, 4, 4,155,156, - 157,104,104,104,104, 42, 42, 85,158, 39, 39, 66,104,159, 62, 66, - 36, 36, 36, 60, 56,160,161, 68, 36, 36, 36, 36, 36, 62, 39, 68, - 43, 43, 61, 36, 36, 36, 36, 36, 66, 27, 27, 66, 66, 66, 66, 66, - 66, 66, 66, 43, 43, 43, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, - 27, 27, 27, 27, 27, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, - 162, 27, 27, 27, 27, 27, 27, 27, 36, 36, 82, 36, 36, 36, 36, 36, - 66, 66, 66, 91, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,163, 2, - 7, 7, 7, 7, 7, 36, 43, 43, 32, 32, 32, 32, 32, 32, 32, 69, - 50,164, 42, 42, 42, 42, 42, 87, 32, 32, 32, 32, 32, 32, 39, 42, - 36, 36, 36,104,104,104,104,104, 42, 2, 2, 2, 43, 43, 43, 43, - 40, 40, 40,161, 39, 39, 39, 39, 40, 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, 41,165, 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, - 32, 32, 11, 11, 34, 34, 32, 32, 32, 32, 32, 32, 32, 32, 46, 43, - 51, 39,166, 35, 39, 35, 36, 36, 36, 70, 36, 70, 36, 69, 36, 36, - 36, 93, 86, 84, 66, 66, 79, 43, 27, 27, 27, 66,167, 43, 43, 43, - 36, 36, 2, 2, 43, 43, 43, 43, 85, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 85, 85, 85, 85, 85, 85, 85, 85, 42, 43, 43, 43, 43, 2, - 42, 36, 36, 36, 2, 71, 71, 69, 36, 36, 36, 42, 42, 42, 42, 2, - 36, 36, 36, 69, 42, 42, 42, 42, 42, 85, 43, 43, 43, 43, 43, 92, - 36, 69, 85, 42, 42, 85, 42, 85,106, 2, 2, 2, 2, 2, 2, 51, - 7, 7, 7, 7, 7, 43, 43, 2, 36, 36, 69, 68, 36, 36, 36, 36, - 7, 7, 7, 7, 7, 36, 36, 60, 36, 36, 36, 36, 69, 42, 42, 84, - 86, 84, 86, 79, 43, 43, 43, 43, 36, 69, 36, 36, 36, 36, 84, 43, - 7, 7, 7, 7, 7, 43, 2, 2, 68, 36, 36, 76, 66, 93, 84, 36, - 70, 42, 70, 69, 70, 36, 36, 42, 69, 60, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 61, 82, 2, 36, 36, 36, 36, 36, 93, 42, 85, - 2, 82,168, 79, 43, 43, 43, 43, 61, 36, 36, 60, 61, 36, 36, 60, - 61, 36, 36, 60, 43, 43, 43, 43, 16, 16, 16, 16, 16,113, 39, 39, - 16, 16, 16, 16,110, 40, 43, 43, 36, 93, 86, 85, 84,106, 86, 43, - 36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 43, 61, 36, 36, - 169,169,169,169,169,169,169,169,170,170,170,170,170,170,170,170, - 16, 16, 16,109, 43, 43, 43, 43, 43,149, 16, 16, 43, 43, 61, 70, - 36, 36, 36, 36,171, 36, 36, 36, 36, 36, 36, 60, 36, 36, 60, 60, - 36, 61, 60, 36, 36, 36, 36, 36, 36, 40, 40, 40, 40, 40, 40, 40, - 40, 22, 66, 66, 66, 66, 66, 66, 66, 77, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36,147, 66, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 66, 66, 66, 66, 36, 36, 36, 36, 36, 36,167, 66, - 2, 2, 2,151,129, 43, 43, 43, 6,172,173,147,147,147,147,147, - 147,147,129,151,129, 2,126,174, 2, 63, 2, 2,155,147,147,129, - 2,175, 8,176, 65, 2, 43, 43, 36, 36, 60, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 60, 78, 92, 2, 3, 2, 4, 5, 6, 2, - 16, 16, 16, 16, 16, 17, 18,128,129, 4, 2, 36, 36, 36, 36, 36, - 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 39, - 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 36, 36, 43, 36, 60, 43, - 20,177, 55,178, 26, 8,143, 91, 43, 43, 43, 43, 78, 64, 66, 43, - 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 60, 36, 61, - 2, 63, 43,179, 27, 27, 27, 27, 27, 27, 43, 54, 66, 66, 66, 66, - 104,104,142, 27, 90, 66, 66, 66, 66, 66, 66, 66, 66, 27, 66, 91, - 66, 66, 66, 66, 66, 66, 91, 43, 91, 43, 43, 43, 43, 43, 43, 43, - 66, 66, 66, 66, 66, 66, 49, 43,180, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 43, 43, 27, 27, 43, 43, 43, 43, 61, 36, - 154, 36, 36, 36, 36,181, 43, 43, 36, 36, 36, 42, 42, 79, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 92, 36, 36, 43, 43, 36, 36, 36, 36, - 182,104,104, 43, 43, 43, 43, 43, 11, 11, 11, 11, 16, 16, 16, 16, - 11, 11, 43, 43, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 43, 43, - 36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, 43, 92, - 11, 11, 11, 11, 11, 46, 11, 11, 11, 46, 11,149, 16, 16, 16, 16, - 16,149, 16, 16, 16, 16, 16, 16, 16,149, 16, 16, 16,149,109, 43, - 39, 39, 39, 51, 39, 39, 39, 39, 80, 39, 39, 39, 39, 80, 43, 43, - 36, 36, 36, 43, 60, 36, 36, 36, 36, 36, 36, 61, 60, 43, 60, 61, - 36, 36, 36, 92, 27, 27, 27, 27, 36, 36, 36, 76,162, 27, 27, 27, - 43, 43, 43,179, 27, 27, 27, 27, 36, 60, 36, 43, 43,179, 27, 27, - 36, 36, 36, 27, 27, 27, 43, 92, 36, 36, 36, 36, 36, 43, 43, 92, - 36, 36, 36, 36, 43, 43, 27, 36, 43, 27, 27, 27, 27, 27, 27, 27, - 69, 42, 56, 79, 43, 43, 42, 42, 36, 36, 61, 36, 61, 36, 36, 36, - 36, 36, 36, 43, 42, 79, 43, 56, 27, 27, 27, 27, 99, 43, 43, 43, - 2, 2, 2, 2, 63, 43, 43, 43, 36, 36, 36, 36, 36, 36,183, 30, - 36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 77, 36, 36, 36, - 36, 36, 69, 79, 43,179, 27, 27, 2, 2, 2, 63, 43, 43, 43, 43, - 36, 36, 36, 43, 92, 2, 2, 2, 36, 36, 36, 43, 27, 27, 27, 27, - 36, 60, 43, 43, 27, 27, 27, 27, 36, 43, 43, 43, 92, 2, 63, 43, - 43, 43, 43, 43,179, 27, 27, 27, 11, 46, 43, 43, 43, 43, 43, 43, - 16,109, 43, 43, 43, 27, 27, 27, 36, 36, 42, 42, 43, 43, 43, 43, - 7, 7, 7, 7, 7, 36, 36, 68, 11, 11, 11, 43, 56, 42, 42,158, - 16, 16, 16, 43, 43, 43, 43, 8, 27, 27, 27, 27, 27, 27, 27, 99, - 36, 36, 36, 36, 36, 56,184, 43, 36, 43, 43, 43, 43, 43, 43, 43, - 43, 36, 82, 36, 43, 43, 43, 43, 96, 66, 66, 66, 91, 43, 43, 43, - 43, 43, 43, 43, 43, 42, 42, 42, 27, 27, 27, 94, 43, 43, 43, 43, - 180, 27, 30, 2, 2, 43, 43, 43, 36, 42, 42, 2, 2, 43, 43, 43, - 36, 36,183, 27, 27, 27, 43, 43, 86, 97, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 42, 59, 2, 2, 2, 43, - 27, 27, 27, 7, 7, 7, 7, 7, 70, 69, 70, 43, 43, 43, 43, 56, - 85, 86, 42, 84, 86, 59,185, 2, 2, 79, 43, 43, 43, 43, 78, 43, - 42, 70, 36, 36, 36, 36, 36, 36, 36, 36, 36, 69, 42, 42, 86, 42, - 42, 42, 79, 7, 7, 7, 7, 7, 2, 2, 93, 97, 43, 43, 43, 43, - 36, 69, 2, 60, 43, 43, 43, 43, 36, 93, 85, 42, 42, 42, 42, 84, - 97, 36, 62, 2, 58, 42, 59, 86, 7, 7, 7, 7, 7, 62, 62, 2, - 179, 27, 27, 27, 27, 27, 27, 27, 27, 27, 99, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 85, 86, 42, 85, 84, 42, 2, 2, 2, 70, - 69, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 60, 60, 36, 36, 61, - 36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, 62, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 69, 85, 86, 42, 42, 42, 79, 43, 43, - 42, 85, 61, 36, 36, 36, 60, 61, 60, 36, 61, 36, 36, 56, 70, 85, - 84, 85, 89, 88, 89, 88, 85, 43, 60, 43, 43, 88, 43, 43, 61, 36, - 36, 85, 43, 42, 42, 42, 79, 43, 42, 42, 79, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 61, 43, 60, 36, 36, 36, 61, 85, 86, 42, 42, - 79, 89, 88, 88, 85, 89, 85, 84, 70, 70, 2, 92, 63, 43, 43, 43, - 56, 79, 43, 43, 43, 43, 43, 43, 36, 36, 93, 85, 42, 42, 42, 42, - 85, 42, 84, 70, 36, 62, 2, 2, 7, 7, 7, 7, 7, 2, 92, 70, - 85, 86, 42, 42, 84, 84, 85, 86, 84, 42, 36, 71, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 93, 85, 42, 42, 43, 85, 85, 42, 86, - 59, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 42, 43, - 85, 86, 42, 42, 42, 84, 86, 86, 59, 2, 60, 43, 43, 43, 43, 43, - 2, 2, 2, 2, 2, 2, 63, 43, 36, 36, 36, 36, 36, 69, 86, 85, - 42, 42, 42, 86, 62, 43, 43, 43, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 56, 86, - 85, 42, 42, 86, 42, 42, 43, 43, 7, 7, 7, 7, 7, 27, 2, 96, - 42, 42, 42, 42, 86, 59, 43, 43, 27, 99, 43, 43, 43, 43, 43, 61, - 36, 36, 36, 60, 61, 43, 36, 36, 36, 36, 61, 60, 36, 36, 36, 36, - 85, 85, 85, 88, 89, 56, 84, 70, 97, 86, 2, 63, 43, 43, 43, 43, - 36, 36, 36, 36, 43, 36, 36, 36, 93, 85, 42, 42, 43, 42, 85, 85, - 70, 71, 89, 43, 43, 43, 43, 43, 69, 42, 42, 42, 42, 70, 36, 36, - 36, 69, 42, 42, 84, 69, 42, 59, 2, 2, 2, 58, 43, 43, 43, 43, - 69, 42, 42, 84, 86, 42, 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, - 42, 42, 42, 84, 42, 2, 71, 2, 2, 63, 43, 43, 43, 43, 43, 43, - 2, 2, 2, 2, 2, 43, 43, 43, 84, 42, 84, 84, 43, 43, 43, 43, - 62, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 42, 42, 42, 86, - 62, 2, 2, 43, 43, 43, 43, 43, 2, 36, 36, 36, 36, 36, 36, 36, - 43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 88, 42, 42, 42, - 84, 42, 86, 79, 43, 43, 43, 43, 36, 36, 36, 60, 36, 61, 36, 36, - 69, 42, 42, 79, 43, 79, 42, 56, 42, 42, 42, 69, 43, 43, 43, 43, - 36, 36, 36, 61, 60, 36, 36, 36, 36, 36, 36, 36, 36, 85, 85, 89, - 42, 88, 86, 86, 60, 43, 43, 43, 36, 36, 36, 36, 82, 36, 43, 43, - 36, 69, 84,106, 63, 43, 43, 43, 42, 93, 36, 36, 36, 36, 36, 36, - 36, 36, 85, 42, 42, 79, 43, 85, 84, 59, 2, 2, 2, 2, 2, 2, - 7, 7, 7, 7, 7, 79, 43, 43, 27, 27, 90, 66, 66, 66, 55, 20, - 167, 66, 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 43, 43, 92, - 104,104,104,104,104,104,104,181, 2, 2, 63, 43, 43, 43, 43, 43, - 62, 63, 43, 43, 43, 43, 43, 43, 64, 64, 64, 64, 64, 64, 64, 64, - 70, 36, 36, 69, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 85, 86, 42, - 42, 42, 59, 43, 43, 43, 43, 43, 42, 42, 42, 59, 2, 2, 66, 66, - 39, 39, 96, 43, 43, 43, 43, 43, 7, 7, 7, 7, 7,179, 27, 27, - 27, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 61, 36, - 39, 68, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 82,163, 2, - 27, 27, 27, 30, 2, 63, 43, 43, 11, 11, 11, 11, 46,149, 16, 16, - 16, 16, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 60, 43, 56, - 93, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 43, 43, 43, 56, 42, 73, 39, 39, 39, 39, 39, 39, - 39, 87, 79, 43, 43, 43, 43, 43, 85, 39,104,181, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 61, 36, 60, 43, 43, 43, 43, 43, 43, - 39, 39, 51, 39, 39, 39, 51, 80, 43, 60, 43, 43, 43, 43, 43, 43, - 36, 60, 61, 43, 43, 43, 43, 43, 43, 43, 36, 36, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 43, 49, 59, 64, 64, 43, 43, 43, 43, 43, 43, - 7, 7, 7, 7, 7, 66, 91, 43, 66, 66, 43, 43, 43, 66, 66, 66, - 176, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 79, 43, 43, 43, 43, - 66, 66, 66, 91, 54, 66, 66, 66, 66, 66,186, 86, 42, 66,186, 85, - 85,187, 64, 64, 64, 83, 42, 42, 42, 75, 49, 42, 42, 42, 66, 66, - 66, 66, 66, 66, 66, 42, 42, 66, 66, 42, 75, 43, 43, 43, 43, 43, - 27, 27, 43, 43, 43, 43, 43, 43, 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,109, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 46, 11, 43, 46, 47, 46, 47, 11, 46, 11, - 11, 11, 11, 16, 16,149,149, 16, 16, 16,149, 16, 16, 16, 16, 16, - 16, 16, 11, 47, 11, 46, 47, 11, 11, 11, 46, 11, 11, 11, 46, 16, - 16, 16, 16, 16, 11, 47, 11, 46, 11, 11, 46, 46, 43, 11, 11, 11, - 46, 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, 43, 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, 43, 7, - 42, 42, 42, 75, 66, 49, 42, 42, 42, 42, 42, 42, 42, 42, 75, 66, - 66, 66, 49, 66, 66, 66, 66, 66, 66, 66, 75, 21, 2, 2, 43, 43, - 43, 43, 43, 43, 43, 56, 42, 42, 16, 16, 16, 16, 16,138, 16, 16, - 16, 16, 16, 16, 16, 16, 16,109, 43, 43,149, 16, 16,109, 43, 43, - 42, 42, 42, 79, 42, 42, 42, 42, 42, 42, 42, 42, 79, 56, 42, 42, - 42, 56, 79, 42, 42, 79, 43, 43, 39, 39, 39, 39, 39, 39, 39, 43, - 43, 43, 43, 43, 43, 43, 43, 56, 42, 42, 42, 73, 39, 39, 39, 43, - 7, 7, 7, 7, 7, 43, 43, 76, 36, 36, 36, 36, 36, 36, 36, 79, - 36, 36, 36, 36, 36, 36, 42, 42, 7, 7, 7, 7, 7, 43, 43, 95, - 36, 36, 36, 36, 36, 82, 42, 42,188, 7, 7, 7, 7,189, 43, 92, - 36, 69, 36, 70, 36, 36, 36, 42, 36, 36, 69, 43, 43, 43, 43, 82, - 36, 36, 36, 60, 36, 36, 61, 60, 36, 36, 60,179, 27, 27, 27, 27, - 16, 16, 42, 42, 42, 73, 43, 43, 27, 27, 27, 27, 27, 27,162, 27, - 190, 27, 99, 43, 43, 43, 43, 43, 27, 27, 27, 27, 27, 27, 27,162, - 27, 27, 27, 27, 27, 27, 27, 43, 36, 36, 61, 36, 36, 36, 36, 36, - 61, 60, 60, 61, 61, 36, 36, 36, 36, 60, 36, 36, 61, 61, 43, 43, - 43, 60, 43, 61, 61, 61, 61, 36, 61, 60, 60, 61, 61, 61, 61, 61, - 61, 60, 60, 61, 36, 60, 36, 36, 36, 60, 36, 36, 61, 36, 60, 60, - 36, 36, 36, 36, 36, 61, 36, 36, 61, 36, 61, 36, 36, 61, 36, 36, - 8, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 66, 43, 43, - 54, 66, 66, 66, 66, 66, 66, 66, 27, 27, 27, 27, 27, 27, 90, 66, - 66, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, 66, 66, 66, 66, 66, - 66, 91, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 91, 43, 43, 43, - 66, 43, 43, 43, 43, 43, 43, 43, 66, 66, 66, 66, 66, 25, 40, 40, - 66, 66, 66, 66, 91, 43, 66, 66, 66, 66, 66, 66, 43, 43, 43, 43, - 8, 8, 8, 8,176, 43, 43, 43, 66, 66, 66, 66, 66, 91, 43, 66, - 66, 66, 66, 91, 91, 43, 54, 66, 66, 66, 66, 66, 66, 66, 91, 54, - 66, 66, 66, 66, 66, 91, 43, 54, 66, 91, 66, 66, 66, 66, 66, 66, - 7, 7, 7, 7, 7, 91, 43, 43, 78, 43, 43, 43, 43, 43, 43, 43, - 170,170,170,170,170,170,170, 43,170,170,170,170,170,170,170, 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, 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, 21, 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, 24, 7, 7, 6, 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, 10, 21, 17, 21, 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, 1, 2, 15, 6, 18, 6, 12, 11, 9, 26, - 26, 9, 26, 5, 7, 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, 21, 22, - 18, 17, 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, 6, 9, 23, 26, - 6, 10, 4, 4, 3, 3, 7, 25, 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, 7, 13, 13, 2, 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, 34, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, - 0, 0, 0, 36, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, - 43, 44, 45, 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, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, - 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, - 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, - 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, - 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, - 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, - 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, - 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, - 74, 75, 0, 0, 0, 0, 76, 77, 0, 78, 79, 0, 0, 80, 81, 0, - 82, 62, 0, 83, 84, 0, 0, 85, 86, 87, 0, 88, 0, 89, 0, 90, - 0, 0, 51, 91, 51, 0, 92, 0, 93, 0, 0, 0, 81, 0, 0, 0, - 94, 95, 0, 96, 97, 98, 99, 0, 0, 0, 0, 0, 51, 0, 0, 0, - 0,100,101, 0, 0, 0, 0, 0, 0,102, 0, 0, 0, 0, 0, 0, - 103, 0, 0, 0, 0, 0, 0,104,105, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,106, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,108,109, 0, 0,110, 0, 0, 0, 0, 0, 0,111, 0,112, 0, - 105, 0, 0, 0, 0, 0,113,114, 0, 0, 0, 0, 0, 0, 0,115, - 0, 0, 0,116, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0,118, - 0,119, 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, 0, 0, - 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, - 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, - 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, - 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, - 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, - 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, - 0, 0, 57, 58, 0, 0, 0, 59, 60, 61, 62, 0, 0, 0, 0, 63, - 52, 0, 64, 65, 0, 0, 66, 0, 0, 0, 67, 68, 0, 0, 0, 69, - 0, 70, 71, 72, 73, 74, 1, 75, 0, 76, 77, 78, 0, 0, 79, 80, - 0, 0, 0, 81, 0, 0, 1, 1, 0, 0, 82, 0, 0, 83, 0, 0, - 0, 0, 79, 84, 0, 85, 0, 0, 0, 0, 0, 80, 86, 0, 87, 0, - 52, 0, 1, 80, 0, 0, 88, 0, 0, 89, 0, 0, 0, 0, 0, 90, - 57, 0, 0, 0, 0, 0, 0, 91, 92, 0, 0, 86, 0, 0, 33, 0, - 0, 93, 0, 0, 0, 0, 94, 0, 0, 0, 0, 49, 0, 0, 95, 0, - 0, 0, 0, 96, 97, 0, 0, 98, 0, 0, 99, 0, 0, 0,100, 0, - 0, 0,101, 0, 0, 0,102, 0, 0, 0, 0,103,104, 95, 0, 0, - 105, 0, 0, 0, 86, 0, 0,106, 0, 0, 0,107,108, 0, 0,109, - 110, 0, 0, 0, 0, 0, 0,111, 0, 0,112, 0, 0, 0, 0,113, - 33, 0,114,115,116, 57, 0, 0,117, 35, 0, 0,118, 0, 0, 0, - 119, 0, 0, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,122, - 90, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,123, 0, 0, 0, - 0,124, 0, 0,125, 0, 0, 0, 0,123, 0, 0,126, 0, 0, 0, - 0, 0, 81, 0, 0, 0, 0,127, 0, 0, 0,128, 0, 0, 0,129, - 0,130, 0, 0, 0, 0,131,132,133, 0,134, 0,135, 0, 0, 0, - 136,137,138, 0, 79, 0, 0, 0, 0, 0, 35, 0, 0, 0,139, 0, - 0, 0,140, 0, 0, 0,141, 0, 0, 0,142,143, 0,144, 0, 0, - 145, 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, - 0, 19, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, - 54, 21, 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, - 0, 0, 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, - 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, - 0, 0, 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, - 0, 77, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, - 0, 80, 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, - 0, 0, 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, - 1, 52, 15, 86, 36, 10, 21, 1, 1, 1, 1, 41, 1, 21, 87, 0, - 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, - 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 90, 9, 12, 4, - 91, 8, 92, 47, 0, 58, 50, 0, 21, 1, 21, 93, 94, 1, 1, 1, - 1, 95, 96, 97, 98, 1, 99, 58, 81,100,101, 4, 58, 0, 0, 0, - 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,102,103, - 0, 0,104, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0, - 0, 0, 0, 62, 0, 0,105, 68, 61, 0, 0, 0, 78, 0, 0, 0, - 106,107, 58, 38, 81, 0, 0, 0, 0, 0, 0,108, 1, 14, 4, 12, - 84, 0, 0, 0, 0, 38, 90, 0, 0, 0, 0,109, 0, 0,110, 61, - 0,111, 0, 0, 0, 1, 0, 0, 0, 0, 49, 50, 0, 0, 19, 58, - 0, 0,112, 51, 0,112, 14, 52,113, 41, 0, 0, 62, 0, 0, 61, - 0, 0,114, 0, 90, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, - 0,114, 0, 0, 0, 0,115, 0, 0, 0, 78, 55, 0, 38, 1, 58, - 1, 58, 0, 0, 0, 0, 0, 88, 63, 89, 0, 0,116, 0, 0, 0, - 55, 0, 0, 0, 0,116, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, - 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, 0, 0, - 8, 92, 0, 0, 1, 90, 0, 0,117, 0, 0, 0, 0, 0, 0,118, - 0,119,120,121,122, 0,105, 4,123, 49, 23, 0, 0, 0, 38, 50, - 38, 58, 0, 0, 1, 90, 1, 1, 1, 1, 39, 1, 48,106, 90, 0, - 0, 0, 0, 1, 0, 0, 0,124, 0, 0, 0,113, 19, 59, 0, 38, - 0, 81, 0, 0, 4,123, 0, 0, 0, 1,125, 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,230,220,220,220, - 230,230, 0,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, 9, 9, 0, 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,230,230,230,234, 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,218,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, - 0, 0, 0,220,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, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, - 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,232,232,220,230, - 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, 24, 3, 3, - 3, 3, 3, 3, 25, 3, 3, 3, 3, 3, 3, 3, 3, 26, 3, 3, - 27, 28, 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, 0, 56, 57, 0, 0, 0, 0, 0, 19, 58, 31, - 0, 0, 0, 0, 0, 0, 0, 59, 14, 0, 0, 0, 0, 1, 0, 2, - 0, 0, 0, 3, 0, 0, 0, 60, 61, 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, 0, 0, 8, 21, - 21, 21, 9, 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, 12, 13, - 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 13, 13, 13, - 24, 25, 26, 26, 26, 27, 13, 13, 13, 28, 29, 30, 13, 31, 32, 33, - 34, 35, 36, 37, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 38, 7, 7, 39, 7, 40, 7, 7, - 7, 41, 13, 42, 7, 7, 43, 7, 7, 7, 44, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 13, 13, 13, - 13, 13, 13, 13, 45, 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, 59, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 59, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 78, 69, 69, 69, 69, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80, - 81, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 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, 94, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 69, 69, 96, 97, 98, 99, 99, 99, - 100,101,102,103,104,105,106,107,108,109, 95,110,111,112,113,114, - 115,116,117,117,118,119,120,121,122,123,124,125,126,127,128,129, - 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145, - 95,146,147,148,149, 95,150,151,152,153,154,155,156,157,158,159, - 160,161, 95,162,163,164,165,165,165,165,165,165,165,166,167,165, - 168, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95,169,170,170,170,170,170,170,170,170,171,170, - 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, - 170,170,170,170,170,170,170,170,170,170,170,170,170,172,173,173, - 173,173,174, 95, 95, 95, 95, 95,175, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95,176,176,176,176,177,178,179,180, 95, 95, - 181, 95,182,183,184,185,186,186,186,186,186,186,186,186,186,186, - 186,186,186,186,186,186,186,186,186,186,186,186,187,187,187,188, - 189,190, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95,191,192,193,194,195,195,196, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,197,198, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 59,199, - 59, 59, 59,200,201,202, 59,203,204,205,206,207,208, 95,209,210, - 211, 59, 59,212, 59,213,214,214,214,214,214,215, 95, 95, 95, 95, - 95, 95, 95, 95,216, 95,217,218,219, 95, 95,220, 95, 95, 95,221, - 95,222, 95,223, 95,224,225,226,227, 95, 95, 95, 95, 95,228,229, - 230, 95,231,232, 95, 95,233,234, 59,235,236, 95, 59, 59, 59, 59, - 59, 59, 59,237, 59,238,239,240, 59, 59,241,242, 59,243, 95, 95, - 95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69,244, 69, 69,245, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69,246, 69, 69, 69, 69, 69, 69, 69, 69, 69,247, 69, 69, - 69, 69,248, 95, 95, 95, 69, 69, 69, 69,249, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 69, 69, 69, 69, 69, 69,250, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,251, 95, - 95, 95, 95, 95, 95, 95,252, 95,253,254, 0, 1, 2, 2, 0, 1, - 2, 2, 2, 3, 4, 5, 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, 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, 2, 9, 9, 9, 55, 55, 55, 55, - 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 2, 2, 2, 2, 14, 14, 2, 2, 2, 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, 37, 37, 2, 37, 37, 37, - 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 2, 2, 64, 64, - 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, - 2, 2, 90, 90, 90, 2, 95, 95, 95, 95, 2, 2, 95, 2, 3, 3, - 2, 2, 2, 2, 2, 3, 3, 3, 0, 3, 7, 7, 7, 7, 7, 1, - 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, - 5, 5, 5, 2, 2, 5, 5, 2, 5, 5, 5, 2, 5, 2, 2, 2, - 5, 5, 5, 5, 2, 2, 5, 5, 5, 2, 2, 2, 2, 5, 5, 5, - 2, 5, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, - 2, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11, - 2, 2, 2, 11, 2, 2, 11, 2, 11, 2, 2, 2, 11, 11, 2, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, - 2, 2, 10, 2, 2, 2, 2, 2, 10, 10, 2, 21, 21, 21, 21, 21, - 21, 21, 21, 2, 2, 21, 21, 2, 21, 21, 21, 21, 2, 2, 21, 21, - 2, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, - 22, 2, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, - 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 23, 23, 23, 23, 23, 2, - 23, 23, 23, 23, 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 2, - 23, 23, 2, 2, 2, 23, 16, 16, 16, 16, 16, 2, 16, 16, 2, 16, - 16, 16, 16, 16, 2, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, - 16, 16, 20, 20, 20, 20, 20, 2, 20, 20, 2, 2, 20, 20, 2, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, - 2, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 2, - 36, 2, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 2, 2, 2, 2, 0, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, - 18, 2, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, 2, 2, 18, 2, - 18, 2, 25, 25, 25, 25, 2, 25, 25, 25, 25, 2, 2, 2, 25, 2, - 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 33, 33, 33, 33, 8, 8, - 8, 8, 8, 8, 2, 8, 2, 8, 2, 2, 8, 8, 8, 0, 12, 12, - 12, 12, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, - 30, 2, 2, 30, 30, 30, 30, 2, 2, 2, 29, 29, 29, 29, 29, 29, - 2, 2, 28, 28, 28, 28, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35, - 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 45, 45, - 45, 45, 45, 45, 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 0, - 0, 2, 43, 43, 43, 43, 46, 46, 46, 46, 46, 2, 46, 46, 31, 31, - 31, 31, 31, 31, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, - 32, 32, 32, 32, 2, 2, 32, 2, 2, 2, 32, 32, 32, 2, 28, 28, - 2, 2, 48, 48, 48, 48, 48, 48, 48, 2, 48, 2, 2, 2, 52, 52, - 52, 52, 52, 52, 2, 2, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, - 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 2, 2, - 54, 54, 91, 91, 91, 91, 91, 91, 91, 2, 91, 2, 2, 91, 91, 91, - 2, 2, 1, 1, 2, 2, 62, 62, 62, 62, 62, 2, 62, 62, 76, 76, - 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, - 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 6, 6, 6, 2, 8, 8, - 8, 2, 2, 8, 8, 8, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, - 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 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, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, - 9, 9, 1, 1, 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, - 0, 19, 0, 0, 0, 2, 19, 2, 2, 2, 0, 0, 2, 2, 1, 2, - 2, 2, 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, 2, 2, - 0, 0, 56, 56, 56, 56, 2, 55, 55, 55, 61, 61, 61, 61, 2, 2, - 2, 61, 61, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, - 2, 2, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, - 12, 12, 2, 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, 0, 2, 26, 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, - 12, 2, 12, 12, 12, 0, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39, - 39, 2, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79, 2, 19, - 19, 19, 60, 60, 60, 60, 60, 2, 2, 2, 65, 65, 65, 65, 75, 75, - 75, 75, 75, 75, 2, 2, 2, 2, 75, 75, 69, 69, 69, 69, 69, 69, - 0, 69, 74, 74, 74, 74, 2, 2, 2, 74, 12, 2, 2, 2, 84, 84, - 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33, - 33, 2, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, 2, 2, 92, 92, - 92, 92, 92, 92, 92, 2, 2, 2, 2, 92, 87, 87, 87, 87, 87, 87, - 87, 2, 19, 9, 19, 19, 19, 19, 0, 0, 87, 87, 2, 2, 2, 2, - 2, 12, 19, 19, 19, 2, 2, 2, 2, 4, 14, 2, 14, 2, 14, 14, - 2, 14, 14, 2, 14, 14, 3, 3, 0, 0, 1, 1, 6, 6, 3, 2, - 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 17, 17, 17, 17, - 0, 0, 2, 2, 12, 12, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49, - 49, 2, 49, 49, 2, 49, 49, 49, 2, 2, 0, 2, 2, 2, 9, 2, - 2, 2, 0, 1, 2, 2, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, - 67, 67, 67, 2, 2, 2, 42, 42, 42, 42, 2, 42, 42, 42, 41, 41, - 41, 41, 41, 41, 41, 2,118,118,118,118,118,118,118, 2, 53, 53, - 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 2, 2, 40, 40, - 40, 40, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 2, 2,135,135, - 135,135,106,106,106,106,104,104,104,104, 2, 2, 2,104,161,161, - 161,161,161,161,161, 2,161,161, 2,161,161, 2, 2, 2,170,170, - 170,170,110,110,110,110,110,110,110, 2,110,110, 2, 2, 19, 19, - 2, 19, 19, 2, 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, - 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81, - 81, 81, 81, 81, 2, 81,120,120,120,120,116,116,116,116,116,116, - 116, 2, 2, 2, 2,116,128,128,128,128,128,128,128, 2,128,128, - 2, 2, 2, 2, 2,128, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, - 72, 72, 72, 72, 2, 2, 2, 2, 2, 72,173,173,173,173,173,173, - 2, 2, 98, 98, 98, 98, 97, 97, 97, 97, 2, 2, 97, 97, 57, 57, - 57, 57, 2, 57, 57, 2, 2, 57, 57, 57, 57, 57, 2, 2, 57, 57, - 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 88, 88, 88, 88,117,117, - 117,117,112,112,112,112,112,112,112, 2, 2, 2, 2,112, 78, 78, - 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 83, 83, 83, 83, 83, 83, - 2, 2, 82, 82, 82, 82, 82, 82, 82, 2,122,122,122,122,122,122, - 2, 2, 2,122,122,122,122, 2, 2, 2, 89, 89, 89, 89, 89, 2, - 2, 2,130,130,130,130,130,130,130, 2, 2, 2,130,130,144,144, - 144,144,144,144, 2, 2,165,165,165,165,165,165, 2, 2, 2,165, - 165,165, 2, 2,165,165, 3, 3, 3, 2,156,156,156,156,156,156, - 2,156,156,156, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2,147,147, - 147,147,148,148,148,148,148,148, 2, 2,158,158,158,158,158,158, - 2, 2,153,153,153,153,149,149,149,149,149,149,149, 2, 94, 94, - 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 2, 2, 2, 94, 85, 85, - 85, 85, 85, 85, 85, 2, 2, 85, 2, 2,101,101,101,101,101, 2, - 2, 2,101,101, 2, 2, 96, 96, 96, 96, 96, 2, 96, 96,111,111, - 111,111,111,111,111, 2,100,100,100,100,108,108,108,108,108,108, - 2,108,108,108, 2, 2,129,129,129,129,129,129,129, 2,129, 2, - 129,129,129,129, 2,129,129,129, 2, 2,109,109,109,109,109,109, - 109, 2,109,109, 2, 2,107,107,107,107, 2,107,107,107,107, 2, - 2,107,107, 2,107,107,107,107, 2, 1,107,107, 2, 2,107, 2, - 2, 2, 2, 2, 2,107, 2, 2,107,107,171,171,171,171,171,171, - 2,171, 2, 2,171, 2,171, 2,171, 2, 2,171, 2,171,171,171, - 171, 2,171, 2, 2, 2, 2,171,171, 2,137,137,137,137, 2,137, - 137,137,137,137, 2, 2,124,124,124,124,124,124, 2, 2,123,123, - 123,123,123,123, 2, 2,114,114,114,114,114, 2, 2, 2,114,114, - 2, 2,102,102,102,102,102,102, 2, 2,126,126,126,126,126,126, - 126, 2, 2,126,126,126,142,142,142,142,125,125,125,125,125,125, - 125, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154, - 2, 2, 2,154,154, 2,154,154, 2,154,154, 2, 2,154,154,154, - 2, 2,150,150,150,150, 2, 2,150,150,150, 2, 2, 2,141,141, - 141,141,140,140,140,140,140,140,140, 2,121,121,121,121,121, 2, - 2, 2, 7, 7, 2, 2,169,169,169,169,169,169, 2, 2,133,133, - 133,133,133, 2,133,133,133,133,133, 2,133,133, 2, 2,133, 2, - 2, 2,134,134,134,134, 2, 2,134,134, 2,134,134,134,134,134, - 134, 2,138,138,138,138,138,138,138, 2,138,138, 2,138, 2, 2, - 138, 2,138,138, 2, 2,143,143,143,143,143,143, 2,143,143, 2, - 143,143,143,143,143, 2,143, 2, 2, 2,143,143, 2, 2,175,175, - 175,175,175,175, 2, 2,145,145,145,145,145, 2, 2, 2,163,163, - 163,163,163, 2,163,163,163,163,163, 2, 2, 2,163,163, 86, 2, - 2, 2, 63, 63, 63, 63, 63, 63, 2, 2, 63, 63, 63, 2, 63, 2, - 2, 2,157,157,157,157,157,157,157, 2, 80, 80, 80, 80, 80, 80, - 2, 2, 80, 80, 80, 2,127,127,127,127,127,127,127, 2,166,166, - 166,166,166,166, 2, 2, 79, 2, 2, 2,115,115,115,115,115,115, - 115, 2,115,115, 2, 2, 2, 2,115,115,159,159,159,159,159,159, - 159, 2,159,159, 2, 2,103,103,103,103,103,103, 2, 2,119,119, - 119,119,119,119, 2, 2,119,119, 2,119, 2,119,119,119,167,167, - 167,167,167,167, 2, 2,146,146,146,146,146,146,146, 2,172,172, - 172,172,172, 2, 2,172, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, - 2, 99,136,139, 13, 13,155, 2, 2, 2, 13, 13, 13, 2,136,136, - 136,136,155,155,155,155,155,155, 2, 2, 2, 2, 2,155,136,136, - 136, 2, 2, 17, 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 17, 17, - 17, 2, 2, 2, 15, 2, 2, 17, 2, 2,139,139,139,139,105,105, - 105,105,105,105,105, 2,105, 2, 2, 2,105,105, 2, 2, 1, 1, - 1, 2, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 2, 2, - 0, 2, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 2,131,131, - 131,131, 2, 2, 2,131, 2,131,131,131, 56, 56, 56, 2, 56, 2, - 2, 56, 56, 56, 2, 56, 56, 2, 56, 56, 6, 6, 2, 2, 2, 2, - 2, 6,151,151,151,151,151, 2, 2, 2,151,151, 2, 2, 2, 2, - 151,151,160,160,160,160,160,160,160, 2,152,152,152,152,152,152, - 2, 2, 2, 2, 2,152,164,164,164,164,164,164, 2, 2,168,168, - 168,168,168,168,168, 2, 2, 2, 2,168,174,174,174,174,174,174, - 174, 2,174,174, 2, 2, 2, 2,174,174, 2, 30, 30, 2,113,113, - 113,113,113, 2, 2,113,113,113,113, 2,132,132,132,132,132,132, - 2, 2, 2, 2,132,132, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, - 2, 3, 2, 3, 2, 3, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, - 2, 3, 15, 0, 0, 2, 0, 2, 2, 0, 13, 2, 2, 2, 2, 0, - 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, 18, 9, 9, 9, 9, 9, 19, 20, 21, 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, 23, 9, 9, 9, 9, 9, 24, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 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, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 26, 27, - 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, + 3, 4, 5, 6, 7, 2, 2, 2, 2, 2, 8, 2, 2, 9, 1, 10, + 11, 12, 13, 14, 15, 0, 16, 2, 17, 0, 18, 19, 20, 21, 22, 23, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 24, 25, 26, 2, 27, 28, + 2, 29, 2, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 2, 23, 24, 25, 2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 5, 38, 39, 40, 41, 42, 3, 43, 5, 44, 45, 46, 47, 48, + 49, 50, 51, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 52, 2, 2, + 53, 2, 2, 2, 54, 2, 55, 56, 57, 58, 59, 60, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 61, 4, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 62, 63, 2, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 2, 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, + 2, 2, 2, 98, 99,100, 0, 0, 0, 0, 0, 0, 0, 0, 0,101, + 2, 2, 2, 2,102, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2,103, 2, 2,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,105, 0, 0, 0, 0, 0, 0, 2, 2,106,107, 0,108,109,110, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,111,112, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,113, + 2,114,115, 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,117, 3,118,119, + 120,121,122,123,124,125,126,127, 3, 3,128, 0, 0, 0, 0,129, + 130,131,132, 0,133,134,135,136,137,138, 0, 0,139,140,141, 0, + 142,143,144,145, 3, 3,146,147,148, 3,149,150, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2,151, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2,152, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,153, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,154, 2, 2,155, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,156, 0, 0, 0, 0, 0, + 2, 2, 2,157, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2,158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 159,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,161, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, + 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, + 11, 11, 11, 11, 11, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, + 13, 13, 13, 13, 13, 13, 13, 13, 16, 16, 16, 16, 16, 16, 16, 16, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 14, + 1, 1, 1, 1, 14, 1, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, + 1, 5, 0, 11, 11, 11, 11, 11, 1, 1, 1, 1, 1, 1, 14, 0, + 1, 1, 1, 1, 14, 0, 0, 0, 6, 6, 6, 6, 7, 7, 7, 7, + 1, 1, 1, 1, 1, 14, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 14, 0, 0, 0, 0, + 1, 1, 1, 14, 1, 1, 1, 14, 3, 3, 3, 3, 3, 3, 0, 0, + 28, 28, 28, 28, 28, 28, 28, 28, 11, 11, 11, 11, 11, 1, 1, 1, + 14, 17, 1, 1, 1, 1, 1, 1, 14, 0, 0, 0, 0, 0, 0, 0, + 14, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 0, 0, 0, + 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 29, 0, + 11, 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 6, 6, 6, + 0, 0, 0, 11, 11, 11, 11, 11, 17, 1, 1, 1, 1, 1, 1, 1, + 11, 11, 11, 11, 11, 10, 10, 10, 1, 1, 1, 0, 0, 0, 0, 0, + 5, 46, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 41, 41, 41, 41, + 3, 3, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 0, 0, 12, + 1, 1, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, + 49, 10, 10, 10, 10, 10, 10, 10, 7, 6, 6, 6, 6, 6, 6, 6, + 44, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, + 3, 3, 3, 3, 0, 0, 0, 0, 11, 11, 11, 11, 11, 12, 9, 77, + 88, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,102,103,104, + 89, 6, 6, 6, 6, 6, 6, 6, 22, 22, 22, 22, 22, 22, 22, 22, + 26, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 5, 5, 5, 5, 5, + 5, 20, 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, + 11, 11, 11, 11, 11, 12, 12, 12, 1, 1, 1, 1, 14, 1, 1, 0, + 14, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 14, 1, 1, 1, 1, + 10, 10, 10, 10, 10, 10, 51, 0,115, 1, 1, 1, 1, 1, 1, 1, + 5, 5, 5, 5, 5, 5, 5, 0, 1, 1, 1, 1, 13, 13, 13, 12, + 6, 6, 6, 0, 7, 7, 7, 0, 30, 30, 30, 30, 30, 30, 30, 30, + 3, 3, 3, 3, 3, 29, 0, 0, 3, 3, 3, 3, 3, 3, 3, 29, + 10, 10, 10, 10, 10, 3, 3, 3, 75, 10, 10, 10, 10, 10, 10, 10, + 3, 3, 3, 29, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 32, 7, 7, 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 51, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 10, + 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 15, 19, + 1, 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 5, + 15, 15, 15, 15, 15, 15, 15, 15, 1, 14, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 23, 0, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, + 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 3, 3, 3, 3, 29, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 87, 12,100, 12, 27,101, 76, 12, 6, 6, 6, 6, 6,105,106,135, + 87, 30, 30, 66,107,136,137,108, 50, 10, 89, 12,138,139, 10, 78, + 7, 7, 7, 59, 7, 7, 7, 8, 6, 6, 6, 60, 6, 6, 6, 6, + 8, 8, 8, 8, 21, 21, 21, 21, 21, 21, 21, 21, 6, 8, 8, 8, + 8, 8, 8, 8, 7, 21, 21, 6, 21, 8, 8, 7, 21, 7, 6, 7, + 7, 21, 8, 7, 8, 6, 7, 21, 8, 8, 8, 7, 21, 6, 8, 7, + 21, 7, 21, 21, 8, 67, 8, 6, 1, 1,109, 21,110,109, 21, 21, + 21, 21, 21, 21, 21, 21, 6, 8, 21,110, 8, 7, 8, 8, 8, 8, + 8, 8, 6, 6, 6, 7, 21, 8, 21, 21, 7, 8, 8, 8, 8, 8, + 6, 6, 1, 6, 6, 6, 6, 6, 13, 22, 22, 13, 13, 13, 13, 13, + 13, 22, 22, 22, 22, 22, 22, 22, 13, 13, 68, 22, 22, 22, 68, 68, + 8, 8, 68, 8, 0, 69, 6, 88, 0, 0, 22,140, 7, 32, 32, 7, + 21, 7, 7, 7, 7, 7, 7, 7, 7, 39, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 21, 6, 7, 8, 6, 8, 8, 8, 8, + 6, 6, 8, 90, 21, 8, 21, 7, 8, 43, 5, 5, 79, 8, 8, 8, + 7, 21, 21, 21, 21, 21, 21, 6, 39, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 32, 54, 12, 12, 12, 6, 6, 6, 6,111,141, 44, 70, + 5, 5, 5, 5, 5, 5, 5,142, 71, 36, 5, 71, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 14, 0, 17, 1, 40, 33, 0, 0, 0, 0, 0, + 18, 18, 18, 9, 77, 80, 12, 3, 5, 5, 5, 5, 5, 36,143, 12, + 52, 1, 1, 1, 1, 24, 5, 5, 11, 11, 11, 11, 11, 12, 12, 1, + 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 53, 5, 5, 5,144, 43, + 5, 5, 81, 72, 55, 5, 5, 1, 11, 11, 11, 11, 11, 1, 56, 82, + 12, 12, 12, 12, 12, 12, 12, 73, 24, 1, 1, 1, 1, 1, 1, 1, + 5, 5, 5, 5, 5, 23, 17, 1, 25, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 24, 5, 5, 5, 5, 13, 66, 12, 61, 26, 30, + 1, 1, 1, 5, 5, 72, 5, 5, 5, 5, 72, 5, 72, 5, 5, 0, + 12, 12, 12, 12, 12, 12, 12, 33, 1, 1, 1, 1, 24, 5, 0, 33, + 1, 1, 1, 1,145, 1, 1, 1, 18, 0, 0, 26, 5, 5, 5, 5, + 1, 1, 1, 1, 45, 5, 5, 5, 5, 91, 5, 5, 5, 5, 5, 5, + 1, 1, 1, 1, 1, 20, 25, 15, 19, 5, 5, 5, 20, 15, 19, 15, + 24, 5, 5, 5, 1, 1, 1, 1, 1, 5, 12, 11, 11, 11, 11, 11, + 62, 1, 1, 1, 1, 1, 1, 1, 24, 15, 17, 1, 1, 1, 14, 17, + 14, 14, 0, 1, 1, 0, 25, 15, 19, 5, 23, 35, 37, 35, 19, 14, + 0, 0, 0, 35, 0, 0, 1, 17, 1, 30, 10, 10, 10, 70, 40, 23, + 26, 20, 17, 1, 1, 14, 0, 17, 14, 1, 17, 14, 1, 0, 23, 15, + 19, 23, 0, 26, 23, 26, 5, 0, 26, 0, 0, 0, 17, 1, 14, 14, + 5, 1, 24, 33, 0, 0, 0, 0, 26, 20, 17, 1, 1, 1, 1, 17, + 14, 1, 17, 1, 1, 0, 25, 15, 19, 5, 5, 26, 20, 35, 19, 0, + 80, 0, 0, 0, 17, 5, 5, 5, 26, 15, 17, 1, 1, 1, 14, 17, + 14, 1, 17, 1, 1, 0, 25, 19, 19, 5, 23, 35, 37, 35, 19, 0, + 0, 0, 26, 20, 0, 0, 1, 17, 82, 10, 10, 10, 0, 0, 0, 0, + 0, 25, 17, 1, 1, 14, 0, 1, 14, 1, 1, 0, 17, 14, 14, 1, + 0, 17, 14, 0, 1, 14, 0, 1, 1, 1, 1, 1, 1, 0, 0, 15, + 20, 37, 0, 15, 37, 15, 19, 0, 14, 0, 0, 35, 0, 0, 0, 0, + 10, 63, 3, 3, 70, 29, 0, 0, 20, 15, 25, 1, 1, 1, 14, 1, + 1, 1, 1, 1, 1, 0, 25, 5, 20, 15, 37, 5, 23, 5, 5, 0, + 0, 0, 26, 23, 1, 14, 1, 0, 0, 0, 0, 38, 10, 10, 10, 63, + 24, 15, 53, 1, 1, 1, 14, 1, 1, 1, 17, 1, 1, 0, 25, 19, + 15, 15, 37, 20, 37, 15, 5, 0, 0, 0, 35, 37, 0, 0, 1, 14, + 17, 34, 0, 0, 0, 0, 0, 0, 5, 15, 1, 1, 1, 1, 14, 1, + 1, 1, 1, 1, 1, 24, 25, 15, 19, 5, 23, 15, 37, 15, 19, 56, + 0, 0, 1, 34, 10, 10, 10,112, 10, 10, 10, 10, 63, 1, 1, 1, + 26, 15, 17, 1, 1, 1, 1, 1, 1, 1, 1, 14, 0, 1, 1, 1, + 1, 17, 1, 1, 1, 1, 17, 0, 1, 1, 1, 14, 0, 23, 0, 35, + 15, 5, 23, 23, 15, 15, 15, 15, 0, 15, 33, 0, 0, 0, 0, 0, + 24, 1, 5, 5, 5, 23, 0,113, 1, 1, 1, 72, 5, 5, 5, 36, + 11, 11, 11, 11, 11, 12, 0, 0, 17, 14, 14, 1, 1, 14, 1, 1, + 1, 1, 17, 17, 1, 1, 1, 1, 24, 1, 5, 5, 5, 5, 25, 0, + 1, 1, 14, 61, 5, 5, 5, 23, 11, 11, 11, 11, 11, 0, 1, 1, + 56, 3, 12, 12, 12, 12, 12, 12, 12, 57, 57, 3, 5, 3, 3, 3, + 10, 10, 43, 43, 43, 27, 27, 15, 1, 1, 1, 1, 17, 1, 1, 1, + 26, 5, 5, 5, 5, 5, 5, 20, 5, 5, 36, 5, 1, 1, 24, 5, + 5, 5, 5, 5, 26, 5, 5, 5, 5, 5, 5, 5, 5, 5, 23, 3, + 3, 3, 3, 55, 3, 3, 29, 3, 12, 12, 57, 3, 66, 33, 0, 0, + 1, 1, 1, 1, 1, 34, 19, 5, 20, 5, 5, 5, 19, 20, 19, 25, + 1, 1, 1, 15, 5, 1, 1, 5, 25, 15, 46, 34, 15, 15, 15, 1, + 24, 5, 25, 1, 1, 1, 1, 1, 1, 20, 19, 20, 15, 15, 19, 34, + 11, 11, 11, 11, 11, 15, 19, 3, 7, 7, 7, 39, 0, 0, 39, 0, + 6, 6, 6, 6, 6,111, 69, 6, 1, 1, 1, 14, 14, 1, 1, 0, + 14, 1, 1, 0, 1, 1, 1, 14, 1, 1, 1, 1, 1, 14, 26, 5, + 12, 12, 12, 12,114, 10, 10, 10, 7, 7, 7, 0, 6, 6, 6, 0, + 1, 1, 1, 1, 1, 1, 56, 53,146, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1,147,116, 0, 1, 1, 1, 1, 1, 40, 12, 16, + 148, 1, 1, 1, 14, 0, 0, 0, 1, 5, 20, 0, 0, 0, 0, 17, + 1, 5, 83, 33, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 14, 1, 14, 5, 0, 0, 0, 0, 0, 0, + 1, 1, 5, 19, 5, 5, 5, 15, 15, 15, 15, 20, 19, 5, 5, 5, + 5, 5, 12, 62, 12, 80, 24, 0, 10, 10, 10, 10, 10, 0, 0, 0, + 12, 12, 12, 92, 12, 71, 5, 91, 1, 45, 1, 1, 1, 1, 1, 1, + 1, 1, 24, 25, 1, 1, 1, 1, 1, 1, 1, 1, 24, 14, 0, 0, + 5, 20, 15, 19, 20, 15, 0, 0, 15, 20, 15, 15, 19, 5, 0, 0, + 29, 0, 12, 11, 11, 11, 11, 11, 1, 1, 14, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 51, 0, 3, 1, 1, 1, 24, 20, 19, 0, 12, + 1, 1, 34, 20, 5, 5, 5, 23, 20, 20, 19, 5, 5, 5, 20, 15, + 15, 19, 5, 5, 5, 5, 23, 26, 12, 12, 12, 62, 12, 12, 12, 0, + 5, 5, 5, 5, 5, 5, 5, 93, 5, 5, 5, 5, 5, 5, 0, 0, + 5, 5, 46, 1, 1, 1, 1, 1, 1, 1, 20, 5, 5, 20, 20, 15, + 15, 20, 46, 1, 1, 1, 14, 12, 57, 3, 3, 3, 3, 43, 5, 5, + 5, 5, 3, 3, 3, 3, 66, 12, 34, 5, 5, 15, 5, 19, 5, 1, + 1, 1, 1, 20, 5, 15, 19, 19, 5, 15, 0, 0, 0, 0, 12, 12, + 1, 1, 15, 15, 15, 15, 5, 5, 5, 5, 15, 5, 0, 38, 12, 12, + 11, 11, 11, 11, 11, 0, 17, 1, 6, 6, 6, 6, 21, 47, 0, 0, + 7, 7, 7, 7, 7, 32, 39, 7, 12, 12, 12, 12, 0, 0, 0, 0, + 5, 36, 5, 5, 5, 5, 5, 5, 20, 5, 5, 5, 25, 1, 24, 1, + 1, 1, 25, 34, 5, 14, 0, 0, 6, 6, 6, 6, 6, 6, 13, 13, + 13, 13, 13, 13, 13, 69, 6, 6, 6, 6, 6, 6, 69, 6, 6, 6, + 6, 6, 6, 6, 6,117, 13, 13, 8, 8, 8, 6, 6, 6, 6, 8, + 6, 6, 6, 6, 39, 39, 39, 39, 6, 6, 6, 6, 6, 6, 6, 0, + 6, 6, 47, 6, 7, 7, 94,118, 22, 6, 47, 6, 7, 7, 94, 22, + 6, 6, 0, 6, 7, 7,149, 22, 6, 6, 6, 6, 7, 7,150, 22, + 0, 6, 47, 6, 7, 7, 94,151, 74, 74, 74, 74, 74,152, 18, 18, + 84, 84, 84, 12, 58,119, 58,119, 12, 12, 12, 12,153, 18, 18,154, + 12, 12, 12, 12,120,121, 12,122,123, 12, 64, 65, 12, 12, 12, 12, + 12, 77,123, 12, 12, 12, 12,155, 18, 18,156, 18, 18, 18, 18, 18, + 157, 0, 10, 10, 10, 9, 64,158, 10, 10, 10, 10, 10, 9, 64,116, + 13, 13, 13, 13, 13, 13, 61, 0, 30, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5,159, 79, 93, 79, 93, 5, 5, 5, 5, 5, + 23, 0, 0, 0, 0, 0, 0, 0, 3, 85, 3, 95, 3, 21, 7, 6, + 7, 8, 95, 3, 90, 7, 7, 3, 3, 3, 85, 85, 85, 7, 7,160, + 7, 7, 67, 1,124, 3, 6, 7, 9, 9, 90, 6, 6, 50, 3,125, + 16,161,162, 16,126, 3, 0, 0, 9, 9, 48, 3, 3, 9, 3, 3, + 48, 50, 3, 48, 3, 3, 3, 48, 3, 3, 3, 3, 3, 3, 3, 9, + 3, 48, 48, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, + 3, 3, 3, 3, 27, 27, 3, 3, 9, 3, 3, 3,163,164, 3, 3, + 3, 3, 3, 3, 3, 3, 48, 3, 3, 3, 3, 3, 3, 50, 9, 9, + 9, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, + 9, 3, 3, 3, 3, 3, 3, 3, 10, 10, 10, 10, 10, 10, 3, 3, + 3, 3, 3, 3, 3, 10, 10, 10, 3, 3, 3, 50, 3, 3, 3, 3, + 50, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, + 3, 3, 3, 3, 3, 3, 3, 50, 3, 3, 3, 3, 27, 27, 27, 27, + 27, 27, 27, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, + 9, 9, 64,127, 9, 9, 9, 9, 9, 9, 9, 27, 27, 27, 27, 27, + 9, 64, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,127, 9, 9, 9, + 9, 9, 9, 9, 27, 27, 9, 9, 9, 9, 9, 9, 9, 9, 27, 9, + 9, 9, 48, 50, 9, 9, 48, 3, 3, 3, 0, 3, 3, 3, 3, 3, + 8, 7, 8, 21, 21, 21, 21, 7, 8, 8, 21, 6, 6, 6, 13, 7, + 8, 8,125, 3, 3, 95, 21,165, 5, 8, 0, 0, 38, 12,114, 12, + 6, 6, 6, 42, 0, 0, 42, 0, 1, 1, 1, 1, 0, 0, 0, 54, + 33, 0, 0, 0, 0, 0, 0, 26, 12, 58, 58, 12,120,121, 58, 12, + 12, 12, 12, 76, 12, 92, 58, 12, 58, 27, 27, 27, 27, 12, 12, 62, + 12, 12, 12, 12, 12, 84, 12, 12, 92,166, 12, 12, 12, 12, 12, 12, + 3, 12, 96, 31, 31, 31,167, 0, 3, 3, 3, 3, 3, 44, 3, 3, + 87, 12,168,128, 27, 27, 27, 27, 27, 3, 27, 27, 27, 27,129,169, + 170, 16, 16, 16, 16, 5, 5, 15,130, 13, 13, 3, 16,171, 40, 3, + 1, 1, 1, 14, 26,172,131, 52, 1, 1, 1, 1, 1, 40, 13, 52, + 0, 0, 17, 1, 1, 1, 1, 1, 3, 10, 10, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 0, 0, 0, 44, 3, 3, 3, 3, 10, 10, 10, 10, + 1, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,132, 12, + 11, 11, 11, 11, 11, 1, 0, 0, 8, 8, 8, 8, 8, 8, 8, 24, + 79,173, 5, 5, 5, 5, 5, 62, 8, 8, 8, 8, 8, 8, 13, 5, + 1, 1, 1, 16, 16, 16, 16, 16, 5, 12, 12, 12, 0, 0, 0, 0, + 22, 22, 22,131, 13, 13, 13, 13, 22, 8, 8, 8, 8, 8, 8, 8, + 6, 8, 8, 8, 8, 8, 8, 8, 69, 6, 6, 6, 21, 21, 21, 8, + 8, 8, 8, 8, 68,174, 21, 67, 8, 8, 6, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 7, 7, 8, 7, 7, 8, 8, 8, 8, 8, 8, + 8, 8, 7, 7, 21, 21, 8, 8, 8, 8, 8, 8, 8, 8, 32, 0, + 54, 13,175, 67, 13, 67, 1, 1, 1, 25, 1, 25, 1, 24, 1, 1, + 1, 34, 19, 20, 3, 3, 23, 0, 10, 10, 10, 3, 97, 0, 0, 0, + 1, 1, 12, 12, 0, 0, 0, 0, 15, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 5, 0, 0, 0, 0, 12, + 5, 1, 1, 1, 12, 53, 53, 24, 1, 1, 1, 5, 5, 5, 5, 12, + 1, 1, 1, 24, 5, 5, 5, 5, 5, 15, 0, 0, 0, 0, 0, 38, + 1, 24, 15, 5, 5, 15, 5, 15, 83, 12, 12, 12, 12, 12, 12, 54, + 1, 1, 24, 52, 1, 1, 1, 1, 11, 11, 11, 11, 11, 1, 1, 14, + 1, 1, 1, 1, 24, 5, 5, 20, 19, 20, 19, 23, 0, 0, 0, 0, + 1, 24, 1, 1, 1, 1, 20, 0, 11, 11, 11, 11, 11, 0, 12, 12, + 52, 1, 1, 56, 3, 34, 20, 1, 25, 5, 25, 24, 25, 1, 1, 5, + 24, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 45, 12, + 1, 1, 1, 1, 1, 34, 5, 15, 12, 45,176, 23, 0, 0, 0, 0, + 17, 1, 1, 14, 17, 1, 1, 14, 17, 1, 1, 14, 0, 0, 0, 0, + 6, 6, 6, 6, 6,118, 13, 13, 6, 6, 6, 6,117, 22, 0, 0, + 1, 34, 19, 15, 20, 83, 19, 0, 1, 1, 1, 14, 0, 17, 1, 1, + 6, 6, 6, 47, 0, 0, 0, 0, 0, 42, 6, 6, 0, 0, 17, 25, + 1, 1, 1, 1,177, 1, 1, 1, 1, 1, 1, 14, 1, 1, 14, 14, + 1, 17, 14, 1, 1, 1, 1, 1, 1, 22, 22, 22, 22, 22, 22, 22, + 22,107, 3, 3, 3, 3, 3, 3, 3, 82, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 31, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 97, 3, + 12, 12, 12, 96, 65, 0, 0, 0, 76,178,179, 31, 31, 31, 31, 31, + 31, 31, 65, 96, 65, 12,122,180, 12, 33, 12, 12,129, 31, 31, 65, + 12,181, 9, 98, 80, 12, 0, 0, 1, 1, 14, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 14, 73, 38, 12,100, 12, 27,101, 76, 12, + 6, 6, 6, 6, 6,105,106, 64, 65, 27, 12, 1, 1, 1, 1, 1, + 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 14, 0, + 30,182, 70,183, 50, 9, 48, 29, 0, 0, 0, 0, 73, 18, 3, 0, + 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, 14, 1, 17, + 12, 33, 0, 49, 10, 10, 10, 10, 10, 10, 0, 44, 3, 3, 3, 3, + 16, 16,126, 10, 63, 3, 3, 3, 3, 3, 3, 3, 3, 10, 3, 29, + 3, 3, 3, 3, 3, 3, 43, 0,133, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, 10, 10, 0, 0, 0, 0, 17, 1, + 128, 1, 1, 1, 1, 99, 0, 0, 1, 1, 1, 5, 5, 23, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 38, 1, 1, 0, 0, 1, 1, 1, 1, + 184, 16, 16, 0, 0, 0, 0, 0, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 38, 7, 32, 7, 42, 6, 6, 6, 6, + 6, 42, 6, 6, 6, 6, 6, 6, 6, 42, 6, 6, 6, 42, 47, 0, + 13, 13, 13, 54, 13, 13, 13, 13, 61, 13, 13, 13, 13, 61, 0, 0, + 1, 1, 1, 0, 14, 1, 1, 1, 1, 1, 1, 17, 14, 0, 14, 17, + 1, 1, 1, 38, 10, 10, 10, 10, 1, 1, 1, 56, 75, 10, 10, 10, + 0, 0, 0, 49, 10, 10, 10, 10, 1, 14, 1, 0, 0, 49, 10, 10, + 1, 1, 1, 10, 10, 10, 0, 38, 1, 1, 1, 1, 1, 0, 0, 38, + 1, 1, 1, 1, 0, 0, 10, 1, 24, 5, 26, 23, 0, 0, 5, 5, + 1, 1, 17, 1, 17, 1, 1, 1, 1, 1, 1, 0, 5, 23, 0, 26, + 12, 12, 12, 12, 33, 0, 0, 0, 1, 1, 1, 1, 1, 1, 86, 78, + 1, 1, 1, 1, 82, 1, 1, 1, 1, 1, 24, 23, 0, 49, 10, 10, + 12, 12, 12, 33, 0, 0, 0, 0, 1, 1, 1, 0, 38, 12, 12, 12, + 1, 1, 1, 0, 10, 10, 10, 10, 1, 14, 0, 0, 10, 10, 10, 10, + 1, 0, 0, 0, 38, 12, 33, 0, 0, 0, 0, 0, 49, 10, 10, 10, + 7, 32, 0, 0, 0, 0, 0, 0, 6, 47, 0, 0, 0, 10, 10, 10, + 1, 1, 5, 5, 0, 0, 0, 0, 11, 11, 11, 11, 11, 1, 1, 52, + 7, 7, 7, 0, 26, 5, 5,130, 6, 6, 6, 0, 0, 0, 0, 9, + 10, 10, 10, 10, 10, 10, 10, 51, 1, 1, 1, 1, 1, 26,185, 0, + 0, 1, 45, 1, 0, 0, 0, 0, 57, 3, 3, 3, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 5, 5, 10, 10, 10,112, 0, 0, 0, 0, + 133, 10, 78, 12, 12, 0, 0, 0, 1, 5, 5, 12, 12, 0, 0, 0, + 1, 1, 86, 10, 10, 10, 0, 0, 19, 46, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 36, 12, 12, 12, 0, + 10, 10, 10, 11, 11, 11, 11, 11, 25, 24, 25, 0, 0, 0, 0, 26, + 15, 19, 5, 20, 19, 36,186, 12, 12, 23, 0, 0, 0, 0, 73, 0, + 5, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24, 5, 5, 19, 5, + 5, 5, 23, 11, 11, 11, 11, 11, 12, 12, 34, 46, 0, 0, 0, 0, + 1, 24, 12, 14, 0, 0, 0, 0, 1, 34, 15, 5, 5, 5, 5, 20, + 46, 1, 40, 12, 71, 5, 36, 19, 11, 11, 11, 11, 11, 40, 40, 12, + 10, 10, 51, 0, 0, 0, 0, 0, 5, 15, 20, 5, 12, 12, 12, 25, + 24, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 14, 14, 1, 1, 17, + 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 40, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 24, 15, 19, 5, 5, 5, 23, 0, 0, + 5, 15, 17, 1, 1, 1, 14, 17, 14, 1, 17, 1, 1, 26, 25, 15, + 20, 15, 37, 35, 37, 35, 15, 0, 14, 0, 0, 35, 0, 0, 17, 1, + 1, 15, 0, 5, 5, 5, 23, 0, 5, 5, 23, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 17, 0, 14, 1, 1, 1, 17, 15, 19, 5, 5, + 23, 37, 35, 35, 15, 37, 15, 20, 25, 25, 12, 38, 33, 0, 0, 0, + 26, 23, 0, 0, 0, 0, 0, 0, 1, 1, 34, 15, 5, 5, 5, 5, + 15, 5, 20, 25, 1, 40, 12, 12, 11, 11, 11, 11, 11, 12, 38, 25, + 15, 19, 5, 5, 20, 20, 15, 19, 20, 5, 1, 53, 0, 0, 0, 0, + 15, 5, 5, 0, 15, 15, 5, 19, 36, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 1, 1, 5, 0, 15, 19, 5, 5, 5, 20, 19, 19, + 36, 12, 14, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 33, 0, + 1, 1, 1, 1, 1, 24, 19, 15, 5, 5, 5, 19, 40, 0, 0, 0, + 11, 11, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14, 26, 19, + 15, 5, 5, 19, 5, 5, 0, 0, 11, 11, 11, 11, 11, 10, 12, 57, + 5, 5, 5, 5, 19, 36, 0, 0, 10, 51, 0, 0, 0, 0, 0, 17, + 1, 1, 1, 14, 17, 0, 1, 1, 1, 1, 17, 14, 1, 1, 1, 1, + 15, 15, 15, 35, 37, 26, 20, 25, 46, 19, 12, 33, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 1, 1, 1, 34, 15, 5, 5, 0, 5, 15, 15, + 25, 53, 37, 0, 0, 0, 0, 0, 24, 5, 5, 5, 5, 25, 1, 1, + 1, 24, 5, 5, 20, 24, 5, 36, 12, 12, 12, 71, 0, 0, 0, 0, + 24, 5, 5, 20, 19, 5, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, + 5, 5, 5, 20, 5, 12, 53, 12, 12, 33, 0, 0, 0, 0, 0, 0, + 12, 12, 12, 12, 12, 0, 0, 0, 20, 5, 20, 20, 0, 0, 0, 0, + 40, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 23, 5, 5, 5, 19, + 40, 12, 12, 0, 0, 0, 0, 0, 12, 1, 1, 1, 1, 1, 1, 1, + 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 35, 5, 5, 5, + 20, 5, 19, 23, 0, 0, 0, 0, 1, 1, 1, 14, 1, 17, 1, 1, + 24, 5, 5, 23, 0, 23, 5, 26, 5, 5, 5, 24, 0, 0, 0, 0, + 1, 1, 1, 17, 14, 1, 1, 1, 1, 1, 1, 1, 1, 15, 15, 37, + 5, 35, 19, 19, 14, 0, 0, 0, 1, 1, 1, 1, 45, 1, 0, 0, + 1, 24, 20, 83, 33, 0, 0, 0, 5, 34, 1, 1, 1, 1, 1, 1, + 1, 1, 15, 5, 5, 23, 0, 15, 20, 36, 12, 12, 12, 12, 12, 12, + 11, 11, 11, 11, 11, 23, 0, 0, 10, 10, 63, 3, 3, 3, 70, 30, + 97, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 38, + 16, 16, 16, 16, 16, 16, 16, 99, 12, 12, 33, 0, 0, 0, 0, 0, + 40, 33, 0, 0, 0, 0, 0, 0, 25, 1, 1, 24, 5, 5, 5, 5, + 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 15, 19, 5, + 5, 5, 36, 0, 0, 0, 0, 0, 5, 5, 5, 36, 12, 12, 3, 3, + 13, 13, 57, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 49, 10, 10, + 10, 17, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 17, 1, + 13, 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45,132, 12, + 10, 10, 10, 78, 12, 33, 0, 0, 7, 7, 7, 7, 32, 42, 6, 6, + 6, 6, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14, 0, 26, + 34, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 26, + 5, 81, 13, 13, 13, 13, 13, 13, 13, 62, 23, 0, 0, 0, 0, 0, + 15, 13, 16, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, + 13, 13, 54, 13, 13, 13, 54, 61, 0, 14, 0, 0, 0, 0, 0, 0, + 1, 14, 17, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 43, 36, 18, 18, 0, 0, 0, 0, 0, 0, + 11, 11, 11, 11, 11, 3, 29, 0, 3, 3, 0, 0, 0, 3, 3, 3, + 98, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 29, 44, 3, 3, 3, + 3, 3,134, 19, 5, 3,134, 15, 15,187, 18, 18, 18, 91, 5, 5, + 5, 55, 43, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, + 3, 5, 55, 0, 0, 0, 0, 0, 6, 6, 47, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 32, 7, 0, 32, 39, 32, 39, 7, 32, 7, + 7, 7, 7, 6, 6, 42, 42, 6, 6, 6, 42, 6, 6, 6, 6, 6, + 6, 6, 7, 39, 7, 32, 39, 7, 7, 7, 32, 7, 7, 7, 32, 6, + 6, 6, 6, 6, 7, 39, 7, 32, 7, 7, 32, 32, 0, 7, 7, 7, + 32, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 7, 7, 7, 7, + 59, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 60, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 59, 6, 6, + 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 59, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 60, 6, 6, 6, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, + 7, 7, 7, 7, 59, 6, 6, 6, 6, 60, 6, 6, 6, 8, 0, 11, + 5, 5, 5, 55, 3, 43, 5, 5, 5, 5, 5, 5, 5, 5, 55, 3, + 3, 3, 43, 3, 3, 3, 3, 3, 3, 3, 55, 66, 12, 12, 0, 0, + 0, 0, 0, 0, 0, 26, 5, 5, 6, 6, 6, 6, 6,124, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 47, 0, 0, 42, 6, 6, 47, 0, 0, + 5, 5, 5, 23, 5, 5, 5, 5, 5, 5, 5, 5, 23, 26, 5, 5, + 5, 26, 23, 5, 5, 23, 0, 0, 13, 13, 13, 13, 13, 13, 13, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 5, 5, 5, 81, 13, 13, 13, 0, + 11, 11, 11, 11, 11, 0, 0, 56, 1, 1, 1, 1, 1, 1, 1, 23, + 1, 1, 1, 1, 1, 1, 5, 5, 11, 11, 11, 11, 11, 0, 0,113, + 1, 1, 1, 1, 1, 45, 5, 5,188, 11, 11, 11, 11,189, 0, 38, + 1, 24, 1, 25, 1, 1, 1, 5, 1, 1, 24, 0, 0, 0, 0, 45, + 1, 1, 1, 14, 1, 1, 17, 14, 1, 1, 14, 49, 10, 10, 10, 10, + 6, 6, 5, 5, 5, 81, 0, 0, 10, 10, 10, 10, 10, 10, 75, 10, + 190, 10, 51, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 75, + 10, 10, 10, 10, 10, 10, 10, 0, 1, 1, 17, 1, 1, 1, 1, 1, + 17, 14, 14, 17, 17, 1, 1, 1, 1, 14, 1, 1, 17, 17, 0, 0, + 0, 14, 0, 17, 17, 17, 17, 1, 17, 14, 14, 17, 17, 17, 17, 17, + 17, 14, 14, 17, 1, 14, 1, 1, 1, 14, 1, 1, 17, 1, 14, 14, + 1, 1, 1, 1, 1, 17, 1, 1, 17, 1, 17, 1, 1, 17, 1, 1, + 9, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 63, 3, + 0, 0, 0, 3, 3, 3, 3, 3, 3, 29, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3,108, 22, 22, 3, 3, 3, 3, 29, 0, 3, 3, + 9, 9, 9, 9, 98, 0, 0, 0, 3, 3, 3, 3, 3, 29, 0, 3, + 3, 3, 3, 29, 29, 0, 44, 3, 3, 3, 3, 3, 3, 3, 29, 44, + 3, 3, 3, 3, 3, 29, 0, 44, 3, 29, 3, 3, 3, 3, 3, 3, + 11, 11, 11, 11, 11, 29, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 7, 7, 3, 3, 26, 26, + 4, 4, 12, 12, 5, 5, 9, 9, 9, 5, 25, 25, 15, 15, 13, 13, + 21, 21, 6, 6, 7, 2, 10, 10, 14, 14, 2, 7, 1, 1, 10, 12, + 12, 10, 5, 9, 24, 24, 12, 2, 7, 12, 12, 7, 2, 12, 22, 18, + 0, 0, 26, 2, 23, 23, 18, 22, 9, 2, 21, 2, 7, 10, 2, 10, + 12, 21, 10, 2, 2, 21, 2, 9, 7, 21, 8, 8, 2, 5, 26, 12, + 2, 26, 7, 6, 10, 7, 5, 2, 25, 26, 2, 15, 26, 25, 15, 2, + 6, 7, 21, 7, 2, 6, 12, 26, 7, 26, 21, 26, 20, 19, 9, 25, + 5, 25, 6, 2, 21, 6, 15, 26, 25, 22, 18, 21, 26, 21, 5, 7, + 6, 24, 6, 5, 26, 23, 21, 12, 6, 12, 2, 1, 29, 29, 26, 15, + 21, 17, 25, 21, 15, 21, 11, 11, 21, 23, 12, 6, 26, 7, 10, 21, + 17, 17, 9, 26, 7, 15, 29, 21, 21, 9, 24, 5, 25, 9, 1, 12, + 17, 21, 11, 12, 8, 24, 26, 9, 21, 22, 23, 26, 25, 2, 14, 2, + 23, 21, 21, 25, 9, 22, 21, 18, 24, 16, 5, 22, 25, 18, 24, 26, + 26, 24, 9, 8, 8, 5, 5, 21, 15, 7, 2, 23, 21, 15, 17, 7, + 18, 2, 5, 6, 5, 24, 22, 20, 21, 20, 19, 21, 21, 16, 16, 21, + 7, 5, 5, 26, 14, 15, 18, 25, 7, 14, 17, 22, 17, 6, 24, 6, + 6, 21, 12, 15, 26, 10, 25, 0, 7, 20, 25, 1, 24, 15, 7, 19, + 9, 21, 17, 2, 17, 12, 1, 21, 12, 1, 24, 7, 29, 7, 7, 22, + 14, 7, 2, 24, 9, 24, 24, 2, 29, 1, 27, 28, 1, 29, 21, 29, + 1, 2, 15, 6, 18, 6, 12, 11, 26, 5, 14, 9, 5, 14, 26, 22, + 18, 26, 5, 12, 22, 21, 18, 17, 26, 6, 18, 18, 26, 14, 14, 6, + 12, 24, 11, 21, 24, 9, 6, 9, 6, 10, 7, 25, 17, 16, 16, 22, + 16, 16, 25, 17, 25, 24, 23, 2, 21, 14, 12, 17, 21, 1, 10, 1, + 7, 13, 13, 2, 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, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, 0, 37, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, + 0, 0, 0, 0, 0, 0, 41, 42, 43, 44, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 9, 0, 0, + 0, 10, 11, 12, 13, 0, 14, 15, 16, 0, 17, 18, 19, 20, 21, 1, + 22, 1, 23, 1, 2, 1, 2, 1, 2, 0, 2, 1, 24, 1, 2, 25, + 2, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 36, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 38, + 0, 0, 39, 0, 0, 40, 0, 41, 0, 0, 0, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 0, 0, 51, 0, 0, 0, 52, 0, 0, 0, 53, 0, + 0, 0, 0, 0, 0, 0, 54, 0, 3, 0, 55, 56, 0, 57, 0, 0, + 0, 0, 0, 0, 58, 59, 60, 0, 0, 0, 0, 61, 0, 0, 62, 63, + 64, 4, 65, 0, 0, 66, 67, 0, 0, 0, 68, 0, 0, 0, 0, 69, + 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 71, 0, 0, 0, 72, 0, 73, 0, 0, 74, 0, 0, 75, 0, + 0, 0, 0, 0, 0, 0, 0, 76, 77, 0, 0, 0, 0, 78, 79, 0, + 80, 81, 0, 0, 82, 5, 0, 83, 4, 0, 84, 85, 0, 0, 86, 87, + 88, 0, 89, 0, 90, 0, 91, 0, 0, 3, 92, 3, 0, 93, 0, 94, + 0, 0, 0, 5, 0, 0, 0, 95, 96, 0, 97, 98, 99,100, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0,101,102, 0, 0, 0, 0, 0, 0, + 103, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,106, 0, 0,107, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,108,109, 0, 0,110, 0, 0, 0, + 0, 0, 0,111, 0,112, 0, 6, 0, 0, 0, 0, 0,113,114, 0, + 0, 0, 0, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,117, 0, + 0, 0, 0, 0, 0, 0,118, 0,119, 0, 0, 0, 0, 0, 0, 0, + 2, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 11, 0, 0, 0, + 14, 0, 0, 0, 16, 3, 17, 18, 19, 20, 21, 22, 0, 23, 0, 0, + 0, 0, 24, 25, 26, 27, 0, 0, 0, 0, 28, 0, 0, 29, 30, 0, + 31, 0, 32, 33, 0, 0, 34, 0, 35, 36, 0, 0, 0, 0, 0, 37, + 38, 0, 39, 40, 0, 0, 41, 0, 0, 0, 42, 0, 0, 43, 44, 45, + 46, 1, 47, 0, 0, 1, 0, 0, 7, 1, 48, 0, 0, 0, 0, 0, + 49, 50, 0, 0, 0, 0, 0, 0, 51, 52, 0, 0, 0, 0, 0, 0, + 53, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 57, 58, 0, 0, + 0, 59, 0, 0, 0, 0, 0, 0, 60, 12, 0, 0, 0, 0, 61, 0, + 0, 0, 62, 0, 5, 0, 63, 0, 0, 0, 0, 64, 0, 0, 0, 0, + 65, 0, 66, 0, 0, 0, 0, 6, 67, 0, 0, 0, 68, 69, 70, 71, + 0, 0, 0, 0, 72, 5, 0, 73, 74, 0, 0, 75, 0, 0, 0, 76, + 77, 0, 0, 0, 78, 0, 79, 80, 81, 82, 83, 3, 84, 0, 85, 86, + 87, 0, 0, 8, 9, 0, 0, 3, 3, 0, 0, 88, 0, 0, 89, 0, + 0, 0, 0, 8, 90, 0, 91, 0, 0, 0, 0, 0, 9, 10, 0, 92, + 0, 5, 0, 3, 9, 0, 0, 93, 0, 0, 94, 0, 0, 6, 0, 0, + 0, 0, 0, 0, 95, 96, 0, 0, 10, 0, 0, 1, 0, 0, 97, 0, + 0, 0, 0, 98, 0, 0, 0, 0, 12, 0, 0, 13, 0, 0, 0, 0, + 99,100, 0, 0,101, 0, 0,102, 0, 0, 0,103, 0, 0, 0,104, + 0, 0, 0,105, 0, 0, 0, 0,106,107, 13, 0, 0,108, 0, 0, + 0, 10, 0, 0,109,110, 0, 0,111,112, 0, 0, 0, 0, 0, 0, + 113, 0, 0,114, 0, 0, 0, 0,115, 1, 0,116,117,118, 6, 0, + 0,119, 7, 0, 0,120, 0, 0, 0,121, 0, 0, 0, 0, 0, 0, + 122, 0, 0,123, 0, 0, 0, 0,124, 11, 0, 0, 0, 0, 0, 6, + 0, 0, 0, 0, 5, 15, 0, 0, 0, 0,125, 0, 0,126, 0, 0, + 0, 0, 15, 0, 0,127, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, + 128, 0, 0, 0,129, 0,130, 0, 0, 0, 0,131,132,133, 0,134, + 0,135, 0, 0, 0,136,137,138, 0, 8, 0, 0, 0, 0, 0, 7, + 0, 0, 0,139, 0, 0, 0,140, 0, 0, 0,141, 0, 0, 0,142, + 143, 0,144, 0, 0,145, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, + 0, 9, 1, 1, 1, 1, 0, 0, 0, 2, 0, 3, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 19, 0, 0, 0, 6, 11, 0, 0, 0, 0, 14, + 0, 0, 15, 0, 0, 0, 0, 0, 0, 17, 29, 0, 0, 0, 0, 0, + 31, 0, 0, 2, 0, 0, 1, 12, 0, 0, 1, 49, 50, 5, 51, 52, + 53, 5, 5, 22, 32, 23, 1, 54, 24, 55, 16, 33, 56, 57, 58, 1, + 1, 1, 6, 1, 0, 0, 59, 7, 60, 1, 34, 5, 7, 61, 62, 63, + 64, 65, 66, 67, 0, 0, 1, 1, 68, 0, 0, 0, 69, 70, 71, 35, + 1, 25, 72, 0, 0, 0, 0, 8, 1, 26, 16, 26, 73, 27, 74, 0, + 0, 0, 36, 25, 75, 37, 7, 37, 76, 0, 0, 0, 6, 1, 7, 0, + 0, 17, 0, 8, 38, 1, 1, 13, 13, 11, 0, 0, 39, 0, 0, 6, + 18, 1, 0, 0, 8, 16, 5, 1, 1, 1, 77, 7, 36, 18, 78, 7, + 35, 1, 79, 10, 0, 0, 0, 80, 0, 0, 0, 0, 2, 3, 0, 0, + 14, 0, 0, 0, 81, 0, 0, 0, 82, 0, 0, 0, 83, 0, 0, 0, + 84, 0, 0, 0, 40, 0, 0, 85, 86, 0, 87, 88, 89, 90, 91, 92, + 0, 0, 0, 93, 0, 0, 0, 15, 28, 0, 0, 0, 0, 13, 0, 41, + 0, 0, 14, 0, 0, 20, 0, 0, 94, 0, 0, 0, 95, 0, 0, 6, + 29, 0, 0, 13, 1, 96, 1, 18, 33, 97, 25, 23, 7, 1, 1, 1, + 1, 27, 1, 7, 98, 0, 0, 9, 0, 0, 0, 0, 6, 23, 1, 0, + 0, 0, 0, 0, 30, 0, 0, 21, 0, 0, 30, 0, 0, 0, 0, 15, + 0, 0, 12, 32, 24, 5, 99, 22, 42, 17, 0, 10, 11, 0, 7, 1, + 7,100,101, 1, 1, 1, 1,102,103,104,105, 1,106, 10, 20,107, + 108, 5, 10, 0, 0, 0, 0, 0,109,110, 0, 0,111, 0, 0, 1, + 1, 11, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 43, 40, 2, 0, + 0, 0, 44,112, 10, 8, 20, 0, 0, 0, 0, 0, 0,113, 1, 16, + 5, 24, 0, 8, 12, 0, 0, 0, 0,114, 0, 0,115, 2, 0,116, + 0, 0, 0, 1, 0, 0, 0, 0, 13, 11, 0, 0, 6, 10, 0, 0, + 45, 39, 0, 45, 16, 18, 46, 27, 0, 0, 3, 0, 0, 2, 12, 0, + 0, 0, 2, 3, 0, 0, 3, 0, 21, 0, 0, 31, 0, 0, 0, 0, + 117, 0, 0, 0, 15, 9, 0, 8, 1, 10, 1, 10, 0, 0, 0, 0, + 0, 30, 14, 21, 0, 0, 47, 0, 0, 0, 9, 0, 0, 0, 0, 47, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 28, 0, 0, 4, 0, 21, 41, + 0, 0, 28, 0, 0, 0, 22, 42, 0, 0,118, 0, 0, 0, 0, 0, + 0,119, 0,120,121,122,123, 0, 43, 5, 48, 13, 34, 0, 0, 0, + 8, 11, 8, 10, 0, 0, 1, 12, 1, 1, 1, 1, 26, 1, 38, 44, + 12, 0, 0, 0, 0, 1, 0, 0, 0,124, 0, 0, 0, 46, 6, 19, + 0, 8, 0, 20, 0, 0, 5, 48, 0, 0, 0, 1,125, 0, 0, 0, + 0,230,230,230,230, 0, 0, 0, 9, 9, 0, 0, 0, 0, 9, 0, + 0,220,220,220,220, 0, 0, 0,230,230,230,220,230, 0, 0,230, + 230, 7, 0, 0, 0,230, 0, 0, 0,230,230, 0, 0,230,230,230, + 0, 0,230,230,230, 0, 0, 9, 0, 0, 0, 0, 7,230,230,230, + 220, 0,220, 0, 0,230,220,220,220, 0, 0,230, 0, 0,230, 0, + 0, 0, 0, 7, 0, 1, 1, 1, 1,220,230,230,230,220,220,230, + 230,220,230,230,220,230, 0, 0,230,230,220, 0, 0, 0, 9, 9, + 0,220, 0, 0, 0, 0, 0, 9, 9, 0, 9, 7, 0, 1,220,220, + 220,220,220,220,230,230,230,220,220,230,220,220,230,230,220,230, + 230,220,230,220,230,230,230, 0,230, 0,220,220,220,220,220, 0, + 0, 9, 9, 0, 0, 1, 0, 0, 0, 0, 0, 0,220,230, 0,230, + 230, 0, 0,220,220, 0, 0,230,220, 0, 0, 9, 7,220,220,220, + 0,230,232,220,220,220,220,232,216,220,202,202,220,220,220,220, + 202,202,220,220,220,230,240,230,220,230,220,220, 0,232,220,220, + 230,233,234,234,233,234,234,233,230, 0,220,230,230,230,230,222, + 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, 35, 0, 0, + 0,230, 0,220,230, 0, 36, 0, 0,220,220,230,220,220,230,230, + 0,230,230, 0,220, 27, 28, 29,230, 0,230,220,230, 0, 84, 91, + 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122, + 122, 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,228, 0, 0, 0,222,230,220,230, 0, 0, + 220,230,220, 0,220,230,230,230,234,230, 0, 1, 1,230,234,214, + 220,202,230,230,230,230,230,232,228,228,220,218,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,220, 0, 0, + 230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230,220, + 0, 0, 7, 9, 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,232,232,220, + 230,230,230, 7, 0, 1, 0, 0, 32, 0, 48, 0, 0, 84, 96,135, + 144, 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,176, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 24, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 40, + 0, 0, 0, 0, 0, 48, 56, 64, 0, 0, 0, 0, 0, 72, 80, 88, + 96,104, 0, 0, 0, 0, 0, 0, 0, 0,112, 0,120, 0, 0, 0, + 0, 0, 0,128,136,144,152,160,168, 0, 0, 0,176,184,192, 0, + 0, 0, 0, 0, 0,200, 0, 0, 0, 0, 0, 0, 0, 0,208, 0, + 0,216,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 36, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 0, 0, + 64, 0, 68, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 72, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 0, 0, 0, 0, + 0, 0, 20, 0, 20, 0, 0, 0, 0, 0, 0, 0, 76, 80, 84, 88, + 0, 0, 12, 92, 96, 28, 0,100,104, 4, 4, 4,108, 44,112,116, + 120, 4,124, 0,128,132, 4, 4, 48,136,140, 0, 32, 0, 0, 0, + 40, 0, 0, 0, 0, 0, 0, 0, 4, 48, 0, 52,144, 20,148,152, + 4, 0, 0,156,160,164,168,172, 4, 0,176, 56, 60,180, 32, 0, + 16,184, 56, 0, 0, 0, 0, 0, 52, 12, 12, 0, 0, 0, 0, 12, + 0, 0,188, 8, 8, 8, 8,192,196, 8, 8, 8, 8,200,204,208, + 212, 60, 44, 0, 0, 0, 0, 0, 0, 0,216, 28,220, 0, 12, 4, + 16, 0, 0, 0, 0,224,228, 0, 0, 0, 0, 0, 4,232, 32, 0, + 0, 0, 0, 0, 0, 0,236, 12, 0, 0, 0, 0, 16, 0, 36, 0, + 0, 0, 24, 0, 0, 0,240,244, 0, 0, 0, 0, 2, 2, 2, 2, + 4, 4, 4, 4, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 6, 8, + 0, 10, 12, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 14, 16, + 6, 8, 0, 0, 4, 8, 0, 0, 2, 2, 2, 0, 0, 6, 4, 8, + 2, 0, 2, 0, 0, 0, 0, 6, 0, 20, 0, 0, 0, 22, 0, 0, + 0, 6, 8, 0, 24, 26, 28, 0, 0, 0, 30, 0, 0, 0, 0, 32, + 34, 36, 38, 0, 0, 40, 42, 0, 0, 0, 18, 0, 0, 0, 2, 2, + 2, 2, 0, 2, 2, 2, 0, 6, 44, 0, 0, 0, 0, 2, 0, 46, + 48, 50, 0, 0, 52, 0, 0, 0, 6, 4, 54, 0, 2, 0, 0, 2, + 2, 56, 58, 60, 0, 62, 64, 18, 2, 10, 12, 0, 0, 0, 66, 8, + 0, 2, 2, 2, 0, 6, 4, 4, 4, 4, 68, 2, 70, 4, 4, 4, + 8, 72, 0, 0, 74, 76, 2, 0, 78, 0, 0, 0, 4, 8, 2, 0, + 0, 0, 80, 0, 6, 4, 4, 4, 4, 8, 0, 2, 2, 2, 2, 6, + 4, 4, 4, 8, 0, 0, 0, 82, 0, 84, 86, 0, 0, 0, 2, 88, + 0, 0, 0, 90, 6, 8, 2, 0, 0, 0, 6, 4, 4, 4, 8, 0, + 2, 0, 2, 2, 6, 4, 4, 8, 0, 10, 12, 6, 8, 2, 0, 0, + 4, 5, 6, 7, 8, 9, 10, 1, 1, 11, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 12, 13, 2, 2, 2, 2, 14, 0, 0, 0, 0, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 25, 26, 3, 3, + 3, 27, 0, 0, 0, 28, 29, 30, 0, 31, 32, 33, 34, 35, 36, 37, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 38, 1, 1, 39, 1, 40, 1, 1, 1, 41, 0, 42, + 1, 1, 43, 1, 1, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 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, 3, + 3, 20, 21, 8, 8, 8, 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, 2, 2, 51, 52, 53, 54, 9, 9, 9, 9, 9, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 8, 8, 70, + 71, 72, 73, 74, 75, 5, 5, 5, 5, 76, 5, 5, 5, 5, 5, 5, + 5, 15, 15, 5, 5, 5, 5, 77, 5, 78, 79, 80, 81, 82, 83, 1, + 84, 85, 86, 87, 88, 89, 90, 91, 5, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 92, 1, 1, 1, + 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 93, 16, 16, 94, 95, 96, + 97, 98, 99,100,101,102,103,104,105, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 106, 0, 0, 1, 1,107,108,109, 13, 13, 13,110,111,112,113,114, + 115,116,117,118,119, 0,120,121,122,123,124,125,126, 17, 17,127, 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, + 144,145,146,147,148,149,150,151,152,153,154, 0,155,156,157,158, + 0,159,160,161,162,163,164,165,166,167,168,169,170, 0,171,172, + 173, 7, 7, 7, 7, 7, 7, 7,174,175, 7,176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162, 0,163, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,164,165, 0, 0, 0, 0, 0, - 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 177, 4, 4, 4, 4, 4, 4, 4, 4,178, 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,179, 11, 11, 11, 11,180, 0, 0, + 0, 0, 0,181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 12, 12, 12, 12,182,183,184,185, 0, 0,186, 0,187,188,189, + 190, 3, 3, 3, 3, 3, 3, 14, 14, 14,191,192,193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,167, 0, 0, 0,168,169, 0, 0,170, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,171, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,172, 0, 0, 0, 0, + 194,195,196,197, 18, 18,198, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,199,200, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,201, 5, 5, 5,202,203, + 204, 5,205,206,207,208,209,210, 0,211,212,213, 5, 5,214, 5, + 215, 10, 10, 10, 10, 10,216, 0, 0, 0, 0, 0, 0, 0, 0,217, + 0,218,219,220, 0, 0,221, 0, 0, 0,222, 0,223, 0,224, 0, + 225,226,227,228, 0, 0, 0, 0, 0,229,230,231, 0,232,233, 0, + 0,234,235, 5,236,237, 0, 5, 5, 5, 5, 5, 5, 5,238, 5, + 239,240,241, 5, 5,242,243, 5,244, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,245, 1, + 1,246, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,247, 1, + 1, 1, 1, 1, 1, 1, 1, 1,248, 1, 1, 1, 1,249, 0, 0, + 0, 1, 1, 1, 1,250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1,251, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1,252, 0, 0, 0, 0, 0, 0, + 0,253, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 13, 13, 13, 13, 12, 12, 12, 12, 0, 0, 0, + 0,136,136,136,136, 80, 80, 80, 80, 19, 19, 19, 19, 3, 3, 3, + 3, 63, 63, 63, 63, 39, 39, 39, 39, 28, 28, 28, 28,131,131,131, + 131, 79, 79, 79, 79, 1, 1, 1, 1,127,127,127,127, 6, 6, 6, + 6,155,155,155,155, 9, 9, 9, 9, 30, 30, 30, 30,139,139,139, + 139, 15, 15, 15, 15,110,110,110,110, 77, 77, 77, 77, 17, 17, 17, + 17, 27, 27, 27, 27, 33, 33, 33, 33,113,113,113,113, 49, 49, 49, + 49, 25, 25, 25, 25, 29, 29, 29, 29, 7, 7, 7, 7, 8, 8, 8, + 8, 32, 32, 32, 32, 99, 99, 99, 99, 31, 31, 31, 31,105,105,105, + 105, 55, 55, 55, 55, 62, 62, 62, 62, 56, 56, 56, 56, 91, 91, 91, + 91,119,119,119,119, 14, 14, 14, 14, 94, 94, 94, 94, 20, 20, 20, + 20,100,100,100,100,130,130,130,130,157,157,157,157,137,137,137, + 137, 97, 97, 97, 97,123,123,123,123,133,133,133,133,146,146,146, + 146, 84, 84, 84, 84,159,159,159,159,132,132,132,132, 4, 4, 4, + 4, 36, 36, 36, 36, 24, 24, 24, 24, 30, 30, 30, 2, 35, 35, 35, + 35, 40, 40, 40, 40,124,124,124,124,125,125,125,125,140,140,140, + 140, 37, 37, 37, 37, 58, 58, 58, 58, 0, 0, 2, 2, 75, 75, 75, + 75, 68, 68, 68, 68,114,114,114,114,163,163,163,163, 22, 22, 22, + 22, 23, 23, 23, 23, 76, 76, 76, 76, 0, 0, 0, 2, 26, 26, 26, + 26, 87, 87, 87, 87,135,135,135,135, 89, 89, 89, 89,141,141,141, + 141, 70, 70, 70, 70, 92, 92, 92, 92, 96, 96, 96, 96, 5, 5, 5, + 5, 18, 18, 18, 18, 48, 48, 48, 48, 85, 85, 85, 85,109,109,109, + 109,102,102,102,102,151,151,151,151, 16, 16, 16, 16, 0, 2, 2, + 2,165,165,165,165,108,108,108,108,171,171,171,171,142,142,142, + 142,150,150,150,150,134,134,134,134,138,138,138,138, 64, 64, 64, + 64, 90, 90, 90, 90, 21, 21, 21, 21, 93, 93, 93, 93, 61, 61, 61, + 61, 65, 65, 65, 65, 78, 78, 78, 78,126,126,126,126,154,154,154, + 154,121,121,121,121,166,166,166,166,167,167,167,167,152,152,152, + 152, 10, 10, 10, 10, 2, 0, 0, 0,104,104,104,104,170,170,170, + 170, 57, 57, 57, 57,107,107,107,107,175,175,175,175, 38, 38, 38, + 38, 73, 73, 73, 73, 86, 86, 86, 86, 67, 67, 67, 67, 59, 59, 59, + 59, 51, 51, 51, 51,161,161,161,161,144,144,144,144,143,143,143, + 143,172,172,172,172,174,174,174,174, 60, 60, 60, 60, 69, 69, 69, + 69, 47, 47, 47, 47,112,112,112,112,118,118,118,118,106,106,106, + 106,156,156,156,156,147,147,147,147,148,148,148,148,169,169,169, + 169,164,164,164,164,168,168,168,168, 11, 11, 11, 11, 74, 74, 74, + 74, 42, 42, 42, 42, 50, 50, 50, 50,116,116,116,116,111,111,111, + 111,115,115,115,115, 52, 52, 52, 52, 13, 13, 2, 2,120,120,120, + 120, 98, 98, 98, 98, 88, 88, 88, 88,117,117,117,117,101,101,101, + 101,103,103,103,103, 19, 19, 19, 0, 95, 95, 95, 95, 30, 30, 2, + 2, 34, 34, 34, 34, 54, 54, 54, 54, 0, 2, 0, 0, 71, 71, 71, + 71, 53, 53, 53, 53, 81, 81, 81, 81, 66, 66, 66, 66, 83, 83, 83, + 83,153,153,153,153,160,160,160,160, 2, 2, 22, 22, 30, 2, 30, + 30, 9, 9, 2, 2, 2, 2, 0, 0, 41, 41, 41, 41, 72, 72, 72, + 72,173,173,173,173, 82, 82, 82, 82,158,158,158,158,129,129,129, + 129,145,145,145,145, 2, 3, 3, 3, 23, 2, 23, 23, 16, 2, 16, + 16, 2, 2, 2, 0, 45, 45, 45, 45, 44, 44, 44, 44, 43, 43, 43, + 43,128,128,128,128,122,122,122,122,149,149,149,149, 0, 19, 19, + 19, 0, 0, 19, 0, 9, 2, 9, 9, 5, 2, 2, 5, 2, 10, 10, + 10, 10, 10, 2, 10, 2, 21, 21, 21, 21, 2, 2, 21, 22, 22, 22, + 2, 22, 22, 2, 2, 20, 2, 20, 20, 2, 30, 30, 30, 12, 12, 12, + 2, 19, 19, 19, 2, 2, 2, 12, 12,161,161, 2,161, 3, 3, 3, + 2,107, 2, 2,107, 2, 3, 2, 3, 19, 0, 0, 0, 2, 2, 9, + 9, 9, 9, 9, 2, 2, 4, 4, 4, 2, 11, 11, 11, 11, 11, 11, + 2, 11, 2, 11, 11, 10, 10, 2, 2, 22, 2, 22, 22, 2, 2, 2, + 22, 23, 23, 2, 2, 2, 36, 36, 36, 2, 2, 36, 36, 2, 25, 25, + 25, 46, 46, 46, 46, 31, 31, 2, 2, 91, 91, 2, 2, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 17, 17, 17, 49, 49, 49, 2,161,161,161, + 2, 2,107,107,107,107, 2, 2, 2,171,171, 2,171, 0, 0, 2, + 0, 2, 3, 3, 2, 3, 2, 2, 3, 4, 4, 4, 2, 2, 14, 14, + 14, 14, 14, 14, 2, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, + 0, 37, 37, 37, 2, 3, 3, 2, 2, 2, 2, 2, 3, 2, 2, 5, + 5, 5, 5, 5, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 2, + 2, 10, 2, 10, 10, 21, 2, 21, 21, 21, 21, 2, 2, 22, 2, 2, + 2, 2, 16, 16, 16, 16, 16, 2, 2, 36, 36, 36, 2, 36, 2, 2, + 2, 18, 18, 18, 2, 18, 18, 2, 2, 25, 2, 25, 25, 8, 8, 2, + 8, 2, 8, 2, 2, 29, 29, 2, 2, 46, 2, 46, 46, 32, 2, 2, + 2, 1, 1, 2, 2, 1, 1, 1, 0, 19, 19, 9, 9, 2, 9, 2, + 9, 0, 0, 0, 19, 19, 2, 2, 2, 0, 0, 19, 19, 2, 2, 2, + 61, 15, 15, 15, 2, 17, 17, 17, 0, 2, 19, 19, 19, 75, 75, 2, + 2, 12, 2, 2, 2, 68, 68, 2, 2, 87, 87, 2, 2, 49, 49, 2, + 2, 50, 50, 2, 2, 2, 57, 57, 57, 57, 2, 2, 2,112,112,112, + 2, 2,122,122,122,130,130,130, 2,165,165, 2, 2,156,156, 2, + 2, 2, 2, 3, 3, 94, 94, 2, 2,129,129, 2,129,107, 2,107, + 107,123,123, 2, 2,102,102, 2, 2,126,126,126, 2,154,154,154, + 2, 2, 2,150,150,169,169, 2, 2,138,138,138, 2,138,138, 2, + 138,143,143, 2,143,163,163,163, 2,103,103, 2, 2,119,119, 2, + 119, 2, 2, 2, 99, 13, 13, 13, 2,136,136,136, 2,105, 2, 2, + 2, 0, 0, 0, 1, 56, 56, 56, 2,151,151, 2, 2, 3, 3, 2, + 3, 0, 0, 26, 26, 0, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, + 0, 9, 9, 2, 9, 9, 9, 55, 55, 6, 1, 1, 6, 2, 2, 2, + 14, 14, 2, 2, 2, 3, 3, 3, 1, 1, 1, 3, 3, 1, 3, 3, + 3, 37, 37, 2, 37, 2, 37, 37, 37, 38, 38, 2, 2, 64, 64, 64, + 2, 2, 64, 64, 64, 90, 90, 2, 2, 90, 90, 90, 2, 2, 2, 95, + 2, 3, 3, 0, 3, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, + 7, 2, 5, 5, 5, 5, 2, 5, 5, 5, 2, 5, 2, 5, 5, 2, + 2, 2, 2, 2, 5, 5, 5, 2, 5, 2, 11, 11, 2, 2, 11, 2, + 2, 11, 2, 11, 2, 2, 2, 11, 11, 10, 2, 2, 2, 2, 2, 10, + 10, 21, 21, 2, 21, 2, 2, 21, 21, 2, 22, 22, 22, 2, 22, 22, + 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 2, 23, 23, 2, 2, 2, + 23, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 16, 16, 2, 2, 20, + 20, 36, 36, 2, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, + 36, 36, 2, 36, 2, 2, 24, 24, 24, 24, 24, 24, 2, 2, 18, 18, + 2, 18, 2, 18, 18, 2, 18, 2, 18, 18, 2, 18, 2, 25, 2, 2, + 2, 25, 0, 0, 0, 0, 25, 25, 2, 8, 8, 8, 0, 30, 2, 2, + 2, 34, 2, 2, 2, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2, 2, + 2, 45, 45, 2, 2, 2, 2, 2, 45, 44, 0, 0, 2, 32, 32, 0, + 0, 32, 0, 32, 32, 32, 32, 2, 2, 32, 32, 32, 2, 28, 28, 2, + 2, 48, 48, 48, 2, 48, 2, 2, 2, 52, 52, 2, 2, 52, 2, 2, + 2, 58, 58, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 2, 2, 54, + 54, 91, 91, 91, 2, 91, 2, 2, 91, 62, 2, 62, 62, 2, 2, 2, + 70, 70, 70, 2, 2, 2, 70, 70, 70, 6, 6, 6, 2, 8, 8, 8, + 2, 2, 8, 8, 8, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, + 2, 9, 9, 9, 6, 19, 9, 9, 9, 9, 9, 19, 19, 9, 9, 9, + 19, 6, 19, 19, 19, 19, 19, 19, 9, 2, 9, 9, 9, 0, 19, 2, + 2, 1, 2, 2, 2, 0, 0, 9, 0, 2, 55, 55, 55, 61, 2, 2, + 2, 13, 13, 2, 13, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, + 1, 1, 1, 12, 12, 2, 15, 15, 15, 2, 1, 1, 0, 0, 15, 15, + 15, 2, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 0, 39, 2, 2, + 2, 39, 39, 39, 2, 60, 2, 2, 2, 2, 2, 75, 75, 69, 69, 0, + 69, 2, 2, 2, 74, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, + 84, 33, 33, 33, 2, 68, 68, 68, 2, 92, 92, 92, 2, 2, 2, 2, + 92, 87, 87, 87, 2, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, + 12, 2, 2, 2, 4, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, + 14, 3, 3, 0, 0, 1, 1, 6, 6, 3, 2, 3, 3, 3, 2, 2, + 0, 0, 0, 17, 17, 17, 17, 0, 0, 2, 49, 49, 49, 49, 49, 2, + 49, 9, 2, 2, 2, 0, 1, 2, 2, 71, 2, 2, 2, 67, 2, 2, + 2, 2, 42, 42, 42, 41, 41, 41, 2,118,118,118, 2, 53, 53, 2, + 53, 59, 59, 2, 2, 2, 2, 2,104,161, 2, 2, 2,110,110,110, + 2,110,110, 2, 2, 19, 19, 2, 19, 19, 2, 19, 19, 47, 47, 2, + 2, 47, 2, 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, + 47, 81, 81, 2, 81,116,116,116, 2, 2, 2, 2,116,128,128,128, + 2,128,128, 2, 2, 2, 2, 2,128, 2, 2, 2, 66, 72, 72, 2, + 2, 2, 2, 2, 72,173,173, 2, 2, 2, 2, 97, 97, 2, 57, 57, + 2, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 2, 2, 2, + 112, 78, 78, 2, 2, 2, 78, 78, 78, 83, 83, 2, 2, 82, 82, 82, + 2,122,122, 2, 2,122, 2, 2, 2, 89, 2, 2, 2, 2, 2,130, + 130,144,144, 2, 2, 2,165,165,165, 2, 2,165,165,156,156, 2, + 156, 3, 2, 2, 2,148,148, 2, 2,158,158, 2, 2,149,149,149, + 2, 2, 2, 94, 94, 2, 2, 2, 94, 85, 85, 85, 2, 2, 85, 2, + 2,101, 2, 2, 2,101,101, 2, 2, 96, 2, 96, 96,111,111,111, + 2,108,108, 2,108,108,108, 2, 2,129,129,129, 2,129, 2,129, + 129,129,129, 2, 2,109,109,109, 2,109,109, 2, 2,107,107, 2, + 1,107,107, 2, 2, 2, 2, 2,107, 2, 2,107,107, 2, 2,171, + 2,171, 2,171, 2, 2,171, 2,171,171,171,171, 2,171, 2, 2, + 2, 2,171,171, 2, 2,137,137,137,137,137, 2, 2,124,124, 2, + 2,114, 2, 2, 2,114,114, 2, 2, 2,126,126,126,125,125,125, + 2, 2, 2, 2,125, 2,154, 2, 2, 2,154,154, 2,154,154, 2, + 154,154, 2, 2,154,154,154, 2, 2,150, 2, 2, 2,140,140,140, + 2,121, 2, 2, 2, 7, 7, 2, 2,133, 2,133,133,133,133,133, + 2,133,133, 2, 2,133, 2, 2, 2, 2, 2,134,134, 2,134,134, + 134,134,134,134, 2, 2, 2,138, 2,138,138, 2, 2,143, 2,143, + 143,143,143,143, 2,143, 2, 2, 2,143,143, 2, 2,175,175, 2, + 2,145, 2, 2, 2,163, 2,163,163, 2, 2,163,163, 86, 2, 2, + 2, 63, 63, 2, 2, 63, 63, 63, 2, 63, 2, 2, 2,157,157,157, + 2, 80, 80, 2, 2, 80, 80, 80, 2,127,127,127, 2,166,166, 2, + 2, 79, 2, 2, 2,115,115,115, 2,115,115, 2, 2, 2, 2,115, + 115,159,159,159, 2,159,159, 2, 2,119,119, 2, 2, 2,119,119, + 119,167,167, 2, 2,146,146,146, 2,172, 2, 2,172, 99, 99, 99, + 2,136,139, 13, 13,155, 2, 2, 2,155,155, 2, 2, 2, 2, 2, + 155, 2, 17, 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 17, 17, 17, + 2, 2, 2, 15, 2, 2, 17, 2, 2,105,105,105, 2,105,105, 2, + 2, 1, 1, 1, 2, 0, 1, 1, 1, 0, 0, 1, 1, 2, 2, 0, + 2, 2, 0, 0, 2, 0, 2, 0, 2, 2, 2, 2,131, 2,131,131, + 131, 56, 2, 2, 56, 56, 56, 2, 56, 56, 2, 56, 56, 6, 6, 2, + 2, 2, 2, 2, 6,151, 2, 2, 2, 2, 2,151,151,160,160,160, + 2,152,152, 2, 2, 2, 2, 2,152,164,164, 2, 2,168,168,168, + 2, 2, 2, 2,168,174,174,174, 2,174,174, 2, 2, 2, 2,174, + 174, 2, 30, 30, 2,113, 2, 2,113,113,113,113, 2,132,132, 2, + 2, 2, 2,132,132, 2, 2, 3, 2, 3, 2, 3, 2, 15, 0, 0, + 2, 0, 2, 2, 0, 13, 2, 2, 2, 2, 0, 2, 2, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 10, 0, 11, 12, 13, 0, + 0, 0, 14, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,176,177, 0, 0, 0, 0,178,179, 0, 0, 0, - 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,207,208,209,210,211, - 212,213, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 0, 0, 0, 0, 18, + 0, 0, 0, 0, 0, 19, 20, 21, 0, 22, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, + 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 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, 27, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,162, 0,163, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,164,165, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, + 0, 0, 0,168,169, 0, 0,170, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,171, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,172, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,173, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,174, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 176,177, 0, 0, 0, 0,178,179, 0, 0, 0,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,207,208,209,210,211,212,213, 0, 0, 0, + 0, 0, 0, 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 uint16_t _hb_ucd_u16[10904]= +static const uint16_t _hb_ucd_u16[10877]= { - 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, 48, 72, 73, 48, 48, 74, 32, 75, 32, - 76, 48, 48, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 83, 84, 91, 92, 93, 94, 95, 96, 97, 84, 98, 99, 100, 88, 101, - 102, 83, 84, 103, 104, 105, 88, 106, 107, 108, 109, 110, 111, 112, 94, 113, - 114, 115, 84, 116, 117, 118, 88, 119, 120, 115, 84, 121, 122, 123, 88, 124, - 125, 115, 48, 126, 127, 128, 88, 129, 130, 131, 48, 132, 133, 134, 94, 135, - 136, 48, 48, 137, 138, 139, 140, 140, 141, 48, 142, 143, 144, 145, 140, 140, - 146, 147, 148, 149, 150, 48, 151, 152, 153, 154, 32, 155, 156, 157, 140, 140, - 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, 179, 48, 180, 181, 48, 48, 48, 48, 182, 183, - 48, 184, 48, 185, 48, 186, 187, 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, 32, 216, 217, 140, - 218, 48, 48, 219, 220, 160, 221, 222, 223, 48, 224, 64, 48, 48, 225, 226, - 48, 48, 227, 228, 229, 64, 48, 230, 231, 9, 9, 232, 233, 234, 235, 236, - 11, 11, 237, 27, 27, 27, 238, 239, 11, 240, 27, 27, 32, 32, 32, 32, - 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, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 273, 274, 275, 276, 209, 277, 278, 209, 279, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 281, 209, 282, 209, 209, 209, 209, 283, 209, 284, 280, 285, 209, 286, 287, 209, - 209, 209, 176, 140, 288, 140, 272, 272, 272, 289, 209, 209, 209, 209, 290, 272, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 291, 292, 209, 209, 293, - 209, 209, 209, 209, 209, 209, 294, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 295, 296, 272, 297, 209, 209, 298, 280, 299, 280, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 280, 280, 280, 280, 280, 280, 280, 280, 300, 301, 280, 280, 280, 302, 280, 303, - 209, 209, 209, 280, 304, 209, 209, 305, 209, 209, 209, 209, 209, 209, 209, 209, - 9, 9, 9, 11, 11, 11, 306, 307, 13, 13, 13, 13, 13, 13, 308, 309, - 11, 11, 310, 48, 48, 48, 311, 312, 48, 313, 314, 314, 314, 314, 32, 32, - 315, 316, 317, 318, 319, 320, 140, 140, 209, 321, 209, 209, 209, 209, 209, 322, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 323, 140, 209, - 324, 325, 326, 327, 136, 48, 48, 48, 48, 328, 178, 48, 48, 48, 48, 329, - 330, 48, 48, 136, 48, 48, 48, 48, 200, 331, 48, 48, 209, 209, 332, 48, - 209, 333, 334, 209, 335, 336, 209, 209, 334, 209, 209, 336, 209, 209, 209, 209, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 209, 209, 209, 209, - 48, 337, 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, 338, 48, 48, 230, - 339, 48, 340, 140, 13, 13, 341, 342, 13, 343, 48, 48, 48, 48, 344, 345, - 31, 346, 347, 348, 13, 13, 13, 349, 350, 351, 352, 353, 354, 355, 140, 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, 76, 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, 314, 11, 11, 385, 386, 11, 11, 11, 11, 11, 48, 48, 387, 192, - 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, - 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, - 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 207, 140, 140, - 392, 393, 394, 395, 396, 48, 48, 48, 48, 48, 48, 397, 398, 399, 48, 48, - 48, 48, 48, 400, 209, 48, 48, 48, 48, 401, 48, 48, 402, 140, 140, 403, - 32, 404, 32, 405, 406, 407, 408, 409, 48, 48, 48, 48, 48, 48, 48, 410, - 411, 2, 3, 4, 5, 412, 413, 414, 48, 415, 48, 200, 416, 417, 418, 419, - 420, 48, 172, 421, 204, 204, 140, 140, 48, 48, 48, 48, 48, 48, 48, 71, - 422, 272, 272, 423, 273, 273, 273, 424, 425, 426, 427, 140, 140, 209, 209, 428, - 140, 140, 140, 140, 140, 140, 140, 140, 48, 151, 48, 48, 48, 100, 429, 430, - 48, 48, 431, 48, 432, 48, 48, 433, 48, 434, 48, 48, 435, 436, 140, 140, - 9, 9, 437, 11, 11, 48, 48, 48, 48, 204, 192, 9, 9, 438, 11, 439, - 48, 48, 440, 48, 48, 48, 441, 442, 442, 443, 444, 445, 48, 48, 48, 388, - 48, 48, 48, 313, 48, 199, 440, 140, 446, 27, 27, 447, 140, 140, 140, 140, - 448, 48, 48, 449, 48, 450, 48, 451, 48, 200, 452, 140, 140, 140, 48, 453, - 48, 454, 48, 455, 48, 207, 140, 140, 48, 48, 48, 456, 272, 457, 272, 272, - 458, 459, 48, 460, 461, 462, 48, 463, 48, 464, 140, 140, 465, 48, 466, 467, - 48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474, - 48, 48, 475, 192, 476, 9, 477, 11, 478, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 272, 479, 48, 48, 480, 481, 482, 483, 140, 484, - 48, 464, 485, 48, 62, 486, 140, 48, 487, 140, 140, 48, 488, 140, 48, 313, - 489, 48, 48, 490, 491, 457, 492, 493, 223, 48, 48, 494, 495, 48, 196, 192, - 496, 48, 497, 498, 499, 48, 48, 500, 223, 48, 48, 501, 502, 503, 504, 505, - 48, 97, 506, 507, 508, 140, 140, 140, 509, 510, 511, 48, 48, 512, 513, 192, - 514, 83, 84, 515, 516, 517, 518, 519, 520, 48, 48, 521, 522, 523, 524, 140, - 48, 48, 48, 525, 526, 527, 481, 140, 48, 48, 48, 528, 529, 192, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 530, 531, 532, 533, 140, 140, - 48, 48, 48, 534, 535, 192, 536, 140, 48, 48, 537, 538, 192, 539, 540, 140, - 48, 541, 542, 543, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 506, 544, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 545, - 546, 547, 48, 548, 549, 192, 140, 140, 140, 140, 550, 48, 48, 551, 552, 140, - 553, 48, 48, 554, 555, 556, 48, 48, 557, 558, 559, 48, 48, 48, 48, 196, - 560, 140, 140, 140, 140, 140, 561, 140, 140, 140, 140, 140, 48, 48, 562, 192, - 84, 48, 530, 563, 564, 148, 175, 565, 48, 566, 567, 568, 140, 140, 140, 140, - 569, 48, 48, 570, 571, 192, 572, 48, 573, 574, 192, 48, 48, 575, 192, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 576, - 577, 115, 48, 578, 579, 580, 140, 140, 140, 140, 140, 100, 272, 581, 582, 583, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 207, 140, 140, 140, 140, 140, 140, - 273, 273, 273, 273, 273, 273, 584, 585, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 388, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 586, - 48, 48, 48, 587, 588, 589, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 71, - 48, 48, 48, 48, 313, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 590, 591, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 592, - 48, 48, 48, 593, 594, 595, 596, 597, 48, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 598, 48, 599, 192, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 9, 9, 11, 11, 272, 600, 9, 601, 11, 602, 140, 140, - 48, 48, 48, 48, 603, 604, 605, 605, 606, 607, 140, 140, 140, 140, 608, 609, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 140, 610, - 48, 200, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 48, 611, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 612, - 48, 48, 611, 613, 140, 614, 615, 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, - 48, 48, 48, 48, 48, 48, 71, 151, 196, 616, 617, 140, 140, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 618, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 619, 209, 427, 209, 620, - 32, 32, 216, 32, 621, 209, 209, 209, 209, 209, 209, 209, 322, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 323, - 209, 209, 622, 209, 209, 209, 623, 624, 625, 209, 626, 209, 209, 209, 288, 140, - 209, 209, 209, 209, 627, 140, 140, 140, 140, 140, 140, 140, 272, 628, 272, 628, - 209, 209, 209, 209, 209, 338, 272, 461, 140, 140, 140, 140, 140, 140, 140, 140, - 9, 629, 11, 630, 631, 632, 242, 9, 633, 634, 635, 636, 637, 9, 629, 11, - 638, 639, 11, 640, 641, 642, 643, 9, 644, 11, 9, 629, 11, 630, 631, 11, - 242, 9, 633, 643, 9, 644, 11, 9, 629, 11, 645, 9, 646, 647, 648, 649, - 11, 650, 9, 651, 652, 653, 654, 11, 655, 9, 656, 11, 657, 539, 539, 539, - 32, 32, 32, 658, 32, 32, 659, 660, 661, 662, 45, 140, 140, 140, 140, 140, - 663, 664, 665, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 666, 667, 668, 27, 27, 27, 669, 140, 670, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 151, 671, 672, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 673, 140, 48, 48, 674, 675, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 676, 192, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 590, 677, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 200, 678, 679, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 680, 200, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 681, 621, 140, 140, - 9, 9, 633, 11, 682, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 504, 272, 272, 683, 684, 140, 140, 140, 140, - 504, 272, 685, 686, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 687, 48, 688, 689, 690, 691, 692, 693, 694, 206, 695, 206, 140, 140, 140, 696, - 209, 209, 697, 209, 209, 209, 209, 209, 209, 322, 333, 698, 698, 698, 209, 323, - 699, 209, 209, 209, 209, 209, 209, 209, 209, 209, 700, 140, 140, 140, 701, 209, - 702, 209, 209, 697, 703, 704, 323, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 705, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 706, 426, 426, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 176, 697, 427, - 697, 209, 209, 209, 707, 176, 209, 209, 707, 209, 700, 697, 704, 708, 140, 140, - 209, 209, 209, 209, 209, 707, 700, 426, 709, 209, 209, 209, 710, 711, 712, 703, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 713, 209, 209, 209, 209, 209, 714, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 140, 140, - 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, 204, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 100, 48, - 48, 48, 48, 48, 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 207, 140, 140, 140, 140, 140, 140, 140, 140, - 715, 140, 587, 587, 587, 587, 587, 587, 140, 140, 140, 140, 140, 140, 140, 140, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140, - 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 716, - 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 717, - 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, 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, 27, 27, 45, 27, 27, 27, 27, 46, 27, - 47, 47, 47, 47, 47, 48, 49, 47, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 108, 109, 110, 111, 108, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 121, 122, 121, 123, 124, 124, 125, 126, 127, 128, 129, 130, 124, 124, - 131, 131, 131, 131, 132, 131, 133, 134, 131, 132, 131, 135, 135, 136, 124, 124, - 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 138, 138, 139, 138, 138, 140, - 141, 141, 141, 141, 141, 141, 141, 141, 142, 142, 142, 142, 143, 144, 142, 142, - 143, 142, 142, 145, 146, 147, 142, 142, 142, 146, 142, 142, 142, 148, 142, 149, - 142, 150, 151, 151, 151, 151, 151, 152, 153, 153, 153, 153, 153, 153, 153, 153, - 154, 155, 156, 156, 156, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 167, 167, 167, 167, 168, 169, 169, 170, 171, 172, 172, 172, 172, 172, 173, - 172, 172, 174, 153, 153, 153, 153, 175, 176, 177, 178, 178, 179, 180, 181, 182, - 183, 183, 184, 183, 185, 186, 167, 167, 187, 188, 189, 189, 189, 190, 189, 191, - 192, 192, 193, 8, 8, 194, 195, 124, 196, 196, 196, 196, 197, 196, 196, 196, - 198, 198, 198, 198, 199, 199, 199, 200, 201, 201, 201, 202, 203, 204, 204, 204, - 205, 138, 138, 206, 207, 208, 209, 210, 4, 4, 211, 4, 4, 212, 213, 214, - 4, 4, 4, 215, 8, 8, 8, 8, 11, 216, 11, 11, 216, 217, 11, 218, - 11, 11, 11, 219, 219, 220, 11, 221, 222, 0, 0, 0, 0, 0, 223, 224, - 225, 226, 0, 0, 227, 8, 8, 228, 0, 0, 229, 230, 231, 0, 4, 4, - 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 233, 124, 234, 124, 0, 0, 235, 235, 235, 235, 235, 235, 235, 235, - 0, 0, 0, 0, 0, 0, 0, 236, 237, 237, 237, 237, 237, 237, 4, 4, - 238, 238, 238, 238, 238, 238, 238, 239, 138, 138, 139, 240, 240, 240, 241, 242, - 142, 243, 244, 244, 244, 244, 14, 14, 0, 0, 0, 0, 0, 245, 124, 124, - 246, 247, 246, 246, 246, 246, 246, 248, 246, 246, 246, 246, 246, 246, 246, 246, - 246, 246, 246, 246, 246, 249, 124, 0, 250, 0, 251, 252, 253, 254, 254, 254, - 254, 255, 256, 257, 257, 257, 257, 258, 259, 260, 260, 261, 141, 141, 141, 141, - 262, 0, 260, 260, 0, 0, 263, 257, 141, 262, 0, 0, 0, 0, 141, 264, - 0, 0, 0, 0, 0, 257, 257, 265, 257, 257, 257, 257, 257, 266, 0, 0, - 246, 246, 246, 246, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267, - 268, 267, 267, 267, 269, 270, 270, 270, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 272, 124, 14, 14, 14, 14, 14, 14, 273, 273, 273, 273, 273, 274, - 0, 0, 275, 4, 4, 4, 4, 4, 276, 4, 4, 4, 4, 226, 124, 277, - 278, 278, 279, 233, 280, 280, 280, 281, 282, 282, 282, 282, 283, 284, 47, 47, - 285, 285, 286, 287, 287, 288, 141, 289, 290, 290, 290, 290, 291, 292, 137, 293, - 294, 294, 294, 295, 296, 297, 137, 137, 298, 298, 298, 298, 299, 300, 301, 302, - 303, 304, 244, 4, 4, 305, 306, 151, 151, 151, 151, 151, 301, 301, 307, 308, - 141, 141, 309, 141, 310, 141, 141, 311, 124, 124, 124, 124, 124, 124, 124, 124, - 246, 246, 246, 246, 246, 246, 312, 246, 246, 246, 246, 246, 246, 313, 124, 124, - 314, 315, 21, 316, 317, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 318, 27, 27, 27, 27, 27, 27, 27, 27, 27, 124, 124, 27, - 8, 233, 319, 0, 0, 320, 321, 322, 27, 27, 27, 27, 27, 27, 27, 323, - 324, 0, 1, 2, 1, 2, 325, 256, 257, 326, 141, 262, 327, 328, 329, 330, - 331, 332, 333, 334, 335, 335, 124, 124, 332, 332, 332, 332, 332, 332, 332, 336, - 337, 0, 0, 338, 11, 11, 11, 11, 339, 340, 341, 124, 124, 0, 0, 342, - 343, 344, 345, 345, 345, 346, 347, 348, 349, 349, 350, 351, 352, 353, 353, 354, - 355, 356, 357, 357, 358, 359, 124, 124, 360, 360, 360, 360, 360, 361, 361, 361, - 362, 363, 364, 365, 365, 366, 365, 367, 368, 368, 369, 370, 370, 370, 371, 372, - 372, 373, 374, 375, 376, 376, 376, 377, 378, 378, 378, 378, 378, 378, 378, 378, - 378, 378, 378, 379, 378, 380, 381, 124, 382, 4, 4, 383, 124, 124, 124, 124, - 384, 385, 385, 386, 387, 388, 389, 389, 390, 391, 392, 124, 124, 124, 393, 394, - 395, 396, 397, 398, 399, 400, 124, 124, 401, 401, 402, 403, 402, 404, 402, 402, - 405, 406, 407, 408, 409, 409, 410, 410, 411, 411, 124, 124, 412, 412, 413, 414, - 415, 415, 415, 416, 417, 418, 419, 420, 421, 422, 423, 124, 124, 124, 124, 124, - 424, 424, 424, 424, 425, 124, 124, 124, 426, 426, 426, 427, 426, 426, 426, 428, - 429, 429, 430, 431, 432, 432, 433, 432, 434, 124, 124, 124, 124, 124, 124, 124, - 124, 124, 124, 124, 124, 124, 27, 435, 436, 436, 437, 438, 439, 440, 124, 441, - 442, 442, 443, 444, 444, 445, 124, 446, 447, 124, 124, 448, 449, 124, 450, 451, - 452, 452, 452, 452, 453, 454, 452, 455, 456, 456, 456, 456, 457, 458, 459, 460, - 461, 461, 461, 462, 463, 464, 464, 465, 466, 466, 466, 466, 466, 466, 467, 468, - 469, 470, 469, 469, 471, 124, 124, 124, 472, 473, 474, 475, 475, 475, 476, 477, - 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 487, 488, 489, 490, 491, 124, - 492, 492, 492, 492, 492, 493, 494, 124, 495, 495, 495, 495, 496, 497, 124, 124, - 498, 498, 498, 499, 498, 500, 124, 124, 501, 501, 501, 501, 502, 503, 504, 124, - 505, 505, 505, 506, 506, 137, 507, 124, 508, 509, 510, 508, 511, 124, 124, 124, - 512, 512, 512, 513, 124, 124, 124, 124, 124, 124, 514, 514, 514, 514, 514, 515, - 516, 517, 518, 519, 520, 521, 124, 124, 124, 124, 522, 523, 523, 522, 524, 124, - 525, 525, 525, 525, 526, 527, 527, 527, 527, 527, 528, 153, 529, 529, 529, 530, - 531, 124, 124, 124, 124, 124, 532, 124, 124, 124, 124, 124, 533, 533, 534, 535, - 536, 537, 537, 538, 539, 537, 540, 541, 541, 542, 543, 544, 124, 124, 124, 124, - 545, 546, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 555, 556, 557, 124, - 124, 124, 124, 124, 124, 124, 558, 559, 560, 561, 560, 562, 560, 563, 124, 124, - 124, 124, 124, 564, 565, 565, 565, 566, 567, 567, 567, 567, 567, 567, 567, 567, - 567, 568, 124, 124, 124, 124, 124, 124, 567, 567, 567, 567, 567, 567, 569, 570, - 567, 567, 567, 567, 571, 124, 124, 124, 124, 572, 572, 572, 572, 572, 572, 573, - 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 575, 574, 574, - 574, 574, 574, 574, 574, 574, 574, 576, 577, 577, 577, 577, 577, 577, 577, 577, - 577, 577, 577, 577, 578, 124, 124, 124, 579, 579, 579, 580, 124, 124, 124, 124, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 581, 582, 583, 584, 585, - 585, 585, 585, 586, 587, 588, 589, 590, 591, 591, 591, 591, 592, 593, 594, 595, - 591, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 596, 596, 596, 597, - 124, 124, 124, 124, 598, 598, 598, 598, 598, 599, 600, 601, 600, 602, 124, 124, - 603, 603, 603, 603, 604, 603, 603, 603, 605, 603, 124, 124, 124, 124, 606, 607, - 608, 608, 608, 608, 608, 608, 608, 608, 609, 609, 609, 609, 609, 609, 609, 609, - 609, 609, 609, 609, 609, 610, 124, 611, 608, 612, 124, 124, 124, 124, 124, 124, - 608, 608, 608, 608, 608, 608, 608, 613, 124, 124, 124, 124, 124, 124, 124, 614, - 615, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, - 254, 254, 616, 617, 124, 618, 619, 620, 620, 620, 620, 620, 620, 620, 620, 620, - 620, 620, 620, 620, 620, 620, 620, 621, 622, 622, 622, 622, 622, 622, 623, 624, - 625, 626, 627, 124, 124, 124, 124, 124, 0, 0, 0, 0, 0, 0, 0, 340, - 0, 0, 0, 628, 0, 629, 0, 629, 8, 8, 194, 8, 630, 0, 0, 0, - 0, 0, 0, 0, 627, 124, 124, 124, 0, 0, 0, 0, 0, 0, 0, 631, - 0, 0, 632, 0, 0, 0, 633, 634, 635, 0, 636, 0, 0, 0, 234, 124, - 11, 11, 11, 11, 637, 124, 124, 124, 124, 124, 124, 124, 0, 627, 0, 627, - 0, 0, 0, 0, 0, 638, 0, 639, 0, 0, 0, 0, 0, 223, 0, 0, - 0, 640, 641, 642, 643, 0, 0, 0, 644, 645, 0, 646, 647, 648, 0, 0, - 0, 0, 649, 0, 0, 0, 0, 0, 0, 0, 0, 0, 650, 0, 0, 0, - 651, 651, 651, 651, 651, 651, 651, 651, 652, 653, 654, 124, 124, 124, 124, 124, - 4, 655, 656, 124, 124, 124, 124, 124, 657, 658, 659, 14, 14, 14, 660, 124, - 661, 124, 124, 124, 124, 124, 124, 124, 662, 662, 663, 664, 665, 124, 124, 124, - 124, 666, 667, 124, 668, 668, 668, 669, 124, 124, 124, 124, 124, 670, 670, 671, - 124, 124, 124, 124, 124, 672, 672, 673, 124, 124, 124, 124, 674, 675, 674, 676, - 124, 124, 124, 124, 124, 124, 677, 678, 679, 679, 679, 679, 679, 679, 679, 679, - 679, 679, 679, 679, 680, 681, 124, 124, 682, 682, 682, 682, 683, 684, 124, 124, - 124, 124, 124, 124, 124, 124, 124, 324, 0, 0, 0, 685, 124, 124, 124, 124, - 324, 0, 0, 245, 124, 124, 124, 124, 686, 27, 687, 688, 689, 690, 691, 692, - 693, 694, 695, 694, 124, 124, 124, 696, 0, 0, 348, 0, 0, 0, 0, 0, - 0, 627, 225, 324, 324, 324, 0, 631, 0, 0, 245, 124, 124, 124, 697, 0, - 698, 0, 0, 348, 639, 227, 631, 124, 0, 0, 0, 0, 0, 699, 340, 340, - 0, 0, 0, 0, 0, 233, 348, 629, 348, 0, 0, 0, 700, 233, 0, 0, - 700, 0, 245, 348, 227, 639, 124, 124, 0, 0, 0, 0, 0, 700, 245, 340, - 701, 0, 0, 0, 702, 703, 704, 639, 0, 320, 0, 0, 0, 0, 0, 234, - 246, 246, 246, 246, 246, 246, 124, 124, 246, 312, 246, 246, 246, 246, 246, 246, - 246, 246, 312, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 705, 246, - 246, 246, 246, 246, 246, 312, 124, 124, 246, 312, 124, 124, 124, 124, 124, 124, - 246, 246, 246, 246, 706, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 313, - 707, 124, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 0, 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, 10, 11, - 12, 13, 14, 15, 8, 8, 8, 8, 16, 8, 8, 8, 17, 18, 18, 18, - 19, 19, 19, 19, 19, 20, 19, 19, 21, 22, 22, 22, 22, 22, 22, 22, - 22, 23, 21, 22, 22, 22, 23, 21, 24, 25, 25, 25, 25, 25, 25, 25, - 25, 25, 12, 12, 25, 25, 26, 27, 25, 28, 12, 12, 29, 30, 29, 31, - 29, 29, 32, 32, 29, 29, 29, 29, 31, 29, 33, 7, 7, 34, 29, 29, - 35, 29, 29, 29, 29, 29, 29, 30, 36, 36, 36, 37, 36, 36, 36, 36, - 36, 36, 38, 39, 40, 40, 40, 40, 41, 12, 12, 12, 42, 42, 42, 42, - 42, 42, 43, 44, 45, 45, 45, 45, 45, 45, 45, 46, 45, 45, 45, 47, - 48, 48, 48, 48, 48, 48, 48, 49, 36, 36, 38, 12, 50, 51, 29, 29, - 52, 29, 29, 29, 53, 53, 53, 53, 54, 55, 53, 53, 53, 56, 53, 53, - 57, 58, 57, 59, 59, 57, 57, 57, 57, 57, 60, 57, 61, 62, 63, 57, - 57, 59, 59, 64, 12, 65, 12, 66, 57, 62, 57, 57, 57, 57, 57, 64, - 67, 67, 68, 69, 70, 71, 71, 71, 71, 71, 72, 71, 72, 73, 74, 72, - 68, 69, 70, 74, 75, 12, 67, 76, 12, 77, 71, 71, 71, 68, 12, 12, - 78, 78, 79, 80, 80, 79, 79, 79, 79, 79, 81, 79, 81, 78, 82, 79, - 79, 80, 80, 82, 83, 12, 12, 12, 79, 84, 79, 79, 82, 12, 78, 79, - 85, 85, 86, 87, 87, 86, 86, 86, 86, 86, 88, 86, 88, 85, 89, 86, - 86, 87, 87, 89, 12, 85, 12, 90, 86, 91, 86, 86, 86, 86, 12, 12, - 92, 93, 94, 92, 95, 96, 97, 95, 98, 99, 94, 92, 100, 100, 96, 92, - 94, 92, 95, 96, 99, 98, 12, 12, 12, 92, 100, 100, 100, 100, 94, 12, - 101, 101, 101, 102, 102, 101, 101, 101, 101, 101, 102, 101, 101, 101, 103, 101, - 101, 102, 102, 103, 12, 104, 105, 103, 101, 106, 101, 101, 12, 107, 101, 101, - 108, 108, 108, 109, 109, 108, 108, 108, 108, 108, 109, 108, 108, 110, 111, 108, - 108, 109, 109, 111, 12, 112, 12, 113, 108, 114, 108, 108, 110, 12, 12, 12, - 115, 115, 115, 116, 116, 115, 115, 115, 115, 115, 115, 115, 115, 116, 116, 115, - 12, 115, 115, 115, 115, 117, 115, 115, 118, 118, 119, 119, 119, 120, 121, 119, - 119, 119, 119, 119, 122, 119, 119, 123, 119, 120, 124, 125, 119, 126, 119, 119, - 12, 121, 119, 119, 121, 127, 12, 12, 128, 129, 129, 129, 129, 129, 129, 129, - 129, 129, 130, 131, 129, 129, 129, 12, 12, 12, 12, 12, 132, 133, 134, 135, - 135, 135, 135, 135, 135, 136, 135, 135, 135, 135, 135, 137, 135, 138, 135, 134, - 135, 135, 137, 135, 139, 139, 139, 139, 139, 139, 140, 139, 139, 139, 139, 141, - 140, 139, 139, 139, 139, 139, 139, 142, 139, 143, 144, 12, 145, 145, 145, 145, - 146, 146, 146, 146, 146, 147, 12, 148, 146, 146, 149, 146, 150, 150, 150, 150, - 151, 151, 151, 151, 151, 151, 152, 153, 151, 154, 152, 153, 152, 153, 151, 154, - 152, 153, 151, 151, 151, 154, 151, 151, 151, 151, 154, 155, 151, 151, 151, 156, - 151, 151, 153, 12, 157, 157, 157, 157, 157, 158, 157, 158, 159, 159, 159, 159, - 160, 160, 160, 160, 160, 160, 160, 161, 162, 162, 162, 162, 162, 162, 163, 164, - 162, 162, 165, 12, 166, 166, 166, 166, 166, 167, 12, 168, 169, 169, 169, 169, - 169, 170, 12, 12, 171, 171, 171, 171, 171, 12, 12, 12, 172, 172, 172, 173, - 173, 12, 12, 12, 174, 174, 174, 174, 174, 174, 174, 175, 174, 174, 175, 12, - 176, 177, 178, 178, 178, 178, 179, 12, 178, 178, 178, 178, 178, 178, 180, 12, - 178, 178, 181, 12, 159, 182, 12, 12, 183, 183, 183, 183, 183, 183, 183, 184, - 183, 183, 183, 12, 185, 183, 183, 183, 186, 186, 186, 186, 186, 186, 186, 187, - 186, 188, 12, 12, 189, 189, 189, 189, 189, 189, 189, 12, 189, 189, 190, 12, - 189, 189, 191, 192, 193, 193, 193, 193, 193, 193, 193, 194, 195, 195, 195, 195, - 195, 195, 195, 196, 195, 195, 195, 197, 195, 195, 198, 12, 195, 195, 195, 198, - 7, 7, 7, 199, 7, 7, 7, 12, 200, 200, 200, 200, 200, 200, 200, 201, - 202, 202, 202, 202, 203, 203, 203, 203, 203, 12, 12, 203, 204, 204, 204, 204, - 204, 204, 205, 204, 204, 204, 206, 207, 208, 208, 208, 208, 19, 19, 209, 12, - 146, 146, 210, 211, 202, 202, 12, 12, 212, 7, 7, 7, 213, 7, 214, 215, - 0, 214, 216, 12, 2, 217, 218, 2, 2, 2, 2, 219, 220, 217, 221, 2, - 2, 2, 222, 2, 2, 2, 2, 223, 8, 224, 8, 224, 8, 8, 225, 225, - 8, 8, 8, 224, 8, 15, 8, 8, 8, 10, 8, 226, 10, 15, 8, 14, - 0, 0, 0, 227, 0, 228, 0, 0, 229, 0, 0, 230, 0, 0, 0, 231, - 2, 2, 2, 232, 233, 12, 12, 12, 234, 12, 12, 12, 0, 235, 236, 0, - 4, 0, 0, 0, 0, 0, 0, 4, 2, 2, 5, 12, 0, 0, 233, 12, - 0, 0, 231, 12, 237, 237, 237, 237, 0, 238, 0, 0, 239, 239, 239, 239, - 18, 18, 18, 18, 18, 12, 240, 18, 241, 241, 241, 241, 241, 241, 12, 242, - 243, 12, 12, 242, 151, 154, 12, 12, 151, 154, 151, 154, 0, 0, 0, 233, - 244, 244, 244, 244, 244, 244, 245, 244, 244, 12, 12, 12, 244, 246, 12, 12, - 0, 247, 0, 0, 248, 244, 249, 250, 0, 0, 244, 0, 251, 252, 252, 252, - 252, 252, 252, 252, 252, 253, 254, 255, 256, 257, 257, 257, 257, 257, 257, 257, - 257, 257, 258, 256, 12, 259, 260, 260, 260, 260, 260, 260, 261, 150, 150, 150, - 150, 150, 150, 262, 0, 233, 12, 131, 150, 150, 150, 263, 257, 257, 257, 258, - 257, 257, 0, 0, 264, 264, 264, 264, 264, 264, 264, 265, 264, 266, 12, 12, - 267, 267, 267, 267, 268, 268, 268, 268, 268, 268, 268, 12, 269, 269, 269, 269, - 269, 269, 12, 12, 236, 2, 2, 2, 2, 2, 230, 2, 270, 2, 2, 2, - 271, 271, 271, 271, 271, 271, 271, 272, 273, 273, 273, 273, 273, 273, 12, 12, - 274, 274, 274, 274, 274, 275, 12, 276, 274, 274, 275, 12, 277, 277, 277, 277, - 277, 277, 277, 278, 279, 279, 279, 279, 279, 12, 12, 280, 150, 150, 150, 281, - 282, 282, 282, 282, 282, 282, 282, 283, 282, 282, 284, 285, 145, 145, 145, 286, - 287, 287, 287, 287, 287, 288, 12, 12, 287, 287, 287, 289, 287, 287, 289, 287, - 290, 290, 290, 290, 291, 12, 12, 12, 12, 12, 292, 290, 293, 293, 293, 293, - 293, 294, 12, 12, 155, 154, 155, 154, 155, 154, 12, 12, 2, 2, 3, 2, - 2, 295, 296, 12, 293, 293, 293, 297, 293, 293, 297, 12, 150, 12, 12, 12, - 150, 262, 298, 150, 150, 150, 150, 12, 244, 244, 244, 246, 244, 244, 246, 12, - 2, 299, 12, 12, 300, 22, 12, 24, 25, 26, 25, 301, 302, 303, 25, 25, - 29, 29, 29, 304, 7, 7, 7, 305, 231, 0, 0, 0, 0, 231, 0, 12, - 29, 306, 29, 29, 29, 29, 29, 307, 308, 0, 0, 0, 0, 309, 257, 257, - 257, 257, 257, 310, 311, 150, 311, 150, 311, 150, 311, 281, 0, 231, 0, 231, - 12, 12, 308, 233, 312, 312, 312, 313, 312, 312, 312, 312, 312, 314, 312, 312, - 312, 312, 314, 315, 312, 312, 312, 316, 312, 312, 314, 12, 231, 131, 0, 0, - 0, 131, 0, 0, 8, 8, 8, 14, 0, 0, 0, 317, 318, 12, 12, 12, - 0, 0, 0, 319, 320, 320, 320, 320, 320, 320, 320, 321, 322, 322, 322, 322, - 323, 12, 12, 12, 214, 0, 0, 0, 0, 0, 0, 12, 324, 324, 324, 324, - 324, 12, 12, 325, 326, 326, 326, 326, 326, 326, 327, 12, 328, 328, 328, 328, - 328, 328, 329, 12, 330, 330, 330, 330, 330, 330, 330, 331, 332, 332, 332, 332, - 332, 12, 332, 332, 332, 333, 12, 12, 334, 334, 334, 334, 335, 335, 335, 335, - 336, 336, 336, 336, 336, 336, 336, 337, 336, 336, 337, 12, 338, 338, 338, 338, - 338, 12, 338, 338, 338, 338, 338, 12, 339, 339, 339, 339, 339, 339, 12, 12, - 340, 340, 340, 340, 340, 12, 12, 341, 342, 342, 343, 342, 343, 344, 342, 342, - 344, 342, 342, 342, 344, 342, 344, 345, 346, 346, 346, 346, 346, 12, 12, 12, - 347, 347, 347, 347, 347, 348, 12, 12, 347, 349, 12, 12, 347, 347, 12, 12, - 2, 350, 2, 2, 351, 2, 299, 12, 352, 353, 354, 352, 352, 352, 352, 352, - 352, 355, 356, 357, 358, 358, 358, 358, 358, 359, 358, 358, 360, 360, 360, 360, - 361, 361, 361, 361, 361, 361, 361, 362, 12, 363, 361, 361, 364, 364, 364, 364, - 365, 366, 367, 364, 368, 368, 368, 368, 368, 368, 368, 369, 370, 370, 370, 370, - 370, 370, 371, 372, 373, 373, 373, 373, 373, 373, 374, 12, 375, 375, 375, 375, - 376, 376, 376, 376, 376, 376, 12, 376, 377, 376, 376, 376, 378, 379, 12, 378, - 378, 380, 380, 378, 378, 378, 378, 378, 378, 381, 382, 383, 378, 378, 384, 12, - 385, 385, 385, 385, 386, 386, 386, 386, 387, 387, 387, 387, 387, 388, 389, 387, - 387, 388, 12, 12, 390, 390, 390, 390, 390, 391, 392, 390, 393, 393, 393, 393, - 393, 394, 393, 393, 395, 395, 395, 395, 396, 12, 395, 395, 397, 397, 397, 397, - 398, 12, 399, 400, 12, 12, 399, 397, 401, 401, 401, 401, 401, 401, 402, 12, - 403, 403, 403, 403, 404, 12, 12, 12, 404, 12, 405, 403, 406, 406, 406, 406, - 406, 406, 12, 12, 406, 406, 407, 12, 408, 408, 408, 408, 408, 409, 410, 408, - 408, 409, 12, 411, 29, 29, 29, 412, 413, 413, 413, 413, 413, 413, 414, 415, - 415, 12, 12, 12, 416, 29, 12, 12, 29, 29, 417, 12, 12, 12, 416, 29, - 418, 418, 418, 418, 418, 418, 12, 12, 419, 419, 419, 419, 419, 419, 420, 12, - 421, 421, 421, 421, 421, 421, 422, 12, 423, 423, 423, 423, 423, 423, 423, 12, - 424, 424, 424, 424, 424, 425, 12, 12, 426, 426, 426, 426, 426, 426, 426, 427, - 428, 426, 426, 426, 426, 427, 12, 429, 430, 430, 430, 430, 431, 12, 12, 432, - 433, 433, 433, 433, 433, 433, 434, 12, 433, 433, 435, 12, 436, 436, 436, 436, - 436, 437, 436, 436, 436, 436, 12, 12, 438, 438, 438, 438, 438, 439, 12, 12, - 440, 440, 440, 440, 118, 119, 119, 119, 119, 127, 12, 12, 441, 441, 441, 441, - 442, 441, 441, 441, 443, 12, 12, 12, 444, 445, 446, 447, 444, 444, 444, 447, - 444, 444, 448, 12, 449, 449, 449, 449, 449, 449, 450, 12, 449, 449, 451, 12, - 452, 453, 452, 454, 454, 452, 452, 452, 452, 452, 455, 452, 455, 453, 456, 452, - 452, 454, 454, 457, 458, 459, 12, 453, 452, 460, 452, 458, 452, 458, 12, 12, - 461, 461, 462, 463, 461, 461, 461, 461, 461, 462, 461, 461, 464, 465, 466, 461, - 461, 462, 467, 12, 468, 12, 12, 12, 469, 469, 469, 469, 469, 469, 469, 470, - 471, 12, 12, 12, 472, 472, 472, 472, 472, 472, 12, 12, 472, 472, 473, 12, - 474, 474, 474, 474, 474, 475, 474, 474, 474, 474, 474, 475, 476, 476, 476, 476, - 476, 477, 12, 12, 476, 476, 478, 12, 178, 178, 178, 180, 479, 479, 479, 479, - 479, 479, 480, 12, 145, 12, 12, 12, 481, 481, 481, 481, 481, 481, 482, 483, - 481, 481, 481, 12, 481, 482, 12, 12, 484, 484, 484, 484, 484, 484, 484, 12, - 485, 485, 485, 485, 486, 12, 12, 487, 488, 489, 490, 488, 488, 491, 488, 488, - 488, 488, 488, 488, 488, 492, 493, 488, 488, 489, 12, 12, 488, 488, 494, 12, - 495, 495, 496, 495, 495, 495, 495, 495, 495, 497, 12, 12, 498, 498, 498, 498, - 498, 498, 12, 12, 499, 499, 499, 499, 500, 12, 12, 12, 501, 501, 501, 501, - 501, 501, 502, 12, 53, 53, 503, 12, 440, 440, 12, 12, 504, 504, 504, 504, - 505, 12, 12, 12, 504, 504, 505, 12, 506, 506, 507, 506, 506, 506, 506, 506, - 506, 508, 506, 506, 506, 509, 12, 12, 506, 506, 506, 510, 511, 511, 511, 511, - 512, 511, 511, 511, 511, 511, 513, 511, 511, 514, 12, 12, 515, 516, 517, 515, - 515, 515, 515, 515, 515, 516, 518, 517, 515, 515, 12, 12, 515, 515, 519, 12, - 520, 521, 522, 520, 520, 520, 520, 520, 520, 520, 520, 523, 521, 520, 524, 12, - 520, 520, 525, 12, 526, 526, 526, 526, 526, 526, 526, 12, 526, 526, 527, 12, - 528, 528, 528, 528, 528, 528, 529, 12, 530, 530, 530, 530, 531, 530, 530, 530, - 530, 530, 532, 533, 530, 530, 532, 12, 534, 12, 12, 12, 100, 100, 100, 100, - 96, 12, 12, 98, 535, 535, 535, 535, 535, 535, 536, 12, 535, 535, 535, 537, - 535, 538, 12, 12, 535, 12, 12, 12, 539, 539, 539, 539, 540, 12, 12, 12, - 541, 541, 541, 541, 541, 542, 12, 12, 541, 541, 543, 12, 544, 544, 544, 544, - 544, 545, 12, 12, 546, 546, 546, 546, 546, 546, 547, 12, 269, 269, 548, 12, - 549, 549, 549, 549, 549, 549, 549, 550, 549, 549, 551, 552, 553, 553, 553, 553, - 553, 553, 553, 554, 553, 553, 555, 12, 556, 556, 556, 556, 556, 556, 556, 557, - 556, 557, 12, 12, 558, 558, 558, 558, 558, 559, 12, 12, 558, 558, 560, 558, - 560, 558, 558, 558, 558, 558, 12, 561, 562, 562, 562, 562, 562, 562, 563, 12, - 564, 564, 564, 564, 564, 564, 565, 12, 566, 566, 566, 566, 566, 566, 567, 566, - 566, 12, 12, 12, 568, 568, 568, 568, 568, 568, 569, 570, 568, 568, 12, 570, - 571, 572, 12, 12, 244, 573, 12, 12, 574, 574, 574, 574, 575, 575, 575, 575, - 575, 576, 12, 12, 12, 12, 12, 577, 574, 574, 574, 578, 578, 12, 12, 12, - 257, 579, 257, 580, 581, 252, 252, 252, 582, 12, 12, 12, 583, 12, 12, 12, - 253, 584, 12, 12, 12, 257, 12, 12, 585, 585, 585, 585, 585, 585, 585, 12, - 586, 586, 586, 586, 586, 586, 587, 12, 586, 586, 586, 588, 586, 586, 588, 12, - 586, 586, 589, 586, 0, 12, 12, 12, 0, 12, 238, 0, 317, 12, 12, 12, - 7, 590, 12, 12, 0, 233, 12, 12, 0, 231, 308, 0, 0, 591, 227, 0, - 0, 0, 591, 7, 212, 592, 7, 0, 0, 0, 593, 227, 8, 224, 12, 12, - 0, 231, 12, 12, 0, 0, 317, 12, 0, 0, 0, 228, 594, 595, 308, 228, - 0, 0, 596, 308, 0, 308, 0, 0, 0, 596, 231, 308, 0, 228, 0, 228, - 0, 0, 596, 231, 0, 597, 238, 0, 228, 0, 0, 0, 0, 233, 0, 0, - 0, 0, 0, 238, 598, 598, 598, 598, 598, 598, 598, 12, 12, 12, 599, 598, - 600, 598, 598, 598, 2, 2, 2, 299, 12, 270, 299, 12, 239, 601, 239, 239, - 239, 239, 602, 239, 603, 604, 601, 12, 19, 19, 19, 605, 12, 12, 12, 606, - 607, 607, 607, 607, 607, 607, 607, 608, 607, 607, 607, 609, 607, 607, 609, 610, - 611, 611, 611, 611, 611, 611, 611, 612, 613, 613, 613, 613, 613, 613, 614, 615, - 616, 616, 616, 616, 616, 616, 617, 12, 618, 618, 618, 618, 618, 618, 619, 620, - 621, 621, 621, 621, 621, 621, 621, 622, 621, 623, 12, 624, 151, 154, 151, 625, - 151, 151, 151, 154, 626, 626, 626, 626, 626, 627, 626, 626, 626, 628, 12, 12, - 629, 629, 629, 629, 629, 629, 629, 12, 629, 629, 630, 631, 0, 317, 12, 12, - 29, 632, 29, 29, 633, 634, 632, 29, 412, 29, 635, 12, 636, 51, 635, 632, - 633, 634, 635, 635, 633, 634, 412, 29, 412, 29, 632, 637, 29, 29, 638, 29, - 29, 29, 29, 12, 632, 632, 638, 29, 50, 12, 12, 12, 12, 238, 0, 0, - 639, 12, 12, 12, 0, 0, 317, 0, 0, 0, 12, 12, 0, 0, 231, 238, - 0, 231, 317, 308, 0, 0, 0, 640, 0, 0, 231, 131, 641, 12, 12, 12, - 244, 244, 573, 12, 642, 12, 12, 12, 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, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 224, 224, 768, 424, 432, 440, 448, 776, 224, 224, 784, 792, 72, 800, 40, 808, + 48, 48, 48, 816, 824, 48, 48, 832, 840, 848, 856, 864, 872, 880, 48, 888, + 48, 48, 48, 896, 904, 40, 40, 40, 40, 912, 40, 96, 920, 928, 936, 456, + 64, 64, 64, 64, 64, 64, 64, 944, 952, 960, 968, 40, 976, 984, 48, 992, + 72, 72, 72, 40, 40, 40, 48, 48,1000, 48, 48, 48,1008, 48, 48, 48, + 48, 48, 48,1016, 72,1024, 40, 40,1032, 464, 64,1040,1048, 8,1056,1064, + 1072,1080, 8, 8,1088, 64,1096,1104, 8, 8, 8, 8, 8,1112,1120,1128, + 1136,1144, 8, 64,1152, 8, 8, 8, 8, 8, 472,1160, 232, 8,1168,1176, + 8,1184,1192,1200, 8,1208, 176, 8,1216,1224, 8, 8,1232, 64,1240, 64, + 480, 8, 8,1248,1256,1264,1272,1280,1288, 240, 128,1296,1304,1312, 144,1320, + 1328, 240, 128,1336,1344,1352, 304,1360,1368, 488, 128,1376,1384, 248, 144,1392, + 1400, 240, 128,1408,1416,1424, 144,1432,1440,1448,1456,1464,1472,1480, 304,1488, + 1496, 256, 128,1504,1512,1520, 144,1528,1536, 256, 128,1544,1552,1560, 144,1568, + 1576, 256, 8,1584,1592,1600, 144,1608,1616,1624, 8,1632,1640,1648, 304,1656, + 312, 8, 8,1664,1672,1680, 0, 0,1688, 8,1696,1704,1712,1720, 0, 0, + 1728,1736, 320,1744,1752, 8, 152,1760,1768,1776, 64,1784,1792,1800, 0, 0, + 8, 8,1808,1816, 496,1824,1832,1840,1848,1856, 72, 72,1864, 40, 40,1872, + 8, 8, 8, 8, 504,1880, 8, 8, 504, 8, 8,1888, 512, 520, 8, 8, + 8, 512, 8, 8, 8,1896,1904, 528, 8, 264, 72, 72, 72, 72, 72,1912, + 536, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8,1920, 8,1928,1936, 8, 8, 8, 8,1944,1952, + 8,1960, 8,1968, 8,1976,1984,1992, 8, 8, 8,2000,2008,2016, 80,2024, + 2032, 80, 8, 8,2040, 8, 8, 160,2048, 8,2056, 8, 8, 8, 8, 328, + 8, 120,2064,2072,2080, 8, 112,2088, 8, 8, 184, 8, 192,2096, 24, 24, + 8,2104, 8, 8, 8,2112,2120,2128, 80, 80,2136,2144, 64, 544,2152, 0, + 2160, 8, 8,2168,2176, 496,2184,2192, 336, 8,2200, 232, 8, 8,2208,2216, + 8, 8,2224,2232,2240, 232, 8, 552,2248, 72, 72,2256,2264,2272,2280,2288, + 40, 40,2296, 96, 96, 96,2304,2312, 40,2320, 96, 96, 64, 64, 64, 64, + 48, 48, 48, 48, 48, 48, 48, 48, 48,2328, 48, 48, 48, 48, 48, 48, + 168, 560, 168, 168, 560,2336, 168,2344, 344, 344, 344,2352,2360,2368,2376,2384, + 2392,2400,2408,2416,2424,2432,2440,2448,2456,2464, 568, 568,2472,2480,2488,2496, + 2504,2512,2520,2528,2536, 88, 104, 104,2544,2552,2560, 24,2568,2576, 24,2584, + 2592, 24,2600, 24, 24, 24, 24,2608, 24,2616, 56,2624, 24,2632,2640, 24, + 24, 24, 264, 0, 576, 0, 88, 88, 88,2648, 24, 24, 24, 24,2656, 88, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,2664,2672, 24, 24,2680, + 24, 24, 24, 24, 24, 24,2688, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24,2696,2704, 88,2712, 24, 24,2720, 56,2728, 56, + 56, 56, 56, 56, 56, 56, 56, 56,2736,2744, 56, 56, 56,2752, 56,2760, + 24, 24, 24, 56,2768, 24, 24,2776, 24, 24, 24, 24, 24, 24, 24, 24, + 72, 72, 72, 40, 40, 40,2784,2792, 48, 48, 48, 48, 48, 48,2800,2808, + 40, 40,2816, 8, 8, 8,2824,2832, 8, 200, 208, 208, 208, 208, 64, 64, + 2840,2848,2856,2864,2872,2880, 0, 0, 24,2888, 24, 24, 24, 24, 24, 352, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 272, 0, 24, + 2896,2904,2912,2920, 312, 8, 8, 8, 8,2928, 536, 8, 8, 8, 8,2936, + 2944, 8, 8, 312, 8, 8, 8, 8, 120,2952, 8, 8, 24, 24,2960, 8, + 24, 584, 592, 24,2968, 600, 24, 24, 592, 24, 24, 600, 24, 24, 24, 24, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 24, 24, 24, 24, + 8,2976, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 152, 24, 24, 24, 608, 8, 8, 552, + 2984, 8,2992, 0, 48, 48,3000,3008, 48,3016, 8, 8, 8, 8,3024,3032, + 456,3040,3048,3056, 48, 48, 48,3064,3072,3080,3088,3096,3104,3112, 0,3120, + 3128, 8,3136,3144, 8, 8, 8,3152,3160, 8, 8,3168,3176, 80, 64,3184, + 232, 8,3192, 8,3200,3208, 8, 152, 480, 8, 8,3216,3224, 360,3232,3240, + 8, 8,3248,3256,3264,3272, 8,3280, 8, 8, 8,3288,3296,3304,3312,3320, + 3328,3336, 208, 40, 40,3344,3352, 40, 40, 40, 40, 40, 8, 8,3360, 80, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 368, 8,3368, 8, 8, 184, + 8, 8, 8, 8, 8, 8, 112, 8, 8, 8, 8, 8, 8, 192, 0, 0, + 3376,3384,3392,3400,3408, 8, 8, 8, 8, 8, 8,3416,3424,3432, 8, 8, + 8, 8, 8,3440, 24, 8, 8, 8, 8,3448, 8, 8,3456, 0, 0,3464, + 64,3472, 64,3480,3488,3496,3504,3512, 8, 8, 8, 8, 8, 8, 8,3520, + 3528, 424, 432, 440, 448,3536,3544,3552, 8,3560, 8, 120,3568,3576,3584,3592, + 3600, 8, 520,3608, 112, 112, 0, 0, 8, 8, 8, 8, 8, 8, 8, 176, + 3616, 88, 88,3624, 104, 104, 104,3632,3640, 280, 376, 0, 0, 24, 24,3648, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 152, 8, 8, 8, 248,3656,3664, + 8, 8,3672, 8,3680, 8, 8,3688, 8,3696, 8, 8,3704,3712, 0, 0, + 72, 72,3720, 40, 40, 8, 8, 8, 8, 112, 80, 72, 72,3728, 40,3736, + 8, 8, 616, 8, 8, 8,3744, 624, 624,3752,3760,3768, 8, 8, 8, 368, + 8, 8, 8, 200, 8, 328, 616, 0,3776, 96, 96,3784, 0, 0, 0, 0, + 3792, 8, 8,3800, 8,3808, 8,3816, 8, 120,3824, 0, 0, 0, 8,3832, + 8,3840, 8,3848, 8, 192, 0, 0, 8, 8, 8,3856, 88, 632, 88, 88, + 3864,3872, 8,3880, 640,3888, 8,3896, 8, 648, 0, 0,3904, 8,3912,3920, + 8, 8, 8,3928, 8,3936, 8,3944, 8,3952,3960, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 160, 0, 0, 0, 72, 72, 72,3968, 40, 40, 40,3976, + 8, 8,3984, 80,3992, 72,4000, 40,4008, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 88,4016, 8, 8,4024, 656,4032,4040, 0,4048, + 8, 648,4056, 8, 472,4064, 0, 8,4072, 0, 0, 8,4080, 0, 8, 200, + 4088, 8, 8,4096,4104, 632,4112,4120, 336, 8, 8,4128,4136, 8, 160, 80, + 4144, 8,4152,4160,4168, 8, 8,4176, 336, 8, 8,4184,4192,4200, 384,4208, + 8, 488, 664,4216,4224, 0, 0, 0,4232,4240,4248, 8, 8,4256,4264, 80, + 4272, 240, 128,4280,4288,4296,4304,4312,4320, 8, 8,4328,4336,4344,4352, 0, + 8, 8, 8,4360,4368,4376, 656, 0, 8, 8, 8,4384,4392, 80, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 672,4400,4408,4416, 0, 0, + 8, 8, 8,4424,4432, 80,4440, 0, 8, 8,4448,4456, 80, 288,4464, 0, + 8,4472,4480,4488, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 664,4496, 0, 0, 0, 0, 0, 0, 72, 72, 40, 40, 320,4504, + 4512,4520, 8,4528,4536, 80, 0, 0, 0, 0,4544, 8, 8,4552,4560, 0, + 4568, 8, 8,4576,4584,4592, 8, 8,4600,4608,4616, 8, 8, 8, 8, 160, + 4624, 0, 0, 0, 0, 0,4632, 0, 0, 0, 0, 0, 8, 8,4640, 80, + 128, 8, 672,4648,4656, 320, 528,4664, 8,4672,4680,4688, 0, 0, 0, 0, + 4696, 8, 8,4704,4712, 80,4720, 8,4728,4736, 80, 8, 8,4744, 80, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,4752, + 4760, 256, 8,4768,4776,4784, 0, 0, 0, 0, 0, 248, 88,4792,4800,4808, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 192, 0, 0, 0, 0, 0, 0, + 104, 104, 104, 104, 104, 104,4816,4824, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8,4832, + 8, 8, 8, 136,4840,4848, 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, 176, + 8, 8, 8, 8, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 680,4856, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 160, 8, 120, 360, 8, 8, 8, 8, 120, 80, 8, 112,4864, + 8, 8, 8,4872,4880,4888,4896,4904, 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,4912, 8,4920, 80, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 72, 72, 40, 40, 88,4928, 72,4936, 40,4944, 0, 0, + 8, 8, 8, 8,4952,4960, 688, 688,4968,4976, 0, 0, 0, 0,4984,4992, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 328, 0,5000, + 8, 120, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 696, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5008, + 8, 8, 696,5016, 0,5024,5032, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 184, + 8, 8, 8, 8, 8, 8, 176, 152, 160,5040,5048, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5056, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5064, 24, 376, 24,5072, + 64, 64, 544, 64, 704, 24, 24, 24, 24, 24, 24, 24, 352, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 272, + 24, 24,5080, 24, 24, 24,5088,5096,5104, 24,5112, 24, 24, 24, 576, 0, + 24, 24, 24, 24,5120, 0, 0, 0, 0, 0, 0, 0, 88, 712, 88, 712, + 24, 24, 24, 24, 24, 608, 88, 640, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 296, 40, 720, 728,5128, 168, 72, 392,5136,5144,5152,5160, 72, 296, 40, + 5168,5176, 40,5184,5192,5200, 736, 72, 744, 40, 72, 296, 40, 720, 728, 40, + 168, 72, 392, 736, 72, 744, 40, 72, 296, 40,5208, 72,5216,5224,5232,5240, + 40,5248, 72,5256,5264,5272,5280, 40,5288, 72,5296, 40,5304, 288, 288, 288, + 64, 64, 64,5312, 64, 64,5320,5328,5336,5344, 464, 0, 0, 0, 0, 0, + 5352,5360,5368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5376,5384,5392, 96, 96, 96,5400, 0,5408, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 152,5416,5424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5432, 0, 8, 8,5440,5448, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,5456, 80, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 680,5464, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120,5472,5480, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,5488, 120, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,5496, 704, 0, 0, + 72, 72, 392, 40,5504, 360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 384, 88, 88,5512,5520, 0, 0, 0, 0, + 384, 88,5528,5536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5544, 8,5552,5560,5568,5576,5584,5592,5600, 184,5608, 184, 0, 0, 0,5616, + 24, 24, 216, 24, 24, 24, 24, 24, 24, 352, 584, 400, 400, 400, 24, 272, + 5624, 24, 24, 24, 24, 24, 24, 24, 24, 24, 408, 0, 0, 0,5632, 24, + 5640, 24, 24, 216, 752, 760, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5648, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,5656, 280, 280, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 264, 216, 376, + 216, 24, 24, 24, 416, 264, 24, 24, 416, 24, 408, 216, 760,5664, 0, 0, + 24, 24, 24, 24, 24, 416, 408, 280,5672, 24, 24, 24,5680,5688,5696, 752, + 24, 24, 24, 24, 24, 24, 24, 24, 24,5704, 24, 24, 24, 24, 24,5712, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, + 8, 112, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 112, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 248, 8, + 8, 8, 8, 8, 8, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 176, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 192, 0, 0, 0, 0, 0, 0, 0, 0, + 5720, 0, 136, 136, 136, 136, 136, 136, 0, 0, 0, 0, 0, 0, 0, 0, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,5728, + 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, + 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, + 20, 20, 20, 20, 20, 20, 20, 20, 12, 12, 12, 12, 12, 12, 12, 12, + 24, 24, 24, 24, 24, 24, 24, 24, 28, 28, 28, 28, 28, 28, 28, 28, + 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, + 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 36, + 64, 64, 64, 64, 64, 64, 64, 64, 92, 92, 92, 92, 92, 92, 92, 92, + 84, 84, 84, 84, 84, 84, 84, 84, 80, 80, 80, 80, 80, 80, 80, 80, + 68, 68, 68, 68, 68, 68, 68, 68, 56, 56, 56, 56, 56, 56, 56, 56, + 12, 12, 12, 12, 228, 232, 228, 232, 12, 12, 468, 468, 32, 472, 32, 472, + 32, 32, 32, 692, 12, 12, 696, 12, 56, 56, 56, 56, 56, 56, 56, 700, + 704, 72, 708, 72, 72, 72, 712, 72, 60, 60, 60, 60, 60, 60, 60, 60, + 716, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 720, 308, 724, 308, 308, + 728, 732, 236, 236, 736, 236, 740, 744, 748, 752, 36, 36, 756, 760, 36, 764, + 36, 36, 36, 36, 36, 768, 36, 36, 772, 312, 312, 312, 776, 36, 36, 36, + 316, 316, 316, 780, 320, 320, 320, 784, 476, 476, 788, 792, 796, 800, 804, 36, + 36, 808, 36, 36, 36, 36, 812, 36, 112, 112, 112, 112, 112, 816, 820, 112, + 824, 828, 832, 836, 840, 844, 848, 852, 856, 860, 864, 868, 872, 876, 880, 884, + 888, 892, 896, 900, 904, 908, 912, 916, 920, 924, 928, 932, 936, 940, 944, 948, + 952, 956, 960, 964, 968, 972, 976, 980, 984, 988, 992, 996,1000,1004,1008,1012, + 1016,1020,1024,1028,1032,1036,1040,1044,1048,1052, 324, 324,1056,1060,1064, 324, + 1068,1072,1076,1080,1084,1088,1092,1096,1100, 328, 328,1104, 328,1108, 0, 0, + 1112,1116,1120,1124,1128,1132, 0, 0, 128, 128, 128, 128, 480, 128,1136,1140, + 128, 480, 128, 484, 484,1144, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 116, 116, 488, 116, 116,1148, 88, 88, 88, 88, 492,1152, 88, 88, + 492, 88, 88,1156, 496,1160, 88, 88, 88, 496, 88, 88, 88,1164, 88,1168, + 88,1172, 108, 108, 108, 108, 108,1176,1180,1184, 240, 240, 240, 240,1188,1192, + 1196,1200,1204,1208,1212,1216,1220,1224, 132, 132, 132, 132, 132,1228, 500, 500, + 1232,1236, 136, 136, 136, 136, 136,1240, 136, 136,1244, 40, 40, 40, 40,1248, + 1252,1256, 504, 504,1260,1264,1268,1272, 332, 332,1276, 332,1280,1284, 132, 132, + 1288,1292, 244, 244, 244,1296, 244,1300, 508, 508,1304, 56, 56, 512,1308, 0, + 140, 140, 140, 140,1312, 140, 140, 140, 248, 248, 248, 248, 336, 336, 336,1316, + 340, 340, 340,1320,1324, 344, 344, 344,1328, 116, 116,1332,1336,1340,1344,1348, + 32, 32,1352, 32, 32,1356,1360,1364, 32, 32, 32,1368, 56, 56, 56, 56, + 72, 516, 72, 72, 516,1372, 72,1376, 72, 72, 72, 520, 520,1380, 72,1384, + 1388, 12, 12, 12, 12, 12, 524,1392, 528, 532, 12, 12, 348, 56, 56,1396, + 12, 12,1400,1404,1408, 12, 32, 32,1412, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 176, 0, 352, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12,1416, + 148, 148, 148, 148, 148, 148, 32, 32, 144, 144, 144, 144, 144, 144, 144,1420, + 116, 116, 488, 356, 356, 356,1424,1428, 88,1432, 180, 180, 180, 180, 60, 60, + 12, 12, 12, 12, 12, 184, 0, 0, 4,1436, 4, 4, 4, 4, 4,1440, + 4, 4, 4, 4, 4,1444, 0, 12,1448, 12,1452,1456,1460, 76, 76, 76, + 76,1464, 536, 100, 100, 100, 100,1468,1472, 252, 252,1476, 8, 8, 8, 8, + 360, 12, 252, 252, 12, 12,1480, 100, 8, 360, 12, 12, 12, 12, 8,1484, + 12, 12, 12, 12, 12, 100, 100,1488, 100, 100, 100, 100, 100,1492, 12, 12, + 4, 4, 4, 4, 12, 12, 12, 12,1496, 24, 24, 24,1500, 364, 364, 364, + 84, 84,1504, 0, 60, 60, 60, 60, 60, 60, 44, 44, 44, 44, 44,1508, + 12, 12,1512, 32, 32, 32, 32, 32,1516, 32, 32, 32, 32, 532, 0,1520, + 540, 540,1524, 176, 368, 368, 368,1528, 256, 256, 256, 256,1532,1536, 112, 112, + 544, 544,1540, 548, 548,1544, 8,1548, 260, 260, 260, 260,1552,1556, 96,1560, + 372, 372, 372,1564,1568,1572, 96, 96, 264, 264, 264, 264,1576,1580, 376,1584, + 1588,1592, 180, 32, 32,1596,1600, 108, 108, 108, 108, 108, 376, 376,1604,1608, + 8, 8,1612, 8,1616, 8, 8,1620, 4, 4, 4, 4, 4, 4, 188, 4, + 4, 4, 4, 4, 4, 552, 0, 0,1624,1628, 236,1632,1636, 36, 36, 36, + 36, 36, 36,1640, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 0, 36, + 56, 176,1644, 12, 12, 556,1648,1652, 36, 36, 36, 36, 36, 36, 36,1656, + 152, 12, 228, 232, 228, 232,1660, 536, 100,1664, 8, 360,1668,1672,1676,1680, + 1684, 120,1688,1692, 560, 560, 0, 0, 120, 120, 120, 120, 120, 120, 120,1696, + 1700, 12, 12,1704, 72, 72, 72, 72,1708, 192,1712, 0, 0, 12, 12,1716, + 1720,1724, 380, 380, 380,1728,1732, 156, 564, 564,1736,1740,1744, 568, 568,1748, + 1752,1756, 572, 572,1760,1764, 0, 0, 196, 196, 196, 196, 196, 384, 384, 384, + 1768,1772,1776, 388, 388,1780, 388,1784, 576, 576,1788, 392, 392, 392,1792, 580, + 580,1796,1800,1804, 396, 396, 396,1808, 80, 80, 80,1812, 80,1816,1820, 0, + 1824, 32, 32,1828, 0, 0, 0, 0,1832, 584, 584,1836,1840,1844, 588, 588, + 1848,1852,1856, 0, 0, 0,1860,1864,1868,1872,1876,1880,1884,1888, 0, 0, + 592, 592, 268,1892, 268,1896, 268, 268,1900,1904,1908,1912, 596, 596, 600, 600, + 604, 604, 0, 0, 608, 608,1916,1920, 400, 400, 400,1924,1928,1932,1936,1940, + 1944,1948,1952, 0, 0, 0, 0, 0, 272, 272, 272, 272,1956, 0, 0, 0, + 160, 160, 160,1960, 160, 160, 160,1964, 612, 612,1968,1972, 404, 404,1976, 404, + 1980, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36,1984, + 616, 616,1988,1992,1996,2000, 0,2004, 620, 620,2008, 624, 624,2012, 0,2016, + 2020, 0, 0,2024,2028, 0,2032,2036, 200, 200, 200, 200,2040,2044, 200,2048, + 276, 276, 276, 276,2052,2056,2060,2064, 408, 408, 408,2068,2072, 628, 628,2076, + 164, 164, 164, 164, 164, 164,2080,2084, 412,2088, 412, 412,2092, 0, 0, 0, + 2096,2100,2104, 416, 416, 416,2108,2112,2116,2120,2124,2128,2132,2136,2140,2144, + 2148, 632, 632,2152,2156,2160,2164, 0, 204, 204, 204, 204, 204,2168,2172, 0, + 280, 280, 280, 280,2176,2180, 0, 0, 284, 284, 284,2184, 284,2188, 0, 0, + 288, 288, 288, 288,2192,2196,2200, 0, 420, 420, 420, 636, 636, 96,2204, 0, + 640,2208,2212, 640,2216, 0, 0, 0, 424, 424, 424,2220, 0, 0, 0, 0, + 0, 0, 208, 208, 208, 208, 208,2224,2228,2232,2236,2240,2244,2248, 0, 0, + 0, 0, 644, 648, 648, 644,2252, 0, 292, 292, 292, 292,2256, 212, 212, 212, + 212, 212,2260, 40, 428, 428, 428,2264,2268, 0, 0, 0, 0, 0,2272, 0, + 0, 0, 0, 0, 652, 652,2276,2280,2284, 432, 432,2288,2292, 432,2296, 656, + 656,2300,2304,2308, 0, 0, 0, 0,2312, 660, 660,2316,2320,2324,2328,2332, + 2336,2340,2344, 664, 664,2348,2352, 0, 0, 0, 0, 0, 0, 0,2356,2360, + 436,2364, 436,2368, 436,2372, 0, 0, 0, 0, 0,2376, 440, 440, 440,2380, + 28,2384, 0, 0, 0, 0, 0, 0, 28, 28, 28, 28, 28, 28,2388,2392, + 28, 28, 28, 28,2396, 0, 0, 0, 0, 168, 168, 168, 168, 168, 168,2400, + 20, 20, 20, 20, 20,2404, 20, 20, 20, 20, 20, 20, 20, 20, 20,2408, + 52, 52, 52, 52,2412, 0, 0, 0, 444, 444, 444,2416, 0, 0, 0, 0, + 44, 44, 44,2420,2424,2428,2432, 296, 296, 296, 296,2436,2440,2444,2448,2452, + 216, 216, 216, 216,2456,2460,2464,2468, 216, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 448, 448, 448,2472, 0, 0, 0, 0, 220, 220, 220, 220, + 220,2476, 668,2480, 668,2484, 0, 0, 124, 124, 124, 124,2488, 124, 124, 124, + 2492, 124, 0, 0, 0, 0,2496,2500, 64, 64, 64, 64, 64,2504, 0,2508, + 16,2512, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16,2516, + 0, 0, 0, 0, 0, 0, 0,2520,2524, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,2528,2532, 0,2536,2540, 68, + 68, 68, 68, 68, 68, 68, 68,2544, 172, 172, 172, 172, 172, 172,2548,2552, + 2556,2560, 224, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 12, 192, + 12, 12, 12,2564, 12, 452, 12, 452, 56, 56, 512, 56,2568, 12, 12, 12, + 12, 12, 12, 12, 224, 0, 0, 0, 12, 12, 12, 12, 12, 12, 12, 456, + 12, 12,2572, 12, 12, 12,2576,2580,2584, 12,2588, 12, 12, 12, 352, 0, + 72, 72, 72, 72,2592, 0, 0, 0, 0, 0, 0, 0, 12, 224, 12, 224, + 12, 12, 12, 12, 12,2596, 12, 300, 12, 12, 12, 12, 12, 524, 12, 12, + 12,2600,2604,2608,2612, 12, 12, 12,2616,2620, 12,2624,2628,2632, 12, 12, + 12, 12,2636, 12, 12, 12, 12, 12, 12, 12, 12, 12,2640, 12, 12, 12, + 2644,2648,2652, 0, 0, 0, 0, 0, 32,2656,2660, 0, 0, 0, 0, 0, + 2664,2668,2672, 60, 60, 60,2676, 0,2680, 0, 0, 0, 0, 0, 0, 0, + 672, 672,2684,2688,2692, 0, 0, 0, 0,2696,2700, 0, 460, 460, 460,2704, + 0, 0, 0, 0, 0, 676, 676,2708, 0, 0, 0, 0, 0, 680, 680,2712, + 0, 0, 0, 0, 684,2716, 684,2720, 0, 0, 0, 0, 0, 0,2724,2728, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,2732,2736, 0, 0, + 304, 304, 304, 304,2740,2744, 0, 0, 0, 0, 0, 0, 0, 0, 0, 152, + 12, 12, 12,2748, 0, 0, 0, 0, 152, 12, 12, 184, 0, 0, 0, 0, + 2752, 36,2756,2760,2764,2768,2772,2776,2780, 688,2784, 688, 0, 0, 0,2788, + 12, 12, 156, 12, 12, 12, 12, 12, 12, 224, 528, 152, 152, 152, 12, 456, + 12, 12, 184, 0, 0, 0,2792, 12,2796, 12, 12, 156, 300, 348, 456, 0, + 12, 12, 12, 12, 12,2800, 192, 192, 12, 12, 12, 12, 12, 176, 156, 452, + 156, 12, 12, 12, 464, 176, 12, 12, 464, 12, 184, 156, 348, 300, 0, 0, + 12, 12, 12, 12, 12, 464, 184, 192,2804, 12, 12, 12,2808,2812,2816, 300, + 12, 556, 12, 12, 12, 12, 12, 352, 4, 4, 4, 4, 4, 4, 0, 0, + 4, 188, 4, 4, 4, 4, 4, 4, 4, 4, 188, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4,2820, 4, 4, 4, 4, 4, 4, 188, 0, 0, + 4, 188, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,2824, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 552,2828, 0, 12, 12, 12, 12, 12, 12, + 0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12, + 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36, 32, 32, 32, 32, + 24, 24, 24, 24, 28, 28, 28, 28, 40, 40, 40, 40, 48, 48, 48, 48, + 44, 44, 44, 44, 56, 56, 56, 56, 52, 52, 52, 52, 60, 60, 60, 60, + 64, 64, 64, 64, 76, 76, 76, 76, 68, 68, 68, 68, 80, 80, 80, 80, + 84, 84, 84, 84, 88, 88, 88, 88, 72, 72, 72, 72, 96, 96, 96, 96, + 100, 100, 100, 100, 92, 92, 92, 92, 104, 104, 104, 104, 116, 116, 116, 116, + 120, 120, 120, 120, 124, 124, 124, 124, 108, 108, 108, 108, 132, 132, 132, 132, + 112, 112, 112, 112, 136, 136, 136, 136, 128, 128, 128, 128, 148, 148, 148, 148, + 144, 144, 144, 144, 152, 152, 152, 152, 452, 12, 12, 12, 12, 12, 12, 0, + 180, 180, 180, 180, 176, 176, 176, 176, 184, 184, 184, 184, 140, 140, 140, 140, + 12, 12, 264, 0, 72, 232, 72, 232, 12, 12, 12, 264, 4, 4, 4, 600, + 12, 12, 12, 364, 240, 240, 240, 240, 168, 168, 168, 168, 188, 188, 188, 188, + 248, 248, 248, 248, 252, 252, 252, 252, 160, 160, 160, 160, 204, 204, 204, 204, + 12, 0, 0, 0, 764, 24, 24, 24, 24, 24, 628, 12, 164, 164, 164, 164, + 236, 236, 236, 236, 156, 156, 156, 156, 292, 292, 292, 292, 300, 300, 300, 300, + 268, 268, 268, 268, 208, 208, 208, 208, 324, 324, 324, 324, 192, 192, 192, 192, + 312, 312, 312, 312, 344, 344, 344, 344, 244, 244, 244, 244, 196, 196, 196, 196, + 276, 276, 276, 276, 316, 316, 316, 316, 212, 212, 212, 212, 12, 12, 364, 0, + 216, 216, 216, 216, 220, 220, 220, 220, 256, 256, 256, 256, 476, 476, 476, 476, + 396, 396, 396, 396, 172, 172, 172, 172, 228, 228, 228, 228, 260, 260, 260, 260, + 408, 408, 408, 408, 320, 320, 320, 320, 480, 480, 480, 480, 264, 0, 0, 0, + 12, 12, 296, 0, 412, 412, 412, 412, 8, 8, 8, 812, 484, 484, 484, 484, + 416, 416, 416, 416, 272, 272, 272, 272, 304, 304, 304, 304, 488, 488, 488, 488, + 496, 496, 496, 496, 308, 308, 308, 308, 456, 456, 456, 456, 460, 460, 460, 460, + 420, 420, 420, 420, 368, 368, 368, 368, 328, 328, 328, 328, 372, 372, 372, 372, + 348, 348, 348, 348, 352, 352, 352, 352, 380, 380, 380, 380, 432, 432, 432, 432, + 200, 200, 200, 200, 280, 280, 280, 280, 284, 284, 284, 284, 436, 436, 436, 436, + 440, 440, 440, 440, 364, 0, 0, 0, 12, 264, 0, 0, 444, 444, 444, 444, + 12, 12, 0, 0, 12, 12, 768, 12, 24, 628, 24, 24, 400, 400, 400, 400, + 112, 112, 892, 112, 112, 112, 112,1048, 124,1052, 0,1056, 72, 72, 684, 636, + 684, 636, 72, 72, 136, 136, 900, 0, 340, 340, 340, 0, 156, 156, 904, 0, + 52, 52, 52,1072, 68, 688, 68, 688, 68, 772, 68, 68, 12, 648, 12, 12, + 12, 12, 12, 296, 24, 24, 24,1092, 916, 92, 92, 92, 520, 520, 520, 520, + 524, 524, 524, 524, 572, 572, 572, 572, 4, 4, 600, 0, 296, 12, 12, 12, + 108, 108, 108,1132, 576, 576, 576, 576, 536, 536, 536, 536, 492, 492, 492, 492, + 540, 540, 540, 540, 500, 500, 924, 500, 528, 528, 528, 528, 604, 604, 604, 604, + 608, 608, 608, 608, 464, 464,1144, 0, 612, 612, 612, 612, 616, 616, 616, 616, + 532, 532, 532, 532, 504, 504, 504, 504, 544, 544, 544, 544, 548, 548, 548, 548, + 552, 552, 552, 552, 588, 588, 588, 588, 376, 376, 376, 376, 352, 352,1188, 0, + 424, 424, 424, 424, 384, 384,1200, 384, 384, 384, 384, 384, 556, 556, 556, 556, + 388, 388, 388, 388, 392, 392, 392, 392, 472, 472, 472, 472, 512, 512, 512, 512, + 356, 356, 356, 356, 560, 560, 560, 560, 564, 564, 564, 564, 516, 516, 516, 516, + 28, 28, 28, 0, 24, 24, 840, 12, 24, 840,1264, 12, 68,1268, 844,1272, + 0,1276, 848, 772,1280, 68, 68, 68,1284, 144, 144, 144, 60,1288, 60, 60, + 852, 220, 220, 220, 220, 952, 852, 220, 220, 220, 952, 852, 956, 164, 164, 164, + 164, 164, 0, 0, 164, 164, 960,1292, 164,1296, 0, 0, 28, 964, 28, 968, + 28, 28, 972, 972, 968, 28,1300, 52, 52,1304, 28, 28,1308, 28, 28, 28, + 28, 28, 28, 964, 256, 256, 256,1312, 256, 256, 976,1316,1320, 0, 0, 0, + 396, 396,1324,1328, 400, 400, 400,1332, 400, 400, 400,1336, 632, 632, 632, 632, + 632, 632, 632,1340, 256, 256, 976, 0, 980, 984, 28, 28,1344, 28, 28, 28, + 1348,1352, 120, 120, 120,1356, 120, 120, 332,1360, 332, 776, 776, 332, 332, 332, + 332, 332,1364, 332,1368, 988,1372, 332, 332, 776, 776, 992, 0,1376, 0,1380, + 332, 988, 332, 332, 332, 332, 332, 992, 856, 856, 860, 996,1000, 568, 568, 568, + 568, 568, 864, 568, 864,1384,1004, 864, 860, 996,1000,1004,1388, 0, 856,1392, + 0,1396, 568, 568, 568, 860, 0, 0, 780, 780, 448, 784, 784, 448, 448, 448, + 448, 448,1008, 448,1008, 780, 868, 448, 448, 784, 784, 868,1400, 0, 0, 0, + 448,1404, 448, 448, 868, 0, 780, 448, 788, 788, 404, 792, 792, 404, 404, 404, + 404, 404,1012, 404,1012, 788,1016, 404, 404, 792, 792,1016, 0, 788, 0,1408, + 404,1412, 404, 404, 404, 404, 0, 0, 680,1416, 796, 680, 872, 800,1420, 872, + 876,1020, 796, 680, 284, 284, 800, 680, 796, 680, 872, 800,1020, 876, 0, 0, + 0, 680, 284, 284, 284, 284, 796, 0, 288, 288, 288, 728, 728, 288, 288, 288, + 288, 288, 728, 288, 288, 288, 880, 288, 288, 728, 728, 880, 0,1424,1428, 880, + 288,1432, 288, 288, 0,1436, 288, 288, 360, 360, 360, 732, 732, 360, 360, 360, + 360, 360, 732, 360, 360,1024,1028, 360, 360, 732, 732,1028, 0,1440, 0,1444, + 360,1448, 360, 360,1024, 0, 0, 0, 172, 172, 172, 804, 804, 172, 172, 172, + 172, 804, 804, 172, 0, 172, 172, 172, 172,1452, 172, 172, 884, 884, 224, 224, + 224,1032, 888, 224, 224, 224, 224, 224,1456, 224, 224,1460, 224,1032,1464,1468, + 224,1472, 224, 224, 0, 888, 224, 224, 888,1036, 0, 0,1476, 228, 228, 228, + 228, 228,1480, 736, 228, 228, 228, 0,1484,1488,1040, 336, 336, 336, 336, 336, + 336,1492, 336, 336, 336, 336, 336,1044, 336,1496, 336,1040, 336, 336,1044, 336, + 112, 112, 112,1500, 892, 112, 112, 112, 112,1504,1508, 0, 124, 124,1512, 124, + 72, 232, 684, 636, 684, 636, 72, 232, 72, 232, 72, 72, 72, 72, 232, 808, + 72, 72, 72,1516, 72, 72, 636, 0, 116,1060, 116,1060, 640, 640, 640, 640, + 640, 640, 640,1520, 236, 236,1524,1528, 236, 236,1532, 0, 740, 740, 740, 740, + 740,1536, 0,1540, 744, 744, 744, 744, 744,1544, 0, 0, 748, 748, 748, 748, + 748, 0, 0, 0, 896, 896, 896,1064,1064, 0, 0, 0, 136, 136, 136, 900, + 1548,1552, 128, 128, 128, 128,1556, 0, 128, 128,1068, 0, 128, 128,1560, 0, + 40,1564, 0, 0, 340, 340, 340, 340, 340, 340, 340,1568,1572, 340, 340, 340, + 596, 596, 596, 596, 596, 596, 596,1576, 596,1580, 0, 0, 260, 260, 260, 0, + 260, 260,1584, 0, 260, 260,1588,1592, 644, 644, 644, 644, 644, 644, 644,1596, + 156, 156, 156,1600, 156, 156, 156,1604, 156, 156, 156, 904, 52, 52, 52, 0, + 148, 148, 148,1608, 408, 0, 0, 408, 320, 320,1612, 320, 320, 320,1616,1620, + 60, 60,1624, 0, 124, 124,1628,1632, 292, 292, 0, 0,1076, 52, 52, 52, + 1636, 52, 908,1640, 12, 908,1644, 0, 24,1080,1648, 24, 24, 24, 24,1652, + 1656,1080,1660, 24, 24, 24,1664, 24, 24, 24, 24,1668, 68, 68,1084,1084, + 68, 68, 68, 688, 68, 844, 68,1672, 844, 772, 68, 848, 12, 12, 12, 912, + 1676, 12, 12,1088,1680, 0, 0, 0, 12,1684,1096, 12, 768, 12, 12, 12, + 12, 12, 12, 768, 24, 24, 840, 0, 12, 692, 12, 12, 144, 0,1688, 144, + 412, 412, 0,1100,1692, 0, 0,1100, 72, 232, 0, 0, 4, 4,1696, 4, + 4, 0, 0, 0, 4, 600, 0, 0, 12,1700, 12, 12,1704, 4,1708,1712, + 12, 12, 4, 12,1716, 80, 80, 80, 80,1104,1720,1724, 92, 92,1108, 916, + 0,1728, 300, 300,1732, 8, 8, 8, 12, 264, 0, 736, 8, 8, 8,1736, + 92, 92, 92,1108, 92, 92, 12, 12, 36, 36, 36,1740, 36,1744, 0, 0, + 88, 88, 88, 0, 48, 48, 0, 0,1096, 24, 24, 24, 24, 24,1088, 24, + 1112, 24, 24, 24, 520, 520, 520,1748, 416, 416, 0, 0, 268,1116, 0,1752, + 268, 268,1116, 0, 524, 524, 524,1756, 572, 0, 0,1760, 8, 8, 8,1120, + 208, 208, 208,1764, 208, 208,1768,1772, 100, 100, 100,1776, 272,1780, 0, 0, + 272, 272, 272,1124, 272, 272,1124, 272,1784, 0, 0, 0, 0, 0,1788, 324, + 304,1792, 0, 0, 808, 232, 808, 232, 808, 232, 0, 0, 24, 24, 628, 24, + 24,1796,1800, 0, 304, 304, 304,1128, 304, 304,1128, 0, 8, 0, 0, 0, + 8, 812,1804, 8, 8, 8, 8, 0, 24, 816, 0, 0,1808, 220, 0, 956, + 164, 960, 164,1812,1816,1820, 164, 164, 28, 28, 28,1824, 52, 52, 52,1828, + 12, 296, 12, 0, 28,1832, 28, 28, 28, 28, 28,1836, 12,1840, 92, 92, + 92, 92, 92,1844, 820, 8, 820, 8, 820, 8, 820,1120, 12, 296, 12, 296, + 0, 0, 452, 264, 108, 108, 108,1848, 108, 920, 108, 108, 108, 108, 920,1852, + 108, 108, 920, 0, 296, 736, 12, 12, 12, 736, 12, 12, 68, 68, 68, 848, + 1856, 0, 0, 0, 12, 12, 12,1860, 652, 652, 652, 652, 652, 652, 652,1864, + 1868, 0, 0, 0, 908, 12, 12, 12, 576, 0, 0,1872, 696, 696, 696, 696, + 696, 696,1876, 0, 536, 536,1880, 0, 656, 656, 656, 656, 656, 656, 656,1884, + 492, 0, 492, 492, 492,1888, 0, 0, 580, 580, 580, 580, 580, 580, 580,1136, + 580, 580,1136, 0, 308, 0, 308, 308, 308, 308, 308, 0, 540, 540, 0, 0, + 456, 0, 0,1892, 924, 824, 500, 500, 824, 500, 500, 500, 824, 500, 824,1896, + 460, 0, 0, 0, 84,1900, 0, 0, 84,1904, 0, 0, 84, 84, 0, 0, + 24,1908, 24, 24,1912, 24, 816, 0, 528,1916,1920, 528, 528,1924,1928,1932, + 660, 660, 660, 660, 660,1936, 660, 660, 584, 584, 584, 584, 584, 584, 584,1940, + 0,1944, 584, 584, 752, 752, 752, 752,1948,1952,1956, 752, 664, 664, 664, 664, + 664, 664, 664,1960, 700, 700, 700, 700, 700, 700,1964,1968, 704, 704, 704, 704, + 704, 704,1972, 0, 192, 192, 0, 192,1976, 192, 192, 192, 464,1980, 0, 464, + 464,1140,1140, 464, 464, 464, 464, 464, 464,1984,1988,1992, 532,1148,1996, 532, + 532,1148, 0, 0, 420,2000,2004, 420, 668, 668, 668, 668, 668,2008, 668, 668, + 708, 708, 708, 708,2012, 0, 708, 708, 756, 756, 756, 756,2016, 0,1152,2020, + 0, 0,1152, 756, 312, 312,2024, 0,1156, 0, 0, 0,1156, 0,2028, 180, + 504, 504, 0, 0, 504, 504,2032, 0, 368,1160,2036, 368, 368,1160, 0,2040, + 28, 28, 28, 828, 544, 544,2044,1164,1164, 0, 0, 0,1168, 28, 0, 0, + 28, 28,2048, 0, 0, 0,1168, 28, 548, 548, 0, 0, 552, 552,2052, 0, + 712, 712, 712, 712, 712, 712,2056, 0, 672, 672, 672, 672, 672, 672, 672, 0, + 760, 760, 760, 760, 760,2060, 0, 0, 168, 168, 168,1172,2064, 168, 168, 168, + 168,1172, 0,2068,2072, 0, 0,2076, 620, 620, 620, 620, 620, 620,2080, 0, + 620, 620,2084, 0, 328,2088, 328, 328, 328, 328, 0, 0, 588,2092, 0, 0, + 884, 224, 224, 224, 224,1036, 0, 0,2096, 372, 372, 372,2100, 0, 0, 0, + 716,2104,2108,1176, 716, 716, 716,1176, 716, 716,2112, 0, 348, 348,2116, 0, + 348, 348,2120, 0, 468, 928, 468, 832, 832, 468, 468, 468, 468, 468,1180, 468, + 1180, 928,2124, 468, 468, 832, 832,2128, 932,2132, 0, 928, 468,2136, 468, 932, + 468, 932, 0, 0, 376, 376, 936,2140, 376, 936, 376, 376,2144,2148,2152, 376, + 376, 936,2156, 0,2160, 0, 0, 0, 188, 188, 188,2164,2168, 0, 0, 0, + 244, 244, 0, 0, 244, 244,2172, 0, 196,1184, 196, 196, 196, 196, 196,1184, + 276,2176, 0, 0, 276, 276,2180, 0, 128, 128, 128,1068, 100, 0, 0, 0, + 424, 424,1192,2184, 424, 424, 424, 0, 424,1192, 0, 0, 380, 380, 380, 0, + 2188, 0, 0,2192, 428,1196,2196, 428, 428,2200, 428, 428, 428, 428, 428, 428, + 428,2204,2208, 428, 428,1196, 0, 0, 428, 428,2212, 0, 384,2216, 0, 0, + 316, 316, 0, 0,2220, 0, 0, 0, 432, 432,2224, 0, 120, 120,2228, 0, + 176, 176, 0, 0,1204, 0, 0, 0, 556, 556,1204, 0, 200, 200,2232, 200, + 200,2236, 200, 200, 200,2240, 0, 0, 200, 200, 200,2244,2248, 388, 388, 388, + 388, 388,2252, 388, 388,2256, 0, 0, 392,1208,1212, 392, 392,1208,2260,1212, + 392, 392, 0, 0, 392, 392,2264, 0, 508,1216,2268, 508, 508, 508, 508, 508, + 508, 508, 508,2272,1216, 508,2276, 0, 508, 508,2280, 0, 472, 472, 472, 0, + 472, 472,2284, 0, 720, 720, 720, 720, 720, 720,2288, 0,2292, 280, 280, 280, + 280, 280,1220,2296, 280, 280,1220, 0,2300, 0, 0, 0, 800, 0, 0, 876, + 32, 32,2304, 0, 32, 32, 32,2308, 32,2312, 0, 0, 32, 0, 0, 0, + 2316, 0, 0, 0, 20,2320, 0, 0, 20, 20,2324, 0, 56,2328, 0, 0, + 436, 436,2332, 0, 48, 48,2336, 0, 592, 592, 592, 592, 592, 592, 592,2340, + 592, 592,2344,2348, 212, 212, 212,2352, 212, 212,2356, 0, 624, 624, 624, 624, + 624, 624, 624,1224, 624,1224, 0, 0, 160,2360, 0, 0, 160, 160,1228, 160, + 1228, 160, 160, 160, 160, 160, 0,2364, 440, 440,2368, 0, 204, 204,2372, 0, + 512, 512,2376, 512, 512, 0, 0, 0, 132, 132,2380,1232, 132, 132, 0,1232, + 2384,2388, 0, 0, 4,1236, 0, 0, 64,2392, 0, 0, 0, 0, 0,2396, + 16, 16, 16,1240,1240, 0, 0, 0, 92,2400, 92,2404,2408, 80, 80, 80, + 2412, 0, 0, 0,2416, 0, 0, 0,1104,2420, 0, 0, 0, 92, 0, 0, + 76, 76, 76, 0, 140, 140,2424, 0, 140, 140, 140,1244, 140, 140,1244, 0, + 140, 140,2428, 140, 12, 0, 692, 12, 52,2432, 0, 0, 12, 296, 452, 12, + 12,1248, 912, 12, 12, 12,1248, 52,1076,2436, 52, 12, 12, 12,2440, 912, + 68, 688, 0, 0, 12, 296, 0, 0, 12, 12, 12, 648,2444,2448, 452, 648, + 12, 12, 940, 452, 12, 452, 12, 12, 12, 940, 296, 452, 12, 648, 12, 648, + 12, 12, 940, 296, 12,2452, 692, 12, 648, 12, 12, 12, 12, 264, 12, 12, + 12, 12, 12, 692, 44, 44, 44, 0, 0, 0,2456, 44,2460, 44, 44, 44, + 24, 24, 24, 816, 0,1112, 816, 0, 152,1252, 152, 152, 152, 152,2464, 152, + 2468,2472,1252, 0, 60, 60, 60,2476, 0, 0, 0,2480, 356, 356, 356,2484, + 356, 356, 356,1256, 356, 356,1256,2488, 676, 676, 676, 676, 676, 676, 676,2492, + 444, 444,2496,2500, 560, 560,2504, 0, 564, 564,2508,2512, 516, 516, 516,2516, + 516,2520, 0,2524, 72, 232, 72,2528, 72, 72, 72, 232, 104,2532, 104, 104, + 104,2536, 0, 0, 216, 216, 216, 0, 216, 216,2540,2544, 12, 364, 0, 0, + 28, 724, 28, 28, 944, 948, 724, 28, 828, 28, 836, 0,2548, 984, 836, 724, + 944, 948, 836, 836, 944, 948, 828, 28, 828, 28, 724,2552, 28, 28,1260, 28, + 724, 724,1260, 28, 980, 0, 0, 0, 0, 692, 12, 12,2556, 0, 0, 0, + 12, 12, 364, 12, 12, 12, 296, 692, 12, 296, 364, 452, 12, 12, 12,2560, + 12, 12, 296, 736,2564, 0, 0, 0, 4, 4,1236, 0,2568, 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,1446,1458,1468,1476,1480,1486,1517, 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,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,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,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 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, - 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, + 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, - 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, + 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,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,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,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,1936, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1937, 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,1936, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1938, 0,1939, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1940, 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,1943,1944, 0, 0, 0, 0, 0, 0, + 1945, 0,1946, 0, 0, 0, 0, 0, 0, 0, 0,1947, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,1938, 0,1939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1940, 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,1943,1944, 0, 0, 0, 0, 0, 0,1945, 0,1946, 0, 0, - 0, 0, 0, 0, 0, 0,1947, 0, 0,1948, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1950, 0,1949, - 1951, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1953,1952, 0,1954, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,1955,1956, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1957, 0, 0, 0, 0, 0, 0, 0, 0,1958,1961,1959,1965,1960,1962,1964, - 1963, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1967,1966,1968, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1969,1970,1971,1972,1973,1974,1975, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1976,1977,1978,1980,1979,1981, 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,1950, 0,1949,1951, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1953,1952, 0,1954, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1955,1956, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1957, 0, 0, 0, 0, 0, 0, 0, 0,1958,1961, + 1959,1965,1960,1962,1964,1963, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1967,1966,1968, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1969,1970,1971,1972,1973, + 1974,1975, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1976,1977,1978,1980,1979,1981, 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, + 0, 0, 1, -1, -1, 1, 0, 1, -1, 0, 0, 2, 0, -2, 2, 0, + -2, 0, -7, 0, 0, 16, 0, -16, 3, 3, 3, -3, -3, -3, 0, 2016, + 0, 2527, 1923, 1914, 1918, 0, 2250, 0, 0, 138, 0, 7, 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, @@ -4360,11 +4357,13 @@ static const int16_t _hb_ucd_i16[92]= static inline uint8_t _hb_ucd_gc (unsigned u) { - return u<1114110 ? _hb_ucd_u8[6560u+((_hb_ucd_u8[816u+((_hb_ucd_u16[((_hb_ucd_u8[272u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>4))>>4)])<<4)+((((((((u)>>1))>>3))>>4))&15)])<<4)+((((((u)>>1))>>3))&15)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : 2; + /* packtab: [2^8,2^4,2^4,2^3,2^1] */ + return u<1114110u ? (uint8_t)(_hb_ucd_u8[6536u+((_hb_ucd_u8[800u+_hb_ucd_u16[((_hb_ucd_u8[272u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>4))>>4)])<<4)+((((((((u)>>1))>>3))>>4))&15)])<<4)+((((((u)>>1))>>3))&15)]+((((u)>>1))&7)])<<1)+((u)&1)]) : 2; } static inline uint8_t _hb_ucd_ccc (unsigned u) { - return u<125259 ? _hb_ucd_u8[8620u+((_hb_ucd_u8[8036u+((_hb_ucd_u8[7556u+((_hb_ucd_u8[7188u+((_hb_ucd_u8[6942u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 0; + /* packtab: [2^8,2^3,2^2,2^2,2^2] */ + return u<125259u ? (uint8_t)(_hb_ucd_u8[8589u+((_hb_ucd_u8[8006u+((_hb_ucd_u8[7529u+((_hb_ucd_u8[7163u+((_hb_ucd_u8[6918u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)]) : 0; } static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) { @@ -4372,15 +4371,18 @@ static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) } static inline int16_t _hb_ucd_bmg (unsigned u) { - return u<65380 ? _hb_ucd_i16[((_hb_ucd_u8[9516u+((_hb_ucd_u8[9284u+((_hb_ucd_u8[9188u+((_hb_ucd_b4(_hb_ucd_u8+9124u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)])<<3)+((((((u)>>1))>>2))&7)])<<2)+((((u)>>1))&3)])<<1)+((u)&1)] : 0; + /* packtab: [2^4,2^3,2^3,2^2,2^1] */ + return u<65380u ? (int16_t)(_hb_ucd_i16[_hb_ucd_u8[9480u+_hb_ucd_u8[9251u+_hb_ucd_u8[9157u+((_hb_ucd_b4(_hb_ucd_u8+9093u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)]+((((((u)>>1))>>2))&7)]+((((u)>>1))&3)]+((u)&1)]) : 0; } static inline uint8_t _hb_ucd_sc (unsigned u) { - return u<918000 ? _hb_ucd_u8[10950u+((_hb_ucd_u16[4648u+((_hb_ucd_u16[2608u+((_hb_ucd_u8[10214u+((_hb_ucd_u8[9764u+((((((((u)>>2))>>2))>>3))>>4)])<<4)+((((((((u)>>2))>>2))>>3))&15)])<<3)+((((((u)>>2))>>2))&7)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 2; + /* packtab: [2^8,2^4,2^3,2^2,2^2] */ + return u<918000u ? (uint8_t)(_hb_ucd_u8[10913u+_hb_ucd_u16[4624u+_hb_ucd_u16[2592u+((_hb_ucd_u8[10177u+((_hb_ucd_u8[9728u+((((((((u)>>2))>>2))>>3))>>4)])<<4)+((((((((u)>>2))>>2))>>3))&15)])<<3)+((((((u)>>2))>>2))&7)]+((((u)>>2))&3)]+((u)&3)]) : 2; } static inline uint16_t _hb_ucd_dm (unsigned u) { - return u<195102 ? _hb_ucd_u16[7480u+((_hb_ucd_u8[13904u+((_hb_ucd_u8[13522u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)] : 0; + /* packtab: [2^8,2^5,2^4] */ + return u<195102u ? (uint16_t)(_hb_ucd_u16[7453u+((_hb_ucd_u8[13867u+((_hb_ucd_u8[13485u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)]) : 0; } @@ -4388,824 +4390,824 @@ static inline uint16_t _hb_ucd_dm (unsigned u) #include -static const uint8_t _hb_ucd_u8[13937]= +static const uint8_t _hb_ucd_u8[13905]= { - 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 7, 11, 12, 12, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 7, 21, 22, 22, 22, 23, 24, 7, 7, - 7, 25, 22, 22, 22, 26, 27, 28, 22, 29, 30, 31, 32, 33, 34, 35, - 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, 21, 22, 36, - 7, 7, 7, 7, 7, 7, 37, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 38, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 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, 84, 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, - 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, 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,118, 34, 34, 34,119, - 120,121,122,123,124,125,126,127, 34,128,129,130,131,132,133,134, - 135,136,137,138,139,140,141,142,143,144,111,145,146,147,148,111, - 149,150,151,152,153,154,155,156,157,158,159,160,111,161,162,163, - 34, 34, 34, 34, 34, 34, 34, 34,164, 34, 34,111,111,111,111,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,165, - 34, 34, 34, 34, 34, 34, 34, 34,166, 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,167,111,111,111,111,111,111,111,111,111,111,111,111,111, - 34, 34, 34, 34,168,169,170, 34,111,111,171,111,172,173,174,175, - 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,119, - 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,176,111,111,111,111,111,111, - 111,111,111,111,111,111,111,111, 67,177, 67, 67, 67,178,179, 67, - 67, 67,180,181,182,131, 65,111,183,184,185,186,187,188,189,190, - 67, 67, 67, 67,191,192,111,111,111,111,111,111,111,111,193,111, - 194,195,196,111,111,197,111,111,111,198,111,199,111,200,111, 34, - 34,201,202,111,111,111,111,111,131,203,204,111, 34,205,111,111, - 67, 67,206, 67, 67,111, 67,207, 67, 67, 67, 67, 67, 67, 67, 67, - 67,208, 67, 67, 67, 67, 67,177,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, 34, 34,111,111,111,111,111,111,111, - 209,111,195,195,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, 36, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 40, 40, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, - 39, 39, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40, - 42, 42, 42, 42, 42, 42, 42, 42, 32, 32, 41, 32, 16, 43, 16, 10, - 40, 40, 40, 44, 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, 45, 34, 32, 34, 11, - 32, 46, 42, 42, 47, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, - 11, 11, 11, 11, 48, 2, 2, 2, 16, 16, 16, 16, 49, 50, 51, 52, - 53, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 54, - 55, 56, 42, 55, 42, 42, 42, 42, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 57, 2, 2, 2, 2, 2, 2, 58, 58, 58, 8, 9, 59, 2, 60, - 42, 42, 42, 42, 42, 56, 61, 2, 62, 36, 36, 36, 36, 63, 42, 42, - 7, 7, 7, 7, 7, 2, 2, 36, 64, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 65, 42, 42, 42, 66, 46, 42, 42, 67, 68, 69, 42, 42, 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, 42, 42, 42, 42, 42, 42, 64, 36, - 36, 36, 36, 42, 42, 42, 42, 42, 7, 7, 7, 7, 7, 36, 36, 36, - 36, 36, 36, 36, 36, 63, 42, 42, 42, 42, 39, 21, 2, 39, 68, 20, - 36, 36, 36, 42, 42, 68, 42, 42, 42, 42, 68, 42, 68, 42, 42, 42, - 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 36, 36, 63, 42, 42, 2, - 36, 36, 36, 36, 73, 36, 36, 36, 58, 58, 58, 74, 42, 42, 42, 42, - 36, 36, 36, 36, 75, 42, 42, 42, 42, 74, 42, 42, 42, 42, 42, 42, - 42, 76, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 76, 64, 77, - 78, 42, 42, 42, 76, 77, 78, 77, 63, 42, 42, 42, 36, 36, 36, 36, - 36, 42, 2, 7, 7, 7, 7, 7, 79, 36, 36, 36, 36, 36, 36, 36, - 63, 77, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 77, - 78, 42, 42, 76, 77, 77, 78, 36, 36, 36, 36, 81, 77, 77, 36, 36, - 36, 42, 42, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 52, 57, 42, - 42, 76, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 42, 77, - 78, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 64, 36, 36, 36, - 36, 36, 36, 7, 7, 7, 7, 7, 42, 36, 63, 2, 2, 2, 2, 2, - 78, 42, 42, 42, 76, 77, 78, 42, 59, 20, 20, 20, 82, 42, 42, 42, - 42, 77, 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 78, - 78, 42, 42, 76, 77, 77, 78, 42, 42, 42, 42, 76, 77, 77, 36, 36, - 71, 27, 27, 27, 27, 27, 27, 27, 42, 64, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 77, 76, 77, 77, 77, 77, 77, 78, 42, - 36, 36, 36, 81, 77, 77, 77, 77, 77, 77, 77, 7, 7, 7, 7, 7, - 27, 83, 60, 60, 52, 60, 60, 60, 76, 77, 64, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 64, 42, 76, 77, 77, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 36, 36, 36, 36, 7, 7, 7, 84, 27, 27, 27, 83, - 63, 77, 65, 36, 36, 36, 36, 36, 77, 77, 77, 76, 77, 77, 42, 42, - 42, 42, 76, 77, 77, 77, 36, 36, 85, 81, 77, 77, 77, 77, 77, 77, - 42, 77, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 64, 77, - 78, 42, 42, 77, 77, 77, 78, 70, 60, 60, 36, 81, 27, 27, 27, 86, - 27, 27, 27, 27, 83, 36, 36, 36, 36, 36, 36, 36, 36, 42, 42, 76, - 77, 42, 42, 42, 77, 77, 77, 77, 7, 77, 2, 2, 2, 2, 2, 2, - 63, 36, 42, 42, 42, 42, 42, 87, 36, 36, 36, 68, 42, 42, 42, 56, - 7, 7, 7, 7, 7, 2, 2, 2, 63, 36, 42, 42, 42, 42, 64, 36, - 36, 36, 36, 39, 42, 42, 42, 42, 7, 7, 7, 7, 7, 7, 36, 36, - 70, 60, 2, 2, 2, 2, 2, 2, 2, 88, 88, 60, 42, 60, 60, 60, - 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 46, 46, 46, 4, 4, 77, - 63, 42, 42, 42, 42, 42, 42, 76, 42, 42, 56, 42, 36, 36, 63, 42, - 42, 42, 42, 42, 42, 42, 42, 60, 60, 60, 60, 69, 60, 60, 60, 60, - 2, 2, 88, 60, 21, 2, 2, 2, 36, 36, 36, 36, 36, 81, 78, 42, - 76, 42, 42, 42, 78, 76, 78, 64, 36, 36, 36, 77, 42, 36, 36, 42, - 64, 77, 80, 81, 77, 77, 77, 36, 63, 42, 64, 36, 36, 36, 36, 36, - 36, 76, 78, 76, 77, 77, 78, 81, 7, 7, 7, 7, 7, 77, 78, 60, - 16, 16, 16, 16, 16, 49, 43, 16, 36, 36, 36, 36, 36, 36, 63, 42, - 2, 2, 2, 2, 89, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 60, 60, 60, 60, 60, 60, 60, 60, 11, 11, 11, 11, 16, 16, 16, 16, - 90, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 65, - 91, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 92, 93, 93, - 36, 36, 36, 36, 36, 57, 2, 94, 95, 36, 36, 36, 36, 36, 36, 36, - 36, 42, 76, 77, 77, 77, 77, 80, 36, 42, 96, 2, 2, 2, 2, 2, - 36, 42, 42, 42, 42, 42, 42, 42, 36, 36, 42, 78, 42, 42, 42, 77, - 77, 77, 77, 76, 78, 42, 42, 42, 42, 42, 2, 79, 2, 59, 63, 42, - 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 97, 2, 55, 42, 74, - 36, 75, 36, 36, 36, 36, 36, 36, 36, 36, 63, 64, 36, 36, 36, 36, - 36, 36, 36, 36, 63, 36, 36, 36, 42, 76, 77, 78, 76, 77, 77, 77, - 77, 76, 77, 77, 78, 42, 42, 42, 60, 60, 2, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 27, 27, 60, 36, 36, 36, 63, 76, 78, 42, 2, - 36, 36, 81, 76, 42, 42, 42, 42, 76, 76, 78, 42, 42, 42, 76, 77, - 77, 78, 42, 42, 42, 42, 42, 42, 2, 2, 2, 79, 2, 2, 2, 2, - 42, 42, 42, 42, 42, 42, 42, 98, 42, 42, 80, 36, 36, 36, 36, 36, - 36, 36, 76, 42, 42, 76, 76, 77, 77, 76, 80, 36, 36, 36, 36, 2, - 88, 60, 60, 60, 60, 46, 42, 42, 42, 42, 60, 60, 60, 60, 21, 2, - 42, 80, 36, 36, 36, 36, 36, 36, 81, 42, 42, 77, 42, 78, 42, 36, - 36, 36, 36, 76, 42, 77, 78, 78, 42, 77, 77, 77, 77, 77, 2, 2, - 36, 36, 77, 77, 77, 77, 42, 42, 42, 42, 77, 42, 42, 56, 2, 2, - 7, 7, 7, 7, 7, 7, 85, 36, 36, 36, 36, 36, 39, 39, 39, 2, - 16, 16, 16, 16, 34, 16, 16, 16, 42, 56, 42, 42, 42, 42, 42, 42, - 76, 42, 42, 42, 64, 36, 63, 36, 36, 36, 64, 81, 42, 36, 36, 36, - 16, 16, 16, 16, 16, 16, 39, 39, 39, 39, 39, 39, 39, 43, 16, 16, - 16, 16, 16, 16, 43, 16, 16, 16, 16, 16, 16, 16, 16, 99, 39, 39, - 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,100,100,100,100, - 16, 16, 16, 16, 11, 11,101,102, 40, 16, 16, 16, 11, 11,101, 40, - 16, 16, 16, 16, 11, 11,103, 40,104,104,104,104,104,105, 58, 58, - 50, 50, 50, 2,106,107,106,107, 2, 2, 2, 2,108, 58, 58,109, - 2, 2, 2, 2,110,111, 2,112,113, 2,114,115, 2, 2, 2, 2, - 2, 9,113, 2, 2, 2, 2,116, 58, 58, 58, 58, 58, 58, 58, 58, - 117, 39, 27, 27, 27, 8,114,118, 27, 27, 27, 27, 27, 8,114, 93, - 20, 20, 20, 20, 20, 20, 20, 20, 42, 42, 42, 42, 42, 42,119, 47, - 98, 47, 98, 42, 42, 42, 42, 42, 60,120, 60,121, 60, 34, 11, 16, - 11, 32,121, 60, 45, 11, 11, 60, 60, 60,120,120,120, 11, 11,122, - 11, 11, 35, 36,123, 60, 16, 11, 8, 8, 45, 16, 16, 26, 60,124, - 94, 94, 94, 94, 94, 94, 94, 94, 94,125,126, 94,127, 60, 60, 60, - 8, 8,128, 60, 60, 8, 60, 60,128, 26, 60,128, 60, 60, 60,128, - 60, 60, 60, 60, 60, 60, 60, 8, 60,128,128, 60, 60, 60, 60, 60, - 60, 60, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 60, 60, 60, 60, 4, 4, 60, 60, 8, 60, 60, 60,129,130, 60, 60, - 60, 60, 60, 60, 60, 60,128, 60, 60, 60, 60, 60, 60, 26, 8, 8, - 8, 8, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 8, 8, - 8, 60, 60, 60, 60, 60, 60, 60, 27, 27, 27, 27, 27, 27, 60, 60, - 60, 60, 60, 60, 60, 27, 27, 27, 60, 60, 60, 26, 60, 60, 60, 60, - 26, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 8, 8, 8, 8, - 60, 60, 60, 60, 60, 60, 60, 26, 60, 60, 60, 60, 4, 4, 4, 4, - 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 60, 60, 60, 60, 60, 60, - 8, 8,114,131, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, - 8,114,132,132,132,132,132,132,132,132,132,132,131, 8, 8, 8, - 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, - 8, 8,128, 26, 8, 8,128, 60, 32, 11, 32, 34, 34, 34, 34, 11, - 32, 32, 34, 16, 16, 16, 39, 11, 32, 32,124, 60, 60,121, 34,133, - 42, 32, 16, 16, 49, 2, 89, 2, 36, 36, 36, 36, 36, 36, 36, 75, - 2, 2, 2, 2, 2, 2, 2, 55, 2,106,106, 2,110,111,106, 2, - 2, 2, 2, 6, 2, 97,106, 2,106, 4, 4, 4, 4, 2, 2, 79, - 2, 2, 2, 2, 2, 50, 2, 2, 97,134, 2, 2, 2, 2, 2, 2, - 60, 2,135,132,132,132,136, 50, 50, 50, 50, 50, 50, 50, 50, 50, - 1, 2,137,138, 4, 4, 4, 4, 4, 60, 4, 4, 4, 4,139, 93, - 140, 94, 94, 94, 94, 42, 42, 77,141, 39, 39, 60, 94,142, 57, 60, - 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63,143,144, 62, - 36, 36, 36, 36, 36, 57, 39, 62, 60, 27, 27, 60, 60, 60, 60, 60, - 27, 27, 27, 27, 27, 60, 60, 60, 60, 60, 60, 60, 27, 27, 27, 27, - 145, 27, 27, 27, 27, 27, 27, 27, 36, 36, 75, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36,146, 2, 32, 32, 32, 32, 32, 32, 32, 63, - 47,147, 42, 42, 42, 42, 42, 79, 32, 32, 32, 32, 32, 32, 39, 42, - 36, 36, 36, 94, 94, 94, 94, 94, 42, 2, 2, 2, 2, 2, 2, 2, - 40, 40, 40,144, 39, 39, 39, 39, 40, 32, 32, 32, 32, 32, 32, 32, - 16, 32, 32, 32, 32, 32, 32, 32, 43, 16, 16, 16, 34, 34, 34, 32, - 32, 32, 32, 32, 41,148, 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, - 32, 32, 11, 11, 34, 34, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, - 48, 39,149, 35, 39, 35, 36, 36, 36, 64, 36, 64, 36, 63, 36, 36, - 36, 81, 78, 76, 60, 60, 42, 42, 27, 27, 27, 60,150, 60, 60, 60, - 36, 36, 2, 2, 2, 2, 2, 2, 77, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 77, 77, 77, 77, 77, 77, 77, 77, 42, 42, 42, 42, 42, 2, - 42, 36, 36, 36, 2, 65, 65, 63, 36, 36, 36, 42, 42, 42, 42, 2, - 36, 36, 36, 63, 42, 42, 42, 42, 42, 77, 77, 77, 77, 77, 77, 96, - 36, 63, 77, 42, 42, 77, 42, 77, 96, 2, 2, 2, 2, 2, 2, 79, - 7, 7, 7, 7, 7, 7, 7, 2, 36, 36, 63, 62, 36, 36, 36, 36, - 36, 36, 36, 36, 63, 42, 42, 76, 78, 76, 78, 42, 42, 42, 42, 42, - 36, 63, 36, 36, 36, 36, 76, 77, 7, 7, 7, 7, 7, 7, 2, 2, - 62, 36, 36, 70, 60, 81, 76, 36, 64, 42, 64, 63, 64, 36, 36, 42, - 36, 36, 36, 36, 36, 36, 75, 2, 36, 36, 36, 36, 36, 81, 42, 77, - 2, 75,151, 42, 42, 42, 42, 42, 16, 16, 16, 16, 16,102, 39, 39, - 16, 16, 16, 16, 99, 40, 40, 40, 36, 81, 78, 77, 76, 96, 78, 42, - 152,152,152,152,152,152,152,152,153,153,153,153,153,153,153,153, - 16, 16, 16, 16, 16, 16, 35, 64, 36, 36, 36, 36,154, 36, 36, 36, - 36, 40, 40, 40, 40, 40, 40, 40, 40, 22, 60, 60, 60, 60, 60, 60, - 60, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,132, - 60, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 60, 60, 60, 60, - 36, 36, 36, 36, 36, 36,150, 60, 2, 2, 2,135,115, 2, 2, 2, - 6,155,156,132,132,132,132,132,132,132,115,135,115, 2,112,157, - 2, 2, 2, 2,139,132,132,115, 2,158, 8, 8, 59, 2, 2, 2, - 36, 36, 36, 36, 36, 36, 36,159, 2, 2, 3, 2, 4, 5, 6, 2, - 16, 16, 16, 16, 16, 17, 18,114,115, 4, 2, 36, 36, 36, 36, 36, - 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 39, - 20,160, 52, 20, 26, 8,128, 60, 60, 60, 60, 60,161, 58, 60, 60, - 2, 2, 2, 89, 27, 27, 27, 27, 27, 27, 27, 83, 60, 60, 60, 60, - 94, 94,127, 27, 83, 60, 60, 60, 60, 60, 60, 60, 60, 27, 60, 60, - 60, 60, 60, 60, 60, 60, 46, 42,162,162,162,162,162,162,162,162, - 163, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 86, 36, - 138, 36, 36, 36, 36, 94, 94, 94, 36, 36, 36, 36, 36, 36, 36, 57, - 164, 94, 94, 94, 94, 94, 94, 94, 11, 11, 11, 32, 16, 16, 16, 16, - 36, 36, 36, 57, 27, 27, 27, 27, 36, 36, 36, 70,145, 27, 27, 27, - 36, 36, 36,165, 27, 27, 27, 27, 36, 36, 36, 36, 36,165, 27, 27, - 36, 36, 36, 27, 27, 27, 27, 30, 36, 36, 36, 36, 36, 36, 27, 36, - 63, 42, 42, 42, 42, 42, 42, 42, 36, 36, 36, 36, 42, 42, 42, 42, - 36, 36, 36, 36, 36, 36,165, 30, 36, 36, 36, 36, 36, 36,165, 27, - 36, 36, 36, 36, 71, 36, 36, 36, 36, 36, 63, 42, 42,163, 27, 27, - 36, 36, 36, 36, 57, 2, 2, 2, 36, 36, 36, 36, 27, 27, 27, 27, - 16, 16, 16, 16, 16, 27, 27, 27, 36, 36, 42, 42, 42, 42, 42, 42, - 7, 7, 7, 7, 7, 36, 36, 62, 11, 11, 11, 11,166, 42, 42,141, - 16, 16, 16, 16, 16, 16, 16, 8, 36, 36, 36, 36, 36, 63,167, 50, - 88, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 42, 42, 42, - 27, 27, 27, 86, 36, 36, 36, 36,163, 27, 30, 2, 2, 2, 2, 2, - 36, 42, 42, 2, 2, 2, 2, 2, 36, 36,165, 27, 27, 27, 27, 27, - 78, 80, 36, 36, 36, 36, 36, 36, 42, 42, 42, 56, 2, 2, 2, 2, - 2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 7, 7, 7, - 64, 63, 64, 36, 36, 36, 36, 63, 77, 78, 42, 76, 78, 56, 72, 2, - 2, 42, 42, 42, 42, 42, 66, 58, 36, 36, 36, 63, 42, 42, 78, 42, - 42, 42, 42, 7, 7, 7, 7, 7, 2, 2, 81, 80, 36, 36, 36, 36, - 36, 63, 2, 36, 36, 36, 36, 36, 36, 81, 77, 42, 42, 42, 42, 76, - 80, 36, 57, 2, 55, 42, 56, 78, 7, 7, 7, 7, 7, 57, 57, 2, - 89, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 77, 78, - 42, 77, 76, 42, 2, 2, 2, 64, 36, 36, 36, 36, 36, 36, 36, 63, - 76, 77, 77, 77, 77, 77, 77, 77, 36, 36, 36, 81, 77, 77, 80, 36, - 36, 77, 77, 42, 42, 42, 42, 42, 36, 36, 36, 36, 77, 78, 42, 42, - 42, 77, 77, 77, 77, 77, 77, 76, 64, 64, 2, 2, 2, 2, 2, 2, - 55, 42, 42, 42, 42, 42, 42, 42, 36, 36, 81, 77, 42, 42, 42, 42, - 77, 42, 76, 64, 36, 57, 2, 2, 7, 7, 7, 7, 7, 2, 2, 64, - 77, 78, 42, 42, 76, 76, 77, 78, 76, 42, 36, 65, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 81, 77, 42, 42, 42, 77, 77, 42, 78, - 56, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 42, 42, - 77, 78, 42, 42, 42, 76, 78, 78, 56, 2, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 63, 78, 77, 42, 42, 42, 78, 57, 2, 2, 2, - 36, 36, 36, 36, 36, 36, 63, 78, 77, 42, 42, 78, 42, 42, 42, 42, - 7, 7, 7, 7, 7, 27, 2, 88, 42, 42, 42, 42, 78, 56, 2, 2, - 27, 27, 27, 27, 27, 27, 27, 86, 77, 77, 77, 77, 77, 78, 76, 64, - 80, 78, 2, 2, 2, 2, 2, 2, 81, 77, 42, 42, 42, 42, 77, 77, - 64, 65, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 63, 42, 42, 42, 42, 64, 36, 36, 36, 63, 42, 42, 76, 63, 42, 56, - 2, 2, 2, 55, 42, 42, 42, 42, 63, 42, 42, 76, 78, 42, 36, 36, - 36, 36, 36, 36, 36, 42, 42, 42, 42, 42, 42, 76, 42, 2, 65, 2, - 76, 42, 76, 76, 77, 77, 77, 77, 57, 2, 2, 2, 2, 2, 2, 2, - 42, 42, 42, 42, 42, 42, 42, 78, 2, 36, 36, 36, 36, 36, 36, 36, - 42, 42, 42, 42, 76, 42, 42, 42, 76, 42, 78, 42, 42, 42, 42, 42, - 42, 42, 42, 63, 42, 42, 42, 42, 36, 36, 36, 36, 36, 77, 77, 77, - 42, 76, 78, 78, 36, 36, 36, 36, 36, 36, 36, 36, 75, 36, 36, 36, - 36, 63, 76, 96, 2, 2, 2, 2, 42, 81, 36, 36, 36, 36, 36, 36, - 36, 36, 77, 42, 42, 42, 42, 77, 76, 56, 2, 2, 2, 2, 2, 2, - 7, 7, 7, 7, 7, 42, 42, 42, 27, 27, 83, 60, 60, 60, 52, 20, - 150, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 21, - 64, 36, 36, 63, 42, 42, 42, 42, 36, 36, 36, 36, 36, 36, 36, 42, - 42, 42, 42, 42, 42, 77, 78, 42, 42, 42, 56, 2, 2, 2, 2, 2, - 42, 42, 42, 56, 2, 2, 60, 60, 39, 39, 88, 60, 60, 60, 60, 60, - 7, 7, 7, 7, 7,168, 27, 27, 27, 86, 36, 36, 36, 36, 36, 36, - 39, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 75,146, 2, - 27, 27, 27, 30, 2, 2, 2, 2, 11, 11, 11, 11, 11, 32, 16, 16, - 81, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 78, - 42, 67, 39, 39, 39, 39, 39, 39, 39, 79, 42, 42, 42, 42, 42, 42, - 77, 39, 94, 94, 94, 94, 94, 94, 36, 36, 36, 36, 36, 36, 46, 56, - 7, 7, 7, 7, 7, 60, 60, 60, 60, 60,169, 78, 42, 60,169, 77, - 77,170, 58, 58, 58, 74, 42, 42, 42, 69, 46, 42, 42, 42, 60, 60, - 60, 60, 60, 60, 60, 42, 42, 60, 60, 42, 69, 60, 60, 60, 60, 60, - 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, - 42, 42, 42, 69, 60, 46, 42, 42, 42, 42, 42, 42, 42, 42, 69, 60, - 60, 60, 46, 60, 60, 60, 60, 60, 60, 60, 69, 21, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 55, 42, 42, 16, 16, 16, 16, 16,123, 16, 16, - 42, 42, 42, 67, 39, 39, 39, 39, 7, 7, 7, 7, 7, 7, 7, 70, - 36, 36, 36, 36, 36, 36, 42, 42, 7, 7, 7, 7, 7, 7, 7,171, - 36, 36, 36, 36, 36, 75, 42, 42,172, 7, 7, 7, 7, 7, 7, 84, - 36, 63, 36, 64, 36, 36, 36, 42, 36, 36, 63, 42, 42, 42, 42, 75, - 16, 16, 42, 42, 42, 67, 39, 39, 27, 27, 27, 27, 27, 27,145, 27, - 173, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,145, - 27, 27, 27, 27, 27, 27, 83, 60, 60, 60, 60, 60, 60, 25, 40, 40, - 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, 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, 1, 21, 6, 7, 7, 12, - 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, - 21, 1, 24, 7, 1, 12, 7, 6, 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, - 10, 21, 17, 21, 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, 7, 5, 5, 26, 14, 9, 5, 14, 14, 15, - 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 22, 21, 21, 22, - 18, 17, 26, 6, 7, 14, 17, 22, 26, 14, 17, 6, 14, 6, 12, 24, - 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, - 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 7, 1, - 25, 24, 26, 1, 2, 2, 12, 15, 21, 14, 7, 15, 9, 12, 12, 17, - 13, 15, 26, 10, 10, 1, 13, 23, 7, 13, 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, + 4, 5, 6, 7, 8, 9, 10, 2, 2, 11, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 12, 13, 2, 2, 2, 2, 2, 14, 1, 1, 1, 15, + 16, 17, 18, 19, 20, 21, 22, 2, 3, 0, 0, 0, 23, 24, 2, 2, + 2, 25, 0, 0, 0, 26, 27, 28, 0, 29, 30, 31, 32, 33, 34, 35, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 36, + 2, 2, 2, 2, 2, 2, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, - 0, 36, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 43, 44, - 45, 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, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, - 0, 19, 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, - 0, 0, 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, - 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, - 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, - 0, 52, 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, - 0, 0, 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, - 0, 66, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, - 0, 0, 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 75, - 0, 0, 0, 0, 76, 77, 0, 78, 79, 0, 0, 80, 81, 0, 82, 62, - 0, 83, 84, 0, 0, 85, 86, 87, 0, 88, 0, 89, 0, 90, 0, 0, - 51, 91, 51, 0, 92, 0, 93, 0, 0, 0, 81, 0, 0, 0, 94, 95, - 0, 96, 97, 98, 99, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0,100, - 101, 0, 0, 0, 0, 0, 0,102, 0, 0, 0, 0, 0, 0,103, 0, - 0, 0, 0, 0, 0,104,105, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,106, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,108, - 109, 0, 0,110, 0, 0, 0, 0, 0, 0,111, 0,112, 0,105, 0, - 0, 0, 0, 0,113,114, 0, 0, 0, 0, 0, 0, 0,115, 0, 0, - 0,116, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0,118, 0,119, - 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, 0, 0, 28, 29, - 30, 31, 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, - 0, 0, 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, - 0, 39, 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, - 0, 44, 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, - 0, 48, 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, - 0, 0, 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, - 57, 58, 0, 0, 0, 59, 60, 61, 62, 0, 0, 0, 0, 63, 52, 0, - 64, 65, 0, 0, 66, 0, 0, 0, 67, 68, 0, 0, 0, 69, 0, 70, - 71, 72, 73, 74, 1, 75, 0, 76, 77, 78, 0, 0, 79, 80, 0, 0, - 0, 81, 0, 0, 1, 1, 0, 0, 82, 0, 0, 83, 0, 0, 0, 0, - 79, 84, 0, 85, 0, 0, 0, 0, 0, 80, 86, 0, 87, 0, 52, 0, - 1, 80, 0, 0, 88, 0, 0, 89, 0, 0, 0, 0, 0, 90, 57, 0, - 0, 0, 0, 0, 0, 91, 92, 0, 0, 86, 0, 0, 33, 0, 0, 93, - 0, 0, 0, 0, 94, 0, 0, 0, 0, 49, 0, 0, 95, 0, 0, 0, - 0, 96, 97, 0, 0, 98, 0, 0, 99, 0, 0, 0,100, 0, 0, 0, - 101, 0, 0, 0,102, 0, 0, 0, 0,103,104, 95, 0, 0,105, 0, - 0, 0, 86, 0, 0,106, 0, 0, 0,107,108, 0, 0,109,110, 0, - 0, 0, 0, 0, 0,111, 0, 0,112, 0, 0, 0, 0,113, 33, 0, - 114,115,116, 57, 0, 0,117, 35, 0, 0,118, 0, 0, 0,119, 0, - 0, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,122, 90, 0, - 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,123, 0, 0, 0, 0,124, - 0, 0,125, 0, 0, 0, 0,123, 0, 0,126, 0, 0, 0, 0, 0, - 81, 0, 0, 0, 0,127, 0, 0, 0,128, 0, 0, 0,129, 0,130, - 0, 0, 0, 0,131,132,133, 0,134, 0,135, 0, 0, 0,136,137, - 138, 0, 79, 0, 0, 0, 0, 0, 35, 0, 0, 0,139, 0, 0, 0, - 140, 0, 0, 0,141, 0, 0, 0,142,143, 0,144, 0, 0,145, 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, 0, 19, - 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, - 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, - 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, - 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, - 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, - 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, - 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, - 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, - 15, 86, 36, 10, 21, 1, 1, 1, 1, 41, 1, 21, 87, 0, 0, 55, - 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0, 0, 89, - 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 90, 9, 12, 4, 91, 8, - 92, 47, 0, 58, 50, 0, 21, 1, 21, 93, 94, 1, 1, 1, 1, 95, - 96, 97, 98, 1, 99, 58, 81,100,101, 4, 58, 0, 0, 0, 0, 0, - 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,102,103, 0, 0, - 104, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0, 0, 0, - 0, 62, 0, 0,105, 68, 61, 0, 0, 0, 78, 0, 0, 0,106,107, - 58, 38, 81, 0, 0, 0, 0, 0, 0,108, 1, 14, 4, 12, 84, 0, - 0, 0, 0, 38, 90, 0, 0, 0, 0,109, 0, 0,110, 61, 0,111, - 0, 0, 0, 1, 0, 0, 0, 0, 49, 50, 0, 0, 19, 58, 0, 0, - 112, 51, 0,112, 14, 52,113, 41, 0, 0, 62, 0, 0, 61, 0, 0, - 114, 0, 90, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0,114, - 0, 0, 0, 0,115, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, - 0, 0, 0, 0, 0, 88, 63, 89, 0, 0,116, 0, 0, 0, 55, 0, - 0, 0, 0,116, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, - 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, 0, 0, 8, 92, - 0, 0, 1, 90, 0, 0,117, 0, 0, 0, 0, 0, 0,118, 0,119, - 120,121,122, 0,105, 4,123, 49, 23, 0, 0, 0, 38, 50, 38, 58, - 0, 0, 1, 90, 1, 1, 1, 1, 39, 1, 48,106, 90, 0, 0, 0, - 0, 1, 0, 0, 0,124, 0, 0, 0,113, 19, 59, 0, 38, 0, 81, - 0, 0, 4,123, 0, 0, 0, 1,125, 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,230,220,220,220,230,230, - 0,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, 9, 9, 0, 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,230,230,230,234, 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,218,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, 0, 0, - 0,220,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, 0, - 230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7, 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,232,232,220,230,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, 24, 3, 3, 3, 3, - 3, 3, 25, 3, 3, 3, 3, 3, 3, 3, 3, 26, 3, 3, 27, 28, - 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, 0, 56, 57, 0, 0, 0, 0, 0, 19, 58, 31, 0, 0, - 0, 0, 0, 0, 0, 59, 14, 0, 0, 0, 0, 1, 0, 2, 0, 0, - 0, 3, 0, 0, 0, 60, 61, 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, 0, 0, 8, 21, 21, 21, - 9, 0, 1, 0, 1, 1, 8, 21, 21, 9, 0, 4, 5, 8, 9, 1, - 0, 0, 16, 50, 84,118,136,152,186,187,187,187,187,187,187,187, - 187,187,187,187,187,187,187,187,187,187,187,187,187,187, 12, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, - 13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 15, 16, 17, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 19, 32, 33, 33, 33, 33, 33, - 34, 19, 19, 19, 19, 19, 19, 35, 19, 36, 37, 38, 38, 38, 38, 38, - 38, 39, 40, 19, 19, 19, 19, 19, 19, 19, 41, 42, 19, 19, 43, 19, - 19, 19, 44, 45, 9, 46, 47, 48, 49, 50, 51, 52, 9, 9, 19, 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, 13, 53, 19, 19, 53, 19, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 54, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 55, - 0, 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 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, 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, 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,104,105,105,105, 2,106, - 107,108,109,110,111,112,113,114,115,116,117, 89,118,119,120,121, - 122,123,124,125,126,127,128,129,130, 87,131,132,133,134, 87,135, - 136,137,138,139,140,141,142,143,144,145,146, 87,147,148,149,150, - 150,150,150,150,150,150,150,150,150,150, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87,151,152,152,152,152,152,152,152,152,153, - 153,153,153,153, 87, 87, 87, 87, 87,154, 87, 87, 87, 87, 87,155, - 155,155,155,156,157,158,158, 87, 87,159, 87,160,161,162,163,164, - 164,164,164,164,164,164,164,164,164,164,164,164,164,165,165,165, - 165,164,164, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,166,167, - 168,169,170,170,170, 87, 87,171,172, 87, 87, 87, 87, 87, 87, 56, - 56, 56, 56, 56, 56,173, 56, 56, 56,174,175, 51, 56, 56, 87,176, - 176,176,176,176,176, 87, 87, 87, 87, 87, 87, 87, 87, 2, 87,177, - 6,178, 87, 87,179, 87, 87, 87,180, 87,181, 87,182, 87, 33,183, - 183,184, 87, 87, 87, 87, 87, 56, 56, 56, 87, 89, 89, 87, 87, 56, - 56, 56, 56,185, 87, 56, 56, 62, 62, 62, 62, 62, 87, 87, 87, 62, - 87, 87, 87, 87, 87, 87, 87, 56, 87,186,186, 0, 1, 2, 2, 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, 21, 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, 21, 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,151,151, - 151,151,151,152,152,152,152,153,153,153,153,153,153,153,153,154, - 154,154,154,155,155,156,156,157,157,157,157,157,157,158,158,159, - 159,160,160,161,161,161,161,162,162,163,163,163,163,163,163,164, - 164,164,164,164,164,165,165,166,166,166,166,167,167,167,167,168, - 168,168,168,169,169,170,170,171,171,171,171,171,171,171,171,172, - 172,172,172,172,172,172,172,173,173,173,173,173,173,173,173,174, - 174,174,174,175,175,175,175,175,175,175,175,175,175,175,175,176, - 176,176,176,177, 21, 21, 21,178,178,178,179,179,179,179,180,180, - 180,180,181,181,181,182,182,183,183,183,183,183,183,183,183,184, - 184,184,184,184,185,185,185,186,186,186,186,186,187,187,187,188, - 188,188,188,188,188,189, 43,190,190,190,190,190,190,190,190,191, - 191,191,192,192,192,192,192,193,193,193,194,193,193,193,193,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,199, 66, 66,200,200,200,200,200, 49, 49, 49,201, - 201,201,201,201,201,201,201,202,202,202,202,202,202,202,202,203, - 203,203,203,203,203,203,203,204,204,204,204,204,204,204,204,205, - 205,205,205,205,205,205,205,206,206,206,206,206,207,207,207,207, - 207,207, 55,208,208,208,208, 32, 32, 32, 32, 32, 32,188,188,209, - 209,209,209,209,209,209,209,210,210,210,210,210,210,210,211,211, - 211,211,211,211,211,211,211,212,212,212,212,212,212,213,213,213, - 213,213,214,214,214,214,214,215,215,215,215,215,215,215,215,216, - 216,216,216,216,216,216,216,110,110,110,110, 39, 39, 39, 39,217, - 217,217,217,217,217,217,217,218,218,218,218,218,218,218,218,219, - 219,219,219,219,219,219,219,220,220,220,220,220,220,220,220,221, - 221,221,221,221,221,221,221,112,112,112,112,112,112,112,112,112, - 112,112,112,222,222,222,223,223,223,223,223,223,224,224,224,225, - 225,225,225,225,225,225,225,226,226,226,226,226,226,226,226,227, - 227,227,227,227,227,227,227,227,227,228,228,228,228,228,228,229, - 229,229,229,229,229,229,229,229,229,229,229,229,229,230, 94,231, - 231,231,231,231,231,231,231,232,232,232,232,232,232,232,232,102, - 102,102,102,102,102,102,102,233, 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, 99,102,234, 99,235,102,236,236, - 236,236,236,236,236,236,236,237,237,237,237,237,237,237,237,237, - 237, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, 0, 0, - 0, 0, 0, 0, 0,238,239,240, 0,241, 0, 0, 0, 0, 0,242, - 242,242,242,242,242,242,242, 91, 91, 91, 13, 13, 13, 13, 13,243, - 243,243,243,243,243,243,243,244,244,244,244,245,245,245,245,246, - 246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,248, - 248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,250, - 250,250,250,250,250,250,250,251, 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, 20, 20, 20,179, - 179,179,179,180,180,180,180,181,181,181,181,182,182,182,182,183, - 183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,187, - 187,187,187,188,188,188,188,189,189,189,189,190, 45, 45, 45,191, - 191,191,191,192,192,192,192,193,193,193,193,194,194,194,194,194, - 194,195,194,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,216,216,216,217,217,217,217,218,218,218,218,219, - 219,219,219,220,220,220,220,221,221,221,221,222,222,222,222,223, - 223,223,223,224,224,224,224,225,225,225,225,226,226,226,226,227, - 227,227,227,228,228,228,228,229,229,229,229,230,230,230,230,231, - 232,232,232,233,233,233,233,232,232,232,232,234,106,106,106,235, - 106,106,106,106,236,109,109,237,237,237,237,238,238,238,238, 0, - 239, 86, 0, 0, 0,239, 7, 82,138, 7, 0, 0, 0,240, 86,241, - 241,241,241,242,242,242,242,243,243,243,243,244,244,244,244,245, - 245,245,245,246,246,246,246,247,247,247,247,248,248,248,248,249, - 249,249,249,250, 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,161,161,161,161,170,170,170,170,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,173, - 173,173,173, 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,165,165,165,165,156,156,156,156,156, - 156, 3, 3,147,147,147,147,148,148,148,148,158,158,158,158,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,171,171,171,171,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,169, - 169,169,169,133,133,133,133,134,134,134,134,138,138,138,138,143, - 143,143,143,175,175,175,175,145,145,145,145,163,163,163,163, 63, - 63, 63, 63,157,157,157,157, 80, 80, 80, 80,127,127,127,127,166, - 166,166,166,115,115,115,115,159,159,159,159,103,103,103,103,119, - 119,119,119,167,167,167,167,146,146,146,146,172,172,172,172, 99, - 99, 99, 99,136,139, 13, 13,155,155,155,155,136,136,136,136, 17, - 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17,139,139,139,139,105, - 105,105,105, 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131,151, - 151,151,151,160,160,160,160,152,152,152,152,164,164,164,164,168, - 168,168,168,174,174,174,174,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, 18, 9, 9, 9, 9, 9, 19, 20, 21, 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, 23, 9, 9, 9, 9, 9, 24, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 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, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 26, - 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 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, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, + 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, 2, 2, 2, 2, 45, 46, 47, 2, 2, 2, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 5, 5, 72, 73, 8, 74, 3, 75, 76, 3, 77, 78, + 3, 3, 5, 79, 5, 5, 80, 3, 81, 82, 83, 84, 85, 3, 3, 3, + 86, 87, 2, 88, 89, 90, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 2, 2, 2, + 92, 2, 2, 2, 2, 2, 2, 2, 2, 93, 2, 2, 94, 95, 96, 97, + 98, 99,100,101,102,103,104,105, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 2, 2, 2, 2,106,107, 2, 2,108,109,110,111,112,113, + 2, 2,114,115, 0,116,117,118,119,120,121,122, 2, 2, 2, 9, + 123,124,125,126,127,128,129,130, 2,131,132,133, 6,134,135,136, + 137,138,139,140,141,142,143,144,145,146, 0,147,148,149,150, 0, + 151,152,153,154,155,156,157,158,159,160,161,162, 0,163,164,165, + 2, 2, 2, 2, 2, 2, 2, 2,166, 2, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, + 2, 2, 2, 2, 2, 2, 2, 2,168, 2, 2, 2, 2, 2, 2, 2, + 0, 0,169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2,170,171,172, 2, 0, 0,173, 0,174,175,176,177, + 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, 0, 0, 0, 0, 0, 0, 9, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2,178, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 10, 3, 3, 3,179,180, 3, + 3, 3,181,182,183, 6, 8, 0,184,185,186,187,188,189,190,191, + 3, 3, 3, 3,192,193, 0, 0, 0, 0, 0, 0, 0, 0,194, 0, + 195, 7,196, 0, 0,197, 0, 0, 0,198, 0,199, 0,200, 0, 2, + 2,201,202, 0, 0, 0, 0, 0, 6,203,204, 0, 2,205, 0, 0, + 3, 3,206, 3, 3, 0, 3,207, 3, 3, 3, 3, 3, 3, 3, 3, + 3,208, 3, 3, 3, 3, 3, 10, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 209, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, + 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 11, 11, 11, 11, 11, 11, 11, 11, + 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, + 9, 9, 9, 9, 9, 9, 9, 9, 13, 13, 13, 13, 13, 13, 13, 13, + 10, 10, 10, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, 6, 6, 6, 6, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 1, 1, 1, 1, 4, 4, 9, 9, 9, 9, 9, + 25, 25, 25, 25, 25, 25, 25, 25, 14, 14, 14, 14, 14, 14, 14, 14, + 8, 8, 8, 8, 8, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, + 1, 1, 1, 4, 4, 4, 4, 4, 4, 14, 30, 1, 1, 1, 1, 1, + 9, 9, 9, 9, 9, 10, 10, 10, 9, 9, 9, 9, 9, 7, 7, 7, + 8, 8, 8, 8, 6, 6, 6, 6, 1, 4, 4, 4, 4, 4, 4, 4, + 4, 30, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 32, 32, 32, 32, + 24, 24, 24, 24, 24, 24, 24, 24, 9, 9, 9, 9, 9, 9, 9, 10, + 1, 1, 1, 1, 1, 1, 1, 29, 21, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 1, 1, 29, 10, 10, 10, 29, 10, 10, 10, 10, 10, 10, 10, + 1, 1, 1, 1, 1, 1, 1, 4, 6, 6, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 8, 8, + 8, 8, 8, 6, 6, 6, 6, 6, 9, 9, 9, 9, 9, 10, 11, 65, + 73, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 86, 87, 88, + 74, 6, 6, 6, 6, 6, 6, 6, 20, 20, 20, 20, 20, 20, 20, 20, + 19, 8, 8, 8, 8, 8, 8, 8, 22, 1, 1, 1, 1, 1, 1, 1, + 21, 1, 1, 1, 1, 1, 1, 1, 4, 17, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 22, 14, 4, 17, 30, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 22, 18, 4, 22, 1, 1, 1, 1, 1, 1, + 14, 14, 14, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 21, 22, 14, + 10, 10, 10, 10, 60, 7, 7, 7,100, 1, 1, 1, 1, 1, 1, 1, + 14, 18, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 13, 13, 13, 10, + 20, 6, 6, 6, 8, 8, 79, 20, 6, 6, 6, 6, 8, 8,103, 20, + 26, 26, 26, 26, 26, 26, 26, 26, 7, 7, 7, 7, 7, 3, 3, 3, + 63, 7, 7, 7, 7, 7, 7, 7, 1, 1, 34, 1, 1, 1, 1, 1, + 1, 1, 1, 46, 7, 7, 7, 7, 1, 1, 1, 1, 4, 4, 4, 4, + 1, 1, 1, 1, 1, 1, 46, 7, 1, 1, 1, 1, 7, 7, 7, 7, + 1, 1, 1, 1, 1, 1, 14, 18, 1, 1, 1, 1, 1, 1, 1, 21, + 1, 1, 1, 1, 1, 1, 1, 27, 9, 9, 9, 9, 9, 3, 3, 3, + 72, 10, 84, 10, 23, 85, 64, 10, 6, 6, 6, 6, 6, 89, 90,119, + 72, 24, 24, 47, 91,120,121, 92, 36, 7, 74, 10,122,123, 7, 54, + 8, 8, 8, 48, 8, 8, 8, 12, 6, 6, 6, 49, 6, 6, 6, 6, + 12, 12, 12, 12, 19, 19, 19, 19, 19, 19, 19, 19, 6, 12, 12, 12, + 12, 12, 12, 12, 8, 19, 19, 6, 19, 12, 12, 8, 19, 8, 6, 8, + 8, 19, 12, 8, 12, 6, 8, 19, 12, 12, 12, 8, 19, 6, 12, 8, + 19, 8, 19, 19, 12, 50, 12, 6, 1, 1, 93, 19, 94, 93, 19, 19, + 19, 19, 19, 19, 19, 19, 6, 12, 19, 94, 12, 8, 12, 12, 12, 12, + 12, 12, 6, 6, 6, 8, 19, 12, 19, 19, 8, 12, 12, 12, 12, 12, + 6, 6, 1, 6, 6, 6, 6, 6, 13, 20, 20, 13, 13, 13, 13, 13, + 13, 20, 20, 20, 20, 20, 20, 20, 13, 13, 55, 20, 20, 20, 55, 55, + 12, 12, 55, 12, 6, 56, 6, 73, 20, 20, 20,124, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 19, + 6, 8, 12, 6, 12, 12, 12, 12, 6, 6, 12, 75, 19, 12, 19, 8, + 12, 33, 4, 4, 66, 12, 12, 12, 8, 19, 19, 19, 19, 19, 19, 6, + 8, 8, 8, 8, 95, 10, 10, 10, 6, 6, 6, 6, 76, 26,125, 57, + 126, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,127, + 37, 31, 4, 37, 4, 4, 4, 4, 1, 29, 10, 10, 10, 10, 10, 10, + 15, 15, 15, 11, 65, 67, 10, 3, 4, 4, 4, 4, 4, 31,128, 10, + 38, 1, 1, 1, 1, 21, 4, 4, 9, 9, 9, 9, 9, 10, 10, 1, + 1, 1, 39, 4, 4, 4, 96, 33, 4, 4, 68, 51, 40, 4, 4, 1, + 9, 9, 9, 9, 9, 1, 41, 58, 10, 10, 10, 10, 10, 10, 10, 97, + 4, 4, 4, 4, 4, 4, 22, 1, 1, 1, 1, 1, 1, 21, 4, 4, + 4, 4, 13, 47, 10, 13, 51, 24, 1, 1, 1, 4, 4, 51, 4, 4, + 4, 4, 51, 4, 51, 4, 4, 4, 1, 1, 1, 1, 21, 4, 4, 10, + 1, 1, 1, 1,129, 1, 1, 1, 15, 15, 15, 69, 4, 4, 4, 4, + 1, 1, 1, 1, 34, 4, 4, 4, 4, 69, 4, 4, 4, 4, 4, 4, + 1, 1, 1, 1, 1, 17, 22, 14, 18, 4, 4, 4, 17, 14, 18, 14, + 21, 4, 4, 4, 1, 1, 1, 1, 1, 4, 10, 9, 9, 9, 9, 9, + 42, 1, 1, 1, 1, 1, 1, 1, 21, 14, 30, 1, 1, 1, 1, 1, + 18, 4, 4, 17, 14, 14, 18, 1, 1, 1, 1, 27, 14, 14, 1, 1, + 1, 24, 7, 7, 7, 57, 29, 4, 1, 1, 1, 1, 1, 1, 4, 14, + 18, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 22, 1, 1, 1, + 1, 1, 1, 9, 9, 9, 9, 9, 4, 1, 21, 10, 10, 10, 10, 10, + 18, 4, 4, 4, 17, 14, 18, 4, 67, 24, 24, 24,130, 4, 4, 4, + 18, 4, 4, 17, 14, 14, 18, 4, 4, 4, 4, 17, 14, 14, 1, 1, + 58, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 14, + 17, 14, 14, 14, 14, 14, 18, 4, 1, 1, 1, 27, 14, 14, 14, 14, + 7, 43, 3, 3, 57, 3, 3, 3, 17, 14, 22, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 22, 4, 17, 14, 14, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 1, 1, 1, 1, 9, 9, 9, 98, 7, 7, 7, 43, + 21, 14, 39, 1, 1, 1, 1, 1, 14, 14, 14, 17, 14, 14, 4, 4, + 4, 4, 17, 14, 14, 14, 1, 1, 99, 27, 14, 14, 14, 14, 14, 14, + 4, 14, 1, 1, 1, 1, 1, 1, 18, 4, 4, 14, 14, 14, 18, 41, + 3, 3, 1, 27, 7, 7, 7, 59, 7, 7, 7, 7, 43, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 17, 14, 4, 4, 4, 14, 14, 14, 14, + 9, 14, 10, 10, 10, 10, 10, 10, 21, 1, 4, 4, 4, 4, 4,131, + 1, 1, 1, 51, 4, 4, 4, 31, 21, 1, 4, 4, 4, 4, 22, 1, + 1, 1, 1, 13, 4, 4, 4, 4, 9, 9, 9, 9, 9, 9, 1, 1, + 41, 3, 10, 10, 10, 10, 10, 10, 10, 44, 44, 3, 4, 3, 3, 3, + 7, 7, 33, 33, 33, 23, 23, 14, 21, 4, 4, 4, 4, 4, 4, 17, + 4, 4, 31, 4, 1, 1, 21, 4, 4, 4, 4, 4, 4, 4, 4, 3, + 3, 3, 3, 40, 3, 3, 3, 3, 10, 10, 44, 3, 47, 10, 10, 10, + 1, 1, 1, 1, 1, 27, 18, 4, 17, 4, 4, 4, 18, 17, 18, 22, + 1, 1, 1, 14, 4, 1, 1, 4, 22, 14, 30, 27, 14, 14, 14, 1, + 21, 4, 22, 1, 1, 1, 1, 1, 1, 17, 18, 17, 14, 14, 18, 27, + 9, 9, 9, 9, 9, 14, 18, 3, 6, 6, 6, 6, 6, 76, 56, 6, + 1, 1, 1, 1, 1, 1, 21, 4, 1, 1, 1, 1, 1, 1, 41, 39, + 132, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,133, 70, 70, + 1, 1, 1, 1, 1, 29, 10, 16,134, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 17, 14, 14, 14, 14, 30, 1, 4, 61, 10, 10, 10, 10, 10, + 1, 1, 4, 18, 4, 4, 4, 14, 14, 14, 14, 17, 18, 4, 4, 4, + 4, 4, 10, 42, 10, 67, 21, 4, 10, 10, 10, 77, 10, 37, 4, 69, + 1, 34, 1, 1, 1, 1, 1, 1, 1, 1, 21, 22, 1, 1, 1, 1, + 1, 1, 1, 1, 21, 1, 1, 1, 4, 17, 14, 18, 17, 14, 14, 14, + 14, 17, 14, 14, 18, 4, 4, 4, 3, 3, 10, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 7, 7, 3, 1, 1, 1, 21, 17, 18, 4, 10, + 1, 1, 27, 17, 4, 4, 4, 4, 17, 17, 18, 4, 4, 4, 17, 14, + 10, 10, 10, 42, 10, 10, 10, 10, 4, 4, 4, 4, 4, 4, 4, 78, + 4, 4, 30, 1, 1, 1, 1, 1, 1, 1, 17, 4, 4, 17, 17, 14, + 14, 17, 30, 1, 1, 1, 1, 10, 44, 3, 3, 3, 3, 33, 4, 4, + 4, 4, 3, 3, 3, 3, 47, 10, 27, 4, 4, 14, 4, 18, 4, 1, + 1, 1, 1, 17, 4, 14, 18, 18, 4, 14, 14, 14, 14, 14, 10, 10, + 1, 1, 14, 14, 14, 14, 4, 4, 4, 4, 14, 4, 4, 31, 10, 10, + 9, 9, 9, 9, 9, 9, 99, 1, 6, 6, 6, 6, 19, 6, 6, 6, + 4, 31, 4, 4, 4, 4, 4, 4, 17, 4, 4, 4, 22, 1, 21, 1, + 1, 1, 22, 27, 4, 1, 1, 1, 6, 6, 6, 6, 6, 6, 13, 13, + 13, 13, 13, 13, 13, 56, 6, 6, 6, 6, 6, 6, 56, 6, 6, 6, + 6, 6, 6, 6, 6,101, 13, 13, 12, 12, 12, 6, 6, 6, 6, 12, + 6, 6, 6, 6, 19, 8, 8, 8, 6, 6, 6, 6, 8, 8, 79,102, + 62, 62, 62, 62, 62,135, 15, 15, 26, 26, 26, 10, 45,104, 45,104, + 10, 10, 10, 10,136, 15, 15,137, 10, 10, 10, 10,105,106, 10,107, + 108, 10, 52, 53, 10, 10, 10, 10, 10, 65,108, 10, 10, 10, 10,138, + 139, 13, 7, 7, 7, 11, 52,140, 7, 7, 7, 7, 7, 11, 52, 70, + 4, 4, 4, 4, 4, 4,141, 66, 78, 66, 78, 4, 4, 4, 4, 4, + 3, 71, 3, 80, 3, 19, 8, 6, 8, 12, 80, 3, 75, 8, 8, 3, + 3, 3, 71, 71, 71, 8, 8,142, 8, 8, 50, 1,109, 3, 6, 8, + 11, 11, 75, 6, 6, 36, 3,110, 16,143,144, 16,111, 3, 3, 3, + 11, 11, 35, 3, 3, 11, 3, 3, 35, 36, 3, 35, 3, 3, 3, 35, + 3, 3, 3, 3, 3, 3, 3, 11, 3, 35, 35, 3, 3, 3, 3, 3, + 3, 3, 11, 11, 11, 11, 11, 11, 3, 3, 3, 3, 23, 23, 3, 3, + 11, 3, 3, 3,145,146, 3, 3, 3, 3, 3, 3, 3, 3, 35, 3, + 3, 3, 3, 3, 3, 36, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, + 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, + 3, 3, 3, 36, 3, 3, 3, 3, 36, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 36, + 3, 3, 3, 3, 23, 23, 23, 23, 23, 23, 23, 7, 7, 7, 7, 7, + 7, 7, 3, 3, 3, 3, 3, 3, 11, 11, 52,112, 11, 11, 11, 11, + 11, 11, 11, 23, 23, 23, 23, 23, 11, 52, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28,112, 11, 11, 11, 11, 11, 11, 11, 23, 23, 11, 11, + 11, 11, 11, 11, 11, 11, 23, 11, 11, 11, 35, 36, 11, 11, 35, 3, + 12, 8, 12, 19, 19, 19, 19, 8, 12, 12, 19, 6, 6, 6, 13, 8, + 12, 12,110, 3, 3, 80, 19,147, 4, 12, 6, 6, 76, 10, 60, 10, + 1, 1, 1, 1, 1, 1, 1, 34, 10, 10, 10, 10, 10, 10, 10, 37, + 10, 45, 45, 10,105,106, 45, 10, 10, 10, 10, 64, 10, 77, 45, 10, + 45, 23, 23, 23, 23, 10, 10, 42, 10, 10, 10, 10, 10, 26, 10, 10, + 77,148, 10, 10, 10, 10, 10, 10, 3, 10, 81, 28, 28, 28,149, 26, + 72, 10,150,113, 23, 23, 23, 23, 23, 3, 23, 23, 23, 23,114, 70, + 151, 16, 16, 16, 16, 4, 4, 14,115, 13, 13, 3, 16,152, 29, 3, + 58, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21,153,116, 38, + 1, 1, 1, 1, 1, 29, 13, 38, 3, 7, 7, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1,117, 10, + 12, 12, 12, 12, 12, 12, 12, 21, 66,154, 4, 4, 4, 4, 4, 42, + 12, 12, 12, 12, 12, 12, 13, 4, 1, 1, 1, 16, 16, 16, 16, 16, + 4, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20,116, 13, 13, 13, 13, + 20, 12, 12, 12, 12, 12, 12, 12, 6, 12, 12, 12, 12, 12, 12, 12, + 56, 6, 6, 6, 19, 19, 19, 12, 12, 12, 12, 12, 55,155, 19, 50, + 12, 12, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 8, 8, 12, + 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 8, 8, 19, 19, 12, 12, + 12, 12, 12, 12, 12, 12, 8, 8, 95, 13,156, 50, 13, 50, 1, 1, + 1, 22, 1, 22, 1, 21, 1, 1, 1, 27, 18, 17, 3, 3, 4, 4, + 7, 7, 7, 3, 82, 3, 3, 3, 1, 1, 10, 10, 10, 10, 10, 10, + 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 14, 14, 14, 14, 14, + 14, 14, 4, 4, 4, 4, 4, 10, 4, 1, 1, 1, 10, 39, 39, 21, + 1, 1, 1, 4, 4, 4, 4, 10, 1, 1, 1, 21, 4, 4, 4, 4, + 4, 14, 14, 14, 14, 14, 14, 61, 1, 21, 14, 4, 4, 14, 4, 14, + 61, 10, 10, 10, 10, 10, 10, 42, 1, 1, 21, 38, 1, 1, 1, 1, + 1, 1, 1, 1, 21, 4, 4, 17, 18, 17, 18, 4, 4, 4, 4, 4, + 1, 21, 1, 1, 1, 1, 17, 14, 9, 9, 9, 9, 9, 9, 10, 10, + 38, 1, 1, 41, 3, 27, 17, 1, 22, 4, 22, 21, 22, 1, 1, 4, + 1, 1, 1, 1, 1, 1, 34, 10, 1, 1, 1, 1, 1, 27, 4, 14, + 10, 34,157, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6,102, 13, 13, + 6, 6, 6, 6,101, 20, 20, 20, 1, 27, 18, 14, 17, 61, 18, 4, + 6, 6, 6, 6, 6, 6, 50, 22, 1, 1, 1, 1,158, 1, 1, 1, + 1, 20, 20, 20, 20, 20, 20, 20, 20, 91, 3, 3, 3, 3, 3, 3, + 3, 58, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 82, 3, 10, 10, 10, 81, 53, 10, 10, 10, + 64,159,160, 28, 28, 28, 28, 28, 28, 28, 53, 81, 53, 10,107,161, + 10, 10, 10, 10,114, 28, 28, 53, 10,162, 11, 11, 67, 10, 10, 10, + 1, 1, 1, 1, 1, 1, 1,163, 10, 10, 84, 10, 23, 85, 64, 10, + 6, 6, 6, 6, 6, 89, 90, 52, 53, 23, 10, 1, 1, 1, 1, 1, + 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, + 24,164, 57, 24, 36, 11, 35, 3, 3, 3, 3, 3,165, 15, 3, 3, + 10, 10, 10, 60, 7, 7, 7, 7, 7, 7, 7, 43, 3, 3, 3, 3, + 16, 16,111, 7, 43, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 3, + 3, 3, 3, 3, 3, 3, 33, 4, 83, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 59, 1,113, 1, 1, 1, 1, 16, 16, 16, + 166, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 12, 6, 6, 6, 6, + 1, 1, 1, 29, 7, 7, 7, 7, 1, 1, 1, 41, 63, 7, 7, 7, + 1, 1, 1, 1, 1, 46, 7, 7, 1, 1, 1, 7, 7, 7, 7, 54, + 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 46, 54, + 1, 1, 1, 1, 58, 1, 1, 1, 1, 1, 21, 4, 4, 83, 7, 7, + 6, 6, 6, 6, 6, 7, 7, 7, 1, 1, 4, 4, 4, 4, 4, 4, + 9, 9, 9, 9, 9, 1, 1, 38, 8, 8, 8, 8,167, 4, 4,115, + 6, 6, 6, 6, 6, 6, 6, 11, 1, 1, 1, 1, 1, 21,168, 26, + 44, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, + 7, 7, 7, 59, 1, 1, 1, 1, 83, 7, 54, 10, 10, 10, 10, 10, + 1, 4, 4, 10, 10, 10, 10, 10, 1, 1, 46, 7, 7, 7, 7, 7, + 18, 30, 1, 1, 1, 1, 1, 1, 4, 4, 4, 31, 10, 10, 10, 10, + 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, + 22, 21, 22, 1, 1, 1, 1, 21, 14, 18, 4, 17, 18, 31, 97, 10, + 10, 4, 4, 4, 4, 4, 96, 15, 1, 1, 1, 21, 4, 4, 18, 4, + 4, 4, 4, 9, 9, 9, 9, 9, 10, 10, 27, 30, 1, 1, 1, 1, + 1, 21, 10, 1, 1, 1, 1, 1, 1, 27, 14, 4, 4, 4, 4, 17, + 30, 1, 29, 10, 37, 4, 31, 18, 9, 9, 9, 9, 9, 29, 29, 10, + 60, 7, 7, 7, 7, 7, 7, 7, 4, 14, 17, 4, 10, 10, 10, 22, + 17, 14, 14, 14, 14, 14, 14, 14, 1, 1, 1, 27, 14, 14, 30, 1, + 1, 14, 14, 4, 4, 4, 4, 4, 1, 1, 1, 1, 14, 18, 4, 4, + 4, 14, 14, 14, 14, 14, 14, 17, 22, 22, 10, 10, 10, 10, 10, 10, + 37, 4, 4, 4, 4, 4, 4, 4, 1, 1, 27, 14, 4, 4, 4, 4, + 14, 4, 17, 22, 1, 29, 10, 10, 9, 9, 9, 9, 9, 10, 10, 22, + 14, 18, 4, 4, 17, 17, 14, 18, 17, 4, 1, 39, 1, 1, 1, 1, + 14, 4, 4, 4, 14, 14, 4, 18, 31, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 1, 1, 4, 4, 14, 18, 4, 4, 4, 17, 18, 18, + 31, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 18, 14, + 4, 4, 4, 18, 29, 10, 10, 10, 1, 1, 1, 1, 1, 1, 21, 18, + 14, 4, 4, 18, 4, 4, 4, 4, 9, 9, 9, 9, 9, 7, 10, 44, + 4, 4, 4, 4, 18, 31, 10, 10, 7, 7, 7, 7, 7, 7, 7, 59, + 14, 14, 14, 14, 14, 18, 17, 22, 30, 18, 10, 10, 10, 10, 10, 10, + 27, 14, 4, 4, 4, 4, 14, 14, 22, 39, 14, 14, 14, 14, 14, 14, + 21, 4, 4, 4, 4, 22, 1, 1, 1, 21, 4, 4, 17, 21, 4, 31, + 10, 10, 10, 37, 4, 4, 4, 4, 21, 4, 4, 17, 18, 4, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 17, 4, 10, 39, 10, + 17, 4, 17, 17, 14, 14, 14, 14, 4, 4, 4, 4, 4, 4, 4, 18, + 10, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 17, 4, 4, 4, + 17, 4, 18, 4, 4, 4, 4, 4, 4, 4, 4, 21, 4, 4, 4, 4, + 1, 1, 1, 1, 1, 14, 14, 14, 4, 17, 18, 18, 1, 1, 1, 1, + 1, 1, 1, 1, 34, 1, 1, 1, 1, 21, 17, 61, 10, 10, 10, 10, + 4, 27, 1, 1, 1, 1, 1, 1, 1, 1, 14, 4, 4, 4, 4, 14, + 17, 31, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 4, 4, 4, + 7, 7, 43, 3, 3, 3, 57, 24, 82, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 47, 22, 1, 1, 21, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 14, 18, 4, 4, 4, 31, 10, 10, 10, 10, 10, + 4, 4, 4, 31, 10, 10, 3, 3, 13, 13, 44, 3, 3, 3, 3, 3, + 9, 9, 9, 9, 9,169, 7, 7, 7, 59, 1, 1, 1, 1, 1, 1, + 13, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 34,117, 10, + 7, 7, 7, 54, 10, 10, 10, 10, 8, 8, 8, 8, 8, 12, 6, 6, + 27, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 18, + 4, 68, 13, 13, 13, 13, 13, 13, 13, 42, 4, 4, 4, 4, 4, 4, + 14, 13, 16, 16, 16, 16, 16, 16, 1, 1, 1, 1, 1, 1, 33, 31, + 3, 3,118, 18, 4, 3,118, 14, 14,170, 15, 15, 15, 69, 4, 4, + 4, 40, 33, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, + 3, 4, 40, 3, 3, 3, 3, 3, 48, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 49, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 48, 6, 6, 6, 6, 49, 6, 6, 6, 8, 8, + 8, 8, 48, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 49, + 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 48, + 6, 6, 6, 6, 49, 6, 6, 6, 8, 8, 8, 8, 48, 6, 6, 6, + 6, 49, 6, 6, 6, 12, 6, 9, 4, 4, 4, 40, 3, 33, 4, 4, + 4, 4, 4, 4, 4, 4, 40, 3, 3, 3, 33, 3, 3, 3, 3, 3, + 3, 3, 40, 47, 10, 10, 10, 10, 10, 10, 10, 10, 10, 37, 4, 4, + 6, 6, 6, 6, 6,109, 6, 6, 4, 4, 4, 68, 13, 13, 13, 13, + 9, 9, 9, 9, 9, 9, 9, 41, 1, 1, 1, 1, 1, 1, 4, 4, + 9, 9, 9, 9, 9, 9, 9,171, 1, 1, 1, 1, 1, 34, 4, 4, + 172, 9, 9, 9, 9, 9, 9, 98, 1, 21, 1, 22, 1, 1, 1, 4, + 1, 1, 21, 4, 4, 4, 4, 34, 6, 6, 4, 4, 4, 68, 13, 13, + 7, 7, 7, 7, 7, 7, 63, 7,173, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 63, 7, 7, 7, 7, 7, 7, 43, 3, + 3, 3, 3, 3, 3, 92, 20, 20, 2, 2, 7, 7, 3, 3, 26, 26, + 12, 12, 4, 4, 5, 5, 15, 15, 9, 9, 13, 13, 21, 21, 25, 25, + 9, 5, 6, 6, 10, 10, 1, 1, 14, 14, 12, 10, 10, 12, 5, 9, + 24, 24, 7, 12, 12, 7, 22, 18, 23, 23, 0, 0, 17, 17, 7, 10, + 18, 22, 7, 21, 10, 7, 12, 21, 8, 8, 26, 12, 7, 6, 25, 26, + 26, 25, 21, 12, 6, 7, 21, 7, 12, 26, 7, 26, 21, 6, 15, 26, + 21, 26, 20, 19, 7, 15, 26, 21, 9, 25, 5, 25, 5, 7, 6, 12, + 25, 22, 18, 21, 15, 21, 6, 24, 6, 5, 26, 23, 26, 7, 15, 7, + 21, 15, 10, 21, 29, 29, 26, 15, 21, 17, 25, 21, 11, 11, 21, 23, + 12, 6, 1, 12, 18, 18, 9, 26, 29, 21, 21, 9, 24, 5, 25, 9, + 5, 21, 17, 21, 11, 12, 8, 24, 26, 9, 21, 22, 23, 26, 12, 15, + 23, 21, 21, 25, 9, 22, 21, 18, 24, 16, 5, 22, 25, 18, 24, 26, + 26, 24, 9, 8, 8, 5, 9, 6, 12, 1, 21, 1, 13, 21, 13, 7, + 17, 7, 5, 6, 5, 24, 9, 24, 22, 20, 21, 20, 19, 21, 21, 16, + 16, 21, 7, 5, 5, 26, 14, 15, 18, 25, 7, 14, 17, 22, 17, 6, + 24, 6, 6, 21, 26, 10, 25, 0, 7, 20, 25, 1, 24, 15, 7, 19, + 9, 21, 17, 26, 23, 12, 17, 12, 1, 21, 24, 7, 23, 7, 12, 23, + 29, 7, 7, 22, 14, 7, 29, 1, 27, 28, 1, 29, 21, 29, 15, 6, + 18, 6, 12, 11, 26, 5, 14, 9, 5, 14, 26, 22, 18, 26, 5, 12, + 22, 21, 18, 17, 26, 6, 26, 14, 14, 6, 12, 24, 11, 21, 24, 9, + 6, 9, 6, 10, 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 7, 1, + 25, 24, 26, 1, 21, 14, 9, 12, 12, 17, 13, 15, 10, 1, 13, 23, + 7, 13, 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, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 35, 0, 0, 0, 0, 36, 0, 37, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, + 0, 0, 0, 0, 41, 42, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 9, 0, 0, 0, 10, + 11, 12, 13, 0, 14, 15, 16, 0, 17, 18, 19, 20, 21, 1, 22, 1, + 23, 1, 2, 1, 2, 1, 2, 0, 2, 1, 24, 1, 2, 25, 2, 0, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 36, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 38, 0, 0, + 39, 0, 0, 40, 0, 41, 0, 0, 0, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 0, 0, 51, 0, 0, 0, 52, 0, 0, 0, 53, 0, 0, 0, + 0, 0, 0, 0, 54, 0, 3, 0, 55, 56, 0, 57, 0, 0, 0, 0, + 0, 0, 58, 59, 60, 0, 0, 0, 0, 61, 0, 0, 62, 63, 64, 4, + 65, 0, 0, 66, 67, 0, 0, 0, 68, 0, 0, 0, 0, 69, 0, 0, + 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 71, 0, 0, 0, 72, 0, 73, 0, 0, 74, 0, 0, 75, 0, 0, 0, + 0, 0, 0, 0, 0, 76, 77, 0, 0, 0, 0, 78, 79, 0, 80, 81, + 0, 0, 82, 5, 0, 83, 4, 0, 84, 85, 0, 0, 86, 87, 88, 0, + 89, 0, 90, 0, 91, 0, 0, 3, 92, 3, 0, 93, 0, 94, 0, 0, + 0, 5, 0, 0, 0, 95, 96, 0, 97, 98, 99,100, 0, 0, 0, 0, + 0, 3, 0, 0, 0, 0,101,102, 0, 0, 0, 0, 0, 0,103, 0, + 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,106, 0, 0,107, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,108,109, 0, 0,110, 0, 0, 0, 0, 0, + 0,111, 0,112, 0, 6, 0, 0, 0, 0, 0,113,114, 0, 0, 0, + 0, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,117, 0, 0, 0, + 0, 0, 0, 0,118, 0,119, 0, 0, 0, 0, 0, 0, 0, 2, 1, + 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 11, 0, 0, 0, 14, 0, + 0, 0, 16, 3, 17, 18, 19, 20, 21, 22, 0, 23, 0, 0, 0, 0, + 24, 25, 26, 27, 0, 0, 0, 0, 28, 0, 0, 29, 30, 0, 31, 0, + 32, 33, 0, 0, 34, 0, 35, 36, 0, 0, 0, 0, 0, 37, 38, 0, + 39, 40, 0, 0, 41, 0, 0, 0, 42, 0, 0, 43, 44, 45, 46, 1, + 47, 0, 0, 1, 0, 0, 7, 1, 48, 0, 0, 0, 0, 0, 49, 50, + 0, 0, 0, 0, 0, 0, 51, 52, 0, 0, 0, 0, 0, 0, 53, 54, + 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 57, 58, 0, 0, 0, 59, + 0, 0, 0, 0, 0, 0, 60, 12, 0, 0, 0, 0, 61, 0, 0, 0, + 62, 0, 5, 0, 63, 0, 0, 0, 0, 64, 0, 0, 0, 0, 65, 0, + 66, 0, 0, 0, 0, 6, 67, 0, 0, 0, 68, 69, 70, 71, 0, 0, + 0, 0, 72, 5, 0, 73, 74, 0, 0, 75, 0, 0, 0, 76, 77, 0, + 0, 0, 78, 0, 79, 80, 81, 82, 83, 3, 84, 0, 85, 86, 87, 0, + 0, 8, 9, 0, 0, 3, 3, 0, 0, 88, 0, 0, 89, 0, 0, 0, + 0, 8, 90, 0, 91, 0, 0, 0, 0, 0, 9, 10, 0, 92, 0, 5, + 0, 3, 9, 0, 0, 93, 0, 0, 94, 0, 0, 6, 0, 0, 0, 0, + 0, 0, 95, 96, 0, 0, 10, 0, 0, 1, 0, 0, 97, 0, 0, 0, + 0, 98, 0, 0, 0, 0, 12, 0, 0, 13, 0, 0, 0, 0, 99,100, + 0, 0,101, 0, 0,102, 0, 0, 0,103, 0, 0, 0,104, 0, 0, + 0,105, 0, 0, 0, 0,106,107, 13, 0, 0,108, 0, 0, 0, 10, + 0, 0,109,110, 0, 0,111,112, 0, 0, 0, 0, 0, 0,113, 0, + 0,114, 0, 0, 0, 0,115, 1, 0,116,117,118, 6, 0, 0,119, + 7, 0, 0,120, 0, 0, 0,121, 0, 0, 0, 0, 0, 0,122, 0, + 0,123, 0, 0, 0, 0,124, 11, 0, 0, 0, 0, 0, 6, 0, 0, + 0, 0, 5, 15, 0, 0, 0, 0,125, 0, 0,126, 0, 0, 0, 0, + 15, 0, 0,127, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,128, 0, + 0, 0,129, 0,130, 0, 0, 0, 0,131,132,133, 0,134, 0,135, + 0, 0, 0,136,137,138, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, + 0,139, 0, 0, 0,140, 0, 0, 0,141, 0, 0, 0,142,143, 0, + 144, 0, 0,145, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 9, + 1, 1, 1, 1, 0, 0, 0, 2, 0, 3, 0, 0, 3, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 6, 11, 0, 0, 0, 0, 14, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 17, 29, 0, 0, 0, 0, 0, 31, 0, + 0, 2, 0, 0, 1, 12, 0, 0, 1, 49, 50, 5, 51, 52, 53, 5, + 5, 22, 32, 23, 1, 54, 24, 55, 16, 33, 56, 57, 58, 1, 1, 1, + 6, 1, 0, 0, 59, 7, 60, 1, 34, 5, 7, 61, 62, 63, 64, 65, + 66, 67, 0, 0, 1, 1, 68, 0, 0, 0, 69, 70, 71, 35, 1, 25, + 72, 0, 0, 0, 0, 8, 1, 26, 16, 26, 73, 27, 74, 0, 0, 0, + 36, 25, 75, 37, 7, 37, 76, 0, 0, 0, 6, 1, 7, 0, 0, 17, + 0, 8, 38, 1, 1, 13, 13, 11, 0, 0, 39, 0, 0, 6, 18, 1, + 0, 0, 8, 16, 5, 1, 1, 1, 77, 7, 36, 18, 78, 7, 35, 1, + 79, 10, 0, 0, 0, 80, 0, 0, 0, 0, 2, 3, 0, 0, 14, 0, + 0, 0, 81, 0, 0, 0, 82, 0, 0, 0, 83, 0, 0, 0, 84, 0, + 0, 0, 40, 0, 0, 85, 86, 0, 87, 88, 89, 90, 91, 92, 0, 0, + 0, 93, 0, 0, 0, 15, 28, 0, 0, 0, 0, 13, 0, 41, 0, 0, + 14, 0, 0, 20, 0, 0, 94, 0, 0, 0, 95, 0, 0, 6, 29, 0, + 0, 13, 1, 96, 1, 18, 33, 97, 25, 23, 7, 1, 1, 1, 1, 27, + 1, 7, 98, 0, 0, 9, 0, 0, 0, 0, 6, 23, 1, 0, 0, 0, + 0, 0, 30, 0, 0, 21, 0, 0, 30, 0, 0, 0, 0, 15, 0, 0, + 12, 32, 24, 5, 99, 22, 42, 17, 0, 10, 11, 0, 7, 1, 7,100, + 101, 1, 1, 1, 1,102,103,104,105, 1,106, 10, 20,107,108, 5, + 10, 0, 0, 0, 0, 0,109,110, 0, 0,111, 0, 0, 1, 1, 11, + 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 43, 40, 2, 0, 0, 0, + 44,112, 10, 8, 20, 0, 0, 0, 0, 0, 0,113, 1, 16, 5, 24, + 0, 8, 12, 0, 0, 0, 0,114, 0, 0,115, 2, 0,116, 0, 0, + 0, 1, 0, 0, 0, 0, 13, 11, 0, 0, 6, 10, 0, 0, 45, 39, + 0, 45, 16, 18, 46, 27, 0, 0, 3, 0, 0, 2, 12, 0, 0, 0, + 2, 3, 0, 0, 3, 0, 21, 0, 0, 31, 0, 0, 0, 0,117, 0, + 0, 0, 15, 9, 0, 8, 1, 10, 1, 10, 0, 0, 0, 0, 0, 30, + 14, 21, 0, 0, 47, 0, 0, 0, 9, 0, 0, 0, 0, 47, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 28, 0, 0, 4, 0, 21, 41, 0, 0, + 28, 0, 0, 0, 22, 42, 0, 0,118, 0, 0, 0, 0, 0, 0,119, + 0,120,121,122,123, 0, 43, 5, 48, 13, 34, 0, 0, 0, 8, 11, + 8, 10, 0, 0, 1, 12, 1, 1, 1, 1, 26, 1, 38, 44, 12, 0, + 0, 0, 0, 1, 0, 0, 0,124, 0, 0, 0, 46, 6, 19, 0, 8, + 0, 20, 0, 0, 5, 48, 0, 0, 0, 1,125, 0, 0, 0, 0,230, + 230,230,230, 0, 0, 0, 9, 9, 0, 0, 0, 0, 9, 0, 0,220, + 220,220,220, 0, 0, 0,230,230,230,220,230, 0, 0,230,230, 7, + 0, 0, 0,230, 0, 0, 0,230,230, 0, 0,230,230,230, 0, 0, + 230,230,230, 0, 0, 9, 0, 0, 0, 0, 7,230,230,230,220, 0, + 220, 0, 0,230,220,220,220, 0, 0,230, 0, 0,230, 0, 0, 0, + 0, 7, 0, 1, 1, 1, 1,220,230,230,230,220,220,230,230,220, + 230,230,220,230, 0, 0,230,230,220, 0, 0, 0, 9, 9, 0,220, + 0, 0, 0, 0, 0, 9, 9, 0, 9, 7, 0, 1,220,220,220,220, + 220,220,230,230,230,220,220,230,220,220,230,230,220,230,230,220, + 230,220,230,230,230, 0,230, 0,220,220,220,220,220, 0, 0, 9, + 9, 0, 0, 1, 0, 0, 0, 0, 0, 0,220,230, 0,230,230, 0, + 0,220,220, 0, 0,230,220, 0, 0, 9, 7,220,220,220, 0,230, + 232,220,220,220,220,232,216,220,202,202,220,220,220,220,202,202, + 220,220,220,230,240,230,220,230,220,220, 0,232,220,220,230,233, + 234,234,233,234,234,233,230, 0,220,230,230,230,230,222,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, 35, 0, 0, 0,230, + 0,220,230, 0, 36, 0, 0,220,220,230,220,220,230,230, 0,230, + 230, 0,220, 27, 28, 29,230, 0,230,220,230, 0, 84, 91, 0,103, + 103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122, 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,228, 0, 0, 0,222,230,220,230, 0, 0,220,230, + 220, 0,220,230,230,230,234,230, 0, 1, 1,230,234,214,220,202, + 230,230,230,230,230,232,228,228,220,218,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,220, 0, 0,230, 0, + 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230,220, 0, 0, + 7, 9, 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,232,232,220,230,230, + 230, 7, 0, 1, 0, 0, 32, 0, 48, 0, 0, 84, 96,135,144, 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,176, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 24, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 40, 0, 0, + 0, 0, 0, 48, 56, 64, 0, 0, 0, 0, 0, 72, 80, 88, 96,104, + 0, 0, 0, 0, 0, 0, 0, 0,112, 0,120, 0, 0, 0, 0, 0, + 0,128,136,144,152,160,168, 0, 0, 0,176,184,192, 0, 0, 0, + 0, 0, 0,200, 0, 0, 0, 0, 0, 0, 0, 0,208, 0, 0,216, + 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, + 36, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 0, 0, 64, 0, + 68, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 72, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 0, 0, 0, 0, 0, 0, + 20, 0, 20, 0, 0, 0, 0, 0, 0, 0, 76, 80, 84, 88, 0, 0, + 12, 92, 96, 28, 0,100,104, 4, 4, 4,108, 44,112,116,120, 4, + 124, 0,128,132, 4, 4, 48,136,140, 0, 32, 0, 0, 0, 40, 0, + 0, 0, 0, 0, 0, 0, 4, 48, 0, 52,144, 20,148,152, 4, 0, + 0,156,160,164,168,172, 4, 0,176, 56, 60,180, 32, 0, 16,184, + 56, 0, 0, 0, 0, 0, 52, 12, 12, 0, 0, 0, 0, 12, 0, 0, + 188, 8, 8, 8, 8,192,196, 8, 8, 8, 8,200,204,208,212, 60, + 44, 0, 0, 0, 0, 0, 0, 0,216, 28,220, 0, 12, 4, 16, 0, + 0, 0, 0,224,228, 0, 0, 0, 0, 0, 4,232, 32, 0, 0, 0, + 0, 0, 0, 0,236, 12, 0, 0, 0, 0, 16, 0, 36, 0, 0, 0, + 24, 0, 0, 0,240,244, 0, 0, 0, 0, 2, 2, 2, 2, 4, 4, + 4, 4, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 6, 8, 0, 10, + 12, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 14, 16, 6, 8, + 0, 0, 4, 8, 0, 0, 2, 2, 2, 0, 0, 6, 4, 8, 2, 0, + 2, 0, 0, 0, 0, 6, 0, 20, 0, 0, 0, 22, 0, 0, 0, 6, + 8, 0, 24, 26, 28, 0, 0, 0, 30, 0, 0, 0, 0, 32, 34, 36, + 38, 0, 0, 40, 42, 0, 0, 0, 18, 0, 0, 0, 2, 2, 2, 2, + 0, 2, 2, 2, 0, 6, 44, 0, 0, 0, 0, 2, 0, 46, 48, 50, + 0, 0, 52, 0, 0, 0, 6, 4, 54, 0, 2, 0, 0, 2, 2, 56, + 58, 60, 0, 62, 64, 18, 2, 10, 12, 0, 0, 0, 66, 8, 0, 2, + 2, 2, 0, 6, 4, 4, 4, 4, 68, 2, 70, 4, 4, 4, 8, 72, + 0, 0, 74, 76, 2, 0, 78, 0, 0, 0, 4, 8, 2, 0, 0, 0, + 80, 0, 6, 4, 4, 4, 4, 8, 0, 2, 2, 2, 2, 6, 4, 4, + 4, 8, 0, 0, 0, 82, 0, 84, 86, 0, 0, 0, 2, 88, 0, 0, + 0, 90, 6, 8, 2, 0, 0, 0, 6, 4, 4, 4, 8, 0, 2, 0, + 2, 2, 6, 4, 4, 8, 0, 10, 12, 6, 8, 2, 0, 0, 50, 84, + 118,152, 17,161, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 5, 16, 17, 18, 1, 1, 1, 1, 1, 1, 19, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 20, 21, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 0, 35, 4, 4, 4, 4, 4, 36, 0, 0, 0, + 0, 0, 0, 37, 0, 38, 39, 3, 3, 3, 3, 3, 3, 40, 41, 0, + 0, 0, 0, 0, 0, 0, 42, 43, 0, 0, 44, 0, 0, 0, 45, 46, + 5, 47, 48, 49, 50, 51, 52, 53, 5, 5, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6, 0, 0, 6, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 54, 0, 0, 55, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, + 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, + 3, 3, 3, 1, 1, 1, 1, 1, 0, 0, 0, 26, 27, 8, 8, 8, + 28, 29, 30, 19, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 2, 2, 13, + 13, 13, 56, 11, 11, 11, 11, 11, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 8, 8, 16, 16, 72, 73, 74, 75, 3, + 3, 3, 3, 20, 20, 3, 3, 3, 3, 3, 3, 76, 77, 78, 79, 3, + 1, 1, 80, 81, 82, 83, 84, 85, 86, 87, 3, 1, 1, 1, 88, 1, + 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 89, 21, 21, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101, 0, 0, 1, 1, 1, + 1,102, 9, 9, 9,103, 9,104,105,106,107, 22, 22,108,109, 0, + 110,111,112,113,114,115,116, 17, 17, 17, 8,117,118,119,120,121, + 122,123,124,125,126,127,128, 9,129,130,131,132,133,134,135,136, + 137,138,139,140,141, 0,142,143,144,145, 0,146,147,148,149,150, + 151,152,153,154,155,156,157, 0,158,159,160, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,161, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0,162, 0, 0, + 0, 0, 0, 14, 14, 14, 14,163,164, 23, 23, 0, 0,165, 0,166, + 167,168,169, 4, 4, 4, 4, 4, 4, 15, 15, 15, 15, 4, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,170,171,172,173, 18, 18, + 18, 0, 0,174,175, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, + 3,176, 3, 3, 3,177,178, 16, 3, 3, 0, 10, 10, 10, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0,179, 19,180, 0, 0, + 181, 0, 0, 0,182, 0,183, 0,184, 0, 13, 24, 24,185, 0, 0, + 0, 0, 0, 3, 3, 3, 0, 9, 9, 0, 0, 3, 3, 3, 3,186, + 0, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 25, 25, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 7, + 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 10, + 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 16, + 16, 16, 16, 16, 16, 16, 16, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 18, 18, 18, 18, 18, 18, 18, 18, 17, + 17, 17, 17, 17, 17, 17, 17, 20, 20, 20, 20, 20, 20, 20, 20, 19, + 19, 19, 19, 19, 19, 19, 19, 15, 15, 15, 15, 15, 15, 15, 15, 25, + 25, 25, 25, 25, 25, 25, 25, 23, 23, 23, 23, 23, 23, 23, 23, 26, + 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, + 28, 28, 28, 28, 28, 28, 28, 14, 14, 14, 14, 14, 14, 14, 14, 3, + 3, 3, 3,118,119,118,119, 3, 3,156,156, 7,157, 7,157, 7, + 7, 7,158, 3, 3,180, 3, 14, 14, 14, 14, 14, 14, 14,181,182, + 17, 17, 17, 17, 17,183, 17,184, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15,185,100,100,100,100,100,186, 40, 40, 40, 40, 40, 40,187, + 188, 6, 6,189,190, 6,191, 6, 6, 6, 6, 6,192, 6, 6, 85, + 85, 85, 85, 85, 6, 6, 6,120,120,120,120,121,121,121,121,122, + 122,122,122,159,159, 85, 6, 6, 6, 6, 6, 6, 6,193, 6, 30, + 30, 30, 30, 30,194,195, 30, 45, 45, 45, 45, 45, 45, 45, 45, 46, + 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 48, + 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 49, + 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51, + 51, 51, 51, 51, 51, 51, 51, 41, 41, 41, 41, 41, 41, 41, 41, 81, + 81, 81,196, 81, 81, 81, 81, 52, 52, 52, 52, 52, 52, 52, 52, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,197, 29, 29, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 35, 35, 35, 35, 35,198, 12, + 12, 36, 36, 36, 36, 36, 36,160,160,101,101,101,101,199,101,161, + 161,200,201,162,162,163,163, 37, 37, 37, 37, 37, 37, 37, 37,202, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 11, 11, 11, 11, 11,102, + 102,102,102,102,140,140,140, 86, 86, 86, 86, 86, 86, 37, 37,164, + 164, 42, 42, 42, 42, 42, 42, 42, 42, 42, 14, 14, 14, 14, 14, 53, + 53, 53, 53, 53, 53, 53, 53,103,103,103,103,123,123,123,123,104, + 104,104,104,104,141,141,141, 15, 35, 35, 35,103,203,204,205, 7, + 7,206, 7, 7,207,208,209, 7, 7, 7,210, 14, 14, 14, 14,211, + 3, 3, 3, 3, 3, 3,212, 3, 7, 3, 3, 3, 14, 14, 14, 3, + 3,213,214,215, 3, 7, 7,158, 3, 3, 3, 3, 3, 3, 3, 43, + 43, 43, 43, 43, 43, 7, 7, 54, 54, 54, 54, 54, 54, 54, 54, 35, + 35, 35,105,105,105,105,105, 12, 12, 12, 12, 12, 12, 15, 15, 1, + 1, 1, 1, 1, 1, 1, 3,216, 3,217,218,219, 22, 22, 22, 22, + 220,165, 21, 21, 21, 21,221,106,106,106,222, 2, 2, 2, 2, 2, + 3,106,106, 3, 3, 3, 21, 2, 2, 3, 3, 3, 3, 2,223, 3, + 3, 3, 3, 3, 21, 21,224, 21, 21, 21, 21, 21,225, 3, 3, 1, + 1, 1, 1, 3, 3, 3, 3, 9, 9, 9, 9, 9, 82, 82, 82, 23, + 23, 23, 23, 15, 15, 15, 15, 15, 15, 13, 13, 13, 13, 13, 13, 3, + 3,226, 7, 7, 7, 7, 7,227, 7, 7, 7, 7, 7, 7, 7,142, + 142,142, 3,124,124,124,124, 87, 87, 87, 87, 87, 87, 30, 30,166, + 166,228,143,143,143, 2, 2,107,107,107,107,229,107, 24, 24, 88, + 88, 88, 88, 88, 88, 24, 24, 89, 89, 89, 89, 89, 89, 90, 90, 12, + 12, 12, 7, 7,230,231, 36, 36, 36, 36, 36, 90, 90, 90, 90, 7, + 232, 40, 40, 40, 6, 6, 6, 6, 6, 6,233, 6, 6, 6, 6, 14, + 3,234, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6,235, 3, + 3,118,119,118,119,236,165, 21,237, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3, 17, 17, 17, 17, 17, 3, 17, 17, 17, 3, 3,238,167, + 167,125,125,125,125,239, 3,144,144,144,168,168,145,145,145,169, + 169, 91, 91, 91, 91, 91, 91,108,108,108,108,108,146,146,146,147, + 147,147,109,109,109,109,109,148,148,148,126,126,126,126,110,110, + 110,110,110,127,127,127,127,128,128,128,128,170,170,171,171, 92, + 92, 92, 92, 92, 92,172,172,173,173,174,174,129,129,129,129,175, + 175, 93, 93, 93, 93, 93, 93, 94, 94, 94, 94, 94, 94,176,176,130, + 130,130,130,131,131,131,131,132,132,132,132,177,177,178,178, 55, + 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 57, + 57, 57, 57, 57, 57, 57, 57,133,133,133,133, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34,134,134,134,134,240, 6, 6, 6,149, + 149,149,135,135,135,135,136,136,136,136,150,150,150,179,179, 58, + 58, 58, 58, 58, 58, 58, 58,111,111,111,111,111,151,151,151,112, + 112,112,112,112,152,152,152, 59, 59, 59, 59, 59, 59,241, 41, 60, + 60, 60, 60, 60, 60, 60, 60,153,153,153,113,113,113,113,113, 83, + 83, 83,242, 83, 83, 83, 83, 61, 61, 61, 61, 61, 61, 61, 61, 62, + 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 64, + 64, 64, 64, 64, 64, 64, 64, 95, 95, 95, 95, 95, 95, 33, 33,114, + 114,114,114,114, 24, 24, 24, 65, 65, 65, 65, 65, 65, 65, 65, 66, + 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, 68, + 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69,115, + 115,115,115,115, 96, 96, 96, 96, 96, 96, 11,137,137,137,137, 30, + 30, 30, 30, 30, 30, 59, 59, 70, 70, 70, 70, 70, 70, 70, 70, 84, + 84, 84, 84, 84, 84, 84, 44, 44, 44, 44, 44, 44, 44, 44, 44, 97, + 97, 97, 97, 97, 97,116,116,116,116,116,117,117,117,117,117, 71, + 71, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 72, 72, 82, + 82, 82, 82, 32, 32, 32, 32, 73, 73, 73, 73, 73, 73, 73, 73, 74, + 74, 74, 74, 74, 74, 74, 74, 13, 13, 13, 13,154,154,154, 98, 98, + 98, 98, 98, 98,155,155,155, 75, 75, 75, 75, 75, 75, 75, 75, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 99, 99, 99, 99, 99, 99, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,243, 1, 21, + 21, 21, 21, 21, 21, 21, 21,244, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 21,245, 22,246, 21, 19, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 3, 3, 3, 3, 3, 3, 14, + 14, 14, 14, 14, 3, 3, 3, 3, 3, 3, 3, 3, 3,247,248,249, + 3,250, 3, 3, 3, 3, 3, 43, 43, 43, 15, 15, 15, 15, 15, 76, + 76, 76, 76, 76, 76, 76, 76,138,138,138,138,139,139,139,139, 77, + 77, 77, 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, 79, + 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, 80,251, + 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 1, 1, 1, 1, 2, + 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, + 10, 10, 10, 11, 11, 11, 11, 13, 13, 13, 13, 14, 14, 14, 14, 12, + 12, 12, 12, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, + 18, 18, 18, 21, 21, 21, 21, 22, 22, 22, 22, 19, 19, 19, 19, 20, + 20, 20, 20, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, + 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, + 30, 30, 30, 31, 31, 31, 31, 33, 33, 33, 33, 32, 32, 32, 32, 34, + 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 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, 46, 46, 46, 46, 47, + 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, + 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 45, + 45, 45, 45, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, + 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, + 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, + 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, + 70, 70, 70, 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, 83, + 83, 83, 83, 82, 82, 82, 82, 84, 84, 84, 84, 86, 86, 86, 86, 87, + 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, + 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, + 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97, 98, 98, 98, 98, 99, + 99, 99, 99,100,100,100,100, 85, 85, 85, 85,102,102,102,102,103, + 103,103,103,104,104,104,104,105,105,105,105,106,106,106,106,107, + 107,107,107,101,101,101,101,108,108,108,108,109,109,109,109,110, + 110,110,110,111,111,111,111,112,112,112,112,113,113,113,113,114, + 114,114,114,115,115,115,115,116,116,116,116,117,117,117,117,175, + 7, 7, 7, 7, 7,174, 3,118,118,118,118,119,119,119,119,120, + 120,120,120,121,121,121,121,122,122,122,122,123,123,123,123,124, + 124,124,124,125,125,125,125,126,126,126,126,127,127,127,127,128, + 128,128,128,129,129,129,129,130,130,130,130,131,131,131,131,132, + 132,132,132,133,133,133,133,134,134,134,134,135,135,135,135,136, + 136,136,136,137,137,137,137,138,138,138,138,139,139,139,139,140, + 140,140,140,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, 3, 3,177, 3, 7,174, 7, 7, 7, + 7,179, 3,155,155,155,155,156,156,156,156,157,157,157,157,158, + 158,158,158,159,159,159,159,160,160,160,160,182, 19, 19, 19,154, + 154,154,154,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, 7,179,194, 3, 17,195, 17,196, 17, + 197, 17, 17,198, 45, 45, 45, 15,199, 15, 15,200, 85, 85, 85,183, + 40, 40, 40, 6,184, 6,185, 6, 6,180,180,185, 6,201, 12, 12, + 202, 6, 6,203, 6, 6, 6, 6, 6, 6,184,204, 6, 6, 6,205, + 206, 30, 30, 30,207, 30, 30, 81, 81, 81,208, 29,209,210, 29, 35, + 35,211, 35,102,102,212,213,176,176,176,176,176,214, 3, 3,215, + 216, 32, 32,186, 12, 12, 12,217, 12,181,218, 3,181,178, 3, 7, + 187,219, 7, 7, 7, 7,220,221,187,222, 7, 7, 7,223, 7, 7, + 7, 7,224, 3, 3, 3,178,175, 3, 3,188, 3,225,189, 3,177, + 3, 3, 3, 3, 3, 3,177, 3,226, 3, 3,227, 1,228,229, 3, + 3, 1, 3,190, 20, 20, 20, 20, 20,230,190, 19, 19,191,182,231, + 2, 2, 2, 2, 2, 2,232, 19, 19, 19,191, 19, 19, 3, 3,189, + 7, 7, 7, 7, 7,188, 7,154,154,154,233,101,101,101,234, 7, + 7,174, 7, 7,235,236, 3,237, 85, 85,183, 6, 6, 6,238, 12, + 12, 12,239, 6, 6, 6,180, 3,240, 19, 19, 19, 19, 19,241, 3, + 3, 3,192,181, 3, 3, 3,242, 6, 6, 6,243, 41, 41, 41, 82, + 82,244, 82,245, 18, 18, 18,246, 20, 20, 20,247, 20, 20, 20, 20, + 248, 19, 19, 3,193,178, 3, 3, 3,193, 12,186,192, 12, 3, 3, + 3,249,178,250, 3, 3, 3, 2, 2, 2, 2, 13, 13, 13, 13, 12, + 12, 12, 12, 0, 0, 0, 0,136,136,136,136, 80, 80, 80, 80, 3, + 3, 3, 3, 19, 19, 19, 19, 63, 63, 63, 63, 39, 39, 39, 39,131, + 131,131,131, 28, 28, 28, 28, 1, 1, 1, 1, 30, 30, 30, 30, 79, + 79, 79, 79, 6, 6, 6, 6,127,127,127,127, 9, 9, 9, 9,155, + 155,155,155, 17, 17, 17, 17, 15, 15, 15, 15,139,139,139,139,110, + 110,110,110, 77, 77, 77, 77, 33, 33, 33, 33, 27, 27, 27, 27, 49, + 49, 49, 49,119,119,119,119,113,113,113,113, 25, 25, 25, 25, 7, + 7, 7, 7, 99, 99, 99, 99, 32, 32, 32, 32, 22, 22, 22, 22,165, + 165,165,165, 8, 8, 8, 8, 29, 29, 29, 29, 31, 31, 31, 31,146, + 146,146,146,105,105,105,105, 14, 14, 14, 14, 36, 36, 36, 36, 91, + 91, 91, 91, 56, 56, 56, 56,134,134,134,134, 55, 55, 55, 55, 5, + 5, 5, 5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 23, + 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 18, 18, 18, 18, 62, + 62, 62, 62,122,122,122,122, 89, 89, 89, 89,130,130,130,130, 94, + 94, 94, 94,100,100,100,100,108,108,108,108,171,171,171,171,137, + 137,137,137,124,124,124,124,123,123,123,123,126,126,126,126,142, + 142,142,142,125,125,125,125,154,154,154,154,150,150,150,150,169, + 169,169,169,145,145,145,145,163,163,163,163,157,157,157,157,166, + 166,166,166,167,167,167,167,151,151,151,151,164,164,164,164,168, + 168,168,168,174,174,174,174,132,132,132,132, 24, 24, 24, 24,107, + 107,107,107, 86, 86, 86, 86,133,133,133,133, 4, 4, 4, 4, 37, + 37, 37, 37, 58, 58, 58, 58, 75, 75, 75, 75, 68, 68, 68, 68, 92, + 92, 92, 92, 87, 87, 87, 87, 59, 59, 59, 59,116,116,116,116, 97, + 97, 97, 97, 57, 57, 57, 57,114,114,114,114,140,140,140,140,138, + 138,138,138,159,159,159,159,172,172,172,172, 84, 84, 84, 84, 35, + 35, 35, 35, 48, 48, 48, 48, 76, 76, 76, 76, 70, 70, 70, 70, 61, + 61, 61, 61, 26, 26, 26, 26, 40, 40, 40, 40,135,135,135,135,161, + 161,161,161, 85, 85, 85, 85, 96, 96, 96, 96,109,109,109,109,102, + 102,102,102,141,141,141,141,143,143,143,143,175,175,175,175, 38, + 38, 38, 38, 64, 64, 64, 64, 90, 90, 90, 90, 93, 93, 93, 93, 65, + 65, 65, 65, 67, 67, 67, 67,104,104,104,104,170,170,170,170, 47, + 47, 47, 47,173,173,173,173,117,117,117,117,112,112,112,112, 78, + 78, 78, 78,144,144,144,144,156,156,156,156,148,148,148,148,158, + 158,158,158,121,121,121,121,160,160,160,160,152,152,152,152, 52, + 52, 52, 52, 73, 73, 73, 73, 60, 60, 60, 60, 74, 74, 74, 74, 42, + 42, 42, 42,118,118,118,118, 51, 51, 51, 51, 50, 50, 50, 50,106, + 106,106,106,147,147,147,147,153,153,153,153,101,101,101,101,111, + 111,111,111,129,129,129,129,115,115,115,115,103,103,103,103, 69, + 69, 69, 69, 95, 95, 95, 95, 34, 34, 34, 34, 45, 45, 45, 45, 43, + 43, 43, 43, 46, 46, 46, 46, 54, 54, 54, 54, 71, 71, 71, 71, 41, + 41, 41, 41, 53, 53, 53, 53, 81, 81, 81, 81,120,120,120,120,128, + 128,128,128, 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 88, + 88, 88, 88, 83, 83, 83, 83, 82, 82, 82, 82,149,149,149,149, 19, + 19, 19, 0, 0, 19, 19, 19, 44, 44, 44, 44, 0, 0, 19, 0, 1, + 1, 0, 0, 19, 0, 0, 0, 3, 3, 3, 0, 1, 0, 0, 0, 0, + 17, 17, 17, 4, 14, 14, 14, 3, 0, 3, 3, 0, 3, 3, 3, 1, + 1, 1, 0, 19, 19, 9, 9, 0, 0, 0, 19, 0, 0, 19, 19, 0, + 15, 15, 15, 17, 17, 17, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, + 0, 26, 26, 0, 9, 9, 9, 9, 9, 0, 9, 9, 0, 9, 0, 9, + 9, 55, 55, 6, 1, 1, 6, 6, 4, 4, 4, 3, 3, 3, 1, 1, + 1, 3, 3, 1, 3, 3, 3, 3, 3, 0, 3, 7, 1, 1, 1, 1, + 7, 7, 7, 0, 0, 7, 7, 24, 24, 24, 0, 25, 0, 0, 0, 0, + 25, 25, 25, 8, 8, 8, 0, 35, 35, 35, 0, 0, 0, 35, 35, 44, + 0, 0, 0, 32, 32, 0, 0, 32, 0, 32, 32, 1, 0, 1, 1, 0, + 1, 0, 0, 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, 9, 0, 0, + 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 15, + 1, 1, 0, 26, 12, 12, 12, 12, 12, 12, 0, 69, 69, 0, 69, 84, + 84, 84, 0, 19, 9, 19, 19, 19, 19, 0, 0, 19, 19, 19, 4, 3, + 3, 0, 0, 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0,156, + 156, 3, 3,100, 36, 36, 36,107,107,107, 1,136,139, 13, 13, 17, + 15, 15, 15, 17, 17, 15, 15, 15, 17, 17, 17, 0, 0, 1, 1, 15, + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, + 10, 0, 11, 12, 13, 0, 0, 0, 14, 0, 0, 15, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, + 17, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 19, 20, 21, 0, 22, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 23, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 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, + 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 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, 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, @@ -5224,8 +5226,6 @@ static const uint8_t _hb_ucd_u8[13937]= 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, @@ -5260,116 +5260,116 @@ static const uint8_t _hb_ucd_u8[13937]= 0,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,207,208,209,210, 211,212,213, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, + 0, }; static const uint16_t _hb_ucd_u16[5104]= { - 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, 68, 69, 47, 47, 70, 32, 71, 32, - 72, 47, 47, 73, 74, 75, 76, 77, 78, 47, 47, 79, 80, 81, 82, 83, - 84, 47, 47, 85, 86, 87, 88, 89, 84, 47, 47, 79, 90, 47, 82, 91, - 92, 47, 47, 93, 94, 95, 82, 96, 97, 47, 47, 98, 99, 100, 101, 102, - 103, 47, 47, 104, 105, 106, 82, 107, 108, 47, 47, 93, 109, 110, 82, 111, - 112, 47, 47, 113, 114, 115, 82, 116, 92, 47, 47, 47, 117, 118, 101, 119, - 47, 47, 47, 120, 121, 122, 66, 66, 47, 47, 47, 123, 124, 125, 47, 47, - 126, 127, 128, 129, 47, 47, 47, 130, 131, 32, 32, 132, 133, 134, 66, 66, - 47, 47, 135, 136, 122, 137, 138, 139, 140, 141, 9, 9, 9, 11, 11, 142, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 143, 144, 145, - 47, 146, 9, 9, 9, 9, 9, 147, 148, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 149, 47, 150, 151, 47, 47, 47, 47, 152, 153, - 47, 154, 47, 155, 47, 156, 47, 156, 47, 47, 47, 157, 158, 159, 160, 145, - 161, 160, 47, 47, 162, 47, 47, 47, 163, 47, 164, 47, 47, 47, 47, 47, - 47, 47, 165, 166, 167, 47, 47, 47, 47, 47, 47, 47, 47, 168, 146, 146, - 47, 169, 47, 47, 47, 170, 171, 172, 160, 160, 173, 174, 32, 32, 32, 32, - 175, 47, 47, 176, 177, 122, 178, 179, 180, 47, 181, 61, 47, 47, 182, 183, - 47, 47, 184, 185, 186, 61, 47, 187, 188, 9, 9, 9, 66, 189, 190, 191, - 11, 11, 192, 27, 27, 27, 193, 194, 11, 195, 27, 27, 32, 32, 32, 32, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 196, 13, 13, 13, 13, 13, 13, - 197, 197, 197, 197, 197, 198, 197, 11, 199, 199, 199, 200, 201, 202, 202, 201, - 203, 204, 205, 206, 207, 208, 209, 210, 211, 27, 212, 212, 212, 213, 214, 32, - 215, 216, 217, 218, 219, 145, 220, 220, 221, 222, 223, 146, 224, 225, 146, 226, - 227, 227, 227, 227, 227, 227, 227, 227, 228, 146, 229, 146, 146, 146, 146, 230, - 146, 231, 227, 232, 146, 233, 234, 146, 146, 146, 146, 146, 146, 146, 145, 145, - 145, 235, 146, 146, 146, 146, 236, 145, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 237, 238, 146, 146, 239, 146, 146, 146, 146, 146, 146, 240, 146, - 146, 146, 146, 146, 146, 146, 241, 242, 145, 243, 146, 146, 244, 227, 245, 227, - 246, 247, 227, 227, 227, 248, 227, 249, 146, 146, 146, 227, 250, 146, 146, 146, - 9, 9, 9, 11, 11, 11, 251, 252, 13, 13, 13, 13, 13, 13, 253, 254, - 11, 11, 11, 47, 47, 47, 255, 256, 47, 47, 47, 47, 47, 47, 32, 32, - 257, 258, 259, 260, 261, 262, 263, 263, 264, 265, 266, 267, 268, 47, 47, 47, - 47, 269, 148, 47, 47, 47, 47, 270, 47, 271, 47, 47, 146, 146, 146, 47, - 146, 146, 272, 146, 273, 274, 146, 146, 272, 146, 146, 274, 146, 146, 146, 146, - 47, 47, 47, 47, 146, 146, 146, 146, 47, 275, 47, 47, 47, 47, 47, 47, - 47, 146, 146, 146, 146, 47, 47, 187, 276, 47, 61, 47, 13, 13, 277, 278, - 13, 279, 47, 47, 47, 47, 280, 281, 31, 282, 283, 284, 13, 13, 13, 285, - 286, 287, 288, 289, 290, 291, 9, 292, 293, 47, 294, 295, 47, 47, 47, 296, - 297, 47, 47, 298, 299, 160, 32, 300, 61, 47, 301, 47, 302, 303, 47, 47, - 72, 47, 47, 304, 305, 306, 307, 61, 47, 47, 308, 309, 310, 311, 47, 312, - 47, 47, 47, 313, 58, 314, 315, 316, 47, 47, 47, 11, 11, 317, 318, 11, - 11, 11, 11, 11, 47, 47, 319, 160, 320, 320, 320, 320, 320, 320, 320, 320, - 321, 321, 321, 321, 321, 321, 321, 321, 11, 322, 323, 47, 47, 47, 47, 47, - 47, 47, 47, 324, 325, 326, 47, 47, 47, 47, 47, 327, 146, 47, 47, 47, - 47, 328, 47, 47, 329, 146, 146, 330, 32, 331, 32, 332, 333, 334, 335, 47, - 47, 47, 47, 47, 47, 47, 47, 336, 337, 2, 3, 4, 5, 338, 339, 340, - 47, 341, 47, 47, 47, 47, 342, 343, 344, 145, 145, 345, 220, 220, 220, 346, - 347, 146, 146, 146, 146, 146, 146, 348, 349, 349, 349, 349, 349, 349, 349, 349, - 47, 47, 47, 47, 47, 47, 350, 145, 47, 47, 351, 47, 352, 47, 47, 60, - 47, 353, 47, 47, 47, 354, 220, 220, 9, 9, 147, 11, 11, 47, 47, 47, - 47, 47, 160, 9, 9, 147, 11, 11, 47, 47, 47, 47, 47, 47, 353, 9, - 9, 355, 11, 11, 47, 47, 47, 47, 27, 27, 27, 27, 27, 27, 27, 27, - 47, 47, 47, 47, 47, 356, 47, 357, 47, 47, 358, 145, 145, 145, 47, 359, - 47, 360, 47, 353, 47, 47, 47, 47, 47, 47, 47, 361, 145, 145, 145, 145, - 362, 47, 47, 363, 145, 66, 47, 364, 47, 365, 145, 145, 366, 47, 367, 66, - 47, 47, 47, 368, 47, 369, 47, 369, 47, 368, 144, 145, 145, 145, 145, 145, - 9, 9, 9, 9, 11, 11, 11, 370, 47, 47, 371, 160, 372, 9, 373, 11, - 374, 227, 227, 227, 227, 227, 227, 227, 145, 145, 145, 145, 145, 145, 145, 145, - 47, 47, 375, 47, 275, 376, 146, 377, 47, 365, 378, 47, 60, 379, 66, 47, - 380, 66, 66, 47, 381, 145, 47, 47, 382, 47, 47, 363, 383, 384, 385, 386, - 180, 47, 47, 387, 388, 47, 47, 160, 97, 47, 389, 390, 391, 47, 47, 392, - 180, 47, 47, 393, 394, 395, 396, 145, 47, 47, 397, 398, 362, 32, 32, 32, - 47, 47, 368, 47, 47, 399, 172, 160, 92, 47, 47, 113, 400, 401, 402, 32, - 47, 47, 47, 403, 404, 405, 406, 32, 47, 47, 47, 407, 408, 409, 47, 47, - 47, 47, 47, 410, 411, 160, 160, 160, 47, 47, 412, 413, 414, 415, 32, 32, - 47, 47, 47, 416, 417, 160, 66, 66, 47, 47, 418, 419, 160, 160, 160, 160, - 47, 420, 421, 422, 47, 47, 47, 47, 47, 47, 397, 423, 66, 66, 66, 66, - 9, 9, 9, 9, 11, 11, 128, 424, 47, 47, 47, 425, 426, 160, 160, 160, - 47, 47, 47, 47, 47, 427, 428, 429, 430, 47, 47, 431, 432, 433, 47, 47, - 434, 435, 66, 47, 47, 47, 47, 47, 66, 66, 66, 66, 66, 66, 436, 429, - 47, 47, 47, 47, 47, 47, 437, 160, 47, 47, 412, 438, 437, 128, 145, 439, - 47, 156, 440, 441, 32, 32, 32, 32, 47, 47, 47, 362, 442, 160, 47, 47, - 443, 444, 160, 47, 47, 445, 160, 160, 47, 47, 47, 47, 47, 47, 47, 446, - 447, 47, 47, 448, 449, 450, 32, 32, 47, 47, 47, 47, 145, 451, 452, 453, - 220, 220, 220, 220, 220, 220, 220, 66, 47, 47, 47, 47, 47, 47, 47, 437, - 47, 47, 47, 209, 454, 32, 47, 47, 47, 455, 456, 160, 160, 160, 160, 160, - 47, 47, 47, 47, 47, 47, 306, 47, 47, 47, 47, 47, 160, 47, 47, 457, - 47, 47, 47, 458, 459, 460, 461, 47, 27, 27, 27, 27, 462, 47, 463, 160, - 9, 9, 9, 9, 9, 9, 11, 11, 145, 464, 9, 465, 11, 11, 11, 11, - 47, 47, 47, 47, 399, 466, 429, 429, 467, 468, 27, 27, 27, 27, 469, 470, - 47, 471, 209, 209, 209, 209, 209, 209, 146, 146, 146, 146, 146, 146, 146, 472, - 146, 146, 146, 146, 146, 146, 146, 227, 32, 32, 32, 32, 32, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 473, 474, 475, 146, 476, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 477, 146, 146, 146, 9, 478, 11, 479, 480, 11, 197, 9, - 481, 482, 9, 483, 11, 9, 478, 11, 479, 480, 11, 197, 9, 481, 482, 9, - 483, 11, 9, 478, 11, 479, 480, 11, 197, 9, 481, 482, 9, 483, 11, 9, - 478, 11, 197, 9, 484, 485, 486, 487, 11, 488, 9, 489, 490, 491, 492, 11, - 493, 9, 494, 11, 495, 160, 160, 160, 32, 32, 32, 496, 32, 32, 497, 498, - 499, 500, 32, 32, 32, 32, 32, 32, 501, 11, 11, 11, 11, 11, 11, 11, - 32, 32, 32, 27, 27, 27, 27, 27, 32, 32, 32, 32, 32, 32, 32, 32, - 47, 47, 47, 502, 503, 146, 146, 146, 47, 47, 455, 32, 47, 47, 504, 505, - 47, 47, 47, 47, 47, 47, 506, 160, 47, 47, 47, 47, 47, 47, 455, 507, - 47, 47, 47, 47, 47, 47, 508, 509, 47, 47, 47, 47, 358, 32, 32, 32, - 9, 9, 481, 11, 510, 306, 66, 66, 145, 145, 511, 512, 145, 145, 145, 145, - 145, 145, 513, 145, 145, 145, 145, 145, 47, 47, 47, 47, 47, 47, 47, 227, - 514, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 515, - 146, 146, 146, 146, 146, 227, 227, 227, 209, 209, 209, 209, 209, 209, 209, 209, + 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, + 8, 8, 8, 8, 8, 8, 8, 8, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, + 56, 56, 56, 56, 56, 56, 56, 56, 40, 40, 40, 40, 40, 40, 40, 40, + 24, 24, 24, 24, 24, 24, 56, 56, 96, 96, 96, 96, 96, 96, 96, 96, + 24, 24, 24, 24, 24, 24, 24, 592, 152, 152, 600, 336, 344, 352, 360, 608, + 152, 152, 616, 624, 72, 632, 48, 640, 80, 80, 80, 648, 656, 80, 80, 664, + 672, 680, 688, 696, 704, 712, 80, 720, 80, 80, 80, 728, 736, 48, 48, 48, + 48, 744, 48, 96, 752, 760, 768, 368, 40, 40, 40, 40, 40, 40, 40, 776, + 784, 376, 792, 48, 800, 808, 80, 816, 72, 72, 72, 48, 48, 48, 80, 80, + 824, 80, 80, 80, 832, 80, 80, 80, 80, 80, 80, 376, 72, 840, 48, 48, + 848, 856, 40, 864, 872, 8, 8, 880, 888, 896, 8, 8, 904, 40, 912, 384, + 8, 8, 8, 8, 8, 920, 928, 936, 944, 392, 8, 40, 952, 8, 8, 8, + 8, 8, 184, 384, 136, 8, 960, 968, 8, 976, 984, 104, 8, 992, 8, 8, + 1000,1008, 8, 8,1016, 40,1024, 40, 400, 8, 8,1032,1040,1048,1056,1064, + 1072, 8, 8, 408,1080,1088, 144,1096, 416, 8, 8,1104,1112,1120,1128,1136, + 416, 8, 8, 408,1144, 8, 144,1152, 192, 8, 8, 424,1160,1168, 144,1176, + 432, 8, 8,1184,1192,1200, 440,1208,1216, 8, 8,1224,1232,1240, 144,1248, + 1256, 8, 8, 424,1264,1272, 144,1280,1288, 8, 8, 448,1296,1304, 144,1312, + 192, 8, 8, 8,1320,1328, 440,1336, 8, 8, 8,1344,1352, 200, 104, 104, + 8, 8, 8,1360,1368,1376, 8, 8,1384,1392, 208,1400, 8, 8, 8,1408, + 1416, 40, 40,1424,1432,1440, 104, 104, 8, 8,1448,1456, 200,1464,1472,1480, + 1488,1496, 72, 72, 72, 48, 48,1504, 8, 8, 8, 8, 8,1512, 456, 56, + 8, 24, 72, 72, 72, 72, 72, 216, 464, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8,1520, 8,1528,1536, 8, 8, 8, 8,1544,1552, + 8,1560, 8,1568, 8, 224, 8, 224, 8, 8, 8,1576,1584,1592, 88, 56, + 1600, 88, 8, 8,1608, 8, 8, 8,1616, 8,1624, 8, 8, 8, 8, 8, + 8, 8,1632,1640,1648, 8, 8, 8, 8, 8, 8, 8, 8,1656, 24, 24, + 8,1664, 8, 8, 8,1672,1680, 472, 88, 88,1688,1696, 40, 40, 40, 40, + 1704, 8, 8,1712,1720, 200,1728,1736, 232, 8,1744, 136, 8, 8,1752,1760, + 8, 8,1768,1776,1784, 136, 8, 480,1792, 72, 72, 72, 104,1800,1808,1816, + 48, 48,1824, 96, 96, 96,1832,1840, 48,1848, 96, 96, 40, 40, 40, 40, + 80, 80, 80, 80, 80, 80, 80, 80, 80,1856, 80, 80, 80, 80, 80, 80, + 128, 128, 128, 128, 128,1864, 128, 48, 240, 240, 240,1872, 488, 496, 496, 488, + 1880,1888,1896,1904,1912,1920, 112,1928,1936, 96, 248, 248, 248,1944,1952, 40, + 1960,1968,1976,1984,1992, 56, 120, 120,2000,2008,2016, 24,2024,2032, 24,2040, + 2048, 24,2056, 24, 24, 24, 24,2064, 24,2072, 64,2080, 24,2088,2096, 24, + 56,2104, 24, 24, 24, 24,2112, 56, 24, 24, 24,2120,2128, 24, 24,2136, + 24, 24, 24, 24, 24, 24,2144, 24, 24, 24, 24, 24, 24, 24,2152,2160, + 56,2168, 24, 24,2176, 64,2184, 64,2192,2200, 64, 64, 64,2208, 64,2216, + 24, 24, 24, 64,2224, 24, 24, 24, 72, 72, 72, 48, 48, 48,2232,2240, + 80, 80, 80, 80, 80, 80,2248,2256, 48, 48, 48, 8, 8, 8,2264,2272, + 8, 8, 8, 8, 8, 8, 40, 40,2280,2288,2296,2304,2312,2320, 504, 504, + 2328,2336,2344,2352,2360, 8, 8, 8, 8,2368, 464, 8, 8, 8, 8,2376, + 8,2384, 8, 8, 24, 24, 24, 8, 24, 24, 512, 24,2392, 520, 24, 24, + 512, 24, 24, 520, 24, 24, 24, 24, 8, 8, 8, 8, 24, 24, 24, 24, + 8, 528, 8, 8, 8, 8, 8, 8, 8, 24, 24, 24, 24, 8, 8, 480, + 2400, 8, 136, 8, 80, 80,2408,2416, 80,2424, 8, 8, 8, 8,2432,2440, + 368,2448,2456,2464, 80, 80, 80,2472,2480,2488,2496,2504,2512,2520, 72,2528, + 2536, 8,2544,2552, 8, 8, 8,2560,2568, 8, 8,2576,2584, 88, 40,2592, + 136, 8,2600, 8,2608,2616, 8, 8, 400, 8, 8,2624,2632, 256,2640, 136, + 8, 8,2648,2656,2664,2672, 8,2680, 8, 8, 8,2688, 392,2696,2704,2712, + 8, 8, 8, 48, 48,2720,2728, 48, 48, 48, 48, 48, 8, 8,2736, 88, + 48,2744,2752, 8, 8, 8, 8, 8, 8, 8, 8,2760,2768,2776, 8, 8, + 8, 8, 8,2784, 24, 8, 8, 8, 8,2792, 8, 8,2800, 24, 24,2808, + 40,2816, 40,2824,2832,2840,2848, 8, 8, 8, 8, 8, 8, 8, 8,2856, + 2864, 336, 344, 352, 360,2872,2880,2888, 8,2896, 8, 8, 8, 8,2904,2912, + 2920, 56, 56,2928, 120, 120, 120,2936,2944, 24, 24, 24, 24, 24, 24,2952, + 8, 8, 8, 8, 8, 8,2960, 56, 8, 8,2968, 8,2976, 8, 8, 184, + 8, 264, 8, 8, 8,2984, 120, 120, 72, 72, 216, 48, 48, 8, 8, 8, + 8, 8, 88, 72, 72, 216, 48, 48, 8, 8, 8, 8, 8, 8, 264, 72, + 72,2992, 48, 48, 8, 8, 8, 8, 8, 8, 8, 8, 8,3000, 8,3008, + 8, 8, 536, 56, 56, 56, 8,3016, 8,3024, 8, 264, 8, 8, 8, 8, + 8, 8, 8,3032, 56, 56, 56, 56, 272, 8, 8, 544, 56, 104, 8,3040, + 8, 552, 56, 56,3048, 8,3056, 104, 8, 8, 8, 280, 8, 560, 8, 560, + 8, 280, 456, 56, 56, 56, 56, 56, 72, 72, 72, 72, 48, 48, 48,3064, + 8, 8,3072, 88,3080, 72,3088, 48,3096, 64, 64, 64, 64, 64, 64, 64, + 8, 8,3104, 8, 528,3112, 24,3120, 8, 552,3128, 8, 184,3136, 104, 8, + 3144, 104, 104, 8,3152, 56, 8, 8,3160, 8, 8, 544,3168,3176,3184,3192, + 232, 8, 8,3200,3208, 8, 8, 88, 432, 8,3216,3224,3232, 8, 8,3240, + 232, 8, 8,3248,3256,3264,3272, 56, 8, 8, 568,3280, 272, 40, 40, 40, + 8, 8, 280, 8, 8, 576, 472, 88, 192, 8, 8, 448,3288,3296,3304, 40, + 8, 8, 8,3312,3320,3328,3336, 40, 8, 8, 8,3344,3352,3360, 8, 8, + 8, 8, 8,3368,3376, 88, 88, 88, 8, 8, 584,3384,3392,3400, 40, 40, + 8, 8, 8,3408,3416, 88, 104, 104, 8, 8,3424,3432, 88, 88, 88, 88, + 8,3440,3448,3456, 8, 8, 8, 8, 8, 8, 568,3464, 104, 104, 104, 104, + 72, 72, 72, 72, 48, 48, 208,3472, 8, 8, 8,3480,3488, 88, 88, 88, + 8, 8, 8, 8, 8,3496,3504, 160,3512, 8, 8,3520,3528,3536, 8, 8, + 3544,3552, 104, 8, 8, 8, 8, 8, 104, 104, 104, 104, 104, 104,3560, 160, + 8, 8, 8, 8, 8, 8, 288, 88, 8, 8, 584,3568, 288, 208, 56,3576, + 8, 224,3584,3592, 40, 40, 40, 40, 8, 8, 8, 272,3600, 88, 8, 8, + 3608,3616, 88, 8, 8,3624, 88, 88, 8, 8, 8, 8, 8, 8, 8,3632, + 3640, 8, 8,3648,3656,3664, 40, 40, 8, 8, 8, 8, 56,3672,3680,3688, + 120, 120, 120, 120, 120, 120, 120, 104, 8, 8, 8, 8, 8, 8, 8, 288, + 8, 8, 8, 112,3696, 40, 8, 8, 8, 296,3704, 88, 88, 88, 88, 88, + 8, 8, 8, 8, 8, 8, 256, 8, 8, 8, 8, 8, 88, 8, 8,3712, + 8, 8, 8,3720,3728,3736,3744, 8, 96, 96, 96, 96,3752, 8,3760, 88, + 72, 72, 72, 72, 72, 72, 48, 48, 56,3768, 72,3776, 48, 48, 48, 48, + 8, 8, 8, 8, 576,3784, 160, 160,3792,3800, 96, 96, 96, 96,3808,3816, + 8,3824, 112, 112, 112, 112, 112, 112, 24, 24, 24, 24, 24, 24, 24, 64, + 40, 40, 40, 40, 40, 24, 24, 24, 24, 24, 24, 24, 24, 24,3832,3840, + 3848, 24,3856, 24, 24, 24, 24, 24, 24, 24, 24, 24,3864, 24, 24, 24, + 72, 168, 48, 304, 312, 48, 128, 72, 176, 320, 72, 328, 48, 72, 168, 48, + 304, 312, 48, 128, 72, 176, 320, 72, 328, 48, 72, 168, 48, 304, 312, 48, + 128, 72, 176, 320, 72, 328, 48, 72, 168, 48, 128, 72,3872,3880,3888,3896, + 48,3904, 72,3912,3920,3928,3936, 48,3944, 72,3952, 48,3960, 88, 88, 88, + 40, 40, 40,3968, 40, 40,3976,3984,3992,4000, 40, 40, 40, 40, 40, 40, + 4008, 48, 48, 48, 48, 48, 48, 48, 40, 40, 40, 96, 96, 96, 96, 96, + 8, 8, 8,4016,4024, 24, 24, 24, 8, 8, 296, 40, 8, 8,4032,4040, + 8, 8, 8, 8, 8, 8,4048, 88, 8, 8, 8, 8, 8, 8, 296,4056, + 8, 8, 8, 8, 8, 8,4064,4072, 8, 8, 8, 8, 536, 40, 40, 40, + 72, 72, 176, 48,4080, 256, 104, 104, 56, 56,4088,4096, 56, 56, 56, 56, + 56, 56,4104, 56, 56, 56, 56, 56, 8, 8, 8, 8, 8, 8, 8, 64, + 4112, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,4120, + 24, 24, 24, 24, 24, 64, 64, 64, 112, 112, 112, 112, 112, 112, 112, 112, 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, @@ -5587,9 +5587,9 @@ static const uint16_t _hb_ucd_u16[5104]= }; 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, + 0, 0, 1, -1, -1, 1, 0, 1, -1, 0, 0, 2, 0, -2, 2, 0, + -2, 0, -7, 0, 0, 16, 0, -16, 3, 3, 3, -3, -3, -3, 0, 2016, + 0, 2527, 1923, 1914, 1918, 0, 2250, 0, 0, 138, 0, 7, 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, @@ -5597,11 +5597,13 @@ static const int16_t _hb_ucd_i16[92]= static inline uint8_t _hb_ucd_gc (unsigned u) { - return u<1114112 ? _hb_ucd_u8[5296u+((_hb_ucd_u8[1168u+((_hb_ucd_u16[((_hb_ucd_u8[544u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>3))>>4)])<<4)+((((((((u)>>1))>>3))>>3))&15)])<<3)+((((((u)>>1))>>3))&7)])<<3)+((((u)>>1))&7)])<<1)+((u)&1)] : 2; + /* packtab: [2^8,2^4,2^3,2^3,2^1] */ + return u<1114112u ? (uint8_t)(_hb_ucd_u8[5288u+((_hb_ucd_u8[1160u+_hb_ucd_u16[((_hb_ucd_u8[544u+((_hb_ucd_u8[((((((((u)>>1))>>3))>>3))>>4)])<<4)+((((((((u)>>1))>>3))>>3))&15)])<<3)+((((((u)>>1))>>3))&7)]+((((u)>>1))&7)])<<1)+((u)&1)]) : 2; } static inline uint8_t _hb_ucd_ccc (unsigned u) { - return u<125259 ? _hb_ucd_u8[7322u+((_hb_ucd_u8[6738u+((_hb_ucd_u8[6258u+((_hb_ucd_u8[5890u+((_hb_ucd_u8[5644u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 0; + /* packtab: [2^8,2^3,2^2,2^2,2^2] */ + return u<125259u ? (uint8_t)(_hb_ucd_u8[7307u+((_hb_ucd_u8[6724u+((_hb_ucd_u8[6247u+((_hb_ucd_u8[5881u+((_hb_ucd_u8[5636u+((((((((u)>>2))>>2))>>2))>>3)])<<3)+((((((((u)>>2))>>2))>>2))&7)])<<2)+((((((u)>>2))>>2))&3)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)]) : 0; } static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) { @@ -5609,15 +5611,18 @@ static inline uint8_t _hb_ucd_b4 (const uint8_t* a, unsigned i) } static inline int16_t _hb_ucd_bmg (unsigned u) { - return u<65380 ? _hb_ucd_i16[((_hb_ucd_u8[8218u+((_hb_ucd_u8[7986u+((_hb_ucd_u8[7890u+((_hb_ucd_b4(_hb_ucd_u8+7826u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)])<<3)+((((((u)>>1))>>2))&7)])<<2)+((((u)>>1))&3)])<<1)+((u)&1)] : 0; + /* packtab: [2^4,2^3,2^3,2^2,2^1] */ + return u<65380u ? (int16_t)(_hb_ucd_i16[_hb_ucd_u8[8198u+_hb_ucd_u8[7969u+_hb_ucd_u8[7875u+((_hb_ucd_b4(_hb_ucd_u8+7811u,((((((((u)>>1))>>2))>>3))>>3)))<<3)+((((((((u)>>1))>>2))>>3))&7)]+((((((u)>>1))>>2))&7)]+((((u)>>1))&3)]+((u)&1)]) : 0; } static inline uint8_t _hb_ucd_sc (unsigned u) { - return u<918016 ? _hb_ucd_u8[11655u+((_hb_ucd_u8[10647u+((_hb_ucd_u8[9151u+((_hb_ucd_u8[8703u+((_hb_ucd_u8[8495u+((_hb_ucd_b4(_hb_ucd_u8+8466u,((((((((((u)>>2))>>2))>>3))>>3))>>4)))<<4)+((((((((((u)>>2))>>2))>>3))>>3))&15)])<<3)+((((((((u)>>2))>>2))>>3))&7)])<<3)+((((((u)>>2))>>2))&7)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)] : 2; + /* packtab: [2^4,2^4,2^3,2^3,2^2,2^2] */ + return u<918016u ? (uint8_t)(_hb_ucd_u8[11623u+((_hb_ucd_u8[10615u+((_hb_ucd_u8[9119u+((_hb_ucd_u8[8675u+((_hb_ucd_u8[8475u+((_hb_ucd_b4(_hb_ucd_u8+8446u,((((((((((u)>>2))>>2))>>3))>>3))>>4)))<<4)+((((((((((u)>>2))>>2))>>3))>>3))&15)])<<3)+((((((((u)>>2))>>2))>>3))&7)])<<3)+((((((u)>>2))>>2))&7)])<<2)+((((u)>>2))&3)])<<2)+((u)&3)]) : 2; } static inline uint16_t _hb_ucd_dm (unsigned u) { - return u<195102 ? _hb_ucd_u16[1680u+((_hb_ucd_u8[13041u+((_hb_ucd_u8[12659u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)] : 0; + /* packtab: [2^8,2^5,2^4] */ + return u<195102u ? (uint16_t)(_hb_ucd_u16[1680u+((_hb_ucd_u8[13009u+((_hb_ucd_u8[12627u+((((u)>>4))>>5)])<<5)+((((u)>>4))&31)])<<4)+((u)&15)]) : 0; } 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 711dd9b6571..7200952547a 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 @@ -27,36 +27,36 @@ static const uint8_t _hb_emoji_u8[624]= { - 16, 17, 17, 17, 50, 20, 21, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,118,152, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 50, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 3, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 7, - 0, 0, 0, 8, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0, - 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0, - 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, - 23, 0, 24, 25, 0, 26, 27, 28, 29, 30, 31, 31, 32, 31, 33, 34, - 31, 31, 31, 35, 36, 37, 38, 39, 31, 40, 31, 41, 0, 0, 0, 42, - 43, 44, 45, 46, 47, 48, 31, 31, 0, 49, 31, 31, 0, 0, 0, 0, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 36, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4, 0, 0, 2, 0, 0,240, 3, 0, 6, 0, 0, - 0, 0, 0, 12, 0, 1, 0, 0, 0,128, 0, 0, 0,254, 15, 7, - 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 64, 0, - 1, 0, 0, 0, 0, 0, 0,120, 31, 64, 50, 33, 77,196, 0, 7, - 5,255, 15,128,105, 1, 0,200, 0, 0,252, 26,131, 12, 3, 96, - 48,193, 26, 0, 0, 6,191, 39, 36,191, 84, 32, 2, 1, 24, 0, - 144, 80,184, 0, 24, 0, 0, 0, 0, 0,224, 0, 2, 0, 1,128, - 0, 0, 0, 0, 0, 0, 48, 0,224, 0, 0, 24, 0, 0, 0, 0, - 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, - 0, 0,128, 2, 0, 0, 0, 0, 16, 0, 0, 0, 0,240, 0, 0, - 0, 0,240,255, 0,128, 1, 0, 1,128, 1, 0, 0, 0,192,255, - 0, 0, 0, 0, 0, 0, 3,192, 0, 64,254, 7, 0,192,255,255, - 255,255,255,255, 63, 0, 0, 0,254,255, 0, 4, 0,128,252,247, - 0,254,255,255,192,255,255,255,255,255,255,255,255,255,255,255, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,152, + 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, 0, 0, 0, 0, 0, + 3, 4, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 7, 0, 0, 8, + 0, 0, 0, 9, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, + 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 20, 21, 0, 0, + 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, + 24, 0, 25, 26, 0, 27, 28, 29, 30, 31, 1, 1, 32, 1, 33, 34, + 1, 1, 1, 35, 36, 37, 38, 39, 1, 40, 1, 41, 0, 0, 0, 42, + 43, 44, 45, 46, 47, 48, 1, 1, 0, 49, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255, + 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, + 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 2, + 0, 0,240, 3, 0, 6, 0, 0, 0, 0, 0, 12, 0, 1, 0, 0, + 0,128, 0, 0, 0,254, 15, 7, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 12, 64, 0, 1, 0, 0, 0, 0, 0, 0,120, + 31, 64, 50, 33, 77,196, 0, 7, 5,255, 15,128,105, 1, 0,200, + 0, 0,252, 26,131, 12, 3, 96, 48,193, 26, 0, 0, 6,191, 39, + 36,191, 84, 32, 2, 1, 24, 0,144, 80,184, 0, 24, 0, 0, 0, + 0, 0,224, 0, 2, 0, 1,128, 0, 0, 0, 0, 0, 0, 48, 0, + 224, 0, 0, 24, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 32, 0, 0,128, 2, 0, 0, 0, 0, + 16, 0, 0, 0, 0,240, 0, 0, 0, 0,240,255, 0,128, 1, 0, + 1,128, 1, 0, 0, 0,192,255, 0, 0, 0, 0, 0, 0, 3,192, + 0, 64,254, 7, 0,192,255,255,255,255,255,255, 63, 0, 0, 0, + 254,255, 0, 4, 0,128,252,247, 0,254,255,255,192,255,255,255, 255,255,255,255,243,255,255,255,255,255,207,206,255,255,255,255, 255,255,255,255,255,255,185, 7,255,255,255,255,255,255,255,191, 255,255,255,255,255,255,255, 63, 0,126,255,255,255,128,249, 7, @@ -78,7 +78,8 @@ static inline uint8_t _hb_emoji_b1 (const uint8_t* a, unsigned i) } static inline uint8_t _hb_emoji_is_Extended_Pictographic (unsigned u) { - return u<131070 ? _hb_emoji_b1(_hb_emoji_u8+224u,((_hb_emoji_u8[64u+((_hb_emoji_b4(_hb_emoji_u8,((((u)>>6))>>4)))<<4)+((((u)>>6))&15)])<<6)+((u)&63)) : 0; + /* packtab: [2^4,2^4,2^6] */ + return u<131070u ? (uint8_t)(_hb_emoji_b1(_hb_emoji_u8+224u,((_hb_emoji_u8[64u+((_hb_emoji_b4(_hb_emoji_u8,((((u)>>6))>>4)))<<4)+((((u)>>6))&15)])<<6)+((u)&63))) : 0; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc b/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc index fa0d66174ff..df76bd99d90 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc @@ -376,8 +376,12 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, void *user_data, \ hb_destroy_func_t destroy) \ { \ + auto destroy_guard = hb_make_scope_guard ([&]() { \ + if (destroy) destroy (user_data); \ + }); \ + \ if (hb_object_is_immutable (ufuncs)) \ - goto fail; \ + return; \ \ if (!func) \ { \ @@ -396,11 +400,7 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, ufuncs->func.name = ufuncs->parent->func.name; \ ufuncs->user_data.name = user_data; \ ufuncs->destroy.name = destroy; \ - return; \ - \ -fail: \ - if (destroy) \ - destroy (user_data); \ + destroy_guard.release (); \ } HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh index b650ca9f066..b0aa842bb23 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh @@ -62,7 +62,7 @@ struct hb_vector_t hb_requires (hb_is_iterable (Iterable))> explicit hb_vector_t (const Iterable &o) : hb_vector_t () { - extend (o); + extend (o, true); } HB_ALWAYS_INLINE_VECTOR_ALLOCS hb_vector_t (const hb_vector_t &o) : hb_vector_t () @@ -117,12 +117,12 @@ struct hb_vector_t template HB_ALWAYS_INLINE_VECTOR_ALLOCS - void extend (const Iterable &o) + void extend (const Iterable &o, bool exact=false) { auto iter = hb_iter (o); if (iter.is_random_access_iterator || iter.has_fast_len) { - if (unlikely (!alloc (hb_len (iter), true))) + if (unlikely (!alloc (length + hb_len (iter), exact))) return; unsigned count = hb_len (iter); for (unsigned i = 0; i < count; i++) @@ -138,16 +138,16 @@ struct hb_vector_t } } HB_ALWAYS_INLINE_VECTOR_ALLOCS - void extend (array_t o) + void extend (array_t o, bool exact=false) { - alloc (length + o.length); + alloc (length + o.length, exact); if (unlikely (in_error ())) return; copy_array (o); } HB_ALWAYS_INLINE_VECTOR_ALLOCS - void extend (c_array_t o) + void extend (c_array_t o, bool exact=false) { - alloc (length + o.length); + alloc (length + o.length, exact); if (unlikely (in_error ())) return; copy_array (o); } @@ -182,10 +182,46 @@ struct hb_vector_t { if (unlikely (in_error ())) reset_error (); - resize (0); + clear (); return *this; } + HB_ALWAYS_INLINE_VECTOR_ALLOCS + hb_vector_t &reset_if_error () + { + if (unlikely (in_error ())) + reset (); + return *this; + } + + /* Transfer ownership of the backing storage to caller. + * Returns nullptr if storage is not owned by this vector. */ + Type * + steal (unsigned *len = nullptr, int *allocated_out = nullptr) + { + if (!is_owned ()) + return nullptr; + if (len) + *len = length; + if (allocated_out) + *allocated_out = allocated; + Type *p = arrayZ; + init (); + return p; + } + + /* Adopt a previously detached owned buffer. */ + void + recycle_buffer (Type *buffer, + unsigned len, + int allocated_len) + { + fini (); + arrayZ = buffer; + length = len; + allocated = allocated_len; + } + friend void swap (hb_vector_t& a, hb_vector_t& b) noexcept { hb_swap (a.allocated, b.allocated); @@ -236,7 +272,7 @@ struct hb_vector_t const Type& tail () const { return (*this)[length - 1]; } explicit operator bool () const { return length; } - unsigned get_size () const { return length * item_size; } + size_t get_size () const { return length * item_size; } /* Sink interface. */ template @@ -290,6 +326,12 @@ struct hb_vector_t } template HB_ALWAYS_INLINE_VECTOR_ALLOCS + bool push_or_fail (Args&&... args) + { + return push (std::forward (args)...) != std::addressof (Crap (Type)); + } + template + HB_ALWAYS_INLINE_VECTOR_ALLOCS Type *push_has_room (Args&&... args) { /* Emplace. */ @@ -543,7 +585,7 @@ struct hb_vector_t HB_ALWAYS_INLINE_VECTOR_ALLOCS void clear () { - resize (0); + shrink_vector (0); } template @@ -671,8 +713,11 @@ struct hb_vector_t /* Sorting API. */ - void qsort (int (*cmp)(const void*, const void*) = Type::cmp) - { as_array ().qsort (cmp); } + template + void qsort (Compar compar) + { as_array ().qsort (compar); } + void qsort () + { as_array ().qsort (); } /* Unsorted search API. */ template diff --git a/src/java.desktop/share/native/libharfbuzz/hb-version.h b/src/java.desktop/share/native/libharfbuzz/hb-version.h index c673d1e3612..7ab4a82fd85 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-version.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-version.h @@ -41,26 +41,26 @@ HB_BEGIN_DECLS * * The major component of the library version available at compile-time. */ -#define HB_VERSION_MAJOR 12 +#define HB_VERSION_MAJOR 14 /** * HB_VERSION_MINOR: * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 3 +#define HB_VERSION_MINOR 2 /** * HB_VERSION_MICRO: * * The micro component of the library version available at compile-time. */ -#define HB_VERSION_MICRO 2 +#define HB_VERSION_MICRO 0 /** * HB_VERSION_STRING: * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "12.3.2" +#define HB_VERSION_STRING "14.2.0" /** * HB_VERSION_ATLEAST: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-zlib.hh b/src/java.desktop/share/native/libharfbuzz/hb-zlib.hh new file mode 100644 index 00000000000..3b8eb791a17 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-zlib.hh @@ -0,0 +1,37 @@ +#ifndef HB_ZLIB_HH +#define HB_ZLIB_HH + +#include "hb-blob.hh" + +static inline bool +hb_blob_is_gzip (const char *data, + unsigned data_len) +{ + return data_len >= 3 && + (unsigned char) data[0] == 0x1Fu && + (unsigned char) data[1] == 0x8Bu && + (unsigned char) data[2] == 0x08u; +} + +static inline bool +hb_gzip_get_uncompressed_size (const char *data, + unsigned data_len, + uint32_t *size) +{ + if (data_len < 4) + return false; + + const unsigned char *trailer = (const unsigned char *) data + data_len - 4; + if (size) + *size = (uint32_t) trailer[0] | + ((uint32_t) trailer[1] << 8) | + ((uint32_t) trailer[2] << 16) | + ((uint32_t) trailer[3] << 24); + return true; +} + +HB_INTERNAL hb_blob_t * +hb_blob_decompress_gzip (hb_blob_t *blob, + unsigned max_output_len); + +#endif /* HB_ZLIB_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb.hh b/src/java.desktop/share/native/libharfbuzz/hb.hh index 7582abaa933..25565c0caa1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb.hh @@ -138,6 +138,7 @@ /* Ignored intentionally. */ #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED +#pragma GCC diagnostic ignored "-Warray-bounds" // https://github.com/harfbuzz/harfbuzz/issues/5738 #pragma GCC diagnostic ignored "-Wclass-memaccess" #pragma GCC diagnostic ignored "-Wcast-function-type-strict" // https://github.com/harfbuzz/harfbuzz/pull/3859#issuecomment-1295409126 #pragma GCC diagnostic ignored "-Wdangling-reference" // https://github.com/harfbuzz/harfbuzz/issues/4043 @@ -526,7 +527,7 @@ static_assert ((sizeof (hb_var_int_t) == 4), ""); /* Pie time. */ // https://github.com/harfbuzz/harfbuzz/issues/4166 -#define HB_PI 3.14159265358979f +#define HB_PI 3.14159265358979323846f #define HB_2_PI (2.f * HB_PI) /* Compile-time custom allocator support. */ @@ -570,6 +571,13 @@ extern "C" void hb_free_impl(void *ptr); #include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector +/* Library-internal alias for hb::unique_ptr defined in hb-cplusplus.hh. + * Unique-ownership RAII wrapper around an HB object; destroys on scope exit + * via the type's hb_*_destroy() function. Usage: hb_unique_ptr_t. + * Matches the hb_*_t naming used elsewhere in internal code. */ +template using hb_unique_ptr_t = hb::unique_ptr; + + /* Our src/test-*.cc use hb_assert(), such that it's not compiled out under NDEBUG. * https://github.com/harfbuzz/harfbuzz/issues/5418 */ #define hb_always_assert(x) \ From 8ba600d6f314e2162bd63230623e8776333858a0 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 3 Jun 2026 04:32:58 +0000 Subject: [PATCH 037/115] 8385333: Shenandoah: Final mark spins up workers without work to do Reviewed-by: xpeng, kdnilsen --- .../gc/shenandoah/shenandoahClosures.hpp | 12 ++ .../shenandoah/shenandoahConcurrentMark.cpp | 107 ++++++++---------- .../gc/shenandoah/shenandoahPhaseTimings.hpp | 1 + 3 files changed, 62 insertions(+), 58 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index 9ab45380c61..976a505c713 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -253,4 +253,16 @@ public: }; #endif // ASSERT +class ShenandoahMultiThreadClosure : public ThreadClosure { + ThreadClosure& _cl1; + ThreadClosure& _cl2; +public: + ShenandoahMultiThreadClosure(ThreadClosure& cl1, ThreadClosure& cl2) : + _cl1(cl1), _cl2(cl2) {} + inline void do_thread(Thread* thread) override { + _cl1.do_thread(thread); + _cl2.do_thread(thread); + } +}; + #endif // SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 4db8821399f..31ffbc817f1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -59,6 +59,10 @@ public: ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::conc_mark, ShenandoahPhaseTimings::Work, worker_id, true); SuspendibleThreadSetJoiner stsj; _cm->mark_loop(worker_id, _terminator, GENERATION, true /*cancellable*/); + // Concurrent marking loop flushes Java thread buffers, coordinating with a handshake. + // Here, a GC worker has completed marking work, so it is a good time to flush its SATB buffers too. + SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set(); + satb_mq_set.flush_queue(ShenandoahThreadLocalData::satb_mark_queue(Thread::current())); } }; @@ -67,32 +71,14 @@ class ShenandoahFinalMarkingTask : public WorkerTask { private: ShenandoahConcurrentMark* _cm; TaskTerminator* _terminator; - ThreadsClaimTokenScope _threads_claim_token_scope; // needed for Threads::possibly_parallel_threads_do public: ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator) : - WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), - _threads_claim_token_scope() { - } + WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator) {} void work(uint worker_id) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahWorkerTimingsTracker timer(ShenandoahPhaseTimings::finish_mark, ShenandoahPhaseTimings::Work, worker_id, true); ShenandoahParallelWorkerSession worker_session(worker_id); - // First drain remaining SATB buffers. - { - ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id); - ShenandoahObjToScanQueue* old_q = _cm->get_old_queue(worker_id); - - ShenandoahSATBBufferClosure cl(q, old_q); - SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set(); - while (satb_mq_set.apply_closure_to_completed_buffer(&cl)) {} - assert(!heap->has_forwarded_objects(), "Not expected"); - - ShenandoahFlushSATB tc(satb_mq_set); - Threads::possibly_parallel_threads_do(true /* is_par */, &tc); - } _cm->mark_loop(worker_id, _terminator, GENERATION, false /*not cancellable*/); assert(_cm->task_queues()->is_empty(), "Should be empty"); } @@ -255,49 +241,54 @@ void ShenandoahConcurrentMark::finish_mark() { } void ShenandoahConcurrentMark::finish_mark_work() { - // Finally mark everything else we've got in our queues during the previous steps. - // It does two different things for concurrent vs. mark-compact GC: - // - For concurrent GC, it starts with empty task queues, drains the remaining - // SATB buffers, and then completes the marking closure. - // - For mark-compact GC, it starts out with the task queues seeded by initial - // root scan, and completes the closure, thus marking through all live objects - // The implementation is the same, so it's shared here. ShenandoahHeap* const heap = ShenandoahHeap::heap(); - ShenandoahGCPhase phase(ShenandoahPhaseTimings::finish_mark); - uint nworkers = heap->workers()->active_workers(); - task_queues()->reserve(nworkers); + SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set(); - TaskTerminator terminator(nworkers, task_queues()); - - switch (_generation->type()) { - case YOUNG:{ - ShenandoahFinalMarkingTask task(this, &terminator); - heap->workers()->run_task(&task); - break; - } - case OLD:{ - ShenandoahFinalMarkingTask task(this, &terminator); - heap->workers()->run_task(&task); - break; - } - case GLOBAL:{ - ShenandoahFinalMarkingTask task(this, &terminator); - heap->workers()->run_task(&task); - break; - } - case NON_GEN:{ - ShenandoahFinalMarkingTask task(this, &terminator); - heap->workers()->run_task(&task); - break; - } - default: - ShouldNotReachHere(); + // First drain all remaining SATB buffers and put them to SATB MQ. + // Also, while we are iterating threads, mark the invisible roots. + { + ShenandoahTimingsTracker t(ShenandoahPhaseTimings::final_mark_flush_satb_roots); + ShenandoahInvisibleRootsMarkClosure invisible_cl; + ShenandoahFlushSATB flush_cl(satb_mq_set); + ShenandoahMultiThreadClosure mux(flush_cl, invisible_cl); + Threads::threads_do(&mux); } - if (!generation()->is_old() && heap->is_concurrent_young_mark_in_progress()) { - // Lastly, ensure all the invisible roots are marked. - ShenandoahInvisibleRootsMarkClosure cl; - Threads::java_threads_do(&cl); + + // There is a very high chance we have already completed the marking. + // But if there is outstanding work, finish it now. + if (!task_queues()->is_empty() || satb_mq_set.completed_buffers_num() > 0) { + ShenandoahGCPhase phase(ShenandoahPhaseTimings::finish_mark); + + uint nworkers = heap->workers()->active_workers(); + task_queues()->reserve(nworkers); + TaskTerminator terminator(nworkers, task_queues()); + + switch (_generation->type()) { + case YOUNG:{ + ShenandoahFinalMarkingTask task(this, &terminator); + heap->workers()->run_task(&task); + break; + } + case OLD:{ + ShenandoahFinalMarkingTask task(this, &terminator); + heap->workers()->run_task(&task); + break; + } + case GLOBAL:{ + ShenandoahFinalMarkingTask task(this, &terminator); + heap->workers()->run_task(&task); + break; + } + case NON_GEN:{ + ShenandoahFinalMarkingTask task(this, &terminator); + heap->workers()->run_task(&task); + break; + } + default: + ShouldNotReachHere(); + } } assert(task_queues()->is_empty(), "Should be empty"); + assert(satb_mq_set.completed_buffers_num() == 0, "Should be empty"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index 385ab10893c..bc52d755139 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -70,6 +70,7 @@ class outputStream; SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_gross, "Pause Final Mark (G)") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark, "Pause Final Mark (N)") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_verify, " Verify") \ + SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_flush_satb_roots, " Flush SATB and Roots") \ SHENANDOAH_WORKER_PHASE_DEF(f, finish_mark, " Finish Mark", \ " FM: ") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_propagate_gc_state, " Propagate GC State") \ From 39de79eae23410e335d2d1ced8fe3b4d7937a541 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 3 Jun 2026 06:33:32 +0000 Subject: [PATCH 038/115] 8367584: Implement JEP 536: JFR In-Process Data Redaction Reviewed-by: mgronlun --- src/hotspot/share/jfr/dcmd/jfrDcmds.cpp | 106 ++- src/hotspot/share/jfr/dcmd/jfrDcmds.hpp | 3 +- .../share/jfr/periodic/jfrOSInterface.cpp | 33 +- .../share/jfr/periodic/jfrOSInterface.hpp | 3 +- .../share/jfr/periodic/jfrPeriodic.cpp | 34 +- .../share/jfr/periodic/jfrRedactedEvents.cpp | 663 ++++++++++++++++++ .../share/jfr/periodic/jfrRedactedEvents.hpp | 223 ++++++ .../share/jfr/recorder/jfrRecorder.cpp | 4 + .../jfr/recorder/service/jfrOptionSet.cpp | 38 +- src/hotspot/share/logging/logTag.hpp | 1 + .../share/services/diagnosticFramework.hpp | 5 +- src/java.base/share/man/java.md | 43 +- test/jdk/jdk/jfr/startupargs/Application.java | 32 + .../jdk/jfr/startupargs/TestOptionsHelp.java | 47 ++ test/jdk/jdk/jfr/startupargs/TestRedact.java | 456 ++++++++++++ .../jfr/startupargs/redacted-arguments.txt | 6 + .../jdk/jdk/jfr/startupargs/redacted-keys.txt | 2 + 17 files changed, 1621 insertions(+), 78 deletions(-) create mode 100644 src/hotspot/share/jfr/periodic/jfrRedactedEvents.cpp create mode 100644 src/hotspot/share/jfr/periodic/jfrRedactedEvents.hpp create mode 100644 test/jdk/jdk/jfr/startupargs/Application.java create mode 100644 test/jdk/jdk/jfr/startupargs/TestOptionsHelp.java create mode 100644 test/jdk/jdk/jfr/startupargs/TestRedact.java create mode 100644 test/jdk/jdk/jfr/startupargs/redacted-arguments.txt create mode 100644 test/jdk/jdk/jfr/startupargs/redacted-keys.txt diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp index 549d879de99..a41515edfbb 100644 --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "jfr/dcmd/jfrDcmds.hpp" #include "jfr/jfr.hpp" #include "jfr/jni/jfrJavaSupport.hpp" +#include "jfr/periodic/jfrRedactedEvents.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/support/jfrThreadLocal.hpp" @@ -401,11 +402,25 @@ JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* out }; void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const { - outputStream* out = output(); + print_help(output(), false); +} + +static void print_filters(outputStream* out, JfrRedactedEvents::StringArray* filters) { + for (int i = 0; i < filters->length(); i++) { + out->print_cr(" %s", filters->at(i)->text()); + } +} + +void JfrConfigureFlightRecorderDCmd::print_help(outputStream* out, bool startup) { // 0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890 + if (startup) { + out->print_cr("Syntax : -XX:FlightRecorderOptions:[options]"); + out->print_cr(""); + } out->print_cr("Options:"); out->print_cr(""); - out->print_cr(" globalbuffercount (Optional) Number of global buffers. This option is a legacy"); + out->print_cr( " %-19s (Optional) Number of global buffers. This option is a legacy", + startup ? "numglobalbuffers": "globalbuffercount"); out->print_cr(" option: change the memorysize parameter to alter the number of"); out->print_cr(" global buffers. This value cannot be changed once JFR has been"); out->print_cr(" initialized. (STRING, default determined by the value for"); @@ -427,7 +442,8 @@ void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const { out->print_cr(" gigabytes. This value cannot be changed once JFR has been"); out->print_cr(" initialized. (STRING, 10M)"); out->print_cr(""); - out->print_cr(" repositorypath (Optional) Path to the location where recordings are stored until"); + out->print_cr( " %-19s (Optional) Path to the location where recordings are stored until", + startup ? "repository" : "repositorypath"); out->print_cr(" they are written to a permanent file. (STRING, The default"); out->print_cr(" location is the temporary directory for the operating system. On"); out->print_cr(" Linux operating systems, the temporary directory is /tmp. On"); @@ -443,7 +459,8 @@ void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const { out->print_cr(" degradation. This value cannot be changed once JFR has been"); out->print_cr(" initialized. (LONG, 64)"); out->print_cr(""); - out->print_cr(" thread_buffer_size (Optional) Local buffer size for each thread in bytes if one of"); + out->print_cr( " %-19s (Optional) Local buffer size for each thread in bytes if one of", + startup ? "threadbuffersize" : "thread_buffer_size"); out->print_cr(" the following suffixes is not used: 'k' or 'K' for kilobytes or"); out->print_cr(" 'm' or 'M' for megabytes. Overriding this parameter could reduce"); out->print_cr(" performance and is not recommended. This value cannot be changed"); @@ -452,14 +469,77 @@ void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const { out->print_cr(" preserve-repository (Optional) Preserve files stored in the disk repository after the"); out->print_cr(" Java Virtual Machine has exited. (BOOLEAN, false)"); out->print_cr(""); - out->print_cr("Options must be specified using the or = syntax."); - out->print_cr(""); - out->print_cr("Example usage:"); - out->print_cr(""); - out->print_cr(" $ jcmd JFR.configure"); - out->print_cr(" $ jcmd JFR.configure repositorypath=/temporary"); - out->print_cr(" $ jcmd JFR.configure stackdepth=256"); - out->print_cr(" $ jcmd JFR.configure memorysize=100M"); + if (startup) { + out->print_cr(" old-object-queue-size (Optional) Maximum number of old objects to track. By default,"); + out->print_cr(" the number of objects is set to 256. (LONG, 256)"); + out->print_cr(""); + out->print_cr(" redact-argument (Optional) Replace command-line arguments that match a"); + out->print_cr(" semicolon-separated list of glob patterns, for example,"); + out->print_cr(" *secret*;password*. Matching is case-insensitive, and the"); + out->print_cr(" supported wildcards are '*' and '?'. To redact multiple arguments,"); + out->print_cr(" use a literal space (' ') as a separator. For example, to match"); + out->print_cr(" the two arguments --auth username:token, use the filter"); + out->print_cr(" --auth *:*. Filters containing spaces must be quoted as a single"); + out->print_cr(" command-line argument, for example,"); + out->print_cr(" -XX:FlightRecorderOptions:'redact-argument=--auth *:*'."); + out->print_cr(" Arguments containing spaces might not be matched as expected."); + out->print_cr(" The option redact-argument is best-effort and applies only to"); + out->print_cr(" command-line arguments in the jdk.JVMInformation event and to"); + out->print_cr(" the java.command system property in the jdk.InitialSystemProperty"); + out->print_cr(" event. Other events, such as jdk.ProcessStart (child processes),"); + out->print_cr(" are not redacted."); + out->print_cr(""); + out->print_cr(" If the redact-argument option is not specified, the following"); + out->print_cr(" filters are used by default:"); + out->print_cr(""); + print_filters(out, JfrRedactedEvents::argument_filters()); + out->print_cr(""); + out->print_cr(" To load patterns from a file (one per line), use @."); + out->print_cr(" To add to the default patterns instead of replacing them, prefix"); + out->print_cr(" the whole list with '+', for example, +*foo*;@redact.txt."); + out->print_cr(" Use 'none' (lowercase) to disable all redaction filters for"); + out->print_cr(" command-line arguments. Redacted arguments will be replaced"); + out->print_cr(" with '[REDACTED]'. (STRING, default filters)"); + out->print_cr(""); + out->print_cr(" redact-key (Optional) Replace the value of environment variables and system"); + out->print_cr(" properties whose key matches a semicolon-separated list of glob"); + out->print_cr(" patterns, for example, *password*;*token*. Matching is"); + out->print_cr(" case-insensitive, and the supported wildcards are '*' and '?'."); + out->print_cr(" The option redact-key is best-effort and applies only to the"); + out->print_cr(" jdk.InitialSystemProperty, jdk.InitialEnvironmentVariable and"); + out->print_cr(" jdk.JVMInformation (-Dkey...) events. Other events, such as"); + out->print_cr(" jdk.InitialSecurityProperty, are not redacted."); + out->print_cr(""); + out->print_cr(" If the redact-key option is not specified, the"); + out->print_cr(" following filters are used by default:"); + out->print_cr(""); + print_filters(out, JfrRedactedEvents::key_filters()); + out->print_cr(""); + out->print_cr(" To load patterns from a file (one per line), use @."); + out->print_cr(" To add to the default patterns instead of replacing them, prefix"); + out->print_cr(" the whole list with '+', for example, +*cred*;@keys.txt."); + out->print_cr(" Use 'none' (lowercase) to disable all redaction filters for key"); + out->print_cr(" matching. Redacted values will be replaced with '[REDACTED]'."); + out->print_cr(" (STRING, default filters)"); + out->print_cr(""); + out->print_cr("Options must be specified using the = syntax. Multiple options are separated"); + out->print_cr("with a comma."); + out->print_cr(""); + out->print_cr("Example usage:"); + out->print_cr(""); + out->print_cr(" -XX:FlightRecorderOptions:repository=/temporary,stackdepth=256"); + out->print_cr(" -XX:FlightRecorderOptions:'redact-key=+*confidential*;*private*,redact-argument=+https://*:*@*'"); + out->print_cr(" -XX:FlightRecorderOptions:'redact-argument=+-*private *'"); + } else { + out->print_cr("Options must be specified using the or = syntax."); + out->print_cr(""); + out->print_cr("Example usage:"); + out->print_cr(""); + out->print_cr(" $ jcmd JFR.configure"); + out->print_cr(" $ jcmd JFR.configure repositorypath=/temporary"); + out->print_cr(" $ jcmd JFR.configure stackdepth=256"); + out->print_cr(" $ jcmd JFR.configure memorysize=100M"); + } out->print_cr(""); } diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp index 8e7dad5a20c..aecd187a2e0 100644 --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -202,6 +202,7 @@ class JfrConfigureFlightRecorderDCmd : public DCmdWithParser { return "Low"; } static int num_arguments() { return 10; } + static void print_help(outputStream* out, bool startup); virtual void execute(DCmdSource source, TRAPS); virtual void print_help(const char* name) const; }; diff --git a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp index 18b2d7c5785..71bcf7e02bf 100644 --- a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp +++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -268,37 +268,6 @@ const char* JfrOSInterface::virtualization_name() { return "No virtualization detected"; } -int JfrOSInterface::generate_initial_environment_variable_events() { - if (os::get_environ() == nullptr) { - return OS_ERR; - } - - if (EventInitialEnvironmentVariable::is_enabled()) { - // One time stamp for all events, so they can be grouped together - JfrTicks time_stamp = JfrTicks::now(); - for (char** p = os::get_environ(); *p != nullptr; p++) { - char* variable = *p; - char* equal_sign = strchr(variable, '='); - if (equal_sign != nullptr) { - // Extract key/value - ResourceMark rm; - ptrdiff_t key_length = equal_sign - variable; - char* key = NEW_RESOURCE_ARRAY(char, key_length + 1); - char* value = equal_sign + 1; - strncpy(key, variable, key_length); - key[key_length] = '\0'; - EventInitialEnvironmentVariable event(UNTIMED); - event.set_starttime(time_stamp); - event.set_endtime(time_stamp); - event.set_key(key); - event.set_value(value); - event.commit(); - } - } - } - return OS_OK; -} - int JfrOSInterface::system_processes(SystemProcess** sys_processes, int* no_of_sys_processes) { return instance()._impl->system_processes(sys_processes, no_of_sys_processes); } diff --git a/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp b/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp index 141e7505efb..9e8d4837a52 100644 --- a/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp +++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,6 @@ class JfrOSInterface: public JfrCHeapObj { static int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); static int os_version(char** os_version); static const char* virtualization_name(); - static int generate_initial_environment_variable_events(); static int system_processes(SystemProcess** system_processes, int* no_of_sys_processes); static int network_utilization(NetworkInterface** network_interfaces); }; diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 92f406bd095..83d58c704fc 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -41,6 +41,7 @@ #include "jfr/periodic/jfrNativeMemoryEvent.hpp" #include "jfr/periodic/jfrNetworkUtilization.hpp" #include "jfr/periodic/jfrOSInterface.hpp" +#include "jfr/periodic/jfrRedactedEvents.hpp" #include "jfr/periodic/jfrThreadCPULoadEvent.hpp" #include "jfr/periodic/jfrThreadDumpEvent.hpp" #include "jfr/recorder/jfrRecorder.hpp" @@ -100,17 +101,8 @@ TRACE_REQUEST_FUNC(ResidentSetSize) { } TRACE_REQUEST_FUNC(JVMInformation) { - ResourceMark rm; - EventJVMInformation event; - event.set_jvmName(VM_Version::vm_name()); - event.set_jvmVersion(VM_Version::internal_vm_info_string()); - event.set_javaArguments(Arguments::java_command()); - event.set_jvmArguments(Arguments::jvm_args()); - event.set_jvmFlags(Arguments::jvm_flags()); - event.set_jvmStartTime(Management::vm_init_done_time()); - event.set_pid(os::current_process_id()); - event.commit(); - } + JfrRedactedEvents::emit_jvm_information(); +} TRACE_REQUEST_FUNC(OSInformation) { ResourceMark rm; @@ -169,7 +161,9 @@ TRACE_REQUEST_FUNC(NativeLibrary) { } TRACE_REQUEST_FUNC(InitialEnvironmentVariable) { - JfrOSInterface::generate_initial_environment_variable_events(); + if (!JfrRedactedEvents::emit_initial_environment_variables()) { + log_debug(jfr, system)( "Unable to generate periodic event InitialEnvironmentVariable"); + } } TRACE_REQUEST_FUNC(CPUInformation) { @@ -393,7 +387,7 @@ TRACE_REQUEST_FUNC(BooleanFlag) { } TRACE_REQUEST_FUNC(StringFlag) { - SEND_FLAGS_OF_TYPE(StringFlag, ccstr); + JfrRedactedEvents::emit_string_flags(); } class VM_GC_SendObjectCountEvent : public VM_GC_HeapInspection { @@ -476,19 +470,7 @@ TRACE_REQUEST_FUNC(YoungGenerationConfiguration) { } TRACE_REQUEST_FUNC(InitialSystemProperty) { - SystemProperty* p = Arguments::system_properties(); - JfrTicks time_stamp = JfrTicks::now(); - while (p != nullptr) { - if (!p->internal()) { - EventInitialSystemProperty event(UNTIMED); - event.set_key(p->key()); - event.set_value(p->value()); - event.set_starttime(time_stamp); - event.set_endtime(time_stamp); - event.commit(); - } - p = p->next(); - } + JfrRedactedEvents::emit_initial_system_properties(); } TRACE_REQUEST_FUNC(ThreadAllocationStatistics) { diff --git a/src/hotspot/share/jfr/periodic/jfrRedactedEvents.cpp b/src/hotspot/share/jfr/periodic/jfrRedactedEvents.cpp new file mode 100644 index 00000000000..5ace0d0fae4 --- /dev/null +++ b/src/hotspot/share/jfr/periodic/jfrRedactedEvents.cpp @@ -0,0 +1,663 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "jfr/jfrEvents.hpp" +#include "jfr/periodic/jfrRedactedEvents.hpp" +#include "jfr/utilities/jfrTime.hpp" +#include "logging/log.hpp" +#include "logging/logMessage.hpp" +#include "runtime/arguments.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/os.hpp" +#include "runtime/vm_version.hpp" +#include "services/diagnosticArgument.hpp" +#include "services/diagnosticFramework.hpp" +#include "services/management.hpp" +#include "utilities/ostream.hpp" + +#include +#include +#include + +using StringArray = JfrRedactedEvents::StringArray; +using String = JfrRedactedEvents::String; +using StringFlag = JfrRedactedEvents::StringFlag; +using StringKeyValueArray = GrowableArray*; + +static const char REDACTED[] = "[REDACTED]"; +static const char DELIMITER[] = " "; +static const char REDACT_ARGUMENT_EQUAL[] = "redact-argument="; + +static const size_t REDACTED_LENGTH = sizeof(REDACTED) -1; +static const size_t DELIMITER_LENGTH = sizeof(DELIMITER) -1; +static const size_t REDACT_ARGUMENT_EQUAL_LENGTH = sizeof(REDACT_ARGUMENT_EQUAL) -1; + +String* JfrRedactedEvents::_redacted_java_command_line = nullptr; +String* JfrRedactedEvents::_redacted_jvm_command_line = nullptr; +String* JfrRedactedEvents::_redacted_flags_command_line = nullptr; +String* JfrRedactedEvents::_redacted_flight_recorder_options = nullptr; + +StringKeyValueArray JfrRedactedEvents::_initial_environment_variables = nullptr; +StringKeyValueArray JfrRedactedEvents::_initial_system_properties = nullptr; +GrowableArray* JfrRedactedEvents::_string_flags = nullptr; + +StringArray* JfrRedactedEvents::_redacted_arguments = nullptr; +StringArray* JfrRedactedEvents::_argument_filters = nullptr; +StringArray* JfrRedactedEvents::_key_filters = nullptr; + +bool JfrRedactedEvents::_initialized = false; + +bool JfrRedactedEvents::set_argument_filter(const char* filters) { + assert (_argument_filters == nullptr, "invariant"); + assert (filters != nullptr, "invariant"); + _argument_filters = new StringArray(); + return append_filters(_argument_filters, true, filters); +} + +bool JfrRedactedEvents::set_key_filter(const char* filters) { + assert (_key_filters == nullptr, "invariant"); + assert (filters != nullptr, "invariant"); + _key_filters = new StringArray(); + return append_filters(_key_filters, false, filters); +} + +void JfrRedactedEvents::log_redaction() { + //At this point JFR is not enabled so events will not be emitted + ensure_initialized(); + emit_initial_environment_variables(true); + emit_initial_system_properties(true); + emit_jvm_information(true); + emit_string_flags(true); +} + +StringArray* JfrRedactedEvents::key_filters() { + ensure_initialized(); + return _key_filters; +} + +StringArray* JfrRedactedEvents::argument_filters() { + ensure_initialized(); + return _argument_filters; +} + +void JfrRedactedEvents::add_default_filters(StringArray* target, bool argument) { + if (argument) { + target->add("-*api*key *"); + target->add("-*client*secret *"); + target->add("-*credential *"); + target->add("-*jaas*config *"); + target->add("-*passphrase *"); + target->add("-*passwd *"); + target->add("-*password *"); + target->add("-*private*key *"); + target->add("-*pwd *"); + target->add("-*secret *"); + target->add("-*token *"); + } else { + target->add("*auth*"); + } + target->add("*api*key*"); + target->add("*client*secret*"); + target->add("*credential*"); + target->add("*jaas*config*"); + target->add("*passphrase*"); + target->add("*passwd*"); + target->add("*password*"); + target->add("*private*key*"); + target->add("*pwd*"); + target->add("*secret*"); + target->add("*token*"); +} + +bool JfrRedactedEvents::append_filters(StringArray* target, bool argument, const char* filters) { + const char* option_name = argument ? "redact-argument": "redact-key"; + + if (filters == nullptr) { + log_warning(jfr, redact)("Missing value for option -XX:FlightRecorderOptions:%s", option_name); + return false; + } + if (filters[0] == '\0') { + LogMessage(jfr, redact) msg; + msg.warning("Default redaction filters are replaced. Specify:"); + msg.warning("-XX:FlightRecorderOptions:%s=none to disable filters without a warning.", option_name); + return true; + } + if (strcmp(filters, "none") == 0) { + return true; + } + if (filters[0] == '+') { + filters++; + add_default_filters(target, argument); + } else { + if (strncmp(filters, "none;", 5) != 0) { + LogMessage(jfr, redact) msg; + msg.warning("Default redaction filters are replaced. Prepend with '+' to add filters to the"); + msg.warning("defaults, or specify -XX:FlightRecorderOptions:'%s=none;'", option_name); + msg.warning("to replace without a warning."); + } else { + filters += 5; + } + } + StringArray* filter_array = split(filters, ';'); + bool success = true; + for (int i = 0; i < filter_array->length(); i++) { + const String* filter = filter_array->at(i); + if (strcmp(filter->text(), "none") == 0) { + log_error(jfr, redact)("'none' can only be used as the first filter."); + success = false; + break; + } + if (filter->at(0) == '@') { + const char* filename = filter->text() + 1; + if (!read_file(target, filename)) { + success = false; + } + } else { + target->add_contents(filter); + } + } + delete filter_array; + return success; +} + +char* JfrRedactedEvents::new_redacted_text() { + char* result = NEW_C_HEAP_ARRAY(char, REDACTED_LENGTH + 1, mtTracing); + strncpy(result, REDACTED, REDACTED_LENGTH + 1); + return result; +} + +bool JfrRedactedEvents::emit_initial_environment_variables(bool log) { + if (_initial_environment_variables == nullptr) { + ensure_initialized(); + char** envp = os::get_environ(); + if (envp == nullptr) { + return false; + } + _initial_environment_variables = make_array(0); + for (char** p = envp; *p != nullptr; ++p) { + char* variable = *p; + char* equal_sign = strchr(variable, '='); + if (equal_sign != nullptr) { + ptrdiff_t length = equal_sign - variable; + String* key = new String(variable, (size_t)length); + const char* value = equal_sign + 1; + if (is_redacted_key(key->text())) { + value = REDACTED; + if (log) { + log_debug(jfr, redact)("Redacted initial environment variable named '%s'", key->text()); + } + } + _initial_environment_variables->append(new StringKeyValue(key, value)); + } + } + } + JfrTicks time_stamp = JfrTicks::now(); + for (int i = 0; i < _initial_environment_variables->length(); i++) { + StringKeyValue* pair = _initial_environment_variables->at(i); + EventInitialEnvironmentVariable event(UNTIMED); + event.set_starttime(time_stamp); + event.set_endtime(time_stamp); + event.set_key(pair->key()); + event.set_value(pair->value()); + event.commit(); + } + return true; +} + +void JfrRedactedEvents::emit_initial_system_properties(bool log) { + if (_initial_system_properties == nullptr) { + ensure_initialized(); + _initial_system_properties = make_array(0); + for (SystemProperty* p = Arguments::system_properties(); p != nullptr; p = p->next()) { + if (!p->internal()) { + const char* value = p->value(); + if (strcmp(p->key(), "sun.java.command") == 0) { + value = String::c_str(_redacted_java_command_line); + } + if (is_redacted_key(p->key())) { + value = REDACTED; + } + if (log && value != nullptr && strstr(value, REDACTED) != nullptr) { + log_debug(jfr, redact)("Redacted initial system property named '%s'", p->key()); + } + _initial_system_properties->append(new StringKeyValue(p->key(), value)); + } + } + } + + JfrTicks time_stamp = JfrTicks::now(); + for (int i = 0; i < _initial_system_properties->length(); i++) { + StringKeyValue* pair = _initial_system_properties->at(i); + EventInitialSystemProperty event(UNTIMED); + event.set_key(pair->key()); + event.set_value(pair->value()); + event.set_starttime(time_stamp); + event.set_endtime(time_stamp); + event.commit(); + } +} + +bool JfrRedactedEvents::match_flag(const char* flag_name, const char* arg) { + if (flag_name == nullptr || arg == nullptr) { + return false; + } + while (*flag_name) { + if (*arg != *flag_name) { + return false; + } + flag_name++; + arg++; + } + return *arg == '\0' || *arg == '='; +} + +void JfrRedactedEvents::emit_string_flags(bool log) { + if (_string_flags == nullptr) { + ensure_initialized(); + _string_flags = make_array(0); + JVMFlag *flag = JVMFlag::flags; + while (flag->name() != nullptr) { + if (flag->is_ccstr() && flag->is_unlocked()) { + const char* value = nullptr; + bool redacted = false; + for (int i = 0; i < _redacted_arguments->length(); i++) { + if (match_flag(flag->name(), _redacted_arguments->at(i)->text())) { + value = REDACTED; + redacted = true; + break; + } + } + if (strcmp("FlightRecorderOptions", flag->name()) == 0) { + if (_redacted_flight_recorder_options != nullptr) { + value = _redacted_flight_recorder_options->text(); + redacted = true; + } + } + if (log && redacted) { + log_debug(jfr, redact)("Redacted string flag '%s'", flag->name()); + } + _string_flags->append(new StringFlag(flag, value)); + } + ++flag; + } + } + for (int i = 0; i < _string_flags->length(); i++) { + StringFlag* sf = _string_flags->at(i); + const JVMFlag* flag = sf->jvm_flag(); + EventStringFlag event; + event.set_name(flag->name()); + if (sf->redacted_value() != nullptr) { + // If a flag is redacted and later changed at runtime, + // the event will still show the redacted text. + event.set_value(sf->redacted_value()); + } else { + // If a flag is not redacted the first time, + // it will not be redacted later if it's changed at runtime. + event.set_value(flag->get_ccstr()); + } + event.set_origin(static_cast(flag->get_origin())); + event.commit(); + } +} + +void JfrRedactedEvents::log_jvm_information_redaction(const char* type, const String* redacted) { + const char* text = String::c_str(redacted); + if (text != nullptr && strstr(text, REDACTED) != nullptr) { + log_debug(jfr, redact)("Redacted %s '%s'", type, text); + } +} + +void JfrRedactedEvents::emit_jvm_information(bool log) { + ensure_initialized(); + EventJVMInformation event; + event.set_jvmName(VM_Version::vm_name()); + event.set_jvmVersion(VM_Version::internal_vm_info_string()); + event.set_javaArguments(String::c_str(_redacted_java_command_line)); + event.set_jvmArguments(String::c_str(_redacted_jvm_command_line)); + event.set_jvmFlags(String::c_str(_redacted_flags_command_line)); + event.set_jvmStartTime(Management::vm_init_done_time()); + event.set_pid(os::current_process_id()); + event.commit(); + if (log) { + log_jvm_information_redaction("Java Arguments", _redacted_java_command_line); + log_jvm_information_redaction("JVM Arguments", _redacted_jvm_command_line); + log_jvm_information_redaction("JVM Flags", _redacted_flags_command_line); + } +} + +void JfrRedactedEvents::ensure_initialized() { + if (_initialized) { + return; + } + if (_key_filters == nullptr) { + _key_filters = new StringArray(); + add_default_filters(_key_filters, false); + } + if (_argument_filters == nullptr) { + _argument_filters = new StringArray(); + add_default_filters(_argument_filters, true); + } + if (FlightRecorderOptions != nullptr) { + if (strstr(FlightRecorderOptions, REDACT_ARGUMENT_EQUAL) != nullptr) { + DCmdIter iterator(FlightRecorderOptions, ','); + stringStream result; + size_t pos = 0; + while(iterator.has_next()) { + CmdLine line = iterator.next(); + const char* start = line.cmd_addr(); + if (strncmp(start, REDACT_ARGUMENT_EQUAL, REDACT_ARGUMENT_EQUAL_LENGTH) == 0) { + result.print(REDACT_ARGUMENT_EQUAL); + result.print(REDACTED); + // Preserve ',' if there are more tokens + pos = iterator.has_next() ? iterator.cursor() - 1 : iterator.cursor(); + } + while (pos < iterator.cursor()) { + result.write(FlightRecorderOptions + pos, 1); + pos++; + } + } + _redacted_flight_recorder_options = new String(result.base()); + } else { + _redacted_flight_recorder_options = new String(FlightRecorderOptions); + } + } + + _redacted_arguments = new StringArray(); + + StringArray* java_args = make_java_args_array(); + _redacted_java_command_line = redact_command_line(java_args); + delete java_args; + + StringArray* jvm_args = make_jvm_args_array(Arguments::jvm_args_array(), Arguments::num_jvm_args()); + _redacted_jvm_command_line = redact_command_line(jvm_args); + delete jvm_args; + + StringArray* flags_args = make_jvm_args_array(Arguments::jvm_flags_array(), Arguments::num_jvm_flags()); + _redacted_flags_command_line = redact_command_line(flags_args); + delete flags_args; + + _initialized = true; +} + +String* JfrRedactedEvents::redact_command_line(StringArray* arguments) { + if (arguments == nullptr) { + return nullptr; + } + GrowableArray* filters = make_array(_argument_filters->length()); + for (int i = 0 ; i < _argument_filters->length(); i++) { + filters->append(make_filter_array(_argument_filters->at(i)->text())); + } + StringArray* result = new StringArray(); + int arg_index = 0; + while (arg_index < arguments->length()) { + int next_index = arg_index; + for (int i = 0; i < filters->length(); i++) { + next_index = match_arguments(filters->at(i), arguments, arg_index); + if (next_index > arg_index) { + break; + } + } + if (next_index > arg_index) { + for (int j = arg_index; j < next_index; j++) { + result->add(REDACTED); + const char* arg = arguments->at(j)->text(); + if (arg != nullptr && strncmp(arg, "-XX:", 4) == 0) { + _redacted_arguments->add(arg + 4); + } + } + arg_index = next_index; + } else { + result->add_contents(arguments->at(arg_index)); + arg_index++; + } + } + destroy_array(filters); + String* ret = concatenate(result); + delete result; + return ret; +} + +String* JfrRedactedEvents::concatenate(StringArray* strings) { + size_t length = 0; + for (int i = 0; i < strings->length(); i++) { + length += strings->at(i)->length(); + if (i != 0) { + length += 1; + } + } + String* text = new String(length); + size_t index = 0; + for (int i = 0; i < strings->length(); i++) { + if (i != 0) { + text->set(index++, ' '); + } + const String* s = strings->at(i); + size_t len = s->length(); + for (size_t j = 0; j < len; j++) { + text->set(index++, s->at(j)); + } + } + return text; +} + +bool JfrRedactedEvents::equals_case_insensitive(char a, char b) { + return tolower((unsigned char)a) == tolower((unsigned char)b); +} + +bool JfrRedactedEvents::is_redacted_key(const char* key) { + return match_key(_key_filters, key); +} + +bool JfrRedactedEvents::is_separator(char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; +} + +bool JfrRedactedEvents::is_whitespace(char c) { + return c == ' '; +} + +StringArray* JfrRedactedEvents::make_filter_array(const char* filter) { + StringArray* result = new StringArray(); + + while (*filter) { + const char* q = strstr(filter, DELIMITER); + if (q == nullptr) { + size_t len = strlen(filter); + if (len > 0) { + result->add(filter, len); + } + break; + } + size_t len = (size_t)(q - filter); + if (len > 0) { + result->add(filter, len); + } + filter = q + DELIMITER_LENGTH; + } + + return result; +} + +StringArray* JfrRedactedEvents::make_jvm_args_array(char** jvm_args_array, int array_length) { + if (jvm_args_array == nullptr) { + return nullptr; + } + StringArray* result = new StringArray(array_length); + for(int i = 0; i < array_length; i++) { + char* argument = jvm_args_array[i]; + if (_redacted_flight_recorder_options != nullptr && + strncmp(argument, "-XX:FlightRecorderOptions", 25) == 0) { + const char* text = _redacted_flight_recorder_options->text(); + size_t length = _redacted_flight_recorder_options->length(); + // Length must be at least 26 or the JVM will not start. + result->add(new String(argument, 26, text, length)); + continue; + } + if (strncmp(argument, "-D", 2) == 0) { + const char* key_start = argument + 2; + const char* eq = strchr(key_start, '='); + if (eq != nullptr) { + size_t key_length = (size_t)(eq - key_start); + String* key_tmp = new String(key_start, key_length); + bool redact = match_key(_key_filters, key_tmp->text()); + delete key_tmp; + if (redact) { + size_t unsensitive_length = (size_t)(eq - argument) + 1; + result->add(new String(argument, unsensitive_length, REDACTED, REDACTED_LENGTH)); + continue; + } + } + } + result->add(argument); + } + return result; +} + +StringArray* JfrRedactedEvents::make_java_args_array() { + StringArray* array = new StringArray(); + const char* p = Arguments::java_command(); + if (p == nullptr) { + return array; + } + const char* end = p + strlen(p); + while (p < end) { + while (p < end && is_whitespace(*p)) { // Launcher separates arguments with ' '. + p++; + } + if (p >= end) { + break; + } + const char* start = p; + while (p < end && !is_whitespace(*p)) { // Launcher separates arguments with ' '. + p++; + } + size_t length = (size_t)(p - start); + if (length > 0) { + array->add(start, length); + } + } + return array; +} + +bool JfrRedactedEvents::match(const char* filter, const char* text) { + const char* filter_last = nullptr; + const char* text_last = nullptr; + while (*text != '\0') { + if (*filter == '*') { + filter_last = filter; + text_last = text; + filter++; + } else if (*filter == '?' || equals_case_insensitive(*filter, *text)) { + filter++; + text++; + } else if (filter_last != nullptr) { + text_last++; + text = text_last; + filter = filter_last + 1; + } else { + return false; + } + } + while (*filter == '*') { + filter++; + } + return *filter == '\0'; +} + +int JfrRedactedEvents::match_arguments(StringArray* filter, StringArray* arguments, int arg_index) { + int index = arg_index; + if (arg_index + filter->length() <= arguments->length()) { + for (int i = 0; i < filter->length(); i++) { + if (!match(filter->at(i)->text(), arguments->at(index)->text())) { + return arg_index; + } + index++; + } + } + return index; +} + +bool JfrRedactedEvents::match_key(StringArray* filters, const char* text) { + for (int i = 0; i < filters->length(); i++) { + const char* filter = filters->at(i)->text(); + if (match(filter, text)) { + return true; + } + } + return false; +} + +bool JfrRedactedEvents::read_file(StringArray* target, const char* filename) { + FILE* file = os::fopen(filename, "r"); + if (file == nullptr) { + log_error(jfr, redact)("Failed to open redaction file: %s", filename); + return false; + } + + stringStream ss; + while (true) { + const int c = fgetc(file); + if (c == EOF && ferror(file) != 0) { + log_error(jfr, redact)("Error reading redaction file: %s", filename); + fclose(file); + return false; + } + if (c == EOF || c == '\n') { + const char* line = ss.base(); + size_t end = ss.size(); + while (end > 0 && is_separator(line[end - 1])) { + end--; + } + if (end > 0) { + target->add(line, end); + } + ss.reset(); + if (c == EOF) { + break; + } + } else { + ss.put((char)c); + } + } + fclose(file); + log_debug(jfr, redact)("Redaction file %s read successfully", filename); + return true; +} + +StringArray* JfrRedactedEvents::split(const char* text, char separator) { + const char* last = text; + StringArray* result = new StringArray(); + for (const char* position = text; *position != '\0'; position++) { + if (*position == separator) { + if (position > last) { + result->add(last, (size_t)(position - last)); + } + last = position + 1; + } + } + if (*last != '\0') { + result->add(last, strlen(last)); + } + return result; +} diff --git a/src/hotspot/share/jfr/periodic/jfrRedactedEvents.hpp b/src/hotspot/share/jfr/periodic/jfrRedactedEvents.hpp new file mode 100644 index 00000000000..38c93310365 --- /dev/null +++ b/src/hotspot/share/jfr/periodic/jfrRedactedEvents.hpp @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_PERIODIC_JFRREDACTEDEVENTS_HPP +#define SHARE_JFR_PERIODIC_JFRREDACTEDEVENTS_HPP + +#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" + +#include + +class JVMFlag; + +class JfrRedactedEvents: public AllStatic { + public: + class StringArray; + // Called at startup + static void log_redaction(); + static char* new_redacted_text(); + static bool set_argument_filter(const char* filters); + static bool set_key_filter(const char* filters); + static StringArray* argument_filters(); + static StringArray* key_filters(); + + // Synchronized in Java + static bool emit_initial_environment_variables(bool log = false); + static void emit_initial_system_properties(bool log = false); + static void emit_jvm_information(bool log = false); + static void emit_string_flags(bool log = false); + + template static GrowableArray* make_array(int size) { + return new (mtTracing) GrowableArray(size, mtTracing); + } + + template static void destroy_array(GrowableArray* array) { + if (array == nullptr) { + return; + } + for (int i = 0; i < array->length(); ++i) { + delete array->at(i); + } + delete array; + } + + class String: public CHeapObj { + public: + String(size_t length) : _length(length) { + _text = NEW_C_HEAP_ARRAY(char, length + 1, mtTracing); + memset(_text, 0, length + 1); + } + String(const char* source, size_t length) : String(length) { + memcpy(_text, source, length); + } + String(const char* source) : String(source, strlen(source)) { + } + String(const char* prefix, size_t prefix_length, const char* postfix, size_t postfix_length) + : String(prefix_length + postfix_length) { + memcpy(_text, prefix, prefix_length); + memcpy(_text + prefix_length, postfix, postfix_length); + } + ~String() { + FREE_C_HEAP_ARRAY(_text); + } + const char* text() const { + return _text; + } + char at(size_t index) const { + assert(index < _length, "out of bounds"); + return _text[index]; + } + void set(size_t index, char c) { + assert(index < _length, "out of bounds"); + _text[index] = c; + } + size_t length() const { + return _length; + } + static String* from_cstr(const char* s) { + return s == nullptr ? nullptr : new String(s); + } + static const char* c_str(const String* s) { + return s == nullptr ? nullptr : s->text(); + } + private: + const size_t _length; + char* _text; + }; + + class StringArray: public CHeapObj { + public: + StringArray() : _array(make_array(0)) { + } + StringArray(int capacity) : _array(make_array(capacity)) { + } + StringArray(const char* const array[], int count) : _array(make_array(count)) { + for (int i = 0; i < count; ++i) { + _array->append(new String(array[i])); + } + } + ~StringArray() { + destroy_array(_array); + } + int length() const { + return _array->length(); + } + const String* at(int i) const { + return _array->at(i); + } + void add(String* s) { + _array->append(s); + } + void add_contents(const String* s) { + add(s->text()); + } + void add(const char* s) { + _array->append(new String(s)); + } + void add(const char* s, size_t length) { + _array->append(new String(s, length)); + } + private: + GrowableArray* const _array; + }; + + class StringKeyValue: public CHeapObj { + public: + StringKeyValue(String* key, const char* value): _key(key), _value(String::from_cstr(value)) { + } + StringKeyValue(const char* key, const char* value) : StringKeyValue(new String(key), value) { + } + ~StringKeyValue() { + delete _key; + delete _value; + } + const char* key() const { + return _key->text(); + } + const char* value() const { + return String::c_str(_value); + } + private: + String* const _key; + String* const _value; + }; + + class StringFlag: public CHeapObj { + public: + StringFlag(const JVMFlag* flag, const char* redacted_value) + : _flag(flag), + _redacted_value(String::from_cstr(redacted_value)) { + } + ~StringFlag() { + delete _redacted_value; + } + const JVMFlag* jvm_flag() const { + return _flag; + } + const char* redacted_value() const { + return _redacted_value == nullptr ? nullptr : _redacted_value->text(); + } + private: + const JVMFlag* const _flag; + String* _redacted_value; + }; + + private: + static bool _initialized; + static StringArray* _argument_filters; + static StringArray* _key_filters; + static StringArray* _redacted_arguments; + static String* _redacted_java_command_line; + static String* _redacted_jvm_command_line; + static String* _redacted_flags_command_line; + static String* _redacted_flight_recorder_options; + static GrowableArray* _initial_system_properties; + static GrowableArray* _initial_environment_variables; + static GrowableArray* _string_flags; + + static bool append_filters(StringArray* target, bool argument, const char* filters); + static void add_default_filters(StringArray* target, bool argument); + static String* concatenate(StringArray* strings); + static bool equals_case_insensitive(char a, char b); + static bool is_redacted_key(const char* key); + static bool is_separator(char c); + static bool is_whitespace(char c); + static void ensure_initialized(); + static StringArray* make_java_args_array(); + static StringArray* make_jvm_args_array(char** jvm_args_array, int array_length); + static StringArray* make_filter_array(const char* filter); + static void log_jvm_information_redaction(const char* type, const String* redacted); + static bool match(const char* pattern, const char* text); + static bool match_flag(const char* flag_name, const char* argument); + static int match_arguments(StringArray* filter_array, StringArray* arguments, int arg_index); + static bool match_key(StringArray* array, const char* text); + static bool read_file(StringArray* target, const char* filename); + static String* redact_command_line(StringArray* arguments); + static StringArray* split(const char* text, char separator); +}; + +#endif // SHARE_JFR_PERIODIC_JFRREDACTEDEVENTS_HPP diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index 5c12d5213ca..bb17b1d0eec 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -29,6 +29,7 @@ #include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/periodic/jfrOSInterface.hpp" +#include "jfr/periodic/jfrRedactedEvents.hpp" #include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp" #include "jfr/periodic/sampling/jfrThreadSampler.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" @@ -243,6 +244,9 @@ bool JfrRecorder::on_create_vm_2() { } bool JfrRecorder::on_create_vm_3() { + if (log_is_enabled(Debug, jfr, redact)) { + JfrRedactedEvents::log_redaction(); + } JVMTI_ONLY( assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence, phase is %d", (int)JvmtiEnvBase::get_phase()); ) return CDSConfig::is_dumping_archive() || launch_command_line_recordings(JavaThread::current()); } diff --git a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp index ec8ab36d75a..bdd42ba881e 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "cds/cdsConfig.hpp" #include "classfile/javaClasses.hpp" #include "jfr/dcmd/jfrDcmds.hpp" +#include "jfr/periodic/jfrRedactedEvents.hpp" #include "jfr/recorder/service/jfrMemorySizer.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/utilities/jfrAllocation.hpp" @@ -262,6 +263,20 @@ static DCmdArgument _dcmd_preserve_repository( false, default_preserve_repository); +static DCmdArgument _dcmd_redact_argument( + "redact-argument", + "Redact command line arguments", + "STRING", + false, + nullptr); + +static DCmdArgument _dcmd_redact_key( + "redact-key", + "Redact environment variables and system properties", + "STRING", + false, + nullptr); + static DCmdParser _parser; static void register_parser_options() { @@ -277,6 +292,8 @@ static void register_parser_options() { _parser.add_dcmd_option(&_dcmd_retransform); _parser.add_dcmd_option(&_dcmd_old_object_queue_size); _parser.add_dcmd_option(&_dcmd_preserve_repository); + _parser.add_dcmd_option(&_dcmd_redact_argument); + _parser.add_dcmd_option(&_dcmd_redact_key); DEBUG_ONLY(_parser.add_dcmd_option(&_dcmd_sample_protection);) } @@ -285,6 +302,11 @@ static bool parse_flight_recorder_options_internal(TRAPS) { return true; } const size_t length = strlen((const char*)FlightRecorderOptions); + if (strcmp(FlightRecorderOptions, "help") == 0) { + JfrConfigureFlightRecorderDCmd::print_help(tty, true); + vm_exit(0); + } + CmdLine cmdline((const char*)FlightRecorderOptions, length, true); _parser.parse(&cmdline, ',', THREAD); if (HAS_PENDING_EXCEPTION) { @@ -332,6 +354,20 @@ bool JfrOptionSet::initialize(JavaThread* thread) { set_retransform(_dcmd_retransform.value()); } set_old_object_queue_size(_dcmd_old_object_queue_size.value()); + if (_dcmd_redact_argument.is_set()) { + if (!JfrRedactedEvents::set_argument_filter(_dcmd_redact_argument.value())) { + return false; + } + _dcmd_redact_argument.destroy_value(); + _dcmd_redact_argument.set_value(JfrRedactedEvents::new_redacted_text()); + } + if (_dcmd_redact_key.is_set()) { + if (!JfrRedactedEvents::set_key_filter(_dcmd_redact_key.value())) { + return false; + } + _dcmd_redact_key.destroy_value(); + _dcmd_redact_key.set_value(JfrRedactedEvents::new_redacted_text()); + } return adjust_memory_options(); } diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index 848ff78678a..15f45d04af3 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -169,6 +169,7 @@ class outputStream; LOG_TAG(ptrqueue) \ LOG_TAG(purge) \ LOG_TAG(record) \ + LOG_TAG(redact) \ LOG_TAG(redefine) \ LOG_TAG(ref) \ LOG_TAG(refine) \ diff --git a/src/hotspot/share/services/diagnosticFramework.hpp b/src/hotspot/share/services/diagnosticFramework.hpp index 5f9253b492e..5fd0182fd77 100644 --- a/src/hotspot/share/services/diagnosticFramework.hpp +++ b/src/hotspot/share/services/diagnosticFramework.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,6 +85,9 @@ public: // instance to the caller. return line; } + size_t cursor() const { + return _cursor; + } }; // Iterator class to iterate over diagnostic command arguments diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 290f729c0ca..70824046824 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -1148,8 +1148,10 @@ These `java` options control the runtime behavior of the Java HotSpot VM. option is disabled. [`-XX:FlightRecorderOptions=`]{#-XX_FlightRecorderOptions}*parameter*`=`*value* (or) `-XX:FlightRecorderOptions:`*parameter*`=`*value* -: Sets the parameters that control the behavior of JFR. Multiple parameters can be specified - by separating them with a comma. +: Sets the parameters that control the behavior of JFR. + `-XX:FlightRecorderOptions:help` prints the available options, default + redaction filters, and example command lines. Multiple parameters can be + specified by separating them with a comma. The following list contains the available JFR *parameter*`=`*value* entries: @@ -1196,6 +1198,43 @@ These `java` options control the runtime behavior of the Java HotSpot VM. false, instrumentation is added when event classes are loaded. By default, this parameter is enabled. + `redact-argument=`argument-filter + : Replace command-line arguments that match a semicolon-separated list + of glob patterns, for example, `*secret*;password*`. Matching is + case-insensitive, and the supported wildcards are `*` and `?`. To redact + multiple arguments, use a literal space (`' '`) as a separator. + For example, to match the two arguments `--auth username:token`, use the + filter `--auth *:*`. Filters containing spaces must be quoted as a single + command-line argument, for example, + `-XX:FlightRecorderOptions='redact-argument=--auth *:*'`. + Arguments containing spaces might not be matched as expected. To load + patterns from a file (one per line) use `@`. To add to the + default patterns instead of replacing them, prefix the whole list with + `+`, for example, `+*foo*;@redact.txt`. Use `none` (lowercase) to disable + all redaction filters for command-line arguments. Redacted arguments will + be replaced with `[REDACTED]`. The option `redact-argument` is best-effort + and applies only to command-line arguments in the `jdk.JVMInformation` + event and to the `java.command` system property in the + `jdk.InitialSystemProperty` event. Other events, such as `jdk.ProcessStart` + (child processes), are not redacted. Use `-XX:FlightRecorderOptions:help` + to see the default filters used by the `redact-argument` option. + + `redact-key=`key-filter + : Replace the value of environment variables and system properties + whose key matches a semicolon-separated list of glob patterns, + for example, `*password*;*token*`. Matching is case-insensitive, and + the supported wildcards are `*` and `?`. To load patterns from a file + (one per line), use `@`. To add to the default patterns + instead of replacing them, prefix the whole list with `+`, + for example, `+*cred*;@keys.txt`. Use `none` (lowercase) to + disable all redaction filters for key matching. Redacted values + will be replaced with `[REDACTED]`. The option `redact-key` is + best-effort and applies only to the `jdk.InitialSystemProperty`, + `jdk.InitialEnvironmentVariable` and `jdk.JVMInformation` (-Dkey=...) + events. Other events, such as `jdk.InitialSecurityProperty`, are not + redacted. Use `-XX:FlightRecorderOptions:help` to see the default filters + used by the `redact-key` option. + `stackdepth=`*depth* : Stack depth for stack traces. By default, the depth is set to 64 method calls. The maximum is 2048. Values greater than 64 could create diff --git a/test/jdk/jdk/jfr/startupargs/Application.java b/test/jdk/jdk/jfr/startupargs/Application.java new file mode 100644 index 00000000000..74235b04f7e --- /dev/null +++ b/test/jdk/jdk/jfr/startupargs/Application.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.startupargs; + +// Purpose of this class is to allow tests capture environment variables, +// system properties and command line arguments. Using 'java -version' will +// not work as Java command line arguments are not captured. +public class Application { + public static void main(String... args) { + } +} diff --git a/test/jdk/jdk/jfr/startupargs/TestOptionsHelp.java b/test/jdk/jdk/jfr/startupargs/TestOptionsHelp.java new file mode 100644 index 00000000000..16f7ce8500c --- /dev/null +++ b/test/jdk/jdk/jfr/startupargs/TestOptionsHelp.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.startupargs; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main jdk.jfr.startupargs.TestOptionsHelp + */ +public class TestOptionsHelp { + + public static void main(String... args) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-XX:FlightRecorderOptions:help"); + OutputAnalyzer out = ProcessTools.executeProcess(pb); + out.shouldContain("Syntax : -XX:FlightRecorderOptions:[options]"); + out.shouldContain("numglobalbuffers"); + out.shouldContain("Multiple options are separated"); + out.shouldHaveExitValue(0); + } +} diff --git a/test/jdk/jdk/jfr/startupargs/TestRedact.java b/test/jdk/jdk/jfr/startupargs/TestRedact.java new file mode 100644 index 00000000000..2d96408a3f5 --- /dev/null +++ b/test/jdk/jdk/jfr/startupargs/TestRedact.java @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.startupargs; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import jdk.jfr.FlightRecorder; +import jdk.jfr.Recording; +import jdk.jfr.RecordingState; +import jdk.jfr.consumer.EventStream; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.CommonHelper; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +/** + * @test + * @summary Test that redaction of sensitive data works + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @build jdk.jfr.startupargs.Application + * @run main/timeout=900 jdk.jfr.startupargs.TestRedact + */ +public class TestRedact { + private static Path TEST_DIRECTORY = Path.of(System.getProperty("test.src", ".")).toAbsolutePath(); + private static Path FILE_REDACTED_ARGUMENTS = TEST_DIRECTORY.resolve("redacted-arguments.txt"); + private static Path FILE_REDACTED_KEYS = TEST_DIRECTORY.resolve("redacted-keys.txt"); + + private record Execution( + Path file, + String jvmArgs, + String jvmFlags, + String javaArgs, + Map environment, + Map systemProperties, + Map stringFlags, + OutputAnalyzer output + ) { + + void assertUnredacted(String text) throws Exception { + if (jvmArgs != null && jvmArgs.contains(text)) { + return; + } + if (javaArgs != null && javaArgs.contains(text)) { + return; + } + if (systemProperties.containsValue(text) || environment.containsValue(text)) { + return; + } + printSystemProperties(); + printEnvironment(); + printCommandLine(); + throw new Exception("Could not find text '" + text + "'. Likely it's been incorrectly redacted."); + } + + private void printCommandLine() { + System.out.println("JVM Args: " + jvmArgs); + System.out.println("JVM Flags: " + jvmFlags); + System.out.println("Java Args: " + javaArgs); + System.out.println(); + } + + void assertRedactedKey(String key) throws Exception { + String v = systemProperties.get(key); + if (v != null) { + printSystemProperties(); + if (!v.equals("[REDACTED]")) { + throw new Exception("Expected system property value of key '" + key + "' to be [REDACTED]"); + } + return; + } + v = environment.get(key); + if (v == null) { + printEnvironment(); + printSystemProperties(); + throw new Exception("Expected key '" + key + "' in environment variable or system property"); + } + if (!v.equals("[REDACTED]")) { + printEnvironment(); + throw new Exception("Expected environment value of key '" + key + "' to be [REDACTED]"); + } + } + + void printEnvironment() { + printProperties("Environment Variables", environment); + } + + void printStringFlags() { + printProperties("String Flags", stringFlags); + } + + void printSystemProperties() { + printProperties("System Properties", systemProperties); + } + + private void printProperties(String title, Map map) { + System.out.println(title); + System.out.println("=".repeat(title.length())); + for (var entry : map.entrySet()) { + System.out.println(entry.getKey() + " = " + entry.getValue()); + } + System.out.println(); + } + + boolean hasCapitalizedLetter(String text) { + return text.chars().anyMatch(Character::isUpperCase); + } + + void assertRedactedArgument(String argument) throws Exception { + if (!hasCapitalizedLetter(argument)) { + throw new IllegalArgumentException("Redacted arguments in test must have at least one capitalized letter to avoid clash with random UUID in temporary filenames."); + } + checkArgument("JVM arguments", jvmArgs, argument); + checkArgument("Java arguments", javaArgs, argument); + checkArgument("Flags", jvmFlags, argument); + checkArgument("sun.java.command", systemProperties.get("sun.java.command"), argument); + } + + private void checkArgument(String kind, String arguments, String argument) throws Exception { + if (arguments != null && arguments.contains(argument)) { + System.out.println("ARGS: " + arguments); + throw new Exception("Found '" + argument + "' in " + kind + ". Should have been [REDACTED]"); + } + } + + public void print() { + printCommandLine(); + printEnvironment(); + printSystemProperties(); + printStringFlags(); + } + } + + public static void main(String... args) throws Exception { + testRedactionOfRedacted(); + testRedactKey(); + testRedactArgument(); + testRedactMultiple(); + testWildcards(); + testDefaults(); + testRedactFile(); + testAppendable(); + testEmpty(); + testBinary(); + } + + private static void testRedactionOfRedacted() throws Exception { + Execution e = run( + "-XX:FlightRecorderOptions:" + + "maxchunksize=1MB,redact-argument=Zebra," + + "old-object-queue-size=256," + + "redact-key=tiger", + "Zebra", + "Tiger" + ); + e.assertRedactedArgument("Zebra"); + e.assertRedactedArgument("redact-argument=Zebra"); + e.assertUnredacted("Tiger"); + } + + private static void testAppendable() throws Exception { + Execution e = run( + Map.of( + "Secret", "Thing", // For default filter + "Cat", "Bird" // For user-defined filter + ), + Map.of( + "Secret", "Stuff", // For default filter + "Cat", "Dog" // For user-defined filter + ), + "-XX:FlightRecorderOptions:redact-argument=+Foo;Bar,redact-key=+Cat", + "Foo", // For user-defined + "Bar", // For user-defined + "Secret"); // For default filter + e.assertRedactedArgument("Foo"); // Matched by user-defined filter + e.assertRedactedArgument("Bar"); // Matched by user-defined filter + e.assertRedactedKey("Cat"); // Matched by user-defined filter + e.assertRedactedArgument("Secret"); // Matched by default filter *secret* + e.assertRedactedKey("Secret"); // Matched by default filter *secret* + } + + private static void testWildcards() throws Exception { + Execution e = run( + "-XX:FlightRecorderOptions:redact-argument=*PPLE;ORAN*;C*HE*RY;N?2?4?;A?C*?F", + "APPLE", "ORANGE", "CHERRY", "N12345", "ABCDEF", "N4711" + ); + e.assertRedactedArgument("APPLE"); + e.assertRedactedArgument("ORANGE"); + e.assertRedactedArgument("CHERRY"); + e.assertRedactedArgument("N12345"); + e.assertRedactedArgument("ABCDEF"); + e.assertUnredacted("N4711"); + // Tests that only fully matched filters are redacted + Execution f = run( + "-XX:FlightRecorderOptions:redact-argument=-*TIGER* *", + "--TIGER" + ); + f.assertUnredacted("--TIGER"); + } + + private static void testBinary() throws Exception { + Execution unredacted = run( + Map.of("stuff1", "hammock"), + Map.of("stuff2", "haberdashery"), + "-XX:FlightRecorderOptions:stackdepth=64", + "hammock" + ); + if (!contains(unredacted.file, "hammock")) { + throw new Exception("Expected 'hammock' to be in recording file"); + } + if (!contains(unredacted.file, "haberdashery")) { + throw new Exception("Expected 'haberdashery' to be in recording file"); + } + + Execution redacted = run( + Map.of("what", "zippers"), + Map.of("where", "haberdashery"), + "-XX:FlightRecorderOptions:redact-argument=zippers,redact-key=what;where", + "zippers" + ); + if (contains(redacted.file, "zippers")) { + redacted.print(); + throw new Exception("Expected all occurrences of 'zippers' to be redacted"); + } + if (contains(redacted.file, "haberdashery")) { + redacted.print(); + throw new Exception("Expected all occurrences of 'haberdashery' to be redacted"); + } + } + + private static boolean contains(Path file, String text) throws IOException { + byte[] bytes = Files.readAllBytes(file); + byte[] chars = text.getBytes(StandardCharsets.UTF_8); + for (int i = 0; i <= bytes.length - chars.length; i++) { + if (matchesAt(bytes, chars, i)) { + System.out.print("Found '" + text + "' at position " + i); + System.out.println(" in file " + file.toAbsolutePath()); + return true; + } + } + return false; + } + + private static boolean matchesAt(byte[] bytes, byte[] chars, int position) { + for (int j = 0; j < chars.length; j++) { + if (bytes[position + j] != chars[j]) { + return false; + } + } + return true; + } + + private static void testRedactFile() throws Exception { + Execution e1 = run( + Map.of("stuff1", "Snake"), + Map.of("stuff2", "Snake"), + "-XX:FlightRecorderOptions:redact-argument=@" + FILE_REDACTED_ARGUMENTS, + "https://John:Smith@www.example.com/myresource", + "-conf-Key=chicken", + "/Foo/Dog", + "-Header", "Authorization:Bearer", "Banana", + "Apple"); + e1.assertRedactedArgument("https://John:Smith@www.example.com/myresource"); + e1.assertRedactedArgument("conf-Key=chicken"); + e1.assertRedactedArgument("/Foo/Dog"); + e1.assertRedactedArgument("-Header"); + e1.assertRedactedArgument("Authorization:Bearer"); + e1.assertRedactedArgument("Banana"); + e1.assertRedactedArgument("Apple"); + e1.assertUnredacted("Snake"); + + Execution e2 = run( + Map.of("confidential", "apple"), + Map.of("very-sensitive", "banana"), + "-XX:FlightRecorderOptions:redact-key=@" + FILE_REDACTED_KEYS, + "Snake"); + e2.assertRedactedKey("confidential"); + e2.assertRedactedKey("very-sensitive"); + e2.assertUnredacted("Snake"); + } + + private static void testEmpty() throws Exception { + var environment = Map.of("API_TOKEN", "Zebra1"); + var properties = Map.of("API_KEY", "Zebra2"); + Execution e1 = run(environment, properties, + "-XX:FlightRecorderOptions:redact-key=,redact-argument=", "Zebra3" + ); + e1.output().shouldContain("Default redaction filters are replaced."); + e1.output().shouldContain("redact-key=none to disable filters without a warning"); + e1.output().shouldContain("redact-argument=none to disable filters without a warning"); + e1.assertUnredacted("Zebra1"); + e1.assertUnredacted("Zebra2"); + e1.assertUnredacted("Zebra3"); + + Execution e2 = run(environment, properties, + "-XX:FlightRecorderOptions:redact-argument=none,redact-key=none", "Zebra3" + ); + e2.output().shouldNotContain("Default redaction filters are replaced."); + e2.output().shouldNotContain("redact-key=none to disable filters without a warning"); + e2.output().shouldNotContain("redact-argument=none to disable filters without a warning"); + e2.assertUnredacted("Zebra1"); + e2.assertUnredacted("Zebra2"); + e2.assertUnredacted("Zebra3"); + } + + private static void testDefaults() throws Exception { + Execution e = run( + Map.of("apiKey","thing"), + Map.of("apiKey", "stuff"), + "-DapiKey=stuff", + "Secret", + "-password=Foo" + ); + e.assertRedactedArgument("Secret"); + e.assertRedactedArgument("-password=Foo"); + e.assertRedactedKey("apiKey"); + } + + private static void testRedactArgument() throws Exception { + Execution e = run( + "-XX:FlightRecorderOptions:redact-argument=" + + // FILTERS + "Plain;" + + "--option *;" + + "--pass-phrase *;" + + "--login * *;" + + "--colon-based:*;" + + "https://*:*@*", + // SENSITIVE INFORMATION + "Plain", + "--option", "Option-value", + "--pass-phrase", "Cant-be-whitespace-outage", + "--login", "John", "N4711", + "--colon-based:Hello", + "https://Smith:abc123@example.com/path", + // UNSENSITIVE INFORMATION + "Banana" + ); + e.assertRedactedArgument("Plain"); + e.assertRedactedArgument("Option-value"); + e.assertRedactedArgument("Cant-be-whitespace-outage"); + e.assertRedactedArgument("Hello"); + e.assertRedactedArgument("John"); + e.assertRedactedArgument("N4711"); + e.assertRedactedArgument("Smith:abc123"); + e.assertUnredacted("Banana"); + } + + private static void testRedactMultiple() throws Exception { + Execution e = run( + Map.of("foo", "bird", "bar, ", "orange"), + Map.of("foo", "tiger", "bar", "banana"), + "-XX:FlightRecorderOptions:redact-key=foo;bar,redact-argument=Baz;Quz", "Baz", "Quz"); + e.assertRedactedKey("foo"); + e.assertRedactedKey("bar"); + e.assertRedactedArgument("Baz"); + e.assertRedactedArgument("Quz"); + } + + private static void testRedactKey() throws Exception { + Execution e = run( + Map.of("cart", "wheel", "banana", "split", "rose", "bud"), + Map.of("banana", "split", "cat", "milk", "carpet","magic", "rose", "bud"), + "-XX:FlightRecorderOptions:redact-key=banana;ca*t", + "rose" + ); + e.assertRedactedKey("banana"); + e.assertRedactedKey("cat"); + e.assertRedactedKey("carpet"); + e.assertUnredacted("rose"); + } + + private static Execution run(String options, String... args) throws Exception { + return run(Map.of(), Map.of(), options, args); + } + + private static Execution run(Map environment, Map properties, String options, String... args) throws Exception { + List arguments = new ArrayList<>(); + Path file = Path.of("file.jfr"); + for (var entry : properties.entrySet()) { + arguments.add("-D" + entry.getKey() + "=" + entry.getValue()); + } + arguments.add("-XX:StartFlightRecording:filename=" + file.toAbsolutePath().toString()); + arguments.add(options); + arguments.add("jdk.jfr.startupargs.Application"); + arguments.addAll(Arrays.asList(args)); + + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(arguments); + pb.environment().put("env.secret", "confidential"); + // An environment variable redacted by default filters + pb.environment().putAll(environment); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + System.out.println(output.getOutput()); + output.shouldHaveExitValue(0); + var environmentVariables = new HashMap(); + var systemProperties = new HashMap(); + var stringFlags = new HashMap(); + var jvmArgs = new AtomicReference(); + var jvmFlags= new AtomicReference(); + var javaArgs = new AtomicReference(); + try (var es = EventStream.openFile(file)) { + es.onEvent("jdk.InitialSystemProperty", e -> { + systemProperties.put(e.getString("key"), e.getString("value")); + }); + es.onEvent("jdk.InitialEnvironmentVariable", e -> { + environmentVariables.put(e.getString("key"), e.getString("value")); + }); + es.onEvent("jdk.JVMInformation", e -> { + jvmArgs.set(e.getString("jvmArguments")); + javaArgs.set(e.getString("javaArguments")); + jvmFlags.set(e.getString("jvmFlags")); + }); + es.onEvent("jdk.StringFlag", e -> { + stringFlags.put(e.getString("name"), e.getString("value")); + }); + es.start(); + } + return new Execution(file, + jvmArgs.get(), jvmFlags.get(), javaArgs.get(), + environmentVariables, systemProperties, stringFlags, output); + } +} diff --git a/test/jdk/jdk/jfr/startupargs/redacted-arguments.txt b/test/jdk/jdk/jfr/startupargs/redacted-arguments.txt new file mode 100644 index 00000000000..8f7ffb22569 --- /dev/null +++ b/test/jdk/jdk/jfr/startupargs/redacted-arguments.txt @@ -0,0 +1,6 @@ +https://*:*@* +apple +-conf-key=* +/foo/* +--passphrase * +-header Authorization:Bearer * diff --git a/test/jdk/jdk/jfr/startupargs/redacted-keys.txt b/test/jdk/jdk/jfr/startupargs/redacted-keys.txt new file mode 100644 index 00000000000..b63aa66cc70 --- /dev/null +++ b/test/jdk/jdk/jfr/startupargs/redacted-keys.txt @@ -0,0 +1,2 @@ +*sensitive +confidential From 2688bf7305ff323e02636bfcc37497ebd1563ab5 Mon Sep 17 00:00:00 2001 From: Vladimir Petko Date: Wed, 3 Jun 2026 06:35:57 +0000 Subject: [PATCH 039/115] 8385738: Javadoc does not produce reproducible output due to the snippet ids Reviewed-by: nbenalla --- .../formats/html/taglets/SnippetTaglet.java | 8 +- .../doclet/testSnippetTag/TestSnippetTag.java | 95 ++++++++++++++++++- 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index 38baa7b2826..b666a14fd95 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ import com.sun.source.util.DocTreePath; import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; +import jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.Action; import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.ParseException; @@ -124,7 +125,8 @@ public class SnippetTaglet extends BaseTaglet { if (id != null && !id.isBlank()) { pre.put(HtmlAttr.ID, id); } else { - pre.put(HtmlAttr.ID, config.htmlIds.forSnippet(element, ids).name()); + var set = ids.computeIfAbsent(tagletWriter.htmlWriter, _ -> new HashSet<>()); + pre.put(HtmlAttr.ID, config.htmlIds.forSnippet(element, set).name()); } var code = HtmlTree.CODE() .addUnchecked(Text.EMPTY); // Make sure the element is always rendered @@ -207,7 +209,7 @@ public class SnippetTaglet extends BaseTaglet { return snippetContainer.add(pre.add(code)); } - private final Set ids = new HashSet<>(); + private final HashMap> ids = new HashMap<>(); private static final class BadSnippetException extends Exception { diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java index 26030629738..24a7b5aa5da 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8266666 8275788 8276964 8299080 8276966 + * @bug 8266666 8275788 8276964 8299080 8276966 8385738 * @summary Implementation for snippets * @library /tools/lib ../../lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -39,6 +39,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; @@ -2685,4 +2686,94 @@ public class TestSnippetTag extends SnippetTester { """); checkNoCrashes(); } + + @Test + public void testSnippetIdCounterResetsPerPage(Path base) throws IOException { + Path src = base.resolve("src"); + + tb.writeJavaFiles(src, + """ + package p; + import java.lang.annotation.Target; + import java.lang.annotation.ElementType; + @Target({ElementType.TYPE, ElementType.METHOD}) + public @interface ACustomAnnotation { + } + """, + """ + package p; + import java.lang.annotation.Target; + import java.lang.annotation.ElementType; + @Target({ElementType.TYPE, ElementType.METHOD}) + public @interface ZCustomAnnotation { + } + """, + """ + package p; + /** Class A. */ + public class A { + /** + * First snippet on A.foo: + * {@snippet : + * int x = 1; // first + * } + * Second snippet on A.foo: + * {@snippet : + * int y = 2; // second + * } + */ + @ACustomAnnotation + @ZCustomAnnotation + public void foo() {} + } + """, + """ + package p; + /** Class B. */ + public class B { + /** + * First snippet on B.foo: + * {@snippet : + * int x = 1; // first + * } + * Second snippet on B.foo: + * {@snippet : + * int y = 2; // second + * } + */ + @ACustomAnnotation + @ZCustomAnnotation + public void foo() {} + } + """); + + javadoc("-d", base.resolve("out").toString(), + "-use", + "-sourcepath", src.toString(), + "p"); + checkExit(Exit.OK); + for (String cls : new String[] { + "A.html", + "B.html", + "class-use/ACustomAnnotation.html", + "class-use/ZCustomAnnotation.html"}) { + var file = base + .resolve("out") + .resolve("p") + .resolve(cls); + String content = Files.readString(file); + for (var snippetId : new String[] {"snippet-foo()1", "snippet-foo()2"}) { + checking("id \"" + snippetId + "\" present in " + cls); + if (content.contains("id=\"" + snippetId + "\"")) { + passed("found"); + } else { + failed("" + snippetId + " not found in " + + String.join("\n", Arrays.asList(content.split("\n")) + .stream() + .filter(l -> l.contains("pre class=\"snippet\"")) + .toList())); + } + } + } + } } From 1900d661bdf88ce9e8439ca35670087c2ceb9c72 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Wed, 3 Jun 2026 07:34:19 +0000 Subject: [PATCH 040/115] 8385312: Intermittent assert while running JCK test api/java_util/concurrent/Assorted/SynchronousQueue20.html Reviewed-by: coleenp, pchilanomate --- src/hotspot/share/runtime/continuation.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index 26d865057e6..f8af2545c37 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -153,12 +153,6 @@ freeze_result Continuation::try_preempt(JavaThread* current, oop continuation) { return res; } -#ifndef PRODUCT -static jlong java_tid(JavaThread* thread) { - return java_lang_Thread::thread_id(thread->threadObj()); -} -#endif - ContinuationEntry* Continuation::get_continuation_entry_for_continuation(JavaThread* thread, oop continuation) { if (thread == nullptr || continuation == nullptr) { return nullptr; @@ -388,9 +382,9 @@ frame Continuation::continuation_bottom_sender(JavaThread* thread, const frame& ContinuationEntry* ce = get_continuation_entry_for_sp(thread, callee.sp()); assert(ce != nullptr, "callee.sp(): " INTPTR_FORMAT, p2i(callee.sp())); - log_develop_debug(continuations)("continuation_bottom_sender: [" JLONG_FORMAT "] [%d] callee: " INTPTR_FORMAT + log_develop_debug(continuations)("continuation_bottom_sender: [" UINT64_FORMAT "] [%d] callee: " INTPTR_FORMAT " sender_sp: " INTPTR_FORMAT, - java_tid(thread), thread->osthread()->thread_id(), p2i(callee.sp()), p2i(sender_sp)); + thread->monitor_owner_id(), thread->osthread()->thread_id(), p2i(callee.sp()), p2i(sender_sp)); frame entry = ce->to_frame(); if (callee.is_interpreted_frame()) { From ec1bffd9a51ae06479a261a6a106f44866212ae7 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 3 Jun 2026 07:36:14 +0000 Subject: [PATCH 041/115] 8385702: Improve polymorphic handling in JDK-8385648 Reviewed-by: mdoerr, sviswanathan, fyang --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 31 +++++++++---------- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 18 +++++------ .../cpu/riscv/macroAssembler_riscv.cpp | 30 +++++++++--------- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 31 +++++++++---------- 4 files changed, 51 insertions(+), 59 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index ac5bae22384..eb658ba4e30 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2147,7 +2147,7 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ Register offset = rscratch2; Label L_loop_search_receiver, L_loop_search_empty; - Label L_restart, L_found_recv, L_found_empty, L_polymorphic, L_count_update; + Label L_restart, L_found_recv, L_found_empty, L_count_update; // The code here recognizes three major cases: // A. Fastest: receiver found in the table @@ -2177,21 +2177,20 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ // if (receiver(i) == recv) goto found_recv(i); // } // - // // Fast: no receiver, but profile is full + // // Fast: no receiver, but profile is not full // for (i = 0; i < receiver_count(); i++) { // if (receiver(i) == null) goto found_null(i); // } - // goto polymorphic + // + // // Slow: profile is full, polymorphic case + // count++; + // return // // // Slow: try to install receiver // found_null(i): // CAS(&receiver(i), null, recv); // goto restart // - // polymorphic: - // count++; - // return - // // found_recv(i): // *receiver_count(i)++ // @@ -2208,7 +2207,7 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ sub(rscratch1, offset, end_receiver_offset); cbnz(rscratch1, L_loop_search_receiver); - // Fast: no receiver, but profile is full + // Fast: no receiver, but profile is not full mov(offset, base_receiver_offset); bind(L_loop_search_empty); ldr(rscratch1, Address(mdp, offset)); @@ -2216,9 +2215,13 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ add(offset, offset, receiver_step); sub(rscratch1, offset, end_receiver_offset); cbnz(rscratch1, L_loop_search_empty); - b(L_polymorphic); - // Slow: try to install receiver + // Slow: Receiver is not found and table is full. + // Increment polymorphic counter instead of receiver slot. + mov(offset, poly_count_offset); + b(L_count_update); + + // Slowest: try to install receiver bind(L_found_empty); // Atomically swing receiver slot: null -> recv. @@ -2237,17 +2240,11 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ // and just restart the search from the beginning. b(L_restart); - // Counter updates: - - // Increment polymorphic counter instead of receiver slot. - bind(L_polymorphic); - mov(offset, poly_count_offset); - b(L_count_update); - // Found a receiver, convert its slot offset to corresponding count offset. bind(L_found_recv); add(offset, offset, receiver_to_count_step); + // Finally, update the counter bind(L_count_update); increment(Address(mdp, offset), DataLayout::counter_increment); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 0d6c272decb..b5bfcb0fced 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -4411,21 +4411,20 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ // if (receiver(i) == recv) goto found_recv(i); // } // - // // Fast: no receiver, but profile is full + // // Fast: no receiver, but profile is not full // for (i = 0; i < receiver_count(); i++) { // if (receiver(i) == null) goto found_null(i); // } - // goto polymorphic + // + // // Slow: profile is full, polymorphic case + // count++; + // return // // // Slow: try to install receiver // found_null(i): // CAS(&receiver(i), null, recv); // goto restart // - // polymorphic: - // count++; - // return - // // found_recv(i): // *receiver_count(i)++ // @@ -4466,11 +4465,12 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ addi(offset, offset, receiver_step); bdnz(L_loop_search_empty); - // Polymorphic: Increment polymorphic counter instead of receiver slot. + // Slow: Receiver is not found and table is full. + // Increment polymorphic counter instead of receiver slot. li(offset, poly_count_offset); b(L_count_update); - // Slow: try to install receiver + // Slowest: try to install receiver bind(L_found_empty); // Atomically swing receiver slot: null -> recv. @@ -4491,7 +4491,7 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ bind(L_found_recv); addi(offset, offset, receiver_to_count_step); - // Counter update + // Finally, update the counter bind(L_count_update); increment_mem64(mdp, offset, DataLayout::counter_increment, /* temp */ (count != noreg) ? count : recv); } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 02798d5204a..7b3e034906e 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -593,7 +593,7 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ Register offset = t1; Label L_loop_search_receiver, L_loop_search_empty; - Label L_restart, L_found_recv, L_found_empty, L_polymorphic, L_count_update; + Label L_restart, L_found_recv, L_found_empty, L_count_update; // The code here recognizes three major cases: // A. Fastest: receiver found in the table @@ -623,21 +623,20 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ // if (receiver(i) == recv) goto found_recv(i); // } // - // // Fast: no receiver, but profile is full + // // Fast: no receiver, but profile is not full // for (i = 0; i < receiver_count(); i++) { // if (receiver(i) == null) goto found_null(i); // } - // goto polymorphic + // + // // Slow: profile is full, polymorphic case + // count++; + // return // // // Slow: try to install receiver // found_null(i): // CAS(&receiver(i), null, recv); // goto restart // - // polymorphic: - // count++; - // return - // // found_recv(i): // *receiver_count(i)++ // @@ -654,7 +653,7 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ sub(t0, offset, end_receiver_offset); bnez(t0, L_loop_search_receiver); - // Fast: no receiver, but profile is full + // Fast: no receiver, but profile is not full mv(offset, base_receiver_offset); bind(L_loop_search_empty); add(t0, mdp, offset); @@ -663,9 +662,13 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ add(offset, offset, receiver_step); sub(t0, offset, end_receiver_offset); bnez(t0, L_loop_search_empty); - j(L_polymorphic); - // Slow: try to install receiver + // Slow: Receiver is not found and table is full. + // Increment polymorphic counter instead of receiver slot. + mv(offset, poly_count_offset); + j(L_count_update); + + // Slowest: try to install receiver bind(L_found_empty); // Atomically swing receiver slot: null -> recv. @@ -683,16 +686,11 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ // and just restart the search from the beginning. j(L_restart); - // Counter updates: - // Increment polymorphic counter instead of receiver slot. - bind(L_polymorphic); - mv(offset, poly_count_offset); - j(L_count_update); - // Found a receiver, convert its slot offset to corresponding count offset. bind(L_found_recv); add(offset, offset, receiver_to_count_step); + // Finally, update the counter bind(L_count_update); add(t1, mdp, offset); increment(Address(t1), DataLayout::counter_increment); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index aa2195d0256..0ac0a8243d4 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -4901,7 +4901,7 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ Register offset = rscratch1; Label L_loop_search_receiver, L_loop_search_empty; - Label L_restart, L_found_recv, L_found_empty, L_polymorphic, L_count_update; + Label L_restart, L_found_recv, L_found_empty, L_count_update; // The code here recognizes three major cases: // A. Fastest: receiver found in the table @@ -4931,21 +4931,20 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ // if (receiver(i) == recv) goto found_recv(i); // } // - // // Fast: no receiver, but profile is full + // // Fast: no receiver, but profile is not full // for (i = 0; i < receiver_count(); i++) { // if (receiver(i) == null) goto found_null(i); // } - // goto polymorphic + // + // // Slow: profile is full, polymorphic case + // count++; + // return // // // Slow: try to install receiver // found_null(i): // CAS(&receiver(i), null, recv); // goto restart // - // polymorphic: - // count++; - // return - // // found_recv(i): // *receiver_count(i)++ // @@ -4961,7 +4960,7 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ cmpptr(offset, end_receiver_offset); jccb(Assembler::notEqual, L_loop_search_receiver); - // Fast: no receiver, but profile is full + // Fast: no receiver, but profile is not full movptr(offset, base_receiver_offset); bind(L_loop_search_empty); cmpptr(Address(mdp, offset, Address::times_ptr), NULL_WORD); @@ -4969,9 +4968,13 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ addptr(offset, receiver_step); cmpptr(offset, end_receiver_offset); jccb(Assembler::notEqual, L_loop_search_empty); - jmpb(L_polymorphic); - // Slow: try to install receiver + // Slow: Receiver is not found and table is full. + // Increment polymorphic counter instead of receiver slot. + movptr(offset, poly_count_offset); + jmpb(L_count_update); + + // Slowest: try to install receiver bind(L_found_empty); // Atomically swing receiver slot: null -> recv. @@ -5023,17 +5026,11 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ // and just restart the search from the beginning. jmpb(L_restart); - // Counter updates: - - // Increment polymorphic counter instead of receiver slot. - bind(L_polymorphic); - movptr(offset, poly_count_offset); - jmpb(L_count_update); - // Found a receiver, convert its slot offset to corresponding count offset. bind(L_found_recv); addptr(offset, receiver_to_count_step); + // Finally, update the counter bind(L_count_update); addptr(Address(mdp, offset, Address::times_ptr), DataLayout::counter_increment); } From 563befb8a1a19e574e7d43068b45783ba8cb7ba3 Mon Sep 17 00:00:00 2001 From: David Briemann Date: Wed, 3 Jun 2026 10:30:43 +0000 Subject: [PATCH 042/115] 8385633: PPC64: Shenandoah weak CAS fails after late barrier expansion Reviewed-by: mdoerr, shade --- .../shenandoahBarrierSetAssembler_ppc.cpp | 26 +-- .../shenandoahBarrierSetAssembler_ppc.hpp | 4 +- .../cpu/ppc/gc/shenandoah/shenandoah_ppc.ad | 149 ++++-------------- 3 files changed, 44 insertions(+), 135 deletions(-) diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp index 9c079107e08..1f6ca4655de 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp @@ -1134,39 +1134,41 @@ void ShenandoahBarrierSetAssembler::store_c2(const MachNode* node, MacroAssemble ShenandoahBarrierStubC2::store_post(masm, node, Address(dst, disp), tmp1, tmp2); } -void ShenandoahBarrierSetAssembler::compare_and_set_c2(const MachNode* node, MacroAssembler* masm, Register res, Register addr, Register oldval, - Register newval, Register tmp1, Register tmp2, Register tmp3, bool exchange, bool narrow, bool weak, bool acquire) { +void ShenandoahBarrierSetAssembler::compare_and_set_c2(const MachNode* node, MacroAssembler* masm, Register res, Register addr, + Register oldval, Register newval, Register tmp1, Register tmp2, bool exchange, bool narrow, bool weak, bool acquire) { - ShenandoahBarrierStubC2::load_store_pre(masm, node, tmp1, addr, tmp2, tmp3, narrow); + ShenandoahBarrierStubC2::load_store_pre(masm, node, res, addr, tmp1, tmp2, narrow); - Register dest_current = exchange ? res : R0; - Register int_flag = exchange ? noreg : res; - int semantics = MacroAssembler::MemBarNone; + Register dest_current = exchange ? res : R0; + Label no_update; + int semantics = MacroAssembler::MemBarNone; if (acquire) { semantics = support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter; } + if (!exchange) { __ li(res, 0); } if (narrow) { - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgw(CR0, dest_current, oldval, newval, addr, semantics, MacroAssembler::cmpxchgx_hint_atomic_update(), - int_flag, nullptr, true, weak); + noreg, &no_update, true, weak); } else { - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgd(CR0, dest_current, oldval, newval, addr, semantics, MacroAssembler::cmpxchgx_hint_atomic_update(), - int_flag, nullptr, true, weak); + noreg, &no_update, true, weak); } + if (!exchange) { __ li(res, 1); } ShenandoahBarrierStubC2::load_store_post(masm, node, Address(addr, 0), tmp1, tmp2); + + __ bind(no_update); } -void ShenandoahBarrierSetAssembler::get_and_set_c2(const MachNode* node, MacroAssembler* masm, Register preval, Register newval, Register addr, Register tmp1, Register tmp2, Register tmp3) { +void ShenandoahBarrierSetAssembler::get_and_set_c2(const MachNode* node, MacroAssembler* masm, Register preval, Register newval, Register addr, Register tmp1, Register tmp2) { bool is_narrow = node->bottom_type()->isa_narrowoop(); - ShenandoahBarrierStubC2::load_store_pre(masm, node, tmp1, addr, tmp2, tmp3, is_narrow); + ShenandoahBarrierStubC2::load_store_pre(masm, node, preval, addr, tmp1, tmp2, is_narrow); if (is_narrow) { __ getandsetw(preval, newval, addr, MacroAssembler::cmpxchgx_hint_atomic_update()); diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp index eda3aafdb2d..5c70a308691 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.hpp @@ -140,10 +140,10 @@ public: Register dst, int disp, bool dst_narrow, Register src, bool src_narrow, Register tmp1, Register tmp2, Register tmp3); void compare_and_set_c2(const MachNode* node, MacroAssembler* masm, Register res, Register addr, Register oldval, - Register newval, Register tmp1, Register tmp2, Register tmp3, bool exchange, bool narrow, bool weak, bool acquire); + Register newval, Register tmp1, Register tmp2, bool exchange, bool narrow, bool weak, bool acquire); void get_and_set_c2(const MachNode* node, MacroAssembler* masm, - Register preval, Register newval, Register addr, Register tmp1, Register tmp2, Register tmp3); + Register preval, Register newval, Register addr, Register tmp1, Register tmp2); #endif // COMPILER2 }; diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoah_ppc.ad b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoah_ppc.ad index a75d1a03e4b..f2e5d4f3a27 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoah_ppc.ad +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoah_ppc.ad @@ -1,6 +1,6 @@ // // Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. -// Copyright (c) 2012, 2021 SAP SE. All rights reserved. +// Copyright (c) 2012, 2026 SAP SE. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -201,10 +201,12 @@ instruct encodePAndStoreN_shenandoah(memory dst, iRegPsrc src, iRegPdstNoScratch // ---------------------- LOAD-STORES ----------------------------------- // -instruct compareAndSwapN_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +// Strong CAS also handles WeakCompareAndSwap* on PPC, see JDK-8385633. +instruct compareAndSwapN_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapN mem_ptr (Binary src1 src2))); + match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2))); predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && !need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); // TEMP_DEF to avoid jump + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); // TEMP_DEF to avoid jump format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, @@ -214,7 +216,6 @@ instruct compareAndSwapN_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst mem_pt $src2$$Register, $tmp1$$Register, $tmp2$$Register, - $tmp3$$Register, /* exchange */ false, /* is_narrow */ true, /* weak */ false, @@ -223,10 +224,11 @@ instruct compareAndSwapN_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst mem_pt ins_pipe(pipe_class_default); %} -instruct compareAndSwapN_acq_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +instruct compareAndSwapN_acq_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapN mem_ptr (Binary src1 src2))); + match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2))); predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); // TEMP_DEF to avoid jump + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); // TEMP_DEF to avoid jump format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, @@ -236,7 +238,6 @@ instruct compareAndSwapN_acq_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst me $src2$$Register, $tmp1$$Register, $tmp2$$Register, - $tmp3$$Register, /* exchange */ false, /* is_narrow */ true, /* weak */ false, @@ -245,9 +246,10 @@ instruct compareAndSwapN_acq_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst me ins_pipe(pipe_class_default); %} -instruct compareAndSwapP_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +instruct compareAndSwapP_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapP mem_ptr (Binary src1 src2))); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); // TEMP_DEF to avoid jump + match(Set res (WeakCompareAndSwapP mem_ptr (Binary src1 src2))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); // TEMP_DEF to avoid jump predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && !need_acquire_load_store(n)); format %{ "CMPXCHGD $res, $mem_ptr, $src1, $src2; as bool; ptr" %} ins_encode %{ @@ -258,7 +260,6 @@ instruct compareAndSwapP_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst mem_pt $src2$$Register, $tmp1$$Register, $tmp2$$Register, - $tmp3$$Register, /* exchange */ false, /* is_narrow */ false, /* weak */ false, @@ -267,9 +268,10 @@ instruct compareAndSwapP_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst mem_pt ins_pipe(pipe_class_default); %} -instruct compareAndSwapP_acq_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +instruct compareAndSwapP_acq_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapP mem_ptr (Binary src1 src2))); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); // TEMP_DEF to avoid jump + match(Set res (WeakCompareAndSwapP mem_ptr (Binary src1 src2))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); // TEMP_DEF to avoid jump predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && need_acquire_load_store(n)); format %{ "CMPXCHGD $res, $mem_ptr, $src1, $src2; as bool; ptr" %} ins_encode %{ @@ -280,7 +282,6 @@ instruct compareAndSwapP_acq_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst me $src2$$Register, $tmp1$$Register, $tmp2$$Register, - $tmp3$$Register, /* exchange */ false, /* is_narrow */ false, /* weak */ false, @@ -289,98 +290,10 @@ instruct compareAndSwapP_acq_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst me ins_pipe(pipe_class_default); %} -instruct weakCompareAndSwapN_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2))); - predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && !need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); // TEMP_DEF to avoid jump - format %{ "weak CMPXCHGW acq $res, $mem_ptr, $src1, $src2; as bool" %} - ins_encode %{ - ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, - $res$$Register, - $mem_ptr$$Register, - $src1$$Register, - $src2$$Register, - $tmp1$$Register, - $tmp2$$Register, - $tmp3$$Register, - /* exchange */ false, - /* is_narrow */ true, - /* weak */ true, - /* acquire */ false); - %} - ins_pipe(pipe_class_default); -%} - -instruct weakCompareAndSwapN_acq_regP_regN_regN_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2))); - predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); // TEMP_DEF to avoid jump - format %{ "weak CMPXCHGW acq $res, $mem_ptr, $src1, $src2; as bool" %} - ins_encode %{ - ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, - $res$$Register, - $mem_ptr$$Register, - $src1$$Register, - $src2$$Register, - $tmp1$$Register, - $tmp2$$Register, - $tmp3$$Register, - /* exchange */ false, - /* is_narrow */ true, - /* weak */ true, - /* acquire */ true); - %} - ins_pipe(pipe_class_default); -%} - -instruct weakCompareAndSwapP_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapP mem_ptr (Binary src1 src2))); - predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && !need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); // TEMP_DEF to avoid jump - format %{ "weak CMPXCHGD $res, $mem_ptr, $src1, $src2; as bool; ptr" %} - ins_encode %{ - ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, - $res$$Register, - $mem_ptr$$Register, - $src1$$Register, - $src2$$Register, - $tmp1$$Register, - $tmp2$$Register, - $tmp3$$Register, - /* exchange */ false, - /* is_narrow */ false, - /* weak */ true, - /* acquire */ false); - %} - ins_pipe(pipe_class_default); -%} - -instruct weakCompareAndSwapP_acq_regP_regP_regP_shenandoah(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapP mem_ptr (Binary src1 src2))); - predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); // TEMP_DEF to avoid jump - format %{ "weak CMPXCHGD $res, $mem_ptr, $src1, $src2; as bool; ptr" %} - ins_encode %{ - ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, - $res$$Register, - $mem_ptr$$Register, - $src1$$Register, - $src2$$Register, - $tmp1$$Register, - $tmp2$$Register, - $tmp3$$Register, - /* exchange */ false, - /* is_narrow */ false, - /* weak */ true, - /* acquire */ true); - %} - ins_pipe(pipe_class_default); -%} - -instruct compareAndExchangeN_regP_regN_regN_shenandoah(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +instruct compareAndExchangeN_regP_regN_regN_shenandoah(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeN mem_ptr (Binary src1 src2))); predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && !need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as narrow oop" %} ins_encode %{ ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, @@ -390,7 +303,6 @@ instruct compareAndExchangeN_regP_regN_regN_shenandoah(iRegNdst res, iRegPdst me $src2$$Register, $tmp1$$Register, $tmp2$$Register, - $tmp3$$Register, /* exchange */ true, /* is_narrow */ true, /* weak */ false, @@ -399,10 +311,10 @@ instruct compareAndExchangeN_regP_regN_regN_shenandoah(iRegNdst res, iRegPdst me ins_pipe(pipe_class_default); %} -instruct compareAndExchangeN_acq_regP_regN_regN_shenandoah(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +instruct compareAndExchangeN_acq_regP_regN_regN_shenandoah(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeN mem_ptr (Binary src1 src2))); predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as narrow oop" %} ins_encode %{ ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, @@ -412,7 +324,6 @@ instruct compareAndExchangeN_acq_regP_regN_regN_shenandoah(iRegNdst res, iRegPds $src2$$Register, $tmp1$$Register, $tmp2$$Register, - $tmp3$$Register, /* exchange */ true, /* is_narrow */ true, /* weak */ false, @@ -421,10 +332,10 @@ instruct compareAndExchangeN_acq_regP_regN_regN_shenandoah(iRegNdst res, iRegPds ins_pipe(pipe_class_default); %} -instruct compareAndExchangeP_regP_regP_regP_shenandoah(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +instruct compareAndExchangeP_regP_regP_regP_shenandoah(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeP mem_ptr (Binary src1 src2))); predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && !need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); format %{ "CMPXCHGD $res, $mem_ptr, $src1, $src2; as ptr; ptr" %} ins_encode %{ ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, @@ -434,7 +345,6 @@ instruct compareAndExchangeP_regP_regP_regP_shenandoah(iRegPdst res, iRegPdst me $src2$$Register, $tmp1$$Register, $tmp2$$Register, - $tmp3$$Register, /* exchange */ true, /* is_narrow */ false, /* weak */ false, @@ -443,10 +353,10 @@ instruct compareAndExchangeP_regP_regP_regP_shenandoah(iRegPdst res, iRegPdst me ins_pipe(pipe_class_default); %} -instruct compareAndExchangeP_acq_regP_regP_regP_shenandoah(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +instruct compareAndExchangeP_acq_regP_regP_regP_shenandoah(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeP mem_ptr (Binary src1 src2))); predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0) && need_acquire_load_store(n)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); format %{ "CMPXCHGD $res, $mem_ptr, $src1, $src2; as ptr; ptr" %} ins_encode %{ ShenandoahBarrierSet::assembler()->compare_and_set_c2(this, masm, @@ -456,7 +366,6 @@ instruct compareAndExchangeP_acq_regP_regP_regP_shenandoah(iRegPdst res, iRegPds $src2$$Register, $tmp1$$Register, $tmp2$$Register, - $tmp3$$Register, /* exchange */ true, /* is_narrow */ false, /* weak */ false, @@ -465,10 +374,10 @@ instruct compareAndExchangeP_acq_regP_regP_regP_shenandoah(iRegPdst res, iRegPds ins_pipe(pipe_class_default); %} -instruct getAndSetP_shenandoah(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +instruct getAndSetP_shenandoah(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (GetAndSetP mem_ptr src)); predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); format %{ "GetAndSetP $res, $mem_ptr, $src" %} ins_encode %{ ShenandoahBarrierSet::assembler()->get_and_set_c2(this, masm, @@ -476,16 +385,15 @@ instruct getAndSetP_shenandoah(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src, iRe $src$$Register, $mem_ptr$$Register, $tmp1$$Register, - $tmp2$$Register, - $tmp3$$Register); + $tmp2$$Register); %} ins_pipe(pipe_class_default); %} -instruct getAndSetN_shenandoah(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, iRegPdstNoScratch tmp3, flagsRegCR0 cr0) %{ +instruct getAndSetN_shenandoah(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src, iRegPdstNoScratch tmp1, iRegPdstNoScratch tmp2, flagsRegCR0 cr0) %{ match(Set res (GetAndSetN mem_ptr src)); predicate(UseShenandoahGC && (n->as_LoadStore()->barrier_data() != 0)); - effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); format %{ "GetAndSetN $res, $mem_ptr, $src" %} ins_encode %{ ShenandoahBarrierSet::assembler()->get_and_set_c2(this, masm, @@ -493,8 +401,7 @@ instruct getAndSetN_shenandoah(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src, iRe $src$$Register, $mem_ptr$$Register, $tmp1$$Register, - $tmp2$$Register, - $tmp3$$Register); + $tmp2$$Register); %} ins_pipe(pipe_class_default); %} From 2352da05efa66e29a0f041290cb841b483ae72d8 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Wed, 3 Jun 2026 10:42:38 +0000 Subject: [PATCH 043/115] 8385836: Update comment in SourceVersion for language evolution history for changes in 27 Reviewed-by: darcy, iris --- .../share/classes/javax/lang/model/SourceVersion.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java index 2835143dc4e..a5d3a523434 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,8 @@ public enum SourceVersion { * third preview) * 26: no changes (primitive Types in Patterns, instanceof, and * switch in fourth preview) - * 27: tbd + * 27: no changes (primitive Types in Patterns, instanceof, and + * switch in fifth preview) */ /** From a29ef339f218217b017197900652c6b6759df77e Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 3 Jun 2026 10:43:10 +0000 Subject: [PATCH 044/115] 8382249: G1: Racy concurrent update of young gen size and revising young gen length Reviewed-by: iwalulya, aboldtch --- src/hotspot/share/gc/g1/g1Policy.cpp | 46 +++++++++++++++------ src/hotspot/share/gc/g1/g1Policy.hpp | 16 ++++--- src/hotspot/share/gc/g1/g1YoungGenSizer.cpp | 26 ++++++------ src/hotspot/share/gc/g1/g1YoungGenSizer.hpp | 11 ++--- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index f9e084248b9..71a482e2505 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -160,7 +160,7 @@ void G1Policy::record_new_heap_size(uint new_number_of_regions) { double reserve_regions_d = (double) new_number_of_regions * _reserve_factor; // We use ceiling so that if reserve_regions_d is > 0.0 (but // smaller than 1.0) we'll get 1. - _reserve_regions = (uint) ceil(reserve_regions_d); + _reserve_regions.store_relaxed((uint) ceil(reserve_regions_d)); _young_gen_sizer.heap_size_changed(new_number_of_regions); @@ -186,8 +186,22 @@ void G1Policy::update_young_length_bounds() { void G1Policy::update_young_length_bounds(size_t pending_cards, size_t card_rs_length, size_t code_root_rs_length) { uint old_young_list_target_length = young_list_target_length(); - uint new_young_list_desired_length = calculate_young_desired_length(pending_cards, card_rs_length, code_root_rs_length); - uint new_young_list_target_length = calculate_young_target_length(new_young_list_desired_length); + uint min_young_length_by_sizer = _young_gen_sizer.min_desired_young_length(); + uint max_young_length_by_sizer = _young_gen_sizer.max_desired_young_length(); + + if (max_young_length_by_sizer < min_young_length_by_sizer) { + // This can happen due to races with heap_size_changed() at mutator time. Do not update the young gen + // lengths. Will be updated on the next regular call anyway. + assert(!SafepointSynchronize::is_at_safepoint(), "must be"); + return; + } + + uint new_young_list_desired_length = calculate_young_desired_length(pending_cards, + card_rs_length, + code_root_rs_length, + min_young_length_by_sizer, + max_young_length_by_sizer); + uint new_young_list_target_length = calculate_young_target_length(new_young_list_desired_length, min_young_length_by_sizer); log_trace(gc, ergo, heap)("Young list length update: pending cards %zu card_rs_length %zu old target %u desired: %u target: %u", pending_cards, @@ -224,9 +238,9 @@ void G1Policy::update_young_length_bounds(size_t pending_cards, size_t card_rs_l // uint G1Policy::calculate_young_desired_length(size_t pending_cards, size_t card_rs_length, - size_t code_root_rs_length) const { - uint min_young_length_by_sizer = _young_gen_sizer.min_desired_young_length(); - uint max_young_length_by_sizer = _young_gen_sizer.max_desired_young_length(); + size_t code_root_rs_length, + uint min_young_length_by_sizer, + uint max_young_length_by_sizer) const { assert(min_young_length_by_sizer >= 1, "invariant"); assert(max_young_length_by_sizer >= min_young_length_by_sizer, "invariant"); @@ -302,7 +316,7 @@ uint G1Policy::calculate_young_desired_length(size_t pending_cards, // Limit the desired (wished) young length by current free regions. If the request // can be satisfied without using up reserve regions, do so, otherwise eat into // the reserve, giving away at most what the heap sizer allows. -uint G1Policy::calculate_young_target_length(uint desired_young_length) const { +uint G1Policy::calculate_young_target_length(uint desired_young_length, uint min_young_length_by_sizer) const { uint allocated_young_length = _g1h->young_regions_count(); uint receiving_additional_eden; @@ -319,8 +333,14 @@ uint G1Policy::calculate_young_target_length(uint desired_young_length) const { // do, we at most eat the sizer's minimum regions into the reserve or half the // reserve rounded up (if possible; this is an arbitrary value). - uint max_to_eat_into_reserve = MIN2(_young_gen_sizer.min_desired_young_length(), - (_reserve_regions + 1) / 2); + // The heap reserve needs to be snapshotted for consistent use in the following. + // It can be concurrently modified by the mutator as it expands the heap. It can + // only increase at that time, so this is a conservative snapshot. So at worst this + // method will return a too small young gen length in that case. + uint reserve_regions = _reserve_regions.load_relaxed(); + + uint max_to_eat_into_reserve = MIN2(min_young_length_by_sizer, + (reserve_regions + 1) / 2); log_trace(gc, ergo, heap)("Young target length: Common " "free regions at end of collection %u " @@ -329,14 +349,14 @@ uint G1Policy::calculate_young_target_length(uint desired_young_length) const { "max to eat into reserve %u", _free_regions_at_end_of_collection, desired_young_length, - _reserve_regions, + reserve_regions, max_to_eat_into_reserve); uint survivor_regions_count = _g1h->survivor_regions_count(); uint desired_eden_length = desired_young_length - survivor_regions_count; uint allocated_eden_length = allocated_young_length - survivor_regions_count; - if (_free_regions_at_end_of_collection <= _reserve_regions) { + if (_free_regions_at_end_of_collection <= reserve_regions) { // Fully eat (or already eating) into the reserve, hand back at most absolute_min_length regions. uint receiving_eden = MIN3(_free_regions_at_end_of_collection, desired_eden_length, @@ -351,9 +371,9 @@ uint G1Policy::calculate_young_target_length(uint desired_young_length) const { log_trace(gc, ergo, heap)("Young target length: Fully eat into reserve " "receiving eden %u receiving additional eden %u", receiving_eden, receiving_additional_eden); - } else if (_free_regions_at_end_of_collection < (desired_eden_length + _reserve_regions)) { + } else if (_free_regions_at_end_of_collection < (desired_eden_length + reserve_regions)) { // Partially eat into the reserve, at most max_to_eat_into_reserve regions. - uint free_outside_reserve = _free_regions_at_end_of_collection - _reserve_regions; + uint free_outside_reserve = _free_regions_at_end_of_collection - reserve_regions; assert(free_outside_reserve < desired_eden_length, "must be %u %u", free_outside_reserve, desired_eden_length); diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 45952963168..0a472dd0527 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -91,9 +91,11 @@ class G1Policy: public CHeapObj { G1SurvRateGroup* _survivor_surv_rate_group; double _reserve_factor; - // This will be set when the heap is expanded - // for the first time during initialization. - uint _reserve_regions; + // The allocation reserve in number of regions that we try to keep free. + // G1 allocation of new regions for eden is restrained when allocating into that reserve. + // This intentionally slows down the allocation when the heap is close to full to allow + // concurrent marking to finish and hopefully avoid a Full GC. + Atomic _reserve_regions; G1YoungGenSizer _young_gen_sizer; @@ -224,9 +226,13 @@ private: // Calculate desired young length based on current situation without taking actually // available free regions into account. - uint calculate_young_desired_length(size_t pending_cards, size_t card_rs_length, size_t code_root_rs_length) const; + uint calculate_young_desired_length(size_t pending_cards, + size_t card_rs_length, + size_t code_root_rs_length, + uint min_young_length_by_sizer, + uint max_young_length_by_sizer) const; // Limit the given desired young length to available free regions. - uint calculate_young_target_length(uint desired_young_length) const; + uint calculate_young_target_length(uint desired_young_length, uint min_young_length_by_sizer) const; double predict_survivor_regions_evac_time() const; double predict_retained_regions_evac_time() const; diff --git a/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp b/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp index ffa573c68cc..60c79ec28df 100644 --- a/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ #include "runtime/globals_extension.hpp" G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), - _use_adaptive_sizing(true), _min_desired_young_length(0), _max_desired_young_length(0) { + _use_adaptive_sizing(true), _min_desired_young_length(), _max_desired_young_length(0) { precond(!FLAG_IS_ERGO(NewRatio)); precond(!FLAG_IS_ERGO(NewSize)); @@ -100,16 +100,16 @@ G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), } if (user_specified_NewSize) { - _min_desired_young_length = MAX2((uint)(NewSize / G1HeapRegion::GrainBytes), 1U); + _min_desired_young_length.store_relaxed(MAX2((uint)(NewSize / G1HeapRegion::GrainBytes), 1U)); } if (user_specified_MaxNewSize) { - _max_desired_young_length = MAX2((uint)(MaxNewSize / G1HeapRegion::GrainBytes), 1U); + _max_desired_young_length.store_relaxed(MAX2((uint)(MaxNewSize / G1HeapRegion::GrainBytes), 1U)); } if (user_specified_NewSize && user_specified_MaxNewSize) { _sizer_kind = SizerMaxAndNewSize; - _use_adaptive_sizing = _min_desired_young_length != _max_desired_young_length; + _use_adaptive_sizing = min_desired_young_length() != max_desired_young_length(); } else if (user_specified_NewSize) { _sizer_kind = SizerNewSizeOnly; } else { @@ -159,20 +159,22 @@ void G1YoungGenSizer::recalculate_min_max_young_length(uint number_of_heap_regio } void G1YoungGenSizer::adjust_max_new_size(uint number_of_heap_regions) { - // We need to pass the desired values because recalculation may not update these // values in some cases. - uint temp = _min_desired_young_length; - uint result = _max_desired_young_length; - recalculate_min_max_young_length(number_of_heap_regions, &temp, &result); + uint unused_new_min = min_desired_young_length(); + uint new_max = max_desired_young_length(); + recalculate_min_max_young_length(number_of_heap_regions, &unused_new_min, &new_max); - size_t max_young_size = result * G1HeapRegion::GrainBytes; + size_t max_young_size = new_max * G1HeapRegion::GrainBytes; if (max_young_size != MaxNewSize) { FLAG_SET_ERGO(MaxNewSize, max_young_size); } } void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) { - recalculate_min_max_young_length(new_number_of_heap_regions, &_min_desired_young_length, - &_max_desired_young_length); + uint min = min_desired_young_length(); + uint max = max_desired_young_length(); + recalculate_min_max_young_length(new_number_of_heap_regions, &min, &max); + _min_desired_young_length.store_relaxed(min); + _max_desired_young_length.store_relaxed(max); } diff --git a/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp b/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp index 138989d4d94..c60c3c373a9 100644 --- a/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp +++ b/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef SHARE_GC_G1_G1YOUNGGENSIZER_HPP #define SHARE_GC_G1_G1YOUNGGENSIZER_HPP +#include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" // There are three command line options related to the young gen size: @@ -78,8 +79,8 @@ private: // true otherwise. bool _use_adaptive_sizing; - uint _min_desired_young_length; - uint _max_desired_young_length; + Atomic _min_desired_young_length; + Atomic _max_desired_young_length; uint calculate_default_min_length(uint new_number_of_heap_regions); uint calculate_default_max_length(uint new_number_of_heap_regions); @@ -96,10 +97,10 @@ public: virtual void heap_size_changed(uint new_number_of_heap_regions); uint min_desired_young_length() const { - return _min_desired_young_length; + return _min_desired_young_length.load_relaxed(); } uint max_desired_young_length() const { - return _max_desired_young_length; + return _max_desired_young_length.load_relaxed(); } bool use_adaptive_young_list_length() const { From bf14f24f76fee928f9911b07b0676731fc47417c Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Wed, 3 Jun 2026 12:28:18 +0000 Subject: [PATCH 045/115] 8385013: Startup regression ~30% / 7-10ms with noop Reviewed-by: liach --- .../jdk/internal/lang/LazyConstantImpl.java | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/lang/LazyConstantImpl.java b/src/java.base/share/classes/jdk/internal/lang/LazyConstantImpl.java index e5a1dd62c11..2031789892c 100644 --- a/src/java.base/share/classes/jdk/internal/lang/LazyConstantImpl.java +++ b/src/java.base/share/classes/jdk/internal/lang/LazyConstantImpl.java @@ -27,6 +27,7 @@ package jdk.internal.lang; import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.AOTSafeClassInitializer; +import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; @@ -84,35 +85,35 @@ public final class LazyConstantImpl implements LazyConstant { return (t != null) ? t : getSlowPath(); } - @SuppressWarnings("unchecked") + @DontInline private T getSlowPath() { preventReentry(); synchronized (this) { T t = getAcquire(); if (t == null) { - switch (computingFunctionOrExceptionType) { - case Supplier computingFunction -> { - try { - @SuppressWarnings("unchecked") - final T newT = (T) computingFunction.get(); - t = newT; - Objects.requireNonNull(t); - setRelease(t); - // Allow the underlying supplier to be collected after - // a successful initialization - computingFunctionOrExceptionType = null; - } catch (Throwable ex) { - // Release the original computing function and replace it with - // an exception marker - final String exceptionType = ex.getClass().getName().intern(); - computingFunctionOrExceptionType = exceptionType; - throw unableToAccessConstant(exceptionType, ex); - } + final Object cf = computingFunctionOrExceptionType; + // Don't use pattern matching here in order to improve startup time. + if (cf instanceof Supplier computingFunction) { + try { + @SuppressWarnings("unchecked") + final T newT = (T) computingFunction.get(); + t = newT; + Objects.requireNonNull(t); + setRelease(t); + // Allow the underlying supplier to be collected after + // a successful initialization + computingFunctionOrExceptionType = null; + } catch (Throwable ex) { + // Release the original computing function and replace it with + // an exception marker + final String exceptionType = ex.getClass().getName().intern(); + computingFunctionOrExceptionType = exceptionType; + throw unableToAccessConstant(exceptionType, ex); } - case String exceptionType -> - throw unableToAccessConstant(exceptionType, null); - default -> - throw new InternalError("Cannot reach here"); + } else if (cf instanceof String exceptionType) { + throw unableToAccessConstant(exceptionType, null); + } else { + throw new InternalError("Cannot reach here"); } } return t; From 15726f9b6c93f4e1707a589901b42b376c9ca82e Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Wed, 3 Jun 2026 13:45:26 +0000 Subject: [PATCH 046/115] 8384182: Incorrect assertion eq4a_state in vectorization AlignmentSolver::solve Reviewed-by: chagedorn, snatarajan --- src/hotspot/share/opto/vectorization.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 8e0ca927a16..96ac4d78dcd 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -1744,8 +1744,8 @@ AlignmentSolution* AlignmentSolver::solve() const { // And since abs(C_pre) < aw, the solutions of (4a, b, c) can now only be constrained or empty. // But since we already handled the empty case, the solutions are now all constrained. assert(eq4a_state == EQ4::State::CONSTRAINED && - eq4a_state == EQ4::State::CONSTRAINED && - eq4a_state == EQ4::State::CONSTRAINED, "all must be constrained now"); + eq4b_state == EQ4::State::CONSTRAINED && + eq4c_state == EQ4::State::CONSTRAINED, "all must be constrained now"); // And since they are all constrained, we must have: // From d3483a98d4fd0763e0e7d6b24737830b2f1b1934 Mon Sep 17 00:00:00 2001 From: Derek White Date: Wed, 3 Jun 2026 13:56:28 +0000 Subject: [PATCH 047/115] 8385831: Prevent APX instruction being generated on non-APX machines Reviewed-by: sviswanathan, shade --- src/hotspot/cpu/x86/x86.ad | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index ab39692b44b..b3dd1a0812b 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -13959,6 +13959,7 @@ instruct orL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) // Use any_RegP to match R15 (TLS register) without spilling. instruct orL_rReg_castP2X(rRegL dst, any_RegP src, rFlagsReg cr) %{ + predicate(!UseAPX); match(Set dst (OrL dst (CastP2X src))); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); @@ -13971,6 +13972,7 @@ instruct orL_rReg_castP2X(rRegL dst, any_RegP src, rFlagsReg cr) %{ %} instruct orL_rReg_castP2X_ndd(rRegL dst, any_RegP src1, any_RegP src2, rFlagsReg cr) %{ + predicate(UseAPX); match(Set dst (OrL src1 (CastP2X src2))); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); From 85db081db4389cc0c1c75bf93fcd3db843ea1f31 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 3 Jun 2026 14:04:11 +0000 Subject: [PATCH 048/115] 8379846: G1: IHOP Allocation rate calculation too sensitive to outliers causing endless concurrent cycles Co-authored-by: Thomas Schatzl Reviewed-by: tschatzl, aboldtch --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 4 +- .../share/gc/g1/g1ConcurrentCycleTracker.cpp | 131 +++ .../share/gc/g1/g1ConcurrentCycleTracker.hpp | 111 ++ .../g1ConcurrentStartToMixedTimeTracker.hpp | 89 -- src/hotspot/share/gc/g1/g1IHOPControl.cpp | 136 +-- src/hotspot/share/gc/g1/g1IHOPControl.hpp | 45 +- .../share/gc/g1/g1OldGenAllocationTracker.cpp | 51 +- .../share/gc/g1/g1OldGenAllocationTracker.hpp | 81 +- src/hotspot/share/gc/g1/g1Policy.cpp | 126 +-- src/hotspot/share/gc/g1/g1Policy.hpp | 17 +- src/hotspot/share/gc/g1/g1Trace.cpp | 43 +- src/hotspot/share/gc/g1/g1Trace.hpp | 21 +- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 10 +- src/hotspot/share/jfr/metadata/metadata.xml | 16 +- .../gtest/gc/g1/test_g1IHOPControl.cpp | 961 ++++++++++++++---- .../jtreg/gc/g1/ihop/lib/IhopUtils.java | 6 +- .../jfr/event/metadata/TestEventMetadata.java | 4 +- 17 files changed, 1301 insertions(+), 551 deletions(-) create mode 100644 src/hotspot/share/gc/g1/g1ConcurrentCycleTracker.cpp create mode 100644 src/hotspot/share/gc/g1/g1ConcurrentCycleTracker.hpp delete mode 100644 src/hotspot/share/gc/g1/g1ConcurrentStartToMixedTimeTracker.hpp diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index d0e549c9b11..8ea880c820f 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -729,7 +729,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) { result = humongous_obj_allocate(word_size); if (result != nullptr) { policy()->old_gen_alloc_tracker()-> - add_allocated_humongous_bytes_since_last_gc(humongous_byte_size); + add_allocated_humongous_bytes(humongous_byte_size); return result; } @@ -2861,7 +2861,7 @@ void G1CollectedHeap::record_obj_copy_mem_stats() { G1ReservePercent); policy()->old_gen_alloc_tracker()-> - add_allocated_bytes_since_last_gc(total_old_allocated * HeapWordSize); + add_allocated_non_humongous_bytes(total_old_allocated * HeapWordSize); _gc_tracer_stw->report_evacuation_statistics(create_g1_evac_summary(&_survivor_evac_stats), create_g1_evac_summary(&_old_evac_stats)); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentCycleTracker.cpp b/src/hotspot/share/gc/g1/g1ConcurrentCycleTracker.cpp new file mode 100644 index 00000000000..ab43a693a60 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1ConcurrentCycleTracker.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "gc/g1/g1ConcurrentCycleTracker.hpp" +#include "gc/g1/g1OldGenAllocationTracker.hpp" +#include "utilities/checkedCast.hpp" +#include "utilities/debug.hpp" + +void G1ConcurrentCycleTracker::reset() { + _state = CycleState::Inactive; + _total_pause_time_s = 0.0; + _cycle_start_time_s = 0.0; + _cycle_end_time_s = 0.0; + + _humongous_bytes_at_start = 0; + _non_humongous_allocated_bytes = 0; + _peak_extra_humongous_occupancy_bytes = 0; +} + +void G1ConcurrentCycleTracker::update_allocation_stats(G1AllocationIntervalStats interval_stats) { + if (!is_active()) { + return; + } + + _non_humongous_allocated_bytes += interval_stats._non_humongous_allocated_bytes; + + intptr_t delta_before = checked_cast(interval_stats._total_humongous_before_bytes) - + checked_cast(_humongous_bytes_at_start); + + intptr_t delta_after = delta_before + + checked_cast(interval_stats._humongous_allocated_bytes); + + if (delta_after > 0) { + _peak_extra_humongous_occupancy_bytes = MAX2(_peak_extra_humongous_occupancy_bytes, checked_cast(delta_after)); + } +} + +G1ConcurrentCycleTracker::G1ConcurrentCycleTracker() +: _state(CycleState::Inactive), + _cycle_start_time_s(0.0), + _cycle_end_time_s(0.0), + _total_pause_time_s(0.0), + _humongous_bytes_at_start(0), + _non_humongous_allocated_bytes(0), + _peak_extra_humongous_occupancy_bytes(0) +{ } + +void G1ConcurrentCycleTracker::record_cycle_start(double cycle_start_time_s, size_t humongous_bytes_after_pause) { + assert(_state == CycleState::Inactive, "Concurrent start out of order."); + _cycle_start_time_s = cycle_start_time_s; + _humongous_bytes_at_start = humongous_bytes_after_pause; + _state = CycleState::Active; +} + +void G1ConcurrentCycleTracker::record_allocation_interval(Pause pause_type, + bool is_periodic_gc, + double pause_start_time_s, + double pause_end_time_s, + G1AllocationIntervalStats interval_stats) { + if (is_periodic_gc || pause_type == Pause::Full || pause_type == Pause::ConcurrentStartUndo) { + reset(); + return; + } + + if (pause_type == Pause::ConcurrentStartFull) { + record_cycle_start(pause_end_time_s, interval_stats._total_humongous_after_bytes); + return; + } + + if (!is_active()) { + return; + } + + update_allocation_stats(interval_stats); + + if (pause_type == Pause::Mixed) { + complete_cycle(pause_start_time_s); + return; + } + + assert(pause_type == Pause::Normal || + pause_type == Pause::PrepareMixed || + pause_type == Pause::Remark || + pause_type == Pause::Cleanup, + "Unhandled pause type"); + + add_pause(pause_end_time_s - pause_start_time_s); +} + +void G1ConcurrentCycleTracker::complete_cycle(double cycle_end_time_s) { + precond(is_active()); + + _cycle_end_time_s = cycle_end_time_s; + _state = CycleState::Complete; +} + +G1ConcurrentCycleStats G1ConcurrentCycleTracker::get_and_reset_cycle_stats() { + precond(has_completed_cycle()); + + double cycle_duration = (_cycle_end_time_s - _cycle_start_time_s - _total_pause_time_s); + + G1ConcurrentCycleStats stats{ + cycle_duration, + _non_humongous_allocated_bytes, + _peak_extra_humongous_occupancy_bytes + }; + + reset(); + return stats; +} diff --git a/src/hotspot/share/gc/g1/g1ConcurrentCycleTracker.hpp b/src/hotspot/share/gc/g1/g1ConcurrentCycleTracker.hpp new file mode 100644 index 00000000000..7d575e7abcd --- /dev/null +++ b/src/hotspot/share/gc/g1/g1ConcurrentCycleTracker.hpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_G1_G1CONCURRENTCYCLETRACKER_HPP +#define SHARE_GC_G1_G1CONCURRENTCYCLETRACKER_HPP + +#include "gc/g1/g1CollectorState.hpp" +#include "utilities/globalDefinitions.hpp" + +struct G1AllocationIntervalStats; + +// The sampling interval for G1ConcurrentCycleTracker covers the concurrent cycle +// from the end of the Concurrent Start GC to start of the first Mixed GC. +struct G1ConcurrentCycleStats { + double _cycle_duration_s; + size_t _non_humongous_allocated_bytes; + size_t _peak_extra_humongous_occupancy_bytes; + + G1ConcurrentCycleStats(double cycle_duration_s, + size_t non_humongous_allocated_bytes, + size_t peak_extra_humongous_occupancy_bytes) + : _cycle_duration_s(cycle_duration_s), + _non_humongous_allocated_bytes(non_humongous_allocated_bytes), + _peak_extra_humongous_occupancy_bytes(peak_extra_humongous_occupancy_bytes) + { } +}; + +class G1ConcurrentCycleTracker { + using Pause = G1CollectorState::Pause; + + enum class CycleState { + Inactive, + Active, + Complete, + }; + + CycleState _state; + double _cycle_start_time_s; + double _cycle_end_time_s; + double _total_pause_time_s; + + // allocation accounting + size_t _humongous_bytes_at_start; + size_t _non_humongous_allocated_bytes; + size_t _peak_extra_humongous_occupancy_bytes; + + void reset(); + + bool is_active() const { + return _state == CycleState::Active; + } + void update_allocation_stats(G1AllocationIntervalStats interval_stats); + + void add_pause(double pause_duration_s) { + _total_pause_time_s += pause_duration_s; + } + + void record_cycle_start(double cycle_start_time_s, size_t humongous_bytes_after_pause); + + void complete_cycle(double cycle_end_time_s); + + public: + G1ConcurrentCycleTracker(); + + void record_allocation_interval(Pause pause_type, + bool is_periodic_gc, + double pause_start_time_s, + double pause_end_time_s, + G1AllocationIntervalStats interval_stats); + + void abort_cycle() { + reset(); + } + + bool has_completed_cycle() const { + return _state == CycleState::Complete; + } + + size_t non_humongous_allocated_bytes() const { + return _non_humongous_allocated_bytes; + } + + size_t peak_extra_humongous_occupancy_bytes() const { + return _peak_extra_humongous_occupancy_bytes; + } + + G1ConcurrentCycleStats get_and_reset_cycle_stats(); +}; + +#endif // SHARE_GC_G1_G1CONCURRENTCYCLETRACKER_HPP diff --git a/src/hotspot/share/gc/g1/g1ConcurrentStartToMixedTimeTracker.hpp b/src/hotspot/share/gc/g1/g1ConcurrentStartToMixedTimeTracker.hpp deleted file mode 100644 index f8bad4bdcd7..00000000000 --- a/src/hotspot/share/gc/g1/g1ConcurrentStartToMixedTimeTracker.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_G1_G1CONCURRENTSTARTTOMIXEDTIMETRACKER_HPP -#define SHARE_GC_G1_G1CONCURRENTSTARTTOMIXEDTIMETRACKER_HPP - -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" - -// Used to track time from the end of concurrent start to the first mixed GC. -// After calling the concurrent start/mixed gc notifications, the result can be -// obtained in get_and_reset_last_marking_time() once, after which the tracking resets. -// Any pauses recorded by add_pause() will be subtracted from that results. -class G1ConcurrentStartToMixedTimeTracker { -private: - bool _active; - double _concurrent_start_end_time; - double _mixed_start_time; - double _total_pause_time; - - double wall_time() const { - return _mixed_start_time - _concurrent_start_end_time; - } -public: - G1ConcurrentStartToMixedTimeTracker() { reset(); } - - // Record concurrent start pause end, starting the time tracking. - void record_concurrent_start_end(double end_time) { - assert(!_active, "Concurrent start out of order."); - _concurrent_start_end_time = end_time; - _active = true; - } - - // Record the first mixed gc pause start, ending the time tracking. - void record_mixed_gc_start(double start_time) { - if (_active) { - _mixed_start_time = start_time; - _active = false; - } - } - - double get_and_reset_last_marking_time() { - assert(has_result(), "Do not have all measurements yet."); - double result = (_mixed_start_time - _concurrent_start_end_time) - _total_pause_time; - reset(); - return result; - } - - void reset() { - _active = false; - _total_pause_time = 0.0; - _concurrent_start_end_time = -1.0; - _mixed_start_time = -1.0; - } - - void add_pause(double time) { - if (_active) { - _total_pause_time += time; - } - } - - bool is_active() const { return _active; } - - // Returns whether we have a result that can be retrieved. - bool has_result() const { return _mixed_start_time > 0.0 && _concurrent_start_end_time > 0.0; } -}; - -#endif // SHARE_GC_G1_G1CONCURRENTSTARTTOMIXEDTIMETRACKER_HPP diff --git a/src/hotspot/share/gc/g1/g1IHOPControl.cpp b/src/hotspot/share/gc/g1/g1IHOPControl.cpp index 164486123f7..782cdadc13b 100644 --- a/src/hotspot/share/gc/g1/g1IHOPControl.cpp +++ b/src/hotspot/share/gc/g1/g1IHOPControl.cpp @@ -31,19 +31,14 @@ double G1IHOPControl::predict(const TruncatedSeq* seq) const { assert(_is_adaptive, "precondition"); assert(_predictor != nullptr, "precondition"); - - return _predictor->predict_zero_bounded(seq); + return _predictor->predict_zero_bounded(seq); } bool G1IHOPControl::have_enough_data_for_prediction() const { assert(_is_adaptive, "precondition"); return ((size_t)_marking_start_to_mixed_time_s.num() >= G1AdaptiveIHOPNumInitialSamples) && - ((size_t)_old_gen_alloc_rate.num() >= G1AdaptiveIHOPNumInitialSamples); -} - -double G1IHOPControl::last_marking_start_to_mixed_time_s() const { - return _marking_start_to_mixed_time_s.last(); + ((size_t)_old_non_humongous_alloc_rate.num() >= G1AdaptiveIHOPNumInitialSamples); } size_t G1IHOPControl::effective_target_occupancy() const { @@ -66,7 +61,6 @@ size_t G1IHOPControl::effective_target_occupancy() const { } G1IHOPControl::G1IHOPControl(double ihop_percent, - const G1OldGenAllocationTracker* old_gen_alloc_tracker, bool adaptive, const G1Predictions* predictor, size_t heap_reserve_percent, @@ -76,11 +70,10 @@ G1IHOPControl::G1IHOPControl(double ihop_percent, _target_occupancy(0), _heap_reserve_percent(heap_reserve_percent), _heap_waste_percent(heap_waste_percent), - _last_allocation_time_s(0.0), - _old_gen_alloc_tracker(old_gen_alloc_tracker), _predictor(predictor), _marking_start_to_mixed_time_s(10, 0.05), - _old_gen_alloc_rate(10, 0.05), + _old_non_humongous_alloc_rate(10, 0.05), + _peak_extra_humongous_occupancy_in_mark_cycle(10, 0.05), _expected_young_gen_at_first_mixed_gc(0) { assert(_initial_ihop_percent >= 0.0 && _initial_ihop_percent <= 100.0, "IHOP percent out of range: %.3f", ihop_percent); @@ -93,22 +86,28 @@ void G1IHOPControl::update_target_occupancy(size_t new_target_occupancy) { _target_occupancy = new_target_occupancy; } -void G1IHOPControl::report_statistics(G1NewTracer* new_tracer, size_t non_young_occupancy) { - print_log(non_young_occupancy); - send_trace_event(new_tracer, non_young_occupancy); +void G1IHOPControl::report_statistics(G1NewTracer* new_tracer, + size_t non_young_occupancy, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy) { + print_log(non_young_occupancy, non_humongous_allocation, peak_extra_humongous_occupancy); + send_trace_event(new_tracer, non_young_occupancy, + non_humongous_allocation, peak_extra_humongous_occupancy); } -void G1IHOPControl::update_allocation_info(double allocation_time_s, size_t expected_young_gen_size) { - assert(allocation_time_s > 0, "Invalid allocation time: %.3f", allocation_time_s); - _last_allocation_time_s = allocation_time_s; - double alloc_rate = _old_gen_alloc_tracker->last_period_old_gen_growth() / allocation_time_s; - _old_gen_alloc_rate.add(alloc_rate); +void G1IHOPControl::record_expected_young_gen_size(size_t expected_young_gen_size) { _expected_young_gen_at_first_mixed_gc = expected_young_gen_size; } -void G1IHOPControl::add_marking_start_to_mixed_length(double length_s) { - assert(length_s >= 0.0, "Invalid marking length: %.3f", length_s); - _marking_start_to_mixed_time_s.add(length_s); +void G1IHOPControl::record_concurrent_cycle(double marking_start_to_mixed_time_s, + size_t non_humongous_bytes, + size_t peak_extra_humongous_occupancy_bytes) { + assert(marking_start_to_mixed_time_s > 0.0, "Invalid concurrent cycle duration: %.3f", marking_start_to_mixed_time_s); + + double non_humongous_rate = non_humongous_bytes / marking_start_to_mixed_time_s; + _marking_start_to_mixed_time_s.add(marking_start_to_mixed_time_s); + _old_non_humongous_alloc_rate.add(non_humongous_rate); + _peak_extra_humongous_occupancy_in_mark_cycle.add(peak_extra_humongous_occupancy_bytes); } // Determine the old generation occupancy threshold at which to start @@ -121,80 +120,93 @@ size_t G1IHOPControl::old_gen_threshold_for_conc_mark_start() const { return (size_t)(_initial_ihop_percent * _target_occupancy / 100.0); } - // During the time between marking start and the first Mixed GC, - // additional memory will be consumed: - // - Old gen grows due to allocations: - // old_gen_alloc_bytes = old_gen_alloc_rate * marking_start_to_mixed_time - // - Young gen will occupy a certain size at the first Mixed GC: - // expected_young_gen_at_first_mixed_gc - double marking_start_to_mixed_time = predict(&_marking_start_to_mixed_time_s); - double old_gen_alloc_rate = predict(&_old_gen_alloc_rate); - size_t old_gen_alloc_bytes = (size_t)(marking_start_to_mixed_time * old_gen_alloc_rate); - - // Therefore, the total heap occupancy at the first Mixed GC is: - // current_old_gen + old_gen_growth + expected_young_gen_at_first_mixed_gc + // Between Concurrent Start GC and the first Mixed GC (i.e. concurrent cycle), + // we expect extra heap occupancy from three sources: + // - non-humongous allocations into the old-gen + // - peak extra humongous occupancy during the cycle, relative to the humongous occupancy + // at the end of the Concurrent Start GC. + // - we also wish to maintain the current desired young generation until the first Mixed-gc; + // promotions into the old gen should not shrink the young gen and degrade performance. // - // To ensure this does not exceed the target_heap_occupancy, we work - // backwards to compute the old gen occupancy at which marking must start: - // mark_start_threshold = target_heap_occupancy - - // (old_gen_growth + expected_young_gen_at_first_mixed_gc) + // We therefore start marking early enough such that: + // + // old_gen_at_concurrent_start + + // predicted_non_hum_old_growth + + // predicted_peak_extra_humongous_occupancy + + // expected_young_gen_at_first_mixed_gc + // + // stays below the effective target occupancy. + double marking_start_to_mixed_time = predict(&_marking_start_to_mixed_time_s); + double old_non_humongous_alloc_rate = predict(&_old_non_humongous_alloc_rate); + size_t old_non_humongous_alloc_bytes = (size_t)(marking_start_to_mixed_time * old_non_humongous_alloc_rate); - size_t predicted_needed = old_gen_alloc_bytes + _expected_young_gen_at_first_mixed_gc; + size_t predicted_peak_extra_humongous_occupancy = + predict(&_peak_extra_humongous_occupancy_in_mark_cycle); + + size_t reserve_for_young_regions = _expected_young_gen_at_first_mixed_gc; size_t target_heap_occupancy = effective_target_occupancy(); - return predicted_needed < target_heap_occupancy - ? target_heap_occupancy - predicted_needed - : 0; + size_t needed_for_concurrent_cycle = reserve_for_young_regions + + old_non_humongous_alloc_bytes + + predicted_peak_extra_humongous_occupancy; + + size_t threshold = needed_for_concurrent_cycle < target_heap_occupancy ? + target_heap_occupancy - needed_for_concurrent_cycle : 0; + return threshold; } -void G1IHOPControl::print_log(size_t non_young_occupancy) { +void G1IHOPControl::print_log(size_t non_young_occupancy, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy) { assert(_target_occupancy > 0, "Target occupancy still not updated yet."); size_t old_gen_mark_start_threshold = old_gen_threshold_for_conc_mark_start(); - log_debug(gc, ihop)("Basic information (value update), old-gen threshold: %zuB (%1.2f%%), target occupancy: %zuB, old-gen occupancy: %zuB (%1.2f%%), " - "recent old-gen allocation size: %zuB, recent allocation duration: %1.2fms, recent old-gen allocation rate: %1.2fB/s, recent marking phase length: %1.2fms", + log_debug(gc, ihop)("Basic information (value update), old-gen threshold: %zuB (%1.2f%%), target occupancy: %zuB, old-gen occupancy: %zuB (%1.2f%%)", old_gen_mark_start_threshold, percent_of(old_gen_mark_start_threshold, _target_occupancy), _target_occupancy, non_young_occupancy, - percent_of(non_young_occupancy, _target_occupancy), - _old_gen_alloc_tracker->last_period_old_gen_bytes(), - _last_allocation_time_s * 1000.0, - _last_allocation_time_s > 0.0 ? _old_gen_alloc_tracker->last_period_old_gen_bytes() / _last_allocation_time_s : 0.0, - last_marking_start_to_mixed_time_s() * 1000.0); + percent_of(non_young_occupancy, _target_occupancy)); - if (!_is_adaptive) { + if (!_is_adaptive || !have_enough_data_for_prediction()) { return; } size_t effective_target = effective_target_occupancy(); - log_debug(gc, ihop)("Adaptive IHOP information (value update), prediction active: %s, old-gen threshold: %zuB (%1.2f%%), internal target occupancy: %zuB, " - "old-gen occupancy: %zuB, additional buffer size: %zuB, predicted old-gen allocation rate: %1.2fB/s, " - "predicted marking phase length: %1.2fms", - BOOL_TO_STR(have_enough_data_for_prediction()), + log_debug(gc, ihop)("Adaptive IHOP information (value update), old-gen threshold: %zuB (%1.2f%%), internal target occupancy: %zuB, " + "old-gen occupancy: %zuB (%1.2f%%), additional buffer size: %zuB, " + "current non-humongous allocation: %zuB, current peak extra humongous occupancy: %zuB, " + "predicted old-gen non-humongous allocation rate: %1.2fB/s, predicted peak extra humongous occupancy: %1.2fB, " + "predicted concurrent cycle duration: %1.2fms", old_gen_mark_start_threshold, percent_of(old_gen_mark_start_threshold, effective_target), effective_target, non_young_occupancy, + percent_of(non_young_occupancy, effective_target), _expected_young_gen_at_first_mixed_gc, - predict(&_old_gen_alloc_rate), + non_humongous_allocation, peak_extra_humongous_occupancy, + predict(&_old_non_humongous_alloc_rate), + predict(&_peak_extra_humongous_occupancy_in_mark_cycle), predict(&_marking_start_to_mixed_time_s) * 1000.0); } -void G1IHOPControl::send_trace_event(G1NewTracer* tracer, size_t non_young_occupancy) { +void G1IHOPControl::send_trace_event(G1NewTracer* tracer, + size_t non_young_occupancy, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy) { assert(_target_occupancy > 0, "Target occupancy still not updated yet."); tracer->report_basic_ihop_statistics(old_gen_threshold_for_conc_mark_start(), _target_occupancy, - non_young_occupancy, - _old_gen_alloc_tracker->last_period_old_gen_bytes(), - _last_allocation_time_s, - last_marking_start_to_mixed_time_s()); + non_young_occupancy); if (_is_adaptive) { tracer->report_adaptive_ihop_statistics(old_gen_threshold_for_conc_mark_start(), effective_target_occupancy(), non_young_occupancy, _expected_young_gen_at_first_mixed_gc, - predict(&_old_gen_alloc_rate), + non_humongous_allocation, + peak_extra_humongous_occupancy, + predict(&_old_non_humongous_alloc_rate), + predict(&_peak_extra_humongous_occupancy_in_mark_cycle), predict(&_marking_start_to_mixed_time_s), have_enough_data_for_prediction()); } diff --git a/src/hotspot/share/gc/g1/g1IHOPControl.hpp b/src/hotspot/share/gc/g1/g1IHOPControl.hpp index 2836408978b..df92f31065f 100644 --- a/src/hotspot/share/gc/g1/g1IHOPControl.hpp +++ b/src/hotspot/share/gc/g1/g1IHOPControl.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_GC_G1_G1IHOPCONTROL_HPP #define SHARE_GC_G1_G1IHOPCONTROL_HPP -#include "gc/g1/g1OldGenAllocationTracker.hpp" #include "memory/allocation.hpp" #include "utilities/numberSeq.hpp" @@ -53,16 +52,15 @@ class G1IHOPControl : public CHeapObj { // Percentage of free heap that should be considered as waste. const size_t _heap_waste_percent; - // Most recent complete mutator allocation period in seconds. - double _last_allocation_time_s; - const G1OldGenAllocationTracker* _old_gen_alloc_tracker; - const G1Predictions* _predictor; // Wall-clock time in seconds from marking start to the first mixed GC, // excluding GC Pause time. TruncatedSeq _marking_start_to_mixed_time_s; - // Old generation allocation rate in bytes per second. - TruncatedSeq _old_gen_alloc_rate; + // Track old-generation allocations during a concurrent cycle: end of the + // Concurrent Start to the first Mixed GC. + // These values are used only when G1UseAdaptiveIHOP is enabled. + TruncatedSeq _old_non_humongous_alloc_rate; + TruncatedSeq _peak_extra_humongous_occupancy_in_mark_cycle; // The most recent unrestrained size of the young gen. This is used as an additional // factor in the calculation of the threshold, as the threshold is based on @@ -77,19 +75,23 @@ class G1IHOPControl : public CHeapObj { double predict(const TruncatedSeq* seq) const; bool have_enough_data_for_prediction() const; - double last_marking_start_to_mixed_time_s() const; // The "effective" target occupancy the algorithm wants to keep until the start // of Mixed GCs. This is typically lower than the target occupancy, as the // algorithm needs to consider restrictions by the environment. size_t effective_target_occupancy() const; - void print_log(size_t non_young_occupancy); - void send_trace_event(G1NewTracer* tracer, size_t non_young_occupancy); + void print_log(size_t non_young_occupancy, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy); + + void send_trace_event(G1NewTracer* tracer, + size_t non_young_occupancy, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy); public: G1IHOPControl(double ihop_percent, - const G1OldGenAllocationTracker* old_gen_alloc_tracker, bool adaptive, const G1Predictions* predictor, size_t heap_reserve_percent, @@ -98,26 +100,23 @@ class G1IHOPControl : public CHeapObj { // Adjust target occupancy. void update_target_occupancy(size_t new_target_occupancy); - void update_target_after_marking_phase(); - - // Update allocation rate information and current expected young gen size for the - // first mixed gc needed for the predictor. Allocation rate is given as the - // separately passed in allocation increment and the time passed (mutator time) - // for the latest allocation increment here. Allocation size is the memory needed - // during the mutator before and the first mixed gc pause itself. + // Updates expected young gen size for the first mixed gc needed for the predictor. // Contents include young gen at that point, and the memory required for evacuating // the collection set in that first mixed gc (including waste caused by PLAB // allocation etc.). - void update_allocation_info(double allocation_time_s, size_t expected_young_gen_size); + void record_expected_young_gen_size(size_t expected_young_gen_size); - // Update the time spent in the mutator beginning from the end of concurrent start to - // the first mixed gc. - void add_marking_start_to_mixed_length(double length_s); + void record_concurrent_cycle(double marking_start_to_mixed_time_s, + size_t non_humongous_bytes, + size_t peak_extra_humongous_occupancy); // Get the current non-young occupancy at which concurrent marking should start. size_t old_gen_threshold_for_conc_mark_start() const; - void report_statistics(G1NewTracer* tracer, size_t non_young_occupancy); + void report_statistics(G1NewTracer* tracer, + size_t non_young_occupancy, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy); }; #endif // SHARE_GC_G1_G1IHOPCONTROL_HPP diff --git a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp index ec3d39d7e50..7355a40c348 100644 --- a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp +++ b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.cpp @@ -26,36 +26,43 @@ #include "logging/log.hpp" G1OldGenAllocationTracker::G1OldGenAllocationTracker() : - _last_period_old_gen_bytes(0), - _last_period_old_gen_growth(0), - _humongous_bytes_after_last_gc(0), - _allocated_bytes_since_last_gc(0), - _allocated_humongous_bytes_since_last_gc(0) { + _humongous_bytes_after_last_pause(0), + _allocated_non_humongous_bytes_since_last_pause(0), + _allocated_humongous_bytes_since_last_pause(0) { } -void G1OldGenAllocationTracker::reset_after_gc(size_t humongous_bytes_after_gc) { +G1AllocationIntervalStats G1OldGenAllocationTracker::end_allocation_interval(size_t humongous_bytes_after_pause) { // Calculate actual increase in old, taking eager reclaim into consideration. - size_t last_period_humongous_increase = 0; - if (humongous_bytes_after_gc > _humongous_bytes_after_last_gc) { - last_period_humongous_increase = humongous_bytes_after_gc - _humongous_bytes_after_last_gc; - assert(last_period_humongous_increase <= _allocated_humongous_bytes_since_last_gc, + size_t last_interval_humongous_increase = 0; + if (humongous_bytes_after_pause > _humongous_bytes_after_last_pause) { + last_interval_humongous_increase = humongous_bytes_after_pause - _humongous_bytes_after_last_pause; + assert(last_interval_humongous_increase <= _allocated_humongous_bytes_since_last_pause, "Increase larger than allocated %zu <= %zu", - last_period_humongous_increase, _allocated_humongous_bytes_since_last_gc); + last_interval_humongous_increase, _allocated_humongous_bytes_since_last_pause); } - _last_period_old_gen_growth = _allocated_bytes_since_last_gc + last_period_humongous_increase; - // Calculate and record needed values. - _last_period_old_gen_bytes = _allocated_bytes_since_last_gc + _allocated_humongous_bytes_since_last_gc; - _humongous_bytes_after_last_gc = humongous_bytes_after_gc; + size_t last_interval_old_gen_growth = _allocated_non_humongous_bytes_since_last_pause + + last_interval_humongous_increase; - log_debug(gc, alloc, stats)("Old generation allocation in the last mutator period, " + G1AllocationIntervalStats allocation_interval_stats{ + _allocated_non_humongous_bytes_since_last_pause, + _allocated_humongous_bytes_since_last_pause, + _humongous_bytes_after_last_pause, + humongous_bytes_after_pause + }; + + _humongous_bytes_after_last_pause = humongous_bytes_after_pause; + + log_debug(gc, alloc, stats)("Old generation allocation in the last allocation interval, " "old gen allocated: %zuB, humongous allocated: %zuB, " "old gen growth: %zuB.", - _allocated_bytes_since_last_gc, - _allocated_humongous_bytes_since_last_gc, - _last_period_old_gen_growth); + _allocated_non_humongous_bytes_since_last_pause, + _allocated_humongous_bytes_since_last_pause, + last_interval_old_gen_growth); - // Reset for next mutator period. - _allocated_bytes_since_last_gc = 0; - _allocated_humongous_bytes_since_last_gc = 0; + // Reset for the next interval. + _allocated_non_humongous_bytes_since_last_pause = 0; + _allocated_humongous_bytes_since_last_pause = 0; + + return allocation_interval_stats; } diff --git a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp index aa5e3c6c942..218f65cf7c1 100644 --- a/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp +++ b/src/hotspot/share/gc/g1/g1OldGenAllocationTracker.hpp @@ -22,46 +22,71 @@ * */ -#ifndef SHARE_VM_GC_G1_G1OLDGENALLOCATIONTRACKER_HPP -#define SHARE_VM_GC_G1_G1OLDGENALLOCATIONTRACKER_HPP +#ifndef SHARE_GC_G1_G1OLDGENALLOCATIONTRACKER_HPP +#define SHARE_GC_G1_G1OLDGENALLOCATIONTRACKER_HPP -#include "gc/g1/g1HeapRegion.hpp" #include "memory/allocation.hpp" +// Allocation statistics for an allocation interval, i.e. the interval between two +// consecutive STW pauses. +// +// The allocation counters record allocations made during that interval. +// +// _total_humongous_before_bytes is the humongous occupancy after the previous +// pause (at the start of the allocation interval). +// +// _total_humongous_after_bytes is the humongous occupancy after the current +// pause (at the end of the allocation interval). +struct G1AllocationIntervalStats { + size_t _non_humongous_allocated_bytes; + size_t _humongous_allocated_bytes; + size_t _total_humongous_before_bytes; + size_t _total_humongous_after_bytes; + + G1AllocationIntervalStats(size_t non_humongous_allocated_bytes, + size_t humongous_allocated_bytes, + size_t total_humongous_before_bytes, + size_t total_humongous_after_bytes) + : _non_humongous_allocated_bytes(non_humongous_allocated_bytes), + _humongous_allocated_bytes(humongous_allocated_bytes), + _total_humongous_before_bytes(total_humongous_before_bytes), + _total_humongous_after_bytes(total_humongous_after_bytes) + { } + + void record_humongous_allocation(size_t humongous_allocation_bytes) { + _humongous_allocated_bytes += humongous_allocation_bytes; + _total_humongous_after_bytes += humongous_allocation_bytes; + } +}; + // Track allocation details in the old generation. class G1OldGenAllocationTracker : public CHeapObj { - // Total number of bytes allocated in the old generation at the end - // of the last gc. - size_t _last_period_old_gen_bytes; - // Total growth of the old geneneration since the last gc, - // taking eager-reclaim into consideration. - size_t _last_period_old_gen_growth; + // Total size of humongous objects after the last STW pause. + size_t _humongous_bytes_after_last_pause; - // Total size of humongous objects for last gc. - size_t _humongous_bytes_after_last_gc; - - // Non-humongous old generation allocations since the last gc. - size_t _allocated_bytes_since_last_gc; - // Humongous allocations during last mutator period. - size_t _allocated_humongous_bytes_since_last_gc; + // Non-humongous old generation allocations since the last STW pause. + size_t _allocated_non_humongous_bytes_since_last_pause; + // Humongous allocations during last allocation interval. + size_t _allocated_humongous_bytes_since_last_pause; public: G1OldGenAllocationTracker(); - void add_allocated_bytes_since_last_gc(size_t bytes) { _allocated_bytes_since_last_gc += bytes; } - void add_allocated_humongous_bytes_since_last_gc(size_t bytes) { _allocated_humongous_bytes_since_last_gc += bytes; } - - // Record a humongous allocation in a collection pause. This allocation - // is accounted to the previous mutator period. - void record_collection_pause_humongous_allocation(size_t bytes) { - _humongous_bytes_after_last_gc += bytes; + void add_allocated_non_humongous_bytes(size_t bytes) { + _allocated_non_humongous_bytes_since_last_pause += bytes; + } + void add_allocated_humongous_bytes(size_t bytes) { + _allocated_humongous_bytes_since_last_pause += bytes; } - size_t last_period_old_gen_bytes() const { return _last_period_old_gen_bytes; } - size_t last_period_old_gen_growth() const { return _last_period_old_gen_growth; }; + // Record a humongous allocation in a collection pause. This allocation + // is accounted to the previous allocation interval. + void record_collection_pause_humongous_allocation(size_t bytes) { + _humongous_bytes_after_last_pause += bytes; + } - // Calculates and resets stats after a collection. - void reset_after_gc(size_t humongous_bytes_after_gc); + // Calculate and reset allocation statistics after a pause. + G1AllocationIntervalStats end_allocation_interval(size_t humongous_bytes_after_pause); }; -#endif // SHARE_VM_GC_G1_G1OLDGENALLOCATIONTRACKER_HPP +#endif // SHARE_GC_G1_G1OLDGENALLOCATIONTRACKER_HPP diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 71a482e2505..35211938065 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -55,8 +55,9 @@ G1Policy::G1Policy(STWGCTimer* gc_timer) : _analytics(new G1Analytics(&_predictor)), _remset_tracker(), _mmu_tracker(new G1MMUTracker(GCPauseIntervalMillis / 1000.0, MaxGCPauseMillis / 1000.0)), + _concurrent_cycle_tracker(), _old_gen_alloc_tracker(), - _ihop_control(create_ihop_control(&_old_gen_alloc_tracker, &_predictor)), + _ihop_control(create_ihop_control(&_predictor)), _policy_counters(new GCPolicyCounters("GarbageFirst", 1, 2)), _cur_pause_start_sec(0.0), _young_list_desired_length(0), @@ -68,7 +69,6 @@ G1Policy::G1Policy(STWGCTimer* gc_timer) : _young_gen_sizer(), _free_regions_at_end_of_collection(0), _pending_cards_from_gc(0), - _concurrent_start_to_mixed(), _collection_set(nullptr), _g1h(nullptr), _phase_times_timer(gc_timer), @@ -589,6 +589,7 @@ void G1Policy::record_full_collection_end(size_t allocation_word_size) { // Consider this like a collection pause for the purposes of allocation // since last pause. double end_sec = os::elapsedTime(); + double start_time_sec = cur_pause_start_sec(); // "Nuke" the heuristics that control the young/mixed GC // transitions and make sure we start with young GCs after the Full GC. @@ -602,9 +603,6 @@ void G1Policy::record_full_collection_end(size_t allocation_word_size) { _survivor_surv_rate_group->reset(); update_young_length_bounds(); - _old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes); - - double start_time_sec = cur_pause_start_sec(); record_pause(Pause::Full, start_time_sec, end_sec); } @@ -954,8 +952,6 @@ G1CollectorState G1Policy::record_young_collection_end(bool concurrent_operation phase_times()->sum_thread_work_items(G1GCPhaseTimes::MergePSS, G1GCPhaseTimes::MergePSSToYoungGenCards)); } - record_pause(collector_state()->gc_pause_type(concurrent_operation_is_full_mark), start_time_sec, end_time_sec); - if (collector_state()->is_in_prepare_mixed_gc()) { assert(!collector_state()->is_in_concurrent_start_gc(), "The young GC before mixed is not allowed to be concurrent start GC"); @@ -988,23 +984,27 @@ G1CollectorState G1Policy::record_young_collection_end(bool concurrent_operation _free_regions_at_end_of_collection = _g1h->num_free_regions(); - _old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes); + Pause this_pause = collector_state()->gc_pause_type(concurrent_operation_is_full_mark); + size_t humongous_allocation_bytes = G1CollectedHeap::is_humongous(allocation_word_size) ? + G1CollectedHeap::allocation_used_bytes(allocation_word_size) : 0; + + record_pause(this_pause, start_time_sec, end_time_sec, humongous_allocation_bytes); // Do not update dynamic IHOP due to G1 periodic collection as it is highly likely // that in this case we are not running in a "normal" operating mode. if (_g1h->gc_cause() != GCCause::_g1_periodic_collection) { update_young_length_bounds(); + // Take snapshots of these values here as update_ihop_prediction + // may complete the concurrent cycle and reset the values. + size_t non_humongous_allocation = _concurrent_cycle_tracker.non_humongous_allocated_bytes(); + size_t peak_extra_humongous_occupancy = _concurrent_cycle_tracker.peak_extra_humongous_occupancy_bytes(); + if (update_ihop_prediction(app_time_ms / 1000.0, is_young_only_pause)) { - _ihop_control->report_statistics(_g1h->gc_tracer_stw(), _g1h->non_young_occupancy_after_allocation(allocation_word_size)); + _ihop_control->report_statistics(_g1h->gc_tracer_stw(), + _g1h->non_young_occupancy_after_allocation(allocation_word_size), + non_humongous_allocation, + peak_extra_humongous_occupancy); } - } else { - // Any garbage collection triggered as periodic collection resets the time-to-mixed - // measurement. Periodic collection typically means that the application is "inactive", i.e. - // the marking threads may have received an uncharacteristic amount of cpu time - // for completing the marking, i.e. are faster than expected. - // This skews the predicted marking length towards smaller values which might cause - // the mark start being too late. - abort_time_to_mixed_tracking(); } // Note that _mmu_tracker->max_gc_time() returns the time in seconds. @@ -1032,10 +1032,8 @@ G1CollectorState G1Policy::record_young_collection_end(bool concurrent_operation return next_state; } -G1IHOPControl* G1Policy::create_ihop_control(const G1OldGenAllocationTracker* old_gen_alloc_tracker, - const G1Predictions* predictor) { +G1IHOPControl* G1Policy::create_ihop_control(const G1Predictions* predictor) { return new G1IHOPControl(G1IHOP, - old_gen_alloc_tracker, G1UseAdaptiveIHOP, predictor, G1ReservePercent, @@ -1052,29 +1050,31 @@ bool G1Policy::update_ihop_prediction(double mutator_time_s, double const min_valid_time = 1e-6; bool report = false; + if (!this_gc_was_young_only && _concurrent_cycle_tracker.has_completed_cycle()) { + G1ConcurrentCycleStats cycle_stats = _concurrent_cycle_tracker.get_and_reset_cycle_stats(); - if (!this_gc_was_young_only && _concurrent_start_to_mixed.has_result()) { - double marking_to_mixed_time = _concurrent_start_to_mixed.get_and_reset_last_marking_time(); - assert(marking_to_mixed_time > 0.0, - "Concurrent start to mixed time must be larger than zero but is %.3f", - marking_to_mixed_time); - if (marking_to_mixed_time > min_valid_time) { - _ihop_control->add_marking_start_to_mixed_length(marking_to_mixed_time); + double concurrent_cycle_duration_s = cycle_stats._cycle_duration_s; + assert(concurrent_cycle_duration_s > 0.0, + "Time for Concurrent Start GC to the first Mixed GC must be larger than zero but is %.3f", + concurrent_cycle_duration_s); + if (concurrent_cycle_duration_s > min_valid_time) { + _ihop_control->record_concurrent_cycle(concurrent_cycle_duration_s, + cycle_stats._non_humongous_allocated_bytes, + cycle_stats._peak_extra_humongous_occupancy_bytes); report = true; } } - // As an approximation for the young gc promotion rates during marking we use - // all of them. In many applications there are only a few if any young gcs during - // marking, which makes any prediction useless. This increases the accuracy of the - // prediction. + // The second clause prevents skewing the IHOP prediction with (typically) degenerate + // back-to-back young-gen-size samples. if (this_gc_was_young_only && mutator_time_s > min_valid_time) { // IHOP control wants to know the expected young gen length if it were not // restrained by the heap reserve. Using the actual length would make the // prediction too small and the limit the young gen every time we get to the // predicted target occupancy. size_t young_gen_size = young_list_desired_length() * G1HeapRegion::GrainBytes; - _ihop_control->update_allocation_info(mutator_time_s, young_gen_size); + + _ihop_control->record_expected_young_gen_size(young_gen_size); report = true; } @@ -1311,11 +1311,11 @@ void G1Policy::decide_on_concurrent_start_pause() { // Force concurrent start. collector_state()->set_in_concurrent_start_gc(); // We might have ended up coming here about to start a mixed phase with a collection set - // active. The following remark might change the change the "evacuation efficiency" of + // active. The following remark might change the "evacuation efficiency" of // the regions in this set, leading to failing asserts later. // Since the concurrent cycle will recreate the collection set anyway, simply drop it here. abandon_collection_set_candidates(); - abort_time_to_mixed_tracking(); + abort_concurrent_cycle_tracking(); log_debug(gc, ergo)("Initiate concurrent cycle (%s requested concurrent cycle)", requester_for_mixed_abort(cause)); } else { @@ -1355,7 +1355,7 @@ void G1Policy::record_concurrent_mark_cleanup_end(bool has_rebuilt_remembered_se } if (!mixed_gc_pending) { - abort_time_to_mixed_tracking(); + abort_concurrent_cycle_tracking(); log_debug(gc, ergo)("request young-only gcs (candidate old regions not available)"); } if (mixed_gc_pending) { @@ -1390,7 +1390,8 @@ void G1Policy::update_gc_pause_time_ratios(Pause gc_type, double start_time_sec, void G1Policy::record_pause(Pause gc_type, double start, - double end) { + double end, + size_t humongous_allocation_bytes) { // Manage the MMU tracker. For some reason it ignores Full GCs. if (gc_type != Pause::Full) { _mmu_tracker->add_pause(start, end); @@ -1398,49 +1399,26 @@ void G1Policy::record_pause(Pause gc_type, update_gc_pause_time_ratios(gc_type, start, end); - update_time_to_mixed_tracking(gc_type, start, end); + size_t humongous_bytes = _g1h->humongous_regions_count() * G1HeapRegion::GrainBytes; + G1AllocationIntervalStats alloc_interval_stats = _old_gen_alloc_tracker.end_allocation_interval(humongous_bytes); + bool is_periodic_gc = _g1h->gc_cause() == GCCause::_g1_periodic_collection; + + if (humongous_allocation_bytes > 0) { + // Record the humongous allocation that triggered the GC and attribute it to + // the ending allocation interval. We do this eagerly, before we know whether + // the post GC allocation succeeds, to keep the common case simple. In the + // rare case where this allocation fails, we over-account; this only + // affects the stored IHOP sample if the current GC is the first Mixed GC. + alloc_interval_stats.record_humongous_allocation(humongous_allocation_bytes); + } + _concurrent_cycle_tracker.record_allocation_interval(gc_type, is_periodic_gc, start, end, alloc_interval_stats); double elapsed_gc_cpu_time = _analytics->gc_cpu_time_ms(); _analytics->set_gc_cpu_time_at_pause_end_ms(elapsed_gc_cpu_time); } -void G1Policy::update_time_to_mixed_tracking(Pause gc_type, - double start, - double end) { - // Manage the mutator time tracking from concurrent start to first mixed gc. - switch (gc_type) { - case Pause::Full: - abort_time_to_mixed_tracking(); - break; - case Pause::Cleanup: - case Pause::Remark: - case Pause::Normal: - case Pause::PrepareMixed: - _concurrent_start_to_mixed.add_pause(end - start); - break; - case Pause::ConcurrentStartFull: - // Do not track time-to-mixed time for periodic collections as they are likely - // to be not representative to regular operation as the mutators are idle at - // that time. Also only track full concurrent mark cycles. - if (_g1h->gc_cause() != GCCause::_g1_periodic_collection) { - _concurrent_start_to_mixed.record_concurrent_start_end(end); - } - break; - case Pause::ConcurrentStartUndo: - assert(_g1h->gc_cause() == GCCause::_g1_humongous_allocation, - "GC cause must be humongous allocation but is %d", - _g1h->gc_cause()); - break; - case Pause::Mixed: - _concurrent_start_to_mixed.record_mixed_gc_start(start); - break; - default: - ShouldNotReachHere(); - } -} - -void G1Policy::abort_time_to_mixed_tracking() { - _concurrent_start_to_mixed.reset(); +void G1Policy::abort_concurrent_cycle_tracking() { + _concurrent_cycle_tracker.abort_cycle(); } bool G1Policy::next_gc_should_be_mixed() const { diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 0a472dd0527..3cfd54c8c94 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -26,7 +26,7 @@ #define SHARE_GC_G1_G1POLICY_HPP #include "gc/g1/g1CollectorState.hpp" -#include "gc/g1/g1ConcurrentStartToMixedTimeTracker.hpp" +#include "gc/g1/g1ConcurrentCycleTracker.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapRegionAttr.hpp" #include "gc/g1/g1MMUTracker.hpp" @@ -58,8 +58,7 @@ class STWGCTimer; class G1Policy: public CHeapObj { using Pause = G1CollectorState::Pause; - static G1IHOPControl* create_ihop_control(const G1OldGenAllocationTracker* old_gen_alloc_tracker, - const G1Predictions* predictor); + static G1IHOPControl* create_ihop_control(const G1Predictions* predictor); // Update the IHOP control with the necessary statistics. Returns true if there // has been a significant update to the prediction. bool update_ihop_prediction(double mutator_time_s, @@ -70,8 +69,9 @@ class G1Policy: public CHeapObj { G1RemSetTrackingPolicy _remset_tracker; G1MMUTracker* _mmu_tracker; + G1ConcurrentCycleTracker _concurrent_cycle_tracker; // Tracking the allocation in the old generation between - // two GCs. + // two pauses. G1OldGenAllocationTracker _old_gen_alloc_tracker; G1IHOPControl* _ihop_control; @@ -114,8 +114,6 @@ class G1Policy: public CHeapObj { // garbage collection or the most recent refinement sweep. size_t _to_collection_set_cards; - G1ConcurrentStartToMixedTimeTracker _concurrent_start_to_mixed; - bool should_update_surv_rate_group_predictors(); double pending_cards_processing_time() const; @@ -264,17 +262,16 @@ public: private: void abandon_collection_set_candidates(); - // Manage time-to-mixed tracking. - void update_time_to_mixed_tracking(Pause gc_type, double start, double end); // Record the given STW pause with the given start and end times (in s). void record_pause(Pause gc_type, double start, - double end); + double end, + size_t humongous_allocation_bytes = 0); void update_gc_pause_time_ratios(Pause gc_type, double start_sec, double end_sec); // Indicate that we aborted marking before doing any mixed GCs. - void abort_time_to_mixed_tracking(); + void abort_concurrent_cycle_tracking(); public: diff --git a/src/hotspot/share/gc/g1/g1Trace.cpp b/src/hotspot/share/gc/g1/g1Trace.cpp index d6eadda5d50..bcc0941dc62 100644 --- a/src/hotspot/share/gc/g1/g1Trace.cpp +++ b/src/hotspot/share/gc/g1/g1Trace.cpp @@ -97,31 +97,31 @@ void G1NewTracer::report_evacuation_statistics(const G1EvacSummary& young_summar } void G1NewTracer::report_basic_ihop_statistics(size_t threshold, - size_t target_ccupancy, - size_t non_young_occupancy, - size_t last_allocation_size, - double last_allocation_duration, - double last_marking_length) { + size_t target_occupancy, + size_t non_young_occupancy) { send_basic_ihop_statistics(threshold, - target_ccupancy, - non_young_occupancy, - last_allocation_size, - last_allocation_duration, - last_marking_length); + target_occupancy, + non_young_occupancy); } void G1NewTracer::report_adaptive_ihop_statistics(size_t threshold, size_t internal_target_occupancy, size_t current_occupancy, size_t additional_buffer_size, - double predicted_allocation_rate, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy, + double predicted_old_non_hum_alloc_rate, + size_t predicted_peak_extra_humongous_occupancy, double predicted_marking_length, bool prediction_active) { send_adaptive_ihop_statistics(threshold, internal_target_occupancy, current_occupancy, additional_buffer_size, - predicted_allocation_rate, + non_humongous_allocation, + peak_extra_humongous_occupancy, + predicted_old_non_hum_alloc_rate, + predicted_peak_extra_humongous_occupancy, predicted_marking_length, prediction_active); } @@ -206,10 +206,7 @@ void G1NewTracer::send_old_evacuation_statistics(const G1EvacSummary& summary) c void G1NewTracer::send_basic_ihop_statistics(size_t threshold, size_t target_occupancy, - size_t non_young_occupancy, - size_t last_allocation_size, - double last_allocation_duration, - double last_marking_length) { + size_t non_young_occupancy) { EventG1BasicIHOP evt; if (evt.should_commit()) { evt.set_gcId(GCId::current()); @@ -217,10 +214,6 @@ void G1NewTracer::send_basic_ihop_statistics(size_t threshold, evt.set_targetOccupancy(target_occupancy); evt.set_thresholdPercentage(target_occupancy > 0 ? ((double)threshold / target_occupancy) : 0.0); evt.set_currentOccupancy(non_young_occupancy); - evt.set_recentMutatorAllocationSize(last_allocation_size); - evt.set_recentMutatorDuration(last_allocation_duration * MILLIUNITS); - evt.set_recentAllocationRate(last_allocation_duration != 0.0 ? last_allocation_size / last_allocation_duration : 0.0); - evt.set_lastMarkingDuration(last_marking_length * MILLIUNITS); evt.commit(); } } @@ -229,7 +222,10 @@ void G1NewTracer::send_adaptive_ihop_statistics(size_t threshold, size_t internal_target_occupancy, size_t current_occupancy, size_t additional_buffer_size, - double predicted_allocation_rate, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy, + double predicted_old_non_hum_alloc_rate, + size_t predicted_peak_extra_humongous_occupancy, double predicted_marking_length, bool prediction_active) { EventG1AdaptiveIHOP evt; @@ -240,7 +236,10 @@ void G1NewTracer::send_adaptive_ihop_statistics(size_t threshold, evt.set_ihopTargetOccupancy(internal_target_occupancy); evt.set_currentOccupancy(current_occupancy); evt.set_additionalBufferSize(additional_buffer_size); - evt.set_predictedAllocationRate(predicted_allocation_rate); + evt.set_nonHumongousAllocation(non_humongous_allocation); + evt.set_peakExtraHumongousOccupancy(peak_extra_humongous_occupancy); + evt.set_predictedNonHumongousAllocation(predicted_old_non_hum_alloc_rate); + evt.set_predictedPeakExtraHumongousOccupancy(predicted_peak_extra_humongous_occupancy); evt.set_predictedMarkingDuration(predicted_marking_length * MILLIUNITS); evt.set_predictionActive(prediction_active); evt.commit(); diff --git a/src/hotspot/share/gc/g1/g1Trace.hpp b/src/hotspot/share/gc/g1/g1Trace.hpp index bfcc275d2ca..c5d099d5807 100644 --- a/src/hotspot/share/gc/g1/g1Trace.hpp +++ b/src/hotspot/share/gc/g1/g1Trace.hpp @@ -52,15 +52,15 @@ public: void report_basic_ihop_statistics(size_t threshold, size_t target_occupancy, - size_t current_occupancy, - size_t last_allocation_size, - double last_allocation_duration, - double last_marking_length); + size_t current_occupancy); void report_adaptive_ihop_statistics(size_t threshold, size_t internal_target_occupancy, size_t current_occupancy, size_t additional_buffer_size, - double predicted_allocation_rate, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy, + double predicted_old_gen_non_humongous_allocation_rate, + size_t predicted_peak_extra_humongous_occupancy, double predicted_marking_length, bool prediction_active); private: @@ -73,15 +73,16 @@ private: void send_basic_ihop_statistics(size_t threshold, size_t target_occupancy, - size_t non_young_occupancy, - size_t last_allocation_size, - double last_allocation_duration, - double last_marking_length); + size_t non_young_occupancy); + void send_adaptive_ihop_statistics(size_t threshold, size_t internal_target_occupancy, size_t non_young_occupancy, size_t additional_buffer_size, - double predicted_allocation_rate, + size_t non_humongous_allocation, + size_t peak_extra_humongous_occupancy, + double predicted_old_gen_non_humongous_allocation_rate, + size_t predicted_peak_extra_humongous_occupancy, double predicted_marking_length, bool prediction_active); }; diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index d0c843aa5d6..bf4a6cca81d 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -542,7 +542,7 @@ public: class FreeCSetStats { size_t _before_used_bytes; // Usage in regions successfully evacuate size_t _after_used_bytes; // Usage in regions failing evacuation - size_t _bytes_allocated_in_old_since_last_gc; // Size of young regions turned into old + size_t _bytes_allocated_in_old_since_last_pause; // Size of young regions turned into old size_t _failure_used_words; // Live size in failed regions size_t _failure_waste_words; // Wasted size in failed regions uint _regions_freed; // Number of regions freed @@ -551,7 +551,7 @@ public: FreeCSetStats() : _before_used_bytes(0), _after_used_bytes(0), - _bytes_allocated_in_old_since_last_gc(0), + _bytes_allocated_in_old_since_last_pause(0), _failure_used_words(0), _failure_waste_words(0), _regions_freed(0) { } @@ -560,7 +560,7 @@ public: assert(other != nullptr, "invariant"); _before_used_bytes += other->_before_used_bytes; _after_used_bytes += other->_after_used_bytes; - _bytes_allocated_in_old_since_last_gc += other->_bytes_allocated_in_old_since_last_gc; + _bytes_allocated_in_old_since_last_pause += other->_bytes_allocated_in_old_since_last_pause; _failure_used_words += other->_failure_used_words; _failure_waste_words += other->_failure_waste_words; _regions_freed += other->_regions_freed; @@ -575,7 +575,7 @@ public: g1h->alloc_buffer_stats(G1HeapRegionAttr::Old)->add_failure_used_and_waste(_failure_used_words, _failure_waste_words); G1Policy *policy = g1h->policy(); - policy->old_gen_alloc_tracker()->add_allocated_bytes_since_last_gc(_bytes_allocated_in_old_since_last_gc); + policy->old_gen_alloc_tracker()->add_allocated_non_humongous_bytes(_bytes_allocated_in_old_since_last_pause); policy->cset_regions_freed(); } @@ -592,7 +592,7 @@ public: // additional allocation: both the objects still in the region and the // ones already moved are accounted for elsewhere. if (r->is_young()) { - _bytes_allocated_in_old_since_last_gc += G1HeapRegion::GrainBytes; + _bytes_allocated_in_old_since_last_pause += G1HeapRegion::GrainBytes; } } diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 09d9e0ccabf..22bd21c8ff4 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1,7 +1,7 @@