aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-10 17:29:27 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2024-05-10 17:29:27 +0000
commitc10acd7538096b177eec1906478ba82fa1fe5fc2 (patch)
tree81511e5a4fba3525fde7c8f5d6ec70403df61003
parentac365fed89454e2dba847056a7182f11f06d75bb (diff)
parent3c2dbe8b94e8eb1d292ee2ad3fb47eff8ead2f8a (diff)
downloadwebp-busytown-mac-infra-release.tar.gz
Merge "Snap for 11819167 from ac19f36b8cdef41a423dcb6ca3d0c2231dc53045 to busytown-mac-infra-release" into busytown-mac-infra-releasebusytown-mac-infra-release
-rw-r--r--.cmake-format.py240
-rw-r--r--.mailmap1
-rw-r--r--AUTHORS9
-rw-r--r--Android.bp1
-rw-r--r--Android.mk1
-rw-r--r--CMakeLists.txt99
-rw-r--r--CONTRIBUTING.md51
-rw-r--r--ChangeLog235
-rw-r--r--LICENSE53
-rw-r--r--METADATA20
-rw-r--r--Makefile.vc6
-rw-r--r--NEWS34
-rw-r--r--README.android2
-rw-r--r--README.md2
-rw-r--r--README.version3
-rw-r--r--build.gradle1
-rw-r--r--cmake/WebPConfig.cmake.in9
-rw-r--r--cmake/config.h.in33
-rw-r--r--cmake/cpu.cmake7
-rw-r--r--cmake/deps.cmake100
-rw-r--r--configure.ac16
-rw-r--r--doc/api.md2
-rw-r--r--doc/building.md18
-rw-r--r--doc/tools.md12
-rw-r--r--doc/webp-container-spec.txt325
-rw-r--r--doc/webp-lossless-bitstream-spec.txt585
-rw-r--r--examples/Makefile.am2
-rw-r--r--examples/anim_dump.c6
-rw-r--r--examples/cwebp.c19
-rw-r--r--examples/gifdec.c2
-rw-r--r--examples/img2webp.c20
-rw-r--r--examples/vwebp.c21
-rw-r--r--examples/webpinfo.c12
-rw-r--r--examples/webpmux.c46
-rw-r--r--extras/Makefile.am1
-rw-r--r--extras/extras.c168
-rw-r--r--extras/extras.h35
-rw-r--r--extras/sharpyuv_risk_table.c6210
-rw-r--r--extras/sharpyuv_risk_table.h27
-rw-r--r--extras/vwebp_sdl.c2
-rw-r--r--extras/webp_to_sdl.c83
-rw-r--r--imageio/image_enc.c81
-rw-r--r--imageio/pngdec.c16
-rwxr-xr-xiosbuild.sh18
-rw-r--r--makefile.unix11
-rw-r--r--man/cwebp.112
-rw-r--r--man/img2webp.116
-rw-r--r--sharpyuv/Makefile.am2
-rw-r--r--sharpyuv/libsharpyuv.rc10
-rw-r--r--sharpyuv/sharpyuv.c164
-rw-r--r--sharpyuv/sharpyuv.h83
-rw-r--r--sharpyuv/sharpyuv_dsp.c5
-rw-r--r--sharpyuv/sharpyuv_gamma.c310
-rw-r--r--sharpyuv/sharpyuv_gamma.h11
-rw-r--r--src/Makefile.am4
-rw-r--r--src/dec/alpha_dec.c61
-rw-r--r--src/dec/buffer_dec.c2
-rw-r--r--src/dec/idec_dec.c50
-rw-r--r--src/dec/tree_dec.c3
-rw-r--r--src/dec/vp8_dec.c22
-rw-r--r--src/dec/vp8_dec.h17
-rw-r--r--src/dec/vp8i_dec.h13
-rw-r--r--src/dec/vp8l_dec.c212
-rw-r--r--src/dec/vp8li_dec.h30
-rw-r--r--src/dec/webp_dec.c81
-rw-r--r--src/dec/webpi_dec.h6
-rw-r--r--src/demux/Makefile.am2
-rw-r--r--src/demux/anim_decode.c22
-rw-r--r--src/demux/demux.c2
-rw-r--r--src/demux/libwebpdemux.rc10
-rw-r--r--src/dsp/alpha_processing.c1
-rw-r--r--src/dsp/alpha_processing_sse2.c41
-rw-r--r--src/dsp/cost.c1
-rw-r--r--src/dsp/cost_neon.c4
-rw-r--r--src/dsp/cpu.c18
-rw-r--r--src/dsp/cpu.h36
-rw-r--r--src/dsp/dec.c26
-rw-r--r--src/dsp/dec_mips32.c56
-rw-r--r--src/dsp/dec_mips_dsp_r2.c16
-rw-r--r--src/dsp/dec_msa.c10
-rw-r--r--src/dsp/dec_neon.c21
-rw-r--r--src/dsp/dec_sse2.c34
-rw-r--r--src/dsp/dsp.h5
-rw-r--r--src/dsp/enc.c22
-rw-r--r--src/dsp/enc_mips32.c20
-rw-r--r--src/dsp/enc_mips_dsp_r2.c4
-rw-r--r--src/dsp/enc_neon.c9
-rw-r--r--src/dsp/enc_sse2.c242
-rw-r--r--src/dsp/filters.c36
-rw-r--r--src/dsp/filters_mips_dsp_r2.c26
-rw-r--r--src/dsp/filters_msa.c22
-rw-r--r--src/dsp/filters_neon.c26
-rw-r--r--src/dsp/filters_sse2.c26
-rw-r--r--src/dsp/lossless.c1
-rw-r--r--src/dsp/lossless.h6
-rw-r--r--src/dsp/lossless_common.h6
-rw-r--r--src/dsp/lossless_enc.c24
-rw-r--r--src/dsp/lossless_enc_mips32.c14
-rw-r--r--src/dsp/lossless_enc_neon.c2
-rw-r--r--src/dsp/lossless_enc_sse41.c54
-rw-r--r--src/dsp/lossless_neon.c8
-rw-r--r--src/dsp/mips_macro.h42
-rw-r--r--src/dsp/msa_macro.h32
-rw-r--r--src/dsp/neon.h4
-rw-r--r--src/dsp/quant.h5
-rw-r--r--src/dsp/rescaler.c1
-rw-r--r--src/dsp/rescaler_neon.c2
-rw-r--r--src/dsp/ssim.c1
-rw-r--r--src/dsp/upsampling.c1
-rw-r--r--src/dsp/upsampling_neon.c2
-rw-r--r--src/dsp/upsampling_sse2.c12
-rw-r--r--src/dsp/upsampling_sse41.c8
-rw-r--r--src/dsp/yuv.c1
-rw-r--r--src/enc/alpha_enc.c27
-rw-r--r--src/enc/analysis_enc.c4
-rw-r--r--src/enc/backward_references_enc.c9
-rw-r--r--src/enc/frame_enc.c12
-rw-r--r--src/enc/histogram_enc.c36
-rw-r--r--src/enc/picture_csp_enc.c5
-rw-r--r--src/enc/picture_enc.c2
-rw-r--r--src/enc/picture_rescale_enc.c20
-rw-r--r--src/enc/syntax_enc.c6
-rw-r--r--src/enc/vp8i_enc.h2
-rw-r--r--src/enc/vp8l_enc.c422
-rw-r--r--src/enc/vp8li_enc.h4
-rw-r--r--src/enc/webp_enc.c10
-rw-r--r--src/libwebp.rc10
-rw-r--r--src/libwebpdecoder.rc10
-rw-r--r--src/mux/Makefile.am2
-rw-r--r--src/mux/anim_encode.c42
-rw-r--r--src/mux/libwebpmux.rc10
-rw-r--r--src/mux/muxedit.c19
-rw-r--r--src/mux/muxi.h2
-rw-r--r--src/mux/muxread.c29
-rw-r--r--src/utils/Makefile.am2
-rw-r--r--src/utils/bit_reader_utils.c3
-rw-r--r--src/utils/bit_reader_utils.h3
-rw-r--r--src/utils/huffman_utils.c100
-rw-r--r--src/utils/huffman_utils.h34
-rw-r--r--src/utils/palette.c402
-rw-r--r--src/utils/palette.h60
-rw-r--r--src/utils/utils.c66
-rw-r--r--src/utils/utils.h3
-rw-r--r--src/webp/decode.h119
-rw-r--r--src/webp/demux.h46
-rw-r--r--src/webp/encode.h83
-rw-r--r--src/webp/mux.h91
-rw-r--r--src/webp/mux_types.h3
-rw-r--r--src/webp/types.h37
-rw-r--r--tests/fuzzer/advanced_api_fuzzer.c13
-rw-r--r--tests/fuzzer/animdecoder_fuzzer.cc23
-rw-r--r--tests/fuzzer/animencoder_fuzzer.cc15
-rw-r--r--tests/fuzzer/enc_dec_fuzzer.cc72
-rw-r--r--tests/fuzzer/fuzz_utils.h18
-rw-r--r--tests/fuzzer/huffman_fuzzer.c65
-rw-r--r--tests/fuzzer/makefile.unix6
-rw-r--r--tests/fuzzer/mux_demux_api_fuzzer.c14
-rw-r--r--tests/fuzzer/simple_api_fuzzer.c15
-rw-r--r--webp_js/README.md23
-rw-r--r--webp_js/index.html2
-rw-r--r--webp_js/index_wasm.html50
-rwxr-xr-xxcframeworkbuild.sh31
162 files changed, 10623 insertions, 2182 deletions
diff --git a/.cmake-format.py b/.cmake-format.py
new file mode 100644
index 00000000..71043af1
--- /dev/null
+++ b/.cmake-format.py
@@ -0,0 +1,240 @@
+# ----------------------------------
+# Options affecting listfile parsing
+# ----------------------------------
+with section("parse"):
+
+ # Specify structure for custom cmake functions
+ additional_commands = { 'foo': { 'flags': ['BAR', 'BAZ'],
+ 'kwargs': {'DEPENDS': '*', 'HEADERS': '*', 'SOURCES': '*'}}}
+
+ # Override configurations per-command where available
+ override_spec = {}
+
+ # Specify variable tags.
+ vartags = []
+
+ # Specify property tags.
+ proptags = []
+
+# -----------------------------
+# Options affecting formatting.
+# -----------------------------
+with section("format"):
+
+ # Disable formatting entirely, making cmake-format a no-op
+ disable = False
+
+ # How wide to allow formatted cmake files
+ line_width = 80
+
+ # How many spaces to tab for indent
+ tab_size = 2
+
+ # If true, lines are indented using tab characters (utf-8 0x09) instead of
+ # <tab_size> space characters (utf-8 0x20). In cases where the layout would
+ # require a fractional tab character, the behavior of the fractional
+ # indentation is governed by <fractional_tab_policy>
+ use_tabchars = False
+
+ # If <use_tabchars> is True, then the value of this variable indicates how
+ # fractional indentions are handled during whitespace replacement. If set to
+ # 'use-space', fractional indentation is left as spaces (utf-8 0x20). If set
+ # to `round-up` fractional indentation is replaced with a single tab character
+ # (utf-8 0x09) effectively shifting the column to the next tabstop
+ fractional_tab_policy = 'use-space'
+
+ # If an argument group contains more than this many sub-groups (parg or kwarg
+ # groups) then force it to a vertical layout.
+ max_subgroups_hwrap = 3
+
+ # If a positional argument group contains more than this many arguments, then
+ # force it to a vertical layout.
+ max_pargs_hwrap = 6
+
+ # If a cmdline positional group consumes more than this many lines without
+ # nesting, then invalidate the layout (and nest)
+ max_rows_cmdline = 2
+
+ # If true, separate flow control names from their parentheses with a space
+ separate_ctrl_name_with_space = False
+
+ # If true, separate function names from parentheses with a space
+ separate_fn_name_with_space = False
+
+ # If a statement is wrapped to more than one line, than dangle the closing
+ # parenthesis on its own line.
+ dangle_parens = False
+
+ # If the trailing parenthesis must be 'dangled' on its on line, then align it
+ # to this reference: `prefix`: the start of the statement, `prefix-indent`:
+ # the start of the statement, plus one indentation level, `child`: align to
+ # the column of the arguments
+ dangle_align = 'prefix'
+
+ # If the statement spelling length (including space and parenthesis) is
+ # smaller than this amount, then force reject nested layouts.
+ min_prefix_chars = 4
+
+ # If the statement spelling length (including space and parenthesis) is larger
+ # than the tab width by more than this amount, then force reject un-nested
+ # layouts.
+ max_prefix_chars = 10
+
+ # If a candidate layout is wrapped horizontally but it exceeds this many
+ # lines, then reject the layout.
+ max_lines_hwrap = 2
+
+ # What style line endings to use in the output.
+ line_ending = 'unix'
+
+ # Format command names consistently as 'lower' or 'upper' case
+ command_case = 'canonical'
+
+ # Format keywords consistently as 'lower' or 'upper' case
+ keyword_case = 'unchanged'
+
+ # A list of command names which should always be wrapped
+ always_wrap = []
+
+ # If true, the argument lists which are known to be sortable will be sorted
+ # lexicographicall
+ enable_sort = True
+
+ # If true, the parsers may infer whether or not an argument list is sortable
+ # (without annotation).
+ autosort = False
+
+ # By default, if cmake-format cannot successfully fit everything into the
+ # desired linewidth it will apply the last, most agressive attempt that it
+ # made. If this flag is True, however, cmake-format will print error, exit
+ # with non-zero status code, and write-out nothing
+ require_valid_layout = False
+
+ # A dictionary mapping layout nodes to a list of wrap decisions. See the
+ # documentation for more information.
+ layout_passes = {}
+
+# ------------------------------------------------
+# Options affecting comment reflow and formatting.
+# ------------------------------------------------
+with section("markup"):
+
+ # What character to use for bulleted lists
+ bullet_char = '*'
+
+ # What character to use as punctuation after numerals in an enumerated list
+ enum_char = '.'
+
+ # If comment markup is enabled, don't reflow the first comment block in each
+ # listfile. Use this to preserve formatting of your copyright/license
+ # statements.
+ first_comment_is_literal = True
+
+ # If comment markup is enabled, don't reflow any comment block which matches
+ # this (regex) pattern. Default is `None` (disabled).
+ literal_comment_pattern = None
+
+ # Regular expression to match preformat fences in comments default=
+ # ``r'^\s*([`~]{3}[`~]*)(.*)$'``
+ fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
+
+ # Regular expression to match rulers in comments default=
+ # ``r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'``
+ ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
+
+ # If a comment line matches starts with this pattern then it is explicitly a
+ # trailing comment for the preceeding argument. Default is '#<'
+ explicit_trailing_pattern = '#<'
+
+ # If a comment line starts with at least this many consecutive hash
+ # characters, then don't lstrip() them off. This allows for lazy hash rulers
+ # where the first hash char is not separated by space
+ hashruler_min_length = 10
+
+ # If true, then insert a space between the first hash char and remaining hash
+ # chars in a hash ruler, and normalize its length to fill the column
+ canonicalize_hashrulers = True
+
+ # enable comment markup parsing and reflow
+ enable_markup = True
+
+# ----------------------------
+# Options affecting the linter
+# ----------------------------
+with section("lint"):
+
+ # a list of lint codes to disable
+ disabled_codes = []
+
+ # regular expression pattern describing valid function names
+ function_pattern = '[0-9a-z_]+'
+
+ # regular expression pattern describing valid macro names
+ macro_pattern = '[0-9A-Z_]+'
+
+ # regular expression pattern describing valid names for variables with global
+ # (cache) scope
+ global_var_pattern = '[A-Z][0-9A-Z_]+'
+
+ # regular expression pattern describing valid names for variables with global
+ # scope (but internal semantic)
+ internal_var_pattern = '_[A-Z][0-9A-Z_]+'
+
+ # regular expression pattern describing valid names for variables with local
+ # scope
+ local_var_pattern = '[a-z][a-z0-9_]+'
+
+ # regular expression pattern describing valid names for privatedirectory
+ # variables
+ private_var_pattern = '_[0-9a-z_]+'
+
+ # regular expression pattern describing valid names for public directory
+ # variables
+ public_var_pattern = '[A-Z][0-9A-Z_]+'
+
+ # regular expression pattern describing valid names for function/macro
+ # arguments and loop variables.
+ argument_var_pattern = '[a-z][a-z0-9_]+'
+
+ # regular expression pattern describing valid names for keywords used in
+ # functions or macros
+ keyword_pattern = '[A-Z][0-9A-Z_]+'
+
+ # In the heuristic for C0201, how many conditionals to match within a loop in
+ # before considering the loop a parser.
+ max_conditionals_custom_parser = 2
+
+ # Require at least this many newlines between statements
+ min_statement_spacing = 1
+
+ # Require no more than this many newlines between statements
+ max_statement_spacing = 2
+ max_returns = 6
+ max_branches = 12
+ max_arguments = 5
+ max_localvars = 15
+ max_statements = 50
+
+# -------------------------------
+# Options affecting file encoding
+# -------------------------------
+with section("encode"):
+
+ # If true, emit the unicode byte-order mark (BOM) at the start of the file
+ emit_byteorder_mark = False
+
+ # Specify the encoding of the input file. Defaults to utf-8
+ input_encoding = 'utf-8'
+
+ # Specify the encoding of the output file. Defaults to utf-8. Note that cmake
+ # only claims to support utf-8 so be careful when using anything else
+ output_encoding = 'utf-8'
+
+# -------------------------------------
+# Miscellaneous configurations options.
+# -------------------------------------
+with section("misc"):
+
+ # A dictionary containing any per-command configuration overrides. Currently
+ # only `command_case` is supported.
+ per_command = {}
diff --git a/.mailmap b/.mailmap
index ddcf1a7a..cf26f1df 100644
--- a/.mailmap
+++ b/.mailmap
@@ -16,3 +16,4 @@ James Zern <jzern@google.com>
Roberto Alanis <alanisbaez@google.com>
Brian Ledger <brianpl@google.com>
Maryla Ustarroz-Calonge <maryla@google.com>
+Yannis Guyon <yguyon@google.com>
diff --git a/AUTHORS b/AUTHORS
index 2f0c537d..4cbe9766 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,6 +2,8 @@ Contributors:
- Aidan O'Loan (aidanol at gmail dot com)
- Alan Browning (browning at google dot com)
- Alexandru Ardelean (ardeleanalex at gmail dot com)
+- Anuraag Agrawal (anuraaga at gmail dot com)
+- Arthur Eubanks (aeubanks at google dot com)
- Brian Ledger (brianpl at google dot com)
- Charles Munger (clm at google dot com)
- Cheng Yi (cyi at google dot com)
@@ -19,6 +21,8 @@ Contributors:
- Jehan (jehan at girinstud dot io)
- Jeremy Maitin-Shepard (jbms at google dot com)
- Johann Koenig (johann dot koenig at duck dot com)
+- Jonathan Grant (jgrantinfotech at gmail dot com)
+- Jonliu1993 (13720414433 at 163 dot com)
- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
- Jyrki Alakuijala (jyrki at google dot com)
- Konstantin Ivlev (tomskside at gmail dot com)
@@ -28,12 +32,16 @@ Contributors:
- Marcin Kowalczyk (qrczak at google dot com)
- Martin Olsson (mnemo at minimum dot se)
- Maryla Ustarroz-Calonge (maryla at google dot com)
+- Masahiro Hanada (hanada at atmark-techno dot com)
- Mikołaj Zalewski (mikolajz at google dot com)
- Mislav Bradac (mislavm at google dot com)
+- natewood (natewood at fb dot com)
- Nico Weber (thakis at chromium dot org)
- Noel Chromium (noel at chromium dot org)
+- Nozomi Isozaki (nontan at pixiv dot co dot jp)
- Oliver Wolff (oliver dot wolff at qt dot io)
- Owen Rodley (orodley at google dot com)
+- Ozkan Sezer (sezeroz at gmail dot com)
- Parag Salasakar (img dot mips1 at gmail dot com)
- Pascal Massimino (pascal dot massimino at gmail dot com)
- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org)
@@ -47,6 +55,7 @@ Contributors:
- Somnath Banerjee (somnath dot banerjee at gmail dot com)
- Sriraman Tallam (tmsriram at google dot com)
- Tamar Levy (tamar dot levy at intel dot com)
+- Thiago Perrotta (tperrotta at google dot com)
- Timothy Gu (timothygu99 at gmail dot com)
- Urvang Joshi (urvang at google dot com)
- Vikas Arora (vikasa at google dot com)
diff --git a/Android.bp b/Android.bp
index ace6a9e9..9ecd22d6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -214,6 +214,7 @@ cc_library_static {
"src/utils/color_cache_utils.c",
"src/utils/filters_utils.c",
"src/utils/huffman_utils.c",
+ "src/utils/palette.c",
"src/utils/quant_levels_dec_utils.c",
"src/utils/random_utils.c",
"src/utils/rescaler_utils.c",
diff --git a/Android.mk b/Android.mk
index c7bcb0f5..a5fd02b6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -164,6 +164,7 @@ utils_dec_srcs := \
src/utils/color_cache_utils.c \
src/utils/filters_utils.c \
src/utils/huffman_utils.c \
+ src/utils/palette.c \
src/utils/quant_levels_dec_utils.c \
src/utils/random_utils.c \
src/utils/rescaler_utils.c \
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f378db5b..b785a8e6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -51,6 +51,8 @@ option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
OFF)
set(WEBP_BITTRACE "0" CACHE STRING "Bit trace mode (0=none, 1=bit, 2=bytes)")
set_property(CACHE WEBP_BITTRACE PROPERTY STRINGS 0 1 2)
+option(WEBP_ENABLE_WUNUSED_RESULT "Add [[nodiscard]] to some functions. \
+ CMake must be at least 3.21 to force C23" OFF)
if(WEBP_LINK_STATIC)
if(WIN32)
@@ -82,7 +84,8 @@ if(WEBP_BUILD_WEBP_JS)
set(WEBP_USE_THREAD OFF)
if(WEBP_ENABLE_SIMD)
- message("wasm2js does not support SIMD, disabling webp.js generation.")
+ message(NOTICE
+ "wasm2js does not support SIMD, disabling webp.js generation.")
endif()
endif()
@@ -98,6 +101,16 @@ if(NOT CMAKE_BUILD_TYPE)
endif()
# Include dependencies.
+if(WEBP_BUILD_ANIM_UTILS
+ OR WEBP_BUILD_CWEBP
+ OR WEBP_BUILD_DWEBP
+ OR WEBP_BUILD_EXTRAS
+ OR WEBP_BUILD_GIF2WEBP
+ OR WEBP_BUILD_IMG2WEBP)
+ set(WEBP_FIND_IMG_LIBS TRUE)
+else()
+ set(WEBP_FIND_IMG_LIBS FALSE)
+endif()
include(cmake/deps.cmake)
include(GNUInstallDirs)
@@ -122,7 +135,7 @@ if(WEBP_UNICODE)
add_definitions(-DUNICODE -D_UNICODE)
endif()
-if(MSVC AND BUILD_SHARED_LIBS)
+if(WIN32 AND BUILD_SHARED_LIBS)
add_definitions(-DWEBP_DLL)
endif()
@@ -150,7 +163,20 @@ if(MSVC)
set(CMAKE_STATIC_LIBRARY_PREFIX "${webp_libname_prefix}")
endif()
-set(CMAKE_C_VISIBILITY_PRESET hidden)
+if(NOT WIN32)
+ set(CMAKE_C_VISIBILITY_PRESET hidden)
+endif()
+
+if(WEBP_ENABLE_WUNUSED_RESULT)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21.0)
+ set(CMAKE_C_STANDARD 23)
+ else()
+ unset(CMAKE_C_STANDARD)
+ add_compile_options($<$<COMPILE_LANGUAGE:C>:-std=gnu2x>)
+ endif()
+ add_compile_options(-Wunused-result)
+ add_definitions(-DWEBP_ENABLE_NODISCARD=1)
+endif()
# ##############################################################################
# Android only.
@@ -452,6 +478,7 @@ endif()
if(WEBP_BUILD_ANIM_UTILS
OR WEBP_BUILD_CWEBP
OR WEBP_BUILD_DWEBP
+ OR WEBP_BUILD_EXTRAS
OR WEBP_BUILD_GIF2WEBP
OR WEBP_BUILD_IMG2WEBP
OR WEBP_BUILD_VWEBP
@@ -488,6 +515,8 @@ if(WEBP_BUILD_ANIM_UTILS
TARGET exampleutil imageioutil imagedec imageenc
PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/src)
+ target_include_directories(imagedec PRIVATE ${WEBP_DEP_IMG_INCLUDE_DIRS})
+ target_include_directories(imageenc PRIVATE ${WEBP_DEP_IMG_INCLUDE_DIRS})
endif()
if(WEBP_BUILD_DWEBP)
@@ -546,7 +575,8 @@ if(WEBP_BUILD_IMG2WEBP)
add_executable(img2webp ${IMG2WEBP_SRCS})
target_link_libraries(img2webp exampleutil imagedec imageioutil webp
libwebpmux)
- target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
+ target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src
+ ${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS img2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
@@ -626,44 +656,82 @@ if(WEBP_BUILD_EXTRAS)
${CMAKE_CURRENT_BINARY_DIR})
# vwebp_sdl
- find_package(SDL)
- if(WEBP_BUILD_VWEBP AND SDL_FOUND)
+ find_package(SDL2 QUIET)
+ if(WEBP_BUILD_VWEBP AND SDL2_FOUND)
add_executable(vwebp_sdl ${VWEBP_SDL_SRCS})
- target_link_libraries(vwebp_sdl ${SDL_LIBRARY} imageioutil webp)
+ target_link_libraries(vwebp_sdl ${SDL2_LIBRARIES} imageioutil webp)
target_include_directories(
vwebp_sdl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
- ${CMAKE_CURRENT_BINARY_DIR}/src ${SDL_INCLUDE_DIR})
+ ${CMAKE_CURRENT_BINARY_DIR}/src ${SDL2_INCLUDE_DIRS})
set(WEBP_HAVE_SDL 1)
target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL)
+
+ set(CMAKE_REQUIRED_INCLUDES "${SDL2_INCLUDE_DIRS}")
+ check_c_source_compiles(
+ "
+ #define SDL_MAIN_HANDLED
+ #include \"SDL.h\"
+ int main(void) {
+ return 0;
+ }
+ "
+ HAVE_JUST_SDL_H)
+ set(CMAKE_REQUIRED_INCLUDES)
+ if(HAVE_JUST_SDL_H)
+ target_compile_definitions(vwebp_sdl PRIVATE WEBP_HAVE_JUST_SDL_H)
+ endif()
endif()
endif()
if(WEBP_BUILD_WEBP_JS)
+ # The default stack size changed from 5MB to 64KB in 3.1.27. See
+ # https://crbug.com/webp/614.
+ if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "3.1.27")
+ # TOTAL_STACK size was renamed to STACK_SIZE in 3.1.27. The old name was
+ # kept for compatibility, but prefer the new one in case it is removed in
+ # the future.
+ set(emscripten_stack_size "-sSTACK_SIZE=5MB")
+ else()
+ set(emscripten_stack_size "-sTOTAL_STACK=5MB")
+ endif()
+ find_package(SDL2 REQUIRED)
# wasm2js does not support SIMD.
if(NOT WEBP_ENABLE_SIMD)
# JavaScript version
add_executable(webp_js ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
- target_link_libraries(webp_js webpdecoder SDL)
+ target_link_libraries(webp_js webpdecoder SDL2)
target_include_directories(webp_js PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set(WEBP_HAVE_SDL 1)
set_target_properties(
webp_js
- PROPERTIES LINK_FLAGS "-sWASM=0 \
+ PROPERTIES
+ # Emscripten puts -sUSE_SDL2=1 in this variable, though it's needed at
+ # compile time to ensure the headers are downloaded.
+ COMPILE_OPTIONS "${SDL2_LIBRARIES}"
+ LINK_FLAGS
+ "-sWASM=0 ${emscripten_stack_size} \
-sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
- -sEXPORTED_RUNTIME_METHODS=cwrap")
+ -sEXPORTED_RUNTIME_METHODS=cwrap ${SDL2_LIBRARIES} \
+ -sALLOW_MEMORY_GROWTH")
set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp)
target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
endif()
# WASM version
add_executable(webp_wasm ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c)
- target_link_libraries(webp_wasm webpdecoder SDL)
+ target_link_libraries(webp_wasm webpdecoder SDL2)
target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(
webp_wasm
- PROPERTIES LINK_FLAGS "-sWASM=1 \
+ PROPERTIES
+ # Emscripten puts -sUSE_SDL2=1 in this variable, though it's needed at
+ # compile time to ensure the headers are downloaded.
+ COMPILE_OPTIONS "${SDL2_LIBRARIES}"
+ LINK_FLAGS
+ "-sWASM=1 ${emscripten_stack_size} \
-sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
- -sEXPORTED_RUNTIME_METHODS=cwrap")
+ -sEXPORTED_RUNTIME_METHODS=cwrap ${SDL2_LIBRARIES} \
+ -sALLOW_MEMORY_GROWTH")
target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)
@@ -742,7 +810,8 @@ endif()
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/WebPConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake
- INSTALL_DESTINATION ${ConfigPackageLocation})
+ INSTALL_DESTINATION ${ConfigPackageLocation}
+ PATH_VARS CMAKE_INSTALL_INCLUDEDIR)
# Install the generated CMake files.
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7a73a303..9540f34f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -19,10 +19,59 @@ again.
All submissions, including submissions by project members, require review. We
use a [Gerrit](https://www.gerritcodereview.com) instance hosted at
-https://chromium-review.googlesource.com for this purpose. See the
+https://chromium-review.googlesource.com for this purpose.
+
+## Sending patches
+
+The basic git workflow for modifying libwebp code and sending for review is:
+
+1. Get the latest version of the repository locally:
+
+ ```sh
+ git clone https://chromium.googlesource.com/webm/libwebp && cd libwebp
+ ```
+
+2. Copy the commit-msg script into ./git/hooks (this will add an ID to all of
+ your commits):
+
+ ```sh
+ curl -Lo .git/hooks/commit-msg https://chromium-review.googlesource.com/tools/hooks/commit-msg && chmod u+x .git/hooks/commit-msg
+ ```
+
+3. Modify the local copy of libwebp. Make sure the code
+ [builds successfully](https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/building.md#cmake).
+
+4. Choose a short and representative commit message:
+
+ ```sh
+ git commit -a -m "Set commit message here"
+ ```
+
+5. Send the patch for review:
+
+ ```sh
+ git push https://chromium-review.googlesource.com/webm/libwebp HEAD:refs/for/main
+ ```
+
+ Go to https://chromium-review.googlesource.com to view your patch and
+ request a review from the maintainers.
+
+See the
[WebM Project page](https://www.webmproject.org/code/contribute/submitting-patches/)
for additional details.
+## Code Style
+
+The C code style is based on the
+[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) and
+`clang-format --style=Google`, though this project doesn't use the tool to
+enforce the formatting.
+
+CMake files are formatted with
+[cmake-format](https://cmake-format.readthedocs.io/en/latest/). `cmake-format
+-i` can be used to format individual files, it will use the settings from
+`.cmake-format.py`.
+
## Community Guidelines
This project follows
diff --git a/ChangeLog b/ChangeLog
index 00ef6175..e0d920ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,232 @@
+8a6a55bb update NEWS
+cf7c5a5d provide a way to opt-out/override WEBP_NODISCARD
+cc34288a update ChangeLog (tag: v1.4.0-rc1)
+f13c0886 NEWS: fix date
+74555950 Merge "vwebp: fix window title when options are given" into 1.4.0
+d781646c vwebp: fix window title when options are given
+c2e394de update NEWS
+f6d15cb7 bump version to 1.4.0
+57c388b8 update AUTHORS
+b3d1b2cb Merge changes I26f4aa22,I83386b6c,I320ed1a2 into main
+07216886 webp-container-spec: fix VP8 chunk ref ('VP8'->'VP8 ')
+f88666eb webp_js/*.html: fix canvas mapping
+e2c8f233 cmake,wasm: simplify SDL2 related flags
+d537cd37 cmake: fix vwebp_sdl compile w/libsdl-org release
+6c484cbf CMakeLists.txt: add missing WEBP_BUILD_EXTRAS check
+7b0bc235 man/cwebp.1: add more detail to -partition_limit
+3c0011bb WebPMuxGetChunk: add an assert
+955a3d14 Merge "muxread,MuxGet: add an assert" into main
+00abc000 muxread,MuxGet: add an assert
+40e85a0b Have the window title reflect the filename.
+1bf46358 man/cwebp.1: clarify -pass > 1 behavior w/o -size/-psnr
+eba03acb webp-container-spec: replace 'above' with 'earlier'
+a16d30cb webp-container-spec: clarify chunk order requirements
+8a7e9112 Merge "CMakeLists.txt: apply cmake-format" into main
+7fac6c1b Merge "Copy C code to not have multiplication overflow" into main
+e2922e43 Merge "Check for the presence of the ANDROID_ABI variable" into main
+501d9274 Copy C code to not have multiplication overflow
+fba7d62e CMakeLists.txt: apply cmake-format
+661c1b66 Merge "windows exports: use dllexport attribute, instead of visibility." into main
+8487860a windows exports: use dllexport attribute, instead of visibility.
+8ea678b9 webp/mux.h: data lifetime note w/copy_data=0
+79e05c7f Check for the presence of the ANDROID_ABI variable
+45f995a3 Expose functions for managing non-image chunks on WebPAnimEncoder
+1fb9f3dc gifdec: fix ErrorGIFNotAvailable() declaration
+4723db65 cosmetics: s/SANITY_CHECK/DCHECK/
+f4b9bc9e clear -Wextra-semi-stmt warnings
+713982b8 Limit animdecoder_fuzzer to 320MB
+cbe825e4 cmake: fix sharpyuv simd files' build
+f99305e9 Makefile.vc: add ARM64 support
+5efd6300 mv SharpYuvEstimate420Risk to extras/
+e78e924f Makefile.vc: add sharpyuv_risk_table.obj
+d7a0506d Add YUV420 riskiness metric.
+89c5b917 Merge "BuildHuffmanTable check sorted[] array bounds before writing" into main
+34c80749 Remove alpha encoding pessimization.
+13d9c30b Add a WEBP_NODISCARD
+24d7f9cb Switch code to SDL2.
+0b56dedc BuildHuffmanTable check sorted[] array bounds before writing
+a429c0de sharpyuv: convert some for() to do/while
+f0cd7861 DoSharpArgbToYuv: remove constant from loop
+339231cc SharpYuvConvertWithOptions,cosmetics: fix formatting
+307071f1 Remove medium/large code model-specific inline asm
+deadc339 Fix transfer functions where toGamma and toLinear are swapped.
+e7b78d43 Merge "Fix bug in FromLinearLog100." into main
+15a1309e Merge "webp-lossless-bitstream-spec: delete extra blank line" into main
+54ca9752 Fix bug in FromLinearLog100.
+d2cb2d8c Dereference after NULL check.
+e9d50107 webp-lossless-bitstream-spec: delete extra blank line
+78657971 Merge changes Ief442c90,Ie6e9c9a5 into main
+e30a5884 webp-lossless-bitstream-spec: update variable names
+09ca1368 Merge "webp-container-spec: change assert to MUST be TRUE" into main
+38cb4fc0 iosbuild,xcframeworkbuild: add SharpYuv framework
+40afa926 webp-lossless-bitstream-spec: simplify abstract
+9db21143 webp-container-spec: change assert to MUST be TRUE
+cdbf88ae Fix typo in API docs for incremental decoding
+05c46984 Reformat vcpkg build instructions.
+8534f539 Merge "Never send VP8_STATUS_SUSPENDED back in non-incremental." into main
+35e197bd Never send VP8_STATUS_SUSPENDED back in non-incremental.
+61441425 Add vcpkg installation instructions
+dce8397f Fix next is invalid pointer when WebPSafeMalloc fails
+57c58105 Cmake: wrong public macro WEBP_INCLUDE_DIRS
+c1ffd9ac Merge "vp8l_enc: fix non-C90 code" into main
+a3965948 Merge changes If628bb93,Ic79f6309,I45f0db23 into main
+f80e9b7e vp8l_enc: fix non-C90 code
+accd141d Update lossless spec for two simple codes.
+ac17ffff Fix non-C90 code.
+433c7dca Fix static analyzer warnings.
+5fac76cf Merge tag 'v1.3.2'
+ca332209 update ChangeLog (tag: v1.3.2)
+1ace578c update NEWS
+63234c42 bump version to 1.3.2
+a35ea50d Add a fuzzer for ReadHuffmanCodes
+95ea5226 Fix invalid incremental decoding check.
+2af26267 Fix OOB write in BuildHuffmanTable.
+902bc919 Fix OOB write in BuildHuffmanTable.
+7ba44f80 Homogenize "__asm__ volatile" vs "asm volatile"
+68e27135 webp-container-spec: reorder example chunk layout
+943b932a Merge changes I6a4d0a04,Ibc37b91e into main
+1cc94f95 decode.h: wrap idec example in /* */
+63acdd1e decode.h: fix decode example
+aac5c5d0 ReadHuffmanCode: rm redundant num code lengths check
+a2de25f6 webp-lossless-bitstream-spec: normalize list item case
+68820f0e webp-lossless-bitstream-spec: normalize pixel ref
+cdb31aa8 webp-lossless-bitstream-spec: add missing periods
+0535a8cf webp-lossless-bitstream-spec: fix grammar
+b6c4ce26 normalize numbered list item format
+dd7364c3 Merge "palette.c: fix msvc warnings" into main
+c63c5df6 palette.c: fix msvc warnings
+0a2cad51 webp-container-spec: move terms from intro section
+dd88d2ff webp-lossless-bitstream-spec: color_cache -> color cache
+6e750547 Merge changes I644d7d39,Icf05491e,Ic02e6652,I63b11258 into main
+67a7cc2b webp-lossless-bitstream-spec: fix code blocks
+1432ebba Refactor palette sorting computation.
+cd436142 webp-lossless-bitstream-spec: block -> chunk
+3cb66f64 webp-lossless-bitstream-spec: add some missing commas
+56471a53 webp-lossless-bitstream-spec: normalize item text in 5.1
+af7fbfd2 vp8l_dec,ReadTransform: improve error status reporting
+7d8e0896 vp8l_dec: add VP8LSetError()
+a71ce1cf animencoder_fuzzer: fix error check w/Nallocfuzz
+e94b36d6 webp-lossless-bitstream-spec: relocate details from 5.1
+84628e56 webp-lossless-bitstream-spec: clarify image width changes
+ee722997 alpha_dec: add missing VP8SetError()
+0081693d enc_dec_fuzzer: use WebPDecode()
+0fcb311c enc_dec_fuzzer: fix WebPEncode/pic.error_code check
+982c177c webp-lossless-bitstream-spec: fix struct member refs
+56cf5625 webp-lossless-bitstream-spec: use RFC 7405 for ABNF
+6c6b3fd3 webp-lossless-bitstream-spec,cosmetics: delete blank lines
+29b9eb15 Merge changes Id56ca4fd,I662bd1d7 into main
+47c0af8d ReadHuffmanCodes: rm max_alphabet_size calc
+b92deba3 animencoder_fuzzer: no WebPAnimEncoderAssemble check w/nallocfuzz
+6be9bf8b animencoder_fuzzer: fix leak on alloc failure
+5c965e55 vp8l_dec,cosmetics: add some /*param=*/ comments
+e4fc2f78 webp-lossless-bitstream-spec: add validity note for max_symbol
+71916726 webp-lossless-bitstream-spec: fix max_symbol definition
+eac3bd5c Have the palette code be in its own file.
+e2c85878 Add an initializer for the SharpYuvOptions struct.
+4222b006 Merge tag 'v1.3.1'
+25d94f47 Implement more transfer functions in libsharpyuv
+2153a679 Merge changes Id0300937,I5dba5ccf,I57bb68e0,I2dba7b4e,I172aca36, ... into main
+4298e976 webp-lossless-bitstream-spec: add PredictorTransformOutput
+cd7e02be webp-lossless-bitstream-spec: fix RIFF-header ABNF
+6c3845f9 webp-lossless-bitstream-spec: split LZ77 Backward Ref section
+7f1b6799 webp-lossless-bitstream-spec: split Meta Prefix Codes section
+7b634d8f webp-lossless-bitstream-spec: note transform order
+6d6d4915 webp-lossless-bitstream-spec: update transformations text
+fd7bb21c update ChangeLog (tag: v1.3.1-rc2, tag: v1.3.1)
+e1adea50 update NEWS
+6b1c722a lossless_common.h,cosmetics: fix a typo
+08d60d60 webp-lossless-bitstream-spec: split code length section
+7a12afcc webp-lossless-bitstream-spec: rm unused anchor
+43393320 enc/*: normalize WebPEncodingSetError() calls
+287fdefe enc/*: add missing WebPEncodingSetError() calls
+c3bd7cff EncodeAlphaInternal: add missing error check
+14a9dbfb webp-lossless-bitstream-spec: refine single node text
+64819c7c Implement ExtractGreen_SSE2
+d49cfbb3 vp8l_enc,WriteImage: add missing error check
+2e5a9ec3 muxread,MuxImageParse: add missing error checks
+ebb6f949 cmake,emscripten: explicitly set stack size
+59a2b1f9 WebPDecodeYUV: check u/v/stride/uv_stride ptrs
+8e965ccb Call png_get_channels() to see if image has alpha
+fe80fbbd webp-container-spec: add some missing commas
+e8ed3176 Merge "treat FILTER_NONE as a regular Unfilter[] call" into main
+03a7a048 webp-lossless-bitstream-spec: rm redundant statement
+c437c7aa webp-lossless-bitstream-spec: mv up prefix code group def
+e4f17a31 webp-lossless-bitstream-spec: fix section reference
+e2ecd5e9 webp-lossless-bitstream-spec: clarify ABNF syntax
+8b55425a webp-lossless-bitstream-spec: refine pixel copy text
+29c9f2d4 webp-lossless-bitstream-spec: minor wording updates
+6b02f660 treat FILTER_NONE as a regular Unfilter[] call
+7f75c91c webp-container-spec: fix location of informative msg
+f6499943 webp-container-spec: consistently quote FourCCs
+49918af3 webp-container-spec: minor wording updates
+7f0a3419 update ChangeLog (tag: v1.3.1-rc1)
+bab7efbe update NEWS
+7138bf8f bump version to 1.3.1
+435b4ded update AUTHORS
+47351229 update .mailmap
+46bc4fc9 Merge "Switch ExtraCost to ints and implement it in SSE." into main
+828b4ce0 Switch ExtraCost to ints and implement it in SSE.
+ff6c7f4e CONTRIBUTING.md: add C style / cmake-format notes
+dd530437 add .cmake-format.py
+adbe2cb1 cmake,cosmetics: apply cmake-format
+15b36508 doc/webp-container-spec: rm future codec comment
+c369c4bf doc/webp-lossless-bitstream-spec: improve link text
+1de35f47 doc/webp-container-spec: don't use 'currently'
+bb06a16e doc/webp-container-spec: prefer present tense
+9f38b71e doc/webp-lossless-bitstream-spec: prefer present tense
+7acb6b82 doc/webp-container-spec: avoid i.e. & e.g.
+4967e7cd doc/webp-lossless-bitstream-spec: avoid i.e. & e.g.
+e3366659 Merge "Do not find_package image libraries if not needed." into main
+428588ef clarify single leaf node trees and use of canonical prefix coding
+709ec152 Do not find_package image libraries if not needed.
+8dd80ef8 fuzz_utils.h: lower kFuzzPxLimit w/ASan
+8f187b9f Clean message calls in CMake
+cba30078 WebPConfig.cmake.in: use calculated include path
+6cf9a76a Merge "webp-lossless-bitstream-spec: remove use of 'dynamics'" into main
+740943b2 Merge "Specialize and optimize ITransform_SSE2 using do_two" into main
+2d547e24 Compare kFuzzPxLimit to max_num_operations
+ac42dde1 Specialize and optimize ITransform_SSE2 using do_two
+17e0ef1d webp-lossless-bitstream-spec: remove use of 'dynamics'
+ed274371 neon.h,cosmetics: clear a couple lint warnings
+3fb82947 cpu.h,cosmetics: segment defines
+0c496a4f cpu.h: add WEBP_AARCH64
+8151f388 move VP8GetCPUInfo declaration to cpu.c
+916548c2 Make kFuzzPxLimit sanitizer dependent
+4070b271 advanced_api_fuzzer: reduce scaling limit
+761f49c3 Merge "webp-lossless-bitstream-spec: add missing bits to ABNF" into main
+84d04c48 webp-lossless-bitstream-spec: add missing bits to ABNF
+0696e1a7 advanced_api_fuzzer: reduce scaling limit
+93d88aa2 Merge "deps.cmake: remove unneeded header checks" into main
+118e0035 deps.cmake: remove unneeded header checks
+4c3d7018 webp-lossless-bitstream-spec: condense normal-prefix-code
+a6a09b32 webp-lossless-bitstream-spec: fix 2 code typos
+50ac4f7c Merge "cpu.h: enable NEON w/_M_ARM64EC" into main
+4b7d7b4f Add contribution instructions
+0afbd97b cpu.h: enable NEON w/_M_ARM64EC
+349f4353 Merge changes Ibd89e56b,Ic57e7f84,I89096614 into main
+8f7513b7 upsampling_neon.c: fix WEBP_SWAP_16BIT_CSP check
+cbf624b5 advanced_api_fuzzer: reduce scaling limit
+89edfdd1 Skip slow scaling in libwebp advanced_api_fuzzer
+859f19f7 Reduce libwebp advanced_api_fuzzer threshold
+a4f04835 Merge changes Ic389aaa2,I329ccd79 into main
+1275fac8 Makefile.vc: fix img2webp link w/dynamic cfg
+2fe27bb9 img2webp: normalize help output
+24bed3d9 cwebp: reflow -near_lossless help text
+0825faa4 img2webp: add -sharp_yuv/-near_lossless
+d64e6d7d Merge "PaletteSortModifiedZeng: fix leak on error" into main
+0e12a22d Merge "EncodeAlphaInternal: clear result->bw on error" into main
+0edbb6ea PaletteSortModifiedZeng: fix leak on error
+41ffe04e Merge "Update yapf style from "chromium" to "yapf"" into main
+2d9d9265 Update yapf style from "chromium" to "yapf"
+a486d800 EncodeAlphaInternal: clear result->bw on error
+1347a32d Skip big scaled advanced_api_fuzzer
+52b6f067 Fix scaling limit in advanced_api_fuzzer.c
+73618428 Limit scaling in libwebp advanced_api_fuzzer.c
+b54d21a0 Merge "CMakeLists.txt: allow CMAKE_INSTALL_RPATH to be set empty" into main
+31c28db5 libwebp{,demux,mux}.pc.in: Requires -> Requires.private
+d9a505ff CMakeLists.txt: allow CMAKE_INSTALL_RPATH to be set empty
+bdf33d03 Merge tag 'v1.3.0'
+b5577769 update ChangeLog (tag: v1.3.0-rc1, tag: v1.3.0)
0ba77244 update NEWS
e763eb1e bump version to 1.3.0
2a8686fc update AUTHORS
@@ -103,7 +332,7 @@ c626e7d5 cwebp: fix WebPPictureHasTransparency call
866e349c Merge tag 'v1.2.4'
c170df38 Merge "Create libsharpyuv.a in makefile.unix." into main
9d7ff74a Create libsharpyuv.a in makefile.unix.
-0d1f1254 update ChangeLog (tag: v1.2.4, origin/1.2.4)
+0d1f1254 update ChangeLog (tag: v1.2.4)
fcbc2d78 Merge "doc/*.txt: restrict code to 69 columns" into main
4ad0e189 Merge "webp-container-spec.txt: normalize fourcc spelling" into main
980d2488 update NEWS
@@ -1134,7 +1363,7 @@ b016cb91 NEON: faster fancy upsampling
f04eb376 Merge tag 'v0.5.2'
341d711c NEON: 5% faster conversion to RGB565 and RGBA4444
abb54827 remove Clang warnings with unused arch arguments.
-ece9684f update ChangeLog (tag: v0.5.2-rc2, tag: v0.5.2, origin/0.5.2)
+ece9684f update ChangeLog (tag: v0.5.2-rc2, tag: v0.5.2)
aa7744ca anim_util: quiet implicit conv warnings in 32-bit
d9120271 jpegdec: correct ContextFill signature
24eb3940 Remove some errors when compiling the code as C++.
@@ -1421,7 +1650,7 @@ bbb6ecd9 Merge "Add MSA optimized distortion functions"
c0991a14 io,EmitRescaledAlphaYUV: factor out a common expr
48bf5ed1 build.gradle: remove tab
bfef6c9f Merge tag 'v0.5.1'
-3d97bb75 update ChangeLog (tag: v0.5.1, origin/0.5.1)
+3d97bb75 update ChangeLog (tag: v0.5.1)
deb54d91 Clarify the expected 'config' lifespan in WebPIDecode()
435308e0 Add MSA optimized encoder transform functions
dce64bfa Add MSA optimized alpha filter functions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..b111a8a1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,53 @@
+Copyright (c) 2010, Google Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of Google nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Additional IP Rights Grant (Patents)
+------------------------------------
+
+"These implementations" means the copyrightable works that implement the WebM
+codecs distributed by Google as part of the WebM Project.
+
+Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge,
+royalty-free, irrevocable (except as stated in this section) patent license to
+make, have made, use, offer to sell, sell, import, transfer, and otherwise
+run, modify and propagate the contents of these implementations of WebM, where
+such license applies only to those patent claims, both currently owned by
+Google and acquired in the future, licensable by Google that are necessarily
+infringed by these implementations of WebM. This grant does not include claims
+that would be infringed only as a consequence of further modification of these
+implementations. If you or your agent or exclusive licensee institute or order
+or agree to the institution of patent litigation or any other patent
+enforcement activity against any entity (including a cross-claim or
+counterclaim in a lawsuit) alleging that any of these implementations of WebM
+or any code incorporated within any of these implementations of WebM
+constitute direct or contributory patent infringement, or inducement of
+patent infringement, then any patent rights granted to you under this License
+for these implementations of WebM shall terminate as of the date such
+litigation is filed.
diff --git a/METADATA b/METADATA
index def00a92..05991759 100644
--- a/METADATA
+++ b/METADATA
@@ -1,15 +1,19 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/webp
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
name: "webp"
description: "Android fork of the libwebp library."
third_party {
- url {
- type: GIT
- value: "https://chromium.googlesource.com/webm/libwebp"
- }
- version: "v1.3.0"
license_type: NOTICE
last_upgrade_date {
- year: 2023
- month: 01
- day: 13
+ year: 2024
+ month: 4
+ day: 16
+ }
+ identifier {
+ type: "Git"
+ value: "https://chromium.googlesource.com/webm/libwebp"
+ version: "v1.4.0"
}
}
diff --git a/Makefile.vc b/Makefile.vc
index 00d899e7..84e9a5dd 100644
--- a/Makefile.vc
+++ b/Makefile.vc
@@ -12,6 +12,8 @@ LIBSHARPYUV_BASENAME = libsharpyuv
ARCH = x86
!ELSE IF ! [ cl 2>&1 | find "x64" > NUL ]
ARCH = x64
+!ELSE IF ! [ cl 2>&1 | find "ARM64" > NUL ]
+ARCH = ARM64
!ELSE IF ! [ cl 2>&1 | find "ARM" > NUL ]
ARCH = ARM
!ELSE
@@ -321,6 +323,7 @@ ENC_OBJS = \
EXTRAS_OBJS = \
$(DIROBJ)\extras\extras.obj \
$(DIROBJ)\extras\quality_estimate.obj \
+ $(DIROBJ)\extras\sharpyuv_risk_table.obj \
IMAGEIO_UTIL_OBJS = \
$(DIROBJ)\imageio\imageio_util.obj \
@@ -336,6 +339,7 @@ UTILS_DEC_OBJS = \
$(DIROBJ)\utils\color_cache_utils.obj \
$(DIROBJ)\utils\filters_utils.obj \
$(DIROBJ)\utils\huffman_utils.obj \
+ $(DIROBJ)\utils\palette.obj \
$(DIROBJ)\utils\quant_levels_dec_utils.obj \
$(DIROBJ)\utils\rescaler_utils.obj \
$(DIROBJ)\utils\random_utils.obj \
@@ -400,7 +404,7 @@ $(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP)
$(DIRBIN)\img2webp.exe: $(DIROBJ)\examples\img2webp.obj $(LIBWEBPMUX)
$(DIRBIN)\img2webp.exe: $(IMAGEIO_DEC_OBJS)
$(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS)
-$(DIRBIN)\img2webp.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
+$(DIRBIN)\img2webp.exe: $(LIBWEBPDEMUX) $(LIBWEBP) $(LIBSHARPYUV)
$(DIRBIN)\get_disto.exe: $(DIROBJ)\extras\get_disto.obj
$(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS)
$(DIRBIN)\get_disto.exe: $(LIBWEBPDEMUX) $(LIBWEBP)
diff --git a/NEWS b/NEWS
index c4f8ef79..8e40d8ea 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,37 @@
+- 4/12/2024: version 1.4.0
+ This is a binary compatible release.
+ * API changes:
+ - libwebpmux: WebPAnimEncoderSetChunk, WebPAnimEncoderGetChunk,
+ WebPAnimEncoderDeleteChunk
+ - libsharpyuv: SharpYuvOptionsInit, SharpYuvConvertWithOptions
+ - extras: SharpYuvEstimate420Risk
+ * further security related hardening in libwebp & examples
+ * some minor optimizations in the lossless encoder
+ * added WEBP_NODISCARD to report unused result warnings; enable with
+ -DWEBP_ENABLE_NODISCARD=1
+ * improvements and corrections in webp-container-spec.txt and
+ webp-lossless-bitstream-spec.txt (#611)
+ * miscellaneous warning, bug & build fixes (#615, #619, #632, #635)
+
+- 9/13/2023: version 1.3.2
+ This is a binary compatible release.
+ * security fix for lossless decoder (chromium: #1479274, CVE-2023-4863)
+
+- 6/23/2023: version 1.3.1
+ This is a binary compatible release.
+ * security fixes for lossless encoder (#603, chromium: #1420107, #1455619,
+ CVE-2023-1999)
+ * improve error reporting through WebPPicture error codes
+ * fix upsampling for RGB565 and RGBA4444 in NEON builds
+ * img2webp: add -sharp_yuv & -near_lossless
+ * Windows builds:
+ - fix compatibility with clang-cl (#607)
+ - improve Arm64 performance with cl.exe
+ - add Arm64EC support
+ * fix webp_js with emcc >= 3.1.27 (stack size change, #614)
+ * CMake fixes (#592, #610, #612)
+ * further updates to the container and lossless bitstream docs (#581, #611)
+
- 12/16/2022: version 1.3.0
This is a binary compatible release.
* add libsharpyuv, which exposes -sharp_yuv/config.use_sharp_yuv
diff --git a/README.android b/README.android
index 8e5fca29..1945b89e 100644
--- a/README.android
+++ b/README.android
@@ -1,5 +1,5 @@
URL: https://chromium.googlesource.com/webm/libwebp
-Version: 1.3.0
+Version: v1.4.0
License: Google BSD like
Local modifications:
diff --git a/README.md b/README.md
index 4e201d33..ffffa538 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
\__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__
- \____/____/\_____/_____/____/v1.3.0
+ \____/____/\_____/_____/____/v1.4.0
```
WebP codec is a library to encode and decode images in WebP format. This package
diff --git a/README.version b/README.version
deleted file mode 100644
index 9189f436..00000000
--- a/README.version
+++ /dev/null
@@ -1,3 +0,0 @@
-URL: https://chromium.googlesource.com/webm/libwebp
-Version: v1.3.0
-BugComponent: 20174
diff --git a/build.gradle b/build.gradle
index c25314c0..14ceebf7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -173,6 +173,7 @@ model {
include "color_cache_utils.c"
include "filters_utils.c"
include "huffman_utils.c"
+ include "palette.c"
include "quant_levels_dec_utils.c"
include "random_utils.c"
include "rescaler_utils.c"
diff --git a/cmake/WebPConfig.cmake.in b/cmake/WebPConfig.cmake.in
index f3347394..a0d721f3 100644
--- a/cmake/WebPConfig.cmake.in
+++ b/cmake/WebPConfig.cmake.in
@@ -8,9 +8,12 @@ if(@WEBP_USE_THREAD@)
find_dependency(Threads REQUIRED)
endif()
-include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
-set(WebP_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
-set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
+set_and_check(WebP_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+set(WebP_INCLUDE_DIRS ${WebP_INCLUDE_DIR})
+set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIR})
set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
set(WEBP_LIBRARIES "${WebP_LIBRARIES}")
+
+check_required_components(WebP)
diff --git a/cmake/config.h.in b/cmake/config.h.in
index 3770935c..fe1c53ad 100644
--- a/cmake/config.h.in
+++ b/cmake/config.h.in
@@ -16,48 +16,18 @@
/* Define to 1 if you have the <cpu-features.h> header file. */
#cmakedefine HAVE_CPU_FEATURES_H 1
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#cmakedefine HAVE_DLFCN_H 1
-
/* Define to 1 if you have the <GLUT/glut.h> header file. */
#cmakedefine HAVE_GLUT_GLUT_H 1
/* Define to 1 if you have the <GL/glut.h> header file. */
#cmakedefine HAVE_GL_GLUT_H 1
-/* Define to 1 if you have the <inttypes.h> header file. */
-#cmakedefine HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the <memory.h> header file. */
-#cmakedefine HAVE_MEMORY_H 1
-
/* Define to 1 if you have the <OpenGL/glut.h> header file. */
#cmakedefine HAVE_OPENGL_GLUT_H 1
-/* Have PTHREAD_PRIO_INHERIT. */
-#cmakedefine HAVE_PTHREAD_PRIO_INHERIT @HAVE_PTHREAD_PRIO_INHERIT@
-
/* Define to 1 if you have the <shlwapi.h> header file. */
#cmakedefine HAVE_SHLWAPI_H 1
-/* Define to 1 if you have the <stdint.h> header file. */
-#cmakedefine HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#cmakedefine HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#cmakedefine HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#cmakedefine HAVE_STRING_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#cmakedefine HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#cmakedefine HAVE_SYS_TYPES_H 1
-
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1
@@ -93,9 +63,6 @@
/* Define to the version of this package. */
#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@"
-/* Define to 1 if you have the ANSI C header files. */
-#cmakedefine STDC_HEADERS 1
-
/* Version number of package */
#cmakedefine VERSION "@VERSION@"
diff --git a/cmake/cpu.cmake b/cmake/cpu.cmake
index 7513ca8a..040c5247 100644
--- a/cmake/cpu.cmake
+++ b/cmake/cpu.cmake
@@ -61,7 +61,7 @@ endif()
set(WEBP_SIMD_FILES_TO_INCLUDE)
set(WEBP_SIMD_FLAGS_TO_INCLUDE)
-if(${ANDROID})
+if(ANDROID AND ANDROID_ABI)
if(${ANDROID_ABI} STREQUAL "armeabi-v7a")
# This is because Android studio uses the configuration "-march=armv7-a
# -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon
@@ -106,8 +106,9 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
endif()
# Check which files we should include or not.
list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION)
- file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../"
- "src/dsp/*${WEBP_SIMD_FILE_EXTENSION}")
+ file(GLOB SIMD_FILES
+ "${CMAKE_CURRENT_LIST_DIR}/../sharpyuv/*${WEBP_SIMD_FILE_EXTENSION}"
+ "${CMAKE_CURRENT_LIST_DIR}/../src/dsp/*${WEBP_SIMD_FILE_EXTENSION}")
if(WEBP_HAVE_${WEBP_SIMD_FLAG})
# Memorize the file and flags.
foreach(FILE ${SIMD_FILES})
diff --git a/cmake/deps.cmake b/cmake/deps.cmake
index 48c821e6..0760ba92 100644
--- a/cmake/deps.cmake
+++ b/cmake/deps.cmake
@@ -43,16 +43,6 @@ if(WEBP_USE_THREAD)
if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
endif()
- check_c_source_compiles(
- "
- #include <pthread.h>
- int main (void) {
- int attr = PTHREAD_PRIO_INHERIT;
- return attr;
- }
- "
- FLAG_HAVE_PTHREAD_PRIO_INHERIT)
- set(HAVE_PTHREAD_PRIO_INHERIT ${FLAG_HAVE_PTHREAD_PRIO_INHERIT})
list(APPEND WEBP_DEP_LIBRARIES Threads::Threads)
endif()
set(WEBP_USE_THREAD ${Threads_FOUND})
@@ -84,72 +74,64 @@ endif()
# Find the standard image libraries.
set(WEBP_DEP_IMG_LIBRARIES)
set(WEBP_DEP_IMG_INCLUDE_DIRS)
-foreach(I_LIB PNG JPEG TIFF)
- # Disable tiff when compiling in static mode as it is failing on Ubuntu.
- if(WEBP_LINK_STATIC AND ${I_LIB} STREQUAL "TIFF")
- message("TIFF is disabled when statically linking.")
- continue()
- endif()
- find_package(${I_LIB})
- set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
- if(${I_LIB}_FOUND)
- list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
- list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIR}
- ${${I_LIB}_INCLUDE_DIRS})
+if(WEBP_FIND_IMG_LIBS)
+ foreach(I_LIB PNG JPEG TIFF)
+ # Disable tiff when compiling in static mode as it is failing on Ubuntu.
+ if(WEBP_LINK_STATIC AND ${I_LIB} STREQUAL "TIFF")
+ message(STATUS "TIFF is disabled when statically linking.")
+ continue()
+ endif()
+ find_package(${I_LIB})
+ set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND})
+ if(${I_LIB}_FOUND)
+ list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES})
+ list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIR}
+ ${${I_LIB}_INCLUDE_DIRS})
+ endif()
+ endforeach()
+ if(WEBP_DEP_IMG_INCLUDE_DIRS)
+ list(REMOVE_DUPLICATES WEBP_DEP_IMG_INCLUDE_DIRS)
endif()
-endforeach()
-if(WEBP_DEP_IMG_INCLUDE_DIRS)
- list(REMOVE_DUPLICATES WEBP_DEP_IMG_INCLUDE_DIRS)
-endif()
-# GIF detection, gifdec isn't part of the imageio lib.
-include(CMakePushCheckState)
-set(WEBP_DEP_GIF_LIBRARIES)
-set(WEBP_DEP_GIF_INCLUDE_DIRS)
-find_package(GIF)
-set(WEBP_HAVE_GIF ${GIF_FOUND})
-if(GIF_FOUND)
- # GIF find_package only locates the header and library, it doesn't fail
- # compile tests when detecting the version, but falls back to 3 (as of at
- # least cmake 3.7.2). Make sure the library links to avoid incorrect detection
- # when cross compiling.
- cmake_push_check_state()
- set(CMAKE_REQUIRED_LIBRARIES ${GIF_LIBRARIES})
- set(CMAKE_REQUIRED_INCLUDES ${GIF_INCLUDE_DIR})
- check_c_source_compiles(
- "
+ # GIF detection, gifdec isn't part of the imageio lib.
+ include(CMakePushCheckState)
+ set(WEBP_DEP_GIF_LIBRARIES)
+ set(WEBP_DEP_GIF_INCLUDE_DIRS)
+ find_package(GIF)
+ set(WEBP_HAVE_GIF ${GIF_FOUND})
+ if(GIF_FOUND)
+ # GIF find_package only locates the header and library, it doesn't fail
+ # compile tests when detecting the version, but falls back to 3 (as of at
+ # least cmake 3.7.2). Make sure the library links to avoid incorrect
+ # detection when cross compiling.
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_LIBRARIES ${GIF_LIBRARIES})
+ set(CMAKE_REQUIRED_INCLUDES ${GIF_INCLUDE_DIR})
+ check_c_source_compiles(
+ "
#include <gif_lib.h>
int main(void) {
(void)DGifOpenFileHandle;
return 0;
}
"
- GIF_COMPILES)
- cmake_pop_check_state()
- if(GIF_COMPILES)
- list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES})
- list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR})
- else()
- unset(GIF_FOUND)
+ GIF_COMPILES)
+ cmake_pop_check_state()
+ if(GIF_COMPILES)
+ list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES})
+ list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR})
+ else()
+ unset(GIF_FOUND)
+ endif()
endif()
endif()
# Check for specific headers.
include(CheckIncludeFiles)
-check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
-check_include_files(dlfcn.h HAVE_DLFCN_H)
check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H)
check_include_files(GL/glut.h HAVE_GL_GLUT_H)
-check_include_files(inttypes.h HAVE_INTTYPES_H)
-check_include_files(memory.h HAVE_MEMORY_H)
check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H)
check_include_files(shlwapi.h HAVE_SHLWAPI_H)
-check_include_files(stdint.h HAVE_STDINT_H)
-check_include_files(stdlib.h HAVE_STDLIB_H)
-check_include_files(strings.h HAVE_STRINGS_H)
-check_include_files(string.h HAVE_STRING_H)
-check_include_files(sys/stat.h HAVE_SYS_STAT_H)
-check_include_files(sys/types.h HAVE_SYS_TYPES_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(wincodec.h HAVE_WINCODEC_H)
check_include_files(windows.h HAVE_WINDOWS_H)
diff --git a/configure.ac b/configure.ac
index de5dfe7a..af7ac0ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([libwebp], [1.3.0],
+AC_INIT([libwebp], [1.4.0],
[https://bugs.chromium.org/p/webp],,
[https://developers.google.com/speed/webp])
AC_CANONICAL_HOST
@@ -106,6 +106,7 @@ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wall])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wconstant-conversion])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wdeclaration-after-statement])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wextra-semi-stmt])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wfloat-conversion])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-nonliteral])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wformat -Wformat-security])
@@ -115,6 +116,7 @@ TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wold-style-definition])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wparentheses-equality])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshadow])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wshorten-64-to-32])
+TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wstrict-prototypes])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wundef])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code-aggressive])
TEST_AND_ADD_CFLAGS([AM_CFLAGS], [-Wunreachable-code])
@@ -464,7 +466,7 @@ AC_ARG_ENABLE([sdl],
@<:@default=auto@:>@]))
AS_IF([test "x$enable_sdl" != "xno"], [
CLEAR_LIBVARS([SDL])
- AC_PATH_PROGS([LIBSDL_CONFIG], [sdl-config])
+ AC_PATH_PROGS([LIBSDL_CONFIG], [sdl2-config])
if test -n "$LIBSDL_CONFIG"; then
SDL_INCLUDES=`$LIBSDL_CONFIG --cflags`
SDL_LIBS="`$LIBSDL_CONFIG --libs`"
@@ -474,13 +476,12 @@ AS_IF([test "x$enable_sdl" != "xno"], [
sdl_header="no"
LIBCHECK_PROLOGUE([SDL])
- AC_CHECK_HEADER([SDL/SDL.h], [sdl_header="SDL/SDL.h"],
- [AC_CHECK_HEADER([SDL.h], [sdl_header="SDL.h"],
- [AC_MSG_WARN(SDL library not available - no sdl.h)])])
+ AC_CHECK_HEADER([SDL2/SDL.h], [sdl_header="SDL2/SDL.h"],
+ [AC_MSG_WARN(SDL2 library not available - no SDL.h)])
if test x"$sdl_header" != "xno"; then
AC_LANG_PUSH(C)
SDL_SAVED_LIBS="$LIBS"
- for lib in "" "-lSDL" "-lSDLmain -lSDL"; do
+ for lib in "" "-lSDL2" "-lSDL2main -lSDL2"; do
LIBS="$SDL_SAVED_LIBS $lib"
# Perform a full link to ensure SDL_main is resolved if needed.
AC_LINK_IFELSE(
@@ -762,7 +763,8 @@ AC_CONFIG_FILES([Makefile src/Makefile man/Makefile \
src/libwebp.pc src/libwebpdecoder.pc \
src/demux/libwebpdemux.pc src/mux/libwebpmux.pc])
-
+dnl fix exports from MinGW builds
+AC_CONFIG_COMMANDS_POST([$SED -i 's/-DDLL_EXPORT/-DWEBP_DLL/' config.status])
AC_OUTPUT
AC_MSG_NOTICE([
diff --git a/doc/api.md b/doc/api.md
index c613ed34..c5d83dbb 100644
--- a/doc/api.md
+++ b/doc/api.md
@@ -157,7 +157,7 @@ decoding is not finished yet or VP8_STATUS_OK when decoding is done. Any other
status is an error condition.
The 'idec' object must always be released (even upon an error condition) by
-calling: WebPDelete(idec).
+calling: WebPIDelete(idec).
To retrieve partially decoded picture samples, one must use the corresponding
method: WebPIDecGetRGB or WebPIDecGetYUVA. It will return the last displayable
diff --git a/doc/building.md b/doc/building.md
index 5efeab9a..d870e34e 100644
--- a/doc/building.md
+++ b/doc/building.md
@@ -96,6 +96,24 @@ make
make install
```
+## Building libwebp - Using vcpkg
+
+You can download and install libwebp using the
+[vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
+
+```shell
+git clone https://github.com/Microsoft/vcpkg.git
+cd vcpkg
+./bootstrap-vcpkg.sh
+./vcpkg integrate install
+./vcpkg install libwebp
+```
+
+The libwebp port in vcpkg is kept up to date by Microsoft team members and
+community contributors. If the version is out of date, please
+[create an issue or pull request](https://github.com/Microsoft/vcpkg) on the
+vcpkg repository.
+
## CMake
With CMake, you can compile libwebp, cwebp, dwebp, gif2webp, img2webp, webpinfo
diff --git a/doc/tools.md b/doc/tools.md
index 853af819..bf492746 100644
--- a/doc/tools.md
+++ b/doc/tools.md
@@ -82,8 +82,8 @@ Options:
green=0xe0 and blue=0xd0
-noalpha ............... discard any transparency information
-lossless .............. encode image losslessly, default=off
--near_lossless <int> ... use near-lossless image
- preprocessing (0..100=off), default=100
+-near_lossless <int> ... use near-lossless image preprocessing
+ (0..100=off), default=100
-hint <string> ......... specify image characteristics hint,
one of: photo, picture or graph
@@ -295,19 +295,23 @@ etc.
Usage:
```shell
-img2webp [file_options] [[frame_options] frame_file]...
+img2webp [file_options] [[frame_options] frame_file]... [-o webp_file]
```
File-level options (only used at the start of compression):
```
-min_size ............ minimize size
--loop <int> .......... loop count (default: 0, = infinite loop)
-kmax <int> .......... maximum number of frame between key-frames
(0=only keyframes)
-kmin <int> .......... minimum number of frame between key-frames
(0=disable key-frames altogether)
-mixed ............... use mixed lossy/lossless automatic mode
+-near_lossless <int> . use near-lossless image preprocessing
+ (0..100=off), default=100
+-sharp_yuv ........... use sharper (and slower) RGB->YUV conversion
+ (lossy only)
+-loop <int> .......... loop count (default: 0, = infinite loop)
-v ................... verbose mode
-h ................... this help
-version ............. print version number and exit
diff --git a/doc/webp-container-spec.txt b/doc/webp-container-spec.txt
index ffa919eb..c64bfd40 100644
--- a/doc/webp-container-spec.txt
+++ b/doc/webp-container-spec.txt
@@ -20,47 +20,48 @@ WebP Container Specification
Introduction
------------
-WebP is an image format that uses either (i) the VP8 key frame encoding
-to compress image data in a lossy way, or (ii) the WebP lossless encoding
-(and possibly other encodings in the future). These encoding schemes should
-make it more efficient than currently used formats. It is optimized for fast
-image transfer over the network (e.g., for websites). The WebP format has
-feature parity (color profile, metadata, animation, etc.) with other formats as
-well. This document describes the structure of a WebP file.
-
-The WebP container (i.e., RIFF container for WebP) allows feature support over
-and above the basic use case of WebP (i.e., a file containing a single image
-encoded as a VP8 key frame). The WebP container provides additional support
-for:
-
- * **Lossless compression.** An image can be losslessly compressed, using the
+WebP is an image format that uses either (i) the VP8 key frame encoding to
+compress image data in a lossy way or (ii) the WebP lossless encoding. These
+encoding schemes should make it more efficient than older formats, such as JPEG,
+GIF, and PNG. It is optimized for fast image transfer over the network (for
+example, for websites). The WebP format has feature parity (color profile,
+metadata, animation, etc.) with other formats as well. This document describes
+the structure of a WebP file.
+
+The WebP container (that is, the RIFF container for WebP) allows feature support
+over and above the basic use case of WebP (that is, a file containing a single
+image encoded as a VP8 key frame). The WebP container provides additional
+support for the following:
+
+ * Lossless Compression: An image can be losslessly compressed, using the
WebP Lossless Format.
- * **Metadata.** An image may have metadata stored in Exif or XMP formats.
+ * Metadata: An image may have metadata stored in Exchangeable Image File
+ Format (Exif) or Extensible Metadata Platform (XMP) format.
- * **Transparency.** An image may have transparency, i.e., an alpha channel.
+ * Transparency: An image may have transparency, that is, an alpha channel.
- * **Color Profile.** An image may have an embedded ICC profile as described
+ * Color Profile: An image may have an embedded ICC profile as described
by the [International Color Consortium][iccspec].
- * **Animation.** An image may have multiple frames with pauses between them,
+ * Animation: An image may have multiple frames with pauses between them,
making it an animation.
+Terminology & Basics
+--------------------
+
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in BCP 14 [RFC 2119][] [RFC 8174][]
when, and only when, they appear in all capitals, as shown here.
-Bit numbering in chunk diagrams starts at `0` for the most significant bit
-('MSB 0') as described in [RFC 1166][].
-
-Terminology & Basics
---------------------
-
-A WebP file contains either a still image (i.e., an encoded matrix of pixels)
+A WebP file contains either a still image (that is, an encoded matrix of pixels)
or an [animation](#animation). Optionally, it can also contain transparency
-information, color profile and metadata. In case we need to refer only to the
-matrix of pixels, we will call it the _canvas_ of the image.
+information, a color profile and metadata. We refer to the matrix of pixels as
+the _canvas_ of the image.
+
+Bit numbering in chunk diagrams starts at `0` for the most significant bit
+('MSB 0'), as described in [RFC 1166][].
Below are additional terms used throughout this document:
@@ -83,20 +84,19 @@ _uint32_
_FourCC_
-: A _FourCC_ (four-character code) is a _uint32_ created by concatenating four
+: A four-character code (FourCC) is a _uint32_ created by concatenating four
ASCII characters in little-endian order. This means 'aaaa' (0x61616161) and
'AAAA' (0x41414141) are treated as different _FourCCs_.
_1-based_
-: An unsigned integer field storing values offset by `-1`. e.g., Such a field
- would store value _25_ as _24_.
+: An unsigned integer field storing values offset by `-1`, for example, such a
+ field would store value _25_ as _24_.
_ChunkHeader('ABCD')_
-: This is used to describe the _FourCC_ and _Chunk Size_ header of individual
- chunks, where 'ABCD' is the FourCC for the chunk. This element's size is 8
- bytes.
+: Used to describe the _FourCC_ and _Chunk Size_ header of individual chunks,
+ where 'ABCD' is the FourCC for the chunk. This element's size is 8 bytes.
RIFF File Format
@@ -124,11 +124,11 @@ Chunk FourCC: 32 bits
Chunk Size: 32 bits (_uint32_)
: The size of the chunk in bytes, not including this field, the chunk
- identifier or padding.
+ identifier, or padding.
Chunk Payload: _Chunk Size_ bytes
-: The data payload. If _Chunk Size_ is odd, a single padding byte -- that MUST
+: The data payload. If _Chunk Size_ is odd, a single padding byte -- which MUST
be `0` to conform with RIFF -- is added.
**Note:** RIFF has a convention that all-uppercase chunk FourCCs are standard
@@ -151,24 +151,24 @@ WebP File Header
'RIFF': 32 bits
-: The ASCII characters 'R' 'I' 'F' 'F'.
+: The ASCII characters 'R', 'I', 'F', 'F'.
File Size: 32 bits (_uint32_)
-: The size of the file in bytes starting at offset 8. The maximum value of
+: The size of the file in bytes, starting at offset 8. The maximum value of
this field is 2^32 minus 10 bytes and thus the size of the whole file is at
- most 4GiB minus 2 bytes.
+ most 4 GiB minus 2 bytes.
'WEBP': 32 bits
-: The ASCII characters 'W' 'E' 'B' 'P'.
+: The ASCII characters 'W', 'E', 'B', 'P'.
A WebP file MUST begin with a RIFF header with the FourCC 'WEBP'. The file size
in the header is the total size of the chunks that follow plus `4` bytes for
the 'WEBP' FourCC. The file SHOULD NOT contain any data after the data
specified by _File Size_. Readers MAY parse such files, ignoring the trailing
data. As the size of any chunk is even, the size given by the RIFF header is
-also even. The contents of individual chunks will be described in the following
+also even. The contents of individual chunks are described in the following
sections.
@@ -188,10 +188,10 @@ Simple WebP (lossy) file format:
| WebP file header (12 bytes) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- : VP8 chunk :
+ : 'VP8 ' Chunk :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-VP8 chunk:
+'VP8 ' Chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -206,15 +206,15 @@ VP8 data: _Chunk Size_ bytes
: VP8 bitstream data.
-Note the fourth character in the 'VP8 ' FourCC is an ASCII space (0x20).
+Note that the fourth character in the 'VP8 ' FourCC is an ASCII space (0x20).
-The VP8 bitstream format specification can be found at [VP8 Data Format and
-Decoding Guide][vp8spec]. Note that the VP8 frame header contains the VP8 frame
+The VP8 bitstream format specification is described in [VP8 Data Format and
+Decoding Guide][rfc 6386]. Note that the VP8 frame header contains the VP8 frame
width and height. That is assumed to be the width and height of the canvas.
The VP8 specification describes how to decode the image into Y'CbCr format. To
-convert to RGB, Rec. 601 SHOULD be used. Applications MAY use another
-conversion method, but visual results may differ among decoders.
+convert to RGB, [Recommendation BT.601][rec601] SHOULD be used. Applications MAY
+use another conversion method, but visual results may differ among decoders.
Simple File Format (Lossless)
@@ -235,10 +235,10 @@ Simple WebP (lossless) file format:
| WebP file header (12 bytes) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- : VP8L chunk :
+ : 'VP8L' Chunk :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-VP8L chunk:
+'VP8L' Chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -266,17 +266,17 @@ Extended File Format
An extended format file consists of:
- * A 'VP8X' chunk with information about features used in the file.
+ * A 'VP8X' Chunk with information about features used in the file.
- * An optional 'ICCP' chunk with color profile.
+ * An optional 'ICCP' Chunk with a color profile.
- * An optional 'ANIM' chunk with animation control data.
+ * An optional 'ANIM' Chunk with animation control data.
* Image data.
- * An optional 'EXIF' chunk with Exif metadata.
+ * An optional 'EXIF' Chunk with Exif metadata.
- * An optional 'XMP ' chunk with XMP metadata.
+ * An optional 'XMP ' Chunk with XMP metadata.
* An optional list of [unknown chunks](#unknown-chunks).
@@ -290,15 +290,18 @@ up of:
For an _animated image_, the _image data_ consists of multiple frames. More
details about frames can be found in the [Animation](#animation) section.
-All chunks SHOULD be placed in the same order as listed above. If a chunk
-appears in the wrong place, the file is invalid, but readers MAY parse the
-file, ignoring the chunks that are out of order.
+All chunks necessary for reconstruction and color correction, that is 'VP8X',
+'ICCP', 'ANIM', 'ANMF', 'ALPH', 'VP8 ' and 'VP8L', MUST appear in the order
+described earlier. Readers SHOULD fail when chunks necessary for reconstruction
+and color correction are out of order.
+
+[Metadata](#metadata) and [unknown](#unknown-chunks) chunks MAY appear out of
+order.
-**Rationale:** Setting the order of chunks should allow quicker file
-parsing. For example, if an 'ALPH' chunk does not appear in its required
-position, a decoder can choose to stop searching for it. The rule of
-ignoring late chunks should make programs that need to do a full search
-give the same results as the ones stopping early.
+**Rationale:** The chunks necessary for reconstruction should appear first in
+the file to allow a reader to begin decoding an image before receiving all of
+the data. An application may benefit from varying the order of metadata and
+custom chunks to suit the implementation.
Extended WebP file header:
{:#extended_header}
@@ -326,7 +329,7 @@ Reserved (Rsv): 2 bits
ICC profile (I): 1 bit
-: Set if the file contains an ICC profile.
+: Set if the file contains an 'ICCP' Chunk.
Alpha (L): 1 bit
@@ -343,7 +346,7 @@ XMP metadata (X): 1 bit
Animation (A): 1 bit
-: Set if this is an animated image. Data in 'ANIM' and 'ANMF' chunks should be
+: Set if this is an animated image. Data in 'ANIM' and 'ANMF' Chunks should be
used to control the animation.
Reserved (R): 1 bit
@@ -372,9 +375,9 @@ Future specifications may add more fields. Unknown fields MUST be ignored.
#### Animation
-An animation is controlled by ANIM and ANMF chunks.
+An animation is controlled by 'ANIM' and 'ANMF' Chunks.
-ANIM Chunk:
+'ANIM' Chunk:
{:#anim_chunk}
For an animated image, this chunk contains the _global parameters_ of the
@@ -396,14 +399,14 @@ Background Color: 32 bits (_uint32_)
: The default background color of the canvas in \[Blue, Green, Red, Alpha\]
byte order. This color MAY be used to fill the unused space on the canvas
around the frames, as well as the transparent pixels of the first frame.
- Background color is also used when disposal method is `1`.
+ The background color is also used when the Disposal method is `1`.
**Note**:
- * Background color MAY contain a non-opaque alpha value, even if the _Alpha_
- flag in [VP8X chunk](#extended_header) is unset.
+ * The background color MAY contain a non-opaque alpha value, even if the
+ _Alpha_ flag in the ['VP8X' Chunk](#extended_header) is unset.
- * Viewer applications SHOULD treat the background color value as a hint, and
+ * Viewer applications SHOULD treat the background color value as a hint and
are not required to use it.
* The canvas is cleared at the start of each loop. The background color MAY be
@@ -411,13 +414,14 @@ Background Color: 32 bits (_uint32_)
Loop Count: 16 bits (_uint16_)
-: The number of times to loop the animation. `0` means infinitely.
+: The number of times to loop the animation. If it is `0`, this means
+ infinitely.
-This chunk MUST appear if the _Animation_ flag in the VP8X chunk is set.
+This chunk MUST appear if the _Animation_ flag in the 'VP8X' Chunk is set.
If the _Animation_ flag is not set and this chunk is present, it MUST be
ignored.
-ANMF chunk:
+'ANMF' Chunk:
For animated images, this chunk contains information about a _single_ frame.
If the _Animation flag_ is not set, then this chunk SHOULD NOT be present.
@@ -459,10 +463,10 @@ Frame Height Minus One: 24 bits (_uint24_)
Frame Duration: 24 bits (_uint24_)
-: The time to wait before displaying the next frame, in 1 millisecond units.
- Note the interpretation of frame duration of 0 (and often <= 10) is
- implementation defined. Many tools and browsers assign a minimum duration
- similar to GIF.
+: The time to wait before displaying the next frame, in 1-millisecond units.
+ Note that the interpretation of the Frame Duration of 0 (and often <= 10) is
+ defined by the implementation. Many tools and browsers assign a minimum
+ duration similar to GIF.
Reserved: 6 bits
@@ -473,10 +477,10 @@ Blending method (B): 1 bit
: Indicates how transparent pixels of _the current frame_ are to be blended
with corresponding pixels of the previous canvas:
- * `0`: Use alpha blending. After disposing of the previous frame, render the
+ * `0`: Use alpha-blending. After disposing of the previous frame, render the
current frame on the canvas using [alpha-blending](#alpha-blending). If
- the current frame does not have an alpha channel, assume alpha value of
- 255, effectively replacing the rectangle.
+ the current frame does not have an alpha channel, assume the alpha value
+ is 255, effectively replacing the rectangle.
* `1`: Do not blend. After disposing of the previous frame, render the
current frame on the canvas by overwriting the rectangle covered by the
@@ -489,20 +493,20 @@ Disposal method (D): 1 bit
* `0`: Do not dispose. Leave the canvas as is.
- * `1`: Dispose to background color. Fill the _rectangle_ on the canvas
- covered by the _current frame_ with background color specified in the
- [ANIM chunk](#anim_chunk).
+ * `1`: Dispose to the background color. Fill the _rectangle_ on the canvas
+ covered by the _current frame_ with the background color specified in the
+ ['ANIM' Chunk](#anim_chunk).
**Notes**:
* The frame disposal only applies to the _frame rectangle_, that is, the
- rectangle defined by _Frame X_, _Frame Y_, _frame width_ and _frame height_.
- It may or may not cover the whole canvas.
+ rectangle defined by _Frame X_, _Frame Y_, _frame width_, and _frame
+ height_. It may or may not cover the whole canvas.
{:#alpha-blending}
- * **Alpha-blending**:
+ * Alpha-blending:
- Given that each of the R, G, B and A channels is 8-bit, and the RGB
+ Given that each of the R, G, B, and A channels is 8 bits, and the RGB
channels are _not premultiplied_ by alpha, the formula for blending
'dst' onto 'src' is:
@@ -518,8 +522,8 @@ Disposal method (D): 1 bit
* Alpha-blending SHOULD be done in linear color space, by taking into account
the [color profile](#color-profile) of the image. If the color profile is
- not present, sRGB is to be assumed. (Note that sRGB also needs to be
- linearized due to a gamma of ~2.2).
+ not present, standard RGB (sRGB) is to be assumed. (Note that sRGB also
+ needs to be linearized due to a gamma of ~2.2.)
Frame Data: _Chunk Size_ - `16` bytes
@@ -531,8 +535,8 @@ Frame Data: _Chunk Size_ - `16` bytes
* An optional list of [unknown chunks](#unknown-chunks).
-**Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual
-_padded_ chunks as described by the [RIFF file format](#riff-file-format).
+**Note**: The 'ANMF' payload, _Frame Data_, consists of individual
+_padded_ chunks, as described by the [RIFF file format](#riff-file-format).
#### Alpha
@@ -549,18 +553,20 @@ Reserved (Rsv): 2 bits
: MUST be `0`. Readers MUST ignore this field.
-Pre-processing (P): 2 bits
+Preprocessing (P): 2 bits
-: These _informative_ bits are used to signal the pre-processing that has
+: These _informative_ bits are used to signal the preprocessing that has
been performed during compression. The decoder can use this information to
- e.g. dither the values or smooth the gradients prior to display.
+ for example, dither the values or smooth the gradients prior to display.
- * `0`: No pre-processing.
+ * `0`: No preprocessing.
* `1`: Level reduction.
+Decoders are not required to use this information in any specified way.
+
Filtering method (F): 2 bits
-: The filtering method used:
+: The filtering methods used are described as follows:
* `0`: None.
* `1`: Horizontal filter.
@@ -584,8 +590,8 @@ made depending on the filtering method:
where `clip(v)` is equal to:
- * 0 if v < 0
- * 255 if v > 255
+ * 0 if v < 0,
+ * 255 if v > 255, or
* v otherwise
The final value is derived by adding the decompressed value `X` to the
@@ -594,17 +600,15 @@ into the \[0..255\] one:
`alpha = (predictor + X) % 256`
-There are special cases for the left-most and top-most pixel positions:
+There are special cases for the left-most and top-most pixel positions. For
+example, the top-left value at location (0, 0) uses 0 as the predictor value.
+Otherwise:
- * The top-left value at location (0, 0) uses 0 as predictor value. Otherwise,
* For horizontal or gradient filtering methods, the left-most pixels at
location (0, y) are predicted using the location (0, y-1) just above.
* For vertical or gradient filtering methods, the top-most pixels at
location (x, 0) are predicted using the location (x-1, 0) on the left.
-
-Decoders are not required to use this information in any specified way.
-
Compression method (C): 2 bits
: The compression method used:
@@ -617,32 +621,32 @@ Alpha bitstream: _Chunk Size_ - `1` bytes
: Encoded alpha bitstream.
This optional chunk contains encoded alpha data for this frame. A frame
-containing a 'VP8L' chunk SHOULD NOT contain this chunk.
+containing a 'VP8L' Chunk SHOULD NOT contain this chunk.
**Rationale**: The transparency information is already part of the 'VP8L'
-chunk.
+Chunk.
-The alpha channel data is stored as uncompressed raw data (when
+The alpha channel data is stored as uncompressed raw data (when the
compression method is '0') or compressed using the lossless format
(when the compression method is '1').
- * Raw data: consists of a byte sequence of length width * height,
+ * Raw data: This consists of a byte sequence of length = width * height,
containing all the 8-bit transparency values in scan order.
- * Lossless format compression: the byte sequence is a compressed
- image-stream (as described in the [WebP Lossless Bitstream Format]
- [webpllspec]) of implicit dimension width x height. That is, this
- image-stream does NOT contain any headers describing the image dimension.
+ * Lossless format compression: The byte sequence is a compressed
+ image-stream (as described in ["WebP Lossless Bitstream Format"]
+ [webpllspec]) of implicit dimensions width x height. That is, this
+ image-stream does NOT contain any headers describing the image dimensions.
- **Rationale**: the dimension is already known from other sources,
- so storing it again would be redundant and error-prone.
+ **Rationale**: The dimensions are already known from other sources,
+ so storing them again would be redundant and prone to error.
- Once the image-stream is decoded into ARGB color values, following
- the process described in the lossless format specification, the
- transparency information must be extracted from the *green* channel
- of the ARGB quadruplet.
+ Once the image-stream is decoded into Alpha, Red, Green, Blue (ARGB) color
+ values, following the process described in the lossless format
+ specification, the transparency information must be extracted from the
+ *green* channel of the ARGB quadruplet.
- **Rationale**: the green channel is allowed extra transformation
+ **Rationale**: The green channel is allowed extra transformation
steps in the specification -- unlike the other channels -- that can
improve compression.
@@ -650,13 +654,13 @@ compression method is '0') or compressed using the lossless format
This chunk contains compressed bitstream data for a single frame.
-A bitstream chunk may be either (i) a VP8 chunk, using "VP8 " (note the
-significant fourth-character space) as its tag _or_ (ii) a VP8L chunk, using
-"VP8L" as its tag.
+A bitstream chunk may be either (i) a 'VP8 ' Chunk, using 'VP8 ' (note the
+significant fourth-character space) as its FourCC, _or_ (ii) a 'VP8L' Chunk,
+using 'VP8L' as its FourCC.
-The formats of VP8 and VP8L chunks are as described in sections
+The formats of 'VP8 ' and 'VP8L' Chunks are as described in sections
[Simple File Format (Lossy)](#simple-file-format-lossy)
-and [Simple File Format (Lossless)](#simple-file-format-lossless) respectively.
+and [Simple File Format (Lossless)](#simple-file-format-lossless), respectively.
#### Color Profile
@@ -683,14 +687,14 @@ If this chunk is not present, sRGB SHOULD be assumed.
#### Metadata
-Metadata can be stored in 'EXIF' or 'XMP ' chunks.
+Metadata can be stored in 'EXIF' or 'XMP ' Chunks.
There SHOULD be at most one chunk of each type ('EXIF' and 'XMP '). If there
are more such chunks, readers MAY ignore all except the first one.
The chunks are defined as follows:
-EXIF chunk:
+'EXIF' Chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -705,7 +709,7 @@ Exif Metadata: _Chunk Size_ bytes
: Image metadata in Exif format.
-XMP chunk:
+'XMP ' Chunk:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -720,62 +724,62 @@ XMP Metadata: _Chunk Size_ bytes
: Image metadata in XMP format.
-Note the fourth character in the 'XMP ' FourCC is an ASCII space (0x20).
+Note that the fourth character in the 'XMP ' FourCC is an ASCII space (0x20).
Additional guidance about handling metadata can be found in the
-Metadata Working Group's [Guidelines for Handling Metadata][metadata].
+Metadata Working Group's ["Guidelines for Handling Metadata"][metadata].
#### Unknown Chunks
-A RIFF chunk (described in [this](#terminology-amp-basics) section) whose _chunk
-tag_ is different from any of the chunks described in this document, is
+A RIFF chunk (described in the [RIFF File Format](#riff-file-format) section)
+whose FourCC is different from any of the chunks described in this document, is
considered an _unknown chunk_.
**Rationale**: Allowing unknown chunks gives a provision for future extension
-of the format, and also allows storage of any application-specific data.
+of the format and also allows storage of any application-specific data.
A file MAY contain unknown chunks:
- * At the end of the file as described in [Extended WebP file
- header](#extended_header) section.
- * At the end of ANMF chunks as described in the
+ * at the end of the file, as described in [Extended WebP file
+ header](#extended_header) section, or
+ * at the end of 'ANMF' Chunks, as described in the
[Animation](#animation) section.
Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their
original order (unless they specifically intend to modify these chunks).
-### Assembling the Canvas From Frames
+### Canvas Assembly from Frames
Here we provide an overview of how a reader MUST assemble a canvas in the case
of an animated image.
The process begins with creating a canvas using the dimensions given in the
-'VP8X' chunk, `Canvas Width Minus One + 1` pixels wide by `Canvas Height Minus
-One + 1` pixels high. The `Loop Count` field from the 'ANIM' chunk controls how
+'VP8X' Chunk, `Canvas Width Minus One + 1` pixels wide by `Canvas Height Minus
+One + 1` pixels high. The `Loop Count` field from the 'ANIM' Chunk controls how
many times the animation process is repeated. This is `Loop Count - 1` for
-non-zero `Loop Count` values or infinitely if `Loop Count` is zero.
+nonzero `Loop Count` values or infinite if the `Loop Count` is zero.
-At the beginning of each loop iteration the canvas is filled using the
-background color from the 'ANIM' chunk or an application defined color.
+At the beginning of each loop iteration, the canvas is filled using the
+background color from the 'ANIM' Chunk or an application-defined color.
-'ANMF' chunks contain individual frames given in display order. Before rendering
+'ANMF' Chunks contain individual frames given in display order. Before rendering
each frame, the previous frame's `Disposal method` is applied.
The rendering of the decoded frame begins at the Cartesian coordinates (`2 *
-Frame X`, `2 * Frame Y`) using the top-left corner of the canvas as the origin.
+Frame X`, `2 * Frame Y`), using the top-left corner of the canvas as the origin.
`Frame Width Minus One + 1` pixels wide by `Frame Height Minus One + 1` pixels
high are rendered onto the canvas using the `Blending method`.
The canvas is displayed for `Frame Duration` milliseconds. This continues until
-all frames given by 'ANMF' chunks have been displayed. A new loop iteration is
-then begun or the canvas is left in its final state if all iterations have been
+all frames given by 'ANMF' Chunks have been displayed. A new loop iteration is
+then begun, or the canvas is left in its final state if all iterations have been
completed.
The following pseudocode illustrates the rendering process. The notation
-_VP8X.field_ means the field in the 'VP8X' chunk with the same description.
+_VP8X.field_ means the field in the 'VP8X' Chunk with the same description.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-assert VP8X.flags.hasAnimation
+VP8X.flags.hasAnimation MUST be TRUE
canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with
background color ANIM.background_color.
loop_count ← ANIM.loopCount
@@ -783,9 +787,9 @@ dispose_method ← Dispose to background color
if loop_count == 0:
loop_count = ∞
frame_params ← nil
-assert next chunk in image_data is ANMF
+next chunk in image_data is ANMF MUST be TRUE
for loop = 0..loop_count - 1
- clear canvas to ANIM.background_color or application defined color
+ clear canvas to ANIM.background_color or application-defined color
until eof or non-ANMF chunk
frame_params.frameX = Frame X
frame_params.frameY = Frame Y
@@ -794,22 +798,24 @@ for loop = 0..loop_count - 1
frame_params.frameDuration = Frame Duration
frame_right = frame_params.frameX + frame_params.frameWidth
frame_bottom = frame_params.frameY + frame_params.frameHeight
- assert VP8X.canvasWidth >= frame_right
- assert VP8X.canvasHeight >= frame_bottom
+ VP8X.canvasWidth >= frame_right MUST be TRUE
+ VP8X.canvasHeight >= frame_bottom MUST be TRUE
for subchunk in 'Frame Data':
if subchunk.tag == "ALPH":
- assert alpha subchunks not found in 'Frame Data' earlier
+ alpha subchunks not found in 'Frame Data' earlier MUST be
+ TRUE
frame_params.alpha = alpha_data
else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
- assert bitstream subchunks not found in 'Frame Data' earlier
+ bitstream subchunks not found in 'Frame Data' earlier MUST
+ be TRUE
frame_params.bitstream = bitstream_data
render frame with frame_params.alpha and frame_params.bitstream
on canvas with top-left corner at (frame_params.frameX,
- frame_params.frameY), using blending method
+ frame_params.frameY), using Blending method
frame_params.blendingMethod.
canvas contains the decoded image.
Show the contents of the canvas for
- frame_params.frameDuration * 1ms.
+ frame_params.frameDuration * 1 ms.
dispose_method = frame_params.disposeMethod
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -817,7 +823,7 @@ for loop = 0..loop_count - 1
Example File Layouts
--------------------
-A lossy encoded image with alpha may look as follows:
+A lossy-encoded image with alpha may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
@@ -826,16 +832,16 @@ RIFF/WEBP
+- VP8 (bitstream)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A losslessly encoded image may look as follows:
+A lossless-encoded image may look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF/WEBP
+- VP8X (descriptions of features used)
-+- XYZW (unknown chunk)
+- VP8L (lossless bitstream)
++- XYZW (unknown chunk)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A lossless image with ICC profile and XMP metadata may
+A lossless image with an ICC profile and XMP metadata may
look as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -859,10 +865,11 @@ RIFF/WEBP
+- EXIF (metadata)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-[vp8spec]: https://datatracker.ietf.org/doc/html/rfc6386
[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/webp-lossless-bitstream-spec.txt
[iccspec]: https://www.color.org/icc_specs2.xalter
[metadata]: https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
+[rec601]: https://www.itu.int/rec/R-REC-BT.601
[rfc 1166]: https://datatracker.ietf.org/doc/html/rfc1166
[rfc 2119]: https://datatracker.ietf.org/doc/html/rfc2119
+[rfc 6386]: https://datatracker.ietf.org/doc/html/rfc6386
[rfc 8174]: https://datatracker.ietf.org/doc/html/rfc8174
diff --git a/doc/webp-lossless-bitstream-spec.txt b/doc/webp-lossless-bitstream-spec.txt
index 563426d4..f4db09a7 100644
--- a/doc/webp-lossless-bitstream-spec.txt
+++ b/doc/webp-lossless-bitstream-spec.txt
@@ -12,32 +12,22 @@ at the end of this file.
Specification for WebP Lossless Bitstream
=========================================
-_Jyrki Alakuijala, Ph.D., Google, Inc., 2012-06-19_
-
-Paragraphs marked as \[AMENDED\] were amended on 2014-09-16.
-
-Paragraphs marked as \[AMENDED2\] were amended on 2022-05-13.
-
-Paragraphs marked as \[AMENDED3\] were amended on 2022-11-21.
+_Jyrki Alakuijala, Ph.D., Google, Inc., 2023-03-09_
Abstract
--------
WebP lossless is an image format for lossless compression of ARGB images. The
lossless format stores and restores the pixel values exactly, including the
-color values for pixels whose alpha value is 0. The format uses subresolution
-images, recursively embedded into the format itself, for storing statistical
-data about the images, such as the used entropy codes, spatial predictors, color
-space conversion, and color table. LZ77, prefix coding, and a color cache are
-used for compression of the bulk data. Decoding speeds faster than PNG have been
+color values for fully transparent pixels. A universal algorithm for sequential
+data compression (LZ77), prefix coding, and a color cache are used for
+compression of the bulk data. Decoding speeds faster than PNG have been
demonstrated, as well as 25% denser compression than can be achieved using
today's PNG format.
-
* TOC placeholder
{:toc}
-
1 Introduction
--------------
@@ -46,7 +36,7 @@ image. It is intended as a detailed reference for the WebP lossless encoder and
decoder implementation.
In this document, we extensively use C programming language syntax to describe
-the bitstream, and assume the existence of a function for reading bits,
+the bitstream and assume the existence of a function for reading bits,
`ReadBits(n)`. The bytes are read in the natural order of the stream containing
them, and bits of each byte are read in least-significant-bit-first order. When
multiple bits are read at the same time, the integer is constructed from the
@@ -65,20 +55,19 @@ b = ReadBits(1);
b |= ReadBits(1) << 1;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We assume that each color component (e.g. alpha, red, blue and green) is
+We assume that each color component, that is, alpha, red, blue, and green, is
represented using an 8-bit byte. We define the corresponding type as uint8. A
-whole ARGB pixel is represented by a type called uint32, an unsigned integer
-consisting of 32 bits. In the code showing the behavior of the transformations,
-alpha value is codified in bits 31..24, red in bits 23..16, green in bits 15..8
-and blue in bits 7..0, but implementations of the format are free to use another
-representation internally.
-
-Broadly, a WebP lossless image contains header data, transform information and
-actual image data. Headers contain width and height of the image. A WebP
-lossless image can go through four different types of transformation before
-being entropy encoded. The transform information in the bitstream contains the
-data required to apply the respective inverse transforms.
-
+whole ARGB pixel is represented by a type called uint32, which is an unsigned
+integer consisting of 32 bits. In the code showing the behavior of the
+transforms, these values are codified in the following bits: alpha in bits
+31..24, red in bits 23..16, green in bits 15..8, and blue in bits 7..0; however,
+implementations of the format are free to use another representation internally.
+
+Broadly, a WebP lossless image contains header data, transform information, and
+actual image data. Headers contain the width and height of the image. A WebP
+lossless image can go through four different types of transforms before being
+entropy encoded. The transform information in the bitstream contains the data
+required to apply the respective inverse transforms.
2 Nomenclature
--------------
@@ -90,7 +79,7 @@ ARGB image
: A two-dimensional array containing ARGB pixels.
color cache
-: A small hash-addressed array to store recently used colors, to be able to
+: A small hash-addressed array to store recently used colors to be able to
recall them with shorter codes.
color indexing image
@@ -102,20 +91,16 @@ color transform image
color components.
distance mapping
-: Changes LZ77 distances to have the smallest values for pixels in 2D
- proximity.
+: Changes LZ77 distances to have the smallest values for pixels in
+ two-dimensional proximity.
entropy image
: A two-dimensional subresolution image indicating which entropy coding should
- be used in a respective square in the image, i.e., each pixel is a meta
+ be used in a respective square in the image, that is, each pixel is a meta
prefix code.
-prefix code
-: A classic way to do entropy coding where a smaller number of bits are used
- for more frequent codes.
-
LZ77
-: Dictionary-based sliding window compression algorithm that either emits
+: A dictionary-based sliding window compression algorithm that either emits
symbols or describes them as sequences of past symbols.
meta prefix code
@@ -126,16 +111,20 @@ predictor image
: A two-dimensional subresolution image indicating which spatial predictor is
used for a particular square in the image.
+prefix code
+: A classic way to do entropy coding where a smaller number of bits are used
+ for more frequent codes.
+
prefix coding
-: A way to entropy code larger integers that codes a few bits of the integer
+: A way to entropy code larger integers, which codes a few bits of the integer
using an entropy code and codifies the remaining bits raw. This allows for
the descriptions of the entropy codes to remain relatively small even when
the range of symbols is large.
scan-line order
-: A processing order of pixels, left-to-right, top-to-bottom, starting from
- the left-hand-top pixel, proceeding to the right. Once a row is completed,
- continue from the left-hand column of the next row.
+: A processing order of pixels (left to right and top to bottom), starting
+ from the left-hand-top pixel. Once a row is completed, continue from the
+ left-hand column of the next row.
3 RIFF Header
-------------
@@ -143,16 +132,16 @@ scan-line order
The beginning of the header has the RIFF container. This consists of the
following 21 bytes:
- 1. String "RIFF"
- 2. A little-endian 32 bit value of the block length, the whole size
- of the block controlled by the RIFF header. Normally this equals
+ 1. String 'RIFF'.
+ 2. A little-endian, 32-bit value of the chunk length, which is the whole size
+ of the chunk controlled by the RIFF header. Normally, this equals
the payload size (file size minus 8 bytes: 4 bytes for the 'RIFF'
identifier and 4 bytes for storing the value itself).
- 3. String "WEBP" (RIFF container name).
- 4. String "VP8L" (chunk tag for lossless encoded image data).
- 5. A little-endian 32-bit value of the number of bytes in the
+ 3. String 'WEBP' (RIFF container name).
+ 4. String 'VP8L' (FourCC for lossless-encoded image data).
+ 5. A little-endian, 32-bit value of the number of bytes in the
lossless stream.
- 6. One byte signature 0x2f.
+ 6. 1-byte signature 0x2f.
The first 28 bits of the bitstream specify the width and height of the image.
Width and height are decoded as 14-bit integers as follows:
@@ -162,8 +151,8 @@ int image_width = ReadBits(14) + 1;
int image_height = ReadBits(14) + 1;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The 14-bit dynamics for image size limit the maximum size of a WebP lossless
-image to 16384✕16384 pixels.
+The 14-bit precision for image width and height limits the maximum size of a
+WebP lossless image to 16384✕16384 pixels.
The alpha_is_used bit is a hint only, and should not impact decoding. It should
be set to 0 when all alpha values are 255 in the picture, and 1 otherwise.
@@ -173,24 +162,24 @@ int alpha_is_used = ReadBits(1);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The version_number is a 3 bit code that must be set to 0. Any other value should
-be treated as an error. \[AMENDED\]
+be treated as an error.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int version_number = ReadBits(3);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+4 Transforms
+------------
-4 Transformations
------------------
-
-Transformations are reversible manipulations of the image data that can reduce
-the remaining symbolic entropy by modeling spatial and color correlations.
-Transformations can make the final compression more dense.
+The transforms are reversible manipulations of the image data that can reduce
+the remaining symbolic entropy by modeling spatial and color correlations. They
+can make the final compression more dense.
-An image can go through four types of transformation. A 1 bit indicates the
+An image can go through four types of transforms. A 1 bit indicates the
presence of a transform. Each transform is allowed to be used only once. The
-transformations are used only for the main level ARGB image: the subresolution
-images have no transforms, not even the 0 bit indicating the end-of-transforms.
+transforms are used only for the main-level ARGB image; the subresolution images
+(color transform image, entropy image, and predictor image) have no transforms,
+not even the 0 bit indicating the end of transforms.
Typically, an encoder would use these transforms to reduce the Shannon entropy
in the residual image. Also, the transform data can be decided based on entropy
@@ -204,10 +193,10 @@ while (ReadBits(1)) { // Transform present.
...
}
-// Decode actual image data (Section 4).
+// Decode actual image data (Section 5).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If a transform is present then the next two bits specify the transform type.
+If a transform is present, then the next two bits specify the transform type.
There are four types of transforms.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -221,39 +210,45 @@ enum TransformType {
The transform type is followed by the transform data. Transform data contains
the information required to apply the inverse transform and depends on the
-transform type. Next we describe the transform data for different types.
+transform type. The inverse transforms are applied in the reverse order that
+they are read from the bitstream, that is, last one first.
+Next, we describe the transform data for different types.
### 4.1 Predictor Transform
The predictor transform can be used to reduce entropy by exploiting the fact
that neighboring pixels are often correlated. In the predictor transform, the
current pixel value is predicted from the pixels already decoded (in scan-line
-order) and only the residual value (actual - predicted) is encoded. The
-_prediction mode_ determines the type of prediction to use. We divide the image
-into squares and all the pixels in a square use the same prediction mode.
+order) and only the residual value (actual - predicted) is encoded. The green
+component of a pixel defines which of the 14 predictors is used within a
+particular block of the ARGB image. The _prediction mode_ determines the type of
+prediction to use. We divide the image into squares, and all the pixels in a
+square use the same prediction mode.
The first 3 bits of prediction data define the block width and height in number
-of bits. The number of block columns, `block_xsize`, is used in indexing
-two-dimensionally.
+of bits.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int size_bits = ReadBits(3) + 2;
int block_width = (1 << size_bits);
int block_height = (1 << size_bits);
-#define DIV_ROUND_UP(num, den) ((num) + (den) - 1) / (den))
-int block_xsize = DIV_ROUND_UP(image_width, 1 << size_bits);
+#define DIV_ROUND_UP(num, den) (((num) + (den) - 1) / (den))
+int transform_width = DIV_ROUND_UP(image_width, 1 << size_bits);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The transform data contains the prediction mode for each block of the image. All
-the `block_width * block_height` pixels of a block use same prediction mode. The
-prediction modes are treated as pixels of an image and encoded using the same
-techniques described in [Chapter 5](#image-data).
+The transform data contains the prediction mode for each block of the image. It
+is a subresolution image where the green component of a pixel defines which of
+the 14 predictors is used for all the `block_width * block_height` pixels within
+a particular block of the ARGB image. This subresolution image is encoded using
+the same techniques described in [Chapter 5](#image-data).
-For a pixel _x, y_, one can compute the respective filter block address by:
+The number of block columns, `transform_width`, is used in two-dimensional
+indexing. For a pixel (x, y), one can compute the respective filter block
+address by:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-int block_index = (y >> size_bits) * block_xsize +
+int block_index = (y >> size_bits) * transform_width +
(x >> size_bits);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -261,7 +256,7 @@ There are 14 different prediction modes. In each prediction mode, the current
pixel value is predicted from one or more neighboring pixels whose values are
already known.
-We choose the neighboring pixels (TL, T, TR, and L) of the current pixel (P) as
+We chose the neighboring pixels (TL, T, TR, and L) of the current pixel (P) as
follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -273,12 +268,12 @@ X X X X X X X X X X X
X X X X X X X X X X X
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-where TL means top-left, T top, TR top-right, L left pixel. At the time of
-predicting a value for P, all pixels O, TL, T, TR and L have already been
-processed, and pixel P and all pixels X are unknown.
+where TL means top-left, T means top, TR means top-right, and L means left. At
+the time of predicting a value for P, all O, TL, T, TR and L pixels have already
+been processed, and the P pixel and all X pixels are unknown.
-Given the above neighboring pixels, the different prediction modes are defined
-as follows.
+Given the preceding neighboring pixels, the different prediction modes are
+defined as follows.
| Mode | Predicted value of each channel of the current pixel |
| ------ | ------------------------------------------------------- |
@@ -310,7 +305,7 @@ The Select predictor is defined as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uint32 Select(uint32 L, uint32 T, uint32 TL) {
- // L = left pixel, T = top pixel, TL = top left pixel.
+ // L = left pixel, T = top pixel, TL = top-left pixel.
// ARGB component estimates for prediction.
int pAlpha = ALPHA(L) + ALPHA(T) - ALPHA(TL);
@@ -325,7 +320,7 @@ uint32 Select(uint32 L, uint32 T, uint32 TL) {
abs(pGreen - GREEN(T)) + abs(pBlue - BLUE(T));
// Return either left or top, the one closer to the prediction.
- if (pL < pT) { // \[AMENDED\]
+ if (pL < pT) {
return L;
} else {
return T;
@@ -339,7 +334,7 @@ for each ARGB component as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Clamp the input value between 0 and 255.
int Clamp(int a) {
- return (a < 0) ? 0 : (a > 255) ? 255 : a;
+ return (a < 0) ? 0 : (a > 255) ? 255 : a;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -357,27 +352,39 @@ int ClampAddSubtractHalf(int a, int b) {
There are special handling rules for some border pixels. If there is a
prediction transform, regardless of the mode \[0..13\] for these pixels, the
-predicted value for the left-topmost pixel of the image is 0xff000000, L-pixel
-for all pixels on the top row, and T-pixel for all pixels on the leftmost
-column.
+predicted value for the left-topmost pixel of the image is 0xff000000, all
+pixels on the top row are L-pixel, and all pixels on the leftmost column are
+T-pixel.
-\[AMENDED2\] Addressing the TR-pixel for pixels on the rightmost column is
+Addressing the TR-pixel for pixels on the rightmost column is
exceptional. The pixels on the rightmost column are predicted by using the modes
-\[0..13\] just like pixels not on the border, but the leftmost pixel on the same
-row as the current pixel is instead used as the TR-pixel.
+\[0..13\], just like pixels not on the border, but the leftmost pixel on the
+same row as the current pixel is instead used as the TR-pixel.
+The final pixel value is obtained by adding each channel of the predicted value
+to the encoded residual value.
-### 4.2 Color Transform
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void PredictorTransformOutput(uint32 residual, uint32 pred,
+ uint8* alpha, uint8* red,
+ uint8* green, uint8* blue) {
+ *alpha = ALPHA(residual) + ALPHA(pred);
+ *red = RED(residual) + RED(pred);
+ *green = GREEN(residual) + GREEN(pred);
+ *blue = BLUE(residual) + BLUE(pred);
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-\[AMENDED2\]
+### 4.2 Color Transform
-The goal of the color transform is to decorrelate the R, G and B values of each
-pixel. The color transform keeps the green (G) value as it is, transforms red
-(R) based on green and transforms blue (B) based on green and then based on red.
+The goal of the color transform is to decorrelate the R, G, and B values of each
+pixel. The color transform keeps the green (G) value as it is, transforms the
+red (R) value based on the green value, and transforms the blue (B) value based
+on the green value and then on the red value.
As is the case for the predictor transform, first the image is divided into
-blocks and the same transform mode is used for all the pixels in a block. For
-each block there are three types of color transform elements.
+blocks, and the same transform mode is used for all the pixels in a block. For
+each block, there are three types of color transform elements.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef struct {
@@ -387,7 +394,7 @@ typedef struct {
} ColorTransformElement;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The actual color transformation is done by defining a color transform delta. The
+The actual color transform is done by defining a color transform delta. The
color transform delta depends on the `ColorTransformElement`, which is the same
for all the pixels in a particular block. The delta is subtracted during the
color transform. The inverse color transform then is just adding those deltas.
@@ -403,9 +410,9 @@ void ColorTransform(uint8 red, uint8 blue, uint8 green,
int tmp_blue = blue;
// Applying the transform is just subtracting the transform deltas
- tmp_red -= ColorTransformDelta(trans->green_to_red_, green);
- tmp_blue -= ColorTransformDelta(trans->green_to_blue_, green);
- tmp_blue -= ColorTransformDelta(trans->red_to_blue_, red);
+ tmp_red -= ColorTransformDelta(trans->green_to_red, green);
+ tmp_blue -= ColorTransformDelta(trans->green_to_blue, green);
+ tmp_blue -= ColorTransformDelta(trans->red_to_blue, red);
*new_red = tmp_red & 0xff;
*new_blue = tmp_blue & 0xff;
@@ -413,7 +420,7 @@ void ColorTransform(uint8 red, uint8 blue, uint8 green,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
`ColorTransformDelta` is computed using a signed 8-bit integer representing a
-3.5-fixed-point number, and a signed 8-bit RGB color channel (c) \[-128..127\]
+3.5-fixed-point number and a signed 8-bit RGB color channel (c) \[-128..127\]
and is defined as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -423,16 +430,16 @@ int8 ColorTransformDelta(int8 t, int8 c) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A conversion from the 8-bit unsigned representation (uint8) to the 8-bit signed
-one (int8) is required before calling `ColorTransformDelta()`. It should be
-performed using 8-bit two's complement (that is: uint8 range \[128..255\] is
-mapped to the \[-128..-1\] range of its converted int8 value).
+one (int8) is required before calling `ColorTransformDelta()`. The signed value
+should be interpreted as an 8-bit two's complement number (that is: uint8 range
+\[128..255\] is mapped to the \[-128..-1\] range of its converted int8 value).
The multiplication is to be done using more precision (with at least 16-bit
-dynamics). The sign extension property of the shift operation does not matter
-here: only the lowest 8 bits are used from the result, and there the sign
+precision). The sign extension property of the shift operation does not matter
+here; only the lowest 8 bits are used from the result, and there the sign
extension shifting and unsigned shifting are consistent with each other.
-Now we describe the contents of color transform data so that decoding can apply
+Now, we describe the contents of color transform data so that decoding can apply
the inverse color transform and recover the original red and blue values. The
first 3 bits of the color transform data contain the width and height of the
image block in number of bits, just like the predictor transform:
@@ -444,14 +451,16 @@ int block_height = 1 << size_bits;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The remaining part of the color transform data contains `ColorTransformElement`
-instances corresponding to each block of the image. `ColorTransformElement`
-instances are treated as pixels of an image and encoded using the methods
-described in [Chapter 5](#image-data).
+instances, corresponding to each block of the image. Each
+`ColorTransformElement` `'cte'` is treated as a pixel in a subresolution image
+whose alpha component is `255`, red component is `cte.red_to_blue`, green
+component is `cte.green_to_blue`, and blue component is `cte.green_to_red`.
During decoding, `ColorTransformElement` instances of the blocks are decoded and
the inverse color transform is applied on the ARGB values of the pixels. As
mentioned earlier, that inverse color transform is just adding
-`ColorTransformElement` values to the red and blue channels. \[AMENDED3\]
+`ColorTransformElement` values to the red and blue channels. The alpha and green
+channels are left as is.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void InverseTransform(uint8 red, uint8 green, uint8 blue,
@@ -473,13 +482,12 @@ void InverseTransform(uint8 red, uint8 green, uint8 blue,
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
### 4.3 Subtract Green Transform
The subtract green transform subtracts green values from red and blue values of
each pixel. When this transform is present, the decoder needs to add the green
-value to both red and blue. There is no data associated with this transform. The
-decoder applies the inverse transform as follows:
+value to both the red and blue values. There is no data associated with this
+transform. The decoder applies the inverse transform as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) {
@@ -488,11 +496,9 @@ void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-This transform is redundant as it can be modeled using the color transform, but
-it is still often useful. Since it can extend the dynamics of the color
-transform and there is no additional data here, the subtract green transform can
-be coded using fewer bits than a full-blown color transform.
-
+This transform is redundant, as it can be modeled using the color transform, but
+since there is no additional data here, the subtract green transform can be
+coded using fewer bits than a full-blown color transform.
### 4.4 Color Indexing Transform
@@ -500,30 +506,30 @@ If there are not many unique pixel values, it may be more efficient to create a
color index array and replace the pixel values by the array's indices. The color
indexing transform achieves this. (In the context of WebP lossless, we
specifically do not call this a palette transform because a similar but more
-dynamic concept exists in WebP lossless encoding: color cache).
+dynamic concept exists in WebP lossless encoding: color cache.)
The color indexing transform checks for the number of unique ARGB values in the
image. If that number is below a threshold (256), it creates an array of those
ARGB values, which is then used to replace the pixel values with the
corresponding index: the green channel of the pixels are replaced with the
-index; all alpha values are set to 255; all red and blue values to 0.
+index, all alpha values are set to 255, and all red and blue values to 0.
-The transform data contains color table size and the entries in the color table.
-The decoder reads the color indexing transform data as follows:
+The transform data contains the color table size and the entries in the color
+table. The decoder reads the color indexing transform data as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 8 bit value for color table size
+// 8-bit value for the color table size
int color_table_size = ReadBits(8) + 1;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The color table is stored using the image storage format itself. The color table
can be obtained by reading an image, without the RIFF header, image size, and
-transforms, assuming a height of one pixel and a width of `color_table_size`.
+transforms, assuming the height of 1 pixel and the width of `color_table_size`.
The color table is always subtraction-coded to reduce image entropy. The deltas
of palette colors contain typically much less entropy than the colors
themselves, leading to significant savings for smaller images. In decoding,
every final color in the color table can be obtained by adding the previous
-color component values by each ARGB component separately, and storing the least
+color component values by each ARGB component separately and storing the least
significant 8 bits of the result.
The inverse transform for the image is simply replacing the pixel values (which
@@ -535,14 +541,14 @@ is done based on the green component of the ARGB color.
argb = color_table[GREEN(argb)];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If the index is equal or larger than `color_table_size`, the argb color value
-should be set to 0x00000000 (transparent black). \[AMENDED\]
+If the index is equal to or larger than `color_table_size`, the argb color value
+should be set to 0x00000000 (transparent black).
When the color table is small (equal to or less than 16 colors), several pixels
are bundled into a single pixel. The pixel bundling packs several (2, 4, or 8)
pixels into a single pixel, reducing the image width respectively. Pixel
bundling allows for a more efficient joint distribution entropy coding of
-neighboring pixels, and gives some arithmetic coding-like benefits to the
+neighboring pixels and gives some arithmetic coding-like benefits to the
entropy code, but it can only be used when there are 16 or fewer unique values.
`color_table_size` specifies how many pixels are combined:
@@ -560,28 +566,35 @@ if (color_table_size <= 2) {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-`width_bits` has a value of 0, 1, 2 or 3. A value of 0 indicates no pixel
+`width_bits` has a value of 0, 1, 2, or 3. A value of 0 indicates no pixel
bundling is to be done for the image. A value of 1 indicates that two pixels are
combined, and each pixel has a range of \[0..15\]. A value of 2 indicates that
four pixels are combined, and each pixel has a range of \[0..3\]. A value of 3
indicates that eight pixels are combined and each pixel has a range of \[0..1\],
-i.e., a binary value.
+that is, a binary value.
The values are packed into the green component as follows:
- * `width_bits` = 1: for every x value where x ≡ 0 (mod 2), a green
- value at x is positioned into the 4 least-significant bits of the
- green value at x / 2, a green value at x + 1 is positioned into the
- 4 most-significant bits of the green value at x / 2.
- * `width_bits` = 2: for every x value where x ≡ 0 (mod 4), a green
+ * `width_bits` = 1: For every x value, where x ≡ 0 (mod 2), a green
+ value at x is positioned into the 4 least significant bits of the
+ green value at x / 2, and a green value at x + 1 is positioned into the
+ 4 most significant bits of the green value at x / 2.
+ * `width_bits` = 2: For every x value, where x ≡ 0 (mod 4), a green
value at x is positioned into the 2 least-significant bits of the
- green value at x / 4, green values at x + 1 to x + 3 are positioned in order
- to the more significant bits of the green value at x / 4.
- * `width_bits` = 3: for every x value where x ≡ 0 (mod 8), a green
- value at x is positioned into the least-significant bit of the green
- value at x / 8, green values at x + 1 to x + 7 are positioned in order to
- the more significant bits of the green value at x / 8.
+ green value at x / 4, and green values at x + 1 to x + 3 are positioned in
+ order to the more significant bits of the green value at x / 4.
+ * `width_bits` = 3: For every x value, where x ≡ 0 (mod 8), a green
+ value at x is positioned into the least significant bit of the green
+ value at x / 8, and green values at x + 1 to x + 7 are positioned in order
+ to the more significant bits of the green value at x / 8.
+
+After reading this transform, `image_width` is subsampled by `width_bits`. This
+affects the size of subsequent transforms. The new size can be calculated using
+`DIV_ROUND_UP`, as defined [earlier](#predictor-transform).
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+image_width = DIV_ROUND_UP(image_width, 1 << width_bits);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 Image Data
------------
@@ -593,23 +606,16 @@ Image data is an array of pixel values in scan-line order.
We use image data in five different roles:
1. ARGB image: Stores the actual pixels of the image.
- 1. Entropy image: Stores the
- [meta prefix codes](#decoding-of-meta-prefix-codes). The red and green
- components of a pixel define the meta prefix code used in a particular
- block of the ARGB image.
- 1. Predictor image: Stores the metadata for
- [Predictor Transform](#predictor-transform). The green component of a pixel
- defines which of the 14 predictors is used within a particular block of the
- ARGB image.
- 1. Color transform image. It is created by `ColorTransformElement` values
- (defined in [Color Transform](#color-transform)) for different blocks of
- the image. Each `ColorTransformElement` `'cte'` is treated as a pixel whose
- alpha component is `255`, red component is `cte.red_to_blue`, green
- component is `cte.green_to_blue` and blue component is `cte.green_to_red`.
- 1. Color indexing image: An array of size `color_table_size` (up to 256
- ARGB values) storing the metadata for the
- [Color Indexing Transform](#color-indexing-transform). This is stored as an
- image of width `color_table_size` and height `1`.
+ 1. Entropy image: Stores the meta prefix codes (see
+ ["Decoding of Meta Prefix Codes"](#decoding-of-meta-prefix-codes)).
+ 1. Predictor image: Stores the metadata for the predictor transform (see
+ ["Predictor Transform"](#predictor-transform)).
+ 1. Color transform image: Created by `ColorTransformElement` values
+ (defined in ["Color Transform"](#color-transform)) for different blocks of
+ the image.
+ 1. Color indexing image: An array of size `color_table_size` (up to 256 ARGB
+ values) storing the metadata for the color indexing transform (see
+ ["Color Indexing Transform"](#color-indexing-transform)).
### 5.2 Encoding of Image Data
@@ -622,25 +628,26 @@ several blocks may share the same entropy codes.
**Rationale:** Storing an entropy code incurs a cost. This cost can be minimized
if statistically similar blocks share an entropy code, thereby storing that code
only once. For example, an encoder can find similar blocks by clustering them
-using their statistical properties, or by repeatedly joining a pair of randomly
+using their statistical properties or by repeatedly joining a pair of randomly
selected clusters when it reduces the overall amount of bits needed to encode
the image.
Each pixel is encoded using one of the three possible methods:
- 1. Prefix coded literal: each channel (green, red, blue and alpha) is
- entropy-coded independently;
- 2. LZ77 backward reference: a sequence of pixels are copied from elsewhere
- in the image; or
- 3. Color cache code: using a short multiplicative hash code (color cache
+ 1. Prefix-coded literals: Each channel (green, red, blue, and alpha) is
+ entropy-coded independently.
+ 2. LZ77 backward reference: A sequence of pixels are copied from elsewhere in
+ the image.
+ 3. Color cache code: Using a short multiplicative hash code (color cache
index) of a recently seen color.
The following subsections describe each of these in detail.
-#### 5.2.1 Prefix Coded Literals
+#### 5.2.1 Prefix-Coded Literals
-The pixel is stored as prefix coded values of green, red, blue and alpha (in
-that order). See [this section](#decoding-entropy-coded-image-data) for details.
+The pixel is stored as prefix-coded values of green, red, blue, and alpha (in
+that order). See [Section 6.2.3](#decoding-entropy-coded-image-data) for
+details.
#### 5.2.2 LZ77 Backward Reference
@@ -654,12 +661,12 @@ Backward references are tuples of _length_ and _distance code_:
The length and distance values are stored using **LZ77 prefix coding**.
LZ77 prefix coding divides large integer values into two parts: the _prefix
-code_ and the _extra bits_: the prefix code is stored using an entropy code,
+code_ and the _extra bits_. The prefix code is stored using an entropy code,
while the extra bits are stored as they are (without an entropy code).
**Rationale**: This approach reduces the storage requirement for the entropy
-code. Also, large values are usually rare, and so extra bits would be used for
-very few values in the image. Thus, this approach results in better compression
+code. Also, large values are usually rare, so extra bits would be used for very
+few values in the image. Thus, this approach results in better compression
overall.
The following table denotes the prefix codes and extra bits used for storing
@@ -697,28 +704,27 @@ int offset = (2 + (prefix_code & 1)) << extra_bits;
return offset + ReadBits(extra_bits) + 1;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-**Distance Mapping:**
-{:#distance-mapping}
+##### Distance Mapping
As noted previously, a distance code is a number indicating the position of a
previously seen pixel, from which the pixels are to be copied. This subsection
defines the mapping between a distance code and the position of a previous
pixel.
-Distance codes larger than 120 denote the pixel-distance in scan-line order,
+Distance codes larger than 120 denote the pixel distance in scan-line order,
offset by 120.
-The smallest distance codes \[1..120\] are special, and are reserved for a close
+The smallest distance codes \[1..120\] are special and are reserved for a close
neighborhood of the current pixel. This neighborhood consists of 120 pixels:
- * Pixels that are 1 to 7 rows above the current pixel, and are up to 8 columns
+ * Pixels that are 1 to 7 rows above the current pixel and are up to 8 columns
to the left or up to 7 columns to the right of the current pixel. \[Total
such pixels = `7 * (8 + 1 + 7) = 112`\].
- * Pixels that are in same row as the current pixel, and are up to 8 columns to
- the left of the current pixel. \[`8` such pixels\].
+ * Pixels that are in the same row as the current pixel and are up to 8
+ columns to the left of the current pixel. \[`8` such pixels\].
-The mapping between distance code `i` and the neighboring pixel offset
-`(xi, yi)` is as follows:
+The mapping between distance code `distance_code` and the neighboring pixel
+offset `(xi, yi)` is as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(0, 1), (1, 0), (1, 1), (-1, 1), (0, 2), (2, 0), (1, 2),
@@ -743,25 +749,22 @@ The mapping between distance code `i` and the neighboring pixel offset
For example, the distance code `1` indicates an offset of `(0, 1)` for the
neighboring pixel, that is, the pixel above the current pixel (0 pixel
-difference in the X-direction and 1 pixel difference in the Y-direction).
-Similarly, the distance code `3` indicates the left-top pixel.
+difference in the X direction and 1 pixel difference in the Y direction).
+Similarly, the distance code `3` indicates the top-left pixel.
-The decoder can convert a distance code `i` to a scan-line order distance `dist`
-as follows:
-
-\[AMENDED3\]
+The decoder can convert a distance code `distance_code` to a scan-line order
+distance `dist` as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(xi, yi) = distance_map[i - 1]
-dist = xi + yi * xsize
+(xi, yi) = distance_map[distance_code - 1]
+dist = xi + yi * image_width
if (dist < 1) {
dist = 1
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-where `distance_map` is the mapping noted above and `xsize` is the width of the
-image in pixels.
-
+where `distance_map` is the mapping noted above, and `image_width` is the width
+of the image in pixels.
#### 5.2.3 Color Cache Coding
{:#color-cache-code}
@@ -770,7 +773,7 @@ Color cache stores a set of colors that have been recently used in the image.
**Rationale:** This way, the recently used colors can sometimes be referred to
more efficiently than emitting them using the other two methods (described in
-[5.2.1](#prefix-coded-literals) and [5.2.2](#lz77-backward-reference)).
+Sections [5.2.1](#prefix-coded-literals) and [5.2.2](#lz77-backward-reference)).
Color cache codes are stored as follows. First, there is a 1-bit value that
indicates if the color cache is used. If this bit is 0, no color cache codes
@@ -783,14 +786,14 @@ int color_cache_code_bits = ReadBits(4);
int color_cache_size = 1 << color_cache_code_bits;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-`color_cache_code_bits` defines the size of the color_cache by (1 <<
-`color_cache_code_bits`). The range of allowed values for
+`color_cache_code_bits` defines the size of the color cache (`1 <<
+color_cache_code_bits`). The range of allowed values for
`color_cache_code_bits` is \[1..11\]. Compliant decoders must indicate a
corrupted bitstream for other values.
A color cache is an array of size `color_cache_size`. Each entry stores one ARGB
-color. Colors are looked up by indexing them by (0x1e35a7bd * `color`) >> (32 -
-`color_cache_code_bits`). Only one lookup is done in a color cache; there is no
+color. Colors are looked up by indexing them by `(0x1e35a7bd * color) >> (32 -
+color_cache_code_bits)`. Only one lookup is done in a color cache; there is no
conflict resolution.
In the beginning of decoding or encoding of an image, all entries in all color
@@ -799,7 +802,6 @@ decoding time. The state of the color cache is maintained by inserting every
pixel, be it produced by backward referencing or as literals, into the cache in
the order they appear in the stream.
-
6 Entropy Code
--------------
@@ -809,7 +811,7 @@ Most of the data is coded using a [canonical prefix code][canonical_huff].
Hence, the codes are transmitted by sending the _prefix code lengths_, as
opposed to the actual _prefix codes_.
-In particular, the format uses **spatially-variant prefix coding**. In other
+In particular, the format uses **spatially variant prefix coding**. In other
words, different blocks of the image can potentially use different entropy
codes.
@@ -821,31 +823,41 @@ potentially better compression.
The encoded image data consists of several parts:
- 1. Decoding and building the prefix codes \[AMENDED2\]
- 1. Meta prefix codes
- 1. Entropy-coded image data
+ 1. Decoding and building the prefix codes.
+ 1. Meta prefix codes.
+ 1. Entropy-coded image data.
-#### 6.2.1 Decoding and Building the Prefix Codes
+For any given pixel (x, y), there is a set of five prefix codes associated with
+it. These codes are (in bitstream order):
+
+ * **Prefix code #1**: Used for green channel, backward-reference length, and
+ color cache.
+ * **Prefix code #2, #3, and #4**: Used for red, blue, and alpha channels,
+ respectively.
+ * **Prefix code #5**: Used for backward-reference distance.
-There are several steps in decoding the prefix codes.
+From here on, we refer to this set as a **prefix code group**.
-**Decoding the Code Lengths:**
-{:#decoding-the-code-lengths}
+#### 6.2.1 Decoding and Building the Prefix Codes
This section describes how to read the prefix code lengths from the bitstream.
The prefix code lengths can be coded in two ways. The method used is specified
by a 1-bit value.
- * If this bit is 1, it is a _simple code length code_, and
+ * If this bit is 1, it is a _simple code length code_.
* If this bit is 0, it is a _normal code length code_.
In both cases, there can be unused code lengths that are still part of the
stream. This may be inefficient, but it is allowed by the format.
+The described tree must be a complete binary tree. A single leaf node is
+considered a complete binary tree and can be encoded using either the simple
+code length code or the normal code length code. When coding a single leaf
+node using the _normal code length code_, all but one code length are zeros,
+and the single leaf node value is marked with the length of 1 -- even when no
+bits are consumed when that single leaf node tree is used.
-**(i) Simple Code Length Code:**
-
-\[AMENDED2\]
+##### Simple Code Length Code
This variant is used in the special case when only 1 or 2 prefix symbols are in
the range \[0..255\] with code length `1`. All other prefix code lengths are
@@ -857,9 +869,9 @@ The first bit indicates the number of symbols:
int num_symbols = ReadBits(1) + 1;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Following are the symbol values.
+The following are the symbol values.
-This first symbol is coded using 1 or 8 bits depending on the value of
+This first symbol is coded using 1 or 8 bits, depending on the value of
`is_first_8bits`. The range is \[0..1\] or \[0..255\], respectively. The second
symbol, if present, is always assumed to be in the range \[0..255\] and coded
using 8 bits.
@@ -874,6 +886,9 @@ if (num_symbols == 2) {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The two symbols should be different. Duplicate symbols are allowed, but
+inefficient.
+
**Note:** Another special case is when _all_ prefix code lengths are _zeros_ (an
empty prefix code). For example, a prefix code for distance can be empty if
there are no backward references. Similarly, prefix codes for alpha, red, and
@@ -881,7 +896,7 @@ blue can be empty if all pixels within the same meta prefix code are produced
using the color cache. However, this case doesn't need special handling, as
empty prefix codes can be coded as those containing a single symbol `0`.
-**(ii) Normal Code Length Code:**
+##### Normal Code Length Code
The code lengths of the prefix code fit in 8 bits and are read as follows.
First, `num_code_lengths` specifies the number of code lengths.
@@ -890,9 +905,7 @@ First, `num_code_lengths` specifies the number of code lengths.
int num_code_lengths = 4 + ReadBits(4);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If `num_code_lengths` is > 19, the bitstream is invalid. \[AMENDED3\]
-
-The code lengths are themselves encoded using prefix codes: lower level code
+The code lengths are themselves encoded using prefix codes; lower-level code
lengths, `code_length_code_lengths`, first have to be read. The rest of those
`code_length_code_lengths` (according to the order in `kCodeLengthCodeOrder`)
are zeros.
@@ -908,34 +921,45 @@ for (i = 0; i < num_code_lengths; ++i) {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Next, if `ReadBits(1) == 0`, the maximum number of different read symbols is
-`num_code_lengths`. Otherwise, it is defined as:
+Next, if `ReadBits(1) == 0`, the maximum number of different read symbols
+(`max_symbol`) for each symbol type (A, R, G, B, and distance) is set to its
+alphabet size:
+
+ * G channel: 256 + 24 + `color_cache_size`
+ * Other literals (A, R, and B): 256
+ * Distance code: 40
+
+Otherwise, it is defined as:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int length_nbits = 2 + 2 * ReadBits(3);
int max_symbol = 2 + ReadBits(length_nbits);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If `max_symbol` is larger than the size of the alphabet for the symbol type, the
+bitstream is invalid.
+
A prefix table is then built from `code_length_code_lengths` and used to read up
to `max_symbol` code lengths.
* Code \[0..15\] indicates literal code lengths.
* Value 0 means no symbols have been coded.
* Values \[1..15\] indicate the bit length of the respective code.
- * Code 16 repeats the previous non-zero value \[3..6\] times, i.e.,
- `3 + ReadBits(2)` times. If code 16 is used before a non-zero
+ * Code 16 repeats the previous nonzero value \[3..6\] times, that is,
+ `3 + ReadBits(2)` times. If code 16 is used before a nonzero
value has been emitted, a value of 8 is repeated.
- * Code 17 emits a streak of zeros \[3..10\], i.e., `3 + ReadBits(3)`
- times.
- * Code 18 emits a streak of zeros of length \[11..138\], i.e.,
+ * Code 17 emits a streak of zeros of length \[3..10\], that is, `3 +
+ ReadBits(3)` times.
+ * Code 18 emits a streak of zeros of length \[11..138\], that is,
`11 + ReadBits(7)` times.
-Once code lengths are read, a prefix code for each symbol type (A, R, G, B,
-distance) is formed using their respective alphabet sizes:
+Once code lengths are read, a prefix code for each symbol type (A, R, G, B, and
+distance) is formed using their respective alphabet sizes.
- * G channel: 256 + 24 + `color_cache_size`
- * other literals (A,R,B): 256
- * distance code: 40
+The Normal Code Length Code must code a full decision tree, that is, the sum of
+`2 ^ (-length)` for all non-zero codes must be exactly one. There is however
+one exception to this rule, the single leaf node tree, where the leaf node
+value is marked with value 1 and other values are 0s.
#### 6.2.2 Decoding of Meta Prefix Codes
@@ -954,37 +978,31 @@ value:
* If this bit is one, the image uses multiple meta prefix codes. These meta
prefix codes are stored as an _entropy image_ (described below).
-**Entropy image:**
+The red and green components of a pixel define a 16-bit meta prefix code used in
+a particular block of the ARGB image.
+
+##### Entropy Image
The entropy image defines which prefix codes are used in different parts of the
-image, as described below.
+image.
-The first 3-bits contain the `prefix_bits` value. The dimensions of the entropy
-image are derived from `prefix_bits`.
+The first 3 bits contain the `prefix_bits` value. The dimensions of the entropy
+image are derived from `prefix_bits`:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int prefix_bits = ReadBits(3) + 2;
-int prefix_xsize = DIV_ROUND_UP(xsize, 1 << prefix_bits);
-int prefix_ysize = DIV_ROUND_UP(ysize, 1 << prefix_bits);
+int prefix_image_width =
+ DIV_ROUND_UP(image_width, 1 << prefix_bits);
+int prefix_image_height =
+ DIV_ROUND_UP(image_height, 1 << prefix_bits);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
where `DIV_ROUND_UP` is as defined [earlier](#predictor-transform).
-The next bits contain an entropy image of width `prefix_xsize` and height
-`prefix_ysize`.
-
-**Interpretation of Meta Prefix Codes:**
-
-For any given pixel (x, y), there is a set of five prefix codes associated with
-it. These codes are (in bitstream order):
+The next bits contain an entropy image of width `prefix_image_width` and height
+`prefix_image_height`.
- * **Prefix code #1**: used for green channel, backward-reference length and
- color cache.
- * **Prefix code #2, #3 and #4**: used for red, blue and alpha channels
- respectively.
- * **Prefix code #5**: used for backward-reference distance.
-
-From here on, we refer to this set as a **prefix code group**.
+##### Interpretation of Meta Prefix Codes
The number of prefix code groups in the ARGB image can be obtained by finding
the _largest meta prefix code_ from the entropy image:
@@ -1007,71 +1025,73 @@ codes to be used as follows:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int position =
- (y >> prefix_bits) * prefix_xsize + (x >> prefix_bits);
-int meta_prefix_code = (entropy_image[pos] >> 8) & 0xffff;
+ (y >> prefix_bits) * prefix_image_width + (x >> prefix_bits);
+int meta_prefix_code = (entropy_image[position] >> 8) & 0xffff;
PrefixCodeGroup prefix_group = prefix_code_groups[meta_prefix_code];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-where, we have assumed the existence of `PrefixCodeGroup` structure, which
+where we have assumed the existence of `PrefixCodeGroup` structure, which
represents a set of five prefix codes. Also, `prefix_code_groups` is an array of
`PrefixCodeGroup` (of size `num_prefix_groups`).
The decoder then uses prefix code group `prefix_group` to decode the pixel
-(x, y) as explained in the [next section](#decoding-entropy-coded-image-data).
+(x, y), as explained in ["Decoding Entropy-Coded Image
+Data"](#decoding-entropy-coded-image-data).
-#### 6.2.3 Decoding Entropy-coded Image Data
-
-\[AMENDED2\]
+#### 6.2.3 Decoding Entropy-Coded Image Data
For the current position (x, y) in the image, the decoder first identifies the
corresponding prefix code group (as explained in the last section). Given the
-prefix code group, the pixel is read and decoded as follows:
+prefix code group, the pixel is read and decoded as follows.
-Read the next symbol S from the bitstream using prefix code #1. Note that S is
+Next, read the symbol S from the bitstream using prefix code #1. Note that S is
any integer in the range `0` to
`(256 + 24 + ` [`color_cache_size`](#color-cache-code)` - 1)`.
The interpretation of S depends on its value:
- 1. if S < 256
+ 1. If S < 256
1. Use S as the green component.
1. Read red from the bitstream using prefix code #2.
1. Read blue from the bitstream using prefix code #3.
1. Read alpha from the bitstream using prefix code #4.
- 1. if S >= 256 && S < 256 + 24
+ 1. If S >= 256 & S < 256 + 24
1. Use S - 256 as a length prefix code.
- 1. Read extra bits for length from the bitstream.
+ 1. Read extra bits for the length from the bitstream.
1. Determine backward-reference length L from length prefix code and the
extra bits read.
- 1. Read distance prefix code from the bitstream using prefix code #5.
- 1. Read extra bits for distance from the bitstream.
- 1. Determine backward-reference distance D from distance prefix code and
- the extra bits read.
- 1. Copy the L pixels (in scan-line order) from the sequence of pixels
- prior to them by D pixels.
- 1. if S >= 256 + 24
+ 1. Read the distance prefix code from the bitstream using prefix code #5.
+ 1. Read extra bits for the distance from the bitstream.
+ 1. Determine backward-reference distance D from the distance prefix code
+ and the extra bits read.
+ 1. Copy L pixels (in scan-line order) from the sequence of pixels starting
+ at the current position minus D pixels.
+ 1. If S >= 256 + 24
1. Use S - (256 + 24) as the index into the color cache.
1. Get ARGB color from the color cache at that index.
-
7 Overall Structure of the Format
---------------------------------
-Below is a view into the format in Augmented Backus-Naur Form ([ABNF]). It does
-not cover all details. End-of-image (EOI) is only implicitly coded into the
-number of pixels (xsize * ysize).
+Below is a view into the format in Augmented Backus-Naur Form (ABNF)
+[RFC 5234][] [RFC 7405][]. It does not cover all details. The end-of-image (EOI)
+is only implicitly coded into the number of pixels (image_width * image_height).
+Note that `*element` means `element` can be repeated 0 or more times. `5element`
+means `element` is repeated exactly 5 times. `%b` represents a binary value.
#### 7.1 Basic Structure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-format = RIFF-header image-size image-stream
-RIFF-header = "RIFF" 4OCTET "WEBP" "VP8L" 4OCTET %x2F
-image-size = 14BIT 14BIT ; width - 1, height - 1
-image-stream = optional-transform spatially-coded-image
+format = RIFF-header image-header image-stream
+RIFF-header = %s"RIFF" 4OCTET %s"WEBPVP8L" 4OCTET
+image-header = %x2F image-size alpha-is-used version
+image-size = 14BIT 14BIT ; width - 1, height - 1
+alpha-is-used = 1BIT
+version = 3BIT ; 0
+image-stream = optional-transform spatially-coded-image
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
#### 7.2 Structure of Transforms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1094,11 +1114,8 @@ color-indexing-image = 8BIT ; color count
entropy-coded-image
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
#### 7.3 Structure of the Image Data
-\[AMENDED2\]
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
spatially-coded-image = color-cache-info meta-prefix data
entropy-coded-image = color-cache-info data
@@ -1120,14 +1137,13 @@ prefix-code-group =
prefix-code = simple-prefix-code / normal-prefix-code
simple-prefix-code = ; see "Simple Code Length Code" for details
-normal-prefix-code = code-length-code encoded-code-lengths
-code-length-code = ; see section "Normal Code Length Code"
+normal-prefix-code = ; see "Normal Code Length Code" for details
lz77-coded-image =
*((argb-pixel / lz77-copy / color-cache-code) lz77-coded-image)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A possible example sequence:
+The following is a possible example sequence:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RIFF-header image-size %b1 subtract-green-tx
@@ -1135,5 +1151,6 @@ RIFF-header image-size %b1 subtract-green-tx
%b0 prefix-codes lz77-coded-image
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-[ABNF]: https://www.rfc-editor.org/rfc/rfc5234
+[RFC 5234]: https://www.rfc-editor.org/rfc/rfc5234
+[RFC 7405]: https://www.rfc-editor.org/rfc/rfc7405
[canonical_huff]: https://en.wikipedia.org/wiki/Canonical_Huffman_code
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 72aa9f91..bbf0bac9 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -92,7 +92,7 @@ webpmux_LDADD += ../src/mux/libwebpmux.la
webpmux_LDADD += ../src/libwebp.la
img2webp_SOURCES = img2webp.c
-img2webp_CPPFLAGS = $(AM_CPPFLAGS)
+img2webp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)
img2webp_LDADD =
img2webp_LDADD += libexample_util.la
img2webp_LDADD += ../imageio/libimageio_util.la
diff --git a/examples/anim_dump.c b/examples/anim_dump.c
index e4473386..269cbaba 100644
--- a/examples/anim_dump.c
+++ b/examples/anim_dump.c
@@ -98,7 +98,11 @@ int main(int argc, const char* argv[]) {
for (i = 0; !error && i < image.num_frames; ++i) {
W_CHAR out_file[1024];
WebPDecBuffer buffer;
- WebPInitDecBuffer(&buffer);
+ if (!WebPInitDecBuffer(&buffer)) {
+ fprintf(stderr, "Cannot init dec buffer\n");
+ error = 1;
+ continue;
+ }
buffer.colorspace = MODE_RGBA;
buffer.is_external_memory = 1;
buffer.width = image.canvas_width;
diff --git a/examples/cwebp.c b/examples/cwebp.c
index 9adb31ec..cab70054 100644
--- a/examples/cwebp.c
+++ b/examples/cwebp.c
@@ -306,6 +306,7 @@ static int MyWriter(const uint8_t* data, size_t data_size,
// Dumps a picture as a PGM file using the IMC4 layout.
static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
int y;
+ int ok = 0;
const int uv_width = (picture->width + 1) / 2;
const int uv_height = (picture->height + 1) / 2;
const int stride = (picture->width + 1) & ~1;
@@ -320,23 +321,26 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
if (f == NULL) return 0;
fprintf(f, "P5\n%d %d\n255\n", stride, height);
for (y = 0; y < picture->height; ++y) {
- if (fwrite(src_y, picture->width, 1, f) != 1) return 0;
+ if (fwrite(src_y, picture->width, 1, f) != 1) goto Error;
if (picture->width & 1) fputc(0, f); // pad
src_y += picture->y_stride;
}
for (y = 0; y < uv_height; ++y) {
- if (fwrite(src_u, uv_width, 1, f) != 1) return 0;
- if (fwrite(src_v, uv_width, 1, f) != 1) return 0;
+ if (fwrite(src_u, uv_width, 1, f) != 1) goto Error;
+ if (fwrite(src_v, uv_width, 1, f) != 1) goto Error;
src_u += picture->uv_stride;
src_v += picture->uv_stride;
}
for (y = 0; y < alpha_height; ++y) {
- if (fwrite(src_a, picture->width, 1, f) != 1) return 0;
+ if (fwrite(src_a, picture->width, 1, f) != 1) goto Error;
if (picture->width & 1) fputc(0, f); // pad
src_a += picture->a_stride;
}
+ ok = 1;
+
+ Error:
fclose(f);
- return 1;
+ return ok;
}
// -----------------------------------------------------------------------------
@@ -592,9 +596,8 @@ static void HelpLong(void) {
" green=0xe0 and blue=0xd0\n");
printf(" -noalpha ............... discard any transparency information\n");
printf(" -lossless .............. encode image losslessly, default=off\n");
- printf(" -near_lossless <int> ... use near-lossless image\n"
- " preprocessing (0..100=off), "
- "default=100\n");
+ printf(" -near_lossless <int> ... use near-lossless image preprocessing\n"
+ " (0..100=off), default=100\n");
printf(" -hint <string> ......... specify image characteristics hint,\n");
printf(" one of: photo, picture or graph\n");
diff --git a/examples/gifdec.c b/examples/gifdec.c
index 99ee9966..9b9a6947 100644
--- a/examples/gifdec.c
+++ b/examples/gifdec.c
@@ -317,7 +317,7 @@ void GIFDisplayError(const GifFileType* const gif, int gif_error) {
#else // !WEBP_HAVE_GIF
-static void ErrorGIFNotAvailable() {
+static void ErrorGIFNotAvailable(void) {
fprintf(stderr, "GIF support not compiled. Please install the libgif-dev "
"package before building.\n");
}
diff --git a/examples/img2webp.c b/examples/img2webp.c
index bfb1bfc1..3735030c 100644
--- a/examples/img2webp.c
+++ b/examples/img2webp.c
@@ -28,6 +28,7 @@
#include "../imageio/imageio_util.h"
#include "./stopwatch.h"
#include "./unicode.h"
+#include "sharpyuv/sharpyuv.h"
#include "webp/encode.h"
#include "webp/mux.h"
@@ -35,17 +36,22 @@
static void Help(void) {
printf("Usage:\n\n");
- printf(" img2webp [file_options] [[frame_options] frame_file]...\n");
- printf("\n");
+ printf(" img2webp [file_options] [[frame_options] frame_file]...");
+ printf(" [-o webp_file]\n\n");
printf("File-level options (only used at the start of compression):\n");
printf(" -min_size ............ minimize size\n");
- printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n");
printf(" -kmax <int> .......... maximum number of frame between key-frames\n"
" (0=only keyframes)\n");
printf(" -kmin <int> .......... minimum number of frame between key-frames\n"
" (0=disable key-frames altogether)\n");
printf(" -mixed ............... use mixed lossy/lossless automatic mode\n");
+ printf(" -near_lossless <int> . use near-lossless image preprocessing\n"
+ " (0..100=off), default=100\n");
+ printf(" -sharp_yuv ........... use sharper (and slower) RGB->YUV "
+ "conversion\n "
+ "(lossy only)\n");
+ printf(" -loop <int> .......... loop count (default: 0, = infinite loop)\n");
printf(" -v ................... verbose mode\n");
printf(" -h ................... this help\n");
printf(" -version ............. print version number and exit\n");
@@ -184,6 +190,11 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[c], "-mixed")) {
anim_config.allow_mixed = 1;
config.lossless = 0;
+ } else if (!strcmp(argv[c], "-near_lossless") && c + 1 < argc) {
+ argv[c] = NULL;
+ config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
+ } else if (!strcmp(argv[c], "-sharp_yuv")) {
+ config.use_sharp_yuv = 1;
} else if (!strcmp(argv[c], "-v")) {
verbose = 1;
} else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
@@ -192,10 +203,13 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[c], "-version")) {
const int enc_version = WebPGetEncoderVersion();
const int mux_version = WebPGetMuxVersion();
+ const int sharpyuv_version = SharpYuvGetVersion();
printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n",
(enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff,
enc_version & 0xff, (mux_version >> 16) & 0xff,
(mux_version >> 8) & 0xff, mux_version & 0xff);
+ printf("libsharpyuv: %d.%d.%d\n", (sharpyuv_version >> 24) & 0xff,
+ (sharpyuv_version >> 16) & 0xffff, sharpyuv_version & 0xff);
goto End;
} else {
continue;
diff --git a/examples/vwebp.c b/examples/vwebp.c
index 35f1b188..fa5fadb1 100644
--- a/examples/vwebp.c
+++ b/examples/vwebp.c
@@ -18,6 +18,7 @@
#define _POSIX_C_SOURCE 200112L // for setenv
#endif
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -430,10 +431,13 @@ static void HandleDisplay(void) {
#endif
}
-static void StartDisplay(void) {
+static void StartDisplay(const char* filename) {
int width = kParams.canvas_width;
int height = kParams.canvas_height;
int screen_width, screen_height;
+ const char viewername[] = " - WebP viewer";
+ // max linux file len + viewername string
+ char title[4096 + sizeof(viewername)] = "";
// TODO(webp:365) GLUT_DOUBLE results in flickering / old frames to be
// partially displayed with animated webp + alpha.
#if defined(__APPLE__) || defined(_WIN32)
@@ -453,8 +457,9 @@ static void StartDisplay(void) {
height = screen_height;
}
}
+ snprintf(title, sizeof(title), "%s%s", filename, viewername);
glutInitWindowSize(width, height);
- glutCreateWindow("WebP viewer");
+ glutCreateWindow(title);
glutDisplayFunc(HandleDisplay);
glutReshapeFunc(HandleReshape);
glutIdleFunc(NULL);
@@ -493,7 +498,7 @@ static void Help(void) {
}
int main(int argc, char* argv[]) {
- int c;
+ int c, file_name_argv_index = 1;
WebPDecoderConfig* const config = &kParams.config;
WebPIterator* const curr = &kParams.curr_frame;
@@ -540,7 +545,10 @@ int main(int argc, char* argv[]) {
} else if (!strcmp(argv[c], "-mt")) {
config->options.use_threads = 1;
} else if (!strcmp(argv[c], "--")) {
- if (c < argc - 1) kParams.file_name = (const char*)GET_WARGV(argv, ++c);
+ if (c < argc - 1) {
+ kParams.file_name = (const char*)GET_WARGV(argv, ++c);
+ file_name_argv_index = c;
+ }
break;
} else if (argv[c][0] == '-') {
printf("Unknown option '%s'\n", argv[c]);
@@ -548,6 +556,7 @@ int main(int argc, char* argv[]) {
FREE_WARGV_AND_RETURN(-1);
} else {
kParams.file_name = (const char*)GET_WARGV(argv, c);
+ file_name_argv_index = c;
}
if (parse_error) {
@@ -613,7 +622,7 @@ int main(int argc, char* argv[]) {
// Position iterator to last frame. Next call to HandleDisplay will wrap over.
// We take this into account by bumping up loop_count.
- WebPDemuxGetFrame(kParams.dmux, 0, curr);
+ if (!WebPDemuxGetFrame(kParams.dmux, 0, curr)) goto Error;
if (kParams.loop_count) ++kParams.loop_count;
#if defined(__unix__) || defined(__CYGWIN__)
@@ -627,7 +636,7 @@ int main(int argc, char* argv[]) {
#ifdef FREEGLUT
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
#endif
- StartDisplay();
+ StartDisplay(argv[file_name_argv_index]);
if (kParams.has_animation) glutTimerFunc(0, decode_callback, 0);
glutMainLoop();
diff --git a/examples/webpinfo.c b/examples/webpinfo.c
index 356abae5..1d2278ee 100644
--- a/examples/webpinfo.c
+++ b/examples/webpinfo.c
@@ -357,12 +357,12 @@ static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data,
}
data += 3;
data_size -= 3;
- printf(" Key frame: %s\n"
- " Profile: %d\n"
- " Display: %s\n"
- " Part. 0 length: %d\n",
- key_frame ? "Yes" : "No", profile,
- display ? "Yes" : "No", partition0_length);
+ printf(
+ " Key frame: %s\n"
+ " Profile: %d\n"
+ " Display: Yes\n"
+ " Part. 0 length: %d\n",
+ key_frame ? "Yes" : "No", profile, partition0_length);
if (key_frame) {
if (!(data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a)) {
LOG_ERROR("Invalid lossy bitstream signature.");
diff --git a/examples/webpmux.c b/examples/webpmux.c
index b61eed6e..9bf45103 100644
--- a/examples/webpmux.c
+++ b/examples/webpmux.c
@@ -150,16 +150,20 @@ static const char* ErrorString(WebPMuxError err) {
}
#define RETURN_IF_ERROR(ERR_MSG) \
- if (err != WEBP_MUX_OK) { \
- fprintf(stderr, ERR_MSG); \
- return err; \
- }
+ do { \
+ if (err != WEBP_MUX_OK) { \
+ fprintf(stderr, ERR_MSG); \
+ return err; \
+ } \
+ } while (0)
#define RETURN_IF_ERROR3(ERR_MSG, FORMAT_STR1, FORMAT_STR2) \
- if (err != WEBP_MUX_OK) { \
- fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
- return err; \
- }
+ do { \
+ if (err != WEBP_MUX_OK) { \
+ fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
+ return err; \
+ } \
+ } while (0)
#define ERROR_GOTO1(ERR_MSG, LABEL) \
do { \
@@ -605,20 +609,26 @@ static int ValidateCommandLine(const CommandLineArguments* const cmd_args,
#define FEATURETYPE_IS_NIL (config->type_ == NIL_FEATURE)
#define CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL) \
- if (argc < i + (NUM)) { \
- fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
- goto LABEL; \
- }
+ do { \
+ if (argc < i + (NUM)) { \
+ fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
+ goto LABEL; \
+ } \
+ } while (0)
#define CHECK_NUM_ARGS_AT_MOST(NUM, LABEL) \
- if (argc > i + (NUM)) { \
- fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
- goto LABEL; \
- }
+ do { \
+ if (argc > i + (NUM)) { \
+ fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
+ goto LABEL; \
+ } \
+ } while (0)
#define CHECK_NUM_ARGS_EXACTLY(NUM, LABEL) \
- CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL); \
- CHECK_NUM_ARGS_AT_MOST(NUM, LABEL);
+ do { \
+ CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL); \
+ CHECK_NUM_ARGS_AT_MOST(NUM, LABEL); \
+ } while (0)
// Parses command-line arguments to fill up config object. Also performs some
// semantic checks. unicode_argv contains wchar_t arguments or is null.
diff --git a/extras/Makefile.am b/extras/Makefile.am
index 7e29888b..d5a9af49 100644
--- a/extras/Makefile.am
+++ b/extras/Makefile.am
@@ -7,6 +7,7 @@ noinst_HEADERS += ../src/webp/types.h
libwebpextras_la_SOURCES =
libwebpextras_la_SOURCES += extras.c extras.h quality_estimate.c
+libwebpextras_la_SOURCES += sharpyuv_risk_table.c sharpyuv_risk_table.h
libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS)
libwebpextras_la_LDFLAGS = -lm
diff --git a/extras/extras.c b/extras/extras.c
index b170ee23..3a3d254e 100644
--- a/extras/extras.c
+++ b/extras/extras.c
@@ -11,14 +11,20 @@
//
#include "extras/extras.h"
-#include "webp/format_constants.h"
-#include "src/dsp/dsp.h"
#include <assert.h>
+#include <limits.h>
#include <string.h>
+#include "extras/sharpyuv_risk_table.h"
+#include "sharpyuv/sharpyuv.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/utils.h"
+#include "webp/format_constants.h"
+#include "webp/types.h"
+
#define XTRA_MAJ_VERSION 1
-#define XTRA_MIN_VERSION 3
+#define XTRA_MIN_VERSION 4
#define XTRA_REV_VERSION 0
//------------------------------------------------------------------------------
@@ -160,3 +166,159 @@ int WebPUnmultiplyARGB(WebPPicture* pic) {
}
//------------------------------------------------------------------------------
+// 420 risk metric
+
+#define YUV_FIX 16 // fixed-point precision for RGB->YUV
+static const int kYuvHalf = 1 << (YUV_FIX - 1);
+
+// Maps a value in [0, (256 << YUV_FIX) - 1] to [0,
+// precomputed_scores_table_sampling - 1]. It is important that the extremal
+// values are preserved and 1:1 mapped:
+// ConvertValue(0) = 0
+// ConvertValue((256 << 16) - 1) = rgb_sampling_size - 1
+static int SharpYuvConvertValueToSampledIdx(int v, int rgb_sampling_size) {
+ v = (v + kYuvHalf) >> YUV_FIX;
+ v = (v < 0) ? 0 : (v > 255) ? 255 : v;
+ return (v * (rgb_sampling_size - 1)) / 255;
+}
+
+#undef YUV_FIX
+
+// For each pixel, computes the index to look up that color in a precomputed
+// risk score table where the YUV space is subsampled to a size of
+// precomputed_scores_table_sampling^3 (see sharpyuv_risk_table.h)
+static int SharpYuvConvertToYuvSharpnessIndex(
+ int r, int g, int b, const SharpYuvConversionMatrix* matrix,
+ int precomputed_scores_table_sampling) {
+ const int y = SharpYuvConvertValueToSampledIdx(
+ matrix->rgb_to_y[0] * r + matrix->rgb_to_y[1] * g +
+ matrix->rgb_to_y[2] * b + matrix->rgb_to_y[3],
+ precomputed_scores_table_sampling);
+ const int u = SharpYuvConvertValueToSampledIdx(
+ matrix->rgb_to_u[0] * r + matrix->rgb_to_u[1] * g +
+ matrix->rgb_to_u[2] * b + matrix->rgb_to_u[3],
+ precomputed_scores_table_sampling);
+ const int v = SharpYuvConvertValueToSampledIdx(
+ matrix->rgb_to_v[0] * r + matrix->rgb_to_v[1] * g +
+ matrix->rgb_to_v[2] * b + matrix->rgb_to_v[3],
+ precomputed_scores_table_sampling);
+ return y + u * precomputed_scores_table_sampling +
+ v * precomputed_scores_table_sampling *
+ precomputed_scores_table_sampling;
+}
+
+static void SharpYuvRowToYuvSharpnessIndex(
+ const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr,
+ int rgb_step, int rgb_bit_depth, int width, uint16_t* dst,
+ const SharpYuvConversionMatrix* matrix,
+ int precomputed_scores_table_sampling) {
+ int i;
+ assert(rgb_bit_depth == 8);
+ (void)rgb_bit_depth; // Unused for now.
+ for (i = 0; i < width;
+ ++i, r_ptr += rgb_step, g_ptr += rgb_step, b_ptr += rgb_step) {
+ dst[i] =
+ SharpYuvConvertToYuvSharpnessIndex(r_ptr[0], g_ptr[0], b_ptr[0], matrix,
+ precomputed_scores_table_sampling);
+ }
+}
+
+#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((uint64_t)(W) * (H), sizeof(T)))
+
+static int DoEstimateRisk(const uint8_t* r_ptr, const uint8_t* g_ptr,
+ const uint8_t* b_ptr, int rgb_step, int rgb_stride,
+ int rgb_bit_depth, int width, int height,
+ const SharpYuvOptions* options,
+ const uint8_t precomputed_scores_table[],
+ int precomputed_scores_table_sampling,
+ float* score_out) {
+ const int sampling3 = precomputed_scores_table_sampling *
+ precomputed_scores_table_sampling *
+ precomputed_scores_table_sampling;
+ const int kNoiseLevel = 4;
+ double total_score = 0;
+ double count = 0;
+ // Rows of indices in
+ uint16_t* row1 = SAFE_ALLOC(width, 1, uint16_t);
+ uint16_t* row2 = SAFE_ALLOC(width, 1, uint16_t);
+ uint16_t* tmp;
+ int i, j;
+
+ if (row1 == NULL || row2 == NULL) {
+ WebPFree(row1);
+ WebPFree(row2);
+ return 0;
+ }
+
+ // Convert the first row ahead.
+ SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
+ width, row2, options->yuv_matrix,
+ precomputed_scores_table_sampling);
+
+ for (j = 1; j < height; ++j) {
+ r_ptr += rgb_stride;
+ g_ptr += rgb_stride;
+ b_ptr += rgb_stride;
+ // Swap row 1 and row 2.
+ tmp = row1;
+ row1 = row2;
+ row2 = tmp;
+ // Convert the row below.
+ SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
+ width, row2, options->yuv_matrix,
+ precomputed_scores_table_sampling);
+ for (i = 0; i < width - 1; ++i) {
+ const int idx0 = row1[i + 0];
+ const int idx1 = row1[i + 1];
+ const int idx2 = row2[i + 0];
+ const int score = precomputed_scores_table[idx0 + sampling3 * idx1] +
+ precomputed_scores_table[idx0 + sampling3 * idx2] +
+ precomputed_scores_table[idx1 + sampling3 * idx2];
+ if (score > kNoiseLevel) {
+ total_score += score;
+ count += 1.0;
+ }
+ }
+ }
+ if (count > 0.) total_score /= count;
+
+ // If less than 1% of pixels were evaluated -> below noise level.
+ if (100. * count / (width * height) < 1.) total_score = 0.;
+
+ // Rescale to [0:100]
+ total_score = (total_score > 25.) ? 100. : total_score * 100. / 25.;
+
+ WebPFree(row1);
+ WebPFree(row2);
+
+ *score_out = (float)total_score;
+ return 1;
+}
+
+#undef SAFE_ALLOC
+
+int SharpYuvEstimate420Risk(const void* r_ptr, const void* g_ptr,
+ const void* b_ptr, int rgb_step, int rgb_stride,
+ int rgb_bit_depth, int width, int height,
+ const SharpYuvOptions* options, float* score) {
+ if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX ||
+ r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || options == NULL ||
+ score == NULL) {
+ return 0;
+ }
+ if (rgb_bit_depth != 8) {
+ return 0;
+ }
+
+ if (width <= 4 || height <= 4) {
+ *score = 0.0f; // too small, no real risk.
+ return 1;
+ }
+
+ return DoEstimateRisk(
+ (const uint8_t*)r_ptr, (const uint8_t*)g_ptr, (const uint8_t*)b_ptr,
+ rgb_step, rgb_stride, rgb_bit_depth, width, height, options,
+ kSharpYuvPrecomputedRisk, kSharpYuvPrecomputedRiskYuvSampling, score);
+}
+
+//------------------------------------------------------------------------------
diff --git a/extras/extras.h b/extras/extras.h
index c084682f..3cc9d700 100644
--- a/extras/extras.h
+++ b/extras/extras.h
@@ -17,9 +17,10 @@
extern "C" {
#endif
+#include "sharpyuv/sharpyuv.h"
#include "webp/encode.h"
-#define WEBP_EXTRAS_ABI_VERSION 0x0002 // MAJOR(8b) + MINOR(8b)
+#define WEBP_EXTRAS_ABI_VERSION 0x0003 // MAJOR(8b) + MINOR(8b)
//------------------------------------------------------------------------------
@@ -70,6 +71,38 @@ WEBP_EXTERN int VP8EstimateQuality(const uint8_t* const data, size_t size);
//------------------------------------------------------------------------------
+// Computes a score between 0 and 100 which represents the risk of having visual
+// quality loss from converting an RGB image to YUV420.
+// A low score, typically < 40, means there is a low risk of artifacts from
+// chroma subsampling and a simple averaging algorithm can be used instead of
+// the more expensive SharpYuvConvert function.
+// A medium score, typically >= 40 and < 70, means that simple chroma
+// subsampling will produce artifacts and it may be advisable to use the more
+// costly SharpYuvConvert for YUV420 conversion.
+// A high score, typically >= 70, means there is a very high risk of artifacts
+// from chroma subsampling even with SharpYuvConvert, and best results might be
+// achieved by using YUV444.
+// If not using SharpYuvConvert, a threshold of about 50 can be used to decide
+// between (simple averaging) 420 and 444.
+// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point
+// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise.
+// rgb_step: distance in bytes between two horizontally adjacent pixels on the
+// r, g and b channels. If rgb_bit_depth is > 8, it should be a
+// multiple of 2.
+// rgb_stride: distance in bytes between two vertically adjacent pixels on the
+// r, g, and b channels. If rgb_bit_depth is > 8, it should be a
+// multiple of 2.
+// rgb_bit_depth: number of bits for each r/g/b value. Only a value of 8 is
+// currently supported.
+// width, height: width and height of the image in pixels
+// Returns 0 on failure.
+WEBP_EXTERN int SharpYuvEstimate420Risk(
+ const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step,
+ int rgb_stride, int rgb_bit_depth, int width, int height,
+ const SharpYuvOptions* options, float* score);
+
+//------------------------------------------------------------------------------
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/extras/sharpyuv_risk_table.c b/extras/sharpyuv_risk_table.c
new file mode 100644
index 00000000..ab3e7fdd
--- /dev/null
+++ b/extras/sharpyuv_risk_table.c
@@ -0,0 +1,6210 @@
+// Copyright 2023 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Precomputed data for 420 risk estimation.
+
+#include "src/webp/types.h"
+
+const int kSharpYuvPrecomputedRiskYuvSampling = 7;
+
+const uint8_t kSharpYuvPrecomputedRisk[] = {
+ 0, 2, 2, 3, 3, 2, 2, 1, 2, 2, 3, 2, 2, 1, 2, 1, 2, 2, 2,
+ 1, 2, 2, 1, 1, 2, 2, 3, 4, 4, 4, 4, 4, 5, 4, 4, 8, 8, 8,
+ 7, 5, 4, 4, 14, 12, 9, 8, 6, 4, 4, 2, 1, 2, 2, 2, 2, 1, 2,
+ 0, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 3, 2, 2, 2, 2, 2, 3,
+ 4, 5, 5, 5, 5, 5, 4, 4, 11, 9, 9, 8, 6, 5, 4, 18, 14, 11, 9,
+ 7, 5, 4, 2, 1, 1, 1, 1, 3, 6, 2, 2, 1, 1, 1, 3, 6, 3, 2,
+ 2, 2, 3, 3, 7, 6, 3, 5, 6, 6, 6, 8, 9, 7, 9, 9, 9, 8, 8,
+ 14, 12, 13, 12, 11, 10, 8, 20, 18, 16, 14, 13, 11, 10, 3, 6, 6, 7, 7,
+ 7, 10, 6, 7, 7, 8, 8, 8, 10, 10, 7, 9, 9, 10, 10, 10, 13, 10, 12,
+ 13, 13, 13, 12, 13, 15, 17, 17, 17, 16, 15, 14, 22, 21, 20, 19, 18, 17, 20,
+ 27, 25, 23, 20, 19, 19, 14, 15, 14, 14, 15, 14, 9, 16, 16, 16, 16, 16, 15,
+ 9, 16, 17, 18, 18, 18, 17, 14, 16, 21, 21, 22, 22, 20, 17, 19, 26, 27, 26,
+ 25, 24, 18, 23, 30, 32, 29, 28, 25, 20, 27, 33, 35, 32, 30, 28, 22, 24, 25,
+ 24, 24, 21, 17, 12, 23, 27, 25, 26, 22, 17, 14, 24, 30, 29, 28, 24, 20, 17,
+ 24, 31, 32, 32, 28, 24, 20, 27, 34, 37, 36, 32, 27, 22, 30, 36, 42, 41, 34,
+ 29, 23, 33, 39, 44, 44, 38, 31, 26, 32, 37, 36, 29, 23, 19, 15, 31, 38, 39,
+ 31, 25, 20, 16, 31, 38, 41, 34, 28, 24, 20, 31, 38, 44, 38, 33, 27, 24, 34,
+ 41, 46, 45, 37, 31, 25, 36, 43, 47, 49, 40, 33, 27, 39, 44, 49, 49, 42, 36,
+ 29, 2, 0, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2,
+ 1, 2, 3, 2, 2, 2, 2, 3, 4, 5, 5, 5, 5, 5, 6, 5, 5, 9, 9,
+ 9, 8, 6, 5, 5, 15, 14, 10, 8, 7, 5, 5, 2, 2, 1, 2, 1, 1, 4,
+ 2, 2, 0, 2, 1, 1, 4, 2, 2, 1, 1, 1, 3, 5, 3, 3, 3, 3, 3,
+ 4, 6, 7, 6, 7, 6, 6, 5, 6, 12, 11, 10, 9, 8, 7, 6, 19, 16, 12,
+ 10, 9, 8, 6, 2, 2, 3, 3, 3, 5, 7, 3, 2, 3, 4, 4, 5, 7, 7,
+ 2, 4, 6, 6, 6, 9, 10, 4, 8, 9, 9, 9, 11, 13, 8, 11, 13, 13, 12,
+ 11, 17, 14, 15, 16, 15, 14, 10, 21, 20, 18, 18, 16, 15, 13, 7, 7, 9, 9,
+ 10, 8, 11, 11, 8, 10, 11, 11, 11, 11, 13, 8, 11, 13, 13, 14, 13, 16, 11,
+ 16, 17, 17, 17, 15, 17, 17, 20, 21, 21, 20, 18, 18, 23, 25, 24, 23, 21, 20,
+ 21, 29, 28, 26, 25, 23, 22, 16, 17, 17, 17, 18, 17, 11, 20, 18, 19, 19, 19,
+ 18, 11, 19, 20, 20, 22, 21, 20, 16, 19, 24, 26, 25, 26, 24, 22, 21, 29, 31,
+ 30, 31, 27, 22, 26, 33, 35, 33, 31, 30, 25, 30, 36, 39, 36, 35, 31, 26, 27,
+ 28, 28, 27, 23, 20, 15, 26, 30, 29, 29, 25, 21, 17, 27, 32, 32, 32, 28, 24,
+ 21, 26, 35, 38, 37, 32, 29, 25, 30, 38, 41, 41, 36, 31, 25, 34, 40, 47, 45,
+ 39, 33, 27, 37, 44, 48, 49, 41, 35, 29, 35, 42, 40, 33, 27, 22, 18, 36, 41,
+ 42, 34, 29, 24, 21, 36, 41, 46, 38, 32, 28, 24, 35, 43, 49, 42, 37, 32, 28,
+ 38, 45, 51, 48, 42, 36, 30, 40, 47, 53, 51, 44, 38, 32, 44, 49, 54, 55, 47,
+ 39, 34, 2, 2, 0, 2, 2, 1, 2, 3, 2, 1, 2, 2, 1, 3, 3, 2, 1,
+ 1, 2, 3, 5, 3, 3, 3, 3, 3, 4, 5, 6, 6, 7, 6, 6, 5, 6, 11,
+ 10, 10, 9, 7, 5, 5, 17, 15, 12, 10, 8, 5, 6, 3, 2, 2, 1, 1, 3,
+ 6, 3, 2, 2, 1, 1, 3, 6, 4, 3, 2, 2, 3, 5, 7, 7, 4, 4, 5,
+ 6, 6, 8, 11, 7, 8, 9, 9, 6, 9, 14, 12, 12, 11, 11, 10, 8, 20, 17,
+ 14, 12, 13, 11, 9, 4, 3, 4, 5, 6, 6, 8, 8, 3, 4, 6, 7, 6, 9,
+ 11, 3, 5, 9, 10, 8, 11, 14, 5, 9, 12, 13, 12, 13, 17, 10, 12, 16, 17,
+ 16, 13, 21, 15, 17, 20, 19, 17, 12, 23, 20, 20, 21, 20, 19, 16, 11, 8, 12,
+ 13, 12, 10, 13, 15, 9, 12, 14, 14, 14, 14, 18, 10, 13, 16, 17, 17, 16, 20,
+ 14, 18, 20, 21, 21, 18, 21, 20, 22, 24, 25, 24, 21, 21, 25, 27, 28, 27, 26,
+ 25, 23, 31, 30, 30, 28, 27, 26, 19, 19, 20, 21, 21, 20, 13, 23, 21, 21, 22,
+ 23, 21, 14, 23, 22, 23, 25, 25, 25, 19, 23, 26, 28, 29, 29, 28, 25, 24, 31,
+ 34, 34, 34, 32, 26, 28, 36, 40, 38, 37, 34, 28, 32, 40, 43, 40, 39, 35, 29,
+ 29, 32, 31, 30, 26, 22, 17, 29, 33, 32, 32, 29, 25, 21, 29, 36, 36, 36, 32,
+ 28, 24, 29, 38, 42, 40, 36, 32, 28, 32, 42, 45, 44, 40, 35, 30, 37, 45, 50,
+ 49, 42, 37, 31, 40, 47, 52, 52, 46, 39, 33, 38, 45, 42, 36, 30, 25, 21, 39,
+ 45, 45, 38, 32, 28, 24, 39, 45, 49, 42, 37, 32, 28, 38, 46, 52, 46, 41, 35,
+ 31, 42, 49, 55, 52, 45, 40, 34, 45, 51, 57, 57, 48, 42, 36, 48, 53, 58, 57,
+ 51, 44, 38, 3, 2, 2, 0, 0, 2, 4, 3, 2, 2, 0, 1, 3, 6, 3, 3,
+ 2, 2, 2, 4, 7, 4, 4, 4, 5, 4, 5, 7, 8, 7, 8, 8, 7, 6, 7,
+ 12, 11, 12, 10, 8, 6, 7, 18, 16, 13, 11, 9, 6, 8, 3, 2, 2, 2, 3,
+ 5, 7, 4, 3, 2, 2, 3, 6, 8, 8, 3, 2, 3, 6, 7, 9, 11, 4, 5,
+ 6, 9, 8, 11, 14, 8, 9, 10, 12, 8, 11, 17, 13, 13, 13, 14, 12, 11, 22,
+ 18, 15, 13, 16, 15, 11, 8, 3, 5, 8, 8, 8, 10, 12, 3, 5, 8, 10, 8,
+ 11, 15, 5, 6, 11, 13, 9, 13, 18, 9, 10, 15, 16, 16, 16, 21, 12, 14, 19,
+ 19, 19, 16, 24, 17, 18, 21, 22, 21, 16, 26, 22, 20, 23, 23, 22, 19, 15, 9,
+ 13, 15, 16, 12, 15, 18, 11, 14, 16, 17, 17, 17, 22, 13, 15, 19, 21, 21, 19,
+ 26, 17, 20, 24, 23, 25, 21, 26, 22, 24, 27, 28, 27, 24, 25, 27, 30, 31, 31,
+ 29, 27, 25, 33, 33, 33, 32, 31, 30, 23, 20, 22, 24, 24, 23, 16, 26, 22, 25,
+ 25, 26, 25, 17, 26, 25, 26, 28, 30, 28, 22, 26, 29, 31, 33, 33, 32, 27, 28,
+ 34, 37, 36, 38, 36, 30, 30, 39, 42, 42, 41, 37, 32, 34, 43, 46, 44, 42, 39,
+ 33, 31, 34, 33, 33, 30, 26, 20, 31, 36, 35, 35, 32, 28, 24, 32, 37, 39, 39,
+ 36, 31, 28, 32, 40, 45, 42, 40, 37, 32, 34, 44, 50, 48, 44, 40, 34, 39, 47,
+ 54, 52, 47, 40, 35, 43, 48, 56, 56, 49, 43, 37, 43, 46, 45, 39, 32, 29, 25,
+ 42, 47, 47, 40, 35, 31, 28, 41, 47, 49, 44, 39, 36, 31, 42, 48, 55, 50, 44,
+ 40, 34, 45, 52, 57, 55, 49, 43, 38, 48, 54, 59, 60, 53, 44, 39, 51, 57, 61,
+ 60, 54, 47, 41, 3, 2, 2, 0, 0, 2, 4, 3, 2, 2, 1, 0, 3, 6, 3,
+ 2, 2, 2, 2, 4, 6, 4, 4, 4, 4, 4, 5, 7, 8, 7, 8, 8, 7, 6,
+ 8, 12, 12, 11, 11, 8, 6, 8, 18, 16, 13, 11, 9, 6, 8, 3, 2, 2, 2,
+ 3, 5, 7, 4, 3, 2, 2, 3, 6, 8, 8, 3, 2, 3, 6, 7, 9, 12, 5,
+ 5, 6, 9, 8, 11, 14, 8, 9, 10, 12, 8, 10, 17, 13, 13, 13, 14, 13, 11,
+ 22, 18, 15, 13, 15, 15, 11, 8, 3, 5, 8, 8, 8, 10, 12, 3, 5, 9, 10,
+ 8, 11, 16, 5, 6, 11, 13, 9, 13, 17, 8, 9, 15, 16, 15, 15, 22, 12, 14,
+ 19, 20, 20, 16, 24, 17, 18, 21, 22, 21, 16, 26, 22, 20, 23, 24, 22, 19, 15,
+ 9, 13, 15, 15, 12, 16, 18, 11, 14, 16, 17, 17, 17, 21, 13, 15, 19, 21, 21,
+ 19, 26, 17, 20, 23, 24, 25, 20, 25, 21, 24, 27, 27, 27, 24, 24, 27, 29, 30,
+ 30, 29, 27, 26, 33, 32, 33, 32, 31, 30, 23, 21, 23, 24, 23, 22, 15, 26, 22,
+ 24, 24, 26, 25, 17, 26, 24, 25, 28, 30, 27, 22, 26, 29, 30, 33, 33, 32, 27,
+ 28, 34, 36, 38, 37, 35, 30, 30, 38, 43, 42, 41, 37, 32, 33, 42, 46, 44, 42,
+ 39, 34, 32, 34, 33, 33, 29, 26, 20, 32, 37, 35, 35, 32, 28, 24, 31, 38, 38,
+ 39, 36, 32, 28, 31, 40, 44, 44, 39, 36, 32, 35, 42, 49, 48, 44, 40, 33, 39,
+ 47, 54, 53, 46, 40, 36, 44, 50, 54, 55, 48, 43, 37, 40, 47, 44, 37, 33, 28,
+ 25, 41, 48, 47, 40, 35, 31, 28, 40, 47, 50, 44, 40, 35, 31, 41, 49, 55, 50,
+ 44, 39, 35, 44, 52, 58, 55, 47, 43, 38, 48, 55, 60, 59, 50, 45, 39, 50, 57,
+ 62, 62, 53, 47, 42, 2, 2, 1, 2, 2, 0, 3, 2, 2, 1, 2, 2, 1, 4,
+ 2, 2, 1, 2, 4, 3, 5, 3, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 9,
+ 8, 6, 11, 11, 11, 10, 9, 8, 6, 18, 15, 13, 11, 10, 7, 6, 2, 2, 2,
+ 1, 1, 3, 5, 3, 2, 2, 1, 1, 4, 6, 6, 2, 2, 3, 4, 5, 7, 10,
+ 4, 5, 6, 7, 6, 9, 11, 8, 9, 9, 10, 7, 8, 16, 13, 13, 12, 12, 11,
+ 9, 21, 18, 15, 13, 14, 13, 9, 6, 2, 4, 6, 6, 6, 8, 10, 2, 4, 7,
+ 8, 6, 9, 14, 3, 5, 9, 10, 7, 11, 16, 6, 9, 13, 14, 13, 13, 18, 11,
+ 12, 17, 18, 17, 13, 22, 16, 17, 20, 20, 18, 13, 25, 22, 20, 22, 22, 20, 17,
+ 14, 7, 12, 13, 13, 9, 13, 17, 9, 12, 14, 15, 14, 14, 20, 12, 13, 17, 18,
+ 19, 16, 22, 15, 18, 22, 22, 22, 18, 22, 20, 22, 25, 26, 25, 21, 23, 25, 28,
+ 28, 28, 27, 24, 24, 31, 31, 30, 30, 29, 27, 22, 19, 21, 21, 21, 20, 13, 24,
+ 20, 22, 22, 23, 22, 14, 24, 22, 23, 26, 26, 25, 19, 25, 26, 28, 29, 32, 29,
+ 25, 25, 32, 34, 35, 35, 32, 27, 28, 36, 41, 39, 37, 34, 30, 32, 40, 43, 43,
+ 39, 36, 30, 29, 32, 32, 30, 26, 22, 17, 29, 35, 32, 32, 29, 25, 22, 29, 35,
+ 35, 36, 33, 29, 25, 29, 38, 41, 41, 37, 33, 29, 33, 41, 47, 45, 42, 37, 30,
+ 38, 44, 52, 52, 44, 38, 32, 41, 47, 53, 53, 47, 40, 34, 39, 46, 42, 36, 30,
+ 26, 22, 39, 45, 45, 38, 33, 29, 25, 39, 44, 48, 42, 36, 33, 28, 39, 46, 52,
+ 47, 41, 37, 33, 42, 50, 54, 52, 45, 39, 36, 45, 52, 58, 56, 49, 43, 35, 49,
+ 54, 58, 59, 52, 44, 37, 1, 1, 2, 4, 4, 3, 0, 2, 1, 2, 4, 4, 3,
+ 2, 2, 1, 1, 4, 5, 4, 4, 2, 3, 3, 5, 7, 7, 6, 5, 6, 7, 8,
+ 10, 8, 7, 10, 10, 11, 11, 10, 8, 7, 17, 15, 12, 11, 11, 8, 7, 2, 1,
+ 1, 3, 2, 2, 3, 2, 2, 1, 2, 2, 2, 4, 2, 2, 1, 3, 3, 3, 5,
+ 6, 3, 4, 5, 5, 4, 6, 9, 7, 8, 8, 8, 6, 6, 13, 12, 12, 11, 9,
+ 8, 6, 20, 18, 13, 12, 11, 9, 6, 2, 2, 3, 3, 3, 5, 6, 6, 2, 3,
+ 4, 4, 4, 6, 11, 2, 4, 7, 7, 5, 8, 15, 4, 8, 10, 10, 10, 10, 16,
+ 9, 11, 14, 14, 14, 10, 19, 14, 16, 18, 16, 15, 10, 23, 21, 19, 19, 18, 16,
+ 14, 11, 7, 9, 10, 10, 7, 11, 15, 7, 10, 11, 12, 11, 11, 17, 9, 12, 14,
+ 15, 15, 12, 19, 13, 16, 18, 18, 18, 14, 19, 17, 20, 22, 23, 22, 18, 20, 23,
+ 26, 26, 25, 23, 21, 22, 29, 29, 27, 26, 25, 23, 19, 17, 18, 18, 18, 17, 11,
+ 22, 18, 20, 19, 20, 19, 11, 22, 20, 21, 23, 23, 22, 17, 22, 24, 26, 27, 27,
+ 26, 22, 23, 30, 31, 32, 32, 28, 24, 25, 34, 37, 36, 34, 30, 26, 30, 37, 41,
+ 37, 36, 33, 27, 27, 29, 27, 27, 24, 20, 15, 26, 31, 30, 29, 26, 22, 18, 27,
+ 33, 32, 33, 30, 26, 22, 26, 35, 39, 36, 34, 29, 25, 31, 37, 43, 42, 38, 33,
+ 28, 35, 44, 48, 47, 40, 34, 30, 38, 45, 49, 49, 42, 37, 31, 35, 41, 38, 32,
+ 26, 23, 18, 36, 42, 41, 35, 29, 25, 22, 36, 40, 43, 38, 33, 29, 25, 36, 42,
+ 50, 43, 37, 34, 29, 39, 45, 52, 47, 42, 37, 31, 42, 47, 53, 54, 45, 39, 33,
+ 46, 51, 54, 54, 46, 40, 35, 1, 2, 3, 3, 3, 2, 2, 0, 2, 2, 3, 3,
+ 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 3, 4,
+ 4, 5, 4, 4, 7, 7, 7, 7, 5, 4, 4, 13, 12, 9, 7, 6, 4, 4, 1,
+ 2, 2, 3, 2, 2, 1, 2, 1, 2, 2, 2, 1, 0, 2, 0, 2, 2, 2, 1,
+ 2, 2, 2, 2, 2, 2, 3, 4, 5, 5, 5, 5, 5, 4, 4, 10, 9, 9, 8,
+ 6, 4, 4, 17, 14, 11, 8, 6, 5, 4, 2, 1, 1, 2, 2, 2, 5, 2, 1,
+ 1, 1, 1, 2, 6, 2, 2, 1, 2, 2, 2, 6, 5, 3, 4, 4, 5, 5, 7,
+ 8, 7, 8, 8, 8, 7, 7, 13, 12, 12, 11, 10, 9, 7, 20, 17, 15, 13, 11,
+ 10, 9, 2, 5, 6, 6, 6, 6, 9, 5, 6, 6, 7, 7, 7, 9, 8, 7, 8,
+ 8, 9, 9, 9, 11, 9, 11, 12, 12, 12, 11, 12, 15, 15, 16, 15, 15, 14, 14,
+ 20, 20, 20, 18, 17, 16, 19, 27, 24, 21, 20, 18, 17, 13, 14, 13, 14, 14, 13,
+ 9, 15, 15, 14, 15, 15, 14, 9, 15, 17, 17, 17, 17, 16, 12, 15, 21, 20, 20,
+ 21, 19, 16, 18, 25, 25, 24, 24, 23, 17, 22, 29, 30, 29, 26, 24, 19, 26, 32,
+ 33, 31, 29, 26, 21, 23, 24, 23, 22, 20, 15, 12, 23, 27, 25, 25, 21, 16, 13,
+ 23, 28, 28, 26, 23, 19, 15, 23, 30, 32, 31, 28, 22, 19, 26, 32, 36, 36, 31,
+ 26, 20, 29, 34, 41, 39, 34, 28, 23, 31, 38, 41, 42, 35, 30, 25, 31, 37, 35,
+ 29, 23, 18, 14, 31, 37, 38, 30, 25, 19, 15, 30, 36, 40, 33, 27, 23, 18, 30,
+ 37, 44, 37, 31, 26, 23, 33, 39, 45, 43, 36, 30, 24, 36, 42, 48, 47, 39, 31,
+ 27, 38, 43, 48, 49, 42, 34, 28, 2, 1, 2, 2, 2, 2, 1, 2, 0, 2, 3,
+ 2, 2, 1, 2, 1, 1, 2, 2, 1, 3, 2, 2, 2, 2, 3, 3, 5, 5, 5,
+ 5, 5, 5, 5, 4, 9, 8, 8, 8, 6, 5, 4, 15, 13, 10, 8, 7, 5, 4,
+ 2, 1, 2, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 3, 2, 2, 1, 1, 1,
+ 2, 5, 2, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 6, 11, 10, 10,
+ 9, 7, 5, 6, 19, 15, 12, 9, 8, 7, 6, 2, 2, 2, 2, 2, 4, 7, 3,
+ 2, 3, 3, 3, 5, 7, 5, 2, 4, 5, 5, 5, 8, 9, 3, 7, 8, 8, 8,
+ 9, 12, 8, 11, 11, 12, 11, 10, 16, 13, 15, 15, 14, 12, 10, 21, 19, 18, 17,
+ 15, 14, 13, 5, 7, 8, 8, 9, 8, 11, 9, 7, 9, 10, 10, 10, 11, 12, 8,
+ 11, 11, 12, 12, 12, 16, 11, 15, 16, 16, 15, 14, 16, 17, 19, 19, 20, 19, 17,
+ 16, 23, 24, 23, 22, 20, 19, 21, 29, 27, 25, 23, 22, 20, 16, 16, 17, 16, 17,
+ 16, 10, 18, 18, 18, 18, 18, 17, 11, 18, 19, 20, 20, 21, 19, 16, 18, 24, 24,
+ 25, 25, 23, 20, 21, 29, 29, 28, 28, 26, 21, 24, 32, 34, 33, 31, 28, 24, 29,
+ 36, 38, 34, 33, 30, 25, 26, 28, 26, 26, 22, 18, 14, 25, 31, 28, 28, 23, 19,
+ 16, 26, 32, 31, 31, 27, 23, 19, 26, 33, 36, 33, 32, 26, 22, 29, 36, 40, 38,
+ 35, 30, 25, 33, 39, 45, 44, 36, 31, 27, 35, 42, 45, 46, 41, 33, 29, 35, 41,
+ 38, 31, 26, 21, 17, 35, 40, 41, 34, 27, 23, 19, 35, 41, 44, 37, 30, 26, 22,
+ 34, 41, 47, 41, 35, 31, 26, 37, 43, 50, 47, 40, 34, 29, 39, 46, 52, 51, 42,
+ 37, 30, 42, 49, 53, 53, 44, 39, 32, 2, 1, 1, 2, 2, 1, 2, 2, 2, 0,
+ 2, 2, 1, 3, 3, 2, 1, 1, 2, 2, 4, 3, 3, 3, 3, 3, 4, 5, 5,
+ 6, 6, 6, 6, 5, 5, 10, 10, 9, 8, 7, 5, 5, 17, 15, 11, 9, 7, 5,
+ 5, 3, 2, 1, 1, 1, 3, 5, 3, 2, 2, 1, 1, 3, 6, 3, 2, 2, 2,
+ 2, 4, 7, 6, 4, 4, 4, 5, 5, 8, 9, 7, 7, 8, 8, 5, 8, 13, 12,
+ 11, 11, 10, 9, 8, 20, 17, 13, 11, 11, 10, 8, 3, 2, 4, 5, 5, 6, 8,
+ 6, 3, 4, 6, 6, 6, 8, 10, 3, 5, 8, 8, 7, 10, 13, 4, 9, 11, 12,
+ 11, 12, 16, 9, 12, 15, 15, 15, 12, 20, 14, 16, 18, 17, 16, 12, 22, 20, 19,
+ 20, 19, 17, 16, 10, 7, 11, 11, 11, 9, 12, 13, 8, 11, 12, 13, 13, 13, 16,
+ 10, 13, 16, 16, 16, 15, 18, 13, 17, 19, 19, 19, 17, 20, 18, 22, 23, 24, 22,
+ 19, 20, 24, 27, 27, 25, 25, 22, 23, 30, 30, 28, 27, 26, 25, 19, 18, 19, 19,
+ 20, 18, 12, 21, 19, 20, 21, 21, 20, 13, 22, 21, 23, 24, 25, 23, 18, 21, 26,
+ 27, 28, 28, 27, 23, 24, 31, 33, 32, 33, 30, 25, 27, 36, 38, 36, 34, 31, 26,
+ 31, 39, 41, 38, 37, 34, 28, 28, 31, 30, 29, 25, 21, 17, 28, 33, 32, 31, 28,
+ 23, 19, 27, 35, 35, 34, 31, 26, 23, 28, 36, 40, 38, 35, 30, 27, 32, 41, 45,
+ 44, 39, 34, 29, 35, 43, 51, 48, 42, 36, 30, 39, 46, 51, 50, 44, 38, 32, 37,
+ 44, 41, 34, 29, 24, 20, 39, 44, 44, 37, 32, 26, 23, 38, 43, 47, 40, 36, 31,
+ 26, 38, 45, 50, 45, 39, 35, 30, 40, 48, 54, 50, 43, 37, 32, 44, 51, 56, 53,
+ 46, 40, 34, 46, 52, 57, 57, 49, 42, 37, 3, 2, 2, 0, 0, 2, 4, 3, 3,
+ 2, 0, 1, 2, 5, 3, 3, 2, 2, 2, 3, 6, 4, 4, 4, 4, 4, 5, 7,
+ 7, 7, 7, 7, 7, 6, 7, 12, 11, 11, 10, 8, 6, 7, 17, 15, 12, 10, 9,
+ 6, 7, 3, 3, 2, 2, 2, 5, 7, 3, 3, 2, 2, 2, 5, 8, 7, 3, 2,
+ 3, 5, 6, 9, 10, 4, 5, 6, 8, 7, 10, 13, 8, 9, 9, 12, 8, 10, 16,
+ 13, 13, 12, 13, 12, 10, 22, 18, 14, 13, 15, 14, 10, 7, 3, 5, 7, 7, 8,
+ 10, 11, 3, 5, 8, 9, 8, 11, 14, 4, 6, 11, 12, 9, 12, 17, 7, 9, 14,
+ 15, 15, 15, 19, 11, 13, 18, 19, 18, 15, 24, 16, 18, 20, 21, 20, 15, 25, 21,
+ 20, 22, 22, 21, 18, 14, 8, 13, 14, 14, 11, 15, 17, 10, 13, 15, 17, 16, 16,
+ 20, 12, 14, 18, 20, 20, 18, 22, 16, 19, 22, 23, 23, 19, 23, 21, 24, 26, 27,
+ 27, 23, 24, 26, 29, 30, 30, 28, 27, 25, 32, 32, 31, 31, 29, 29, 22, 20, 22,
+ 23, 23, 22, 15, 27, 21, 24, 24, 25, 24, 16, 25, 23, 26, 28, 28, 27, 21, 25,
+ 29, 30, 32, 33, 31, 27, 27, 34, 36, 37, 37, 34, 29, 30, 38, 42, 41, 38, 35,
+ 31, 32, 41, 45, 42, 42, 38, 33, 32, 33, 34, 32, 29, 25, 19, 31, 36, 35, 34,
+ 32, 27, 24, 31, 38, 37, 38, 34, 30, 27, 31, 39, 43, 42, 39, 35, 31, 35, 43,
+ 50, 47, 44, 39, 33, 39, 47, 55, 52, 46, 39, 34, 43, 50, 54, 55, 49, 42, 36,
+ 41, 46, 44, 38, 32, 27, 24, 41, 46, 46, 40, 34, 31, 27, 40, 48, 50, 44, 40,
+ 35, 30, 41, 47, 55, 48, 43, 39, 34, 44, 50, 58, 54, 48, 42, 37, 47, 54, 60,
+ 58, 52, 45, 37, 50, 55, 61, 60, 54, 47, 39, 2, 2, 2, 1, 1, 2, 4, 3,
+ 2, 2, 1, 0, 2, 5, 3, 2, 2, 2, 2, 4, 6, 4, 4, 4, 4, 4, 5,
+ 7, 8, 7, 7, 7, 7, 6, 7, 12, 11, 11, 10, 8, 6, 7, 17, 15, 13, 10,
+ 9, 6, 7, 3, 2, 2, 1, 3, 5, 8, 4, 2, 2, 2, 3, 5, 8, 7, 3,
+ 2, 3, 6, 6, 9, 11, 4, 5, 6, 9, 7, 10, 14, 8, 8, 9, 12, 8, 10,
+ 17, 13, 13, 12, 14, 12, 10, 22, 18, 14, 13, 15, 14, 10, 7, 3, 5, 8, 8,
+ 9, 11, 12, 3, 5, 8, 9, 8, 11, 15, 5, 5, 11, 12, 9, 13, 18, 8, 9,
+ 15, 16, 15, 15, 21, 12, 13, 18, 19, 19, 15, 25, 16, 18, 21, 21, 21, 15, 25,
+ 22, 20, 23, 23, 22, 19, 15, 8, 13, 15, 15, 12, 16, 18, 10, 14, 16, 17, 17,
+ 17, 21, 13, 14, 19, 20, 21, 18, 25, 17, 19, 23, 23, 24, 20, 25, 21, 24, 27,
+ 28, 27, 23, 25, 26, 29, 31, 30, 28, 26, 25, 32, 32, 32, 31, 31, 29, 23, 21,
+ 22, 24, 24, 23, 16, 26, 22, 23, 24, 26, 25, 17, 26, 24, 26, 28, 30, 28, 21,
+ 26, 28, 31, 33, 33, 32, 27, 27, 35, 36, 36, 38, 35, 30, 29, 38, 41, 42, 39,
+ 36, 31, 34, 41, 45, 43, 42, 38, 33, 32, 34, 34, 32, 30, 25, 20, 31, 35, 35,
+ 35, 32, 28, 23, 31, 38, 38, 38, 35, 31, 28, 31, 40, 44, 43, 39, 35, 32, 34,
+ 43, 49, 47, 43, 40, 32, 40, 46, 54, 52, 46, 39, 35, 43, 50, 55, 55, 48, 42,
+ 36, 42, 47, 45, 39, 33, 28, 24, 41, 47, 48, 40, 35, 31, 27, 41, 47, 50, 45,
+ 40, 35, 31, 42, 48, 56, 49, 44, 39, 35, 45, 51, 57, 55, 48, 42, 37, 48, 53,
+ 61, 59, 51, 44, 39, 50, 57, 61, 61, 54, 48, 40, 2, 1, 1, 3, 3, 1, 3,
+ 2, 1, 1, 2, 2, 0, 3, 2, 2, 1, 1, 2, 2, 4, 2, 3, 3, 3, 4,
+ 4, 5, 5, 6, 6, 6, 7, 6, 5, 10, 10, 9, 9, 8, 6, 5, 16, 14, 11,
+ 9, 8, 6, 5, 2, 2, 1, 1, 2, 4, 6, 2, 2, 1, 1, 2, 3, 5, 4,
+ 2, 1, 2, 3, 4, 6, 9, 3, 4, 4, 6, 5, 7, 11, 7, 7, 8, 9, 5,
+ 7, 14, 11, 11, 11, 11, 9, 7, 19, 16, 13, 11, 12, 11, 7, 5, 2, 4, 6,
+ 7, 7, 9, 9, 2, 4, 7, 7, 6, 8, 13, 2, 5, 9, 9, 6, 10, 15, 5,
+ 8, 12, 12, 12, 12, 18, 9, 11, 16, 16, 15, 12, 21, 14, 16, 19, 18, 17, 12,
+ 23, 20, 18, 20, 19, 18, 16, 13, 7, 11, 12, 13, 11, 14, 16, 8, 12, 14, 15,
+ 14, 13, 19, 10, 13, 16, 17, 18, 15, 21, 14, 17, 20, 20, 20, 16, 22, 19, 21,
+ 24, 24, 24, 20, 21, 24, 26, 27, 26, 26, 23, 22, 30, 29, 28, 28, 27, 26, 20,
+ 19, 20, 20, 22, 21, 14, 23, 20, 22, 23, 23, 21, 13, 23, 22, 24, 25, 26, 24,
+ 19, 24, 26, 28, 29, 29, 28, 23, 25, 31, 34, 33, 34, 32, 25, 28, 36, 39, 37,
+ 36, 33, 28, 30, 39, 41, 39, 38, 34, 30, 29, 32, 31, 31, 28, 23, 19, 28, 33,
+ 33, 32, 29, 24, 20, 28, 37, 35, 37, 32, 28, 24, 28, 37, 41, 40, 37, 33, 28,
+ 31, 39, 46, 43, 40, 35, 29, 37, 43, 51, 48, 42, 36, 31, 39, 46, 51, 51, 44,
+ 39, 33, 39, 44, 42, 36, 30, 26, 22, 39, 44, 45, 38, 32, 28, 24, 39, 44, 47,
+ 41, 35, 31, 27, 38, 47, 51, 45, 40, 35, 31, 41, 48, 54, 51, 44, 39, 33, 46,
+ 51, 56, 57, 47, 40, 35, 47, 53, 58, 58, 49, 43, 37, 1, 1, 3, 6, 6, 4,
+ 2, 1, 1, 3, 5, 5, 3, 0, 2, 1, 2, 3, 4, 3, 2, 2, 2, 2, 3,
+ 5, 5, 4, 4, 5, 5, 6, 8, 6, 4, 9, 8, 8, 8, 8, 6, 4, 14, 12,
+ 10, 8, 9, 6, 4, 2, 1, 2, 4, 3, 3, 5, 2, 1, 1, 3, 3, 2, 3,
+ 2, 1, 1, 1, 1, 2, 4, 3, 3, 3, 3, 3, 3, 4, 8, 6, 6, 6, 6,
+ 4, 4, 12, 10, 10, 9, 7, 6, 5, 18, 14, 11, 10, 8, 7, 5, 2, 1, 3,
+ 4, 5, 6, 8, 4, 2, 3, 5, 5, 5, 6, 9, 2, 4, 6, 6, 4, 6, 12,
+ 3, 7, 9, 9, 9, 8, 16, 8, 10, 12, 13, 12, 8, 18, 13, 14, 15, 14, 13,
+ 8, 20, 18, 16, 17, 16, 15, 13, 8, 6, 9, 10, 11, 9, 11, 13, 7, 10, 11,
+ 12, 12, 11, 15, 8, 11, 13, 13, 13, 11, 17, 11, 15, 16, 16, 16, 13, 19, 16,
+ 19, 21, 21, 20, 16, 18, 21, 23, 24, 23, 22, 19, 20, 27, 26, 25, 24, 23, 21,
+ 17, 17, 18, 18, 19, 18, 12, 21, 18, 19, 19, 20, 18, 11, 20, 20, 21, 22, 22,
+ 21, 15, 20, 24, 25, 25, 26, 24, 19, 22, 28, 29, 29, 30, 28, 22, 24, 33, 36,
+ 35, 32, 29, 24, 28, 36, 39, 36, 35, 31, 26, 27, 29, 27, 27, 24, 21, 17, 26,
+ 32, 30, 29, 25, 21, 16, 26, 33, 33, 31, 27, 23, 20, 25, 36, 36, 34, 32, 28,
+ 23, 29, 37, 42, 41, 34, 31, 26, 32, 40, 46, 44, 38, 33, 27, 37, 41, 47, 46,
+ 40, 34, 29, 36, 41, 39, 32, 27, 24, 19, 36, 41, 41, 35, 29, 24, 20, 35, 40,
+ 44, 37, 32, 27, 24, 36, 43, 47, 42, 37, 32, 27, 38, 44, 50, 47, 40, 34, 29,
+ 41, 47, 52, 49, 42, 37, 31, 43, 49, 52, 52, 46, 39, 33, 2, 2, 3, 3, 3,
+ 2, 2, 1, 2, 3, 3, 3, 2, 2, 0, 2, 2, 3, 2, 2, 1, 1, 1, 1,
+ 2, 2, 2, 3, 3, 3, 3, 4, 4, 3, 3, 7, 7, 7, 6, 5, 3, 3, 13,
+ 11, 9, 7, 5, 3, 3, 0, 2, 2, 3, 2, 2, 2, 1, 2, 2, 3, 2, 2,
+ 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 3, 4, 4, 4, 4,
+ 4, 3, 4, 9, 8, 8, 7, 5, 4, 4, 16, 13, 10, 8, 6, 4, 3, 2, 1,
+ 2, 2, 2, 1, 4, 2, 1, 1, 1, 1, 1, 4, 2, 1, 1, 0, 0, 1, 5,
+ 3, 2, 3, 3, 3, 3, 6, 7, 6, 6, 6, 7, 6, 6, 12, 11, 11, 10, 8,
+ 7, 6, 19, 17, 13, 12, 10, 9, 8, 2, 4, 4, 5, 5, 5, 8, 3, 5, 5,
+ 6, 6, 6, 8, 7, 6, 6, 7, 7, 7, 8, 10, 9, 10, 10, 10, 11, 10, 10,
+ 14, 14, 14, 14, 13, 13, 13, 19, 19, 18, 16, 15, 14, 18, 25, 22, 20, 18, 16,
+ 16, 12, 12, 12, 12, 12, 12, 8, 14, 14, 14, 13, 14, 13, 8, 14, 16, 15, 15,
+ 15, 14, 11, 14, 19, 19, 19, 19, 18, 14, 17, 23, 23, 23, 23, 20, 16, 21, 27,
+ 28, 27, 26, 23, 18, 25, 31, 32, 29, 28, 25, 20, 21, 23, 22, 21, 18, 14, 10,
+ 21, 25, 23, 23, 20, 16, 11, 21, 27, 26, 25, 22, 18, 14, 21, 27, 30, 29, 25,
+ 21, 18, 24, 30, 34, 34, 30, 25, 19, 27, 33, 39, 37, 32, 26, 21, 30, 36, 40,
+ 40, 35, 28, 23, 29, 34, 33, 27, 22, 17, 13, 29, 35, 37, 29, 23, 19, 14, 29,
+ 35, 39, 32, 25, 22, 17, 30, 35, 42, 35, 30, 25, 21, 31, 37, 44, 40, 35, 29,
+ 23, 33, 41, 46, 46, 36, 31, 25, 36, 43, 47, 46, 39, 32, 26, 1, 2, 2, 2,
+ 2, 2, 1, 2, 1, 2, 3, 2, 2, 1, 2, 0, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 4, 4, 8, 8, 8, 7, 5, 4, 4,
+ 14, 12, 9, 8, 6, 4, 4, 2, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,
+ 1, 2, 2, 2, 1, 2, 2, 1, 4, 2, 2, 2, 3, 2, 3, 5, 6, 5, 5,
+ 5, 5, 4, 5, 11, 10, 9, 8, 6, 5, 5, 18, 15, 11, 9, 7, 5, 5, 2,
+ 2, 1, 2, 1, 3, 6, 2, 2, 2, 2, 2, 4, 6, 4, 2, 3, 3, 4, 4,
+ 7, 7, 3, 6, 6, 6, 7, 9, 11, 7, 9, 10, 10, 10, 8, 15, 12, 14, 13,
+ 12, 11, 8, 20, 18, 17, 15, 14, 12, 11, 4, 6, 7, 7, 8, 7, 10, 8, 7,
+ 8, 8, 9, 9, 10, 11, 8, 10, 10, 11, 11, 11, 14, 10, 14, 14, 14, 14, 13,
+ 14, 16, 18, 18, 18, 17, 16, 15, 21, 22, 21, 20, 18, 18, 20, 28, 26, 24, 22,
+ 20, 19, 14, 15, 15, 15, 16, 15, 10, 17, 17, 16, 16, 17, 15, 10, 16, 18, 19,
+ 19, 19, 18, 14, 17, 22, 23, 23, 23, 21, 18, 19, 27, 27, 27, 27, 24, 20, 24,
+ 31, 34, 32, 29, 27, 21, 28, 34, 36, 33, 31, 28, 23, 24, 26, 24, 24, 21, 17,
+ 13, 24, 29, 27, 26, 23, 18, 14, 24, 30, 29, 28, 25, 21, 17, 24, 31, 34, 32,
+ 29, 25, 22, 29, 35, 38, 37, 34, 29, 23, 32, 37, 44, 42, 36, 31, 25, 34, 40,
+ 45, 44, 39, 33, 26, 33, 38, 37, 30, 24, 20, 16, 32, 39, 40, 32, 26, 21, 18,
+ 32, 38, 42, 35, 30, 25, 21, 33, 40, 46, 39, 33, 28, 24, 34, 41, 48, 43, 38,
+ 32, 27, 37, 43, 49, 49, 41, 35, 28, 40, 46, 49, 50, 44, 36, 30, 2, 1, 1,
+ 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 0, 2, 1, 2, 3, 2,
+ 3, 2, 3, 3, 4, 5, 5, 5, 6, 5, 6, 5, 5, 10, 9, 9, 8, 6, 5,
+ 5, 16, 14, 11, 8, 7, 5, 4, 2, 2, 1, 2, 1, 2, 5, 2, 2, 1, 1,
+ 1, 2, 5, 3, 2, 1, 1, 1, 3, 6, 4, 3, 3, 3, 4, 4, 7, 8, 6,
+ 7, 7, 7, 5, 7, 12, 11, 10, 10, 9, 7, 7, 19, 16, 13, 11, 10, 9, 7,
+ 2, 2, 4, 4, 5, 6, 8, 4, 2, 4, 5, 5, 6, 8, 8, 2, 5, 7, 7,
+ 6, 9, 11, 4, 8, 10, 10, 10, 11, 14, 8, 11, 14, 14, 14, 11, 18, 14, 16,
+ 17, 16, 15, 11, 21, 20, 18, 19, 18, 16, 14, 8, 7, 10, 11, 11, 9, 12, 11,
+ 8, 11, 11, 12, 12, 12, 14, 8, 12, 14, 14, 15, 14, 17, 12, 17, 18, 18, 17,
+ 15, 18, 17, 21, 21, 22, 21, 19, 18, 23, 26, 25, 24, 23, 21, 22, 30, 29, 27,
+ 26, 24, 23, 17, 18, 18, 18, 19, 18, 12, 19, 19, 19, 20, 20, 19, 12, 20, 20,
+ 21, 23, 23, 22, 17, 20, 25, 27, 26, 27, 26, 21, 22, 30, 32, 31, 31, 29, 23,
+ 26, 35, 37, 35, 33, 30, 25, 30, 37, 40, 37, 36, 32, 27, 28, 29, 28, 28, 25,
+ 20, 17, 27, 32, 31, 30, 26, 22, 18, 27, 34, 34, 34, 29, 25, 21, 27, 35, 38,
+ 37, 34, 30, 25, 31, 38, 43, 41, 38, 33, 27, 34, 41, 49, 47, 39, 33, 29, 38,
+ 44, 49, 49, 43, 36, 30, 36, 43, 41, 34, 28, 24, 20, 37, 43, 44, 36, 30, 25,
+ 21, 36, 43, 46, 38, 34, 29, 24, 37, 44, 49, 44, 38, 34, 29, 40, 46, 53, 49,
+ 42, 36, 30, 42, 49, 55, 54, 45, 38, 33, 45, 51, 55, 55, 48, 41, 34, 2, 2,
+ 1, 2, 2, 2, 4, 2, 2, 1, 2, 2, 1, 3, 3, 2, 2, 0, 1, 2, 4,
+ 3, 3, 3, 3, 2, 3, 5, 6, 6, 6, 6, 5, 4, 5, 10, 10, 9, 8, 6,
+ 4, 5, 16, 14, 11, 9, 7, 4, 5, 2, 2, 1, 2, 3, 5, 7, 3, 2, 2,
+ 2, 3, 4, 6, 4, 2, 2, 2, 3, 5, 7, 7, 3, 4, 4, 6, 6, 8, 10,
+ 7, 7, 8, 9, 6, 8, 14, 11, 11, 10, 11, 10, 8, 19, 16, 13, 11, 13, 11,
+ 8, 4, 2, 5, 7, 8, 9, 11, 8, 3, 4, 7, 8, 8, 10, 11, 3, 5, 9,
+ 10, 8, 11, 14, 5, 8, 12, 13, 13, 13, 18, 9, 12, 16, 17, 16, 13, 21, 14,
+ 16, 19, 19, 18, 13, 22, 20, 18, 21, 20, 19, 17, 11, 8, 12, 14, 14, 12, 16,
+ 15, 8, 13, 14, 15, 16, 15, 18, 10, 14, 17, 18, 17, 16, 20, 14, 18, 20, 21,
+ 21, 18, 21, 19, 23, 24, 25, 24, 21, 21, 24, 27, 28, 27, 27, 24, 23, 30, 31,
+ 29, 29, 27, 27, 20, 19, 21, 22, 23, 22, 16, 23, 21, 23, 23, 24, 22, 15, 23,
+ 23, 24, 26, 26, 25, 20, 23, 27, 29, 30, 31, 29, 25, 25, 32, 33, 34, 34, 32,
+ 27, 27, 36, 39, 38, 36, 34, 29, 31, 39, 43, 41, 39, 37, 30, 30, 33, 33, 32,
+ 29, 25, 20, 29, 34, 34, 34, 30, 25, 21, 29, 37, 37, 37, 33, 28, 25, 30, 39,
+ 41, 40, 37, 33, 29, 33, 42, 47, 45, 41, 38, 30, 36, 44, 51, 49, 44, 38, 33,
+ 40, 47, 52, 53, 46, 38, 34, 41, 46, 44, 37, 32, 28, 23, 40, 45, 46, 40, 33,
+ 29, 25, 40, 46, 49, 42, 37, 33, 28, 40, 47, 53, 47, 41, 36, 32, 43, 50, 55,
+ 52, 46, 40, 35, 45, 52, 57, 56, 49, 43, 36, 48, 54, 57, 58, 52, 44, 38, 2,
+ 1, 2, 2, 2, 4, 5, 2, 2, 2, 2, 2, 2, 4, 3, 2, 2, 1, 0, 2,
+ 5, 3, 3, 3, 2, 2, 3, 6, 7, 6, 6, 5, 5, 4, 6, 11, 9, 9, 8,
+ 6, 4, 6, 16, 13, 10, 8, 7, 4, 6, 3, 2, 2, 3, 4, 7, 9, 3, 2,
+ 2, 3, 4, 6, 8, 5, 2, 2, 2, 4, 5, 8, 9, 4, 4, 4, 7, 6, 9,
+ 13, 7, 7, 7, 10, 6, 9, 16, 11, 11, 10, 12, 11, 9, 20, 16, 12, 11, 13,
+ 12, 9, 5, 2, 5, 9, 9, 10, 13, 9, 3, 5, 9, 10, 9, 11, 13, 3, 5,
+ 10, 11, 8, 11, 15, 6, 8, 13, 14, 14, 14, 20, 11, 12, 16, 18, 18, 13, 23,
+ 15, 16, 19, 20, 18, 14, 23, 19, 18, 20, 21, 20, 18, 13, 8, 13, 15, 16, 14,
+ 18, 16, 9, 14, 16, 17, 17, 17, 19, 11, 14, 18, 18, 19, 17, 23, 15, 18, 21,
+ 22, 22, 19, 24, 20, 23, 25, 26, 25, 22, 24, 24, 27, 28, 28, 28, 25, 23, 30,
+ 31, 30, 30, 29, 27, 21, 20, 23, 23, 25, 24, 18, 25, 22, 24, 25, 26, 24, 17,
+ 24, 24, 27, 28, 28, 26, 21, 24, 28, 30, 31, 31, 29, 26, 26, 32, 35, 36, 36,
+ 33, 28, 28, 37, 40, 39, 39, 35, 29, 30, 40, 45, 42, 40, 37, 32, 31, 34, 33,
+ 34, 31, 27, 22, 31, 36, 35, 36, 32, 28, 23, 30, 38, 38, 38, 34, 30, 26, 30,
+ 41, 42, 42, 39, 33, 29, 34, 43, 48, 47, 42, 37, 31, 36, 45, 53, 51, 44, 40,
+ 34, 41, 47, 53, 54, 47, 40, 35, 41, 47, 45, 39, 34, 30, 26, 41, 47, 47, 41,
+ 35, 30, 26, 42, 48, 50, 44, 37, 34, 30, 42, 48, 54, 47, 42, 38, 33, 43, 51,
+ 56, 52, 47, 40, 35, 47, 53, 59, 57, 49, 42, 37, 50, 55, 59, 59, 52, 46, 39,
+ 1, 2, 2, 4, 4, 3, 4, 2, 1, 2, 4, 4, 2, 3, 2, 2, 2, 2, 3,
+ 0, 3, 2, 2, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 4, 4, 8, 8, 7,
+ 7, 6, 4, 4, 13, 11, 9, 7, 6, 4, 4, 2, 1, 2, 3, 4, 6, 7, 2,
+ 1, 2, 3, 4, 5, 6, 3, 2, 1, 1, 2, 3, 5, 6, 3, 2, 3, 4, 4,
+ 6, 10, 5, 5, 6, 7, 4, 6, 12, 9, 9, 8, 9, 7, 6, 17, 14, 10, 9,
+ 10, 9, 6, 2, 2, 5, 7, 8, 9, 11, 7, 2, 4, 8, 8, 8, 9, 11, 2,
+ 4, 7, 8, 6, 8, 14, 4, 7, 10, 10, 11, 10, 17, 8, 10, 14, 15, 14, 10,
+ 19, 12, 14, 16, 16, 15, 10, 20, 17, 15, 17, 18, 17, 15, 11, 7, 12, 14, 14,
+ 12, 15, 14, 8, 12, 15, 16, 15, 15, 17, 9, 12, 15, 16, 16, 14, 19, 12, 16,
+ 18, 19, 18, 15, 21, 17, 20, 22, 23, 22, 18, 20, 22, 24, 25, 25, 23, 22, 20,
+ 26, 26, 27, 26, 25, 24, 18, 18, 21, 22, 23, 22, 16, 21, 20, 22, 23, 24, 23,
+ 15, 22, 21, 24, 25, 24, 23, 18, 22, 26, 26, 28, 28, 27, 23, 23, 30, 31, 32,
+ 33, 29, 24, 26, 34, 38, 36, 34, 31, 26, 27, 36, 39, 37, 37, 34, 27, 28, 31,
+ 32, 32, 29, 25, 20, 29, 33, 33, 33, 29, 25, 21, 27, 36, 35, 34, 30, 27, 23,
+ 28, 38, 39, 37, 34, 29, 26, 31, 39, 43, 42, 38, 32, 28, 34, 41, 48, 46, 41,
+ 34, 30, 37, 44, 49, 49, 42, 37, 31, 39, 44, 42, 36, 31, 27, 23, 39, 45, 45,
+ 38, 33, 28, 23, 39, 45, 47, 40, 34, 30, 26, 40, 45, 52, 44, 38, 34, 30, 41,
+ 47, 52, 49, 42, 37, 33, 43, 48, 55, 53, 45, 39, 33, 46, 51, 56, 55, 48, 40,
+ 35, 2, 3, 5, 6, 6, 5, 4, 1, 2, 4, 6, 6, 4, 2, 1, 2, 3, 4,
+ 5, 3, 0, 1, 1, 1, 3, 4, 3, 2, 3, 3, 3, 4, 6, 4, 2, 7, 6,
+ 6, 6, 6, 4, 2, 11, 9, 7, 6, 6, 4, 2, 1, 2, 3, 5, 4, 5, 6,
+ 1, 2, 3, 4, 4, 4, 5, 2, 1, 2, 3, 2, 2, 3, 2, 1, 1, 1, 1,
+ 2, 4, 5, 4, 4, 4, 3, 2, 3, 9, 8, 7, 7, 5, 4, 4, 14, 11, 8,
+ 7, 7, 6, 4, 2, 1, 5, 5, 6, 8, 9, 2, 1, 4, 6, 6, 6, 8, 5,
+ 1, 4, 6, 6, 5, 6, 10, 2, 5, 7, 7, 7, 7, 13, 6, 8, 10, 11, 10,
+ 7, 15, 11, 11, 13, 13, 11, 7, 16, 14, 13, 14, 14, 13, 12, 6, 6, 11, 11,
+ 12, 11, 13, 11, 7, 11, 12, 13, 13, 12, 13, 7, 11, 13, 13, 13, 11, 16, 10,
+ 14, 15, 14, 15, 12, 17, 15, 17, 19, 19, 18, 15, 16, 19, 20, 21, 21, 20, 18,
+ 16, 22, 23, 23, 23, 21, 20, 15, 17, 18, 19, 20, 19, 13, 18, 18, 20, 20, 21,
+ 20, 12, 18, 19, 21, 21, 21, 19, 15, 18, 22, 24, 24, 24, 22, 18, 20, 27, 28,
+ 28, 28, 26, 20, 21, 30, 33, 31, 29, 28, 22, 24, 33, 34, 33, 32, 28, 24, 27,
+ 30, 29, 29, 26, 22, 17, 26, 31, 30, 31, 27, 22, 18, 26, 34, 33, 31, 27, 23,
+ 19, 26, 34, 35, 33, 31, 27, 22, 28, 36, 40, 38, 34, 29, 24, 31, 37, 43, 42,
+ 36, 30, 26, 33, 39, 45, 44, 39, 33, 27, 37, 41, 39, 34, 29, 25, 21, 36, 41,
+ 42, 36, 30, 25, 21, 37, 41, 45, 37, 31, 26, 22, 36, 42, 46, 41, 35, 31, 26,
+ 37, 43, 48, 44, 38, 31, 28, 39, 45, 50, 48, 41, 34, 29, 41, 46, 51, 51, 45,
+ 36, 29, 2, 2, 3, 4, 4, 3, 2, 2, 2, 3, 4, 4, 3, 2, 1, 2, 2,
+ 3, 3, 2, 1, 0, 2, 2, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 3, 7,
+ 6, 7, 6, 4, 3, 3, 12, 11, 8, 7, 5, 3, 3, 1, 2, 3, 3, 2, 2,
+ 2, 0, 2, 2, 3, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2,
+ 2, 1, 3, 4, 3, 4, 4, 4, 3, 3, 9, 8, 8, 7, 5, 3, 3, 16, 13,
+ 10, 8, 6, 4, 3, 1, 2, 2, 2, 2, 2, 3, 2, 1, 1, 2, 2, 2, 3,
+ 2, 0, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, 5, 6, 5, 5, 5, 5,
+ 4, 5, 12, 10, 10, 9, 7, 6, 5, 18, 17, 13, 10, 9, 7, 6, 2, 3, 3,
+ 4, 4, 4, 7, 2, 4, 4, 5, 5, 5, 8, 5, 5, 5, 6, 6, 6, 7, 8,
+ 8, 8, 9, 9, 9, 9, 9, 13, 13, 12, 13, 12, 11, 12, 19, 17, 16, 15, 14,
+ 13, 18, 24, 21, 18, 17, 15, 15, 11, 11, 11, 11, 11, 11, 8, 13, 13, 12, 13,
+ 13, 12, 8, 12, 15, 15, 14, 14, 13, 10, 13, 18, 18, 17, 18, 16, 13, 16, 23,
+ 22, 22, 22, 20, 15, 20, 26, 28, 26, 25, 21, 17, 24, 29, 30, 27, 27, 23, 18,
+ 20, 23, 21, 21, 17, 13, 10, 21, 24, 23, 22, 19, 15, 10, 21, 25, 26, 24, 21,
+ 17, 12, 21, 27, 28, 27, 25, 20, 17, 23, 29, 33, 33, 29, 23, 19, 25, 32, 38,
+ 36, 30, 26, 20, 29, 35, 39, 39, 34, 27, 21, 28, 34, 33, 25, 21, 17, 12, 28,
+ 34, 34, 29, 22, 17, 13, 28, 34, 38, 30, 25, 20, 16, 29, 34, 40, 33, 29, 24,
+ 20, 30, 37, 42, 38, 33, 26, 22, 33, 39, 44, 43, 36, 29, 24, 35, 41, 44, 44,
+ 38, 32, 26, 1, 2, 3, 4, 4, 3, 3, 2, 2, 3, 4, 4, 3, 2, 1, 2,
+ 3, 3, 3, 2, 1, 2, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ 7, 6, 6, 6, 4, 3, 3, 13, 11, 8, 6, 5, 3, 3, 2, 2, 3, 3, 3,
+ 3, 3, 2, 1, 2, 3, 3, 2, 3, 2, 1, 2, 2, 2, 1, 1, 2, 1, 1,
+ 2, 1, 1, 3, 4, 4, 4, 4, 4, 3, 3, 9, 8, 8, 7, 5, 3, 3, 16,
+ 13, 10, 7, 5, 4, 3, 2, 1, 2, 2, 3, 4, 6, 2, 2, 2, 3, 3, 4,
+ 6, 2, 2, 2, 2, 3, 3, 6, 5, 2, 4, 4, 4, 5, 7, 8, 6, 8, 8,
+ 8, 7, 6, 13, 11, 12, 11, 10, 9, 7, 19, 16, 15, 13, 11, 10, 9, 2, 6,
+ 7, 8, 8, 7, 10, 5, 6, 8, 8, 9, 9, 10, 9, 7, 8, 9, 9, 9, 10,
+ 12, 9, 12, 12, 12, 12, 11, 12, 14, 15, 15, 16, 15, 14, 13, 20, 20, 19, 18,
+ 16, 15, 18, 26, 24, 21, 19, 18, 18, 13, 14, 15, 15, 16, 15, 10, 14, 16, 15,
+ 16, 17, 16, 10, 15, 18, 17, 17, 17, 16, 12, 15, 21, 21, 21, 21, 19, 16, 18,
+ 25, 25, 25, 25, 22, 17, 21, 28, 30, 28, 26, 24, 19, 25, 32, 34, 31, 30, 26,
+ 21, 24, 24, 25, 25, 21, 17, 13, 23, 27, 26, 25, 23, 18, 14, 23, 29, 28, 27,
+ 23, 19, 15, 23, 30, 31, 31, 27, 23, 19, 26, 32, 36, 35, 31, 26, 21, 29, 35,
+ 41, 41, 34, 28, 23, 31, 38, 42, 43, 35, 30, 24, 32, 38, 36, 30, 25, 20, 16,
+ 31, 38, 39, 32, 26, 21, 17, 31, 38, 41, 33, 27, 23, 19, 32, 37, 44, 36, 31,
+ 26, 23, 34, 39, 45, 42, 36, 30, 25, 35, 41, 47, 46, 39, 33, 26, 38, 44, 48,
+ 49, 42, 34, 29, 1, 2, 3, 4, 4, 4, 3, 2, 2, 3, 4, 4, 3, 2, 1,
+ 2, 2, 3, 3, 1, 1, 2, 2, 0, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3,
+ 3, 7, 7, 7, 6, 4, 3, 3, 13, 11, 8, 6, 5, 3, 3, 2, 2, 2, 3,
+ 4, 4, 6, 2, 2, 2, 3, 3, 3, 5, 2, 1, 2, 2, 2, 2, 4, 2, 2,
+ 2, 1, 1, 2, 5, 5, 5, 4, 4, 4, 3, 5, 10, 9, 8, 7, 6, 4, 5,
+ 17, 14, 10, 8, 7, 6, 5, 2, 2, 4, 5, 5, 7, 9, 2, 2, 4, 5, 6,
+ 7, 8, 5, 2, 4, 5, 5, 6, 7, 8, 3, 6, 7, 7, 7, 9, 12, 6, 9,
+ 10, 11, 10, 9, 15, 11, 13, 14, 13, 12, 9, 19, 17, 16, 16, 14, 13, 12, 4,
+ 7, 10, 11, 12, 10, 13, 9, 7, 11, 12, 12, 12, 13, 12, 8, 11, 12, 12, 12,
+ 12, 14, 10, 14, 15, 15, 15, 13, 16, 15, 18, 18, 20, 18, 16, 15, 21, 23, 22,
+ 21, 20, 19, 19, 27, 26, 24, 22, 21, 20, 15, 17, 18, 19, 19, 18, 13, 17, 18,
+ 19, 20, 21, 19, 13, 18, 20, 21, 21, 20, 19, 15, 17, 24, 24, 24, 24, 23, 18,
+ 20, 27, 28, 29, 28, 26, 21, 23, 32, 34, 32, 30, 27, 22, 27, 35, 37, 35, 32,
+ 29, 23, 26, 29, 28, 28, 25, 21, 17, 27, 31, 30, 30, 26, 21, 17, 27, 33, 33,
+ 31, 27, 22, 19, 27, 34, 36, 34, 31, 26, 22, 28, 36, 41, 40, 36, 28, 24, 33,
+ 38, 45, 43, 37, 32, 26, 35, 41, 45, 45, 40, 34, 28, 35, 41, 40, 33, 29, 24,
+ 20, 35, 42, 43, 35, 29, 25, 20, 36, 41, 45, 37, 31, 26, 22, 36, 41, 47, 40,
+ 35, 30, 25, 37, 43, 48, 46, 40, 33, 27, 39, 44, 51, 51, 42, 35, 30, 43, 47,
+ 52, 52, 46, 38, 31, 2, 2, 3, 5, 5, 4, 5, 2, 2, 3, 4, 4, 3, 3,
+ 2, 2, 3, 3, 2, 1, 3, 2, 2, 2, 0, 2, 1, 3, 4, 4, 3, 3, 3,
+ 2, 3, 8, 7, 7, 6, 4, 2, 4, 13, 11, 8, 6, 5, 2, 3, 2, 2, 3,
+ 3, 5, 6, 8, 2, 2, 2, 3, 4, 5, 7, 2, 2, 2, 2, 3, 4, 6, 4,
+ 2, 2, 2, 3, 4, 6, 8, 5, 5, 5, 6, 4, 7, 11, 9, 9, 8, 8, 7,
+ 7, 17, 13, 10, 8, 10, 8, 7, 2, 2, 5, 7, 8, 10, 12, 4, 2, 5, 8,
+ 9, 9, 11, 8, 2, 5, 8, 8, 7, 9, 11, 3, 6, 10, 10, 10, 10, 15, 7,
+ 9, 13, 14, 13, 11, 18, 12, 13, 16, 15, 15, 11, 19, 17, 16, 17, 17, 16, 15,
+ 8, 8, 12, 14, 15, 13, 16, 12, 8, 13, 14, 16, 15, 15, 15, 8, 13, 15, 16,
+ 15, 15, 17, 12, 16, 17, 18, 18, 16, 19, 16, 20, 22, 22, 22, 18, 18, 22, 24,
+ 25, 24, 23, 22, 19, 26, 27, 26, 26, 24, 24, 17, 19, 21, 21, 23, 22, 16, 20,
+ 20, 22, 24, 24, 23, 16, 20, 22, 23, 24, 24, 22, 18, 20, 25, 27, 27, 27, 26,
+ 22, 22, 30, 31, 32, 31, 29, 24, 25, 34, 36, 36, 34, 30, 26, 29, 37, 40, 37,
+ 36, 33, 27, 28, 32, 32, 31, 29, 25, 20, 28, 34, 33, 33, 29, 25, 21, 28, 36,
+ 36, 35, 30, 25, 22, 29, 37, 39, 37, 33, 30, 25, 31, 39, 44, 43, 38, 33, 27,
+ 34, 41, 49, 46, 41, 35, 29, 39, 43, 49, 49, 42, 37, 31, 39, 46, 43, 37, 31,
+ 27, 23, 39, 45, 46, 39, 33, 28, 23, 39, 46, 49, 41, 34, 29, 25, 39, 45, 50,
+ 44, 37, 34, 29, 40, 47, 52, 49, 42, 37, 31, 43, 49, 54, 53, 46, 39, 32, 45,
+ 51, 54, 55, 49, 42, 34, 2, 3, 3, 4, 4, 6, 7, 2, 2, 3, 4, 3, 4,
+ 5, 2, 2, 3, 2, 2, 2, 4, 3, 2, 2, 2, 0, 2, 5, 5, 4, 4, 3,
+ 3, 3, 5, 9, 8, 7, 6, 4, 3, 5, 13, 10, 8, 6, 5, 3, 5, 2, 2,
+ 3, 4, 6, 9, 10, 3, 2, 3, 4, 6, 7, 9, 3, 2, 2, 3, 4, 6, 8,
+ 6, 3, 2, 2, 5, 5, 8, 10, 5, 5, 5, 8, 6, 8, 13, 9, 8, 8, 10,
+ 9, 8, 16, 13, 9, 8, 11, 11, 8, 3, 2, 6, 9, 11, 12, 14, 7, 2, 6,
+ 10, 11, 11, 13, 10, 3, 5, 9, 11, 10, 12, 13, 4, 7, 11, 12, 13, 12, 18,
+ 9, 10, 14, 16, 15, 13, 21, 12, 13, 17, 18, 17, 12, 20, 16, 15, 18, 19, 19,
+ 17, 10, 8, 14, 16, 17, 15, 18, 13, 8, 14, 17, 18, 18, 18, 16, 10, 14, 17,
+ 19, 19, 17, 20, 13, 17, 20, 21, 21, 18, 21, 18, 21, 23, 25, 24, 21, 21, 22,
+ 25, 26, 27, 25, 24, 20, 26, 27, 28, 28, 27, 26, 19, 20, 23, 25, 26, 25, 19,
+ 22, 22, 25, 26, 27, 25, 18, 23, 23, 26, 27, 27, 26, 21, 22, 26, 29, 30, 31,
+ 29, 24, 24, 31, 34, 34, 34, 31, 27, 26, 34, 38, 37, 36, 34, 28, 28, 36, 41,
+ 38, 38, 35, 30, 31, 35, 35, 35, 31, 28, 23, 31, 37, 36, 36, 33, 28, 24, 30,
+ 39, 38, 37, 33, 29, 25, 31, 38, 41, 40, 36, 32, 28, 32, 41, 46, 44, 40, 35,
+ 29, 35, 43, 52, 49, 42, 37, 32, 37, 45, 51, 51, 45, 39, 33, 40, 48, 45, 39,
+ 34, 31, 26, 42, 48, 48, 41, 36, 30, 26, 42, 48, 50, 43, 37, 32, 28, 41, 48,
+ 53, 46, 39, 35, 31, 43, 49, 54, 52, 45, 39, 33, 44, 52, 57, 56, 47, 42, 36,
+ 46, 53, 57, 58, 50, 43, 37, 3, 4, 4, 5, 5, 6, 7, 2, 3, 4, 5, 5,
+ 4, 5, 2, 3, 4, 3, 3, 2, 3, 2, 2, 2, 2, 2, 0, 3, 3, 2, 2,
+ 2, 3, 2, 3, 6, 5, 5, 4, 3, 2, 3, 9, 7, 5, 4, 3, 2, 3, 2,
+ 3, 4, 5, 6, 8, 9, 2, 3, 3, 5, 6, 6, 7, 2, 2, 3, 3, 4, 5,
+ 6, 4, 2, 1, 1, 3, 3, 5, 8, 3, 3, 4, 5, 3, 5, 10, 6, 6, 5,
+ 7, 6, 5, 12, 9, 6, 5, 8, 7, 5, 2, 2, 6, 8, 9, 11, 12, 5, 2,
+ 5, 9, 9, 9, 11, 9, 2, 5, 8, 9, 8, 10, 13, 2, 5, 8, 9, 9, 9,
+ 15, 6, 8, 11, 12, 12, 9, 16, 8, 10, 13, 14, 13, 9, 15, 12, 11, 15, 15,
+ 15, 13, 9, 7, 13, 15, 15, 14, 17, 14, 8, 13, 15, 16, 16, 16, 16, 8, 13,
+ 15, 16, 16, 15, 18, 10, 14, 17, 17, 17, 14, 19, 15, 18, 20, 20, 20, 17, 16,
+ 18, 21, 22, 22, 22, 20, 15, 21, 22, 24, 24, 23, 22, 17, 19, 22, 23, 24, 23,
+ 16, 20, 20, 23, 24, 25, 23, 16, 20, 21, 24, 25, 24, 23, 19, 20, 24, 25, 26,
+ 27, 25, 21, 21, 29, 30, 29, 30, 28, 23, 22, 30, 33, 33, 31, 29, 24, 22, 31,
+ 36, 35, 33, 31, 26, 28, 32, 32, 32, 30, 26, 21, 28, 34, 34, 34, 30, 25, 21,
+ 29, 36, 35, 35, 31, 26, 22, 28, 36, 38, 36, 32, 28, 24, 29, 38, 44, 40, 36,
+ 32, 26, 32, 40, 46, 43, 38, 33, 28, 33, 42, 46, 46, 41, 35, 30, 39, 46, 44,
+ 37, 32, 28, 24, 40, 45, 46, 40, 33, 29, 24, 40, 46, 48, 40, 33, 29, 24, 40,
+ 45, 50, 43, 37, 33, 28, 40, 45, 51, 47, 40, 34, 29, 41, 47, 52, 51, 43, 37,
+ 31, 43, 48, 53, 53, 46, 39, 32, 4, 5, 6, 7, 8, 6, 7, 4, 4, 5, 7,
+ 7, 5, 4, 3, 4, 4, 5, 6, 3, 2, 3, 3, 3, 3, 5, 3, 0, 2, 1,
+ 1, 2, 4, 2, 0, 3, 2, 2, 2, 3, 2, 0, 5, 3, 2, 2, 3, 2, 0,
+ 4, 4, 5, 6, 7, 8, 8, 3, 4, 4, 5, 6, 6, 6, 2, 4, 4, 4, 4,
+ 4, 4, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 2, 2, 1, 3, 4, 3, 2,
+ 2, 2, 2, 3, 8, 5, 3, 2, 4, 3, 3, 3, 4, 6, 7, 9, 10, 11, 2,
+ 3, 6, 8, 8, 8, 9, 5, 3, 6, 7, 7, 6, 8, 9, 2, 4, 7, 6, 7,
+ 6, 12, 3, 5, 7, 8, 8, 6, 13, 4, 6, 9, 9, 9, 6, 11, 8, 6, 9,
+ 10, 10, 10, 5, 7, 11, 12, 13, 13, 14, 10, 8, 12, 13, 14, 14, 13, 13, 8,
+ 12, 13, 14, 14, 12, 15, 8, 12, 14, 14, 14, 11, 15, 10, 13, 15, 16, 15, 14,
+ 13, 12, 15, 17, 17, 17, 16, 11, 15, 17, 18, 19, 18, 18, 15, 17, 20, 20, 21,
+ 21, 14, 18, 18, 21, 21, 21, 20, 13, 18, 20, 22, 22, 22, 20, 16, 18, 20, 22,
+ 22, 23, 21, 17, 16, 23, 26, 24, 24, 22, 18, 16, 24, 27, 28, 26, 24, 20, 17,
+ 25, 30, 28, 28, 26, 21, 27, 29, 30, 29, 26, 23, 18, 27, 32, 31, 31, 27, 22,
+ 18, 27, 33, 33, 32, 27, 23, 19, 27, 33, 35, 32, 29, 24, 19, 26, 33, 37, 35,
+ 31, 26, 22, 27, 34, 39, 37, 32, 28, 23, 27, 34, 40, 40, 35, 29, 24, 37, 42,
+ 41, 34, 29, 25, 21, 37, 42, 43, 35, 30, 25, 21, 37, 43, 44, 36, 31, 27, 22,
+ 37, 42, 46, 40, 32, 27, 23, 36, 41, 46, 41, 35, 28, 24, 36, 42, 46, 45, 37,
+ 31, 26, 36, 41, 46, 46, 39, 33, 27, 4, 5, 6, 8, 8, 6, 5, 4, 5, 6,
+ 7, 8, 6, 4, 3, 4, 5, 6, 7, 4, 3, 3, 3, 4, 4, 4, 3, 2, 0,
+ 2, 2, 2, 3, 2, 2, 4, 4, 4, 3, 3, 2, 2, 10, 8, 6, 4, 3, 2,
+ 2, 3, 4, 5, 6, 5, 5, 5, 3, 4, 5, 6, 6, 5, 4, 2, 4, 4, 5,
+ 4, 4, 3, 2, 2, 3, 3, 3, 2, 1, 2, 2, 2, 2, 2, 2, 1, 6, 5,
+ 6, 5, 2, 1, 1, 13, 11, 7, 5, 3, 1, 1, 2, 3, 4, 4, 5, 5, 5,
+ 2, 3, 4, 4, 5, 4, 5, 2, 2, 4, 3, 4, 4, 4, 2, 1, 1, 1, 1,
+ 1, 2, 3, 3, 2, 2, 3, 1, 2, 9, 8, 7, 6, 4, 3, 2, 15, 14, 10,
+ 7, 6, 4, 3, 2, 3, 5, 5, 6, 6, 8, 1, 4, 5, 6, 6, 6, 8, 3,
+ 5, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 7, 7, 6, 10, 9, 10, 10, 9,
+ 8, 9, 15, 14, 13, 12, 11, 10, 15, 21, 18, 15, 14, 12, 12, 11, 11, 11, 12,
+ 13, 11, 8, 12, 13, 13, 13, 14, 12, 8, 12, 14, 14, 14, 15, 13, 9, 12, 16,
+ 15, 15, 15, 14, 10, 14, 19, 19, 19, 19, 17, 12, 17, 23, 24, 23, 21, 19, 13,
+ 21, 26, 28, 25, 23, 21, 15, 20, 22, 21, 22, 19, 14, 10, 20, 24, 23, 24, 20,
+ 16, 11, 20, 26, 25, 25, 21, 16, 12, 20, 25, 26, 25, 22, 18, 14, 20, 26, 30,
+ 29, 25, 20, 15, 22, 29, 36, 33, 28, 23, 17, 25, 31, 35, 36, 30, 25, 19, 28,
+ 35, 32, 26, 22, 17, 13, 28, 35, 36, 29, 24, 18, 14, 28, 34, 38, 30, 25, 19,
+ 14, 28, 35, 38, 31, 26, 21, 17, 26, 33, 38, 36, 30, 26, 19, 29, 36, 40, 39,
+ 33, 28, 20, 32, 37, 40, 40, 33, 29, 23, 4, 5, 6, 7, 7, 7, 6, 3, 5,
+ 6, 7, 7, 6, 5, 3, 4, 5, 6, 6, 4, 3, 3, 3, 3, 4, 4, 2, 1,
+ 2, 0, 1, 2, 3, 2, 2, 4, 4, 4, 3, 2, 2, 1, 10, 8, 5, 4, 2,
+ 2, 1, 3, 4, 5, 7, 7, 7, 6, 3, 4, 5, 6, 6, 5, 5, 2, 3, 5,
+ 5, 5, 4, 3, 2, 2, 2, 2, 2, 2, 0, 2, 2, 1, 2, 1, 1, 0, 7,
+ 6, 5, 4, 2, 1, 0, 13, 11, 7, 5, 3, 1, 0, 3, 3, 4, 5, 6, 7,
+ 8, 2, 3, 4, 5, 6, 6, 7, 2, 2, 4, 4, 4, 4, 6, 2, 2, 2, 2,
+ 3, 3, 5, 5, 3, 5, 5, 5, 4, 5, 10, 8, 9, 8, 7, 6, 5, 15, 13,
+ 12, 10, 8, 7, 6, 2, 6, 7, 8, 9, 9, 11, 2, 7, 8, 8, 9, 9, 10,
+ 6, 7, 8, 9, 9, 9, 10, 9, 7, 9, 9, 9, 9, 9, 9, 11, 12, 12, 13,
+ 12, 11, 10, 17, 17, 16, 14, 13, 13, 16, 23, 20, 18, 16, 15, 14, 13, 14, 14,
+ 15, 16, 15, 11, 13, 16, 16, 16, 17, 16, 11, 14, 17, 17, 17, 17, 16, 12, 14,
+ 18, 17, 18, 18, 16, 13, 15, 22, 22, 21, 22, 19, 14, 19, 26, 27, 26, 24, 21,
+ 16, 23, 30, 31, 28, 26, 23, 18, 23, 25, 24, 24, 22, 17, 13, 23, 27, 26, 25,
+ 23, 18, 14, 23, 29, 29, 26, 23, 18, 14, 23, 28, 29, 28, 24, 20, 16, 23, 29,
+ 33, 32, 28, 23, 18, 26, 32, 39, 37, 31, 25, 19, 29, 33, 38, 39, 34, 27, 21,
+ 31, 37, 37, 29, 24, 20, 16, 32, 38, 39, 31, 26, 21, 17, 31, 37, 41, 33, 27,
+ 21, 17, 31, 36, 43, 34, 28, 24, 20, 30, 37, 42, 40, 32, 26, 21, 31, 38, 44,
+ 44, 35, 29, 23, 35, 40, 46, 46, 39, 31, 24, 4, 5, 6, 8, 8, 7, 6, 4,
+ 5, 6, 7, 7, 6, 5, 3, 4, 5, 6, 6, 4, 3, 3, 3, 3, 3, 4, 2,
+ 1, 2, 1, 0, 2, 2, 1, 1, 4, 4, 4, 3, 2, 1, 1, 10, 8, 5, 3,
+ 2, 1, 1, 4, 4, 5, 7, 7, 8, 8, 3, 4, 5, 6, 7, 6, 7, 3, 4,
+ 5, 5, 5, 4, 5, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 1, 0, 3,
+ 7, 6, 5, 4, 2, 1, 3, 13, 10, 7, 5, 4, 2, 3, 3, 4, 6, 7, 8,
+ 10, 10, 2, 3, 6, 7, 8, 8, 9, 3, 3, 6, 6, 6, 7, 8, 6, 2, 4,
+ 5, 5, 6, 7, 8, 4, 6, 7, 7, 7, 7, 12, 8, 10, 10, 9, 8, 7, 15,
+ 13, 13, 12, 10, 10, 8, 2, 7, 10, 11, 11, 12, 13, 6, 8, 10, 11, 12, 12,
+ 13, 10, 8, 11, 11, 12, 12, 12, 12, 8, 11, 12, 12, 12, 11, 12, 12, 14, 15,
+ 16, 14, 14, 12, 18, 20, 19, 17, 17, 15, 15, 23, 22, 21, 19, 18, 16, 14, 17,
+ 18, 18, 19, 18, 14, 15, 19, 19, 19, 19, 19, 13, 16, 19, 20, 20, 20, 19, 15,
+ 16, 21, 22, 21, 21, 20, 16, 16, 24, 25, 24, 24, 22, 17, 19, 27, 30, 29, 27,
+ 24, 19, 24, 32, 34, 31, 29, 26, 20, 26, 29, 28, 28, 25, 21, 16, 26, 31, 29,
+ 30, 26, 21, 16, 25, 32, 32, 30, 26, 21, 17, 26, 31, 33, 32, 27, 23, 19, 25,
+ 32, 37, 35, 31, 26, 20, 28, 34, 41, 39, 34, 27, 23, 32, 36, 42, 42, 36, 30,
+ 24, 35, 41, 39, 33, 28, 24, 19, 35, 41, 42, 35, 29, 24, 19, 35, 42, 45, 36,
+ 30, 24, 19, 35, 40, 46, 38, 31, 26, 22, 33, 40, 46, 43, 37, 29, 24, 35, 43,
+ 47, 47, 39, 32, 26, 39, 45, 49, 48, 41, 34, 29, 4, 5, 6, 8, 8, 7, 8,
+ 4, 5, 6, 7, 7, 6, 6, 3, 5, 6, 6, 5, 4, 4, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 0, 2, 1, 2, 5, 4, 4, 3, 2, 1, 2, 9, 7, 5,
+ 3, 2, 1, 2, 4, 5, 5, 7, 8, 10, 10, 3, 4, 5, 6, 7, 8, 8, 3,
+ 4, 5, 5, 5, 6, 6, 3, 2, 3, 3, 3, 4, 5, 4, 2, 2, 2, 3, 3,
+ 5, 8, 6, 5, 5, 5, 4, 5, 12, 9, 6, 5, 6, 5, 5, 3, 4, 7, 9,
+ 10, 12, 13, 3, 3, 7, 9, 9, 10, 11, 6, 3, 6, 8, 8, 8, 10, 9, 2,
+ 5, 7, 8, 8, 9, 11, 4, 7, 10, 10, 10, 9, 14, 8, 10, 12, 12, 11, 9,
+ 14, 11, 11, 14, 13, 12, 11, 6, 8, 12, 13, 14, 14, 16, 10, 9, 13, 14, 15,
+ 15, 16, 13, 9, 13, 14, 15, 15, 15, 15, 9, 13, 15, 15, 16, 14, 15, 13, 16,
+ 18, 18, 18, 17, 14, 18, 21, 21, 20, 19, 18, 14, 21, 23, 23, 22, 21, 20, 16,
+ 19, 20, 21, 22, 22, 16, 18, 20, 22, 23, 23, 22, 16, 18, 21, 23, 23, 24, 22,
+ 18, 18, 23, 24, 24, 25, 23, 19, 18, 27, 28, 27, 27, 25, 20, 21, 30, 33, 31,
+ 30, 27, 22, 24, 31, 35, 33, 32, 29, 23, 27, 32, 31, 31, 28, 24, 20, 28, 34,
+ 32, 33, 29, 24, 20, 27, 35, 36, 34, 29, 25, 20, 28, 35, 37, 36, 31, 27, 22,
+ 27, 34, 40, 39, 35, 29, 23, 31, 38, 44, 43, 37, 31, 25, 34, 39, 45, 46, 40,
+ 33, 27, 38, 45, 43, 37, 31, 26, 22, 39, 44, 46, 39, 33, 27, 23, 39, 45, 47,
+ 40, 33, 28, 23, 39, 45, 49, 41, 35, 30, 26, 37, 43, 49, 46, 39, 33, 27, 38,
+ 45, 51, 50, 43, 35, 29, 41, 46, 51, 51, 44, 38, 31, 5, 5, 6, 7, 7, 9,
+ 10, 5, 5, 6, 7, 7, 7, 8, 4, 5, 6, 5, 5, 5, 6, 4, 3, 3, 3,
+ 3, 3, 4, 3, 3, 2, 2, 0, 1, 4, 4, 3, 3, 2, 1, 1, 4, 6, 5,
+ 3, 2, 2, 2, 4, 4, 5, 6, 7, 9, 11, 12, 4, 5, 5, 7, 9, 10, 10,
+ 4, 4, 5, 5, 7, 8, 9, 5, 3, 3, 3, 5, 6, 7, 6, 3, 2, 3, 6,
+ 5, 7, 8, 4, 4, 4, 7, 7, 7, 10, 7, 4, 4, 8, 8, 7, 3, 5, 8,
+ 11, 12, 14, 15, 5, 4, 7, 11, 12, 12, 14, 8, 4, 7, 10, 11, 11, 13, 12,
+ 3, 5, 10, 11, 12, 11, 13, 4, 7, 12, 13, 13, 12, 14, 6, 8, 12, 14, 14,
+ 12, 14, 9, 9, 13, 16, 16, 15, 8, 9, 14, 17, 18, 17, 20, 12, 10, 15, 17,
+ 19, 19, 19, 15, 10, 16, 18, 19, 19, 18, 17, 10, 15, 18, 18, 19, 17, 16, 14,
+ 17, 20, 21, 21, 20, 15, 16, 20, 22, 23, 23, 22, 14, 18, 21, 23, 24, 24, 24,
+ 19, 21, 24, 25, 26, 26, 19, 21, 22, 25, 26, 28, 26, 19, 21, 24, 26, 28, 27,
+ 25, 21, 21, 25, 26, 27, 28, 27, 22, 20, 28, 30, 30, 31, 29, 24, 21, 29, 34,
+ 33, 32, 30, 25, 21, 30, 37, 35, 34, 33, 27, 30, 34, 35, 34, 32, 28, 24, 30,
+ 37, 37, 37, 33, 28, 24, 30, 39, 39, 37, 33, 29, 25, 31, 38, 40, 39, 35, 30,
+ 25, 30, 39, 43, 41, 36, 32, 27, 31, 40, 47, 44, 39, 33, 29, 32, 41, 45, 47,
+ 41, 36, 31, 42, 48, 47, 40, 35, 31, 26, 43, 49, 49, 42, 36, 32, 27, 42, 48,
+ 51, 44, 37, 32, 27, 43, 48, 53, 44, 39, 33, 29, 41, 47, 53, 49, 41, 35, 31,
+ 42, 48, 52, 50, 44, 38, 32, 43, 48, 53, 53, 46, 40, 33, 4, 5, 5, 6, 6,
+ 8, 8, 4, 5, 5, 6, 6, 6, 6, 3, 4, 5, 4, 4, 4, 4, 3, 3, 3,
+ 2, 3, 2, 3, 2, 2, 1, 1, 1, 0, 2, 3, 2, 2, 2, 1, 0, 2, 5,
+ 3, 2, 1, 1, 0, 2, 4, 4, 5, 6, 8, 10, 10, 3, 4, 5, 6, 7, 8,
+ 9, 3, 3, 4, 4, 5, 6, 7, 4, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2,
+ 4, 3, 5, 7, 3, 2, 2, 5, 5, 5, 9, 5, 3, 2, 6, 6, 5, 3, 4,
+ 7, 9, 11, 12, 14, 5, 3, 7, 10, 10, 10, 12, 9, 3, 6, 9, 9, 9, 10,
+ 13, 2, 5, 8, 9, 10, 9, 13, 3, 5, 9, 10, 11, 9, 16, 5, 6, 10, 12,
+ 12, 9, 14, 8, 7, 11, 13, 13, 13, 9, 8, 13, 15, 16, 15, 17, 13, 8, 13,
+ 16, 16, 17, 17, 16, 8, 13, 16, 17, 16, 16, 18, 9, 14, 16, 17, 17, 14, 18,
+ 12, 15, 18, 19, 18, 17, 15, 13, 17, 19, 20, 20, 20, 14, 16, 19, 21, 21, 21,
+ 21, 16, 19, 22, 23, 24, 24, 18, 20, 20, 22, 24, 25, 23, 17, 20, 21, 25, 25,
+ 25, 24, 19, 20, 24, 25, 26, 26, 24, 20, 18, 25, 27, 28, 28, 25, 21, 18, 26,
+ 30, 30, 29, 27, 23, 18, 27, 32, 32, 31, 30, 25, 29, 33, 33, 32, 30, 26, 21,
+ 28, 35, 34, 34, 31, 26, 21, 29, 38, 37, 35, 31, 27, 22, 28, 36, 38, 37, 32,
+ 28, 23, 28, 36, 41, 39, 34, 29, 25, 29, 36, 42, 42, 35, 30, 26, 30, 37, 43,
+ 43, 38, 33, 27, 40, 47, 45, 37, 33, 28, 24, 40, 45, 46, 40, 34, 29, 25, 41,
+ 46, 49, 41, 34, 29, 25, 40, 45, 50, 42, 36, 31, 26, 39, 44, 49, 46, 38, 33,
+ 28, 39, 45, 50, 47, 40, 34, 30, 39, 46, 50, 49, 43, 36, 30, 4, 5, 6, 8,
+ 8, 6, 6, 4, 4, 5, 7, 7, 5, 4, 3, 4, 5, 5, 6, 4, 2, 3, 3,
+ 3, 3, 5, 3, 0, 2, 1, 1, 2, 4, 2, 0, 2, 2, 2, 2, 3, 2, 0,
+ 4, 3, 2, 2, 3, 2, 0, 4, 4, 5, 6, 6, 8, 8, 3, 4, 5, 5, 6,
+ 6, 6, 3, 4, 4, 4, 4, 4, 5, 2, 2, 2, 2, 2, 2, 3, 2, 2, 1,
+ 1, 1, 1, 3, 4, 2, 2, 2, 2, 2, 3, 7, 5, 2, 2, 3, 3, 3, 3,
+ 4, 6, 8, 9, 10, 11, 2, 3, 6, 8, 8, 8, 9, 5, 3, 6, 7, 7, 7,
+ 8, 9, 2, 4, 7, 6, 7, 6, 11, 2, 4, 7, 8, 8, 6, 13, 4, 5, 8,
+ 9, 9, 6, 10, 8, 6, 9, 10, 10, 10, 5, 7, 11, 12, 13, 13, 14, 10, 7,
+ 11, 13, 14, 14, 13, 13, 8, 12, 13, 14, 13, 12, 15, 7, 12, 14, 14, 14, 11,
+ 16, 10, 13, 15, 15, 15, 14, 12, 12, 15, 16, 17, 17, 16, 10, 15, 17, 18, 18,
+ 18, 18, 15, 17, 20, 20, 21, 20, 14, 18, 18, 21, 21, 22, 20, 13, 18, 19, 21,
+ 22, 22, 20, 17, 17, 21, 23, 23, 23, 21, 16, 16, 22, 25, 25, 25, 23, 18, 16,
+ 24, 27, 27, 25, 24, 20, 17, 25, 30, 28, 28, 26, 21, 25, 29, 30, 30, 26, 23,
+ 18, 27, 32, 32, 30, 27, 23, 18, 27, 34, 34, 33, 28, 23, 19, 27, 33, 34, 32,
+ 29, 25, 20, 26, 33, 37, 34, 30, 26, 21, 27, 33, 41, 38, 32, 28, 23, 27, 34,
+ 39, 41, 35, 29, 24, 36, 42, 39, 34, 29, 25, 21, 37, 43, 42, 36, 31, 26, 22,
+ 37, 43, 45, 38, 31, 26, 22, 38, 42, 47, 39, 32, 28, 23, 37, 40, 45, 42, 34,
+ 29, 24, 35, 41, 46, 44, 36, 30, 26, 36, 42, 46, 45, 40, 33, 27, 8, 9, 10,
+ 12, 12, 11, 10, 8, 9, 10, 12, 12, 10, 9, 7, 8, 9, 10, 11, 8, 7, 7,
+ 7, 7, 8, 8, 6, 3, 4, 4, 4, 5, 4, 3, 2, 0, 2, 2, 2, 3, 3,
+ 2, 6, 5, 2, 2, 2, 3, 2, 7, 8, 10, 11, 11, 11, 10, 7, 8, 9, 10,
+ 10, 10, 9, 6, 7, 9, 9, 9, 8, 7, 6, 6, 6, 7, 6, 5, 2, 3, 3,
+ 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, 7, 4, 2, 1, 2, 2,
+ 6, 8, 9, 9, 10, 11, 10, 6, 7, 8, 9, 9, 9, 9, 5, 6, 7, 7, 8,
+ 8, 7, 5, 5, 5, 5, 5, 5, 3, 2, 1, 1, 2, 2, 2, 3, 5, 4, 3,
+ 2, 0, 2, 3, 11, 10, 6, 4, 2, 2, 3, 6, 7, 8, 9, 11, 12, 11, 5,
+ 7, 8, 10, 10, 10, 10, 4, 7, 8, 8, 8, 9, 8, 5, 6, 5, 6, 6, 6,
+ 6, 3, 6, 6, 6, 7, 7, 7, 5, 11, 10, 9, 8, 8, 8, 11, 16, 13, 12,
+ 10, 9, 10, 9, 10, 11, 11, 12, 12, 12, 11, 12, 12, 12, 13, 12, 10, 11, 13,
+ 14, 13, 13, 12, 8, 11, 15, 14, 14, 14, 13, 9, 11, 16, 16, 15, 15, 15, 10,
+ 12, 18, 21, 20, 18, 16, 11, 17, 21, 24, 21, 20, 18, 13, 18, 20, 20, 21, 18,
+ 14, 11, 19, 23, 23, 22, 19, 14, 10, 19, 24, 25, 24, 20, 15, 10, 18, 24, 25,
+ 26, 22, 16, 11, 18, 24, 27, 27, 23, 17, 13, 19, 24, 30, 29, 24, 20, 15, 21,
+ 27, 31, 31, 27, 21, 16, 27, 33, 33, 26, 21, 16, 12, 27, 33, 35, 27, 22, 17,
+ 13, 27, 33, 36, 29, 23, 18, 13, 28, 33, 37, 30, 25, 19, 15, 26, 33, 36, 33,
+ 26, 22, 16, 27, 32, 35, 34, 28, 23, 19, 28, 31, 36, 36, 31, 25, 20, 8, 9,
+ 10, 11, 11, 11, 10, 7, 8, 10, 11, 11, 10, 8, 7, 8, 9, 10, 9, 8, 6,
+ 6, 6, 7, 7, 7, 5, 2, 4, 4, 4, 4, 4, 2, 2, 2, 0, 2, 2, 2,
+ 2, 2, 6, 4, 2, 2, 2, 2, 2, 7, 8, 9, 11, 11, 11, 11, 6, 8, 9,
+ 10, 11, 9, 9, 6, 7, 8, 9, 8, 7, 6, 6, 5, 6, 6, 6, 5, 2, 3,
+ 3, 3, 3, 2, 2, 2, 3, 2, 2, 2, 1, 2, 2, 9, 7, 3, 2, 1, 2,
+ 2, 6, 7, 8, 9, 11, 11, 12, 6, 6, 8, 9, 10, 10, 10, 6, 6, 8, 8,
+ 8, 8, 8, 5, 5, 6, 6, 5, 5, 5, 3, 2, 3, 3, 3, 3, 4, 5, 5,
+ 5, 4, 3, 4, 5, 11, 9, 8, 6, 5, 5, 5, 6, 9, 9, 11, 12, 14, 13,
+ 5, 8, 10, 11, 12, 12, 11, 5, 8, 9, 9, 9, 10, 9, 8, 7, 8, 8, 8,
+ 9, 8, 6, 8, 9, 9, 10, 10, 10, 6, 13, 13, 12, 11, 11, 11, 11, 18, 16,
+ 14, 12, 12, 13, 12, 13, 14, 14, 15, 15, 13, 12, 15, 15, 16, 16, 14, 11, 13,
+ 16, 17, 16, 16, 15, 11, 13, 17, 17, 16, 17, 16, 12, 12, 19, 19, 18, 18, 17,
+ 13, 14, 22, 23, 21, 20, 18, 14, 19, 24, 26, 24, 22, 20, 16, 22, 24, 24, 24,
+ 21, 17, 13, 22, 26, 25, 25, 22, 17, 12, 22, 28, 28, 27, 22, 17, 13, 22, 27,
+ 29, 27, 24, 19, 14, 22, 27, 30, 30, 25, 20, 16, 21, 28, 34, 33, 27, 21, 17,
+ 25, 30, 34, 35, 30, 24, 18, 31, 37, 36, 29, 23, 19, 15, 30, 36, 39, 32, 25,
+ 20, 16, 30, 37, 40, 32, 26, 21, 17, 31, 35, 41, 33, 27, 22, 17, 29, 35, 41,
+ 36, 29, 23, 19, 29, 35, 41, 38, 32, 26, 20, 30, 37, 40, 42, 34, 27, 22, 8,
+ 9, 10, 12, 11, 11, 10, 7, 8, 10, 11, 11, 9, 8, 7, 8, 9, 9, 9, 7,
+ 6, 6, 6, 7, 7, 7, 5, 2, 4, 4, 3, 4, 3, 2, 2, 2, 2, 0, 2,
+ 2, 2, 2, 5, 3, 2, 1, 2, 2, 2, 7, 8, 9, 10, 11, 11, 12, 7, 8,
+ 9, 10, 11, 10, 10, 6, 7, 8, 8, 8, 7, 7, 6, 6, 6, 6, 5, 4, 4,
+ 3, 3, 3, 3, 2, 2, 4, 3, 2, 2, 1, 2, 2, 3, 7, 5, 3, 1, 1,
+ 2, 3, 6, 7, 9, 11, 12, 14, 14, 6, 7, 10, 11, 12, 12, 12, 6, 7, 9,
+ 10, 9, 9, 9, 5, 5, 7, 7, 7, 7, 6, 6, 2, 4, 5, 5, 5, 6, 8,
+ 4, 7, 7, 6, 6, 6, 8, 7, 8, 9, 7, 7, 8, 6, 10, 11, 12, 14, 15,
+ 15, 5, 9, 11, 12, 13, 13, 13, 8, 9, 11, 11, 12, 11, 11, 10, 8, 11, 11,
+ 11, 12, 10, 9, 9, 11, 12, 12, 12, 13, 8, 13, 15, 15, 14, 14, 14, 8, 16,
+ 17, 16, 15, 15, 15, 13, 16, 17, 17, 18, 18, 15, 15, 17, 18, 18, 19, 17, 13,
+ 15, 18, 20, 19, 19, 18, 14, 15, 20, 20, 20, 20, 19, 14, 13, 22, 22, 21, 21,
+ 20, 15, 16, 24, 26, 24, 23, 21, 17, 18, 25, 28, 27, 25, 23, 19, 24, 27, 27,
+ 27, 24, 20, 16, 26, 29, 29, 29, 25, 21, 16, 25, 31, 31, 30, 25, 21, 17, 24,
+ 31, 32, 30, 26, 22, 17, 24, 30, 34, 32, 28, 23, 18, 24, 31, 36, 36, 30, 24,
+ 20, 27, 33, 38, 39, 33, 27, 21, 35, 39, 39, 32, 27, 22, 18, 34, 41, 42, 34,
+ 28, 23, 19, 35, 41, 44, 36, 29, 24, 19, 34, 40, 44, 37, 30, 25, 21, 33, 39,
+ 44, 39, 32, 26, 22, 32, 39, 43, 43, 34, 29, 23, 34, 40, 45, 45, 39, 30, 25,
+ 7, 8, 9, 10, 10, 10, 11, 7, 7, 8, 10, 10, 9, 8, 6, 7, 8, 9, 8,
+ 7, 6, 6, 6, 6, 6, 6, 4, 3, 3, 3, 3, 3, 2, 1, 2, 2, 2, 2,
+ 0, 2, 2, 2, 4, 3, 2, 1, 1, 1, 2, 7, 7, 8, 9, 10, 12, 13, 6,
+ 7, 8, 9, 10, 10, 11, 6, 7, 7, 7, 8, 8, 8, 5, 5, 5, 5, 5, 5,
+ 5, 3, 2, 2, 2, 2, 3, 5, 3, 2, 2, 2, 2, 3, 4, 6, 4, 2, 2,
+ 3, 3, 4, 6, 7, 10, 11, 13, 14, 15, 5, 6, 9, 12, 12, 12, 12, 4, 6,
+ 9, 10, 10, 10, 10, 8, 4, 6, 8, 8, 8, 8, 10, 2, 4, 7, 8, 8, 8,
+ 11, 3, 5, 8, 9, 9, 8, 10, 7, 6, 10, 10, 10, 11, 5, 10, 13, 13, 15,
+ 15, 17, 8, 9, 12, 14, 14, 14, 15, 11, 9, 13, 13, 14, 14, 14, 13, 8, 13,
+ 14, 14, 15, 13, 13, 10, 14, 15, 16, 16, 16, 11, 12, 16, 16, 17, 16, 17, 10,
+ 15, 17, 18, 18, 18, 18, 15, 18, 20, 20, 22, 21, 17, 17, 20, 22, 22, 22, 21,
+ 15, 17, 20, 23, 22, 22, 22, 17, 17, 22, 23, 23, 23, 22, 17, 16, 24, 25, 25,
+ 25, 23, 19, 16, 25, 28, 27, 26, 24, 20, 17, 26, 30, 28, 29, 26, 22, 27, 31,
+ 31, 31, 27, 24, 19, 27, 32, 33, 33, 28, 24, 19, 27, 35, 35, 34, 29, 24, 20,
+ 27, 33, 35, 34, 29, 25, 21, 26, 33, 38, 36, 31, 26, 22, 27, 32, 39, 39, 33,
+ 27, 23, 28, 34, 39, 40, 35, 30, 25, 38, 44, 42, 36, 31, 26, 21, 38, 45, 45,
+ 38, 31, 27, 22, 37, 44, 47, 39, 32, 27, 22, 38, 43, 48, 40, 34, 28, 23, 37,
+ 42, 48, 43, 35, 30, 25, 36, 43, 47, 45, 37, 32, 27, 37, 42, 47, 47, 41, 33,
+ 28, 6, 6, 7, 8, 8, 9, 10, 5, 6, 7, 8, 8, 8, 8, 5, 6, 6, 6,
+ 6, 6, 6, 4, 4, 4, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 3, 3, 2,
+ 2, 2, 0, 1, 3, 5, 4, 2, 2, 1, 1, 3, 5, 6, 7, 8, 10, 12, 13,
+ 5, 5, 6, 8, 10, 10, 10, 4, 5, 6, 6, 7, 8, 8, 4, 3, 3, 4, 5,
+ 6, 7, 5, 3, 2, 2, 4, 4, 7, 6, 3, 3, 2, 5, 5, 7, 8, 5, 3,
+ 3, 6, 6, 7, 4, 5, 8, 11, 13, 14, 15, 4, 4, 8, 11, 12, 12, 14, 8,
+ 4, 8, 10, 10, 11, 12, 11, 3, 5, 9, 10, 11, 11, 12, 3, 5, 10, 11, 12,
+ 11, 13, 4, 7, 11, 13, 13, 11, 12, 8, 7, 12, 13, 14, 14, 8, 9, 14, 16,
+ 17, 17, 19, 11, 9, 14, 17, 18, 17, 18, 14, 9, 15, 17, 18, 18, 17, 16, 10,
+ 14, 17, 18, 19, 16, 16, 12, 16, 18, 20, 19, 19, 14, 14, 18, 20, 21, 21, 21,
+ 12, 16, 20, 22, 22, 22, 22, 17, 21, 23, 24, 25, 25, 19, 20, 21, 24, 25, 26,
+ 25, 18, 20, 22, 26, 26, 27, 25, 21, 20, 25, 26, 27, 27, 26, 21, 18, 26, 28,
+ 29, 29, 27, 22, 18, 27, 31, 32, 30, 29, 24, 19, 29, 33, 33, 33, 30, 25, 30,
+ 33, 34, 34, 31, 27, 23, 30, 37, 36, 35, 32, 27, 23, 30, 38, 38, 37, 33, 28,
+ 23, 30, 38, 39, 37, 33, 29, 24, 28, 37, 42, 39, 35, 30, 25, 30, 37, 44, 42,
+ 36, 32, 27, 31, 38, 43, 44, 38, 33, 29, 42, 48, 45, 40, 34, 30, 26, 41, 48,
+ 48, 41, 35, 30, 26, 42, 47, 50, 42, 36, 31, 27, 41, 47, 51, 44, 37, 32, 27,
+ 40, 45, 51, 46, 39, 34, 29, 40, 46, 50, 49, 42, 36, 30, 40, 46, 51, 51, 44,
+ 37, 32, 4, 5, 5, 6, 6, 8, 8, 4, 5, 5, 6, 6, 6, 6, 3, 4, 5,
+ 4, 4, 4, 4, 3, 3, 3, 2, 3, 2, 2, 2, 2, 1, 1, 2, 0, 2, 3,
+ 2, 2, 1, 2, 0, 2, 5, 3, 2, 1, 1, 0, 2, 4, 4, 5, 6, 8, 9,
+ 10, 3, 4, 5, 6, 8, 8, 8, 3, 4, 4, 4, 6, 6, 7, 4, 2, 2, 2,
+ 4, 4, 5, 6, 2, 2, 2, 4, 3, 5, 7, 3, 2, 2, 5, 5, 5, 9, 5,
+ 3, 2, 6, 6, 5, 3, 4, 7, 9, 10, 12, 14, 5, 3, 7, 10, 10, 10, 12,
+ 9, 3, 6, 8, 9, 9, 10, 13, 2, 5, 8, 9, 10, 9, 13, 3, 5, 9, 11,
+ 11, 9, 17, 5, 6, 10, 11, 12, 9, 14, 9, 7, 11, 13, 13, 13, 9, 8, 13,
+ 15, 15, 15, 17, 15, 8, 13, 16, 17, 17, 16, 16, 8, 14, 15, 16, 17, 16, 19,
+ 9, 13, 17, 17, 17, 14, 18, 12, 15, 18, 18, 19, 17, 15, 13, 17, 19, 20, 20,
+ 20, 15, 16, 19, 21, 21, 21, 22, 17, 19, 22, 23, 25, 23, 18, 20, 20, 23, 24,
+ 26, 23, 17, 20, 21, 25, 25, 26, 24, 19, 20, 23, 25, 25, 26, 24, 20, 19, 25,
+ 27, 28, 28, 26, 22, 18, 26, 30, 30, 29, 27, 23, 19, 27, 32, 32, 31, 28, 25,
+ 28, 32, 32, 33, 30, 26, 21, 29, 35, 35, 34, 31, 26, 22, 29, 37, 36, 36, 31,
+ 26, 22, 28, 36, 39, 37, 33, 28, 23, 29, 35, 40, 40, 33, 29, 24, 28, 36, 42,
+ 41, 36, 30, 26, 30, 37, 43, 44, 38, 33, 28, 40, 46, 44, 38, 32, 29, 25, 40,
+ 46, 47, 39, 33, 29, 24, 42, 45, 49, 41, 35, 30, 25, 39, 46, 50, 42, 36, 30,
+ 26, 39, 44, 49, 46, 39, 32, 28, 39, 45, 50, 48, 40, 34, 29, 39, 45, 50, 50,
+ 43, 37, 31, 4, 5, 6, 7, 7, 6, 6, 4, 4, 5, 7, 7, 5, 4, 3, 4,
+ 5, 5, 6, 4, 2, 3, 3, 3, 3, 5, 3, 0, 2, 1, 1, 2, 4, 2, 0,
+ 2, 2, 2, 2, 3, 2, 0, 4, 3, 2, 2, 3, 2, 0, 4, 4, 5, 6, 7,
+ 8, 8, 3, 4, 4, 5, 6, 6, 7, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2,
+ 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 3, 4, 2, 2, 2, 2, 2, 3, 7,
+ 5, 2, 2, 4, 3, 3, 3, 4, 6, 8, 9, 10, 11, 2, 3, 7, 8, 8, 8,
+ 9, 5, 3, 6, 7, 6, 6, 8, 9, 2, 4, 7, 6, 6, 6, 11, 2, 4, 7,
+ 8, 8, 6, 12, 4, 5, 8, 9, 9, 6, 10, 8, 6, 9, 10, 10, 10, 5, 7,
+ 11, 13, 13, 13, 14, 10, 7, 11, 13, 14, 14, 13, 13, 8, 12, 13, 14, 13, 12,
+ 15, 8, 12, 14, 14, 14, 11, 15, 10, 13, 15, 15, 15, 14, 13, 12, 15, 16, 17,
+ 16, 17, 10, 15, 17, 18, 18, 18, 18, 15, 17, 19, 20, 21, 20, 15, 18, 19, 20,
+ 21, 22, 21, 13, 18, 20, 22, 22, 22, 20, 16, 18, 22, 22, 22, 23, 22, 17, 16,
+ 23, 24, 24, 25, 23, 18, 16, 24, 27, 27, 26, 23, 20, 17, 25, 30, 28, 28, 25,
+ 21, 27, 30, 29, 30, 27, 23, 19, 27, 32, 32, 31, 27, 23, 18, 26, 34, 34, 32,
+ 27, 23, 19, 27, 33, 34, 33, 29, 24, 19, 25, 33, 37, 35, 31, 26, 21, 27, 33,
+ 40, 38, 32, 26, 22, 27, 34, 40, 40, 34, 29, 24, 37, 43, 40, 34, 29, 26, 21,
+ 37, 42, 44, 36, 31, 25, 22, 36, 41, 46, 37, 30, 26, 22, 37, 42, 47, 39, 32,
+ 28, 23, 36, 41, 46, 42, 36, 29, 24, 36, 40, 45, 44, 36, 31, 25, 35, 41, 45,
+ 46, 40, 33, 28, 14, 15, 16, 18, 18, 17, 16, 13, 15, 16, 18, 17, 16, 14, 13,
+ 14, 16, 16, 16, 13, 11, 12, 13, 13, 13, 13, 9, 5, 10, 10, 10, 9, 6, 5,
+ 5, 6, 6, 5, 4, 5, 5, 4, 0, 2, 2, 3, 4, 5, 4, 13, 14, 16, 17,
+ 17, 17, 16, 12, 14, 15, 16, 17, 16, 14, 12, 13, 15, 15, 14, 13, 11, 11, 12,
+ 12, 12, 11, 9, 4, 9, 8, 8, 8, 5, 4, 4, 5, 4, 4, 3, 3, 4, 4,
+ 3, 2, 2, 2, 3, 4, 4, 12, 13, 15, 16, 17, 17, 17, 11, 13, 14, 15, 16,
+ 15, 15, 12, 12, 13, 13, 13, 12, 11, 11, 11, 10, 10, 10, 8, 4, 7, 7, 7,
+ 7, 3, 4, 4, 2, 2, 2, 2, 3, 3, 4, 5, 4, 1, 2, 3, 4, 5, 11,
+ 13, 14, 16, 17, 18, 18, 11, 13, 14, 16, 17, 16, 16, 10, 13, 14, 14, 14, 14,
+ 12, 7, 12, 11, 11, 11, 9, 9, 4, 8, 7, 7, 5, 5, 6, 3, 6, 6, 6,
+ 7, 6, 7, 5, 11, 8, 8, 8, 8, 8, 12, 12, 14, 15, 17, 18, 19, 10, 12,
+ 14, 15, 16, 16, 16, 10, 12, 13, 13, 13, 13, 12, 10, 12, 12, 12, 12, 10, 7,
+ 8, 13, 13, 13, 14, 13, 8, 8, 14, 16, 16, 16, 15, 10, 11, 17, 19, 18, 18,
+ 17, 11, 16, 18, 18, 19, 16, 17, 18, 16, 20, 20, 21, 17, 15, 15, 16, 22, 22,
+ 21, 17, 12, 11, 16, 21, 23, 23, 19, 14, 10, 15, 20, 25, 24, 20, 17, 11, 15,
+ 22, 27, 25, 23, 18, 13, 17, 23, 27, 28, 24, 20, 15, 25, 31, 30, 24, 18, 16,
+ 17, 25, 31, 32, 26, 20, 15, 14, 25, 31, 33, 27, 21, 16, 11, 25, 30, 35, 28,
+ 23, 18, 13, 24, 30, 32, 28, 24, 21, 15, 24, 28, 31, 30, 25, 21, 17, 24, 28,
+ 31, 31, 27, 23, 19, 12, 13, 15, 16, 16, 16, 15, 12, 13, 14, 15, 15, 14, 12,
+ 11, 12, 14, 14, 13, 11, 9, 11, 11, 11, 11, 10, 7, 3, 8, 8, 8, 7, 5,
+ 3, 3, 5, 4, 3, 3, 3, 3, 3, 2, 0, 2, 2, 3, 3, 3, 11, 12, 14,
+ 15, 16, 16, 15, 11, 12, 13, 15, 15, 14, 12, 11, 12, 13, 13, 12, 11, 9, 11,
+ 10, 10, 10, 9, 7, 3, 8, 7, 7, 7, 3, 3, 3, 4, 3, 3, 2, 2, 3,
+ 3, 3, 2, 2, 2, 2, 2, 3, 10, 12, 13, 14, 15, 16, 17, 10, 11, 13, 14,
+ 14, 14, 14, 11, 11, 12, 12, 12, 11, 10, 10, 10, 10, 10, 9, 7, 5, 5, 6,
+ 7, 6, 4, 4, 5, 3, 2, 3, 3, 3, 4, 5, 3, 2, 3, 3, 3, 4, 4,
+ 11, 13, 14, 15, 17, 18, 18, 9, 13, 14, 15, 16, 16, 15, 7, 13, 14, 13, 13,
+ 13, 11, 8, 11, 11, 11, 10, 9, 9, 6, 7, 8, 8, 8, 8, 8, 3, 8, 9,
+ 9, 9, 9, 10, 3, 11, 11, 11, 10, 11, 11, 12, 13, 14, 15, 17, 18, 17, 11,
+ 13, 14, 15, 16, 16, 15, 11, 14, 15, 15, 15, 14, 11, 11, 15, 15, 15, 15, 14,
+ 10, 10, 17, 17, 16, 17, 15, 12, 11, 17, 20, 19, 18, 17, 13, 13, 18, 22, 20,
+ 21, 19, 14, 20, 22, 22, 22, 19, 18, 17, 20, 24, 23, 24, 20, 16, 15, 20, 26,
+ 26, 25, 20, 16, 12, 20, 26, 27, 25, 22, 17, 13, 19, 24, 28, 28, 24, 19, 14,
+ 19, 25, 31, 30, 25, 20, 16, 20, 25, 31, 33, 27, 22, 17, 28, 34, 33, 27, 22,
+ 18, 17, 29, 36, 36, 29, 23, 18, 14, 28, 35, 39, 30, 25, 19, 14, 29, 34, 39,
+ 31, 25, 20, 16, 27, 33, 38, 34, 28, 22, 18, 28, 33, 37, 36, 30, 25, 19, 27,
+ 34, 38, 39, 33, 26, 21, 9, 11, 12, 13, 13, 13, 12, 9, 10, 11, 13, 12, 11,
+ 9, 9, 9, 11, 11, 10, 9, 7, 8, 8, 8, 8, 8, 5, 2, 6, 6, 5, 5,
+ 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 9, 9,
+ 11, 12, 12, 13, 13, 9, 9, 10, 12, 12, 11, 11, 8, 9, 10, 10, 9, 9, 8,
+ 8, 7, 7, 7, 7, 5, 3, 5, 5, 4, 4, 2, 2, 3, 2, 2, 1, 1, 2,
+ 2, 3, 4, 2, 2, 1, 2, 2, 3, 8, 9, 11, 12, 13, 15, 15, 8, 8, 11,
+ 12, 13, 13, 13, 8, 8, 11, 11, 10, 10, 10, 6, 7, 8, 8, 8, 7, 6, 5,
+ 3, 5, 6, 4, 5, 6, 6, 2, 4, 5, 5, 5, 6, 5, 4, 5, 6, 6, 6,
+ 7, 8, 11, 12, 13, 15, 16, 16, 5, 11, 12, 14, 14, 14, 14, 7, 11, 12, 12,
+ 12, 12, 11, 10, 9, 10, 10, 10, 10, 10, 8, 7, 10, 11, 11, 12, 12, 6, 10,
+ 13, 12, 13, 13, 13, 5, 13, 14, 14, 14, 14, 15, 12, 15, 16, 16, 17, 18, 16,
+ 14, 16, 17, 18, 18, 17, 14, 13, 18, 19, 19, 19, 17, 13, 13, 19, 18, 19, 18,
+ 18, 14, 13, 20, 20, 20, 20, 19, 15, 13, 21, 22, 22, 22, 20, 16, 16, 22, 26,
+ 24, 24, 22, 18, 23, 26, 25, 25, 23, 19, 16, 24, 28, 28, 28, 24, 19, 15, 24,
+ 30, 30, 29, 24, 20, 15, 23, 29, 30, 29, 25, 21, 16, 23, 29, 33, 31, 27, 22,
+ 17, 24, 29, 35, 34, 29, 23, 19, 23, 29, 34, 36, 32, 26, 21, 33, 39, 38, 31,
+ 25, 21, 18, 33, 40, 41, 33, 27, 22, 18, 33, 39, 43, 35, 29, 22, 18, 33, 39,
+ 44, 36, 29, 24, 19, 32, 37, 43, 38, 30, 25, 20, 31, 36, 43, 41, 33, 27, 22,
+ 31, 37, 43, 42, 36, 30, 24, 7, 8, 10, 11, 11, 11, 11, 7, 8, 9, 11, 10,
+ 9, 8, 7, 8, 9, 9, 8, 7, 6, 6, 6, 6, 6, 6, 4, 2, 4, 3, 3,
+ 3, 2, 2, 2, 2, 2, 1, 1, 2, 1, 2, 3, 2, 1, 0, 2, 1, 2, 7,
+ 8, 8, 10, 11, 12, 13, 7, 7, 8, 9, 10, 10, 10, 6, 7, 8, 8, 8, 8,
+ 8, 6, 6, 5, 5, 5, 5, 4, 3, 3, 2, 3, 2, 3, 4, 3, 2, 2, 1,
+ 2, 2, 4, 6, 3, 2, 2, 2, 3, 4, 6, 7, 10, 11, 13, 14, 14, 6, 7,
+ 10, 11, 12, 12, 12, 4, 6, 9, 10, 10, 10, 9, 6, 5, 7, 8, 8, 7, 8,
+ 8, 2, 4, 7, 7, 7, 8, 9, 3, 5, 8, 8, 8, 8, 8, 6, 6, 9, 9,
+ 9, 10, 5, 10, 12, 13, 14, 15, 16, 7, 9, 12, 13, 14, 14, 14, 10, 9, 12,
+ 13, 13, 13, 13, 13, 8, 12, 13, 13, 14, 12, 12, 9, 13, 14, 15, 15, 15, 9,
+ 12, 15, 16, 16, 16, 16, 8, 15, 17, 18, 17, 16, 18, 14, 18, 19, 19, 21, 20,
+ 16, 16, 19, 20, 21, 21, 20, 14, 16, 20, 22, 22, 21, 20, 16, 16, 22, 23, 22,
+ 23, 21, 17, 15, 23, 24, 24, 23, 22, 18, 15, 23, 27, 26, 25, 24, 19, 17, 24,
+ 29, 27, 27, 26, 20, 26, 30, 29, 30, 27, 22, 18, 26, 31, 31, 31, 28, 22, 18,
+ 27, 34, 33, 33, 28, 23, 19, 26, 32, 35, 34, 29, 24, 19, 27, 33, 36, 35, 30,
+ 25, 21, 25, 33, 40, 38, 33, 26, 22, 27, 33, 40, 39, 34, 29, 24, 37, 43, 41,
+ 34, 29, 25, 21, 37, 43, 43, 37, 30, 26, 21, 36, 43, 46, 38, 32, 26, 21, 38,
+ 41, 48, 40, 33, 27, 23, 35, 41, 47, 42, 35, 29, 24, 35, 42, 47, 44, 37, 31,
+ 26, 35, 41, 47, 46, 39, 32, 27, 6, 7, 8, 9, 9, 10, 11, 6, 7, 7, 9,
+ 9, 8, 8, 5, 6, 7, 7, 7, 6, 6, 5, 5, 5, 5, 5, 3, 3, 3, 2,
+ 2, 2, 2, 1, 3, 3, 2, 2, 1, 1, 1, 3, 4, 3, 2, 2, 0, 1, 3,
+ 5, 6, 7, 8, 10, 12, 13, 5, 6, 7, 8, 10, 10, 10, 4, 6, 6, 7, 8,
+ 8, 8, 4, 4, 4, 4, 5, 6, 6, 4, 2, 2, 2, 3, 3, 6, 5, 3, 2,
+ 2, 4, 4, 6, 7, 4, 3, 2, 5, 5, 6, 5, 6, 9, 11, 12, 14, 14, 4,
+ 5, 9, 11, 12, 12, 13, 7, 5, 8, 10, 10, 10, 11, 10, 3, 6, 9, 9, 9,
+ 10, 12, 3, 5, 9, 10, 10, 10, 13, 4, 6, 10, 11, 11, 10, 11, 8, 7, 11,
+ 12, 13, 13, 6, 9, 13, 15, 16, 16, 18, 10, 9, 13, 15, 17, 17, 17, 14, 9,
+ 14, 15, 16, 17, 16, 16, 9, 14, 16, 17, 17, 15, 15, 11, 15, 17, 18, 18, 18,
+ 13, 13, 17, 19, 19, 19, 19, 12, 16, 18, 20, 20, 21, 21, 16, 19, 22, 23, 24,
+ 23, 18, 19, 20, 23, 24, 25, 23, 17, 19, 22, 25, 25, 25, 23, 19, 18, 24, 25,
+ 26, 26, 25, 20, 17, 26, 27, 27, 27, 26, 21, 17, 25, 29, 30, 29, 27, 23, 19,
+ 28, 33, 31, 30, 29, 24, 29, 32, 33, 32, 30, 25, 21, 29, 35, 35, 34, 31, 26,
+ 22, 28, 37, 36, 35, 30, 26, 22, 29, 36, 38, 37, 32, 27, 22, 28, 35, 40, 38,
+ 34, 29, 23, 29, 36, 42, 41, 36, 31, 26, 30, 36, 43, 44, 38, 32, 27, 40, 46,
+ 44, 38, 33, 28, 24, 41, 46, 47, 40, 34, 29, 24, 40, 46, 50, 41, 35, 29, 25,
+ 39, 46, 49, 42, 36, 30, 26, 39, 45, 49, 46, 38, 33, 27, 38, 45, 49, 48, 40,
+ 34, 29, 39, 45, 49, 48, 43, 36, 30, 4, 5, 5, 6, 6, 8, 8, 4, 5, 5,
+ 6, 6, 6, 6, 3, 4, 5, 4, 4, 4, 4, 3, 3, 3, 2, 3, 2, 2, 2,
+ 2, 1, 1, 2, 0, 2, 3, 2, 2, 2, 1, 0, 2, 5, 3, 2, 1, 1, 0,
+ 2, 4, 4, 5, 6, 8, 10, 10, 3, 4, 5, 6, 8, 8, 8, 3, 4, 4, 4,
+ 5, 6, 7, 4, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, 4, 3, 5, 7, 3,
+ 2, 2, 5, 4, 5, 10, 5, 3, 2, 6, 6, 5, 3, 4, 7, 9, 10, 12, 14,
+ 5, 3, 7, 10, 10, 10, 12, 9, 3, 6, 8, 9, 9, 10, 13, 2, 5, 8, 9,
+ 10, 9, 14, 3, 5, 9, 11, 10, 9, 15, 5, 6, 10, 12, 11, 9, 14, 8, 7,
+ 11, 13, 13, 13, 10, 8, 13, 15, 16, 15, 18, 14, 8, 13, 15, 17, 17, 16, 16,
+ 9, 14, 16, 16, 17, 16, 18, 9, 14, 16, 17, 17, 14, 18, 12, 15, 18, 18, 19,
+ 17, 16, 13, 17, 19, 20, 20, 19, 14, 16, 19, 20, 21, 21, 21, 17, 19, 22, 23,
+ 24, 23, 18, 19, 20, 23, 24, 26, 23, 17, 20, 21, 25, 25, 25, 24, 19, 20, 23,
+ 25, 26, 26, 24, 20, 18, 26, 28, 28, 28, 26, 21, 18, 26, 31, 31, 29, 27, 23,
+ 19, 27, 33, 32, 32, 28, 24, 28, 33, 33, 32, 30, 26, 22, 29, 34, 35, 35, 31,
+ 27, 22, 28, 38, 37, 35, 31, 26, 23, 29, 37, 37, 37, 32, 27, 23, 28, 35, 40,
+ 39, 34, 29, 24, 29, 35, 43, 41, 36, 31, 27, 29, 38, 43, 44, 38, 32, 27, 40,
+ 46, 44, 37, 32, 28, 24, 39, 45, 46, 40, 33, 29, 24, 41, 45, 49, 41, 34, 30,
+ 25, 40, 45, 50, 42, 35, 31, 26, 39, 44, 49, 45, 38, 33, 28, 39, 46, 50, 47,
+ 41, 35, 29, 40, 44, 50, 50, 43, 36, 31, 4, 5, 6, 8, 8, 6, 6, 4, 4,
+ 5, 7, 7, 5, 4, 3, 4, 5, 5, 6, 4, 2, 3, 3, 3, 4, 5, 3, 0,
+ 2, 2, 1, 2, 4, 2, 0, 2, 2, 2, 2, 3, 2, 0, 4, 3, 2, 2, 3,
+ 2, 0, 4, 4, 5, 6, 6, 8, 8, 3, 4, 4, 5, 6, 6, 7, 3, 4, 4,
+ 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 3, 4,
+ 3, 2, 2, 2, 2, 3, 7, 5, 2, 2, 3, 3, 3, 3, 4, 6, 8, 9, 10,
+ 11, 2, 3, 6, 8, 8, 8, 9, 5, 3, 6, 7, 6, 6, 8, 9, 2, 4, 7,
+ 6, 6, 6, 11, 2, 4, 7, 8, 8, 6, 12, 4, 5, 8, 9, 9, 6, 10, 8,
+ 6, 9, 10, 10, 10, 5, 7, 11, 12, 13, 13, 14, 10, 7, 12, 13, 13, 14, 13,
+ 14, 8, 12, 13, 13, 13, 12, 14, 8, 12, 14, 14, 14, 11, 15, 10, 13, 15, 15,
+ 15, 14, 14, 12, 15, 16, 17, 16, 16, 10, 15, 17, 18, 18, 18, 18, 15, 18, 19,
+ 20, 21, 20, 14, 18, 18, 20, 21, 22, 20, 13, 18, 20, 22, 22, 21, 20, 16, 18,
+ 22, 23, 22, 23, 22, 17, 16, 24, 24, 24, 24, 22, 18, 16, 24, 27, 27, 26, 24,
+ 20, 17, 25, 30, 29, 28, 26, 21, 26, 29, 30, 29, 26, 22, 18, 26, 32, 30, 30,
+ 27, 23, 19, 27, 33, 33, 32, 27, 23, 19, 26, 33, 34, 32, 28, 24, 20, 27, 34,
+ 36, 35, 31, 25, 21, 27, 34, 40, 38, 33, 27, 23, 28, 34, 39, 39, 35, 29, 24,
+ 36, 42, 40, 34, 29, 25, 21, 37, 43, 43, 36, 30, 25, 21, 36, 42, 45, 37, 32,
+ 27, 21, 37, 41, 46, 38, 32, 27, 23, 35, 40, 45, 41, 35, 28, 24, 36, 42, 46,
+ 44, 37, 32, 25, 37, 41, 46, 46, 38, 33, 27, 2, 2, 3, 3, 3, 2, 2, 1,
+ 2, 3, 3, 3, 2, 2, 0, 2, 2, 3, 3, 2, 1, 1, 2, 2, 2, 2, 2,
+ 4, 3, 3, 3, 4, 4, 3, 4, 7, 7, 7, 6, 5, 4, 4, 13, 11, 9, 7,
+ 5, 4, 4, 0, 2, 2, 3, 2, 2, 1, 1, 2, 2, 3, 2, 2, 1, 2, 1,
+ 2, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 3, 4, 4, 4, 5, 4, 4, 4,
+ 9, 9, 9, 7, 5, 4, 4, 16, 14, 10, 8, 6, 4, 4, 2, 1, 2, 1, 2,
+ 1, 4, 2, 1, 2, 1, 1, 1, 4, 2, 1, 0, 0, 1, 0, 5, 3, 2, 3,
+ 3, 3, 3, 6, 7, 6, 6, 6, 7, 6, 7, 12, 11, 11, 10, 9, 7, 7, 19,
+ 17, 14, 12, 10, 9, 8, 2, 4, 5, 5, 5, 5, 8, 3, 5, 5, 6, 6, 6,
+ 8, 7, 6, 6, 7, 7, 8, 8, 10, 9, 10, 10, 10, 11, 10, 10, 14, 14, 14,
+ 14, 14, 12, 13, 20, 19, 17, 16, 15, 14, 19, 26, 22, 20, 18, 16, 15, 12, 13,
+ 12, 13, 12, 12, 8, 13, 14, 14, 14, 14, 13, 8, 14, 16, 16, 15, 16, 15, 11,
+ 13, 20, 19, 19, 19, 18, 14, 17, 25, 24, 22, 23, 21, 16, 21, 27, 30, 26, 25,
+ 23, 17, 25, 31, 32, 29, 27, 25, 20, 21, 23, 22, 21, 18, 15, 11, 21, 26, 24,
+ 23, 20, 16, 11, 22, 27, 26, 25, 22, 18, 14, 22, 28, 30, 29, 25, 22, 18, 25,
+ 31, 35, 34, 30, 25, 20, 27, 33, 40, 38, 33, 26, 22, 31, 37, 41, 41, 35, 28,
+ 23, 29, 35, 34, 27, 22, 17, 13, 29, 35, 36, 29, 23, 19, 15, 30, 35, 38, 31,
+ 26, 21, 17, 30, 36, 41, 35, 30, 25, 21, 31, 37, 43, 40, 35, 28, 24, 34, 40,
+ 46, 45, 38, 31, 25, 37, 42, 46, 46, 39, 33, 27, 1, 2, 2, 2, 2, 2, 1,
+ 2, 1, 2, 3, 2, 2, 1, 2, 0, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2,
+ 3, 4, 4, 4, 4, 5, 5, 4, 4, 8, 8, 8, 7, 6, 4, 4, 14, 13, 9,
+ 8, 6, 4, 4, 2, 0, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2,
+ 2, 1, 2, 2, 1, 4, 2, 2, 2, 3, 2, 3, 5, 6, 5, 5, 6, 5, 4,
+ 5, 11, 10, 10, 8, 6, 5, 5, 18, 15, 11, 9, 7, 5, 5, 2, 2, 1, 1,
+ 1, 3, 6, 2, 2, 2, 2, 2, 4, 6, 3, 2, 3, 3, 4, 4, 7, 7, 3,
+ 6, 6, 7, 7, 9, 11, 7, 10, 10, 11, 9, 9, 15, 12, 14, 13, 12, 11, 9,
+ 20, 18, 17, 16, 14, 12, 12, 4, 6, 7, 8, 8, 7, 10, 7, 7, 8, 8, 9,
+ 9, 10, 11, 8, 10, 10, 11, 11, 11, 14, 10, 13, 14, 14, 14, 13, 14, 16, 18,
+ 18, 18, 17, 15, 15, 22, 23, 21, 21, 19, 18, 20, 28, 26, 24, 22, 20, 19, 15,
+ 15, 15, 15, 16, 14, 10, 17, 17, 17, 17, 17, 15, 10, 17, 19, 19, 19, 19, 18,
+ 14, 17, 22, 23, 23, 23, 22, 18, 20, 27, 28, 26, 28, 25, 20, 24, 30, 34, 32,
+ 29, 27, 21, 29, 34, 35, 33, 31, 28, 22, 25, 26, 24, 25, 21, 17, 13, 24, 29,
+ 27, 26, 23, 18, 14, 25, 31, 30, 29, 25, 22, 17, 25, 32, 34, 33, 29, 25, 22,
+ 28, 34, 38, 38, 34, 28, 23, 31, 37, 45, 42, 36, 30, 25, 34, 39, 45, 45, 38,
+ 32, 27, 33, 38, 36, 30, 25, 20, 16, 33, 39, 40, 32, 26, 21, 18, 34, 39, 43,
+ 34, 30, 26, 21, 33, 39, 46, 39, 33, 29, 25, 35, 40, 48, 44, 38, 31, 27, 38,
+ 44, 50, 48, 42, 34, 29, 40, 46, 51, 51, 44, 37, 30, 2, 1, 2, 2, 2, 2,
+ 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 3, 2, 3, 2, 3,
+ 3, 4, 5, 5, 5, 6, 5, 6, 5, 5, 10, 9, 9, 8, 7, 5, 5, 16, 13,
+ 11, 8, 7, 5, 5, 2, 2, 0, 2, 1, 2, 4, 3, 2, 1, 2, 1, 2, 5,
+ 3, 2, 1, 1, 1, 3, 6, 4, 3, 3, 3, 3, 4, 7, 8, 7, 7, 7, 7,
+ 5, 7, 12, 11, 11, 10, 9, 7, 7, 20, 16, 13, 11, 10, 9, 7, 3, 2, 4,
+ 4, 4, 5, 7, 5, 2, 4, 4, 5, 5, 8, 8, 3, 5, 7, 7, 6, 9, 11,
+ 4, 8, 10, 10, 10, 11, 15, 9, 11, 14, 14, 13, 11, 18, 14, 16, 17, 16, 15,
+ 11, 21, 19, 19, 19, 18, 16, 15, 8, 7, 10, 10, 10, 8, 11, 12, 8, 11, 11,
+ 12, 12, 12, 15, 9, 12, 14, 14, 15, 14, 17, 12, 17, 18, 18, 18, 15, 18, 17,
+ 20, 21, 22, 22, 19, 18, 24, 26, 25, 23, 23, 21, 22, 30, 28, 28, 25, 24, 23,
+ 17, 18, 19, 18, 19, 17, 12, 20, 19, 20, 19, 20, 19, 12, 20, 20, 22, 23, 23,
+ 22, 17, 20, 24, 26, 27, 27, 26, 22, 23, 29, 31, 31, 31, 29, 24, 25, 33, 36,
+ 35, 33, 30, 25, 30, 38, 40, 38, 36, 31, 27, 28, 29, 28, 27, 24, 21, 15, 27,
+ 32, 31, 30, 26, 22, 18, 27, 33, 33, 32, 30, 25, 22, 28, 35, 39, 37, 33, 29,
+ 25, 31, 38, 43, 42, 38, 32, 27, 35, 42, 48, 46, 40, 34, 28, 38, 44, 49, 49,
+ 43, 36, 30, 37, 42, 39, 34, 27, 23, 19, 37, 42, 43, 36, 30, 25, 21, 37, 42,
+ 46, 39, 33, 29, 25, 37, 44, 50, 42, 38, 32, 28, 39, 45, 52, 49, 42, 36, 31,
+ 43, 48, 54, 54, 46, 39, 33, 44, 50, 55, 55, 48, 41, 33, 2, 2, 1, 2, 2,
+ 1, 3, 3, 2, 2, 2, 1, 1, 4, 3, 2, 2, 2, 3, 3, 5, 3, 3, 4,
+ 3, 4, 5, 6, 6, 6, 7, 7, 7, 6, 6, 11, 11, 11, 10, 8, 6, 6, 17,
+ 15, 12, 10, 8, 6, 6, 3, 2, 2, 0, 1, 4, 6, 3, 2, 2, 1, 1, 4,
+ 6, 5, 3, 2, 3, 3, 5, 8, 8, 4, 4, 5, 7, 6, 9, 11, 7, 8, 9,
+ 10, 7, 9, 15, 12, 12, 12, 12, 10, 9, 21, 18, 14, 12, 13, 12, 9, 5, 3,
+ 5, 6, 6, 7, 8, 8, 3, 5, 7, 7, 6, 9, 11, 3, 5, 9, 10, 8, 11,
+ 15, 5, 9, 13, 13, 13, 13, 18, 10, 12, 17, 18, 16, 13, 21, 16, 17, 20, 19,
+ 18, 13, 24, 21, 20, 21, 21, 19, 17, 11, 8, 12, 12, 13, 10, 13, 15, 9, 12,
+ 14, 15, 14, 15, 18, 11, 14, 17, 18, 19, 16, 20, 14, 18, 20, 21, 21, 18, 21,
+ 20, 22, 24, 25, 24, 21, 22, 25, 29, 28, 26, 27, 24, 23, 31, 31, 31, 29, 29,
+ 27, 20, 19, 20, 21, 21, 20, 13, 24, 20, 21, 23, 23, 22, 14, 23, 22, 24, 26,
+ 27, 25, 20, 24, 26, 29, 30, 30, 29, 25, 24, 33, 35, 35, 35, 31, 27, 28, 37,
+ 40, 39, 37, 33, 28, 32, 40, 44, 40, 40, 37, 32, 29, 32, 31, 32, 27, 23, 18,
+ 29, 35, 33, 33, 30, 26, 22, 29, 36, 36, 37, 32, 28, 25, 29, 37, 41, 41, 37,
+ 33, 29, 33, 41, 47, 46, 42, 36, 31, 36, 45, 52, 50, 44, 38, 31, 40, 46, 53,
+ 53, 46, 40, 34, 40, 45, 43, 37, 30, 26, 22, 40, 46, 45, 38, 32, 28, 25, 39,
+ 45, 49, 43, 38, 32, 28, 39, 46, 53, 46, 41, 36, 33, 44, 49, 54, 52, 46, 40,
+ 35, 45, 52, 58, 57, 48, 43, 36, 48, 54, 60, 59, 52, 44, 38, 2, 1, 1, 3,
+ 3, 1, 2, 2, 2, 1, 2, 3, 2, 3, 2, 2, 1, 3, 4, 4, 4, 2, 3,
+ 4, 5, 6, 6, 6, 6, 7, 7, 8, 10, 8, 6, 11, 11, 11, 10, 10, 8, 7,
+ 17, 15, 13, 11, 10, 8, 7, 2, 2, 1, 1, 0, 2, 4, 2, 2, 1, 1, 1,
+ 3, 5, 5, 2, 2, 2, 3, 4, 6, 9, 3, 4, 5, 6, 5, 8, 11, 7, 8,
+ 9, 10, 6, 8, 15, 13, 13, 12, 11, 10, 8, 21, 18, 15, 13, 13, 12, 8, 5,
+ 2, 4, 5, 5, 5, 7, 10, 2, 4, 6, 7, 5, 8, 13, 2, 5, 9, 10, 6,
+ 10, 15, 5, 8, 12, 13, 12, 12, 17, 10, 12, 16, 17, 16, 12, 21, 16, 17, 19,
+ 19, 17, 12, 24, 21, 20, 21, 20, 19, 16, 13, 7, 11, 12, 11, 8, 11, 16, 9,
+ 11, 12, 14, 13, 13, 19, 11, 13, 16, 17, 17, 15, 21, 14, 17, 20, 20, 21, 17,
+ 21, 19, 22, 24, 23, 24, 21, 22, 25, 27, 28, 27, 26, 23, 24, 31, 31, 30, 28,
+ 27, 26, 21, 18, 19, 20, 20, 19, 11, 24, 19, 21, 21, 22, 22, 13, 25, 21, 23,
+ 25, 26, 24, 19, 24, 26, 27, 30, 29, 28, 24, 25, 31, 33, 34, 35, 33, 26, 27,
+ 36, 39, 38, 36, 34, 28, 32, 41, 42, 41, 39, 35, 30, 28, 30, 30, 28, 25, 22,
+ 16, 29, 33, 31, 31, 28, 24, 20, 28, 35, 34, 35, 31, 28, 24, 29, 37, 40, 39,
+ 37, 31, 28, 32, 40, 45, 45, 41, 35, 29, 36, 44, 51, 48, 42, 37, 32, 39, 48,
+ 51, 50, 45, 39, 33, 38, 43, 41, 34, 28, 24, 21, 38, 43, 43, 37, 31, 28, 24,
+ 37, 44, 46, 39, 36, 31, 28, 37, 45, 51, 45, 39, 36, 31, 41, 49, 54, 51, 45,
+ 39, 33, 44, 51, 57, 56, 47, 41, 34, 47, 52, 57, 58, 50, 43, 37, 2, 1, 3,
+ 5, 5, 3, 2, 2, 1, 3, 4, 6, 4, 3, 2, 1, 2, 5, 7, 6, 5, 2,
+ 3, 4, 6, 8, 8, 8, 5, 6, 7, 9, 11, 10, 8, 11, 11, 11, 12, 12, 10,
+ 8, 17, 15, 13, 12, 12, 10, 8, 2, 1, 2, 4, 2, 0, 2, 2, 2, 2, 3,
+ 3, 1, 4, 2, 2, 1, 4, 4, 3, 5, 5, 3, 4, 6, 6, 6, 6, 8, 7,
+ 8, 9, 9, 7, 7, 14, 13, 12, 12, 10, 8, 6, 21, 18, 15, 12, 10, 9, 7,
+ 2, 2, 3, 2, 2, 3, 5, 6, 2, 3, 3, 4, 4, 6, 10, 2, 4, 6, 7,
+ 5, 7, 13, 3, 8, 10, 10, 10, 10, 15, 9, 12, 14, 14, 13, 10, 19, 15, 17,
+ 17, 16, 15, 10, 23, 22, 19, 19, 17, 16, 14, 10, 7, 9, 9, 9, 6, 8, 14,
+ 7, 10, 10, 11, 11, 10, 16, 9, 11, 13, 14, 15, 12, 19, 12, 16, 18, 18, 18,
+ 14, 18, 17, 20, 22, 22, 21, 17, 19, 24, 25, 25, 25, 24, 21, 23, 30, 29, 28,
+ 26, 24, 23, 19, 16, 17, 17, 17, 16, 9, 23, 18, 18, 18, 20, 18, 10, 23, 20,
+ 21, 22, 23, 21, 16, 22, 24, 26, 27, 27, 26, 22, 22, 29, 31, 31, 31, 29, 23,
+ 25, 35, 37, 36, 34, 31, 25, 31, 38, 39, 37, 35, 32, 26, 27, 28, 27, 26, 23,
+ 18, 14, 28, 31, 27, 27, 25, 21, 18, 26, 32, 32, 32, 29, 25, 21, 26, 34, 37,
+ 36, 32, 29, 25, 30, 38, 43, 42, 39, 31, 28, 35, 42, 49, 46, 39, 33, 28, 39,
+ 44, 49, 49, 42, 38, 30, 35, 41, 36, 31, 25, 21, 18, 34, 39, 39, 32, 27, 25,
+ 20, 36, 40, 41, 36, 33, 29, 25, 35, 42, 47, 42, 36, 32, 29, 39, 44, 52, 49,
+ 41, 37, 31, 42, 48, 54, 52, 44, 38, 32, 45, 50, 53, 54, 47, 41, 34, 1, 4,
+ 5, 7, 7, 5, 3, 1, 3, 5, 7, 8, 6, 5, 1, 2, 5, 7, 9, 8, 6,
+ 2, 3, 6, 8, 10, 9, 8, 5, 6, 8, 10, 12, 10, 8, 10, 10, 12, 13, 12,
+ 10, 8, 16, 15, 13, 13, 13, 10, 8, 1, 2, 4, 5, 4, 2, 0, 2, 1, 4,
+ 5, 4, 3, 2, 2, 1, 3, 6, 5, 4, 4, 2, 3, 5, 7, 7, 6, 6, 6,
+ 7, 8, 10, 10, 8, 6, 12, 12, 12, 13, 10, 8, 6, 20, 17, 14, 13, 11, 9,
+ 6, 2, 1, 1, 1, 2, 2, 3, 2, 2, 1, 1, 1, 2, 4, 5, 2, 2, 3,
+ 3, 3, 5, 10, 3, 6, 7, 6, 7, 7, 12, 8, 10, 11, 11, 10, 7, 17, 14,
+ 15, 14, 12, 11, 7, 22, 20, 18, 16, 14, 13, 11, 5, 6, 6, 6, 6, 5, 7,
+ 11, 6, 7, 7, 8, 8, 7, 14, 7, 9, 10, 11, 11, 9, 16, 10, 14, 14, 14,
+ 15, 11, 16, 16, 18, 18, 18, 18, 15, 17, 23, 23, 22, 21, 19, 18, 22, 30, 26,
+ 24, 22, 21, 20, 16, 14, 14, 13, 14, 13, 7, 18, 15, 15, 15, 16, 15, 7, 18,
+ 18, 18, 19, 19, 17, 13, 19, 22, 22, 23, 23, 22, 18, 20, 27, 28, 28, 28, 25,
+ 20, 24, 31, 34, 32, 29, 26, 22, 29, 34, 37, 34, 32, 29, 23, 24, 24, 23, 23,
+ 19, 15, 11, 24, 28, 25, 24, 21, 18, 14, 24, 30, 28, 27, 26, 21, 18, 24, 31,
+ 33, 32, 29, 26, 22, 27, 34, 39, 36, 33, 29, 23, 32, 38, 44, 42, 35, 30, 25,
+ 34, 41, 45, 45, 39, 33, 26, 30, 37, 33, 27, 22, 18, 14, 32, 36, 35, 29, 24,
+ 21, 18, 32, 36, 38, 32, 28, 25, 21, 31, 37, 44, 38, 33, 29, 25, 34, 40, 46,
+ 42, 38, 32, 27, 38, 44, 48, 48, 41, 34, 29, 42, 48, 50, 50, 43, 35, 30, 2,
+ 2, 3, 4, 4, 3, 2, 2, 2, 3, 4, 4, 2, 2, 1, 2, 2, 3, 3, 2,
+ 1, 0, 2, 2, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 3, 7, 6, 7, 6,
+ 5, 3, 3, 13, 11, 9, 7, 5, 3, 3, 1, 2, 3, 3, 2, 2, 2, 0, 2,
+ 2, 3, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 3,
+ 4, 4, 4, 4, 4, 3, 3, 9, 8, 8, 7, 5, 4, 3, 16, 13, 10, 8, 6,
+ 4, 3, 1, 2, 2, 2, 2, 2, 3, 2, 2, 2, 1, 2, 1, 3, 2, 1, 1,
+ 1, 1, 1, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 5, 5, 6, 5, 5, 12,
+ 11, 10, 9, 7, 6, 5, 18, 16, 13, 11, 9, 7, 7, 2, 3, 4, 4, 4, 4,
+ 8, 2, 5, 4, 5, 5, 5, 8, 5, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9,
+ 9, 10, 9, 9, 13, 13, 13, 13, 12, 12, 12, 18, 17, 16, 15, 14, 13, 18, 24,
+ 21, 19, 16, 15, 15, 11, 11, 12, 12, 12, 11, 7, 13, 13, 13, 13, 13, 12, 8,
+ 13, 15, 14, 15, 14, 13, 10, 13, 19, 18, 18, 18, 17, 14, 16, 23, 22, 21, 23,
+ 20, 15, 20, 26, 27, 26, 24, 22, 17, 24, 29, 31, 28, 26, 24, 19, 20, 22, 21,
+ 21, 18, 14, 9, 21, 24, 23, 22, 19, 15, 10, 21, 26, 25, 25, 21, 17, 13, 21,
+ 27, 29, 28, 25, 20, 17, 23, 28, 33, 32, 29, 23, 18, 26, 31, 38, 37, 32, 25,
+ 20, 29, 35, 38, 39, 34, 28, 22, 28, 35, 33, 26, 21, 17, 12, 28, 34, 35, 28,
+ 23, 18, 14, 28, 34, 38, 30, 25, 20, 16, 28, 34, 40, 35, 29, 24, 20, 30, 36,
+ 43, 39, 32, 28, 23, 32, 38, 43, 42, 36, 29, 24, 34, 40, 44, 46, 38, 32, 26,
+ 0, 2, 2, 3, 3, 2, 2, 1, 2, 2, 3, 2, 2, 1, 2, 1, 2, 2, 2,
+ 1, 2, 2, 1, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 4, 4, 8, 8, 8,
+ 7, 5, 4, 4, 14, 12, 9, 7, 6, 4, 4, 2, 1, 2, 3, 2, 2, 1, 2,
+ 0, 2, 2, 2, 1, 1, 2, 1, 2, 2, 2, 1, 3, 2, 2, 2, 2, 2, 3,
+ 4, 5, 5, 5, 5, 5, 4, 4, 10, 9, 9, 8, 6, 4, 4, 17, 15, 11, 9,
+ 7, 5, 4, 2, 1, 1, 1, 1, 2, 6, 2, 2, 1, 1, 1, 3, 6, 2, 2,
+ 2, 2, 2, 3, 7, 6, 3, 5, 5, 5, 6, 8, 9, 7, 9, 9, 9, 8, 8,
+ 14, 12, 13, 12, 11, 10, 8, 20, 18, 16, 14, 12, 11, 10, 3, 6, 6, 6, 7,
+ 6, 9, 6, 7, 7, 8, 8, 8, 9, 9, 7, 9, 9, 10, 10, 10, 12, 10, 12,
+ 13, 13, 13, 12, 13, 15, 16, 17, 17, 16, 14, 14, 21, 21, 20, 19, 17, 16, 20,
+ 28, 24, 22, 20, 19, 18, 14, 15, 14, 14, 15, 13, 9, 16, 17, 16, 15, 16, 15,
+ 10, 16, 17, 18, 18, 18, 17, 13, 15, 22, 21, 21, 22, 20, 17, 19, 26, 27, 26,
+ 26, 23, 19, 23, 31, 32, 30, 28, 25, 20, 27, 33, 35, 31, 29, 27, 21, 24, 25,
+ 24, 24, 20, 16, 12, 23, 27, 25, 25, 22, 18, 14, 24, 30, 28, 27, 25, 20, 17,
+ 23, 30, 33, 31, 28, 24, 20, 27, 33, 38, 36, 32, 28, 22, 30, 36, 42, 41, 34,
+ 29, 24, 33, 39, 43, 42, 37, 31, 26, 32, 37, 36, 29, 23, 19, 15, 32, 37, 38,
+ 30, 25, 20, 17, 31, 36, 40, 33, 28, 23, 20, 32, 38, 44, 38, 32, 28, 24, 34,
+ 41, 46, 44, 37, 31, 25, 36, 43, 48, 49, 40, 34, 28, 39, 45, 49, 50, 42, 35,
+ 30, 2, 0, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2,
+ 2, 2, 3, 2, 2, 2, 2, 3, 3, 4, 5, 5, 5, 5, 5, 5, 4, 9, 9,
+ 9, 8, 6, 5, 4, 15, 13, 10, 8, 7, 5, 4, 2, 2, 1, 2, 1, 1, 4,
+ 2, 2, 0, 2, 1, 1, 4, 2, 2, 1, 1, 1, 2, 5, 3, 3, 3, 3, 3,
+ 4, 6, 7, 6, 6, 6, 6, 4, 6, 11, 11, 11, 9, 7, 6, 6, 19, 16, 12,
+ 10, 9, 7, 6, 3, 2, 3, 3, 3, 5, 7, 3, 2, 3, 4, 4, 5, 7, 7,
+ 2, 4, 6, 6, 5, 8, 10, 3, 7, 9, 9, 9, 10, 13, 8, 11, 12, 13, 12,
+ 10, 17, 13, 15, 16, 15, 13, 10, 21, 19, 18, 17, 16, 15, 14, 7, 7, 9, 9,
+ 10, 8, 11, 11, 8, 10, 10, 11, 11, 11, 13, 8, 11, 12, 13, 13, 12, 16, 11,
+ 15, 16, 16, 17, 14, 17, 17, 20, 20, 20, 19, 18, 18, 23, 24, 24, 23, 21, 20,
+ 21, 30, 27, 25, 24, 22, 22, 17, 17, 17, 17, 18, 16, 11, 19, 18, 18, 18, 18,
+ 18, 11, 19, 20, 21, 21, 22, 20, 16, 19, 23, 25, 25, 25, 24, 20, 21, 30, 30,
+ 29, 29, 26, 22, 25, 34, 35, 34, 31, 29, 24, 30, 36, 39, 35, 34, 31, 26, 26,
+ 28, 27, 27, 23, 19, 15, 26, 31, 29, 28, 25, 21, 17, 26, 32, 32, 31, 28, 24,
+ 20, 26, 34, 37, 35, 31, 28, 23, 30, 36, 41, 40, 36, 30, 26, 33, 41, 46, 45,
+ 38, 32, 27, 37, 42, 48, 48, 41, 35, 28, 35, 41, 39, 32, 26, 22, 18, 35, 41,
+ 42, 34, 29, 24, 20, 36, 42, 45, 37, 33, 27, 23, 36, 42, 49, 41, 37, 31, 27,
+ 38, 45, 50, 47, 42, 35, 29, 41, 48, 53, 52, 44, 37, 31, 44, 50, 53, 54, 46,
+ 40, 32, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 3, 3, 2, 1,
+ 2, 3, 3, 4, 3, 3, 3, 3, 4, 5, 5, 6, 6, 7, 6, 7, 6, 5, 10,
+ 10, 10, 9, 8, 6, 5, 17, 15, 12, 10, 8, 6, 5, 3, 2, 2, 1, 1, 3,
+ 5, 3, 2, 2, 0, 1, 3, 6, 3, 2, 2, 2, 2, 4, 7, 6, 4, 4, 5,
+ 5, 5, 8, 10, 7, 8, 8, 9, 6, 8, 14, 12, 12, 11, 10, 9, 8, 20, 17,
+ 14, 12, 12, 11, 8, 3, 2, 4, 5, 5, 6, 8, 7, 3, 4, 6, 6, 6, 9,
+ 10, 3, 5, 8, 9, 7, 10, 14, 5, 9, 12, 12, 12, 12, 16, 9, 12, 15, 16,
+ 15, 12, 20, 15, 16, 19, 18, 17, 12, 23, 21, 20, 21, 19, 18, 16, 10, 7, 11,
+ 12, 12, 9, 13, 14, 8, 12, 13, 14, 13, 13, 17, 10, 13, 16, 16, 17, 15, 19,
+ 13, 17, 20, 20, 20, 17, 20, 18, 22, 24, 24, 23, 20, 20, 24, 26, 28, 26, 25,
+ 23, 23, 30, 30, 29, 27, 26, 25, 19, 19, 20, 20, 20, 19, 13, 23, 20, 21, 22,
+ 22, 21, 13, 22, 22, 23, 25, 26, 24, 19, 22, 26, 28, 28, 29, 28, 24, 24, 32,
+ 33, 33, 33, 31, 25, 27, 37, 39, 38, 35, 32, 27, 31, 40, 42, 39, 39, 35, 29,
+ 28, 31, 30, 29, 27, 22, 17, 29, 33, 32, 31, 28, 24, 20, 28, 35, 34, 35, 32,
+ 27, 23, 28, 37, 40, 39, 36, 31, 27, 32, 41, 46, 44, 41, 34, 29, 36, 43, 50,
+ 49, 42, 37, 32, 40, 47, 51, 51, 45, 38, 32, 38, 44, 41, 35, 28, 25, 20, 38,
+ 44, 44, 37, 32, 28, 24, 39, 44, 47, 41, 36, 31, 27, 38, 45, 52, 46, 40, 36,
+ 31, 41, 48, 55, 52, 44, 39, 34, 45, 51, 57, 56, 47, 40, 35, 48, 53, 56, 58,
+ 51, 43, 37, 2, 1, 1, 3, 3, 1, 2, 2, 1, 1, 2, 3, 2, 3, 2, 2,
+ 1, 3, 4, 4, 4, 2, 3, 3, 4, 6, 6, 6, 5, 6, 7, 7, 9, 8, 6,
+ 11, 11, 11, 10, 10, 8, 6, 17, 15, 12, 10, 9, 8, 6, 2, 2, 1, 1, 1,
+ 3, 4, 2, 2, 1, 1, 0, 3, 5, 4, 2, 1, 2, 2, 4, 6, 8, 3, 4,
+ 5, 5, 5, 7, 10, 7, 8, 9, 9, 6, 7, 14, 12, 12, 12, 11, 9, 7, 21,
+ 17, 14, 12, 12, 11, 7, 4, 2, 4, 5, 5, 6, 8, 9, 2, 4, 6, 6, 5,
+ 8, 13, 2, 5, 8, 9, 6, 10, 15, 5, 8, 12, 12, 12, 12, 17, 10, 12, 16,
+ 17, 16, 12, 21, 15, 17, 19, 19, 17, 12, 24, 21, 19, 20, 19, 18, 16, 13, 7,
+ 11, 12, 11, 9, 12, 16, 8, 11, 12, 14, 13, 13, 19, 11, 12, 15, 17, 17, 14,
+ 21, 14, 17, 20, 20, 20, 16, 20, 19, 22, 23, 25, 24, 19, 22, 25, 27, 27, 27,
+ 25, 24, 23, 31, 30, 30, 28, 27, 26, 21, 17, 19, 20, 20, 19, 12, 24, 19, 21,
+ 21, 22, 21, 13, 24, 21, 23, 24, 25, 24, 18, 24, 26, 27, 28, 30, 28, 24, 25,
+ 32, 32, 34, 33, 32, 25, 27, 34, 39, 38, 36, 33, 27, 32, 39, 43, 39, 38, 36,
+ 29, 28, 29, 29, 29, 26, 22, 16, 28, 33, 31, 31, 27, 24, 20, 28, 36, 35, 33,
+ 31, 27, 24, 28, 37, 39, 38, 35, 31, 27, 32, 39, 45, 44, 40, 34, 30, 35, 43,
+ 51, 47, 41, 36, 31, 39, 48, 52, 52, 45, 38, 33, 38, 43, 40, 34, 29, 24, 21,
+ 38, 43, 43, 37, 32, 27, 24, 37, 43, 46, 40, 36, 32, 27, 37, 44, 50, 44, 40,
+ 34, 31, 41, 48, 53, 51, 43, 39, 33, 45, 51, 55, 56, 48, 40, 34, 47, 53, 55,
+ 57, 51, 41, 37, 1, 1, 4, 6, 5, 4, 2, 1, 1, 3, 5, 5, 3, 2, 2,
+ 1, 2, 4, 6, 5, 4, 2, 2, 3, 5, 7, 6, 6, 5, 5, 6, 8, 10, 8,
+ 6, 10, 9, 9, 10, 10, 8, 6, 15, 14, 11, 10, 10, 8, 6, 2, 1, 2, 4,
+ 3, 1, 3, 2, 1, 1, 3, 3, 0, 3, 2, 2, 1, 3, 3, 2, 4, 4, 3,
+ 4, 5, 5, 4, 5, 7, 6, 7, 8, 7, 6, 5, 12, 11, 11, 10, 8, 6, 5,
+ 19, 16, 12, 10, 9, 8, 5, 2, 1, 3, 2, 3, 4, 6, 4, 2, 3, 3, 4,
+ 3, 5, 8, 2, 4, 6, 6, 4, 6, 13, 3, 7, 9, 9, 9, 8, 14, 8, 11,
+ 13, 13, 12, 8, 18, 14, 15, 16, 15, 13, 8, 21, 19, 18, 18, 16, 15, 13, 9,
+ 6, 9, 9, 9, 7, 10, 13, 7, 9, 10, 10, 10, 9, 16, 8, 11, 13, 13, 13,
+ 11, 18, 11, 15, 16, 17, 17, 13, 18, 17, 19, 20, 21, 19, 16, 18, 23, 25, 23,
+ 23, 21, 19, 21, 28, 27, 26, 24, 23, 22, 18, 16, 17, 16, 17, 17, 10, 21, 18,
+ 18, 18, 19, 17, 9, 21, 19, 20, 22, 21, 20, 15, 21, 23, 24, 25, 25, 24, 20,
+ 22, 29, 30, 30, 30, 27, 22, 25, 33, 35, 34, 32, 29, 24, 29, 37, 38, 35, 34,
+ 31, 26, 26, 28, 27, 26, 22, 19, 14, 26, 30, 28, 27, 25, 21, 17, 25, 32, 31,
+ 30, 28, 24, 20, 26, 34, 36, 35, 32, 28, 24, 28, 36, 41, 40, 36, 31, 26, 33,
+ 41, 47, 43, 38, 31, 27, 37, 41, 47, 47, 40, 34, 29, 35, 40, 37, 30, 26, 22,
+ 18, 34, 40, 40, 33, 27, 24, 20, 35, 40, 43, 36, 31, 27, 24, 34, 42, 46, 41,
+ 36, 32, 28, 37, 43, 48, 46, 40, 35, 30, 41, 46, 52, 51, 42, 36, 31, 44, 49,
+ 53, 52, 45, 39, 32, 1, 5, 6, 8, 8, 6, 4, 0, 3, 6, 8, 8, 5, 3,
+ 1, 2, 5, 6, 8, 6, 5, 1, 3, 5, 7, 9, 7, 6, 4, 5, 7, 8, 10,
+ 9, 6, 8, 8, 10, 11, 11, 9, 7, 14, 12, 11, 11, 10, 8, 7, 1, 2, 5,
+ 7, 5, 4, 2, 1, 1, 4, 6, 5, 3, 0, 2, 1, 3, 5, 4, 3, 2, 2,
+ 2, 4, 5, 5, 4, 4, 5, 6, 7, 8, 7, 6, 4, 11, 10, 10, 10, 8, 6,
+ 4, 17, 14, 12, 10, 8, 6, 4, 1, 1, 1, 2, 3, 3, 5, 2, 1, 0, 1,
+ 2, 2, 3, 3, 1, 2, 2, 2, 2, 4, 7, 2, 5, 5, 5, 5, 5, 11, 7,
+ 9, 9, 9, 8, 5, 15, 12, 13, 12, 11, 9, 5, 19, 17, 15, 14, 12, 10, 9,
+ 3, 5, 6, 6, 7, 6, 8, 8, 6, 7, 7, 8, 8, 7, 11, 7, 8, 9, 9,
+ 9, 8, 14, 9, 13, 13, 13, 13, 10, 15, 14, 17, 16, 17, 16, 13, 15, 20, 21,
+ 20, 19, 17, 16, 20, 26, 24, 22, 21, 19, 18, 14, 14, 14, 14, 15, 14, 8, 17,
+ 16, 15, 15, 16, 14, 7, 17, 17, 18, 18, 18, 17, 12, 16, 21, 22, 21, 22, 20,
+ 16, 19, 27, 27, 26, 26, 24, 18, 22, 30, 31, 30, 27, 25, 21, 27, 33, 35, 32,
+ 30, 27, 22, 24, 25, 24, 23, 20, 17, 12, 24, 27, 25, 24, 21, 17, 12, 23, 29,
+ 27, 27, 24, 20, 16, 24, 31, 31, 30, 27, 24, 20, 26, 33, 37, 35, 32, 27, 21,
+ 30, 36, 43, 39, 33, 29, 24, 33, 39, 43, 41, 36, 29, 25, 31, 35, 33, 27, 23,
+ 19, 15, 32, 36, 35, 28, 24, 20, 16, 32, 37, 38, 32, 27, 24, 20, 30, 37, 41,
+ 36, 31, 27, 23, 34, 39, 44, 41, 36, 30, 25, 37, 41, 47, 46, 39, 32, 28, 39,
+ 45, 48, 47, 41, 34, 29, 2, 2, 4, 8, 8, 6, 2, 2, 2, 3, 7, 8, 4,
+ 2, 2, 2, 3, 4, 5, 3, 2, 1, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3, 6, 6, 6, 6, 4, 3, 2, 12, 10, 8, 6, 4, 3, 3, 2, 2,
+ 3, 5, 5, 2, 2, 1, 2, 3, 4, 4, 2, 2, 0, 2, 2, 2, 2, 2, 1,
+ 1, 1, 1, 2, 1, 1, 3, 3, 3, 4, 4, 3, 3, 3, 8, 7, 8, 7, 4,
+ 3, 3, 15, 13, 10, 7, 5, 3, 3, 0, 2, 2, 2, 2, 2, 1, 2, 2, 2,
+ 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 4, 5,
+ 5, 4, 4, 5, 3, 4, 11, 10, 9, 8, 6, 4, 4, 17, 16, 12, 9, 7, 6,
+ 5, 2, 2, 2, 3, 3, 3, 7, 2, 3, 3, 4, 4, 4, 7, 4, 4, 4, 5,
+ 5, 5, 7, 7, 7, 7, 7, 8, 8, 8, 7, 11, 11, 11, 12, 11, 10, 11, 17,
+ 16, 15, 14, 12, 12, 18, 22, 19, 17, 16, 14, 13, 10, 10, 10, 10, 11, 10, 7,
+ 12, 12, 12, 11, 12, 11, 7, 12, 14, 13, 13, 13, 12, 8, 12, 17, 16, 17, 16,
+ 15, 12, 15, 21, 20, 20, 20, 19, 13, 18, 24, 26, 24, 24, 21, 15, 22, 28, 29,
+ 26, 25, 23, 17, 19, 21, 20, 20, 16, 12, 8, 19, 23, 22, 22, 18, 13, 9, 20,
+ 25, 24, 24, 20, 15, 11, 19, 25, 27, 27, 23, 19, 15, 21, 28, 31, 31, 28, 22,
+ 17, 25, 30, 36, 35, 30, 24, 18, 27, 33, 38, 36, 31, 27, 21, 27, 32, 31, 25,
+ 20, 16, 11, 27, 33, 34, 27, 22, 16, 12, 27, 32, 36, 29, 24, 19, 15, 27, 33,
+ 38, 32, 27, 23, 19, 28, 35, 40, 36, 32, 26, 21, 31, 36, 41, 40, 33, 28, 22,
+ 34, 37, 42, 41, 35, 31, 24, 1, 2, 3, 3, 3, 2, 2, 0, 2, 2, 3, 3,
+ 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, 4, 4, 3, 4,
+ 4, 4, 4, 4, 7, 7, 7, 7, 5, 4, 4, 13, 11, 9, 7, 6, 4, 4, 1,
+ 2, 2, 3, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 0, 2, 2, 2, 1,
+ 1, 2, 2, 2, 2, 2, 2, 4, 5, 4, 4, 5, 4, 4, 3, 9, 9, 8, 8,
+ 5, 4, 4, 17, 14, 10, 8, 6, 4, 3, 2, 0, 1, 1, 2, 2, 5, 2, 2,
+ 1, 1, 1, 2, 5, 2, 2, 1, 1, 1, 1, 6, 4, 2, 4, 4, 4, 4, 7,
+ 8, 6, 7, 8, 8, 7, 7, 13, 11, 12, 11, 9, 8, 7, 19, 17, 15, 13, 11,
+ 10, 9, 2, 5, 5, 6, 6, 5, 8, 5, 6, 6, 7, 7, 7, 9, 8, 7, 7,
+ 8, 8, 8, 9, 11, 9, 11, 11, 11, 11, 11, 11, 14, 15, 15, 15, 14, 13, 13,
+ 20, 20, 19, 18, 16, 15, 19, 26, 23, 20, 19, 17, 17, 12, 13, 13, 13, 14, 12,
+ 8, 14, 15, 15, 15, 15, 13, 8, 14, 17, 16, 16, 16, 15, 12, 14, 21, 20, 19,
+ 20, 19, 15, 18, 26, 24, 24, 25, 22, 17, 21, 29, 30, 29, 26, 23, 19, 26, 31,
+ 33, 30, 29, 26, 20, 22, 24, 22, 22, 19, 15, 11, 23, 26, 24, 23, 21, 16, 12,
+ 22, 28, 27, 26, 22, 19, 15, 22, 28, 31, 30, 26, 22, 19, 26, 32, 35, 35, 31,
+ 26, 21, 28, 34, 40, 39, 32, 28, 23, 32, 37, 42, 41, 36, 29, 25, 30, 36, 35,
+ 28, 22, 18, 14, 30, 36, 37, 29, 23, 19, 15, 30, 36, 39, 32, 27, 22, 19, 31,
+ 38, 42, 36, 31, 26, 23, 32, 39, 44, 42, 34, 30, 24, 34, 40, 47, 45, 38, 32,
+ 27, 37, 42, 48, 48, 41, 34, 27, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2,
+ 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 3, 4, 4, 5,
+ 4, 5, 5, 4, 4, 9, 8, 8, 7, 6, 4, 4, 15, 13, 10, 8, 6, 4, 4,
+ 2, 1, 1, 2, 1, 1, 3, 2, 1, 1, 2, 1, 1, 3, 2, 2, 0, 1, 2,
+ 1, 5, 2, 3, 2, 3, 3, 3, 5, 6, 6, 6, 6, 5, 4, 5, 11, 10, 10,
+ 9, 6, 5, 5, 18, 15, 12, 9, 8, 6, 5, 2, 2, 2, 2, 2, 5, 7, 2,
+ 2, 3, 3, 3, 5, 7, 5, 2, 4, 4, 5, 5, 8, 8, 3, 7, 7, 8, 8,
+ 9, 12, 7, 10, 11, 11, 10, 9, 15, 13, 15, 15, 13, 12, 9, 21, 19, 17, 16,
+ 15, 13, 12, 5, 7, 8, 9, 9, 8, 11, 9, 7, 9, 10, 10, 10, 11, 11, 8,
+ 11, 11, 12, 12, 12, 14, 10, 15, 15, 15, 15, 13, 15, 16, 18, 19, 19, 18, 17,
+ 16, 22, 23, 22, 21, 20, 19, 21, 28, 27, 25, 23, 22, 21, 15, 16, 16, 16, 17,
+ 16, 11, 17, 18, 18, 18, 18, 17, 11, 17, 19, 20, 21, 21, 19, 15, 17, 23, 24,
+ 23, 24, 22, 19, 20, 29, 28, 28, 28, 25, 21, 24, 33, 34, 33, 31, 27, 23, 29,
+ 35, 37, 33, 32, 30, 24, 26, 27, 26, 26, 23, 18, 14, 25, 30, 28, 27, 24, 20,
+ 15, 26, 31, 31, 31, 26, 23, 19, 25, 33, 34, 35, 31, 26, 22, 28, 35, 40, 38,
+ 36, 29, 24, 32, 39, 45, 43, 37, 32, 26, 36, 41, 46, 46, 40, 34, 28, 34, 41,
+ 38, 32, 26, 22, 17, 34, 41, 41, 34, 27, 22, 19, 34, 40, 43, 37, 31, 26, 22,
+ 34, 41, 47, 41, 35, 30, 26, 36, 43, 49, 44, 40, 33, 28, 39, 45, 52, 51, 43,
+ 35, 30, 42, 48, 52, 51, 45, 38, 32, 2, 1, 2, 4, 3, 3, 3, 2, 1, 2,
+ 3, 3, 2, 1, 2, 2, 1, 2, 2, 1, 3, 2, 2, 2, 2, 3, 3, 4, 5,
+ 5, 5, 5, 5, 4, 4, 9, 9, 8, 8, 6, 4, 4, 15, 13, 10, 8, 7, 4,
+ 4, 2, 2, 1, 3, 3, 4, 6, 2, 2, 1, 2, 2, 3, 5, 2, 2, 1, 0,
+ 0, 3, 6, 4, 3, 3, 3, 3, 4, 7, 8, 6, 6, 7, 6, 4, 7, 12, 10,
+ 10, 9, 8, 7, 7, 19, 16, 12, 10, 10, 9, 7, 2, 2, 4, 5, 6, 7, 9,
+ 4, 2, 4, 6, 6, 6, 8, 7, 2, 4, 6, 7, 6, 9, 11, 3, 7, 10, 10,
+ 10, 10, 14, 8, 11, 14, 14, 13, 10, 18, 13, 15, 17, 15, 15, 10, 21, 18, 18,
+ 18, 17, 16, 14, 7, 7, 10, 11, 12, 10, 14, 11, 8, 11, 12, 13, 13, 13, 14,
+ 8, 12, 13, 14, 14, 13, 17, 12, 16, 17, 18, 18, 15, 17, 17, 20, 21, 22, 21,
+ 19, 18, 23, 26, 24, 23, 22, 21, 21, 29, 28, 27, 25, 23, 24, 17, 18, 19, 19,
+ 20, 20, 14, 20, 19, 21, 21, 21, 20, 13, 19, 20, 22, 23, 23, 22, 17, 20, 25,
+ 26, 27, 27, 26, 21, 22, 31, 30, 31, 32, 29, 23, 25, 35, 36, 35, 33, 30, 25,
+ 30, 37, 40, 37, 36, 32, 26, 27, 30, 29, 29, 26, 22, 18, 27, 32, 31, 30, 27,
+ 23, 18, 28, 34, 34, 33, 30, 25, 21, 27, 36, 39, 38, 33, 29, 25, 30, 39, 42,
+ 41, 37, 32, 27, 34, 41, 47, 46, 40, 34, 29, 38, 42, 49, 50, 43, 35, 30, 36,
+ 44, 41, 34, 29, 25, 20, 38, 43, 43, 36, 30, 26, 21, 38, 44, 47, 40, 34, 29,
+ 25, 37, 44, 50, 44, 38, 33, 29, 39, 45, 52, 50, 42, 36, 30, 42, 49, 54, 54,
+ 46, 37, 33, 47, 51, 56, 55, 49, 41, 34, 2, 1, 3, 6, 6, 4, 3, 2, 1,
+ 2, 5, 6, 3, 1, 2, 2, 1, 3, 4, 2, 2, 2, 2, 2, 3, 4, 4, 4,
+ 4, 5, 5, 5, 7, 5, 4, 9, 8, 8, 8, 7, 5, 4, 14, 12, 10, 7, 8,
+ 5, 4, 2, 2, 1, 3, 3, 4, 5, 2, 2, 1, 2, 2, 3, 4, 2, 2, 1,
+ 0, 0, 2, 4, 4, 3, 3, 3, 3, 3, 5, 8, 6, 6, 6, 6, 3, 5, 12,
+ 10, 10, 9, 8, 7, 5, 18, 15, 11, 9, 9, 8, 5, 2, 2, 4, 5, 5, 6,
+ 8, 5, 2, 3, 6, 6, 6, 7, 8, 2, 4, 6, 7, 4, 7, 12, 3, 7, 10,
+ 10, 9, 9, 15, 8, 10, 13, 14, 13, 9, 18, 12, 14, 17, 16, 14, 9, 21, 18,
+ 16, 18, 17, 16, 14, 9, 6, 10, 11, 12, 10, 13, 12, 7, 10, 12, 13, 12, 12,
+ 15, 8, 12, 13, 14, 14, 12, 16, 11, 15, 17, 17, 17, 14, 18, 16, 19, 21, 22,
+ 21, 17, 18, 22, 24, 24, 24, 22, 21, 20, 27, 27, 26, 25, 24, 23, 17, 17, 19,
+ 19, 20, 19, 13, 20, 19, 20, 20, 21, 20, 12, 20, 20, 22, 23, 23, 22, 16, 20,
+ 23, 26, 26, 27, 25, 21, 22, 29, 31, 31, 30, 28, 23, 25, 34, 37, 35, 33, 29,
+ 25, 29, 37, 40, 37, 35, 32, 26, 27, 30, 29, 29, 26, 22, 17, 26, 32, 31, 30,
+ 27, 22, 18, 26, 34, 34, 33, 29, 25, 21, 27, 35, 39, 37, 33, 29, 25, 30, 39,
+ 44, 41, 37, 32, 26, 34, 41, 48, 46, 39, 33, 29, 37, 44, 48, 48, 43, 36, 30,
+ 37, 42, 40, 33, 29, 25, 21, 37, 42, 42, 36, 29, 25, 21, 37, 42, 45, 38, 34,
+ 29, 24, 37, 44, 49, 43, 36, 33, 28, 38, 46, 50, 48, 42, 35, 30, 42, 49, 53,
+ 52, 45, 38, 32, 45, 49, 55, 55, 47, 40, 34, 1, 3, 5, 7, 7, 5, 3, 1,
+ 1, 4, 6, 6, 4, 2, 2, 1, 3, 5, 5, 3, 2, 2, 1, 2, 4, 6, 5,
+ 4, 4, 4, 4, 6, 8, 6, 4, 8, 7, 7, 8, 8, 6, 4, 13, 11, 9, 8,
+ 8, 6, 4, 1, 1, 3, 5, 4, 3, 4, 1, 1, 2, 4, 4, 2, 3, 2, 1,
+ 1, 3, 2, 0, 3, 2, 2, 2, 3, 3, 2, 4, 6, 5, 5, 6, 5, 4, 4,
+ 11, 9, 9, 8, 6, 4, 3, 16, 13, 10, 8, 7, 6, 3, 2, 1, 3, 4, 4,
+ 6, 7, 2, 2, 4, 4, 5, 5, 6, 5, 2, 3, 4, 4, 3, 5, 10, 3, 6,
+ 7, 7, 7, 7, 13, 7, 9, 11, 11, 10, 7, 16, 12, 13, 14, 12, 12, 7, 19,
+ 17, 15, 15, 14, 13, 12, 5, 6, 9, 10, 11, 9, 11, 11, 7, 9, 11, 11, 11,
+ 10, 14, 7, 11, 11, 11, 11, 10, 16, 10, 14, 14, 15, 15, 11, 17, 15, 18, 19,
+ 19, 18, 14, 16, 20, 22, 22, 20, 20, 18, 18, 25, 25, 24, 23, 21, 20, 15, 16,
+ 17, 18, 18, 17, 11, 19, 17, 19, 19, 20, 18, 10, 19, 19, 20, 20, 20, 18, 14,
+ 19, 22, 23, 23, 24, 22, 18, 21, 28, 28, 28, 28, 25, 20, 23, 31, 34, 32, 30,
+ 27, 23, 26, 34, 36, 35, 32, 29, 24, 26, 28, 27, 27, 24, 19, 16, 25, 30, 28,
+ 28, 25, 21, 16, 25, 32, 30, 29, 25, 22, 18, 25, 33, 34, 34, 30, 26, 22, 28,
+ 35, 40, 38, 34, 29, 23, 31, 40, 45, 41, 36, 30, 26, 35, 40, 44, 45, 39, 33,
+ 27, 36, 40, 37, 31, 25, 23, 19, 35, 40, 40, 33, 28, 23, 19, 35, 40, 42, 35,
+ 30, 26, 22, 34, 41, 45, 39, 32, 30, 26, 37, 43, 48, 44, 37, 33, 28, 38, 44,
+ 50, 49, 41, 35, 29, 42, 47, 49, 50, 44, 37, 31, 3, 5, 7, 9, 9, 7, 5,
+ 2, 5, 7, 8, 9, 6, 4, 1, 4, 6, 7, 8, 5, 3, 1, 1, 4, 6, 8,
+ 6, 5, 3, 3, 5, 6, 9, 7, 4, 7, 6, 7, 8, 8, 7, 4, 10, 9, 8,
+ 8, 8, 7, 5, 1, 4, 6, 8, 7, 5, 4, 1, 3, 5, 7, 6, 4, 2, 1,
+ 1, 5, 6, 4, 3, 0, 2, 1, 3, 4, 3, 3, 2, 4, 4, 4, 6, 5, 4,
+ 2, 9, 8, 7, 8, 6, 4, 2, 14, 11, 8, 8, 6, 4, 2, 1, 1, 3, 3,
+ 4, 5, 6, 2, 1, 3, 3, 3, 4, 5, 2, 1, 2, 2, 2, 2, 3, 4, 2,
+ 4, 4, 3, 3, 4, 9, 6, 7, 7, 7, 6, 4, 12, 10, 10, 9, 9, 8, 4,
+ 16, 13, 12, 11, 10, 9, 8, 2, 6, 7, 8, 8, 8, 9, 5, 6, 8, 8, 9,
+ 9, 8, 9, 6, 8, 9, 9, 9, 7, 12, 8, 11, 11, 10, 11, 8, 13, 13, 15,
+ 14, 15, 14, 12, 12, 17, 18, 17, 17, 15, 14, 16, 22, 21, 19, 19, 17, 16, 13,
+ 14, 15, 15, 16, 15, 9, 15, 15, 16, 17, 17, 16, 8, 15, 17, 18, 17, 17, 15,
+ 12, 15, 20, 20, 20, 20, 18, 15, 17, 25, 24, 25, 24, 21, 16, 20, 27, 29, 27,
+ 26, 23, 18, 23, 29, 32, 29, 28, 25, 20, 23, 25, 24, 23, 21, 17, 14, 24, 27,
+ 26, 25, 23, 18, 13, 23, 29, 28, 26, 22, 18, 14, 23, 30, 31, 29, 26, 22, 18,
+ 26, 32, 36, 33, 29, 25, 20, 29, 35, 39, 37, 32, 26, 21, 31, 36, 40, 39, 33,
+ 28, 23, 31, 37, 34, 28, 23, 20, 17, 32, 36, 35, 29, 25, 20, 16, 32, 37, 39,
+ 31, 25, 22, 17, 32, 36, 40, 35, 29, 26, 21, 33, 38, 43, 39, 33, 28, 23, 36,
+ 40, 43, 44, 36, 30, 25, 38, 42, 45, 45, 39, 32, 26, 2, 3, 7, 11, 11, 10,
+ 6, 2, 2, 6, 10, 11, 9, 3, 2, 2, 4, 7, 9, 6, 2, 2, 2, 2, 4,
+ 6, 4, 2, 2, 2, 2, 3, 5, 4, 2, 6, 6, 6, 5, 4, 4, 2, 11, 11,
+ 8, 6, 4, 4, 2, 2, 2, 4, 8, 9, 5, 2, 1, 2, 3, 6, 8, 3, 2,
+ 1, 2, 2, 4, 4, 2, 2, 0, 2, 2, 2, 2, 1, 2, 3, 3, 3, 3, 3,
+ 2, 2, 8, 7, 8, 7, 4, 3, 2, 15, 13, 10, 7, 5, 3, 2, 1, 2, 2,
+ 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 0, 2,
+ 1, 1, 1, 1, 1, 2, 5, 4, 4, 4, 4, 3, 2, 11, 10, 9, 8, 6, 3,
+ 2, 17, 16, 12, 9, 6, 5, 3, 1, 1, 1, 1, 1, 2, 6, 1, 2, 3, 3,
+ 3, 3, 6, 3, 3, 3, 4, 4, 4, 6, 6, 6, 6, 6, 7, 7, 8, 6, 10,
+ 10, 10, 10, 10, 9, 11, 15, 15, 14, 12, 11, 10, 17, 21, 18, 16, 15, 13, 12,
+ 9, 9, 9, 10, 10, 9, 6, 11, 11, 11, 11, 11, 10, 6, 11, 12, 12, 12, 13,
+ 11, 7, 11, 16, 15, 15, 15, 14, 10, 14, 20, 19, 19, 20, 18, 12, 17, 23, 25,
+ 23, 22, 20, 14, 21, 27, 28, 26, 24, 22, 16, 18, 19, 19, 20, 16, 12, 7, 18,
+ 22, 21, 21, 18, 13, 9, 18, 23, 23, 23, 19, 15, 10, 18, 24, 27, 25, 22, 18,
+ 14, 20, 27, 30, 27, 26, 21, 16, 23, 28, 34, 31, 28, 24, 18, 27, 31, 35, 34,
+ 30, 25, 20, 26, 32, 29, 24, 20, 15, 10, 26, 31, 32, 26, 21, 16, 11, 26, 32,
+ 33, 28, 23, 18, 14, 25, 31, 36, 29, 26, 22, 18, 26, 31, 37, 34, 29, 25, 20,
+ 30, 34, 38, 36, 30, 26, 22, 31, 36, 37, 37, 32, 29, 24, 2, 3, 4, 4, 4,
+ 4, 3, 2, 3, 4, 4, 4, 3, 3, 1, 2, 3, 4, 4, 3, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 6, 6, 6, 5, 3, 2, 2, 11,
+ 10, 7, 6, 4, 2, 2, 1, 3, 3, 4, 3, 3, 3, 1, 2, 3, 4, 3, 3,
+ 2, 1, 2, 3, 3, 3, 2, 1, 2, 0, 1, 2, 2, 1, 2, 3, 3, 3, 3,
+ 3, 2, 2, 8, 7, 7, 6, 4, 2, 2, 15, 12, 9, 7, 5, 3, 2, 1, 2,
+ 2, 3, 3, 3, 5, 2, 1, 2, 3, 3, 3, 5, 2, 1, 2, 2, 2, 2, 4,
+ 2, 1, 2, 2, 2, 2, 5, 6, 5, 5, 5, 5, 5, 5, 11, 10, 10, 9, 7,
+ 6, 5, 17, 15, 12, 10, 9, 7, 6, 2, 4, 5, 5, 6, 6, 9, 2, 5, 6,
+ 7, 7, 7, 8, 6, 6, 7, 7, 7, 8, 9, 9, 8, 9, 9, 9, 9, 9, 9,
+ 13, 13, 13, 13, 13, 11, 11, 18, 17, 16, 15, 14, 13, 17, 25, 20, 19, 17, 15,
+ 14, 12, 12, 13, 13, 14, 12, 9, 13, 14, 14, 14, 15, 13, 9, 13, 15, 16, 16,
+ 16, 14, 10, 13, 18, 18, 18, 18, 17, 13, 16, 23, 22, 22, 22, 20, 15, 20, 26,
+ 27, 26, 24, 22, 16, 24, 29, 31, 27, 26, 24, 17, 22, 23, 22, 22, 20, 15, 11,
+ 21, 25, 24, 24, 21, 16, 12, 21, 27, 26, 26, 21, 17, 13, 22, 27, 29, 27, 24,
+ 20, 16, 23, 29, 34, 32, 28, 23, 18, 26, 32, 39, 37, 32, 26, 20, 29, 35, 40,
+ 40, 34, 27, 22, 29, 36, 35, 28, 22, 18, 14, 29, 36, 38, 30, 24, 19, 15, 30,
+ 37, 39, 31, 25, 20, 17, 30, 34, 41, 34, 29, 24, 20, 29, 37, 42, 39, 34, 28,
+ 22, 32, 38, 44, 43, 37, 30, 24, 35, 41, 45, 46, 39, 32, 25, 2, 3, 4, 5,
+ 5, 5, 4, 2, 3, 4, 5, 5, 4, 3, 2, 2, 3, 4, 4, 2, 1, 2, 1,
+ 2, 2, 2, 1, 2, 3, 2, 2, 3, 3, 2, 2, 6, 6, 6, 5, 3, 2, 2,
+ 12, 10, 7, 5, 4, 2, 2, 2, 2, 3, 4, 4, 4, 5, 2, 2, 3, 4, 4,
+ 3, 4, 2, 2, 2, 3, 3, 2, 2, 2, 2, 0, 1, 2, 1, 3, 4, 3, 3,
+ 3, 3, 2, 4, 9, 8, 7, 6, 4, 2, 4, 16, 13, 9, 7, 5, 3, 3, 2,
+ 2, 3, 4, 5, 6, 8, 2, 2, 3, 4, 5, 5, 8, 2, 2, 3, 4, 4, 4,
+ 6, 5, 2, 4, 5, 5, 5, 7, 9, 5, 8, 8, 8, 7, 7, 12, 10, 12, 11,
+ 10, 9, 7, 17, 16, 15, 13, 11, 10, 9, 2, 6, 8, 9, 10, 9, 11, 5, 7,
+ 9, 10, 11, 11, 12, 9, 8, 10, 10, 10, 11, 11, 12, 9, 12, 12, 12, 13, 11,
+ 12, 14, 15, 15, 16, 16, 14, 13, 20, 21, 20, 18, 17, 16, 18, 26, 24, 22, 19,
+ 18, 17, 13, 15, 16, 17, 18, 17, 11, 15, 17, 17, 18, 19, 17, 11, 15, 18, 19,
+ 18, 19, 18, 13, 15, 22, 21, 20, 21, 20, 16, 17, 26, 26, 25, 25, 23, 17, 22,
+ 30, 31, 30, 27, 24, 19, 26, 33, 34, 32, 29, 26, 21, 25, 27, 26, 26, 23, 20,
+ 15, 24, 29, 28, 27, 24, 20, 16, 25, 31, 30, 30, 25, 20, 16, 24, 31, 32, 32,
+ 28, 23, 19, 26, 32, 36, 36, 32, 26, 21, 29, 35, 42, 41, 35, 28, 23, 33, 38,
+ 42, 42, 37, 30, 25, 33, 40, 37, 32, 27, 22, 18, 32, 39, 40, 33, 27, 22, 18,
+ 34, 40, 43, 35, 28, 23, 19, 33, 38, 44, 38, 32, 28, 23, 34, 40, 45, 43, 36,
+ 31, 25, 36, 43, 48, 47, 40, 33, 26, 38, 44, 49, 49, 42, 35, 28, 2, 3, 5,
+ 6, 6, 6, 4, 2, 3, 4, 6, 6, 4, 3, 2, 2, 3, 4, 4, 2, 1, 2,
+ 2, 1, 2, 2, 1, 2, 3, 2, 2, 3, 3, 2, 2, 7, 6, 6, 5, 4, 2,
+ 2, 12, 10, 8, 5, 4, 2, 2, 2, 3, 3, 5, 5, 6, 7, 2, 2, 3, 5,
+ 5, 4, 5, 2, 2, 3, 3, 3, 3, 4, 2, 2, 2, 0, 0, 2, 5, 5, 4,
+ 3, 4, 3, 3, 4, 9, 8, 7, 7, 5, 4, 5, 15, 13, 9, 8, 7, 5, 5,
+ 2, 2, 5, 6, 7, 8, 10, 2, 2, 5, 6, 7, 7, 9, 4, 2, 5, 6, 6,
+ 6, 8, 8, 2, 5, 7, 7, 7, 8, 11, 6, 8, 10, 11, 10, 8, 15, 11, 12,
+ 13, 12, 11, 8, 17, 15, 15, 16, 14, 13, 11, 4, 7, 11, 11, 12, 11, 14, 8,
+ 7, 11, 12, 13, 13, 14, 11, 8, 12, 13, 13, 13, 13, 14, 10, 14, 14, 15, 14,
+ 13, 14, 14, 17, 18, 18, 18, 16, 15, 20, 22, 21, 20, 19, 18, 17, 26, 25, 24,
+ 22, 21, 20, 15, 17, 18, 19, 20, 19, 14, 17, 19, 20, 21, 21, 20, 14, 17, 20,
+ 21, 22, 22, 20, 16, 17, 23, 24, 24, 23, 23, 19, 19, 27, 28, 28, 28, 26, 20,
+ 22, 31, 33, 32, 30, 27, 22, 27, 34, 37, 34, 32, 29, 23, 27, 29, 29, 28, 26,
+ 22, 18, 27, 32, 30, 30, 27, 22, 18, 27, 33, 33, 32, 28, 23, 18, 27, 33, 35,
+ 34, 30, 25, 21, 28, 36, 40, 38, 35, 29, 24, 31, 38, 45, 43, 36, 30, 26, 34,
+ 40, 45, 46, 39, 34, 27, 37, 42, 41, 35, 29, 25, 20, 36, 42, 43, 37, 30, 25,
+ 21, 36, 43, 45, 38, 31, 26, 22, 37, 42, 48, 41, 35, 30, 25, 37, 43, 49, 46,
+ 39, 33, 28, 38, 46, 51, 50, 42, 35, 30, 41, 47, 52, 53, 45, 38, 32, 2, 3,
+ 6, 9, 9, 7, 5, 2, 3, 5, 8, 9, 6, 3, 2, 2, 3, 6, 7, 4, 1,
+ 2, 1, 1, 3, 5, 3, 2, 3, 2, 2, 3, 5, 3, 2, 6, 6, 6, 5, 5,
+ 4, 2, 11, 9, 7, 5, 5, 3, 2, 2, 2, 3, 7, 6, 6, 7, 2, 2, 3,
+ 5, 6, 5, 5, 2, 2, 3, 3, 3, 3, 4, 2, 2, 2, 0, 0, 1, 4, 5,
+ 3, 3, 3, 3, 2, 4, 9, 7, 7, 6, 5, 4, 4, 14, 11, 8, 7, 6, 5,
+ 4, 1, 2, 5, 6, 7, 8, 9, 2, 2, 5, 6, 7, 7, 8, 5, 2, 4, 6,
+ 6, 5, 7, 8, 2, 5, 7, 7, 7, 7, 12, 5, 8, 10, 11, 10, 7, 15, 11,
+ 11, 13, 12, 11, 7, 16, 14, 13, 14, 14, 13, 11, 5, 6, 10, 11, 12, 11, 13,
+ 9, 7, 11, 12, 13, 13, 12, 11, 7, 11, 12, 13, 13, 11, 14, 9, 13, 14, 14,
+ 14, 12, 15, 14, 17, 19, 19, 18, 15, 14, 18, 21, 22, 21, 19, 18, 16, 23, 23,
+ 22, 22, 21, 20, 15, 16, 18, 19, 20, 19, 14, 18, 18, 20, 21, 21, 20, 13, 18,
+ 19, 21, 22, 21, 19, 15, 17, 22, 24, 24, 23, 22, 18, 19, 26, 28, 27, 28, 25,
+ 20, 21, 30, 32, 31, 30, 27, 22, 24, 34, 36, 34, 32, 29, 23, 26, 29, 29, 29,
+ 26, 22, 17, 26, 31, 31, 30, 27, 22, 17, 26, 33, 33, 32, 27, 22, 18, 26, 33,
+ 35, 34, 30, 25, 21, 28, 35, 39, 38, 35, 29, 24, 31, 37, 44, 42, 37, 31, 25,
+ 34, 38, 44, 45, 39, 34, 27, 36, 42, 41, 33, 29, 25, 20, 37, 43, 43, 36, 30,
+ 25, 21, 36, 42, 45, 38, 31, 26, 22, 36, 42, 46, 41, 34, 29, 25, 37, 43, 48,
+ 45, 39, 33, 27, 38, 46, 51, 50, 42, 35, 29, 40, 47, 51, 51, 43, 36, 31, 3,
+ 4, 6, 8, 8, 6, 4, 3, 3, 5, 7, 7, 5, 3, 2, 3, 4, 6, 6, 4,
+ 2, 1, 1, 2, 4, 5, 3, 2, 2, 2, 2, 4, 6, 4, 2, 6, 5, 5, 5,
+ 6, 4, 2, 9, 7, 5, 5, 6, 4, 2, 2, 3, 4, 6, 5, 6, 6, 2, 3,
+ 4, 5, 5, 4, 4, 1, 2, 3, 4, 3, 2, 3, 1, 1, 1, 2, 1, 0, 3,
+ 4, 3, 3, 3, 3, 2, 3, 8, 6, 5, 5, 3, 2, 2, 11, 8, 6, 5, 5,
+ 4, 3, 1, 2, 5, 5, 6, 8, 9, 2, 2, 5, 6, 6, 6, 7, 3, 1, 5,
+ 5, 5, 5, 6, 8, 1, 4, 5, 5, 5, 5, 11, 5, 7, 9, 9, 8, 5, 12,
+ 9, 9, 11, 10, 9, 5, 13, 11, 10, 12, 11, 11, 10, 3, 6, 10, 11, 11, 11,
+ 12, 8, 7, 11, 12, 12, 12, 11, 11, 7, 11, 12, 12, 12, 10, 14, 8, 12, 13,
+ 13, 13, 10, 15, 13, 15, 17, 17, 16, 13, 12, 16, 18, 19, 18, 18, 16, 13, 19,
+ 21, 20, 19, 19, 18, 14, 16, 18, 19, 20, 19, 13, 17, 18, 19, 20, 20, 19, 12,
+ 17, 18, 21, 20, 20, 19, 15, 17, 21, 22, 22, 23, 21, 17, 19, 26, 26, 26, 25,
+ 24, 18, 20, 28, 30, 29, 27, 25, 20, 21, 29, 32, 30, 29, 27, 21, 25, 28, 28,
+ 28, 24, 21, 17, 26, 30, 29, 29, 26, 21, 17, 26, 32, 31, 29, 26, 21, 18, 25,
+ 32, 34, 31, 27, 24, 20, 28, 33, 38, 35, 31, 27, 22, 29, 35, 41, 39, 33, 28,
+ 24, 30, 36, 42, 40, 36, 31, 26, 35, 40, 39, 32, 27, 23, 19, 35, 40, 41, 34,
+ 29, 24, 20, 36, 41, 43, 35, 29, 25, 20, 36, 39, 43, 38, 33, 28, 23, 35, 42,
+ 45, 42, 36, 30, 26, 38, 43, 47, 45, 39, 32, 27, 38, 43, 47, 47, 41, 33, 29,
+ 4, 7, 8, 11, 10, 9, 6, 4, 6, 8, 10, 10, 7, 5, 3, 5, 7, 8, 9,
+ 6, 3, 3, 3, 5, 7, 8, 5, 3, 1, 0, 3, 5, 7, 5, 3, 2, 2, 4,
+ 5, 7, 5, 3, 4, 3, 3, 4, 6, 5, 3, 4, 5, 7, 9, 8, 6, 7, 3,
+ 4, 6, 8, 7, 5, 4, 2, 3, 5, 7, 5, 3, 2, 2, 2, 3, 5, 4, 3,
+ 0, 1, 1, 2, 4, 3, 2, 0, 4, 3, 3, 4, 2, 2, 0, 7, 4, 3, 3,
+ 3, 1, 0, 3, 4, 4, 5, 7, 8, 8, 2, 3, 5, 6, 6, 6, 6, 2, 3,
+ 5, 4, 4, 4, 5, 3, 2, 3, 3, 2, 3, 3, 6, 2, 4, 4, 4, 4, 3,
+ 7, 4, 5, 5, 5, 5, 3, 8, 6, 6, 7, 6, 6, 6, 2, 7, 8, 8, 9,
+ 10, 11, 3, 7, 9, 9, 10, 10, 9, 8, 7, 9, 9, 10, 10, 8, 11, 7, 10,
+ 10, 10, 10, 7, 10, 9, 11, 11, 12, 11, 11, 7, 11, 13, 13, 13, 13, 12, 8,
+ 14, 15, 15, 14, 14, 14, 12, 15, 15, 16, 17, 16, 11, 14, 16, 17, 18, 17, 15,
+ 9, 14, 18, 18, 18, 18, 16, 12, 14, 20, 19, 18, 18, 17, 13, 14, 21, 22, 21,
+ 20, 18, 14, 14, 22, 24, 23, 22, 20, 15, 16, 22, 27, 25, 23, 21, 17, 24, 27,
+ 24, 24, 22, 18, 14, 24, 28, 27, 26, 23, 18, 14, 24, 29, 29, 26, 22, 19, 15,
+ 24, 30, 30, 27, 24, 20, 15, 23, 30, 32, 30, 25, 21, 17, 24, 30, 36, 33, 27,
+ 23, 19, 25, 30, 35, 34, 30, 25, 20, 32, 37, 34, 29, 24, 20, 17, 33, 37, 37,
+ 30, 26, 21, 16, 32, 38, 39, 32, 26, 22, 17, 32, 37, 40, 33, 27, 23, 19, 31,
+ 37, 40, 36, 30, 24, 20, 31, 37, 41, 38, 32, 27, 21, 33, 36, 42, 40, 34, 28,
+ 23, 5, 7, 10, 14, 14, 11, 8, 5, 6, 9, 13, 14, 11, 8, 4, 6, 8, 11,
+ 13, 10, 6, 4, 4, 5, 8, 11, 8, 2, 2, 2, 2, 4, 6, 6, 2, 3, 3,
+ 3, 3, 5, 6, 2, 9, 8, 5, 3, 4, 6, 2, 4, 6, 8, 11, 11, 8, 6,
+ 4, 5, 7, 9, 10, 7, 5, 3, 5, 6, 8, 8, 6, 4, 3, 3, 4, 5, 5,
+ 4, 1, 0, 2, 2, 2, 2, 2, 1, 5, 5, 5, 4, 2, 2, 1, 12, 10, 7,
+ 5, 2, 2, 1, 4, 5, 5, 6, 7, 6, 5, 3, 4, 5, 5, 5, 5, 5, 2,
+ 4, 4, 4, 4, 4, 4, 2, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 2, 1,
+ 1, 8, 7, 7, 5, 3, 1, 1, 14, 14, 9, 6, 4, 1, 1, 2, 4, 4, 5,
+ 5, 6, 6, 2, 3, 5, 5, 5, 5, 6, 2, 3, 4, 5, 5, 5, 6, 3, 4,
+ 4, 4, 5, 5, 6, 3, 7, 7, 7, 7, 7, 6, 8, 13, 12, 11, 9, 8, 8,
+ 14, 18, 15, 13, 11, 10, 9, 9, 9, 10, 10, 11, 9, 6, 10, 11, 11, 11, 12,
+ 10, 6, 10, 12, 12, 12, 13, 12, 7, 10, 14, 13, 13, 14, 12, 8, 11, 17, 17,
+ 16, 16, 15, 9, 14, 19, 21, 20, 19, 16, 11, 18, 22, 24, 21, 20, 19, 13, 17,
+ 20, 20, 20, 17, 12, 8, 18, 22, 21, 21, 18, 13, 9, 17, 23, 23, 22, 19, 15,
+ 10, 18, 22, 24, 23, 20, 16, 11, 17, 23, 26, 24, 22, 19, 13, 19, 25, 28, 27,
+ 23, 20, 15, 22, 26, 29, 27, 24, 21, 17, 25, 30, 28, 25, 20, 15, 11, 26, 30,
+ 31, 26, 22, 16, 12, 26, 31, 33, 27, 22, 18, 13, 26, 30, 33, 27, 23, 19, 15,
+ 24, 29, 32, 29, 24, 21, 17, 25, 28, 32, 31, 26, 22, 19, 27, 30, 32, 32, 28,
+ 23, 20, 5, 6, 7, 8, 8, 7, 7, 5, 6, 7, 8, 8, 7, 6, 4, 5, 6,
+ 7, 7, 5, 4, 3, 4, 5, 5, 5, 3, 2, 1, 2, 2, 2, 3, 2, 1, 3,
+ 3, 3, 2, 3, 2, 1, 9, 7, 5, 3, 2, 2, 2, 4, 5, 7, 7, 7, 7,
+ 7, 4, 5, 6, 7, 7, 6, 5, 3, 4, 6, 6, 6, 5, 4, 3, 3, 3, 4,
+ 3, 3, 1, 2, 0, 2, 2, 2, 1, 1, 5, 4, 4, 3, 1, 2, 1, 12, 9,
+ 6, 4, 2, 1, 1, 3, 5, 5, 6, 7, 7, 8, 3, 4, 5, 6, 6, 6, 7,
+ 2, 3, 4, 5, 5, 5, 5, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2,
+ 2, 3, 8, 7, 6, 5, 4, 3, 3, 14, 12, 9, 7, 5, 4, 4, 3, 5, 6,
+ 7, 8, 9, 10, 2, 5, 6, 7, 8, 8, 9, 3, 6, 6, 6, 7, 7, 8, 6,
+ 6, 7, 7, 7, 8, 8, 6, 10, 9, 10, 10, 9, 9, 8, 15, 14, 13, 12, 10,
+ 10, 14, 21, 18, 15, 13, 12, 11, 11, 12, 12, 13, 14, 13, 10, 12, 14, 14, 14,
+ 15, 14, 9, 12, 15, 15, 15, 15, 14, 9, 13, 17, 16, 15, 16, 15, 11, 13, 20,
+ 19, 19, 19, 17, 12, 17, 22, 24, 23, 20, 18, 13, 21, 26, 28, 25, 23, 21, 15,
+ 21, 22, 21, 23, 20, 16, 11, 21, 24, 24, 24, 21, 16, 12, 21, 26, 27, 25, 22,
+ 17, 12, 21, 26, 27, 26, 22, 17, 13, 20, 26, 29, 29, 25, 20, 15, 22, 28, 35,
+ 34, 28, 22, 17, 25, 33, 36, 36, 31, 25, 18, 29, 36, 35, 28, 22, 19, 14, 29,
+ 35, 37, 29, 24, 19, 15, 30, 36, 39, 30, 25, 20, 15, 29, 35, 39, 32, 26, 21,
+ 17, 28, 34, 38, 36, 31, 24, 19, 29, 35, 41, 40, 32, 27, 21, 32, 37, 43, 41,
+ 35, 28, 23, 5, 7, 8, 9, 9, 9, 8, 5, 6, 7, 9, 9, 7, 6, 4, 5,
+ 7, 7, 7, 5, 4, 4, 4, 4, 5, 5, 3, 1, 2, 1, 2, 2, 2, 2, 1,
+ 3, 3, 3, 2, 2, 2, 1, 8, 7, 4, 2, 2, 2, 1, 4, 5, 7, 8, 8,
+ 8, 8, 4, 5, 7, 8, 8, 7, 7, 4, 5, 6, 6, 6, 5, 4, 3, 3, 3,
+ 4, 3, 3, 2, 2, 2, 0, 1, 1, 1, 2, 5, 4, 4, 3, 1, 1, 2, 12,
+ 9, 6, 3, 2, 1, 2, 4, 5, 6, 7, 8, 10, 10, 3, 4, 6, 7, 8, 8,
+ 9, 3, 4, 6, 6, 6, 6, 7, 3, 3, 4, 4, 4, 5, 6, 5, 2, 4, 5,
+ 5, 4, 5, 9, 7, 9, 8, 6, 5, 6, 14, 12, 11, 9, 8, 7, 7, 3, 7,
+ 8, 9, 10, 12, 12, 3, 7, 9, 10, 10, 10, 11, 7, 8, 9, 10, 10, 10, 11,
+ 10, 7, 10, 10, 10, 10, 10, 9, 11, 12, 12, 12, 12, 11, 9, 16, 17, 15, 14,
+ 13, 13, 14, 22, 20, 18, 16, 15, 14, 13, 15, 15, 16, 17, 16, 12, 14, 16, 17,
+ 17, 18, 16, 11, 14, 18, 19, 18, 17, 17, 13, 14, 19, 19, 19, 19, 17, 13, 14,
+ 23, 21, 21, 20, 19, 14, 18, 25, 27, 25, 23, 21, 16, 23, 28, 31, 28, 25, 23,
+ 18, 24, 25, 26, 26, 22, 18, 14, 23, 29, 26, 28, 24, 19, 15, 24, 29, 30, 28,
+ 24, 20, 15, 24, 29, 30, 30, 26, 20, 16, 23, 29, 33, 32, 28, 23, 17, 26, 31,
+ 38, 37, 30, 24, 19, 28, 34, 39, 38, 33, 26, 21, 33, 39, 38, 31, 26, 20, 17,
+ 33, 39, 41, 32, 27, 22, 17, 33, 40, 42, 34, 27, 23, 18, 33, 38, 43, 36, 29,
+ 24, 19, 31, 37, 42, 39, 33, 28, 21, 32, 37, 44, 44, 35, 29, 23, 34, 41, 45,
+ 45, 38, 32, 25, 5, 6, 9, 10, 10, 9, 8, 5, 6, 8, 9, 9, 8, 6, 4,
+ 5, 7, 8, 7, 6, 4, 4, 4, 4, 5, 6, 4, 2, 2, 2, 2, 2, 3, 2,
+ 1, 3, 3, 3, 2, 2, 2, 1, 8, 7, 4, 2, 2, 2, 1, 4, 6, 7, 9,
+ 9, 9, 10, 4, 5, 6, 8, 9, 8, 8, 4, 5, 6, 6, 6, 6, 6, 3, 3,
+ 3, 4, 3, 3, 3, 2, 2, 2, 0, 0, 1, 4, 6, 5, 4, 3, 2, 2, 4,
+ 11, 8, 6, 4, 3, 2, 4, 4, 5, 7, 9, 10, 11, 12, 3, 4, 8, 9, 9,
+ 10, 10, 3, 4, 7, 8, 8, 8, 8, 6, 3, 5, 6, 6, 6, 7, 8, 3, 5,
+ 7, 7, 6, 7, 11, 7, 9, 10, 8, 8, 7, 13, 11, 11, 12, 10, 9, 9, 3,
+ 8, 10, 11, 12, 13, 14, 6, 8, 11, 12, 13, 13, 13, 9, 8, 11, 12, 13, 12,
+ 13, 12, 8, 12, 12, 13, 13, 11, 11, 11, 14, 14, 15, 14, 14, 11, 16, 18, 18,
+ 16, 16, 16, 13, 20, 21, 20, 18, 17, 17, 13, 17, 18, 19, 19, 19, 15, 16, 18,
+ 19, 20, 21, 19, 13, 15, 19, 21, 21, 21, 19, 15, 16, 21, 22, 21, 22, 20, 15,
+ 15, 24, 25, 24, 24, 22, 17, 19, 27, 29, 28, 26, 23, 18, 22, 28, 32, 30, 29,
+ 25, 20, 26, 29, 28, 28, 26, 22, 17, 27, 31, 31, 30, 26, 22, 17, 26, 34, 33,
+ 32, 27, 22, 18, 26, 33, 34, 32, 27, 23, 18, 25, 32, 36, 35, 31, 25, 20, 27,
+ 35, 40, 39, 33, 28, 22, 30, 36, 41, 42, 35, 30, 24, 37, 42, 40, 34, 28, 24,
+ 20, 36, 43, 43, 35, 30, 23, 20, 36, 42, 45, 37, 31, 24, 20, 36, 41, 46, 39,
+ 32, 26, 22, 35, 40, 45, 42, 34, 30, 24, 35, 42, 47, 46, 38, 32, 25, 38, 43,
+ 48, 48, 41, 34, 27, 5, 6, 9, 12, 13, 10, 8, 5, 6, 8, 12, 12, 9, 6,
+ 4, 5, 7, 9, 10, 7, 3, 4, 4, 4, 6, 8, 5, 2, 2, 1, 1, 3, 6,
+ 4, 1, 3, 2, 2, 2, 4, 4, 1, 5, 3, 2, 2, 3, 4, 1, 4, 5, 7,
+ 10, 10, 9, 9, 4, 5, 6, 9, 9, 7, 7, 3, 4, 5, 7, 6, 5, 5, 3,
+ 3, 3, 3, 3, 3, 3, 2, 2, 1, 0, 0, 1, 3, 4, 3, 2, 2, 2, 1,
+ 3, 7, 4, 3, 2, 3, 2, 3, 4, 5, 7, 8, 10, 11, 11, 3, 4, 7, 9,
+ 9, 9, 9, 3, 4, 7, 7, 7, 7, 8, 7, 2, 4, 6, 6, 6, 6, 9, 2,
+ 5, 7, 7, 7, 6, 9, 4, 6, 9, 9, 8, 6, 9, 7, 7, 10, 9, 9, 9,
+ 3, 7, 11, 11, 12, 13, 14, 8, 7, 11, 12, 13, 13, 13, 11, 8, 12, 12, 13,
+ 12, 12, 12, 7, 12, 13, 13, 13, 11, 12, 10, 14, 14, 15, 15, 14, 10, 12, 15,
+ 16, 16, 16, 15, 9, 15, 18, 18, 17, 17, 17, 14, 17, 18, 19, 20, 20, 14, 16,
+ 18, 20, 20, 21, 19, 13, 16, 19, 21, 21, 21, 19, 15, 16, 21, 21, 22, 22, 20,
+ 16, 15, 24, 24, 24, 24, 22, 17, 16, 24, 28, 27, 26, 23, 18, 18, 27, 30, 28,
+ 27, 25, 20, 27, 30, 28, 28, 25, 22, 18, 26, 31, 30, 31, 27, 22, 17, 26, 34,
+ 33, 31, 26, 22, 18, 26, 32, 34, 32, 28, 23, 18, 25, 32, 37, 35, 31, 26, 20,
+ 26, 33, 39, 38, 32, 28, 22, 27, 34, 40, 40, 35, 29, 24, 37, 43, 40, 34, 30,
+ 24, 21, 37, 42, 43, 36, 30, 25, 20, 37, 42, 45, 36, 30, 26, 21, 36, 41, 46,
+ 38, 31, 27, 22, 35, 41, 44, 40, 34, 28, 24, 36, 42, 46, 45, 38, 31, 26, 35,
+ 41, 46, 45, 40, 33, 28, 4, 5, 6, 8, 8, 7, 6, 4, 4, 5, 8, 8, 5,
+ 4, 3, 4, 5, 6, 6, 4, 2, 3, 3, 3, 4, 6, 3, 1, 2, 1, 0, 2,
+ 5, 3, 1, 2, 2, 2, 3, 4, 3, 1, 4, 3, 2, 3, 3, 3, 1, 4, 4,
+ 5, 6, 6, 7, 8, 3, 4, 5, 6, 6, 6, 6, 3, 4, 4, 4, 3, 4, 4,
+ 2, 2, 2, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 2, 3, 2, 2, 2, 1,
+ 1, 2, 7, 4, 2, 2, 3, 2, 2, 3, 4, 6, 7, 8, 9, 10, 2, 3, 6,
+ 7, 7, 8, 9, 3, 3, 6, 6, 6, 6, 7, 7, 2, 4, 6, 6, 5, 5, 9,
+ 2, 4, 6, 7, 7, 5, 10, 4, 5, 7, 8, 8, 5, 9, 7, 6, 8, 9, 9,
+ 9, 3, 7, 10, 11, 12, 12, 13, 8, 7, 11, 12, 13, 12, 12, 12, 8, 12, 12,
+ 12, 12, 11, 14, 7, 11, 13, 13, 13, 10, 14, 10, 12, 14, 14, 14, 13, 11, 12,
+ 14, 15, 16, 16, 15, 9, 15, 16, 17, 17, 17, 17, 14, 17, 19, 19, 20, 19, 13,
+ 17, 18, 19, 20, 20, 19, 12, 17, 19, 20, 21, 20, 19, 15, 17, 21, 21, 21, 22,
+ 20, 15, 16, 22, 24, 24, 23, 22, 17, 15, 23, 26, 26, 24, 22, 18, 16, 24, 28,
+ 27, 26, 24, 20, 26, 29, 28, 28, 25, 21, 17, 26, 31, 30, 30, 26, 22, 17, 26,
+ 33, 32, 31, 26, 22, 17, 26, 32, 33, 32, 27, 23, 18, 25, 32, 35, 33, 30, 25,
+ 20, 26, 33, 38, 36, 30, 26, 21, 26, 33, 38, 39, 33, 27, 23, 36, 41, 38, 32,
+ 27, 24, 20, 35, 41, 42, 34, 29, 25, 20, 35, 41, 44, 36, 30, 25, 20, 35, 40,
+ 45, 37, 31, 26, 22, 35, 40, 44, 40, 33, 27, 23, 34, 40, 44, 43, 36, 30, 25,
+ 35, 40, 45, 45, 37, 31, 25, 4, 6, 9, 11, 10, 9, 6, 4, 6, 8, 10, 10,
+ 7, 4, 3, 5, 7, 8, 9, 6, 4, 3, 3, 5, 7, 8, 5, 3, 1, 0, 3,
+ 5, 7, 5, 3, 2, 2, 4, 5, 7, 5, 3, 4, 3, 3, 4, 6, 5, 3, 4,
+ 5, 7, 9, 8, 7, 6, 3, 4, 6, 8, 7, 5, 4, 3, 4, 5, 6, 5, 3,
+ 2, 2, 2, 4, 5, 4, 3, 0, 1, 1, 2, 3, 3, 2, 0, 3, 2, 3, 4,
+ 2, 2, 0, 6, 4, 3, 3, 2, 1, 0, 3, 4, 4, 5, 7, 8, 8, 2, 3,
+ 5, 6, 6, 6, 6, 2, 3, 5, 4, 4, 4, 5, 3, 2, 3, 3, 3, 3, 3,
+ 6, 2, 4, 4, 4, 4, 3, 7, 4, 5, 5, 5, 5, 3, 9, 7, 6, 6, 6,
+ 6, 6, 2, 7, 8, 9, 9, 10, 11, 3, 7, 9, 9, 10, 10, 9, 8, 7, 9,
+ 9, 10, 9, 8, 11, 7, 10, 10, 9, 10, 7, 10, 9, 11, 11, 12, 11, 10, 8,
+ 11, 13, 13, 13, 13, 12, 8, 14, 15, 15, 14, 14, 13, 13, 15, 16, 16, 16, 16,
+ 11, 14, 17, 17, 17, 18, 16, 10, 14, 18, 18, 18, 18, 16, 12, 14, 20, 19, 18,
+ 18, 17, 13, 14, 21, 21, 20, 20, 18, 14, 15, 22, 24, 23, 21, 19, 15, 16, 23,
+ 26, 24, 24, 20, 17, 24, 25, 24, 24, 21, 18, 14, 24, 28, 27, 25, 22, 18, 14,
+ 24, 30, 29, 27, 22, 19, 15, 23, 29, 30, 27, 23, 20, 15, 23, 29, 32, 30, 26,
+ 22, 17, 24, 30, 36, 33, 28, 23, 18, 25, 30, 35, 35, 29, 25, 20, 32, 37, 34,
+ 29, 23, 20, 17, 32, 37, 36, 30, 25, 21, 17, 33, 37, 39, 31, 26, 22, 17, 32,
+ 37, 40, 33, 27, 23, 18, 31, 38, 39, 36, 29, 25, 20, 31, 36, 40, 39, 32, 26,
+ 20, 32, 36, 41, 40, 34, 28, 23, 10, 12, 14, 17, 18, 16, 13, 10, 11, 13, 17,
+ 17, 14, 12, 9, 11, 12, 14, 15, 12, 10, 9, 9, 10, 11, 14, 9, 4, 6, 7,
+ 7, 8, 8, 7, 4, 2, 2, 3, 3, 6, 7, 4, 5, 4, 2, 3, 5, 8, 4,
+ 9, 11, 12, 15, 15, 14, 12, 9, 10, 12, 14, 14, 12, 11, 8, 10, 11, 12, 12,
+ 11, 9, 8, 8, 9, 9, 9, 8, 3, 5, 5, 5, 5, 4, 4, 3, 0, 2, 2,
+ 2, 3, 3, 3, 8, 6, 3, 2, 2, 3, 3, 8, 10, 11, 11, 13, 13, 12, 8,
+ 9, 11, 11, 12, 12, 11, 7, 8, 10, 10, 10, 10, 9, 7, 7, 7, 7, 8, 7,
+ 4, 3, 3, 4, 4, 3, 3, 3, 3, 2, 2, 1, 2, 2, 3, 9, 9, 5, 2,
+ 1, 3, 3, 7, 9, 10, 11, 12, 13, 13, 7, 8, 10, 11, 12, 12, 12, 6, 8,
+ 9, 10, 10, 10, 10, 4, 7, 7, 7, 7, 7, 5, 2, 3, 4, 4, 4, 4, 5,
+ 3, 8, 7, 7, 6, 6, 6, 9, 13, 11, 9, 7, 7, 8, 7, 8, 9, 11, 12,
+ 13, 13, 8, 9, 9, 10, 11, 11, 12, 8, 10, 11, 11, 11, 9, 9, 9, 12, 12,
+ 11, 12, 11, 6, 8, 13, 13, 14, 14, 13, 8, 9, 15, 16, 15, 15, 15, 10, 13,
+ 17, 18, 16, 16, 16, 12, 16, 18, 19, 19, 15, 12, 13, 16, 20, 20, 20, 16, 12,
+ 11, 16, 22, 22, 21, 18, 12, 9, 16, 21, 21, 21, 19, 14, 10, 15, 21, 22, 21,
+ 18, 16, 12, 16, 20, 22, 21, 19, 16, 13, 17, 21, 23, 22, 20, 17, 15, 24, 28,
+ 27, 23, 18, 14, 12, 24, 28, 28, 24, 20, 15, 10, 24, 28, 30, 23, 21, 16, 11,
+ 24, 27, 29, 25, 20, 18, 13, 22, 26, 28, 25, 20, 18, 15, 22, 25, 27, 26, 20,
+ 18, 16, 22, 24, 27, 28, 22, 19, 16, 9, 11, 12, 13, 13, 13, 12, 9, 10, 12,
+ 13, 13, 11, 10, 8, 10, 11, 11, 11, 10, 8, 8, 8, 9, 9, 9, 6, 3, 5,
+ 6, 6, 6, 4, 3, 2, 2, 2, 2, 2, 3, 3, 3, 4, 3, 2, 2, 3, 3,
+ 3, 8, 10, 11, 12, 13, 13, 12, 8, 9, 10, 12, 12, 11, 10, 7, 9, 10, 10,
+ 10, 9, 7, 7, 7, 7, 8, 7, 6, 2, 5, 4, 4, 5, 3, 2, 2, 2, 0,
+ 1, 2, 2, 2, 2, 7, 5, 2, 2, 2, 2, 2, 8, 9, 10, 11, 12, 13, 13,
+ 7, 8, 10, 11, 11, 11, 11, 7, 8, 9, 9, 9, 9, 8, 7, 7, 6, 6, 7,
+ 6, 4, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 9, 8, 5,
+ 3, 3, 3, 4, 7, 9, 10, 11, 13, 14, 14, 7, 9, 10, 11, 12, 12, 12, 5,
+ 9, 10, 10, 10, 10, 9, 6, 8, 7, 7, 8, 7, 7, 4, 6, 7, 7, 7, 7,
+ 8, 3, 10, 10, 9, 9, 9, 9, 9, 16, 13, 11, 10, 10, 11, 10, 11, 11, 12,
+ 13, 14, 14, 10, 12, 13, 13, 14, 12, 12, 11, 14, 14, 14, 14, 12, 9, 11, 15,
+ 15, 15, 15, 13, 9, 10, 17, 16, 16, 17, 15, 11, 12, 18, 20, 18, 18, 16, 12,
+ 16, 21, 23, 20, 20, 18, 14, 19, 21, 21, 21, 18, 15, 14, 20, 23, 23, 23, 19,
+ 15, 12, 19, 25, 25, 24, 20, 15, 11, 19, 25, 26, 25, 21, 17, 12, 18, 23, 29,
+ 27, 23, 18, 14, 19, 25, 31, 30, 25, 20, 15, 21, 27, 32, 32, 27, 22, 17, 29,
+ 34, 33, 27, 21, 17, 14, 28, 34, 36, 29, 23, 18, 13, 28, 34, 39, 30, 24, 19,
+ 14, 28, 34, 38, 30, 25, 20, 15, 27, 33, 39, 35, 28, 22, 17, 26, 32, 37, 37,
+ 29, 24, 18, 27, 33, 36, 37, 32, 26, 20, 9, 11, 12, 13, 13, 13, 12, 9, 10,
+ 11, 13, 13, 11, 10, 8, 9, 11, 11, 10, 9, 7, 8, 8, 8, 9, 8, 6, 2,
+ 6, 5, 5, 5, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1, 2, 2,
+ 2, 2, 8, 10, 11, 12, 13, 13, 13, 8, 9, 10, 12, 12, 11, 10, 8, 8, 10,
+ 10, 9, 9, 7, 8, 7, 7, 7, 7, 5, 3, 5, 4, 4, 4, 2, 2, 2, 2,
+ 1, 0, 2, 2, 2, 2, 6, 4, 2, 1, 2, 2, 3, 8, 9, 10, 11, 13, 14,
+ 15, 8, 8, 10, 12, 12, 12, 12, 7, 8, 10, 10, 10, 10, 9, 6, 7, 8, 8,
+ 8, 6, 5, 4, 3, 5, 5, 4, 4, 5, 5, 3, 5, 4, 4, 4, 5, 7, 6,
+ 7, 6, 5, 5, 5, 8, 11, 12, 13, 14, 16, 15, 6, 10, 12, 13, 14, 14, 13,
+ 6, 10, 12, 11, 11, 11, 10, 9, 9, 9, 9, 9, 9, 9, 7, 7, 9, 10, 10,
+ 10, 11, 5, 12, 12, 12, 12, 12, 12, 7, 15, 15, 14, 13, 13, 13, 11, 14, 15,
+ 15, 16, 16, 16, 13, 15, 16, 16, 16, 15, 13, 12, 16, 17, 17, 17, 15, 12, 13,
+ 18, 18, 18, 18, 17, 13, 12, 19, 19, 19, 19, 18, 13, 13, 22, 23, 22, 20, 19,
+ 15, 17, 22, 26, 24, 22, 21, 16, 22, 24, 25, 24, 22, 18, 16, 22, 26, 26, 27,
+ 23, 18, 13, 22, 29, 28, 27, 23, 18, 14, 22, 27, 28, 28, 24, 19, 15, 22, 28,
+ 31, 31, 26, 21, 16, 22, 28, 34, 32, 27, 22, 18, 24, 29, 35, 36, 30, 24, 20,
+ 32, 38, 37, 29, 24, 21, 16, 31, 38, 38, 32, 26, 21, 16, 31, 37, 41, 32, 27,
+ 21, 17, 31, 37, 42, 34, 28, 23, 18, 30, 35, 42, 38, 30, 24, 19, 29, 35, 41,
+ 40, 33, 26, 21, 30, 36, 40, 41, 34, 28, 22, 8, 9, 11, 12, 13, 12, 11, 8,
+ 9, 11, 12, 12, 11, 9, 7, 8, 10, 10, 10, 8, 6, 7, 7, 7, 8, 8, 5,
+ 2, 5, 4, 4, 5, 3, 2, 2, 2, 2, 1, 2, 2, 2, 2, 3, 2, 1, 1,
+ 2, 2, 2, 8, 8, 10, 12, 12, 12, 13, 7, 8, 9, 11, 12, 10, 10, 7, 8,
+ 9, 10, 9, 8, 8, 6, 6, 6, 7, 6, 5, 4, 4, 3, 3, 3, 2, 2, 4,
+ 2, 2, 2, 0, 1, 2, 4, 5, 3, 2, 1, 2, 3, 4, 7, 8, 10, 11, 13,
+ 14, 15, 6, 7, 10, 12, 12, 13, 12, 6, 7, 10, 10, 10, 10, 10, 5, 6, 7,
+ 8, 8, 7, 6, 6, 2, 4, 5, 5, 6, 6, 7, 2, 5, 6, 6, 7, 6, 6,
+ 5, 6, 8, 7, 8, 8, 6, 10, 12, 13, 14, 16, 15, 5, 10, 12, 13, 14, 14,
+ 13, 8, 10, 12, 12, 12, 12, 11, 11, 8, 11, 11, 11, 12, 11, 10, 8, 12, 12,
+ 12, 13, 13, 8, 11, 14, 14, 14, 14, 14, 6, 14, 15, 16, 15, 15, 16, 13, 16,
+ 17, 18, 19, 18, 15, 15, 18, 19, 19, 19, 18, 13, 15, 18, 20, 19, 20, 18, 14,
+ 14, 20, 21, 20, 21, 20, 15, 14, 21, 22, 22, 22, 20, 16, 14, 23, 25, 24, 24,
+ 22, 17, 16, 23, 27, 26, 25, 23, 19, 25, 27, 27, 27, 24, 21, 17, 25, 31, 29,
+ 30, 25, 20, 16, 25, 31, 31, 30, 26, 21, 16, 25, 31, 32, 31, 27, 22, 18, 23,
+ 31, 34, 33, 29, 24, 18, 24, 31, 36, 34, 31, 25, 20, 26, 32, 37, 38, 33, 27,
+ 22, 35, 40, 40, 33, 27, 23, 19, 35, 41, 42, 34, 29, 24, 19, 35, 40, 44, 36,
+ 30, 25, 19, 35, 41, 45, 37, 31, 26, 20, 33, 39, 44, 40, 33, 27, 23, 33, 39,
+ 45, 42, 35, 30, 23, 33, 39, 44, 44, 38, 30, 25, 6, 8, 11, 14, 14, 12, 9,
+ 6, 7, 10, 13, 13, 11, 7, 5, 6, 9, 11, 12, 9, 5, 5, 5, 6, 8, 10,
+ 7, 2, 2, 2, 2, 5, 7, 5, 2, 2, 1, 1, 2, 5, 5, 2, 3, 2, 2,
+ 2, 4, 5, 2, 5, 6, 8, 11, 11, 10, 10, 5, 6, 7, 10, 11, 8, 8, 4,
+ 5, 6, 8, 8, 6, 6, 4, 4, 4, 5, 5, 3, 2, 2, 1, 1, 2, 2, 1,
+ 2, 3, 2, 2, 1, 0, 1, 2, 6, 3, 2, 2, 1, 1, 2, 5, 6, 8, 9,
+ 10, 11, 12, 4, 5, 8, 9, 10, 10, 9, 3, 5, 8, 8, 8, 8, 7, 5, 3,
+ 5, 5, 5, 5, 5, 8, 2, 4, 5, 6, 6, 5, 9, 3, 5, 7, 7, 7, 5,
+ 8, 6, 6, 8, 8, 8, 8, 3, 8, 10, 10, 11, 13, 14, 6, 8, 10, 11, 12,
+ 12, 13, 10, 8, 11, 12, 12, 12, 11, 12, 7, 11, 12, 11, 12, 10, 12, 8, 12,
+ 13, 13, 13, 13, 9, 11, 13, 14, 14, 14, 15, 8, 14, 16, 16, 15, 15, 16, 13,
+ 16, 17, 18, 20, 18, 14, 15, 17, 19, 19, 20, 19, 12, 15, 19, 20, 20, 20, 19,
+ 14, 15, 20, 20, 21, 21, 19, 14, 14, 21, 22, 22, 22, 20, 16, 14, 23, 25, 24,
+ 23, 22, 17, 16, 24, 28, 26, 27, 24, 19, 26, 29, 27, 28, 24, 21, 16, 25, 30,
+ 29, 29, 26, 21, 17, 25, 33, 33, 31, 26, 22, 17, 25, 32, 33, 31, 27, 23, 17,
+ 25, 31, 35, 33, 28, 24, 18, 25, 32, 36, 36, 30, 24, 20, 26, 32, 38, 39, 33,
+ 27, 22, 35, 41, 39, 33, 28, 23, 19, 36, 41, 42, 35, 29, 24, 19, 36, 40, 45,
+ 36, 30, 24, 20, 35, 40, 45, 37, 31, 25, 21, 34, 40, 44, 40, 33, 27, 22, 34,
+ 39, 43, 43, 35, 29, 23, 35, 39, 44, 44, 38, 31, 25, 4, 6, 10, 12, 13, 11,
+ 8, 4, 5, 9, 12, 12, 9, 6, 4, 5, 7, 10, 10, 8, 4, 3, 3, 4, 7,
+ 9, 6, 2, 1, 1, 1, 4, 6, 4, 2, 2, 2, 2, 3, 5, 4, 2, 4, 3,
+ 2, 2, 4, 5, 2, 4, 5, 7, 10, 10, 8, 8, 4, 5, 6, 9, 9, 6, 6,
+ 3, 4, 5, 7, 7, 4, 4, 3, 2, 2, 4, 4, 2, 2, 2, 2, 1, 2, 1,
+ 1, 2, 3, 2, 2, 2, 1, 0, 2, 6, 4, 2, 2, 2, 1, 2, 3, 4, 6,
+ 7, 8, 10, 10, 3, 4, 6, 7, 8, 8, 8, 2, 3, 6, 6, 6, 6, 7, 6,
+ 2, 4, 5, 5, 5, 5, 8, 2, 4, 6, 6, 6, 5, 9, 4, 5, 7, 7, 7,
+ 5, 8, 7, 6, 8, 8, 8, 8, 2, 7, 10, 10, 11, 12, 13, 7, 7, 11, 11,
+ 12, 12, 12, 11, 7, 11, 12, 11, 12, 10, 12, 7, 11, 12, 12, 12, 10, 12, 9,
+ 13, 13, 13, 13, 13, 9, 11, 14, 14, 15, 15, 14, 9, 14, 16, 17, 16, 16, 16,
+ 13, 16, 18, 18, 18, 18, 13, 15, 17, 19, 20, 20, 18, 12, 15, 19, 20, 20, 20,
+ 18, 14, 15, 20, 21, 21, 20, 19, 15, 15, 22, 23, 22, 23, 21, 16, 15, 23, 27,
+ 24, 24, 21, 18, 16, 24, 28, 27, 25, 23, 19, 25, 28, 27, 27, 25, 20, 16, 26,
+ 30, 29, 29, 25, 21, 16, 25, 32, 32, 31, 26, 21, 17, 26, 32, 33, 31, 26, 22,
+ 18, 24, 31, 35, 33, 29, 23, 19, 25, 32, 37, 35, 30, 25, 21, 25, 32, 37, 38,
+ 32, 27, 22, 35, 40, 39, 32, 27, 23, 19, 36, 40, 41, 34, 27, 24, 19, 35, 39,
+ 43, 35, 30, 24, 19, 36, 39, 44, 36, 31, 26, 21, 34, 39, 44, 38, 32, 27, 23,
+ 34, 39, 43, 42, 35, 29, 24, 34, 40, 43, 44, 37, 30, 25, 4, 6, 8, 11, 11,
+ 9, 6, 4, 6, 8, 10, 10, 7, 4, 3, 5, 7, 8, 9, 6, 4, 3, 3, 5,
+ 7, 8, 5, 3, 1, 0, 3, 5, 7, 5, 3, 2, 2, 4, 4, 7, 5, 3, 4,
+ 3, 3, 4, 6, 5, 3, 4, 5, 7, 9, 8, 6, 6, 3, 4, 6, 8, 7, 5,
+ 4, 3, 4, 5, 7, 5, 4, 2, 2, 2, 4, 5, 4, 3, 0, 1, 1, 2, 4,
+ 3, 2, 0, 3, 2, 3, 4, 2, 2, 0, 7, 4, 3, 3, 3, 1, 0, 3, 4,
+ 5, 5, 7, 8, 8, 2, 3, 5, 6, 6, 6, 6, 2, 3, 5, 4, 4, 4, 5,
+ 3, 2, 3, 3, 2, 3, 3, 6, 2, 4, 4, 4, 4, 3, 7, 4, 5, 5, 5,
+ 5, 3, 8, 7, 6, 6, 6, 6, 6, 2, 7, 8, 8, 9, 10, 11, 3, 7, 9,
+ 9, 10, 10, 10, 9, 7, 10, 9, 10, 10, 8, 11, 7, 10, 10, 9, 10, 7, 10,
+ 9, 11, 11, 12, 11, 11, 7, 11, 13, 12, 13, 13, 12, 8, 14, 15, 14, 14, 14,
+ 14, 12, 16, 16, 16, 17, 16, 11, 14, 16, 17, 17, 18, 16, 10, 15, 18, 18, 18,
+ 17, 16, 12, 14, 20, 19, 19, 19, 17, 12, 14, 21, 21, 21, 20, 18, 14, 15, 22,
+ 24, 22, 21, 19, 15, 16, 23, 26, 25, 23, 21, 17, 24, 26, 24, 25, 21, 18, 14,
+ 24, 28, 26, 25, 22, 18, 14, 24, 30, 29, 27, 23, 19, 14, 24, 29, 30, 28, 25,
+ 19, 15, 23, 29, 32, 30, 25, 21, 17, 24, 30, 35, 32, 27, 23, 18, 25, 30, 35,
+ 35, 30, 25, 20, 32, 37, 35, 28, 24, 21, 16, 32, 37, 38, 31, 25, 20, 17, 33,
+ 37, 39, 32, 27, 22, 17, 32, 37, 40, 33, 27, 22, 18, 31, 36, 41, 37, 30, 24,
+ 20, 31, 35, 40, 40, 32, 26, 21, 32, 37, 40, 41, 34, 28, 23, 17, 19, 20, 23,
+ 22, 21, 20, 17, 19, 20, 22, 22, 20, 18, 16, 18, 19, 19, 20, 17, 14, 16, 16,
+ 16, 17, 17, 12, 7, 13, 13, 13, 12, 10, 10, 7, 9, 9, 7, 6, 8, 9, 7,
+ 3, 3, 4, 6, 7, 9, 7, 16, 18, 19, 21, 21, 21, 20, 15, 18, 19, 20, 20,
+ 19, 17, 15, 17, 18, 19, 18, 17, 14, 14, 15, 15, 16, 14, 11, 7, 12, 12, 12,
+ 11, 7, 7, 7, 8, 7, 6, 5, 6, 6, 6, 0, 2, 4, 4, 5, 6, 6, 15,
+ 17, 18, 19, 21, 21, 20, 14, 16, 17, 19, 19, 19, 17, 15, 16, 17, 17, 17, 16,
+ 13, 15, 14, 14, 14, 13, 11, 6, 10, 10, 10, 9, 5, 6, 6, 3, 5, 5, 4,
+ 5, 6, 6, 2, 2, 2, 4, 5, 5, 6, 15, 16, 17, 18, 20, 21, 21, 14, 16,
+ 18, 19, 19, 19, 19, 12, 16, 17, 17, 17, 16, 15, 9, 15, 14, 14, 13, 10, 10,
+ 6, 11, 10, 9, 5, 5, 7, 4, 4, 4, 4, 4, 5, 6, 2, 7, 5, 5, 5,
+ 5, 6, 14, 15, 17, 19, 19, 21, 21, 12, 15, 16, 18, 19, 18, 19, 11, 14, 15,
+ 15, 16, 15, 14, 12, 12, 12, 12, 11, 10, 6, 9, 10, 10, 10, 11, 11, 6, 6,
+ 11, 13, 12, 12, 12, 7, 7, 12, 14, 13, 13, 12, 9, 13, 15, 16, 17, 17, 19,
+ 21, 13, 17, 17, 18, 16, 17, 18, 13, 19, 18, 18, 14, 14, 13, 13, 18, 19, 18,
+ 16, 11, 8, 12, 17, 19, 18, 15, 12, 9, 12, 16, 19, 17, 15, 13, 11, 13, 15,
+ 18, 18, 16, 14, 12, 21, 25, 24, 21, 16, 18, 19, 21, 25, 25, 21, 17, 16, 16,
+ 21, 24, 26, 22, 18, 13, 12, 21, 23, 25, 21, 18, 14, 11, 19, 21, 24, 20, 16,
+ 14, 12, 18, 21, 22, 21, 16, 15, 13, 17, 19, 22, 22, 18, 15, 13, 15, 16, 17,
+ 19, 18, 18, 17, 14, 16, 17, 18, 18, 17, 15, 13, 15, 16, 16, 16, 14, 11, 13,
+ 14, 14, 13, 12, 9, 5, 11, 11, 10, 9, 6, 5, 4, 7, 7, 5, 4, 5, 5,
+ 5, 2, 2, 2, 3, 5, 5, 4, 14, 15, 16, 18, 18, 18, 17, 14, 15, 16, 17,
+ 18, 16, 14, 13, 14, 15, 16, 15, 13, 10, 13, 12, 13, 12, 11, 9, 4, 10, 9,
+ 9, 8, 4, 4, 4, 6, 5, 4, 3, 3, 4, 4, 2, 0, 2, 2, 3, 4, 4,
+ 13, 14, 15, 16, 18, 18, 18, 13, 13, 15, 16, 16, 16, 15, 13, 13, 14, 14, 14,
+ 13, 11, 12, 12, 11, 11, 10, 8, 5, 8, 8, 8, 8, 3, 4, 4, 3, 4, 4,
+ 3, 3, 4, 4, 2, 2, 1, 2, 3, 4, 5, 13, 15, 15, 17, 19, 19, 19, 12,
+ 15, 16, 17, 17, 18, 16, 10, 15, 15, 15, 15, 14, 13, 7, 14, 13, 13, 12, 9,
+ 9, 5, 10, 9, 8, 6, 6, 7, 3, 6, 6, 7, 7, 7, 8, 2, 9, 9, 8,
+ 8, 9, 9, 13, 14, 15, 17, 18, 19, 20, 11, 14, 15, 16, 17, 17, 17, 12, 13,
+ 14, 14, 15, 14, 12, 11, 13, 12, 12, 13, 12, 8, 9, 13, 14, 14, 14, 14, 9,
+ 8, 15, 16, 17, 16, 15, 11, 10, 16, 19, 19, 19, 17, 12, 16, 19, 19, 20, 17,
+ 18, 19, 16, 21, 21, 21, 18, 16, 16, 16, 23, 23, 22, 18, 14, 12, 17, 22, 24,
+ 23, 19, 15, 11, 15, 22, 25, 25, 22, 17, 12, 16, 22, 28, 28, 24, 19, 14, 17,
+ 23, 28, 29, 25, 21, 16, 26, 32, 31, 24, 20, 17, 18, 25, 31, 33, 26, 21, 16,
+ 15, 26, 31, 35, 27, 22, 17, 12, 25, 31, 36, 29, 23, 18, 14, 24, 30, 35, 32,
+ 25, 21, 15, 24, 31, 35, 33, 28, 23, 17, 24, 31, 35, 33, 29, 24, 19, 11, 12,
+ 14, 15, 15, 15, 14, 10, 12, 13, 15, 14, 13, 11, 10, 11, 13, 13, 12, 10, 8,
+ 10, 10, 10, 10, 9, 6, 3, 7, 7, 7, 6, 4, 3, 2, 4, 3, 3, 2, 3,
+ 3, 2, 2, 1, 1, 2, 3, 3, 2, 10, 11, 13, 14, 15, 14, 14, 10, 11, 12,
+ 13, 14, 12, 12, 10, 10, 11, 12, 11, 10, 8, 10, 9, 9, 9, 8, 6, 3, 7,
+ 6, 6, 6, 3, 2, 3, 3, 2, 2, 2, 2, 2, 3, 4, 2, 0, 2, 2, 2,
+ 3, 10, 10, 11, 13, 14, 16, 16, 10, 10, 12, 13, 13, 14, 14, 10, 10, 11, 12,
+ 11, 11, 10, 9, 8, 9, 9, 9, 6, 5, 4, 5, 6, 6, 4, 3, 5, 3, 2,
+ 3, 3, 3, 4, 5, 4, 3, 4, 4, 4, 5, 5, 10, 13, 13, 14, 16, 17, 17,
+ 8, 12, 13, 14, 15, 15, 14, 6, 12, 13, 13, 13, 12, 11, 8, 11, 10, 10, 10,
+ 9, 9, 6, 7, 8, 9, 9, 10, 9, 4, 9, 10, 10, 11, 11, 11, 4, 12, 12,
+ 12, 12, 12, 12, 11, 13, 14, 15, 16, 17, 17, 11, 14, 15, 15, 16, 15, 14, 11,
+ 15, 16, 16, 16, 14, 11, 11, 17, 17, 16, 17, 15, 11, 11, 18, 17, 18, 18, 17,
+ 12, 12, 19, 21, 20, 20, 18, 14, 14, 20, 23, 21, 22, 20, 16, 21, 23, 23, 23,
+ 20, 17, 17, 21, 25, 25, 25, 21, 17, 14, 21, 28, 27, 26, 22, 17, 13, 21, 25,
+ 29, 27, 22, 19, 14, 20, 27, 31, 29, 25, 20, 15, 20, 26, 33, 32, 26, 21, 17,
+ 22, 27, 32, 34, 29, 24, 18, 30, 35, 35, 28, 23, 19, 16, 30, 36, 38, 31, 24,
+ 19, 15, 30, 36, 39, 32, 26, 20, 15, 30, 35, 40, 32, 27, 22, 17, 28, 35, 40,
+ 35, 29, 23, 19, 28, 35, 40, 38, 30, 26, 20, 29, 35, 40, 41, 33, 28, 21, 9,
+ 10, 12, 13, 13, 13, 12, 8, 9, 11, 13, 13, 11, 9, 8, 9, 11, 11, 11, 9,
+ 7, 8, 7, 8, 9, 8, 5, 2, 5, 5, 5, 5, 4, 2, 2, 2, 2, 1, 2,
+ 3, 2, 2, 3, 2, 1, 2, 2, 2, 2, 8, 9, 11, 12, 13, 12, 13, 8, 9,
+ 10, 12, 12, 10, 10, 7, 8, 9, 10, 10, 8, 8, 7, 7, 7, 8, 7, 5, 4,
+ 5, 4, 3, 4, 3, 2, 3, 2, 2, 1, 1, 2, 2, 3, 4, 2, 2, 0, 1,
+ 2, 3, 8, 8, 10, 11, 13, 14, 14, 7, 8, 10, 12, 12, 12, 12, 7, 7, 10,
+ 10, 10, 10, 9, 5, 6, 8, 8, 8, 6, 6, 5, 3, 5, 5, 5, 5, 6, 6,
+ 2, 5, 5, 5, 6, 6, 5, 4, 5, 7, 7, 7, 7, 7, 11, 12, 13, 14, 16,
+ 15, 5, 10, 12, 14, 13, 13, 13, 7, 10, 11, 11, 12, 12, 11, 10, 9, 10, 11,
+ 11, 11, 10, 9, 8, 11, 11, 12, 12, 12, 7, 10, 13, 13, 13, 13, 14, 5, 13,
+ 14, 15, 14, 14, 15, 12, 15, 16, 17, 18, 17, 15, 14, 16, 18, 18, 19, 17, 13,
+ 14, 17, 19, 19, 18, 17, 13, 14, 20, 19, 19, 20, 18, 14, 13, 21, 21, 20, 20,
+ 19, 15, 14, 22, 23, 23, 22, 21, 17, 16, 22, 26, 25, 25, 23, 18, 24, 27, 26,
+ 26, 23, 19, 16, 24, 29, 28, 28, 24, 21, 15, 24, 31, 31, 29, 26, 20, 16, 24,
+ 30, 31, 30, 27, 21, 17, 23, 30, 33, 31, 27, 22, 18, 23, 30, 35, 34, 29, 24,
+ 19, 25, 30, 35, 36, 32, 27, 21, 33, 40, 39, 32, 26, 22, 18, 34, 40, 42, 34,
+ 28, 23, 18, 33, 40, 43, 35, 29, 23, 18, 34, 40, 44, 36, 30, 25, 19, 32, 38,
+ 44, 39, 32, 26, 21, 33, 38, 43, 42, 34, 28, 23, 32, 39, 42, 43, 36, 30, 24,
+ 7, 9, 13, 15, 15, 14, 10, 6, 8, 11, 15, 15, 12, 9, 6, 7, 10, 12, 13,
+ 10, 7, 6, 5, 7, 10, 11, 8, 4, 3, 3, 4, 6, 8, 6, 3, 1, 1, 2,
+ 3, 6, 6, 3, 3, 2, 2, 2, 5, 6, 3, 6, 7, 10, 13, 13, 10, 10, 6,
+ 7, 9, 12, 12, 9, 8, 5, 6, 8, 10, 10, 7, 6, 5, 5, 5, 7, 6, 5,
+ 3, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 1, 2, 3, 5, 3, 2, 1,
+ 0, 1, 2, 5, 6, 8, 9, 11, 12, 12, 5, 6, 8, 9, 10, 10, 10, 4, 5,
+ 8, 8, 8, 8, 8, 4, 4, 5, 6, 6, 5, 5, 6, 2, 3, 4, 4, 4, 4,
+ 8, 3, 4, 5, 5, 5, 5, 7, 5, 5, 7, 7, 7, 7, 5, 8, 10, 10, 12,
+ 13, 13, 4, 8, 10, 11, 11, 11, 11, 7, 8, 10, 10, 10, 10, 10, 10, 7, 10,
+ 11, 11, 11, 9, 10, 8, 11, 11, 12, 11, 12, 8, 10, 13, 13, 13, 13, 13, 7,
+ 13, 15, 15, 15, 14, 15, 12, 16, 16, 17, 18, 17, 14, 14, 16, 18, 18, 19, 17,
+ 12, 14, 18, 19, 19, 18, 17, 13, 14, 19, 19, 19, 19, 18, 13, 13, 21, 21, 21,
+ 21, 19, 15, 13, 22, 23, 23, 22, 20, 16, 15, 23, 26, 25, 24, 22, 18, 24, 27,
+ 26, 26, 23, 19, 15, 24, 30, 28, 28, 25, 20, 15, 24, 31, 30, 29, 24, 20, 16,
+ 25, 31, 31, 30, 25, 21, 16, 24, 30, 34, 32, 27, 23, 17, 24, 30, 36, 35, 28,
+ 23, 20, 24, 31, 35, 36, 31, 26, 20, 34, 39, 39, 32, 26, 21, 18, 34, 40, 39,
+ 33, 28, 23, 18, 34, 41, 43, 35, 28, 23, 18, 33, 39, 44, 35, 30, 24, 19, 32,
+ 39, 42, 39, 31, 26, 20, 32, 39, 43, 41, 34, 28, 23, 32, 38, 42, 43, 36, 30,
+ 24, 5, 8, 11, 15, 15, 13, 9, 5, 7, 10, 14, 14, 11, 7, 4, 5, 9, 11,
+ 13, 9, 6, 4, 4, 6, 8, 11, 7, 3, 1, 1, 2, 5, 8, 6, 3, 2, 2,
+ 2, 3, 6, 6, 3, 4, 3, 2, 3, 5, 6, 3, 4, 5, 9, 12, 12, 9, 9,
+ 4, 5, 8, 11, 11, 8, 7, 3, 5, 6, 8, 8, 6, 4, 3, 3, 3, 6, 5,
+ 4, 1, 2, 1, 1, 2, 2, 2, 1, 3, 2, 2, 3, 1, 1, 1, 7, 4, 2,
+ 2, 1, 0, 1, 4, 5, 6, 7, 9, 10, 10, 3, 4, 7, 7, 8, 8, 8, 3,
+ 4, 6, 6, 6, 6, 6, 4, 2, 4, 4, 4, 4, 4, 7, 2, 4, 5, 5, 4,
+ 4, 8, 3, 5, 6, 6, 6, 4, 8, 6, 6, 7, 7, 7, 7, 3, 7, 9, 9,
+ 10, 11, 12, 5, 7, 10, 10, 11, 11, 11, 8, 7, 10, 10, 10, 11, 10, 11, 7,
+ 10, 11, 11, 11, 8, 10, 9, 11, 12, 12, 12, 12, 8, 11, 13, 13, 14, 13, 13,
+ 8, 14, 15, 15, 14, 14, 15, 13, 16, 16, 17, 18, 17, 12, 15, 16, 17, 18, 19,
+ 17, 11, 15, 18, 19, 19, 19, 18, 13, 15, 20, 20, 20, 20, 18, 13, 14, 21, 21,
+ 21, 21, 19, 15, 14, 22, 25, 23, 22, 21, 16, 16, 24, 27, 25, 25, 23, 18, 24,
+ 28, 27, 26, 23, 19, 15, 24, 29, 28, 27, 24, 19, 15, 24, 32, 31, 29, 25, 20,
+ 16, 24, 31, 31, 29, 26, 21, 16, 23, 29, 33, 31, 27, 22, 18, 24, 30, 37, 34,
+ 28, 24, 19, 25, 30, 37, 36, 31, 26, 21, 34, 39, 37, 31, 26, 22, 18, 35, 40,
+ 39, 33, 27, 22, 18, 34, 39, 42, 34, 29, 24, 18, 34, 37, 42, 34, 29, 24, 19,
+ 33, 38, 42, 37, 31, 26, 21, 34, 38, 41, 41, 34, 27, 23, 33, 38, 42, 42, 35,
+ 28, 24, 4, 6, 8, 11, 11, 9, 6, 4, 6, 8, 10, 10, 7, 4, 3, 5, 7,
+ 8, 9, 6, 4, 3, 3, 5, 6, 8, 5, 3, 1, 0, 3, 5, 8, 5, 3, 2,
+ 2, 4, 5, 7, 5, 3, 4, 3, 3, 4, 6, 5, 3, 4, 5, 7, 9, 8, 7,
+ 6, 3, 4, 6, 8, 7, 5, 4, 3, 4, 5, 7, 5, 4, 2, 2, 2, 3, 5,
+ 4, 3, 0, 1, 1, 2, 4, 3, 2, 0, 3, 2, 3, 4, 2, 2, 0, 7, 4,
+ 3, 3, 3, 1, 0, 3, 4, 5, 5, 7, 8, 8, 2, 3, 5, 6, 6, 6, 6,
+ 2, 3, 5, 4, 4, 4, 5, 3, 2, 3, 3, 3, 3, 3, 5, 2, 4, 4, 4,
+ 4, 3, 7, 4, 5, 5, 5, 5, 3, 8, 7, 6, 6, 6, 6, 6, 2, 7, 8,
+ 9, 9, 10, 11, 3, 7, 9, 9, 10, 10, 9, 9, 7, 10, 9, 9, 10, 8, 11,
+ 7, 10, 10, 10, 10, 7, 9, 9, 11, 11, 11, 11, 11, 8, 11, 13, 13, 13, 13,
+ 12, 8, 14, 15, 14, 14, 14, 13, 12, 15, 16, 16, 16, 16, 11, 14, 17, 17, 17,
+ 18, 16, 10, 14, 17, 18, 18, 18, 16, 12, 14, 19, 18, 19, 18, 17, 12, 14, 21,
+ 21, 20, 19, 19, 14, 15, 22, 24, 23, 21, 19, 16, 16, 22, 26, 24, 23, 21, 17,
+ 24, 26, 24, 24, 21, 18, 14, 24, 28, 27, 26, 23, 18, 14, 24, 30, 28, 27, 23,
+ 19, 15, 24, 29, 31, 27, 24, 20, 16, 23, 28, 32, 30, 25, 21, 17, 24, 30, 34,
+ 33, 28, 23, 19, 24, 30, 35, 34, 30, 24, 20, 32, 37, 35, 28, 24, 20, 17, 33,
+ 37, 36, 30, 25, 21, 16, 33, 37, 39, 31, 26, 22, 17, 32, 37, 40, 33, 27, 23,
+ 19, 31, 36, 39, 36, 30, 23, 20, 31, 36, 40, 38, 32, 26, 21, 33, 36, 41, 40,
+ 34, 28, 22, 2, 3, 4, 8, 8, 6, 2, 2, 2, 3, 7, 8, 4, 2, 2, 2,
+ 2, 4, 5, 2, 2, 1, 2, 2, 2, 3, 2, 3, 2, 3, 3, 3, 4, 3, 3,
+ 6, 6, 6, 6, 4, 3, 3, 12, 11, 8, 6, 5, 3, 3, 2, 2, 3, 5, 5,
+ 2, 2, 1, 2, 3, 3, 4, 2, 1, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2,
+ 2, 1, 1, 3, 4, 3, 4, 4, 4, 3, 3, 8, 8, 8, 7, 5, 3, 3, 15,
+ 13, 10, 7, 5, 4, 3, 0, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2,
+ 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 4, 6, 5, 5, 5,
+ 5, 4, 4, 11, 10, 9, 8, 6, 5, 4, 18, 16, 12, 9, 7, 6, 5, 2, 2,
+ 2, 3, 3, 3, 7, 2, 3, 4, 4, 4, 4, 7, 4, 4, 5, 5, 5, 5, 7,
+ 7, 7, 7, 7, 8, 8, 8, 8, 12, 11, 11, 12, 11, 10, 12, 17, 16, 15, 14,
+ 13, 12, 18, 23, 20, 17, 15, 14, 13, 10, 10, 10, 10, 11, 10, 7, 12, 12, 12,
+ 11, 12, 11, 7, 12, 13, 13, 14, 13, 12, 8, 12, 17, 16, 16, 17, 15, 12, 15,
+ 21, 21, 20, 20, 19, 14, 19, 24, 25, 25, 23, 20, 15, 22, 27, 30, 27, 25, 22,
+ 17, 19, 21, 20, 20, 17, 13, 8, 19, 22, 22, 22, 18, 14, 10, 19, 24, 24, 24,
+ 19, 15, 11, 19, 25, 27, 27, 23, 19, 15, 22, 28, 32, 31, 28, 23, 17, 24, 30,
+ 36, 35, 30, 25, 18, 27, 34, 37, 37, 32, 26, 20, 27, 32, 32, 25, 20, 16, 11,
+ 27, 33, 34, 28, 22, 17, 13, 26, 34, 36, 29, 24, 19, 15, 28, 34, 38, 32, 27,
+ 23, 19, 29, 35, 40, 36, 32, 27, 21, 31, 37, 40, 40, 33, 27, 23, 33, 38, 42,
+ 42, 36, 30, 25, 1, 2, 3, 3, 3, 2, 2, 1, 2, 2, 3, 3, 2, 1, 1,
+ 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 4, 4, 3, 4, 4, 4, 4,
+ 4, 8, 7, 7, 7, 5, 4, 4, 13, 12, 9, 7, 6, 4, 4, 1, 2, 2, 3,
+ 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 0, 2, 2, 2, 1, 1, 2, 2,
+ 2, 2, 2, 2, 4, 5, 5, 5, 5, 5, 4, 4, 10, 9, 9, 8, 6, 4, 4,
+ 17, 14, 11, 8, 6, 5, 4, 2, 0, 1, 2, 2, 1, 5, 2, 1, 1, 1, 1,
+ 1, 5, 2, 2, 1, 1, 1, 1, 6, 4, 2, 4, 4, 4, 4, 7, 8, 6, 7,
+ 7, 8, 7, 7, 13, 12, 12, 11, 10, 8, 7, 19, 17, 15, 13, 11, 10, 9, 2,
+ 5, 5, 6, 6, 6, 9, 5, 6, 6, 7, 7, 7, 9, 8, 7, 7, 8, 8, 8,
+ 9, 11, 10, 11, 11, 11, 12, 11, 11, 15, 15, 15, 15, 15, 14, 13, 20, 20, 18,
+ 17, 16, 15, 19, 26, 23, 21, 18, 18, 17, 13, 14, 13, 13, 13, 13, 9, 14, 15,
+ 14, 15, 15, 14, 9, 14, 17, 16, 17, 16, 15, 12, 15, 21, 20, 20, 20, 19, 16,
+ 18, 25, 25, 24, 24, 22, 17, 22, 28, 30, 29, 26, 24, 19, 26, 31, 33, 30, 29,
+ 26, 20, 22, 24, 23, 23, 19, 15, 11, 23, 26, 25, 24, 21, 16, 12, 23, 28, 27,
+ 26, 23, 19, 15, 23, 29, 31, 30, 27, 22, 19, 25, 32, 36, 34, 31, 26, 21, 29,
+ 34, 41, 39, 34, 27, 22, 32, 37, 42, 41, 36, 30, 24, 31, 36, 34, 28, 23, 18,
+ 14, 30, 37, 37, 30, 23, 20, 15, 31, 36, 39, 33, 26, 22, 19, 30, 36, 42, 36,
+ 31, 27, 23, 32, 39, 45, 41, 35, 29, 24, 34, 40, 47, 45, 39, 31, 26, 38, 43,
+ 47, 46, 41, 34, 28, 1, 3, 4, 5, 5, 4, 3, 1, 2, 4, 5, 5, 4, 3,
+ 2, 1, 4, 4, 5, 5, 5, 2, 2, 4, 5, 6, 6, 6, 4, 4, 6, 7, 8,
+ 7, 6, 8, 8, 9, 10, 8, 7, 6, 14, 13, 10, 10, 9, 7, 6, 2, 1, 3,
+ 4, 4, 3, 1, 2, 1, 3, 4, 4, 3, 1, 2, 2, 2, 4, 4, 3, 3, 2,
+ 3, 3, 5, 5, 5, 5, 5, 5, 6, 7, 7, 6, 4, 11, 10, 10, 10, 8, 6,
+ 4, 18, 15, 12, 10, 8, 6, 4, 2, 1, 0, 1, 1, 2, 5, 2, 2, 1, 1,
+ 1, 2, 4, 3, 2, 2, 2, 3, 3, 6, 7, 3, 6, 6, 6, 6, 8, 10, 7,
+ 9, 9, 9, 9, 8, 15, 12, 13, 13, 11, 10, 7, 21, 19, 16, 14, 13, 11, 10,
+ 3, 6, 6, 6, 7, 6, 8, 8, 6, 7, 7, 8, 8, 9, 10, 7, 9, 9, 10,
+ 10, 10, 12, 10, 13, 13, 13, 13, 11, 13, 15, 17, 17, 17, 16, 14, 15, 22, 22,
+ 21, 19, 18, 17, 20, 27, 25, 22, 21, 20, 19, 14, 15, 15, 14, 15, 13, 8, 16,
+ 15, 16, 16, 15, 14, 8, 16, 17, 18, 19, 18, 17, 13, 16, 22, 22, 22, 22, 21,
+ 17, 19, 27, 27, 26, 26, 24, 18, 23, 31, 33, 31, 29, 25, 21, 28, 34, 35, 32,
+ 31, 28, 22, 23, 25, 24, 23, 20, 16, 12, 23, 28, 26, 25, 21, 17, 13, 24, 29,
+ 28, 28, 25, 21, 17, 24, 31, 33, 32, 28, 24, 21, 27, 33, 39, 36, 33, 27, 21,
+ 31, 37, 42, 41, 36, 29, 24, 33, 40, 45, 44, 38, 31, 26, 32, 38, 36, 29, 24,
+ 19, 15, 32, 37, 38, 30, 25, 21, 17, 31, 38, 40, 35, 29, 24, 19, 32, 39, 45,
+ 39, 32, 28, 24, 34, 41, 46, 44, 37, 31, 25, 37, 44, 48, 48, 41, 33, 28, 40,
+ 45, 49, 50, 43, 36, 30, 1, 3, 6, 8, 8, 6, 3, 1, 2, 5, 7, 8, 6,
+ 4, 1, 2, 4, 7, 8, 7, 5, 2, 2, 5, 7, 9, 8, 7, 4, 5, 7, 9,
+ 11, 9, 8, 9, 9, 10, 11, 11, 9, 8, 16, 14, 12, 11, 11, 9, 7, 1, 1,
+ 4, 6, 5, 3, 1, 2, 1, 3, 5, 5, 2, 2, 2, 1, 2, 5, 5, 4, 3,
+ 2, 3, 4, 6, 6, 5, 5, 6, 6, 7, 9, 8, 7, 5, 12, 11, 11, 11, 9,
+ 7, 5, 19, 17, 13, 11, 9, 7, 5, 2, 2, 1, 0, 1, 2, 4, 2, 2, 1,
+ 1, 1, 2, 4, 5, 2, 3, 3, 3, 3, 6, 8, 3, 6, 7, 7, 7, 7, 11,
+ 8, 10, 10, 10, 10, 8, 16, 13, 15, 14, 13, 11, 8, 21, 20, 18, 16, 14, 12,
+ 11, 5, 6, 7, 7, 7, 5, 7, 9, 6, 7, 8, 8, 8, 8, 12, 7, 9, 10,
+ 11, 11, 10, 14, 10, 14, 15, 14, 14, 12, 15, 15, 18, 18, 18, 18, 15, 16, 23,
+ 22, 21, 21, 19, 17, 22, 29, 26, 24, 22, 20, 20, 15, 14, 14, 14, 14, 13, 7,
+ 18, 15, 16, 15, 16, 15, 8, 18, 17, 18, 19, 19, 17, 14, 17, 22, 23, 23, 23,
+ 22, 18, 20, 28, 28, 27, 27, 25, 20, 23, 32, 34, 32, 28, 26, 22, 28, 35, 37,
+ 34, 32, 28, 23, 24, 26, 24, 23, 20, 16, 12, 24, 28, 26, 26, 22, 18, 14, 24,
+ 30, 29, 29, 25, 21, 18, 24, 32, 34, 33, 30, 25, 22, 28, 35, 40, 38, 34, 29,
+ 23, 32, 37, 45, 42, 36, 30, 25, 36, 42, 45, 45, 39, 33, 27, 32, 38, 35, 29,
+ 23, 19, 15, 32, 38, 37, 31, 26, 21, 18, 33, 38, 41, 35, 29, 26, 21, 32, 40,
+ 45, 39, 35, 29, 25, 36, 43, 48, 44, 39, 33, 26, 38, 45, 50, 50, 41, 35, 29,
+ 41, 47, 51, 51, 44, 37, 30, 1, 3, 6, 8, 8, 6, 3, 2, 2, 5, 7, 8,
+ 6, 5, 2, 1, 5, 8, 9, 8, 6, 2, 3, 5, 8, 10, 9, 8, 5, 6, 8,
+ 10, 12, 10, 9, 10, 11, 12, 13, 13, 10, 9, 17, 15, 13, 12, 12, 10, 9, 2,
+ 1, 4, 6, 5, 2, 2, 2, 1, 3, 5, 5, 3, 2, 2, 2, 2, 6, 5, 4,
+ 4, 2, 3, 5, 7, 7, 6, 7, 7, 7, 8, 10, 10, 8, 7, 13, 12, 13, 13,
+ 10, 9, 7, 21, 18, 14, 13, 11, 9, 7, 2, 2, 1, 1, 0, 2, 4, 3, 2,
+ 1, 1, 2, 3, 5, 7, 2, 3, 4, 5, 4, 6, 10, 3, 7, 8, 8, 8, 8,
+ 13, 9, 11, 12, 12, 11, 8, 17, 15, 16, 15, 14, 13, 8, 23, 21, 19, 17, 15,
+ 14, 13, 6, 6, 7, 7, 7, 4, 7, 11, 7, 8, 8, 9, 9, 8, 13, 7, 10,
+ 11, 12, 12, 11, 16, 10, 15, 16, 16, 16, 13, 16, 17, 19, 20, 20, 19, 16, 18,
+ 24, 25, 23, 22, 21, 19, 23, 30, 28, 25, 23, 22, 22, 16, 15, 15, 15, 15, 13,
+ 7, 19, 17, 16, 16, 18, 16, 8, 19, 18, 19, 20, 21, 19, 15, 19, 23, 23, 25,
+ 25, 24, 20, 20, 28, 30, 29, 29, 26, 21, 24, 33, 35, 33, 31, 29, 23, 30, 37,
+ 38, 35, 33, 30, 25, 25, 26, 25, 24, 20, 16, 12, 24, 28, 26, 25, 22, 19, 15,
+ 24, 30, 29, 30, 27, 23, 19, 25, 32, 35, 34, 31, 27, 23, 28, 36, 41, 39, 35,
+ 30, 25, 33, 40, 46, 43, 38, 32, 27, 37, 42, 47, 46, 40, 34, 28, 32, 38, 35,
+ 28, 23, 19, 16, 33, 37, 38, 31, 26, 22, 19, 34, 38, 40, 35, 31, 27, 22, 33,
+ 40, 45, 40, 35, 31, 27, 35, 43, 47, 46, 39, 34, 29, 41, 46, 50, 50, 42, 36,
+ 30, 43, 48, 50, 53, 45, 38, 32, 3, 5, 7, 8, 8, 6, 5, 2, 4, 6, 8,
+ 9, 7, 6, 1, 3, 6, 9, 10, 9, 8, 2, 4, 7, 9, 12, 11, 10, 5, 7,
+ 10, 11, 14, 12, 10, 11, 12, 13, 14, 14, 12, 10, 17, 16, 15, 14, 14, 12, 10,
+ 1, 4, 5, 7, 5, 3, 2, 2, 2, 5, 6, 6, 4, 3, 2, 2, 5, 7, 7,
+ 6, 5, 2, 3, 6, 8, 8, 7, 8, 6, 7, 10, 11, 11, 9, 8, 13, 13, 14,
+ 14, 11, 10, 8, 21, 18, 15, 14, 12, 10, 8, 2, 1, 2, 2, 2, 0, 2, 2,
+ 2, 1, 1, 2, 1, 4, 4, 2, 1, 3, 3, 3, 5, 9, 3, 5, 6, 6, 7,
+ 7, 11, 9, 10, 10, 10, 10, 7, 17, 15, 15, 14, 12, 11, 7, 23, 21, 17, 15,
+ 14, 12, 11, 4, 5, 5, 5, 5, 3, 5, 9, 6, 6, 6, 7, 7, 7, 12, 7,
+ 8, 9, 10, 11, 9, 15, 10, 13, 14, 14, 14, 11, 15, 15, 18, 18, 18, 17, 15,
+ 17, 23, 23, 22, 20, 19, 17, 24, 30, 26, 24, 22, 20, 19, 15, 13, 13, 12, 13,
+ 11, 5, 18, 15, 14, 14, 15, 14, 7, 19, 16, 17, 19, 19, 18, 13, 19, 21, 22,
+ 23, 23, 21, 18, 19, 27, 28, 27, 27, 24, 19, 23, 31, 34, 31, 29, 25, 21, 29,
+ 35, 36, 33, 31, 28, 23, 23, 24, 22, 20, 18, 14, 10, 23, 26, 24, 22, 20, 17,
+ 13, 23, 28, 27, 27, 23, 21, 17, 23, 30, 32, 30, 29, 24, 21, 27, 34, 37, 36,
+ 32, 28, 23, 31, 38, 43, 42, 35, 30, 25, 35, 40, 44, 43, 37, 31, 26, 31, 33,
+ 30, 25, 20, 17, 14, 30, 33, 33, 27, 23, 20, 17, 31, 33, 36, 31, 27, 25, 21,
+ 30, 35, 42, 36, 32, 28, 25, 34, 39, 44, 43, 37, 32, 27, 38, 42, 47, 47, 40,
+ 33, 28, 41, 46, 49, 48, 42, 36, 30, 6, 7, 9, 10, 10, 8, 6, 5, 6, 8,
+ 10, 11, 9, 8, 4, 6, 8, 11, 13, 11, 9, 3, 6, 9, 12, 14, 12, 11, 5,
+ 8, 10, 13, 15, 14, 11, 11, 13, 14, 14, 16, 14, 11, 17, 17, 15, 15, 14, 13,
+ 11, 4, 6, 7, 9, 7, 5, 3, 3, 5, 7, 8, 7, 6, 5, 1, 5, 7, 9,
+ 8, 7, 6, 1, 5, 8, 10, 9, 9, 8, 5, 8, 10, 12, 11, 10, 8, 12, 13,
+ 15, 15, 12, 10, 8, 20, 18, 16, 14, 12, 10, 8, 1, 5, 5, 4, 4, 2, 0,
+ 2, 3, 5, 4, 3, 3, 2, 2, 2, 4, 5, 4, 5, 4, 4, 3, 6, 6, 6,
+ 6, 6, 8, 8, 10, 10, 10, 8, 6, 15, 15, 15, 13, 11, 9, 6, 22, 20, 17,
+ 14, 11, 9, 8, 2, 2, 2, 2, 1, 2, 3, 5, 3, 3, 2, 3, 3, 4, 8,
+ 5, 4, 6, 6, 6, 6, 11, 7, 9, 10, 10, 10, 8, 12, 14, 14, 14, 14, 13,
+ 11, 15, 20, 19, 17, 16, 15, 13, 22, 26, 22, 20, 18, 16, 15, 12, 10, 9, 9,
+ 9, 8, 3, 15, 12, 11, 11, 11, 10, 4, 15, 14, 13, 14, 14, 13, 10, 14, 18,
+ 18, 18, 19, 17, 14, 17, 25, 23, 23, 23, 20, 15, 22, 28, 30, 27, 24, 21, 17,
+ 26, 31, 33, 29, 26, 23, 19, 20, 19, 18, 16, 14, 10, 6, 19, 22, 18, 17, 15,
+ 13, 9, 19, 23, 22, 21, 19, 16, 13, 20, 25, 26, 26, 23, 20, 17, 23, 30, 33,
+ 30, 28, 23, 19, 27, 33, 38, 35, 29, 25, 20, 32, 35, 40, 38, 32, 27, 22, 24,
+ 28, 25, 19, 15, 13, 10, 25, 28, 27, 21, 17, 15, 13, 25, 28, 29, 25, 22, 19,
+ 16, 25, 29, 35, 31, 27, 23, 20, 28, 35, 39, 36, 31, 27, 22, 32, 37, 41, 41,
+ 34, 28, 23, 36, 40, 42, 43, 37, 30, 26, 2, 3, 8, 12, 12, 10, 7, 2, 3,
+ 6, 11, 11, 9, 4, 2, 2, 4, 8, 9, 7, 2, 2, 2, 2, 4, 7, 5, 2,
+ 2, 2, 2, 3, 5, 5, 2, 6, 6, 6, 5, 4, 5, 2, 11, 11, 8, 6, 4,
+ 5, 2, 2, 2, 5, 8, 9, 6, 2, 1, 2, 3, 7, 9, 4, 2, 2, 2, 2,
+ 4, 5, 2, 2, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 7,
+ 7, 8, 6, 4, 3, 2, 15, 13, 10, 7, 5, 3, 2, 1, 2, 2, 2, 3, 2,
+ 2, 0, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1,
+ 1, 1, 2, 5, 4, 4, 4, 4, 3, 2, 11, 9, 9, 7, 5, 3, 2, 17, 16,
+ 12, 9, 6, 4, 3, 1, 1, 1, 1, 1, 1, 5, 2, 2, 2, 3, 3, 3, 6,
+ 2, 3, 3, 3, 4, 4, 6, 5, 5, 6, 6, 6, 7, 7, 6, 10, 10, 10, 10,
+ 9, 9, 11, 15, 14, 14, 12, 11, 10, 17, 21, 18, 16, 14, 13, 12, 9, 9, 9,
+ 9, 10, 9, 6, 11, 11, 10, 11, 11, 10, 6, 11, 12, 12, 12, 12, 11, 7, 11,
+ 15, 14, 15, 15, 14, 11, 13, 20, 19, 19, 19, 18, 12, 17, 23, 25, 24, 21, 20,
+ 14, 21, 26, 27, 24, 24, 21, 16, 18, 20, 19, 19, 16, 12, 7, 18, 21, 21, 21,
+ 18, 12, 9, 18, 23, 22, 22, 18, 14, 10, 18, 24, 26, 25, 22, 18, 14, 20, 25,
+ 30, 28, 25, 21, 16, 22, 28, 33, 31, 27, 23, 18, 25, 31, 34, 34, 29, 25, 19,
+ 26, 31, 29, 24, 19, 15, 10, 26, 31, 31, 26, 21, 16, 11, 26, 31, 33, 27, 23,
+ 18, 14, 25, 31, 35, 30, 26, 21, 18, 27, 32, 35, 33, 28, 24, 20, 29, 35, 37,
+ 36, 31, 27, 22, 32, 34, 36, 37, 31, 28, 23, 2, 2, 3, 3, 3, 2, 2, 1,
+ 2, 3, 3, 3, 2, 2, 1, 2, 2, 3, 3, 2, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 4, 3, 3, 7, 6, 7, 6, 5, 3, 3, 13, 11, 8, 7,
+ 5, 3, 3, 1, 2, 2, 3, 2, 2, 2, 1, 2, 2, 3, 2, 2, 1, 2, 2,
+ 2, 2, 2, 2, 1, 2, 1, 2, 2, 1, 2, 3, 4, 4, 4, 4, 4, 3, 3,
+ 9, 8, 8, 7, 5, 4, 3, 16, 14, 10, 8, 6, 4, 3, 2, 1, 2, 2, 2,
+ 2, 3, 2, 0, 1, 1, 1, 2, 3, 2, 1, 1, 0, 1, 0, 4, 3, 2, 2,
+ 2, 3, 3, 6, 7, 6, 6, 6, 6, 5, 6, 12, 11, 10, 9, 8, 7, 6, 18,
+ 17, 13, 11, 9, 8, 7, 2, 4, 4, 4, 5, 4, 8, 3, 5, 5, 5, 6, 6,
+ 8, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 10, 10, 10, 13, 13, 13,
+ 13, 13, 12, 12, 19, 18, 16, 16, 15, 14, 18, 25, 22, 19, 18, 16, 15, 12, 12,
+ 12, 12, 12, 12, 8, 14, 14, 13, 13, 14, 12, 8, 13, 15, 15, 15, 15, 14, 11,
+ 13, 19, 19, 18, 19, 18, 14, 17, 24, 23, 23, 23, 20, 16, 20, 27, 29, 27, 25,
+ 22, 17, 25, 30, 31, 29, 28, 25, 19, 21, 23, 22, 21, 18, 14, 10, 21, 25, 23,
+ 23, 20, 15, 11, 20, 26, 27, 26, 22, 17, 13, 21, 27, 28, 28, 25, 21, 17, 24,
+ 30, 34, 33, 30, 24, 19, 27, 33, 40, 37, 32, 26, 21, 30, 36, 40, 39, 34, 29,
+ 22, 29, 36, 33, 27, 20, 17, 13, 29, 35, 35, 28, 23, 18, 14, 29, 35, 38, 31,
+ 25, 20, 16, 29, 34, 42, 35, 30, 25, 21, 31, 37, 43, 40, 34, 29, 22, 33, 40,
+ 45, 43, 37, 30, 25, 35, 42, 46, 46, 39, 32, 27, 1, 3, 4, 5, 5, 4, 3,
+ 1, 3, 4, 5, 5, 4, 3, 1, 2, 4, 4, 5, 4, 4, 1, 2, 4, 5, 5,
+ 5, 6, 4, 4, 6, 7, 7, 6, 6, 8, 8, 10, 10, 8, 7, 6, 14, 12, 11,
+ 10, 9, 7, 6, 1, 2, 4, 5, 4, 3, 1, 1, 1, 3, 4, 4, 3, 0, 2,
+ 1, 3, 4, 3, 4, 3, 2, 2, 3, 5, 5, 5, 5, 5, 5, 6, 8, 7, 6,
+ 5, 10, 10, 10, 11, 8, 6, 5, 18, 15, 11, 10, 8, 7, 5, 2, 1, 1, 1,
+ 1, 1, 4, 2, 1, 0, 1, 1, 1, 4, 2, 1, 2, 2, 2, 2, 5, 5, 3,
+ 5, 5, 5, 5, 7, 9, 7, 8, 8, 8, 8, 7, 14, 12, 13, 11, 10, 9, 7,
+ 20, 18, 15, 14, 12, 10, 9, 2, 5, 6, 6, 6, 5, 8, 6, 6, 6, 7, 7,
+ 7, 8, 9, 7, 8, 8, 9, 9, 9, 11, 9, 12, 12, 12, 12, 11, 12, 15, 16,
+ 16, 16, 16, 14, 14, 21, 20, 19, 18, 17, 16, 20, 27, 24, 21, 20, 18, 17, 13,
+ 13, 13, 14, 14, 13, 8, 15, 15, 14, 15, 15, 14, 8, 15, 17, 17, 17, 17, 16,
+ 12, 15, 22, 21, 20, 21, 20, 16, 18, 26, 25, 24, 25, 23, 18, 23, 30, 32, 29,
+ 28, 24, 20, 26, 33, 35, 31, 30, 26, 21, 23, 25, 23, 23, 19, 15, 11, 23, 27,
+ 25, 24, 20, 16, 12, 23, 28, 27, 28, 24, 19, 16, 22, 30, 32, 31, 28, 23, 19,
+ 26, 33, 36, 35, 31, 26, 21, 29, 35, 41, 40, 34, 29, 22, 33, 38, 43, 43, 36,
+ 30, 24, 30, 37, 35, 28, 22, 18, 14, 31, 36, 37, 30, 24, 20, 16, 31, 36, 40,
+ 33, 28, 22, 19, 30, 38, 44, 38, 31, 27, 23, 33, 39, 45, 42, 36, 31, 25, 35,
+ 41, 48, 46, 39, 32, 27, 40, 44, 48, 51, 41, 35, 29, 1, 4, 6, 9, 9, 7,
+ 4, 1, 3, 5, 8, 8, 7, 5, 1, 2, 5, 7, 9, 8, 6, 1, 3, 5, 8,
+ 10, 8, 8, 5, 5, 7, 9, 11, 10, 8, 9, 9, 11, 12, 11, 9, 8, 15, 14,
+ 12, 12, 11, 10, 8, 1, 2, 4, 7, 6, 3, 1, 1, 1, 4, 6, 6, 3, 1,
+ 2, 1, 3, 6, 5, 4, 3, 2, 3, 4, 6, 6, 6, 6, 5, 6, 7, 9, 9,
+ 7, 6, 11, 11, 11, 12, 9, 8, 6, 19, 16, 13, 12, 9, 8, 6, 2, 1, 1,
+ 1, 2, 1, 3, 2, 1, 1, 0, 1, 1, 4, 3, 2, 2, 2, 2, 3, 5, 7,
+ 3, 5, 6, 5, 6, 7, 10, 8, 9, 9, 10, 8, 7, 15, 13, 14, 13, 11, 10,
+ 7, 21, 20, 17, 15, 13, 11, 10, 3, 5, 6, 6, 6, 4, 7, 8, 6, 7, 7,
+ 7, 7, 7, 11, 7, 8, 9, 10, 10, 9, 13, 9, 13, 13, 13, 13, 11, 13, 15,
+ 17, 16, 17, 17, 14, 16, 22, 22, 21, 19, 18, 16, 21, 28, 26, 23, 21, 20, 18,
+ 14, 14, 14, 14, 14, 13, 7, 16, 15, 15, 15, 15, 14, 7, 16, 17, 17, 18, 18,
+ 17, 13, 16, 21, 22, 22, 22, 21, 17, 19, 27, 27, 27, 26, 24, 19, 23, 30, 32,
+ 31, 28, 26, 20, 28, 33, 35, 32, 31, 28, 22, 23, 24, 23, 23, 19, 16, 11, 22,
+ 27, 25, 24, 21, 17, 13, 23, 30, 28, 28, 24, 21, 17, 23, 31, 33, 32, 28, 24,
+ 21, 28, 34, 36, 36, 33, 27, 22, 31, 36, 44, 42, 36, 29, 24, 34, 39, 43, 45,
+ 37, 32, 26, 31, 36, 35, 28, 22, 18, 14, 31, 37, 37, 31, 25, 20, 17, 31, 37,
+ 41, 33, 29, 25, 19, 31, 38, 45, 39, 33, 28, 24, 35, 39, 46, 44, 36, 32, 26,
+ 38, 45, 51, 50, 40, 33, 28, 40, 46, 50, 51, 43, 35, 30, 1, 4, 7, 10, 10,
+ 8, 4, 1, 3, 6, 9, 9, 7, 5, 1, 2, 5, 8, 10, 8, 6, 2, 3, 6,
+ 8, 11, 9, 8, 5, 6, 8, 10, 12, 10, 8, 10, 10, 12, 12, 12, 10, 8, 16,
+ 14, 12, 12, 12, 10, 8, 1, 2, 5, 7, 7, 4, 1, 1, 1, 4, 6, 6, 4,
+ 2, 2, 1, 3, 6, 6, 5, 3, 2, 3, 5, 7, 7, 6, 6, 5, 6, 8, 9,
+ 9, 7, 6, 12, 11, 12, 12, 9, 8, 6, 19, 17, 13, 12, 10, 8, 6, 2, 1,
+ 1, 1, 2, 2, 3, 2, 2, 1, 1, 0, 1, 4, 4, 2, 2, 3, 3, 2, 5,
+ 8, 3, 6, 6, 6, 6, 7, 11, 8, 9, 10, 10, 9, 7, 16, 14, 14, 13, 12,
+ 10, 7, 21, 20, 17, 15, 13, 12, 11, 4, 5, 6, 6, 6, 4, 7, 8, 6, 7,
+ 7, 7, 7, 7, 12, 6, 8, 10, 10, 10, 9, 13, 9, 13, 13, 14, 14, 11, 14,
+ 15, 17, 17, 18, 17, 14, 16, 22, 22, 21, 20, 18, 17, 21, 28, 25, 23, 22, 20,
+ 19, 15, 14, 14, 14, 14, 13, 7, 17, 15, 15, 15, 15, 14, 7, 16, 17, 17, 19,
+ 19, 17, 13, 17, 21, 23, 23, 22, 21, 17, 19, 27, 27, 27, 27, 24, 19, 24, 32,
+ 34, 31, 30, 26, 20, 28, 36, 36, 34, 31, 29, 23, 23, 25, 23, 23, 20, 16, 11,
+ 23, 27, 25, 24, 22, 17, 14, 23, 29, 28, 28, 24, 20, 17, 23, 31, 34, 33, 29,
+ 25, 21, 27, 34, 38, 37, 33, 28, 22, 30, 38, 44, 42, 36, 30, 24, 35, 40, 44,
+ 44, 37, 32, 26, 32, 35, 34, 27, 22, 18, 14, 31, 37, 36, 29, 24, 21, 17, 31,
+ 36, 38, 33, 29, 24, 21, 32, 39, 43, 38, 33, 28, 24, 35, 42, 46, 44, 37, 32,
+ 27, 37, 43, 49, 48, 42, 34, 28, 41, 46, 49, 51, 44, 36, 30, 3, 5, 6, 8,
+ 8, 6, 4, 2, 5, 6, 8, 8, 6, 5, 1, 4, 6, 8, 9, 8, 6, 2, 4,
+ 7, 9, 11, 9, 8, 4, 6, 8, 10, 12, 10, 8, 10, 10, 12, 12, 12, 10, 8,
+ 15, 15, 13, 12, 12, 10, 8, 1, 4, 5, 7, 5, 4, 2, 1, 3, 5, 6, 5,
+ 3, 2, 2, 2, 5, 6, 6, 5, 4, 2, 3, 5, 7, 7, 6, 6, 5, 6, 8,
+ 10, 9, 7, 6, 12, 11, 12, 12, 10, 8, 6, 19, 16, 14, 12, 10, 8, 6, 2,
+ 1, 2, 2, 3, 1, 3, 2, 1, 1, 1, 1, 0, 3, 3, 1, 1, 2, 2, 2,
+ 4, 7, 3, 5, 5, 5, 5, 5, 11, 8, 9, 9, 9, 8, 5, 15, 14, 13, 12,
+ 11, 9, 5, 21, 18, 16, 14, 12, 11, 9, 2, 5, 5, 5, 5, 4, 6, 7, 6,
+ 6, 6, 6, 6, 6, 11, 6, 7, 8, 9, 9, 7, 14, 9, 12, 12, 12, 12, 10,
+ 14, 14, 17, 16, 17, 16, 13, 16, 21, 21, 20, 19, 17, 16, 21, 27, 25, 22, 20,
+ 18, 18, 14, 13, 13, 13, 13, 13, 6, 16, 15, 14, 14, 14, 13, 6, 17, 16, 16,
+ 17, 17, 16, 12, 17, 21, 21, 21, 22, 19, 15, 19, 27, 27, 26, 25, 23, 18, 23,
+ 30, 32, 30, 27, 25, 20, 27, 33, 34, 31, 29, 27, 21, 23, 23, 22, 21, 18, 15,
+ 10, 23, 26, 23, 22, 19, 16, 12, 23, 28, 26, 25, 23, 19, 16, 23, 29, 32, 29,
+ 27, 23, 19, 26, 33, 37, 34, 31, 26, 21, 31, 37, 40, 40, 33, 28, 23, 33, 38,
+ 42, 42, 35, 29, 24, 30, 34, 30, 25, 20, 16, 13, 29, 34, 33, 27, 22, 20, 16,
+ 30, 34, 36, 30, 26, 23, 19, 29, 36, 40, 34, 30, 27, 23, 33, 39, 43, 41, 35,
+ 30, 25, 37, 41, 46, 46, 37, 31, 27, 40, 44, 47, 47, 40, 34, 28, 6, 7, 9,
+ 12, 11, 9, 6, 5, 6, 8, 11, 11, 8, 6, 4, 6, 8, 10, 11, 9, 8, 3,
+ 6, 9, 10, 13, 11, 9, 5, 7, 9, 11, 14, 12, 9, 9, 10, 11, 12, 14, 12,
+ 9, 15, 14, 12, 12, 13, 12, 9, 4, 6, 7, 9, 8, 6, 4, 3, 6, 7, 8,
+ 7, 5, 3, 1, 5, 7, 8, 7, 6, 5, 1, 4, 8, 9, 8, 8, 6, 5, 7,
+ 9, 10, 9, 9, 6, 11, 11, 12, 12, 10, 8, 6, 18, 16, 13, 12, 10, 8, 6,
+ 1, 5, 5, 4, 5, 4, 2, 1, 3, 4, 4, 4, 3, 0, 1, 2, 4, 4, 3,
+ 3, 2, 2, 3, 5, 5, 4, 4, 4, 7, 8, 8, 7, 8, 6, 4, 14, 13, 12,
+ 10, 8, 7, 4, 20, 17, 14, 11, 9, 7, 5, 1, 2, 2, 2, 2, 3, 5, 2,
+ 3, 2, 2, 3, 3, 3, 7, 4, 4, 5, 5, 5, 4, 10, 7, 8, 8, 8, 8,
+ 6, 10, 13, 12, 12, 12, 11, 9, 14, 19, 17, 15, 14, 13, 11, 19, 23, 20, 17,
+ 15, 14, 13, 11, 10, 9, 9, 10, 9, 5, 13, 12, 11, 10, 11, 9, 3, 13, 13,
+ 13, 14, 13, 11, 8, 13, 18, 17, 16, 17, 15, 12, 16, 23, 22, 21, 21, 18, 13,
+ 20, 26, 27, 25, 22, 20, 15, 23, 28, 31, 26, 24, 22, 16, 19, 19, 17, 16, 15,
+ 11, 8, 19, 22, 18, 17, 15, 11, 8, 19, 23, 21, 20, 17, 14, 12, 20, 25, 25,
+ 24, 22, 18, 15, 22, 28, 31, 28, 25, 22, 17, 27, 31, 36, 33, 27, 23, 19, 29,
+ 34, 38, 35, 29, 25, 20, 25, 27, 25, 19, 16, 13, 10, 25, 27, 27, 20, 17, 14,
+ 11, 25, 28, 29, 24, 21, 18, 15, 25, 29, 34, 29, 25, 21, 18, 28, 33, 36, 34,
+ 30, 24, 20, 31, 35, 40, 38, 32, 26, 21, 35, 38, 41, 41, 34, 28, 23, 3, 7,
+ 12, 15, 16, 14, 11, 2, 5, 10, 14, 15, 14, 8, 2, 4, 8, 11, 13, 11, 6,
+ 2, 2, 5, 8, 10, 10, 5, 2, 2, 3, 6, 8, 9, 5, 5, 6, 6, 5, 7,
+ 9, 5, 12, 11, 8, 4, 7, 9, 5, 2, 4, 8, 12, 13, 11, 5, 2, 3, 7,
+ 10, 12, 9, 3, 2, 2, 5, 7, 8, 6, 2, 1, 2, 2, 4, 5, 3, 2, 2,
+ 3, 3, 3, 3, 3, 2, 7, 7, 7, 6, 3, 2, 2, 15, 13, 9, 7, 4, 3,
+ 2, 2, 2, 3, 5, 6, 4, 2, 1, 2, 2, 3, 4, 3, 1, 0, 2, 2, 2,
+ 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 3, 2, 10, 9,
+ 9, 8, 5, 3, 2, 17, 16, 12, 9, 6, 4, 2, 0, 1, 1, 1, 2, 2, 4,
+ 1, 1, 1, 1, 1, 1, 5, 1, 2, 2, 3, 3, 3, 5, 4, 4, 5, 5, 5,
+ 6, 7, 5, 9, 8, 9, 9, 8, 7, 11, 14, 13, 13, 11, 10, 9, 17, 20, 17,
+ 15, 13, 12, 11, 8, 8, 8, 9, 9, 8, 5, 10, 10, 9, 10, 10, 9, 5, 10,
+ 11, 11, 11, 12, 11, 6, 10, 14, 13, 14, 14, 13, 9, 12, 18, 18, 18, 18, 17,
+ 11, 16, 21, 22, 21, 20, 19, 13, 19, 24, 24, 22, 21, 20, 16, 17, 18, 18, 18,
+ 15, 11, 7, 17, 20, 19, 19, 16, 12, 7, 17, 22, 22, 21, 19, 14, 9, 17, 22,
+ 23, 22, 20, 17, 13, 18, 24, 26, 24, 23, 20, 15, 21, 26, 29, 28, 24, 21, 17,
+ 23, 28, 30, 29, 26, 22, 18, 25, 28, 26, 22, 19, 14, 9, 24, 28, 28, 24, 20,
+ 16, 10, 24, 29, 31, 24, 21, 17, 13, 24, 29, 31, 26, 23, 20, 17, 25, 28, 32,
+ 30, 25, 22, 18, 27, 29, 33, 32, 27, 23, 20, 28, 31, 33, 34, 29, 24, 21, 2,
+ 2, 3, 5, 5, 3, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 3, 3, 2,
+ 1, 0, 2, 2, 2, 3, 2, 3, 2, 2, 3, 3, 4, 3, 3, 6, 6, 7, 6,
+ 4, 3, 3, 12, 11, 8, 6, 5, 3, 3, 1, 2, 3, 3, 3, 2, 2, 1, 2,
+ 2, 3, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 3,
+ 4, 3, 4, 4, 4, 3, 3, 9, 8, 8, 7, 5, 3, 3, 16, 13, 10, 8, 5,
+ 4, 3, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 0, 1,
+ 1, 1, 1, 3, 2, 2, 2, 1, 2, 2, 5, 6, 5, 5, 5, 5, 4, 5, 12,
+ 10, 10, 8, 7, 5, 5, 18, 17, 12, 10, 8, 7, 6, 2, 3, 3, 3, 4, 4,
+ 7, 2, 4, 4, 5, 5, 5, 8, 5, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8,
+ 9, 9, 9, 9, 13, 12, 12, 13, 12, 11, 12, 18, 16, 16, 15, 13, 12, 18, 23,
+ 20, 18, 17, 15, 14, 11, 11, 11, 11, 11, 11, 7, 12, 13, 12, 13, 13, 12, 7,
+ 12, 14, 14, 14, 14, 13, 9, 13, 18, 17, 17, 18, 16, 13, 16, 22, 22, 21, 22,
+ 19, 14, 19, 26, 27, 26, 24, 22, 16, 24, 29, 31, 28, 26, 23, 18, 19, 21, 20,
+ 20, 17, 13, 9, 20, 23, 22, 23, 19, 14, 10, 20, 25, 25, 24, 20, 16, 12, 20,
+ 26, 28, 28, 24, 20, 16, 23, 28, 32, 32, 29, 23, 18, 26, 32, 37, 37, 31, 25,
+ 20, 28, 34, 39, 39, 33, 28, 22, 28, 34, 32, 26, 20, 16, 12, 28, 34, 34, 27,
+ 22, 17, 13, 27, 34, 38, 30, 24, 20, 16, 28, 34, 39, 34, 28, 23, 20, 30, 36,
+ 41, 39, 32, 28, 22, 32, 38, 44, 41, 36, 30, 24, 34, 40, 45, 43, 38, 31, 25,
+ 2, 4, 5, 6, 6, 5, 4, 1, 4, 5, 6, 6, 5, 4, 0, 3, 5, 5, 5,
+ 4, 4, 1, 2, 4, 5, 5, 5, 6, 3, 4, 6, 6, 7, 6, 6, 8, 8, 9,
+ 9, 8, 6, 6, 13, 12, 11, 9, 8, 6, 6, 0, 3, 5, 5, 5, 4, 2, 1,
+ 2, 4, 5, 5, 4, 2, 1, 1, 4, 4, 4, 3, 2, 2, 2, 3, 5, 4, 5,
+ 5, 5, 4, 6, 7, 7, 6, 5, 9, 9, 10, 10, 8, 6, 5, 17, 14, 11, 10,
+ 8, 6, 5, 1, 1, 2, 3, 3, 1, 4, 2, 1, 2, 2, 2, 1, 4, 2, 1,
+ 0, 0, 0, 0, 5, 4, 2, 3, 3, 3, 3, 6, 8, 6, 7, 7, 7, 6, 6,
+ 13, 11, 11, 10, 9, 7, 6, 19, 18, 14, 12, 10, 9, 8, 2, 4, 5, 5, 5,
+ 5, 7, 4, 5, 5, 6, 6, 6, 8, 8, 6, 7, 7, 7, 8, 8, 10, 9, 10,
+ 10, 11, 11, 10, 11, 14, 14, 15, 15, 14, 13, 13, 20, 19, 18, 17, 15, 15, 19,
+ 26, 22, 20, 18, 17, 16, 12, 13, 12, 13, 13, 12, 7, 13, 14, 14, 14, 14, 13,
+ 8, 14, 16, 16, 16, 16, 15, 11, 13, 20, 19, 19, 20, 18, 15, 18, 25, 24, 24,
+ 24, 21, 16, 22, 28, 30, 28, 26, 23, 18, 26, 31, 33, 29, 28, 25, 20, 22, 23,
+ 22, 22, 18, 14, 10, 22, 25, 24, 24, 20, 16, 12, 22, 27, 26, 26, 23, 18, 14,
+ 21, 29, 30, 29, 26, 22, 18, 26, 31, 36, 34, 30, 25, 20, 27, 34, 39, 38, 33,
+ 27, 21, 31, 37, 41, 41, 34, 28, 23, 29, 35, 34, 27, 22, 17, 13, 29, 36, 36,
+ 29, 24, 19, 14, 29, 36, 39, 32, 26, 22, 17, 30, 36, 42, 35, 30, 26, 22, 31,
+ 38, 44, 41, 33, 29, 24, 34, 40, 47, 47, 38, 30, 26, 37, 43, 47, 47, 39, 33,
+ 27, 2, 6, 9, 11, 11, 10, 7, 2, 5, 8, 11, 11, 9, 6, 0, 3, 7, 9,
+ 10, 7, 6, 1, 2, 5, 7, 9, 8, 7, 3, 4, 6, 8, 10, 9, 7, 7, 8,
+ 10, 10, 10, 9, 7, 14, 13, 11, 10, 10, 9, 7, 0, 3, 7, 10, 9, 6, 3,
+ 1, 2, 5, 8, 9, 6, 2, 1, 1, 4, 6, 6, 4, 2, 2, 2, 4, 6, 6,
+ 5, 4, 4, 5, 6, 8, 7, 6, 4, 10, 9, 10, 10, 8, 6, 4, 17, 14, 11,
+ 11, 8, 6, 4, 1, 1, 2, 3, 4, 3, 5, 2, 0, 2, 2, 3, 2, 4, 2,
+ 1, 0, 0, 0, 0, 3, 4, 2, 3, 3, 3, 3, 5, 8, 6, 7, 7, 7, 6,
+ 5, 13, 11, 11, 10, 9, 7, 5, 19, 17, 14, 12, 10, 9, 8, 2, 4, 5, 5,
+ 6, 6, 8, 5, 5, 6, 6, 7, 7, 7, 10, 6, 7, 7, 7, 7, 7, 11, 9,
+ 10, 11, 11, 10, 9, 12, 14, 14, 15, 14, 14, 12, 13, 20, 19, 18, 17, 16, 14,
+ 19, 26, 23, 21, 18, 17, 16, 12, 13, 12, 13, 14, 13, 8, 15, 14, 14, 15, 15,
+ 14, 7, 14, 16, 16, 16, 15, 14, 11, 14, 20, 19, 19, 20, 17, 14, 17, 25, 24,
+ 23, 24, 21, 16, 21, 28, 30, 28, 26, 23, 18, 25, 31, 33, 30, 27, 25, 20, 22,
+ 24, 22, 22, 19, 16, 12, 21, 26, 24, 24, 20, 16, 12, 22, 28, 26, 26, 21, 18,
+ 14, 22, 29, 30, 30, 26, 22, 18, 25, 33, 36, 34, 30, 25, 19, 28, 34, 41, 38,
+ 33, 27, 22, 31, 37, 42, 41, 36, 29, 23, 30, 35, 34, 28, 23, 18, 14, 29, 36,
+ 36, 30, 23, 19, 14, 30, 35, 38, 32, 26, 21, 17, 29, 37, 41, 35, 31, 25, 21,
+ 32, 39, 45, 39, 34, 29, 23, 34, 41, 47, 46, 38, 31, 26, 37, 43, 47, 46, 40,
+ 33, 27, 3, 6, 9, 13, 13, 10, 7, 2, 5, 8, 12, 12, 9, 6, 0, 4, 7,
+ 10, 11, 8, 6, 1, 3, 5, 8, 10, 9, 7, 4, 4, 6, 8, 11, 9, 7, 7,
+ 8, 10, 10, 10, 9, 7, 13, 12, 10, 10, 10, 9, 7, 1, 4, 7, 10, 10, 7,
+ 3, 1, 2, 6, 9, 9, 6, 2, 1, 1, 5, 7, 7, 4, 2, 1, 2, 4, 6,
+ 6, 5, 4, 4, 5, 6, 8, 7, 5, 4, 10, 9, 10, 10, 7, 6, 4, 16, 14,
+ 11, 10, 8, 6, 4, 1, 1, 3, 4, 5, 3, 4, 1, 1, 2, 2, 3, 2, 3,
+ 2, 1, 0, 0, 0, 1, 3, 4, 2, 3, 3, 3, 3, 4, 8, 6, 7, 7, 7,
+ 6, 4, 13, 12, 11, 10, 9, 7, 4, 19, 17, 14, 12, 10, 9, 8, 1, 5, 5,
+ 5, 6, 6, 8, 5, 6, 6, 6, 7, 7, 7, 9, 6, 7, 7, 7, 7, 6, 11,
+ 8, 11, 11, 10, 11, 8, 12, 14, 15, 15, 15, 14, 12, 13, 19, 19, 18, 17, 15,
+ 14, 19, 26, 23, 20, 19, 17, 16, 12, 13, 13, 13, 14, 13, 8, 14, 15, 14, 14,
+ 15, 13, 7, 15, 16, 16, 16, 16, 14, 11, 14, 20, 20, 20, 20, 18, 14, 17, 25,
+ 25, 24, 23, 21, 16, 22, 29, 30, 28, 26, 23, 18, 26, 32, 33, 31, 28, 25, 20,
+ 22, 23, 23, 23, 20, 16, 11, 22, 26, 24, 24, 21, 16, 12, 23, 29, 27, 26, 22,
+ 17, 14, 23, 29, 31, 29, 26, 22, 18, 25, 32, 37, 34, 30, 25, 19, 28, 35, 41,
+ 38, 33, 27, 22, 31, 36, 41, 40, 34, 30, 23, 31, 35, 33, 27, 22, 18, 14, 30,
+ 36, 36, 29, 23, 18, 14, 29, 36, 38, 31, 25, 21, 17, 31, 36, 40, 35, 30, 26,
+ 22, 32, 38, 43, 40, 34, 29, 23, 36, 41, 45, 45, 37, 31, 25, 37, 43, 46, 46,
+ 40, 34, 27, 3, 6, 8, 9, 9, 7, 5, 2, 6, 7, 9, 9, 6, 4, 1, 4,
+ 6, 8, 8, 6, 5, 1, 3, 5, 7, 9, 8, 6, 4, 4, 7, 8, 11, 9, 6,
+ 8, 8, 10, 10, 10, 9, 6, 13, 12, 10, 10, 10, 9, 6, 0, 4, 6, 8, 7,
+ 5, 3, 1, 3, 5, 7, 6, 4, 2, 1, 1, 5, 6, 4, 3, 2, 2, 2, 4,
+ 6, 5, 5, 4, 5, 5, 6, 8, 7, 6, 4, 10, 9, 10, 10, 7, 6, 4, 16,
+ 13, 11, 10, 8, 6, 4, 1, 1, 3, 3, 4, 3, 5, 2, 1, 2, 3, 3, 2,
+ 3, 2, 1, 0, 0, 0, 0, 2, 4, 2, 3, 3, 3, 3, 4, 9, 7, 7, 7,
+ 7, 6, 4, 14, 11, 11, 10, 9, 7, 4, 18, 16, 13, 11, 10, 9, 8, 2, 5,
+ 5, 6, 6, 6, 8, 5, 6, 6, 6, 7, 7, 6, 9, 6, 7, 7, 8, 7, 6,
+ 11, 8, 11, 11, 10, 11, 8, 12, 14, 15, 14, 15, 14, 11, 13, 20, 19, 18, 16,
+ 16, 14, 18, 25, 22, 20, 18, 17, 16, 13, 13, 13, 13, 14, 13, 8, 15, 15, 14,
+ 15, 15, 13, 7, 15, 16, 16, 16, 16, 14, 10, 15, 20, 20, 20, 20, 18, 15, 18,
+ 25, 24, 23, 24, 21, 16, 22, 28, 29, 28, 26, 23, 18, 25, 30, 32, 29, 28, 25,
+ 20, 23, 24, 23, 22, 19, 16, 11, 23, 26, 24, 22, 20, 16, 11, 23, 28, 26, 24,
+ 21, 18, 14, 22, 29, 31, 28, 25, 22, 18, 25, 31, 35, 34, 29, 24, 19, 28, 33,
+ 39, 37, 31, 26, 22, 31, 35, 41, 39, 33, 27, 23, 29, 34, 32, 26, 22, 18, 14,
+ 30, 34, 33, 27, 22, 18, 14, 29, 33, 36, 29, 24, 21, 17, 29, 34, 39, 34, 29,
+ 26, 21, 32, 37, 42, 38, 34, 27, 23, 34, 40, 44, 44, 35, 29, 25, 37, 41, 45,
+ 45, 37, 31, 27, 7, 9, 11, 13, 13, 11, 8, 6, 8, 10, 12, 13, 10, 6, 5,
+ 7, 9, 11, 11, 8, 6, 3, 6, 7, 10, 12, 10, 8, 4, 6, 8, 10, 13, 10,
+ 8, 7, 8, 9, 10, 12, 10, 7, 11, 10, 9, 9, 11, 11, 8, 5, 7, 9, 11,
+ 10, 7, 5, 4, 6, 8, 10, 9, 6, 4, 1, 6, 7, 9, 7, 5, 3, 0, 4,
+ 6, 8, 7, 6, 5, 4, 5, 7, 8, 8, 7, 5, 9, 8, 9, 10, 7, 7, 5,
+ 13, 11, 10, 9, 8, 6, 5, 2, 6, 6, 6, 6, 5, 4, 0, 4, 5, 5, 5,
+ 4, 2, 1, 3, 5, 3, 3, 3, 0, 1, 2, 3, 3, 3, 3, 2, 6, 6, 6,
+ 5, 5, 4, 2, 12, 10, 8, 8, 6, 4, 2, 15, 13, 10, 8, 6, 5, 3, 1,
+ 2, 3, 3, 4, 5, 6, 1, 3, 3, 4, 4, 4, 5, 4, 5, 4, 4, 4, 4,
+ 4, 7, 7, 7, 6, 6, 6, 5, 8, 12, 11, 10, 10, 9, 8, 12, 16, 14, 13,
+ 12, 11, 10, 15, 20, 16, 14, 14, 12, 11, 11, 10, 10, 10, 11, 10, 6, 12, 12,
+ 11, 11, 12, 10, 5, 12, 14, 13, 12, 12, 10, 7, 12, 17, 15, 15, 15, 13, 10,
+ 15, 22, 20, 19, 18, 16, 12, 19, 23, 25, 22, 20, 18, 13, 20, 25, 27, 24, 22,
+ 19, 15, 19, 19, 18, 17, 15, 12, 9, 19, 22, 19, 18, 16, 12, 8, 19, 23, 21,
+ 19, 16, 13, 10, 19, 23, 24, 22, 19, 17, 13, 21, 27, 29, 27, 23, 20, 15, 24,
+ 28, 34, 29, 25, 20, 17, 26, 30, 34, 34, 27, 23, 18, 25, 28, 26, 20, 17, 14,
+ 11, 25, 28, 28, 22, 18, 14, 11, 25, 28, 30, 23, 19, 16, 12, 25, 29, 32, 27,
+ 23, 19, 16, 27, 31, 36, 33, 27, 22, 18, 29, 33, 38, 36, 29, 24, 20, 30, 36,
+ 38, 38, 32, 26, 21, 6, 10, 15, 18, 18, 17, 15, 5, 9, 13, 16, 17, 15, 12,
+ 3, 7, 11, 14, 15, 13, 10, 2, 5, 8, 11, 13, 13, 9, 2, 2, 6, 9, 11,
+ 13, 10, 5, 5, 5, 8, 11, 13, 10, 11, 10, 6, 6, 10, 13, 9, 3, 7, 12,
+ 15, 15, 13, 10, 2, 6, 10, 13, 15, 13, 7, 2, 4, 8, 11, 12, 10, 4, 2,
+ 2, 5, 8, 8, 8, 3, 2, 3, 3, 6, 7, 7, 3, 7, 7, 6, 5, 5, 6,
+ 3, 14, 12, 9, 5, 4, 4, 3, 2, 4, 7, 9, 10, 9, 4, 2, 3, 5, 7,
+ 8, 7, 2, 1, 2, 4, 5, 4, 4, 1, 0, 2, 1, 1, 2, 1, 2, 4, 4,
+ 4, 4, 4, 3, 2, 10, 10, 9, 8, 6, 3, 2, 16, 15, 11, 9, 7, 4, 2,
+ 1, 1, 1, 2, 2, 3, 3, 0, 1, 1, 1, 1, 1, 4, 1, 1, 2, 2, 2,
+ 2, 4, 3, 3, 3, 4, 4, 4, 5, 5, 8, 7, 8, 8, 7, 6, 10, 13, 12,
+ 12, 10, 9, 8, 16, 18, 15, 13, 12, 11, 10, 7, 7, 8, 8, 9, 7, 3, 9,
+ 9, 9, 10, 9, 8, 4, 9, 10, 11, 11, 11, 10, 5, 9, 13, 13, 13, 13, 12,
+ 8, 11, 16, 16, 16, 15, 15, 10, 14, 19, 19, 18, 17, 16, 12, 18, 21, 21, 19,
+ 18, 17, 14, 16, 16, 16, 16, 14, 11, 6, 16, 19, 17, 17, 15, 12, 7, 16, 20,
+ 19, 18, 16, 13, 8, 15, 20, 20, 19, 17, 15, 12, 17, 21, 23, 21, 19, 17, 14,
+ 19, 22, 25, 24, 21, 18, 15, 21, 23, 27, 25, 22, 18, 16, 21, 25, 23, 19, 17,
+ 14, 9, 21, 25, 26, 20, 17, 15, 10, 22, 25, 27, 21, 18, 15, 12, 21, 24, 28,
+ 22, 18, 17, 15, 20, 25, 29, 26, 21, 19, 16, 22, 26, 29, 28, 23, 20, 17, 24,
+ 27, 30, 30, 24, 21, 18, 3, 3, 5, 8, 8, 6, 3, 2, 3, 4, 7, 8, 5,
+ 3, 2, 3, 4, 5, 6, 4, 2, 2, 2, 3, 3, 4, 2, 2, 1, 2, 2, 2,
+ 3, 2, 2, 5, 5, 5, 4, 3, 2, 2, 11, 9, 7, 5, 3, 2, 2, 2, 3,
+ 4, 6, 5, 4, 3, 2, 3, 4, 5, 5, 3, 2, 1, 2, 3, 3, 3, 3, 2,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 7, 6, 7, 6, 3,
+ 2, 2, 14, 12, 8, 6, 4, 2, 2, 1, 2, 3, 3, 3, 3, 3, 1, 2, 3,
+ 3, 3, 3, 3, 1, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 2, 4,
+ 4, 3, 3, 4, 2, 3, 10, 9, 8, 7, 5, 3, 3, 17, 15, 11, 8, 6, 5,
+ 4, 2, 3, 3, 4, 4, 4, 7, 2, 4, 4, 5, 5, 5, 8, 3, 5, 5, 6,
+ 6, 6, 8, 5, 6, 6, 6, 7, 7, 8, 6, 10, 10, 10, 10, 10, 9, 10, 16,
+ 15, 14, 13, 11, 11, 16, 21, 18, 16, 14, 13, 12, 10, 11, 11, 11, 12, 11, 7,
+ 11, 12, 12, 12, 13, 12, 8, 12, 13, 14, 14, 14, 13, 9, 12, 16, 16, 15, 15,
+ 15, 11, 14, 20, 19, 19, 19, 17, 12, 17, 23, 25, 24, 22, 20, 14, 20, 27, 29,
+ 26, 24, 22, 16, 19, 21, 21, 20, 18, 14, 9, 20, 23, 23, 23, 19, 14, 10, 19,
+ 25, 25, 24, 21, 16, 11, 19, 24, 26, 26, 22, 18, 14, 21, 26, 31, 29, 27, 21,
+ 16, 23, 29, 34, 34, 28, 24, 17, 26, 31, 35, 34, 31, 25, 20, 28, 34, 32, 26,
+ 22, 17, 12, 27, 34, 34, 28, 23, 18, 13, 27, 33, 37, 30, 24, 19, 14, 28, 33,
+ 38, 31, 26, 22, 18, 27, 34, 39, 36, 30, 25, 19, 29, 36, 39, 39, 33, 27, 22,
+ 33, 37, 39, 41, 34, 30, 24, 5, 8, 9, 10, 10, 9, 8, 4, 7, 9, 10, 9,
+ 8, 7, 3, 6, 8, 8, 8, 7, 5, 2, 4, 6, 6, 7, 5, 4, 1, 2, 4,
+ 5, 5, 5, 4, 5, 5, 7, 6, 5, 5, 4, 10, 10, 8, 7, 6, 5, 4, 3,
+ 6, 8, 9, 8, 8, 6, 2, 5, 7, 9, 8, 7, 5, 1, 4, 7, 7, 7, 6,
+ 4, 1, 2, 4, 5, 5, 4, 3, 2, 2, 4, 5, 4, 4, 3, 7, 6, 8, 7,
+ 5, 4, 3, 14, 11, 9, 8, 5, 4, 3, 2, 4, 6, 6, 7, 5, 6, 1, 2,
+ 5, 5, 6, 5, 5, 1, 2, 3, 3, 3, 3, 3, 1, 1, 0, 0, 0, 0, 3,
+ 5, 4, 3, 3, 3, 3, 3, 10, 9, 8, 7, 5, 4, 3, 16, 15, 11, 8, 7,
+ 6, 5, 1, 4, 5, 5, 6, 6, 9, 2, 5, 5, 6, 7, 7, 8, 4, 6, 6,
+ 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 11, 11, 11, 11, 10, 10, 10,
+ 17, 16, 14, 13, 12, 11, 16, 22, 19, 17, 15, 14, 13, 11, 12, 12, 12, 13, 12,
+ 8, 12, 13, 14, 14, 14, 13, 8, 12, 15, 15, 15, 15, 13, 9, 12, 17, 16, 16,
+ 16, 15, 11, 15, 21, 21, 20, 20, 18, 13, 18, 25, 26, 25, 22, 19, 14, 23, 27,
+ 29, 26, 25, 22, 16, 21, 22, 22, 22, 19, 15, 11, 21, 25, 24, 24, 20, 15, 11,
+ 21, 26, 25, 25, 20, 16, 12, 21, 26, 27, 26, 23, 18, 14, 21, 28, 31, 31, 27,
+ 21, 16, 24, 30, 37, 35, 29, 23, 18, 28, 33, 37, 38, 31, 25, 20, 29, 33, 34,
+ 27, 22, 18, 13, 28, 36, 36, 29, 23, 18, 14, 28, 35, 38, 30, 24, 19, 14, 28,
+ 34, 39, 32, 26, 22, 18, 29, 35, 42, 38, 32, 26, 20, 31, 37, 43, 41, 34, 27,
+ 22, 33, 39, 44, 44, 37, 30, 23, 5, 9, 12, 15, 15, 13, 10, 4, 8, 11, 14,
+ 15, 12, 9, 3, 6, 10, 13, 13, 10, 7, 2, 4, 7, 10, 11, 8, 7, 1, 2,
+ 5, 8, 10, 9, 7, 5, 5, 7, 8, 9, 8, 7, 10, 10, 8, 8, 8, 8, 7,
+ 3, 7, 10, 13, 12, 10, 7, 2, 5, 9, 12, 12, 9, 5, 1, 4, 8, 10, 10,
+ 7, 4, 1, 2, 5, 7, 7, 5, 3, 3, 2, 4, 6, 6, 6, 3, 7, 6, 8,
+ 8, 6, 5, 3, 13, 12, 9, 8, 6, 4, 3, 1, 4, 6, 7, 8, 6, 6, 1,
+ 2, 5, 6, 6, 5, 4, 1, 1, 3, 3, 3, 3, 3, 1, 1, 0, 0, 0, 0,
+ 3, 5, 4, 3, 3, 3, 3, 3, 10, 8, 8, 7, 5, 4, 3, 16, 14, 11, 9,
+ 7, 5, 5, 1, 4, 5, 5, 6, 7, 8, 1, 5, 6, 6, 7, 7, 7, 5, 6,
+ 6, 6, 6, 7, 7, 8, 7, 7, 7, 7, 7, 6, 9, 11, 11, 11, 11, 11, 9,
+ 11, 17, 16, 15, 13, 12, 11, 16, 22, 19, 17, 15, 14, 12, 11, 12, 12, 13, 14,
+ 13, 9, 12, 14, 13, 14, 15, 13, 8, 12, 15, 15, 14, 15, 13, 9, 12, 17, 16,
+ 16, 16, 15, 11, 15, 22, 20, 20, 20, 18, 12, 18, 25, 27, 25, 22, 19, 14, 23,
+ 28, 29, 27, 25, 22, 16, 21, 22, 22, 22, 19, 15, 11, 21, 24, 24, 24, 20, 15,
+ 11, 21, 26, 26, 25, 20, 16, 11, 21, 26, 28, 26, 22, 18, 15, 22, 27, 31, 30,
+ 26, 21, 16, 25, 31, 37, 35, 29, 23, 18, 28, 33, 37, 37, 32, 25, 20, 29, 35,
+ 33, 27, 22, 18, 14, 29, 36, 36, 30, 23, 19, 14, 30, 35, 38, 30, 24, 19, 14,
+ 29, 35, 40, 33, 27, 22, 18, 28, 35, 40, 38, 31, 25, 20, 31, 37, 43, 40, 34,
+ 27, 22, 33, 40, 44, 43, 37, 29, 23, 6, 9, 13, 16, 16, 14, 10, 5, 8, 11,
+ 15, 15, 12, 9, 3, 6, 10, 13, 14, 11, 7, 2, 4, 7, 10, 12, 9, 6, 1,
+ 3, 5, 8, 11, 9, 6, 5, 6, 7, 8, 10, 9, 6, 10, 9, 8, 8, 9, 9,
+ 6, 3, 7, 10, 13, 13, 10, 7, 2, 6, 9, 12, 12, 9, 5, 1, 4, 8, 10,
+ 10, 7, 3, 1, 2, 5, 7, 7, 5, 2, 3, 2, 4, 6, 6, 5, 2, 7, 6,
+ 8, 8, 5, 5, 2, 13, 10, 9, 8, 6, 4, 3, 1, 4, 6, 7, 8, 6, 6,
+ 1, 3, 5, 6, 6, 5, 4, 1, 2, 3, 3, 3, 3, 3, 2, 1, 0, 0, 0,
+ 0, 3, 5, 4, 4, 4, 4, 3, 3, 11, 9, 8, 7, 6, 4, 3, 15, 13, 10,
+ 9, 7, 6, 5, 1, 5, 5, 6, 6, 7, 9, 2, 6, 6, 6, 7, 7, 7, 5,
+ 6, 7, 7, 7, 7, 6, 8, 7, 8, 7, 7, 7, 6, 9, 11, 12, 11, 12, 10,
+ 9, 11, 17, 16, 15, 13, 12, 11, 15, 21, 19, 17, 15, 14, 13, 11, 13, 13, 13,
+ 14, 13, 9, 12, 14, 14, 14, 15, 13, 8, 12, 16, 15, 15, 15, 13, 10, 13, 18,
+ 17, 17, 16, 15, 11, 14, 22, 21, 21, 21, 18, 13, 19, 26, 27, 25, 22, 20, 15,
+ 22, 27, 29, 27, 25, 22, 16, 21, 24, 22, 22, 19, 16, 11, 22, 26, 25, 24, 21,
+ 16, 11, 21, 28, 26, 25, 20, 16, 12, 21, 27, 27, 27, 23, 19, 15, 23, 28, 34,
+ 31, 27, 22, 16, 25, 31, 37, 35, 28, 24, 18, 28, 33, 37, 37, 32, 26, 19, 31,
+ 35, 33, 29, 22, 18, 14, 30, 36, 36, 30, 23, 18, 15, 29, 35, 37, 31, 24, 20,
+ 14, 31, 36, 39, 33, 28, 22, 18, 29, 35, 40, 37, 32, 26, 20, 31, 38, 42, 41,
+ 34, 27, 22, 34, 39, 44, 43, 37, 31, 24, 6, 9, 12, 16, 16, 13, 11, 5, 8,
+ 12, 15, 16, 12, 9, 3, 7, 10, 13, 14, 11, 7, 2, 5, 8, 10, 13, 9, 6,
+ 1, 3, 6, 8, 12, 10, 7, 5, 5, 7, 8, 11, 10, 6, 8, 7, 7, 7, 9,
+ 9, 7, 3, 7, 10, 13, 13, 10, 7, 2, 6, 9, 12, 12, 9, 5, 1, 4, 8,
+ 10, 10, 7, 3, 1, 2, 5, 7, 7, 5, 3, 3, 2, 4, 6, 6, 5, 3, 7,
+ 6, 7, 7, 5, 5, 3, 11, 8, 7, 7, 5, 4, 3, 2, 5, 6, 7, 8, 6,
+ 6, 1, 3, 5, 6, 6, 5, 4, 1, 2, 4, 3, 3, 3, 3, 2, 1, 0, 0,
+ 0, 0, 2, 6, 4, 4, 4, 4, 3, 2, 9, 8, 6, 6, 5, 4, 2, 13, 10,
+ 8, 7, 7, 6, 5, 1, 5, 5, 6, 6, 7, 9, 2, 6, 6, 7, 7, 7, 7,
+ 6, 6, 7, 7, 7, 7, 6, 8, 7, 8, 8, 7, 8, 6, 9, 12, 12, 11, 11,
+ 10, 9, 10, 15, 15, 14, 13, 12, 11, 12, 18, 17, 15, 14, 14, 13, 12, 13, 13,
+ 13, 14, 13, 9, 13, 14, 14, 15, 15, 13, 7, 13, 16, 16, 15, 15, 13, 10, 13,
+ 18, 17, 16, 17, 15, 11, 15, 23, 21, 21, 20, 18, 13, 18, 24, 26, 24, 22, 20,
+ 14, 20, 25, 28, 25, 23, 22, 16, 22, 24, 22, 21, 19, 15, 11, 22, 25, 24, 23,
+ 20, 16, 12, 22, 28, 26, 24, 20, 16, 12, 22, 26, 27, 25, 22, 19, 15, 23, 29,
+ 33, 30, 25, 22, 16, 25, 30, 35, 33, 28, 23, 18, 26, 31, 36, 36, 30, 25, 20,
+ 30, 34, 31, 26, 22, 18, 14, 30, 33, 33, 28, 22, 19, 14, 29, 33, 35, 28, 23,
+ 19, 15, 29, 34, 37, 30, 26, 22, 18, 29, 34, 39, 36, 29, 24, 21, 31, 36, 40,
+ 39, 32, 27, 21, 32, 37, 40, 40, 33, 27, 23, 8, 11, 13, 15, 15, 13, 10, 7,
+ 10, 12, 15, 15, 12, 8, 6, 8, 11, 13, 14, 10, 7, 5, 7, 9, 10, 12, 9,
+ 6, 2, 5, 7, 9, 12, 9, 6, 3, 5, 6, 8, 11, 9, 6, 4, 5, 6, 8,
+ 10, 9, 6, 6, 8, 11, 13, 12, 10, 7, 6, 8, 10, 12, 12, 8, 5, 4, 7,
+ 9, 10, 9, 7, 4, 2, 5, 7, 8, 7, 5, 3, 1, 3, 6, 7, 6, 5, 3,
+ 3, 4, 5, 6, 6, 5, 3, 6, 5, 5, 6, 5, 4, 3, 4, 7, 7, 7, 8,
+ 7, 6, 2, 6, 7, 7, 6, 5, 4, 1, 5, 5, 5, 4, 4, 2, 2, 2, 3,
+ 3, 3, 2, 0, 3, 3, 2, 2, 2, 1, 0, 5, 4, 3, 2, 3, 1, 0, 9,
+ 5, 4, 3, 2, 2, 2, 2, 4, 4, 5, 6, 8, 8, 1, 5, 4, 5, 6, 5,
+ 6, 1, 6, 5, 5, 5, 5, 5, 6, 6, 5, 5, 5, 5, 4, 5, 8, 7, 7,
+ 7, 7, 6, 6, 10, 9, 8, 8, 8, 7, 9, 14, 12, 10, 10, 9, 9, 11, 11,
+ 11, 11, 12, 11, 8, 12, 13, 12, 12, 12, 11, 6, 12, 14, 14, 13, 12, 11, 7,
+ 12, 16, 14, 13, 13, 12, 8, 13, 18, 16, 16, 15, 14, 9, 14, 19, 20, 18, 16,
+ 14, 10, 15, 20, 22, 21, 18, 16, 12, 19, 21, 18, 18, 16, 13, 9, 19, 22, 20,
+ 19, 17, 13, 9, 20, 24, 22, 20, 16, 13, 10, 20, 24, 23, 21, 17, 15, 11, 19,
+ 24, 26, 24, 21, 16, 12, 20, 24, 30, 27, 23, 17, 14, 21, 26, 29, 30, 25, 19,
+ 14, 26, 30, 27, 22, 18, 14, 12, 26, 30, 30, 23, 18, 15, 12, 26, 30, 32, 24,
+ 19, 16, 12, 26, 30, 33, 26, 21, 16, 14, 25, 29, 34, 30, 24, 19, 15, 25, 30,
+ 35, 34, 27, 21, 16, 27, 32, 36, 35, 29, 23, 17, 9, 13, 17, 22, 21, 18, 16,
+ 8, 12, 16, 20, 21, 18, 15, 7, 10, 14, 18, 20, 17, 13, 6, 9, 12, 15, 17,
+ 15, 11, 4, 5, 8, 11, 13, 14, 12, 2, 3, 6, 10, 12, 14, 12, 7, 5, 5,
+ 8, 12, 13, 11, 7, 10, 15, 18, 18, 15, 13, 6, 9, 13, 16, 17, 15, 11, 5,
+ 8, 11, 14, 15, 13, 9, 5, 6, 9, 11, 12, 11, 6, 2, 3, 5, 8, 9, 10,
+ 6, 3, 3, 4, 6, 8, 8, 6, 10, 8, 4, 5, 6, 6, 5, 5, 8, 10, 11,
+ 13, 11, 8, 5, 7, 9, 10, 11, 10, 7, 4, 6, 7, 8, 9, 8, 6, 4, 4,
+ 5, 5, 5, 6, 3, 0, 2, 1, 1, 1, 2, 3, 6, 6, 5, 4, 1, 2, 3,
+ 11, 10, 7, 5, 2, 1, 2, 5, 6, 6, 7, 7, 8, 7, 4, 5, 6, 6, 7,
+ 7, 7, 3, 5, 6, 6, 6, 6, 6, 2, 3, 3, 4, 4, 4, 3, 2, 3, 4,
+ 4, 4, 3, 3, 6, 8, 7, 7, 6, 5, 5, 11, 13, 9, 8, 8, 7, 6, 6,
+ 7, 7, 7, 8, 7, 7, 7, 8, 8, 9, 9, 7, 7, 7, 10, 10, 10, 11, 9,
+ 6, 7, 11, 10, 10, 10, 10, 5, 7, 11, 10, 10, 10, 10, 6, 9, 13, 13, 12,
+ 11, 10, 8, 12, 15, 15, 13, 12, 11, 9, 14, 15, 14, 14, 13, 9, 7, 14, 16,
+ 15, 15, 14, 11, 6, 14, 17, 16, 16, 14, 11, 7, 14, 16, 16, 15, 14, 11, 8,
+ 13, 15, 17, 16, 14, 11, 9, 13, 16, 20, 18, 14, 12, 10, 15, 18, 20, 19, 16,
+ 13, 10, 18, 23, 21, 17, 15, 12, 8, 18, 22, 23, 18, 16, 13, 9, 18, 23, 24,
+ 18, 16, 13, 10, 19, 22, 24, 19, 15, 13, 10, 17, 20, 23, 20, 16, 13, 11, 17,
+ 20, 23, 22, 18, 14, 11, 18, 22, 24, 24, 19, 15, 12, 7, 8, 10, 12, 12, 11,
+ 9, 6, 8, 9, 12, 12, 9, 8, 6, 7, 8, 10, 11, 8, 6, 6, 6, 6, 7,
+ 9, 6, 3, 3, 3, 4, 4, 4, 3, 2, 1, 2, 2, 2, 3, 3, 2, 7, 6,
+ 3, 2, 3, 3, 2, 6, 7, 8, 10, 10, 9, 8, 6, 7, 8, 10, 9, 8, 7,
+ 5, 6, 7, 8, 8, 7, 5, 4, 5, 5, 6, 5, 5, 2, 2, 2, 2, 3, 2,
+ 2, 2, 3, 3, 3, 2, 2, 2, 2, 10, 8, 5, 3, 1, 2, 2, 5, 6, 7,
+ 8, 9, 9, 8, 4, 6, 7, 8, 8, 8, 8, 4, 5, 6, 6, 6, 6, 6, 4,
+ 4, 4, 4, 4, 4, 3, 2, 0, 1, 1, 1, 2, 3, 6, 5, 5, 3, 1, 1,
+ 2, 12, 11, 7, 4, 2, 1, 2, 4, 6, 7, 8, 9, 9, 9, 4, 5, 7, 8,
+ 8, 8, 9, 3, 5, 6, 7, 7, 7, 7, 4, 4, 5, 5, 5, 5, 5, 3, 6,
+ 6, 6, 7, 7, 7, 6, 12, 11, 10, 9, 7, 8, 12, 17, 14, 12, 10, 9, 9,
+ 9, 10, 10, 10, 11, 10, 9, 10, 11, 11, 12, 12, 11, 9, 11, 12, 13, 13, 13,
+ 12, 8, 10, 14, 13, 14, 14, 13, 8, 11, 16, 16, 16, 16, 14, 9, 13, 19, 21,
+ 20, 19, 16, 11, 17, 22, 24, 22, 20, 18, 12, 18, 20, 20, 20, 17, 13, 9, 18,
+ 22, 22, 22, 19, 14, 9, 18, 24, 24, 24, 19, 15, 10, 19, 23, 25, 24, 21, 16,
+ 11, 17, 23, 27, 25, 23, 18, 13, 19, 25, 31, 28, 25, 20, 14, 23, 28, 31, 30,
+ 26, 22, 16, 27, 33, 32, 26, 21, 16, 11, 26, 32, 33, 28, 23, 17, 12, 27, 32,
+ 35, 28, 23, 18, 13, 26, 32, 36, 29, 25, 19, 14, 26, 31, 33, 31, 26, 22, 16,
+ 25, 30, 35, 33, 28, 23, 18, 27, 31, 34, 35, 30, 25, 20, 9, 11, 12, 14, 13,
+ 13, 12, 8, 11, 12, 13, 13, 11, 10, 6, 10, 11, 12, 12, 10, 8, 5, 8, 9,
+ 10, 10, 8, 5, 2, 5, 6, 6, 6, 5, 4, 1, 3, 4, 5, 5, 5, 4, 7,
+ 7, 5, 4, 5, 5, 4, 6, 10, 11, 13, 12, 12, 10, 5, 9, 11, 12, 12, 11,
+ 9, 4, 7, 10, 11, 10, 9, 7, 4, 5, 7, 8, 8, 7, 4, 2, 2, 4, 5,
+ 5, 4, 4, 4, 3, 5, 4, 4, 4, 4, 10, 8, 6, 5, 3, 4, 4, 5, 7,
+ 9, 10, 11, 10, 10, 4, 6, 8, 9, 10, 8, 8, 4, 5, 7, 7, 7, 7, 6,
+ 4, 3, 3, 3, 4, 4, 2, 2, 1, 0, 0, 0, 1, 2, 6, 5, 4, 3, 2,
+ 1, 2, 12, 10, 7, 5, 4, 3, 2, 4, 6, 7, 8, 10, 11, 10, 3, 6, 7,
+ 8, 9, 9, 9, 3, 6, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 7, 6, 4,
+ 8, 7, 8, 8, 8, 8, 7, 13, 12, 11, 10, 9, 9, 12, 18, 15, 13, 11, 10,
+ 10, 11, 12, 12, 12, 13, 12, 10, 11, 13, 13, 13, 14, 12, 9, 12, 14, 14, 14,
+ 14, 13, 9, 11, 16, 15, 15, 15, 14, 9, 12, 18, 17, 17, 17, 15, 11, 14, 20,
+ 21, 21, 19, 16, 12, 18, 23, 26, 23, 21, 18, 13, 20, 22, 22, 22, 19, 15, 11,
+ 19, 24, 23, 24, 19, 15, 11, 20, 26, 24, 24, 20, 15, 11, 20, 25, 26, 26, 21,
+ 17, 12, 19, 25, 29, 27, 23, 18, 13, 20, 26, 32, 32, 26, 19, 14, 23, 29, 33,
+ 35, 28, 22, 16, 27, 35, 33, 28, 21, 17, 13, 29, 34, 36, 29, 23, 18, 13, 28,
+ 35, 38, 30, 24, 19, 14, 29, 34, 38, 30, 25, 20, 15, 27, 34, 38, 34, 28, 22,
+ 17, 27, 34, 39, 38, 31, 24, 19, 30, 36, 40, 41, 34, 26, 21, 9, 13, 16, 19,
+ 18, 17, 14, 8, 11, 15, 18, 18, 16, 13, 6, 10, 14, 16, 16, 13, 10, 5, 8,
+ 11, 13, 14, 11, 8, 2, 5, 7, 10, 11, 9, 7, 2, 3, 5, 7, 10, 9, 7,
+ 7, 6, 6, 7, 9, 9, 7, 7, 10, 14, 16, 16, 14, 11, 5, 9, 12, 15, 16,
+ 13, 9, 4, 7, 11, 13, 13, 11, 7, 4, 5, 8, 10, 10, 9, 4, 2, 2, 4,
+ 7, 7, 7, 4, 4, 3, 5, 5, 5, 6, 4, 9, 7, 6, 5, 4, 5, 4, 5,
+ 7, 9, 10, 12, 10, 9, 4, 6, 8, 9, 10, 9, 8, 4, 5, 7, 7, 7, 7,
+ 5, 4, 3, 3, 3, 4, 4, 2, 1, 1, 0, 0, 0, 1, 2, 6, 5, 4, 3,
+ 2, 1, 2, 11, 9, 7, 5, 3, 2, 2, 4, 6, 7, 8, 9, 11, 10, 4, 6,
+ 7, 8, 8, 9, 8, 3, 6, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 5,
+ 5, 8, 7, 7, 8, 8, 7, 7, 13, 12, 11, 10, 9, 9, 11, 17, 15, 13, 11,
+ 10, 10, 11, 12, 12, 12, 13, 13, 10, 11, 13, 13, 14, 14, 13, 8, 11, 14, 15,
+ 14, 14, 12, 9, 11, 17, 15, 15, 15, 13, 9, 11, 18, 17, 17, 17, 15, 10, 15,
+ 21, 22, 21, 19, 16, 12, 19, 23, 25, 23, 21, 18, 13, 21, 22, 22, 21, 19, 15,
+ 11, 20, 24, 24, 23, 20, 15, 10, 21, 26, 26, 24, 20, 15, 11, 20, 26, 26, 25,
+ 21, 16, 12, 19, 25, 29, 27, 23, 18, 13, 21, 26, 33, 32, 25, 20, 15, 24, 30,
+ 33, 33, 28, 22, 16, 28, 35, 33, 27, 21, 17, 13, 29, 35, 36, 29, 22, 18, 13,
+ 29, 35, 39, 30, 23, 18, 14, 29, 34, 38, 32, 25, 19, 14, 28, 33, 39, 34, 27,
+ 22, 17, 28, 33, 39, 38, 30, 24, 18, 29, 34, 39, 40, 33, 26, 20, 9, 13, 16,
+ 20, 20, 18, 15, 8, 12, 15, 19, 20, 17, 13, 7, 10, 14, 17, 18, 14, 11, 5,
+ 8, 11, 14, 16, 13, 8, 3, 5, 7, 10, 13, 10, 8, 2, 3, 5, 8, 11, 10,
+ 8, 3, 4, 4, 7, 10, 11, 8, 7, 10, 14, 17, 16, 14, 11, 5, 9, 13, 17,
+ 16, 12, 9, 5, 8, 11, 14, 14, 11, 7, 4, 6, 8, 11, 10, 9, 4, 2, 2,
+ 5, 7, 7, 7, 4, 3, 2, 4, 5, 6, 6, 4, 6, 3, 3, 5, 4, 5, 4,
+ 5, 8, 10, 11, 12, 10, 10, 4, 6, 8, 9, 10, 9, 8, 4, 5, 7, 7, 7,
+ 7, 5, 4, 4, 3, 4, 4, 4, 2, 1, 1, 0, 0, 0, 1, 2, 5, 3, 3,
+ 2, 2, 1, 2, 7, 5, 4, 4, 3, 2, 2, 4, 6, 7, 8, 9, 11, 10, 4,
+ 6, 7, 8, 9, 9, 8, 3, 6, 7, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6,
+ 5, 5, 8, 8, 8, 8, 7, 7, 5, 10, 10, 10, 10, 8, 8, 7, 13, 12, 11,
+ 11, 10, 10, 11, 12, 12, 13, 13, 12, 10, 12, 13, 13, 14, 14, 13, 8, 12, 15,
+ 15, 14, 14, 13, 9, 11, 17, 15, 15, 15, 13, 9, 12, 18, 17, 17, 16, 15, 10,
+ 14, 19, 21, 19, 19, 16, 12, 15, 20, 23, 21, 21, 18, 13, 22, 22, 22, 21, 19,
+ 15, 11, 21, 24, 23, 23, 19, 15, 11, 20, 26, 25, 24, 20, 15, 11, 21, 25, 26,
+ 26, 21, 16, 12, 20, 25, 30, 27, 23, 18, 13, 21, 26, 32, 31, 25, 19, 15, 21,
+ 26, 32, 31, 27, 21, 16, 29, 35, 32, 26, 22, 17, 13, 29, 34, 35, 29, 23, 18,
+ 14, 29, 35, 37, 30, 23, 18, 14, 29, 34, 38, 31, 25, 20, 15, 28, 32, 37, 33,
+ 27, 22, 16, 28, 34, 38, 36, 30, 24, 18, 29, 34, 39, 39, 32, 26, 20, 8, 12,
+ 16, 19, 20, 17, 14, 7, 11, 15, 19, 19, 16, 12, 6, 9, 13, 16, 17, 14, 10,
+ 4, 7, 10, 13, 15, 12, 8, 1, 4, 7, 9, 13, 11, 8, 2, 3, 5, 8, 12,
+ 11, 8, 4, 4, 4, 7, 10, 11, 8, 6, 10, 13, 16, 16, 14, 10, 5, 8, 12,
+ 15, 16, 12, 8, 3, 7, 11, 13, 13, 10, 6, 3, 5, 8, 10, 9, 8, 4, 1,
+ 2, 4, 7, 7, 7, 4, 3, 3, 4, 6, 5, 6, 4, 6, 4, 3, 5, 4, 4,
+ 4, 4, 7, 9, 10, 11, 9, 8, 3, 5, 8, 9, 9, 8, 6, 3, 4, 6, 6,
+ 6, 6, 4, 3, 2, 3, 3, 3, 3, 1, 2, 2, 1, 1, 1, 0, 1, 4, 3,
+ 3, 2, 2, 2, 1, 8, 6, 4, 3, 3, 2, 2, 3, 5, 6, 7, 8, 10, 9,
+ 2, 6, 6, 7, 7, 8, 7, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 5, 6, 8, 8, 8, 8, 8, 7, 5, 10, 10, 9, 9, 8, 8, 8, 14, 12,
+ 11, 10, 10, 10, 11, 12, 12, 12, 13, 13, 9, 12, 14, 13, 14, 14, 12, 7, 12,
+ 15, 15, 14, 14, 13, 8, 12, 17, 15, 15, 15, 13, 9, 13, 19, 17, 17, 16, 15,
+ 10, 14, 19, 20, 18, 18, 16, 11, 14, 20, 23, 21, 19, 18, 13, 21, 23, 22, 21,
+ 18, 14, 10, 22, 25, 23, 23, 19, 15, 11, 21, 26, 25, 23, 19, 15, 11, 21, 25,
+ 26, 24, 21, 16, 11, 20, 25, 28, 26, 22, 17, 13, 21, 26, 30, 28, 23, 19, 15,
+ 21, 27, 30, 30, 25, 20, 16, 28, 33, 30, 25, 21, 17, 13, 28, 33, 33, 26, 22,
+ 18, 13, 29, 33, 35, 27, 22, 18, 14, 29, 32, 35, 29, 23, 19, 15, 27, 32, 36,
+ 31, 25, 20, 16, 28, 32, 35, 34, 27, 23, 18, 27, 31, 36, 35, 29, 23, 19, 8,
+ 10, 13, 16, 15, 13, 10, 7, 10, 12, 15, 15, 12, 8, 6, 8, 11, 13, 14, 10,
+ 7, 5, 6, 9, 10, 13, 9, 6, 2, 5, 7, 9, 12, 9, 6, 3, 5, 6, 8,
+ 11, 10, 6, 4, 4, 6, 8, 10, 9, 6, 6, 9, 11, 13, 12, 10, 7, 5, 8,
+ 10, 13, 12, 8, 5, 4, 7, 9, 10, 9, 7, 4, 2, 5, 7, 8, 7, 6, 3,
+ 1, 3, 5, 7, 6, 5, 3, 3, 3, 5, 6, 5, 5, 3, 6, 4, 5, 6, 5,
+ 4, 3, 4, 7, 8, 8, 9, 7, 6, 2, 6, 7, 7, 7, 5, 4, 2, 5, 6,
+ 5, 4, 4, 2, 2, 3, 3, 3, 3, 2, 0, 3, 3, 2, 2, 2, 1, 0, 5,
+ 4, 3, 2, 2, 1, 0, 8, 5, 3, 3, 2, 2, 1, 2, 4, 4, 5, 7, 8,
+ 8, 1, 5, 4, 5, 6, 6, 6, 1, 6, 5, 5, 5, 5, 5, 5, 6, 5, 5,
+ 5, 5, 4, 5, 8, 7, 7, 7, 6, 6, 5, 10, 9, 8, 8, 8, 7, 8, 13,
+ 12, 10, 9, 9, 9, 11, 11, 11, 11, 12, 11, 8, 12, 12, 12, 13, 12, 11, 6,
+ 12, 14, 14, 13, 12, 11, 7, 12, 16, 14, 13, 13, 12, 8, 13, 18, 16, 16, 15,
+ 13, 9, 14, 19, 20, 17, 16, 14, 10, 15, 20, 23, 20, 18, 16, 12, 20, 21, 19,
+ 18, 15, 13, 9, 20, 22, 20, 18, 16, 13, 9, 20, 24, 22, 20, 16, 13, 10, 20,
+ 24, 23, 21, 17, 14, 11, 19, 23, 26, 24, 20, 16, 12, 20, 24, 30, 28, 23, 17,
+ 14, 21, 26, 29, 30, 25, 19, 14, 26, 30, 28, 22, 17, 15, 12, 26, 30, 29, 24,
+ 18, 15, 11, 26, 30, 32, 25, 19, 16, 12, 25, 29, 33, 26, 21, 17, 13, 25, 29,
+ 33, 30, 24, 20, 15, 26, 31, 35, 34, 27, 20, 16, 27, 32, 35, 35, 29, 23, 17,
+ 14, 17, 21, 24, 24, 22, 19, 13, 16, 20, 24, 25, 21, 18, 12, 15, 18, 21, 23,
+ 19, 15, 12, 13, 15, 17, 21, 16, 12, 9, 9, 11, 14, 14, 15, 12, 5, 5, 8,
+ 11, 13, 14, 12, 2, 3, 6, 9, 13, 15, 12, 13, 15, 19, 21, 22, 19, 17, 12,
+ 14, 17, 20, 21, 18, 14, 11, 13, 15, 18, 18, 16, 12, 11, 11, 13, 14, 15, 12,
+ 7, 8, 8, 9, 10, 9, 10, 7, 3, 3, 5, 7, 9, 9, 7, 3, 3, 3, 6,
+ 8, 8, 7, 11, 13, 14, 16, 18, 17, 15, 11, 12, 14, 15, 16, 15, 14, 10, 11,
+ 13, 13, 13, 13, 12, 10, 10, 10, 10, 11, 9, 5, 6, 6, 6, 6, 5, 5, 5,
+ 0, 2, 1, 2, 4, 4, 5, 4, 4, 2, 1, 3, 4, 5, 10, 11, 13, 14, 15,
+ 16, 15, 10, 11, 12, 14, 14, 15, 14, 9, 10, 12, 12, 12, 13, 12, 6, 9, 9,
+ 9, 10, 9, 7, 4, 5, 4, 5, 5, 4, 4, 0, 2, 2, 2, 3, 3, 5, 4,
+ 6, 3, 3, 3, 4, 5, 9, 10, 12, 13, 14, 15, 15, 8, 9, 11, 12, 13, 13,
+ 14, 8, 9, 10, 10, 11, 11, 12, 8, 8, 8, 8, 9, 8, 5, 5, 8, 7, 7,
+ 7, 6, 5, 4, 7, 7, 7, 7, 7, 5, 5, 8, 9, 8, 8, 8, 5, 11, 12,
+ 12, 13, 12, 14, 15, 11, 13, 13, 13, 12, 12, 13, 11, 14, 14, 13, 11, 10, 11,
+ 11, 13, 13, 13, 11, 9, 5, 9, 11, 13, 12, 10, 8, 5, 8, 11, 14, 13, 11,
+ 8, 6, 8, 12, 15, 15, 11, 9, 7, 15, 19, 18, 15, 13, 13, 14, 15, 19, 20,
+ 16, 13, 11, 12, 15, 18, 21, 16, 14, 11, 9, 15, 18, 20, 15, 13, 9, 6, 14,
+ 16, 19, 16, 11, 9, 7, 13, 15, 18, 17, 13, 10, 8, 12, 16, 19, 19, 14, 11,
+ 8, 12, 14, 15, 17, 17, 16, 14, 12, 13, 15, 16, 17, 14, 13, 11, 12, 14, 15,
+ 15, 12, 11, 10, 11, 11, 12, 12, 8, 4, 8, 8, 8, 8, 6, 5, 4, 4, 4,
+ 4, 3, 4, 5, 4, 2, 2, 2, 3, 4, 5, 4, 11, 13, 14, 15, 16, 15, 14,
+ 10, 12, 13, 15, 15, 14, 12, 10, 11, 13, 13, 13, 12, 10, 9, 10, 10, 10, 11,
+ 9, 4, 7, 7, 7, 7, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 5, 4, 2,
+ 2, 3, 3, 4, 10, 11, 13, 14, 15, 15, 15, 9, 10, 12, 13, 14, 14, 13, 9,
+ 10, 12, 12, 12, 11, 10, 9, 9, 9, 9, 9, 8, 4, 5, 5, 5, 5, 3, 3,
+ 4, 2, 0, 1, 2, 2, 3, 4, 7, 6, 2, 0, 3, 3, 4, 10, 11, 12, 13,
+ 15, 16, 16, 9, 11, 12, 13, 14, 14, 14, 8, 11, 12, 12, 12, 12, 11, 5, 9,
+ 9, 9, 9, 8, 7, 3, 5, 5, 5, 5, 5, 5, 2, 7, 7, 6, 6, 6, 7,
+ 7, 13, 10, 8, 8, 8, 8, 10, 11, 12, 13, 14, 16, 16, 9, 10, 11, 13, 14,
+ 14, 14, 9, 11, 11, 11, 12, 12, 11, 9, 12, 11, 12, 12, 11, 7, 8, 13, 14,
+ 13, 14, 13, 9, 9, 15, 17, 17, 16, 15, 10, 12, 17, 19, 18, 18, 16, 11, 16,
+ 19, 18, 19, 16, 15, 16, 16, 21, 21, 21, 17, 13, 13, 16, 22, 23, 21, 17, 12,
+ 10, 16, 22, 23, 23, 19, 14, 10, 15, 21, 25, 23, 21, 17, 11, 16, 22, 27, 25,
+ 21, 18, 13, 18, 22, 26, 25, 23, 20, 15, 25, 30, 29, 25, 19, 15, 14, 25, 30,
+ 31, 26, 20, 15, 12, 25, 30, 33, 26, 21, 16, 11, 25, 30, 34, 28, 22, 18, 14,
+ 24, 29, 32, 27, 23, 20, 16, 24, 27, 30, 29, 24, 21, 17, 23, 27, 30, 30, 25,
+ 22, 19, 13, 16, 17, 18, 18, 17, 16, 12, 15, 17, 18, 18, 16, 14, 11, 14, 16,
+ 16, 15, 13, 11, 10, 12, 13, 13, 13, 10, 5, 7, 9, 10, 10, 8, 6, 5, 3,
+ 5, 7, 5, 6, 6, 5, 2, 3, 5, 5, 6, 6, 5, 11, 14, 16, 17, 17, 17,
+ 15, 10, 13, 15, 16, 17, 15, 13, 9, 12, 15, 15, 14, 13, 10, 9, 9, 12, 13,
+ 11, 9, 5, 7, 6, 8, 9, 6, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 3,
+ 3, 5, 4, 5, 5, 9, 12, 14, 15, 16, 15, 14, 9, 10, 12, 14, 15, 13, 12,
+ 9, 10, 11, 11, 11, 11, 9, 9, 8, 8, 8, 8, 7, 3, 5, 5, 5, 4, 3,
+ 3, 3, 1, 1, 0, 1, 2, 3, 3, 6, 5, 3, 1, 2, 3, 3, 9, 11, 11,
+ 13, 15, 15, 15, 9, 11, 12, 13, 14, 14, 13, 7, 11, 11, 11, 11, 11, 10, 5,
+ 9, 8, 8, 8, 7, 7, 3, 5, 5, 6, 6, 6, 6, 2, 8, 8, 7, 7, 8,
+ 8, 6, 12, 11, 9, 9, 9, 9, 10, 10, 11, 13, 14, 15, 15, 9, 11, 12, 13,
+ 13, 13, 13, 10, 12, 13, 13, 13, 11, 9, 10, 13, 13, 13, 13, 12, 8, 9, 15,
+ 14, 15, 15, 14, 9, 10, 16, 18, 17, 17, 15, 11, 13, 18, 21, 18, 18, 17, 13,
+ 18, 20, 20, 20, 17, 15, 15, 18, 22, 21, 21, 18, 13, 12, 18, 24, 24, 23, 18,
+ 14, 10, 18, 23, 25, 24, 20, 15, 11, 18, 23, 27, 26, 21, 17, 13, 17, 23, 29,
+ 28, 24, 18, 14, 19, 25, 29, 31, 26, 20, 16, 27, 33, 32, 25, 20, 16, 14, 26,
+ 32, 34, 27, 22, 17, 12, 27, 33, 36, 28, 22, 17, 12, 27, 32, 37, 29, 24, 19,
+ 14, 25, 31, 37, 32, 26, 20, 16, 25, 31, 36, 35, 28, 22, 17, 26, 32, 37, 37,
+ 30, 24, 19, 12, 16, 19, 22, 22, 20, 18, 12, 15, 18, 21, 21, 19, 15, 10, 13,
+ 17, 19, 19, 17, 13, 8, 11, 14, 16, 17, 13, 8, 6, 8, 10, 12, 12, 10, 8,
+ 2, 4, 7, 9, 11, 10, 8, 2, 3, 5, 8, 10, 10, 8, 10, 13, 17, 20, 20,
+ 17, 14, 9, 12, 16, 19, 19, 16, 12, 8, 11, 14, 17, 16, 14, 9, 8, 9, 11,
+ 13, 13, 11, 5, 5, 5, 8, 10, 8, 8, 5, 1, 2, 4, 6, 6, 7, 5, 4,
+ 3, 3, 5, 5, 6, 5, 8, 11, 13, 14, 16, 13, 13, 8, 9, 12, 13, 14, 12,
+ 11, 7, 8, 10, 10, 10, 10, 7, 8, 7, 7, 7, 7, 6, 2, 4, 3, 3, 3,
+ 2, 2, 2, 2, 2, 1, 0, 1, 2, 2, 4, 3, 2, 2, 1, 2, 2, 8, 9,
+ 10, 11, 13, 14, 14, 8, 9, 10, 11, 12, 12, 11, 5, 9, 10, 9, 9, 9, 8,
+ 5, 8, 7, 6, 7, 6, 6, 3, 6, 6, 6, 6, 6, 6, 2, 8, 8, 7, 7,
+ 7, 7, 4, 11, 10, 9, 9, 9, 9, 9, 11, 11, 12, 13, 13, 13, 9, 11, 12,
+ 12, 13, 12, 11, 10, 13, 14, 13, 13, 11, 8, 10, 15, 13, 14, 14, 12, 8, 10,
+ 16, 15, 15, 15, 13, 9, 11, 16, 18, 17, 16, 14, 11, 12, 17, 20, 19, 18, 17,
+ 12, 19, 21, 20, 20, 18, 14, 13, 18, 23, 22, 22, 18, 14, 10, 19, 24, 24, 23,
+ 19, 14, 10, 19, 24, 25, 23, 20, 15, 10, 18, 24, 28, 26, 21, 17, 12, 18, 24,
+ 30, 29, 23, 18, 13, 18, 24, 30, 30, 25, 19, 15, 27, 34, 32, 26, 20, 16, 12,
+ 27, 34, 34, 28, 22, 17, 12, 27, 34, 37, 28, 22, 17, 13, 28, 33, 37, 30, 23,
+ 18, 14, 26, 32, 36, 33, 25, 19, 15, 26, 31, 36, 34, 28, 21, 17, 26, 31, 36,
+ 37, 29, 24, 18, 11, 15, 18, 21, 22, 20, 16, 10, 14, 17, 21, 22, 18, 14, 8,
+ 12, 16, 19, 20, 16, 12, 7, 10, 13, 16, 18, 14, 9, 4, 7, 9, 12, 14, 12,
+ 9, 0, 3, 6, 9, 13, 12, 9, 3, 3, 5, 8, 11, 12, 9, 8, 12, 16, 19,
+ 18, 16, 12, 7, 11, 14, 18, 18, 14, 10, 6, 10, 13, 16, 15, 13, 9, 6, 7,
+ 10, 12, 12, 10, 5, 3, 4, 6, 9, 9, 8, 5, 2, 2, 4, 6, 7, 7, 5,
+ 5, 4, 3, 6, 5, 6, 5, 6, 10, 11, 13, 14, 12, 11, 5, 8, 10, 11, 12,
+ 11, 8, 5, 7, 9, 9, 9, 9, 6, 6, 5, 5, 5, 6, 5, 3, 1, 1, 2,
+ 2, 2, 2, 2, 4, 3, 2, 1, 0, 1, 2, 7, 4, 3, 2, 1, 1, 2, 6,
+ 7, 8, 9, 10, 12, 11, 5, 7, 8, 9, 9, 9, 9, 4, 7, 7, 7, 7, 7,
+ 6, 5, 6, 6, 5, 5, 5, 5, 3, 7, 6, 6, 6, 6, 6, 4, 9, 8, 8,
+ 8, 7, 7, 7, 12, 10, 9, 9, 9, 9, 10, 11, 11, 11, 12, 12, 11, 11, 12,
+ 12, 13, 13, 11, 9, 11, 14, 14, 13, 13, 11, 8, 11, 15, 14, 13, 14, 12, 8,
+ 11, 17, 16, 15, 15, 13, 9, 12, 17, 18, 17, 16, 15, 10, 13, 17, 20, 19, 18,
+ 16, 12, 20, 21, 20, 21, 18, 14, 11, 20, 23, 23, 23, 19, 14, 9, 19, 25, 24,
+ 23, 19, 14, 10, 20, 24, 26, 24, 20, 15, 11, 18, 24, 27, 26, 21, 16, 12, 19,
+ 23, 30, 29, 23, 18, 14, 19, 24, 29, 31, 25, 20, 15, 28, 34, 32, 26, 21, 16,
+ 12, 27, 34, 34, 27, 21, 17, 12, 27, 33, 36, 29, 23, 18, 13, 28, 32, 37, 29,
+ 24, 19, 13, 26, 32, 36, 33, 25, 20, 15, 26, 32, 37, 33, 28, 22, 17, 27, 32,
+ 35, 36, 30, 23, 18, 10, 14, 18, 21, 21, 18, 15, 9, 12, 16, 20, 21, 17, 13,
+ 7, 11, 15, 18, 19, 16, 11, 6, 9, 12, 14, 16, 14, 9, 3, 6, 8, 11, 14,
+ 12, 9, 2, 4, 6, 9, 13, 12, 9, 4, 4, 5, 8, 11, 12, 9, 7, 11, 14,
+ 18, 18, 15, 11, 6, 10, 13, 17, 17, 13, 9, 5, 8, 12, 14, 14, 12, 8, 4,
+ 6, 9, 11, 11, 10, 5, 1, 3, 5, 8, 8, 8, 5, 2, 3, 4, 7, 7, 7,
+ 5, 6, 4, 4, 6, 5, 6, 5, 5, 8, 10, 11, 13, 11, 9, 3, 7, 9, 10,
+ 11, 9, 7, 3, 6, 7, 8, 7, 7, 4, 3, 3, 4, 4, 4, 4, 1, 2, 1,
+ 1, 1, 1, 2, 1, 4, 3, 2, 2, 1, 0, 1, 8, 6, 3, 3, 2, 1, 1,
+ 3, 5, 6, 7, 8, 10, 9, 3, 5, 6, 7, 8, 8, 7, 2, 5, 6, 6, 5,
+ 6, 5, 5, 6, 6, 5, 5, 5, 4, 4, 8, 7, 6, 7, 6, 6, 4, 10, 8,
+ 8, 8, 8, 7, 8, 12, 11, 10, 9, 9, 9, 11, 11, 11, 11, 12, 12, 9, 12,
+ 13, 12, 13, 13, 12, 7, 12, 14, 14, 13, 12, 11, 8, 11, 16, 14, 14, 14, 12,
+ 8, 12, 18, 17, 15, 16, 13, 9, 13, 18, 19, 18, 16, 15, 11, 14, 18, 21, 19,
+ 19, 16, 12, 20, 21, 20, 20, 17, 14, 10, 20, 23, 22, 22, 18, 14, 9, 20, 25,
+ 24, 23, 19, 14, 10, 20, 25, 24, 23, 20, 15, 10, 19, 25, 26, 25, 21, 16, 12,
+ 20, 25, 29, 28, 22, 18, 14, 20, 25, 29, 30, 24, 19, 15, 28, 33, 29, 24, 20,
+ 16, 12, 28, 32, 31, 26, 21, 16, 12, 28, 32, 34, 27, 23, 17, 13, 27, 31, 35,
+ 28, 23, 18, 14, 26, 31, 34, 31, 24, 20, 15, 26, 31, 35, 33, 26, 21, 17, 27,
+ 30, 35, 35, 29, 22, 18, 8, 11, 12, 16, 15, 13, 10, 7, 10, 12, 15, 15, 12,
+ 8, 6, 8, 11, 13, 14, 10, 7, 5, 6, 9, 10, 12, 9, 6, 2, 5, 7, 9,
+ 12, 9, 6, 3, 5, 6, 8, 11, 9, 6, 4, 5, 6, 8, 10, 9, 6, 6, 9,
+ 11, 13, 12, 10, 7, 5, 8, 10, 12, 12, 8, 5, 4, 7, 9, 10, 9, 7, 4,
+ 2, 5, 7, 8, 7, 6, 3, 1, 3, 5, 7, 6, 5, 3, 3, 3, 5, 6, 5,
+ 5, 3, 6, 4, 5, 6, 5, 4, 3, 4, 7, 8, 8, 9, 7, 6, 2, 6, 7,
+ 7, 7, 5, 4, 2, 5, 6, 5, 4, 4, 2, 2, 3, 3, 3, 3, 2, 0, 3,
+ 2, 2, 2, 2, 1, 0, 5, 4, 3, 2, 2, 1, 0, 8, 6, 3, 2, 2, 2,
+ 1, 2, 4, 4, 5, 6, 7, 8, 1, 4, 4, 5, 6, 5, 6, 1, 6, 5, 5,
+ 5, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 8, 7, 7, 7, 7, 6, 5, 10,
+ 9, 8, 8, 8, 7, 8, 13, 12, 10, 9, 9, 9, 11, 11, 11, 11, 12, 11, 8,
+ 12, 12, 13, 12, 12, 11, 6, 12, 14, 14, 13, 12, 11, 7, 12, 16, 14, 13, 13,
+ 12, 8, 12, 18, 17, 15, 15, 13, 9, 13, 19, 20, 18, 16, 14, 10, 14, 20, 23,
+ 20, 18, 16, 11, 20, 20, 19, 17, 15, 13, 9, 20, 22, 20, 19, 16, 13, 9, 20,
+ 23, 22, 20, 17, 13, 10, 19, 24, 24, 21, 17, 14, 11, 19, 24, 26, 24, 20, 16,
+ 12, 20, 24, 30, 27, 22, 17, 13, 21, 25, 30, 29, 24, 19, 14, 26, 30, 27, 21,
+ 17, 14, 12, 26, 30, 29, 23, 18, 15, 12, 26, 30, 32, 25, 19, 16, 12, 26, 29,
+ 33, 26, 21, 17, 13, 25, 29, 33, 30, 24, 19, 15, 25, 31, 34, 34, 27, 21, 16,
+ 27, 32, 35, 35, 29, 23, 17, 20, 21, 23, 25, 26, 24, 23, 20, 21, 23, 24, 25,
+ 23, 20, 19, 21, 21, 23, 24, 20, 16, 18, 19, 19, 19, 20, 15, 11, 15, 15, 15,
+ 14, 14, 15, 10, 11, 11, 8, 10, 12, 14, 10, 5, 3, 5, 8, 11, 14, 10, 19,
+ 20, 22, 24, 24, 23, 22, 18, 20, 21, 23, 24, 22, 20, 17, 19, 20, 20, 21, 18,
+ 16, 17, 17, 18, 18, 16, 13, 8, 14, 14, 14, 12, 9, 9, 8, 9, 9, 7, 6,
+ 8, 8, 8, 2, 2, 4, 5, 7, 8, 8, 17, 19, 20, 21, 23, 24, 22, 17, 18,
+ 20, 21, 22, 21, 19, 17, 18, 19, 19, 19, 18, 15, 16, 16, 16, 16, 15, 12, 9,
+ 11, 12, 12, 11, 7, 8, 8, 4, 7, 6, 4, 6, 8, 8, 0, 2, 2, 4, 6,
+ 6, 8, 17, 18, 20, 21, 22, 23, 23, 16, 18, 20, 20, 21, 21, 21, 14, 19, 19,
+ 19, 18, 18, 17, 10, 17, 16, 16, 15, 11, 11, 8, 12, 12, 10, 6, 7, 8, 5,
+ 5, 5, 3, 4, 6, 7, 0, 3, 3, 3, 4, 5, 6, 15, 17, 19, 20, 21, 23,
+ 23, 12, 17, 18, 20, 20, 20, 21, 12, 16, 16, 17, 17, 16, 15, 12, 13, 13, 13,
+ 12, 10, 7, 9, 9, 8, 8, 7, 6, 6, 6, 7, 7, 6, 7, 7, 6, 4, 6,
+ 8, 7, 7, 8, 6, 13, 14, 15, 16, 18, 21, 23, 13, 14, 15, 16, 17, 19, 19,
+ 13, 14, 15, 15, 14, 15, 14, 13, 13, 13, 13, 12, 9, 6, 10, 12, 13, 12, 9,
+ 8, 6, 9, 10, 13, 13, 10, 8, 6, 7, 10, 14, 14, 11, 8, 7, 16, 19, 18,
+ 16, 17, 20, 21, 16, 19, 20, 17, 15, 17, 18, 16, 18, 21, 16, 14, 13, 13, 16,
+ 17, 20, 15, 12, 10, 7, 14, 16, 18, 15, 11, 9, 7, 12, 15, 17, 16, 12, 10,
+ 8, 11, 15, 18, 17, 13, 10, 8, 18, 19, 21, 22, 22, 21, 21, 18, 19, 20, 22,
+ 22, 19, 18, 17, 18, 19, 20, 19, 17, 14, 17, 17, 17, 17, 15, 12, 8, 14, 13,
+ 13, 11, 9, 8, 8, 10, 10, 7, 7, 8, 9, 8, 4, 2, 4, 6, 8, 8, 8,
+ 17, 19, 20, 21, 22, 21, 20, 16, 18, 19, 20, 21, 19, 17, 16, 17, 19, 19, 18,
+ 16, 13, 16, 16, 16, 16, 14, 11, 7, 14, 12, 12, 11, 7, 7, 7, 9, 8, 6,
+ 5, 6, 7, 7, 2, 2, 3, 4, 6, 6, 7, 16, 17, 18, 20, 21, 21, 21, 16,
+ 17, 18, 19, 20, 19, 18, 15, 17, 17, 17, 16, 16, 13, 15, 15, 14, 14, 13, 10,
+ 6, 10, 11, 11, 9, 5, 6, 6, 4, 6, 5, 3, 4, 5, 6, 2, 0, 2, 3,
+ 4, 5, 6, 16, 17, 18, 19, 21, 22, 22, 15, 17, 19, 19, 20, 19, 19, 13, 17,
+ 18, 18, 17, 16, 15, 9, 16, 15, 15, 14, 10, 11, 7, 12, 11, 10, 5, 5, 7,
+ 4, 6, 5, 5, 5, 5, 6, 2, 7, 6, 6, 6, 6, 7, 15, 17, 18, 20, 20,
+ 22, 22, 12, 16, 18, 18, 19, 19, 19, 12, 15, 16, 16, 16, 15, 13, 12, 13, 13,
+ 13, 12, 10, 6, 10, 10, 11, 11, 13, 11, 7, 7, 11, 14, 14, 15, 13, 8, 8,
+ 13, 16, 16, 16, 15, 10, 14, 16, 17, 17, 19, 21, 21, 14, 18, 18, 19, 17, 18,
+ 18, 14, 19, 20, 19, 16, 14, 13, 14, 19, 21, 21, 17, 12, 8, 12, 18, 22, 21,
+ 18, 16, 10, 12, 19, 22, 20, 19, 17, 12, 14, 19, 22, 21, 20, 17, 13, 22, 27,
+ 27, 22, 18, 20, 20, 22, 28, 29, 24, 18, 17, 17, 22, 27, 30, 24, 19, 14, 12,
+ 22, 26, 30, 24, 20, 16, 12, 20, 25, 29, 24, 19, 17, 14, 20, 25, 26, 25, 20,
+ 18, 15, 21, 23, 25, 25, 22, 19, 17, 16, 19, 19, 21, 20, 20, 19, 15, 18, 19,
+ 20, 20, 18, 16, 14, 16, 18, 19, 18, 15, 13, 13, 15, 16, 15, 15, 11, 7, 10,
+ 11, 12, 11, 9, 7, 6, 6, 8, 8, 6, 7, 7, 6, 1, 3, 5, 6, 7, 7,
+ 6, 14, 17, 19, 19, 20, 19, 18, 13, 16, 18, 19, 19, 17, 15, 12, 14, 18, 17,
+ 16, 15, 12, 12, 12, 14, 15, 13, 10, 6, 9, 9, 11, 10, 7, 6, 6, 5, 5,
+ 7, 6, 6, 6, 6, 2, 1, 4, 5, 5, 6, 6, 12, 15, 16, 18, 19, 18, 17,
+ 12, 13, 16, 17, 17, 16, 14, 12, 12, 14, 14, 14, 13, 10, 11, 11, 10, 11, 10,
+ 8, 4, 7, 7, 7, 7, 4, 4, 3, 2, 2, 3, 2, 3, 3, 3, 2, 2, 0,
+ 2, 3, 4, 4, 12, 13, 14, 16, 17, 18, 17, 11, 13, 14, 15, 16, 16, 14, 9,
+ 13, 13, 14, 13, 13, 11, 6, 12, 11, 11, 10, 8, 8, 4, 8, 7, 7, 5, 5,
+ 6, 2, 6, 6, 6, 6, 6, 6, 2, 8, 8, 7, 7, 7, 8, 12, 12, 14, 15,
+ 16, 17, 17, 10, 12, 13, 14, 15, 15, 15, 10, 12, 12, 12, 12, 12, 10, 10, 12,
+ 11, 12, 12, 10, 7, 8, 13, 13, 13, 14, 12, 8, 8, 14, 16, 16, 16, 14, 9,
+ 10, 15, 18, 17, 18, 16, 11, 16, 19, 18, 19, 16, 17, 17, 15, 20, 20, 20, 16,
+ 14, 14, 15, 22, 22, 20, 17, 12, 10, 16, 21, 22, 23, 18, 13, 10, 15, 21, 25,
+ 24, 20, 16, 11, 15, 21, 27, 27, 22, 17, 12, 17, 22, 29, 30, 24, 19, 14, 24,
+ 31, 30, 24, 19, 16, 16, 25, 31, 33, 26, 19, 15, 13, 24, 30, 35, 27, 21, 16,
+ 11, 24, 30, 35, 27, 22, 17, 13, 24, 29, 35, 31, 24, 19, 14, 24, 29, 34, 34,
+ 27, 21, 16, 24, 30, 34, 35, 29, 23, 18, 14, 18, 21, 23, 23, 22, 19, 13, 17,
+ 20, 22, 23, 20, 17, 11, 15, 19, 20, 20, 18, 15, 10, 13, 16, 18, 18, 14, 9,
+ 7, 10, 12, 14, 14, 11, 9, 4, 6, 8, 10, 12, 11, 9, 2, 3, 6, 9, 11,
+ 11, 9, 12, 15, 19, 21, 21, 19, 16, 11, 14, 18, 21, 20, 17, 13, 9, 12, 16,
+ 18, 18, 15, 11, 9, 10, 13, 16, 14, 12, 7, 6, 7, 9, 11, 10, 9, 6, 2,
+ 3, 6, 8, 8, 8, 6, 4, 2, 4, 7, 7, 7, 6, 9, 13, 14, 16, 17, 16,
+ 14, 9, 11, 13, 15, 15, 13, 11, 9, 10, 12, 12, 12, 11, 8, 9, 8, 8, 9,
+ 9, 7, 3, 5, 4, 5, 5, 4, 3, 2, 1, 0, 1, 1, 2, 3, 2, 4, 3,
+ 2, 0, 2, 2, 3, 9, 10, 11, 12, 13, 14, 14, 9, 10, 11, 12, 13, 12, 12,
+ 7, 10, 10, 10, 10, 10, 9, 4, 9, 7, 7, 7, 6, 6, 2, 5, 4, 5, 5,
+ 5, 5, 1, 7, 6, 6, 6, 6, 6, 4, 9, 9, 8, 7, 7, 8, 9, 10, 10,
+ 12, 13, 14, 14, 9, 10, 11, 12, 12, 12, 12, 9, 12, 12, 12, 12, 10, 8, 9,
+ 13, 12, 12, 13, 11, 7, 8, 14, 13, 13, 13, 12, 8, 10, 15, 17, 16, 15, 13,
+ 9, 11, 16, 19, 17, 17, 15, 10, 17, 19, 18, 18, 16, 14, 14, 17, 21, 21, 20,
+ 17, 12, 11, 17, 23, 22, 21, 18, 13, 9, 17, 22, 24, 22, 19, 14, 9, 17, 21,
+ 26, 24, 20, 16, 10, 16, 22, 28, 27, 22, 16, 12, 16, 23, 28, 29, 24, 18, 13,
+ 26, 32, 31, 24, 19, 15, 13, 26, 31, 33, 26, 20, 15, 11, 25, 31, 34, 27, 21,
+ 16, 11, 26, 31, 36, 29, 22, 17, 12, 24, 30, 35, 32, 23, 18, 14, 25, 30, 35,
+ 33, 26, 21, 15, 25, 30, 35, 35, 29, 23, 17, 12, 16, 20, 23, 23, 20, 18, 12,
+ 15, 19, 22, 23, 19, 16, 10, 14, 17, 20, 21, 17, 14, 9, 11, 14, 17, 19, 15,
+ 10, 5, 8, 10, 13, 15, 13, 10, 2, 5, 7, 10, 13, 13, 10, 3, 3, 6, 9,
+ 12, 12, 10, 10, 14, 17, 21, 20, 17, 14, 9, 12, 16, 19, 20, 16, 12, 7, 11,
+ 15, 17, 17, 14, 10, 6, 8, 11, 13, 13, 12, 6, 4, 5, 8, 10, 9, 9, 6,
+ 1, 3, 5, 7, 8, 8, 6, 5, 3, 4, 6, 6, 7, 6, 7, 11, 13, 14, 15,
+ 13, 11, 6, 9, 12, 13, 13, 12, 9, 6, 8, 10, 10, 10, 10, 6, 6, 6, 7,
+ 7, 7, 7, 2, 2, 2, 3, 3, 3, 3, 2, 3, 3, 2, 1, 1, 2, 2, 5,
+ 4, 3, 2, 0, 1, 2, 6, 7, 8, 9, 11, 12, 11, 6, 7, 8, 9, 10, 10,
+ 9, 5, 7, 7, 7, 7, 7, 6, 3, 6, 5, 5, 5, 4, 5, 2, 6, 5, 5,
+ 5, 5, 5, 3, 8, 7, 7, 7, 6, 6, 5, 11, 9, 8, 8, 8, 8, 9, 10,
+ 10, 11, 11, 12, 11, 10, 11, 11, 12, 12, 11, 9, 10, 12, 13, 12, 12, 11, 7,
+ 10, 14, 13, 12, 13, 11, 7, 10, 16, 14, 14, 14, 12, 8, 11, 16, 17, 16, 15,
+ 13, 9, 12, 16, 20, 18, 17, 15, 11, 18, 20, 20, 19, 16, 13, 11, 18, 22, 21,
+ 21, 18, 13, 9, 19, 24, 24, 22, 18, 13, 9, 19, 23, 25, 23, 19, 14, 10, 17,
+ 23, 26, 25, 20, 15, 11, 18, 23, 28, 27, 22, 17, 13, 18, 24, 29, 29, 24, 19,
+ 14, 27, 32, 31, 25, 19, 15, 11, 27, 32, 33, 26, 21, 16, 11, 27, 33, 35, 27,
+ 22, 17, 12, 26, 32, 36, 29, 22, 18, 12, 26, 31, 36, 32, 24, 19, 14, 25, 30,
+ 36, 34, 26, 20, 16, 25, 30, 35, 36, 29, 23, 17, 11, 15, 19, 22, 22, 20, 17,
+ 10, 14, 17, 21, 22, 18, 15, 9, 12, 16, 19, 20, 17, 12, 7, 10, 13, 16, 18,
+ 15, 10, 4, 7, 9, 12, 15, 13, 10, 2, 5, 7, 10, 14, 13, 10, 4, 4, 6,
+ 9, 12, 13, 10, 9, 12, 16, 20, 19, 16, 12, 7, 11, 15, 18, 18, 15, 11, 6,
+ 9, 13, 16, 16, 13, 9, 5, 7, 10, 13, 12, 11, 6, 1, 4, 7, 9, 9, 9,
+ 6, 3, 3, 5, 8, 8, 8, 6, 5, 4, 5, 7, 7, 7, 6, 6, 10, 12, 12,
+ 14, 12, 9, 4, 8, 10, 12, 12, 11, 7, 4, 7, 9, 9, 9, 9, 5, 4, 5,
+ 6, 5, 6, 6, 2, 1, 1, 3, 2, 2, 2, 2, 4, 3, 3, 2, 1, 1, 2,
+ 7, 5, 4, 2, 1, 0, 1, 4, 5, 6, 7, 9, 10, 9, 4, 5, 6, 7, 8,
+ 8, 7, 4, 5, 6, 5, 5, 5, 5, 4, 5, 4, 4, 4, 4, 3, 2, 6, 5,
+ 5, 5, 5, 5, 4, 8, 7, 7, 7, 6, 6, 7, 12, 9, 9, 8, 8, 8, 10,
+ 10, 10, 11, 11, 11, 9, 11, 12, 11, 12, 12, 10, 7, 11, 13, 13, 12, 12, 10,
+ 7, 11, 15, 13, 13, 13, 11, 7, 11, 16, 15, 14, 14, 12, 8, 12, 17, 17, 16,
+ 16, 13, 9, 13, 17, 21, 18, 17, 16, 11, 20, 20, 19, 19, 16, 13, 9, 19, 22,
+ 21, 20, 18, 13, 9, 19, 24, 23, 22, 17, 13, 9, 19, 23, 25, 22, 18, 14, 9,
+ 18, 23, 26, 24, 20, 16, 11, 18, 23, 28, 27, 21, 17, 13, 19, 23, 29, 29, 24,
+ 19, 14, 27, 31, 29, 24, 20, 16, 11, 26, 30, 31, 25, 20, 16, 12, 27, 32, 33,
+ 27, 21, 16, 11, 27, 31, 34, 28, 22, 17, 12, 26, 29, 34, 30, 23, 19, 14, 25,
+ 30, 34, 32, 25, 21, 16, 25, 30, 35, 34, 28, 22, 17, 10, 14, 17, 19, 19, 17,
+ 14, 9, 13, 15, 18, 19, 16, 13, 8, 11, 14, 16, 18, 15, 11, 7, 9, 12, 15,
+ 17, 13, 10, 3, 6, 9, 12, 15, 13, 10, 3, 5, 8, 10, 14, 13, 10, 5, 4,
+ 7, 10, 12, 13, 10, 8, 11, 15, 17, 16, 14, 11, 7, 10, 14, 16, 15, 13, 10,
+ 5, 9, 12, 15, 13, 12, 8, 4, 6, 9, 12, 11, 10, 6, 1, 4, 7, 9, 9,
+ 9, 6, 3, 4, 5, 8, 8, 8, 6, 7, 5, 5, 7, 7, 7, 6, 5, 9, 11,
+ 11, 12, 11, 8, 3, 7, 10, 10, 11, 9, 5, 2, 6, 8, 8, 8, 8, 3, 2,
+ 4, 5, 5, 5, 5, 2, 2, 2, 3, 2, 2, 2, 1, 5, 4, 3, 2, 2, 1,
+ 1, 8, 6, 4, 3, 2, 1, 0, 2, 4, 4, 6, 7, 9, 8, 2, 3, 4, 6,
+ 6, 6, 6, 1, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 3, 3, 8,
+ 6, 5, 5, 5, 5, 5, 10, 8, 7, 7, 6, 6, 8, 13, 10, 9, 8, 8, 7,
+ 10, 10, 10, 10, 11, 10, 8, 11, 12, 11, 11, 11, 10, 6, 12, 13, 12, 12, 11,
+ 10, 6, 12, 15, 13, 12, 12, 11, 6, 12, 17, 15, 14, 13, 12, 8, 13, 17, 18,
+ 16, 15, 13, 9, 13, 18, 20, 17, 16, 14, 10, 19, 19, 18, 17, 15, 12, 8, 19,
+ 20, 19, 18, 16, 12, 8, 19, 23, 21, 19, 15, 12, 8, 19, 23, 22, 19, 16, 13,
+ 9, 18, 22, 24, 22, 18, 14, 10, 19, 23, 27, 25, 20, 15, 12, 18, 23, 28, 27,
+ 22, 17, 13, 25, 28, 25, 20, 17, 14, 11, 24, 28, 27, 22, 17, 14, 11, 24, 28,
+ 29, 22, 17, 14, 11, 25, 27, 30, 24, 19, 16, 12, 23, 27, 31, 28, 22, 17, 13,
+ 24, 28, 32, 31, 24, 19, 14, 25, 28, 32, 32, 26, 20, 15, 3, 7, 11, 15, 16,
+ 13, 11, 2, 5, 10, 14, 15, 13, 8, 2, 4, 8, 11, 13, 10, 5, 2, 2, 5,
+ 8, 10, 9, 5, 2, 2, 2, 5, 8, 10, 5, 5, 6, 6, 5, 8, 9, 5, 12,
+ 10, 8, 5, 6, 9, 5, 2, 4, 8, 11, 13, 10, 5, 2, 3, 7, 10, 13, 8,
+ 3, 2, 2, 5, 7, 9, 5, 2, 1, 2, 2, 4, 5, 3, 2, 2, 3, 3, 3,
+ 3, 3, 2, 7, 7, 8, 6, 3, 2, 2, 15, 13, 10, 7, 5, 3, 2, 2, 2,
+ 3, 5, 6, 4, 2, 1, 2, 2, 3, 4, 3, 1, 0, 2, 2, 2, 2, 2, 1,
+ 1, 2, 1, 1, 1, 1, 2, 4, 4, 4, 4, 4, 3, 2, 10, 10, 9, 8, 6,
+ 4, 2, 17, 16, 12, 9, 6, 4, 2, 0, 1, 1, 1, 2, 2, 5, 1, 2, 2,
+ 2, 2, 2, 5, 2, 2, 3, 3, 3, 3, 5, 4, 4, 5, 5, 5, 6, 7, 6,
+ 9, 9, 9, 9, 8, 7, 10, 15, 14, 13, 11, 10, 9, 17, 20, 17, 15, 13, 12,
+ 11, 8, 8, 8, 9, 9, 8, 5, 10, 10, 10, 10, 10, 9, 5, 10, 11, 11, 12,
+ 12, 10, 6, 10, 14, 14, 14, 14, 13, 9, 13, 18, 18, 18, 18, 17, 11, 15, 21,
+ 23, 21, 20, 18, 13, 20, 24, 25, 23, 21, 20, 15, 17, 18, 18, 18, 16, 11, 7,
+ 17, 20, 20, 19, 17, 12, 7, 17, 22, 21, 20, 19, 14, 9, 17, 23, 22, 22, 20,
+ 17, 14, 18, 24, 26, 25, 23, 20, 15, 21, 26, 29, 28, 24, 20, 17, 24, 28, 29,
+ 30, 25, 23, 18, 24, 29, 27, 22, 19, 15, 9, 24, 28, 29, 23, 20, 16, 11, 24,
+ 29, 30, 25, 21, 17, 13, 24, 29, 30, 26, 22, 20, 17, 25, 28, 32, 29, 25, 23,
+ 19, 26, 30, 33, 32, 26, 24, 20, 28, 32, 34, 33, 28, 25, 22, 6, 7, 8, 8,
+ 9, 7, 7, 5, 7, 8, 9, 9, 7, 6, 4, 6, 7, 8, 8, 7, 6, 3, 6,
+ 7, 7, 8, 7, 7, 3, 6, 7, 8, 9, 8, 7, 7, 9, 10, 9, 9, 8, 7,
+ 13, 13, 11, 10, 9, 8, 7, 4, 6, 7, 7, 7, 6, 5, 3, 6, 7, 7, 7,
+ 6, 5, 2, 5, 7, 7, 6, 6, 6, 1, 4, 7, 7, 6, 6, 7, 4, 5, 7,
+ 8, 7, 7, 6, 9, 9, 11, 10, 8, 7, 7, 16, 14, 12, 11, 8, 7, 7, 2,
+ 5, 6, 6, 6, 5, 2, 1, 4, 5, 5, 5, 5, 2, 1, 3, 4, 4, 5, 5,
+ 2, 1, 3, 4, 4, 5, 5, 4, 6, 6, 6, 6, 6, 5, 4, 11, 11, 11, 9,
+ 7, 5, 4, 18, 17, 13, 10, 7, 5, 4, 1, 0, 1, 1, 1, 2, 4, 1, 2,
+ 2, 2, 2, 2, 4, 2, 3, 2, 2, 3, 3, 4, 5, 5, 5, 6, 6, 6, 6,
+ 6, 10, 9, 9, 10, 9, 8, 12, 15, 14, 13, 11, 11, 9, 19, 21, 18, 15, 13,
+ 12, 11, 9, 8, 8, 8, 9, 7, 4, 10, 10, 9, 9, 10, 8, 4, 10, 11, 11,
+ 11, 11, 10, 6, 10, 15, 14, 14, 14, 13, 10, 13, 19, 18, 18, 19, 17, 11, 17,
+ 22, 24, 23, 21, 19, 13, 20, 26, 28, 25, 24, 21, 15, 17, 18, 17, 17, 14, 10,
+ 6, 17, 21, 19, 19, 16, 11, 7, 17, 21, 22, 21, 17, 13, 9, 17, 24, 25, 25,
+ 21, 17, 13, 20, 25, 31, 30, 25, 20, 15, 22, 28, 35, 33, 28, 22, 16, 25, 31,
+ 35, 36, 30, 24, 18, 25, 31, 29, 22, 17, 13, 9, 25, 30, 32, 25, 19, 15, 10,
+ 25, 31, 34, 27, 21, 17, 13, 24, 31, 37, 30, 26, 21, 17, 27, 33, 38, 36, 31,
+ 25, 18, 28, 36, 40, 40, 33, 27, 20, 32, 38, 41, 41, 35, 29, 23, 6, 9, 12,
+ 13, 13, 11, 9, 5, 8, 11, 13, 13, 11, 10, 4, 7, 10, 12, 13, 12, 10, 3,
+ 7, 10, 12, 14, 12, 11, 5, 7, 9, 12, 14, 13, 11, 8, 9, 11, 12, 14, 13,
+ 11, 14, 14, 12, 12, 13, 13, 11, 5, 7, 10, 12, 11, 9, 6, 4, 6, 9, 11,
+ 11, 9, 6, 2, 5, 8, 10, 10, 9, 7, 1, 5, 8, 11, 10, 10, 8, 4, 6,
+ 8, 10, 10, 11, 8, 10, 11, 11, 12, 10, 10, 8, 17, 16, 13, 12, 10, 9, 8,
+ 2, 5, 6, 7, 7, 5, 2, 1, 4, 5, 6, 6, 5, 2, 1, 3, 5, 5, 5,
+ 5, 3, 1, 3, 5, 5, 5, 6, 4, 6, 7, 7, 7, 7, 6, 4, 13, 12, 12,
+ 10, 8, 6, 4, 20, 18, 14, 11, 8, 6, 4, 1, 1, 0, 1, 1, 1, 3, 1,
+ 2, 1, 1, 1, 1, 3, 4, 3, 3, 3, 3, 3, 4, 7, 6, 6, 6, 6, 7,
+ 6, 8, 11, 10, 10, 10, 10, 8, 13, 16, 15, 14, 12, 11, 10, 19, 22, 19, 16,
+ 14, 13, 12, 9, 8, 8, 8, 8, 7, 3, 11, 10, 9, 9, 9, 8, 3, 10, 12,
+ 12, 12, 11, 10, 7, 10, 16, 15, 14, 15, 14, 10, 14, 21, 20, 20, 19, 17, 12,
+ 18, 24, 25, 23, 21, 18, 14, 22, 27, 28, 26, 24, 21, 15, 17, 19, 17, 17, 13,
+ 9, 5, 17, 21, 19, 18, 15, 11, 6, 17, 22, 22, 21, 17, 13, 10, 18, 24, 26,
+ 25, 21, 17, 13, 20, 27, 30, 30, 26, 20, 15, 23, 29, 36, 35, 29, 23, 17, 27,
+ 32, 37, 37, 31, 25, 19, 25, 30, 29, 22, 16, 12, 8, 25, 31, 31, 24, 18, 14,
+ 10, 25, 30, 35, 27, 22, 17, 13, 26, 31, 37, 31, 26, 21, 17, 27, 34, 39, 37,
+ 30, 25, 19, 30, 37, 43, 41, 33, 27, 20, 33, 38, 43, 43, 36, 29, 23, 7, 9,
+ 12, 15, 15, 13, 10, 6, 8, 11, 14, 15, 13, 10, 5, 7, 10, 13, 15, 14, 11,
+ 4, 7, 11, 14, 16, 14, 12, 5, 8, 11, 13, 17, 15, 12, 9, 11, 12, 13, 16,
+ 14, 12, 16, 15, 14, 13, 15, 15, 12, 5, 8, 10, 13, 12, 9, 6, 4, 7, 9,
+ 12, 12, 9, 6, 3, 5, 9, 11, 11, 10, 8, 1, 5, 9, 11, 11, 11, 9, 5,
+ 7, 9, 11, 11, 11, 9, 11, 12, 13, 13, 11, 10, 8, 19, 17, 14, 13, 10, 10,
+ 8, 3, 6, 6, 6, 7, 5, 2, 1, 4, 6, 6, 6, 5, 2, 1, 3, 5, 5,
+ 5, 6, 3, 2, 4, 5, 5, 6, 6, 5, 7, 8, 8, 8, 8, 7, 5, 14, 13,
+ 13, 11, 9, 7, 5, 21, 19, 15, 12, 9, 7, 6, 1, 1, 1, 0, 1, 1, 3,
+ 2, 2, 2, 1, 2, 1, 3, 5, 3, 3, 4, 4, 4, 5, 8, 6, 7, 7, 7,
+ 7, 7, 9, 12, 11, 11, 12, 10, 9, 14, 18, 16, 15, 14, 12, 11, 21, 24, 20,
+ 17, 15, 13, 12, 10, 9, 8, 8, 8, 7, 3, 11, 10, 9, 9, 9, 8, 3, 11,
+ 12, 12, 13, 12, 11, 7, 11, 16, 16, 16, 16, 15, 11, 15, 22, 21, 20, 21, 18,
+ 13, 19, 25, 26, 25, 22, 20, 14, 23, 28, 30, 27, 25, 21, 16, 18, 19, 17, 17,
+ 14, 9, 5, 18, 21, 19, 19, 15, 11, 7, 18, 23, 22, 22, 18, 14, 11, 18, 25,
+ 27, 25, 23, 19, 15, 21, 28, 32, 32, 26, 21, 16, 24, 32, 37, 36, 29, 23, 18,
+ 28, 34, 38, 38, 32, 26, 20, 26, 31, 29, 22, 17, 12, 8, 25, 31, 31, 24, 19,
+ 15, 11, 25, 30, 33, 28, 24, 18, 14, 26, 31, 37, 32, 27, 22, 18, 29, 35, 40,
+ 38, 31, 26, 20, 31, 38, 42, 42, 34, 28, 22, 34, 39, 44, 44, 37, 30, 24, 7,
+ 10, 12, 15, 15, 12, 10, 6, 9, 11, 14, 15, 13, 11, 5, 7, 11, 15, 16, 15,
+ 12, 4, 8, 11, 14, 17, 16, 13, 6, 9, 11, 14, 18, 16, 13, 11, 12, 14, 14,
+ 17, 16, 13, 17, 17, 15, 14, 16, 15, 13, 5, 8, 10, 13, 11, 9, 6, 4, 7,
+ 10, 12, 12, 9, 7, 3, 6, 9, 12, 12, 10, 8, 2, 6, 10, 12, 12, 11, 9,
+ 5, 8, 10, 12, 12, 12, 9, 12, 13, 14, 15, 12, 11, 9, 20, 19, 16, 14, 12,
+ 10, 9, 3, 6, 7, 6, 7, 5, 1, 1, 5, 6, 6, 6, 5, 2, 2, 4, 5,
+ 6, 6, 6, 4, 2, 4, 6, 6, 6, 6, 6, 7, 9, 9, 9, 10, 8, 6, 15,
+ 15, 14, 12, 10, 9, 6, 22, 21, 17, 14, 11, 9, 7, 2, 1, 1, 1, 0, 1,
+ 3, 3, 2, 2, 2, 2, 2, 3, 7, 3, 3, 4, 5, 5, 5, 9, 6, 8, 9,
+ 9, 8, 7, 10, 12, 12, 12, 13, 12, 10, 16, 19, 17, 16, 15, 14, 12, 22, 25,
+ 21, 18, 16, 15, 14, 10, 9, 8, 8, 8, 7, 2, 13, 11, 10, 9, 10, 9, 3,
+ 13, 12, 12, 13, 13, 12, 9, 13, 17, 17, 18, 17, 16, 12, 16, 23, 22, 22, 22,
+ 19, 14, 21, 27, 28, 26, 24, 21, 16, 24, 29, 31, 28, 27, 23, 17, 18, 19, 18,
+ 17, 13, 9, 5, 19, 21, 19, 18, 15, 12, 8, 18, 23, 22, 23, 19, 16, 12, 19,
+ 24, 28, 27, 23, 19, 16, 22, 29, 32, 31, 28, 23, 17, 27, 32, 39, 36, 29, 24,
+ 19, 30, 36, 38, 39, 33, 27, 21, 25, 29, 26, 21, 16, 12, 8, 25, 30, 29, 23,
+ 19, 16, 12, 26, 30, 31, 26, 23, 19, 15, 25, 32, 35, 31, 27, 24, 20, 29, 35,
+ 39, 38, 32, 26, 21, 32, 38, 43, 42, 35, 29, 23, 35, 40, 43, 45, 37, 31, 25,
+ 6, 8, 10, 12, 12, 9, 8, 6, 8, 9, 11, 12, 11, 9, 5, 7, 9, 12, 14,
+ 12, 11, 4, 7, 10, 13, 16, 14, 13, 6, 9, 12, 14, 18, 15, 13, 11, 13, 15,
+ 16, 17, 15, 13, 18, 18, 16, 15, 16, 15, 13, 5, 7, 8, 10, 8, 6, 5, 4,
+ 6, 8, 9, 9, 7, 6, 3, 6, 8, 10, 10, 9, 8, 2, 6, 9, 11, 11, 11,
+ 10, 6, 9, 11, 13, 13, 12, 9, 13, 14, 16, 15, 13, 12, 10, 22, 19, 17, 16,
+ 13, 11, 10, 3, 6, 5, 5, 5, 3, 2, 2, 5, 5, 4, 4, 4, 3, 2, 4,
+ 5, 5, 6, 6, 5, 3, 4, 6, 7, 7, 7, 8, 8, 9, 10, 11, 11, 10, 8,
+ 16, 17, 15, 14, 12, 10, 8, 23, 22, 18, 14, 12, 10, 8, 2, 2, 1, 1, 1,
+ 0, 2, 4, 2, 2, 2, 2, 3, 4, 8, 4, 3, 5, 6, 6, 6, 11, 6, 8,
+ 9, 9, 10, 8, 11, 13, 13, 14, 14, 12, 11, 16, 20, 18, 17, 16, 14, 13, 23,
+ 26, 22, 19, 17, 16, 15, 11, 9, 8, 8, 8, 7, 2, 14, 11, 10, 9, 10, 9,
+ 4, 14, 13, 12, 13, 14, 12, 9, 14, 17, 17, 17, 17, 17, 13, 16, 23, 23, 23,
+ 22, 19, 15, 21, 27, 28, 26, 23, 21, 17, 26, 31, 31, 28, 26, 22, 18, 18, 17,
+ 15, 13, 12, 9, 6, 18, 19, 16, 14, 12, 12, 9, 18, 21, 18, 19, 17, 15, 13,
+ 18, 23, 25, 24, 22, 19, 17, 22, 29, 31, 29, 26, 23, 18, 26, 33, 37, 34, 28,
+ 23, 20, 30, 36, 38, 37, 30, 25, 21, 22, 25, 22, 17, 13, 10, 9, 22, 25, 24,
+ 18, 15, 14, 12, 22, 25, 27, 22, 20, 18, 15, 22, 27, 33, 29, 25, 22, 20, 27,
+ 31, 37, 34, 30, 25, 21, 31, 36, 40, 40, 32, 27, 22, 35, 39, 42, 41, 35, 29,
+ 24, 9, 11, 13, 16, 16, 13, 10, 9, 11, 12, 15, 16, 14, 12, 8, 9, 12, 16,
+ 17, 15, 13, 8, 10, 13, 16, 19, 16, 14, 8, 11, 13, 17, 20, 18, 14, 11, 13,
+ 15, 16, 19, 18, 15, 18, 17, 16, 16, 18, 17, 14, 8, 10, 12, 13, 11, 8, 7,
+ 8, 9, 11, 13, 12, 10, 8, 7, 8, 11, 14, 13, 11, 9, 6, 8, 11, 14, 13,
+ 12, 11, 6, 10, 12, 14, 14, 13, 11, 13, 14, 16, 15, 14, 13, 11, 22, 19, 17,
+ 15, 13, 12, 11, 7, 8, 8, 7, 7, 5, 3, 6, 8, 8, 7, 7, 6, 4, 5,
+ 7, 7, 8, 8, 8, 6, 3, 7, 8, 8, 9, 9, 8, 7, 9, 10, 10, 10, 9,
+ 8, 16, 16, 15, 13, 11, 9, 8, 23, 22, 18, 14, 11, 9, 8, 5, 4, 3, 3,
+ 3, 3, 0, 2, 2, 3, 2, 2, 2, 2, 6, 2, 2, 3, 3, 3, 4, 10, 3,
+ 5, 6, 6, 6, 6, 9, 10, 10, 10, 10, 9, 7, 15, 18, 16, 14, 12, 10, 8,
+ 24, 25, 19, 15, 13, 11, 9, 4, 3, 2, 2, 2, 2, 0, 6, 3, 3, 2, 3,
+ 3, 2, 6, 4, 4, 5, 6, 6, 5, 6, 8, 9, 10, 10, 9, 8, 9, 14, 15,
+ 15, 15, 13, 9, 16, 20, 22, 20, 17, 14, 10, 22, 25, 25, 21, 19, 15, 11, 8,
+ 7, 6, 5, 3, 2, 1, 7, 10, 7, 6, 4, 4, 3, 8, 11, 10, 11, 9, 8,
+ 7, 8, 14, 17, 17, 14, 12, 10, 12, 19, 23, 23, 20, 16, 11, 18, 24, 30, 28,
+ 22, 17, 13, 24, 28, 31, 30, 24, 19, 14, 13, 16, 14, 8, 5, 3, 2, 13, 16,
+ 16, 10, 7, 6, 5, 13, 16, 19, 15, 12, 10, 8, 13, 18, 25, 21, 18, 15, 13,
+ 17, 24, 30, 28, 23, 19, 14, 22, 28, 34, 34, 27, 21, 15, 27, 32, 35, 35, 29,
+ 23, 17, 6, 10, 15, 18, 18, 16, 15, 5, 9, 14, 17, 18, 15, 13, 3, 8, 11,
+ 15, 16, 14, 11, 2, 5, 9, 11, 13, 13, 10, 1, 2, 6, 10, 12, 14, 10, 5,
+ 5, 5, 8, 11, 14, 10, 11, 9, 5, 7, 10, 14, 10, 3, 7, 12, 15, 16, 14,
+ 10, 2, 6, 11, 14, 15, 13, 8, 2, 5, 9, 11, 12, 11, 5, 2, 2, 6, 8,
+ 9, 8, 3, 2, 2, 3, 6, 7, 8, 3, 7, 7, 6, 5, 6, 6, 4, 15, 12,
+ 8, 5, 4, 5, 4, 2, 5, 7, 9, 11, 9, 5, 2, 3, 6, 8, 8, 8, 2,
+ 1, 2, 4, 5, 5, 5, 1, 0, 2, 2, 1, 2, 1, 1, 4, 4, 4, 4, 4,
+ 2, 1, 10, 9, 9, 8, 5, 3, 1, 16, 15, 11, 9, 6, 4, 2, 1, 1, 1,
+ 2, 3, 4, 2, 0, 1, 1, 2, 2, 1, 3, 1, 1, 1, 1, 1, 1, 3, 3,
+ 3, 3, 3, 4, 4, 4, 5, 7, 7, 7, 8, 7, 6, 9, 13, 11, 11, 10, 9,
+ 8, 16, 18, 14, 13, 12, 10, 9, 7, 7, 7, 8, 8, 7, 3, 8, 8, 9, 9,
+ 9, 8, 3, 8, 10, 10, 10, 11, 9, 5, 8, 13, 12, 13, 13, 12, 8, 11, 16,
+ 15, 15, 15, 14, 10, 14, 18, 19, 17, 16, 16, 12, 17, 20, 21, 18, 18, 16, 13,
+ 16, 16, 16, 16, 14, 10, 5, 15, 18, 17, 16, 14, 11, 7, 15, 19, 18, 17, 16,
+ 13, 8, 15, 19, 19, 18, 16, 15, 11, 16, 20, 22, 21, 18, 16, 13, 18, 22, 25,
+ 23, 20, 17, 14, 20, 24, 25, 25, 21, 18, 15, 21, 25, 22, 19, 16, 14, 8, 21,
+ 25, 25, 20, 16, 14, 10, 20, 25, 27, 21, 17, 15, 11, 21, 24, 27, 22, 18, 17,
+ 15, 21, 25, 28, 26, 21, 18, 16, 21, 25, 29, 28, 23, 19, 17, 24, 26, 29, 29,
+ 24, 20, 17, 7, 8, 9, 11, 11, 9, 7, 6, 7, 8, 10, 10, 8, 7, 5, 7,
+ 8, 9, 9, 8, 7, 4, 6, 7, 8, 8, 8, 8, 4, 7, 8, 8, 9, 8, 8,
+ 7, 8, 9, 9, 9, 8, 8, 13, 13, 11, 9, 9, 8, 7, 5, 7, 8, 9, 9,
+ 7, 6, 4, 7, 8, 8, 8, 7, 6, 3, 6, 7, 7, 7, 7, 6, 2, 5, 7,
+ 8, 7, 7, 7, 3, 5, 7, 8, 7, 7, 7, 8, 9, 10, 10, 8, 7, 7, 16,
+ 15, 12, 10, 8, 7, 7, 3, 6, 6, 6, 7, 6, 3, 2, 5, 6, 6, 6, 6,
+ 3, 1, 4, 5, 5, 6, 6, 3, 1, 4, 5, 5, 6, 6, 5, 5, 6, 6, 6,
+ 6, 6, 5, 11, 11, 11, 9, 7, 5, 5, 18, 17, 13, 10, 7, 5, 3, 2, 2,
+ 2, 2, 2, 2, 2, 1, 0, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3,
+ 4, 4, 4, 4, 4, 4, 5, 6, 8, 8, 8, 8, 7, 6, 11, 14, 13, 12, 10,
+ 9, 8, 18, 20, 16, 14, 12, 10, 9, 7, 7, 7, 7, 7, 6, 2, 9, 9, 8,
+ 8, 8, 7, 3, 9, 10, 10, 10, 10, 8, 4, 9, 13, 13, 12, 13, 12, 8, 12,
+ 18, 17, 17, 18, 15, 10, 15, 21, 23, 21, 20, 17, 11, 19, 24, 26, 23, 22, 18,
+ 13, 16, 17, 17, 16, 13, 9, 5, 15, 20, 18, 18, 14, 10, 6, 15, 21, 20, 20,
+ 16, 12, 8, 16, 22, 24, 23, 19, 15, 11, 18, 24, 29, 28, 24, 19, 13, 20, 27,
+ 32, 31, 27, 21, 15, 25, 30, 34, 32, 28, 23, 17, 23, 29, 28, 22, 16, 12, 7,
+ 23, 29, 30, 24, 18, 13, 9, 23, 30, 33, 26, 20, 15, 11, 24, 29, 34, 29, 24,
+ 20, 15, 24, 31, 35, 34, 28, 23, 17, 27, 33, 37, 36, 30, 25, 19, 30, 35, 39,
+ 38, 33, 27, 22, 7, 10, 12, 14, 14, 12, 10, 7, 9, 12, 13, 14, 12, 10, 5,
+ 8, 10, 13, 13, 12, 11, 4, 8, 10, 12, 14, 13, 12, 5, 8, 10, 13, 15, 13,
+ 12, 8, 10, 11, 13, 14, 13, 11, 14, 14, 13, 12, 13, 13, 12, 5, 8, 11, 12,
+ 11, 10, 7, 5, 7, 10, 12, 11, 10, 7, 3, 6, 9, 11, 11, 10, 8, 3, 6,
+ 9, 11, 11, 11, 9, 5, 6, 8, 11, 11, 11, 9, 10, 11, 12, 12, 10, 10, 9,
+ 17, 16, 13, 12, 10, 9, 9, 4, 6, 7, 7, 8, 6, 3, 2, 5, 6, 7, 7,
+ 6, 3, 1, 4, 5, 5, 6, 6, 3, 1, 4, 5, 6, 6, 6, 4, 6, 7, 7,
+ 7, 7, 6, 5, 12, 12, 11, 10, 8, 6, 4, 19, 19, 14, 11, 8, 6, 5, 2,
+ 2, 1, 1, 2, 2, 3, 1, 1, 0, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2,
+ 4, 6, 5, 5, 5, 5, 5, 5, 7, 9, 9, 9, 9, 9, 7, 12, 15, 14, 13,
+ 11, 10, 9, 19, 21, 17, 15, 13, 11, 11, 8, 7, 7, 7, 7, 6, 3, 9, 9,
+ 8, 8, 8, 7, 3, 9, 10, 10, 10, 10, 9, 5, 9, 14, 14, 14, 14, 13, 9,
+ 13, 19, 19, 18, 18, 16, 11, 17, 22, 24, 23, 20, 18, 12, 21, 26, 28, 24, 23,
+ 20, 14, 16, 18, 17, 16, 13, 9, 4, 16, 20, 18, 18, 14, 9, 6, 17, 21, 21,
+ 20, 16, 12, 8, 17, 24, 25, 24, 21, 16, 12, 20, 25, 30, 29, 25, 19, 14, 22,
+ 28, 35, 32, 28, 21, 16, 25, 31, 35, 36, 28, 23, 18, 24, 30, 27, 21, 16, 12,
+ 7, 24, 30, 30, 23, 18, 13, 9, 24, 30, 33, 26, 21, 16, 12, 24, 31, 36, 30,
+ 24, 20, 16, 25, 32, 38, 34, 29, 23, 18, 28, 34, 39, 40, 33, 26, 20, 31, 37,
+ 41, 41, 35, 28, 21, 8, 10, 13, 16, 16, 13, 11, 7, 9, 12, 15, 16, 14, 11,
+ 6, 8, 11, 14, 16, 14, 12, 5, 9, 11, 14, 17, 15, 13, 6, 8, 11, 14, 17,
+ 16, 13, 10, 11, 12, 14, 17, 16, 13, 16, 15, 13, 13, 15, 15, 13, 6, 8, 11,
+ 14, 12, 10, 7, 5, 8, 10, 13, 12, 10, 7, 4, 7, 10, 12, 12, 10, 9, 3,
+ 7, 10, 12, 12, 12, 9, 5, 7, 9, 12, 12, 12, 9, 11, 11, 13, 13, 11, 12,
+ 9, 19, 17, 15, 13, 10, 10, 9, 4, 7, 7, 7, 8, 6, 2, 3, 5, 7, 7,
+ 7, 6, 2, 1, 5, 6, 6, 6, 6, 4, 1, 5, 6, 6, 7, 7, 5, 7, 8,
+ 8, 8, 8, 7, 5, 14, 14, 13, 11, 9, 7, 5, 21, 20, 15, 12, 9, 7, 5,
+ 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 0, 1, 1, 3, 3, 2, 2, 2, 3,
+ 3, 4, 6, 5, 6, 6, 6, 6, 6, 8, 11, 10, 10, 10, 9, 8, 14, 17, 15,
+ 14, 12, 11, 9, 21, 23, 18, 16, 14, 12, 11, 8, 8, 7, 7, 7, 6, 3, 10,
+ 9, 8, 8, 8, 7, 3, 10, 11, 11, 11, 11, 10, 6, 10, 15, 15, 15, 15, 14,
+ 10, 13, 20, 20, 19, 19, 16, 11, 18, 25, 25, 24, 21, 18, 13, 22, 27, 28, 26,
+ 23, 20, 15, 17, 18, 17, 16, 12, 8, 4, 17, 20, 18, 17, 14, 10, 6, 17, 22,
+ 22, 21, 17, 13, 9, 17, 24, 26, 25, 21, 17, 13, 20, 26, 30, 30, 25, 20, 15,
+ 23, 29, 36, 33, 28, 22, 17, 27, 32, 36, 37, 30, 24, 19, 24, 30, 28, 21, 16,
+ 11, 7, 24, 29, 29, 23, 18, 13, 10, 24, 30, 33, 27, 21, 17, 13, 24, 31, 37,
+ 30, 25, 21, 17, 28, 33, 39, 36, 31, 24, 19, 30, 36, 41, 41, 33, 27, 20, 33,
+ 38, 43, 43, 36, 28, 22, 8, 11, 14, 17, 17, 15, 12, 7, 10, 13, 17, 17, 14,
+ 12, 6, 9, 12, 15, 18, 15, 13, 5, 9, 12, 15, 19, 16, 14, 6, 9, 12, 15,
+ 19, 17, 14, 10, 12, 13, 14, 18, 17, 14, 16, 15, 14, 14, 16, 16, 14, 6, 9,
+ 11, 15, 14, 11, 8, 5, 8, 11, 13, 13, 10, 8, 4, 7, 10, 13, 13, 11, 9,
+ 3, 7, 11, 13, 13, 12, 10, 5, 8, 10, 12, 13, 12, 10, 12, 12, 14, 14, 12,
+ 12, 10, 19, 17, 15, 14, 11, 11, 10, 4, 7, 8, 8, 9, 7, 3, 3, 6, 7,
+ 7, 7, 6, 3, 1, 5, 6, 7, 7, 7, 4, 1, 5, 7, 7, 7, 7, 6, 7,
+ 8, 9, 8, 8, 7, 6, 14, 14, 14, 12, 9, 7, 6, 21, 20, 16, 12, 10, 8,
+ 6, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 2, 4, 2, 2, 3,
+ 3, 3, 3, 7, 5, 6, 6, 6, 6, 5, 8, 11, 10, 10, 11, 9, 8, 14, 17,
+ 15, 14, 12, 11, 10, 21, 23, 19, 16, 14, 12, 11, 8, 7, 7, 7, 7, 6, 2,
+ 10, 9, 8, 8, 8, 7, 2, 10, 11, 10, 11, 11, 10, 6, 10, 15, 15, 15, 15,
+ 14, 10, 14, 21, 20, 20, 19, 17, 12, 18, 24, 26, 24, 21, 18, 13, 23, 28, 29,
+ 26, 24, 21, 15, 17, 18, 17, 15, 12, 9, 4, 16, 19, 18, 17, 13, 10, 6, 17,
+ 22, 21, 21, 18, 13, 9, 16, 24, 26, 25, 22, 18, 13, 20, 27, 30, 30, 26, 21,
+ 15, 24, 30, 37, 35, 28, 23, 17, 28, 32, 37, 37, 30, 24, 19, 24, 28, 25, 20,
+ 15, 11, 7, 24, 28, 28, 22, 17, 13, 10, 24, 29, 31, 25, 21, 17, 13, 24, 30,
+ 35, 31, 25, 21, 17, 28, 33, 38, 35, 30, 24, 19, 30, 35, 41, 40, 32, 27, 21,
+ 34, 39, 41, 42, 35, 29, 23, 8, 11, 14, 17, 17, 15, 11, 7, 10, 13, 16, 16,
+ 14, 12, 6, 9, 12, 15, 17, 16, 13, 5, 9, 12, 16, 18, 16, 14, 6, 9, 12,
+ 15, 18, 17, 14, 10, 12, 13, 14, 18, 17, 14, 17, 16, 14, 14, 16, 17, 14, 6,
+ 9, 12, 14, 13, 11, 8, 5, 8, 11, 13, 13, 10, 8, 4, 7, 10, 14, 13, 11,
+ 9, 3, 7, 11, 13, 13, 12, 10, 5, 8, 10, 13, 13, 12, 10, 11, 12, 14, 13,
+ 12, 12, 10, 19, 17, 15, 14, 11, 11, 9, 4, 7, 8, 8, 9, 7, 3, 3, 6,
+ 7, 7, 7, 6, 3, 2, 5, 6, 7, 7, 7, 4, 1, 5, 7, 7, 7, 7, 6,
+ 6, 8, 9, 9, 8, 7, 6, 14, 14, 13, 11, 9, 8, 6, 21, 19, 15, 12, 10,
+ 8, 6, 2, 2, 1, 1, 2, 3, 2, 1, 1, 1, 1, 0, 0, 2, 5, 2, 2,
+ 3, 3, 3, 3, 7, 5, 6, 6, 6, 6, 5, 9, 11, 10, 11, 10, 10, 8, 14,
+ 17, 16, 14, 13, 11, 10, 21, 23, 19, 16, 14, 13, 12, 9, 8, 7, 6, 7, 6,
+ 2, 11, 10, 8, 8, 8, 7, 2, 11, 11, 10, 11, 11, 10, 6, 10, 15, 15, 15,
+ 15, 14, 10, 14, 21, 20, 20, 19, 16, 12, 18, 24, 25, 23, 21, 18, 13, 23, 27,
+ 29, 25, 22, 20, 15, 16, 16, 14, 13, 11, 8, 5, 16, 18, 15, 13, 12, 10, 6,
+ 16, 20, 17, 17, 15, 12, 10, 17, 21, 23, 21, 19, 17, 13, 20, 26, 28, 26, 23,
+ 20, 15, 24, 29, 33, 30, 25, 21, 17, 27, 33, 34, 33, 26, 23, 19, 21, 23, 20,
+ 15, 13, 10, 7, 21, 24, 23, 17, 14, 13, 9, 21, 24, 25, 21, 18, 16, 13, 21,
+ 25, 30, 25, 22, 19, 16, 25, 29, 34, 32, 27, 23, 19, 29, 33, 37, 36, 29, 24,
+ 20, 32, 35, 37, 38, 32, 26, 21, 9, 11, 14, 17, 17, 14, 11, 9, 11, 13, 16,
+ 17, 13, 11, 8, 10, 12, 15, 17, 15, 12, 8, 10, 13, 16, 18, 15, 13, 8, 10,
+ 13, 15, 19, 17, 13, 11, 11, 13, 15, 18, 16, 13, 16, 15, 14, 14, 16, 17, 13,
+ 8, 10, 12, 14, 13, 10, 7, 8, 9, 11, 13, 13, 9, 7, 7, 8, 11, 13, 12,
+ 10, 8, 6, 9, 12, 14, 13, 12, 9, 6, 9, 11, 13, 13, 12, 10, 11, 12, 13,
+ 13, 12, 11, 10, 19, 17, 14, 13, 11, 11, 10, 7, 9, 9, 8, 9, 7, 4, 6,
+ 8, 8, 7, 7, 6, 3, 5, 8, 8, 7, 7, 6, 5, 4, 7, 8, 8, 7, 7,
+ 6, 7, 9, 9, 8, 8, 7, 6, 14, 14, 13, 11, 9, 7, 6, 21, 19, 14, 11,
+ 9, 7, 6, 5, 4, 3, 3, 3, 4, 2, 3, 3, 3, 2, 2, 2, 0, 2, 2,
+ 2, 3, 2, 2, 2, 7, 3, 4, 5, 4, 4, 4, 8, 9, 9, 8, 8, 7, 5,
+ 14, 15, 14, 11, 10, 8, 6, 20, 21, 16, 13, 11, 9, 7, 5, 3, 2, 2, 2,
+ 2, 2, 6, 4, 3, 2, 3, 2, 0, 5, 5, 4, 4, 4, 4, 3, 5, 8, 8,
+ 8, 8, 8, 6, 9, 14, 13, 13, 13, 10, 7, 14, 19, 20, 18, 15, 12, 8, 20,
+ 23, 23, 19, 17, 14, 9, 9, 9, 7, 6, 4, 3, 2, 9, 11, 9, 8, 5, 3,
+ 2, 8, 12, 11, 11, 9, 6, 5, 9, 14, 17, 16, 13, 10, 8, 12, 18, 22, 21,
+ 18, 14, 9, 17, 23, 27, 25, 20, 15, 11, 22, 26, 29, 28, 23, 17, 12, 14, 18,
+ 15, 10, 6, 3, 2, 13, 18, 18, 12, 8, 5, 3, 14, 18, 20, 15, 12, 9, 6,
+ 14, 19, 25, 21, 17, 13, 11, 17, 23, 28, 26, 22, 17, 12, 22, 26, 32, 32, 25,
+ 19, 14, 26, 30, 33, 33, 27, 20, 15, 10, 14, 18, 22, 22, 20, 17, 8, 12, 17,
+ 20, 22, 19, 16, 7, 11, 14, 17, 20, 17, 13, 5, 9, 12, 15, 16, 15, 13, 3,
+ 6, 10, 13, 15, 16, 14, 4, 5, 8, 11, 14, 16, 13, 10, 7, 7, 11, 13, 15,
+ 14, 7, 11, 15, 18, 20, 17, 13, 5, 9, 14, 17, 19, 15, 12, 4, 8, 12, 13,
+ 15, 14, 9, 3, 6, 9, 11, 12, 13, 8, 2, 3, 7, 10, 12, 12, 8, 6, 5,
+ 6, 8, 10, 11, 8, 12, 10, 6, 8, 8, 8, 8, 4, 8, 10, 12, 13, 12, 9,
+ 2, 7, 9, 11, 11, 11, 7, 1, 5, 8, 9, 9, 10, 4, 1, 3, 4, 5, 5,
+ 5, 1, 3, 3, 3, 3, 3, 3, 1, 9, 8, 7, 5, 4, 2, 1, 14, 13, 9,
+ 7, 5, 4, 1, 2, 2, 4, 5, 7, 8, 6, 1, 1, 2, 3, 4, 5, 2, 0,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4, 6, 6, 6, 6, 5,
+ 4, 9, 10, 9, 8, 8, 7, 6, 14, 15, 11, 10, 9, 8, 8, 6, 6, 6, 6,
+ 6, 4, 6, 7, 7, 8, 8, 8, 6, 3, 7, 9, 8, 8, 9, 8, 3, 7, 10,
+ 10, 10, 10, 9, 6, 9, 13, 12, 12, 12, 11, 8, 11, 15, 15, 14, 13, 12, 9,
+ 14, 17, 17, 15, 14, 13, 10, 13, 13, 13, 13, 11, 8, 5, 12, 15, 14, 13, 12,
+ 9, 6, 12, 16, 15, 14, 12, 10, 7, 13, 15, 16, 15, 13, 11, 9, 13, 16, 18,
+ 17, 16, 12, 10, 14, 18, 22, 20, 17, 14, 11, 16, 20, 22, 21, 18, 15, 12, 17,
+ 20, 19, 16, 13, 11, 6, 18, 21, 21, 16, 13, 11, 8, 17, 21, 23, 17, 14, 11,
+ 9, 17, 21, 23, 19, 15, 13, 11, 17, 21, 24, 21, 18, 15, 12, 18, 22, 25, 25,
+ 19, 16, 13, 20, 23, 26, 25, 21, 16, 14, 7, 8, 10, 13, 13, 11, 9, 7, 8,
+ 10, 12, 13, 10, 8, 6, 8, 9, 10, 11, 9, 7, 5, 7, 8, 9, 10, 8, 8,
+ 5, 7, 8, 9, 10, 9, 8, 7, 8, 9, 9, 9, 8, 8, 13, 13, 11, 9, 9,
+ 8, 8, 7, 8, 9, 10, 11, 9, 7, 6, 7, 8, 10, 11, 8, 7, 4, 7, 8,
+ 8, 8, 7, 6, 3, 6, 7, 8, 7, 7, 7, 3, 6, 8, 8, 8, 8, 7, 8,
+ 9, 10, 9, 7, 7, 7, 16, 15, 12, 10, 8, 7, 7, 4, 7, 7, 7, 7, 7,
+ 5, 3, 6, 7, 7, 7, 6, 4, 2, 5, 6, 6, 6, 6, 5, 1, 5, 6, 6,
+ 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 11, 11, 10, 9, 7, 5, 6, 18, 17,
+ 13, 10, 7, 5, 4, 2, 3, 3, 3, 3, 4, 2, 1, 1, 2, 2, 2, 2, 2,
+ 1, 0, 1, 1, 1, 1, 2, 3, 2, 2, 3, 3, 3, 3, 5, 7, 6, 6, 7,
+ 6, 5, 11, 12, 12, 11, 9, 8, 7, 18, 20, 15, 13, 11, 9, 8, 6, 6, 6,
+ 6, 6, 5, 2, 7, 7, 7, 7, 7, 6, 2, 8, 9, 9, 8, 9, 7, 3, 8,
+ 12, 11, 11, 12, 11, 7, 10, 16, 16, 15, 17, 14, 9, 13, 19, 22, 20, 19, 16,
+ 11, 18, 23, 24, 22, 20, 18, 12, 14, 16, 15, 16, 12, 8, 4, 14, 18, 17, 18,
+ 14, 9, 5, 14, 20, 19, 20, 16, 11, 7, 14, 20, 22, 22, 19, 14, 10, 16, 22,
+ 27, 24, 22, 18, 12, 19, 25, 30, 28, 24, 20, 14, 23, 28, 31, 30, 26, 22, 16,
+ 22, 28, 26, 20, 16, 11, 6, 22, 28, 28, 23, 18, 12, 8, 22, 27, 31, 24, 19,
+ 14, 10, 22, 27, 32, 25, 22, 18, 14, 23, 28, 33, 30, 25, 22, 16, 26, 30, 34,
+ 32, 28, 24, 18, 28, 31, 34, 35, 29, 25, 21, 9, 12, 14, 14, 15, 13, 12, 8,
+ 10, 13, 14, 15, 13, 11, 6, 10, 12, 14, 14, 12, 11, 5, 8, 11, 13, 14, 13,
+ 12, 6, 8, 11, 14, 15, 14, 12, 8, 9, 11, 13, 15, 14, 12, 14, 14, 12, 12,
+ 13, 14, 12, 6, 10, 12, 13, 13, 11, 9, 6, 9, 11, 13, 13, 11, 8, 4, 7,
+ 10, 12, 12, 10, 9, 3, 7, 10, 12, 11, 11, 9, 4, 6, 9, 11, 11, 12, 10,
+ 9, 10, 12, 12, 11, 11, 9, 17, 15, 13, 12, 10, 10, 9, 4, 7, 9, 9, 9,
+ 8, 4, 3, 6, 8, 8, 8, 7, 4, 2, 5, 7, 7, 7, 7, 4, 2, 5, 6,
+ 6, 7, 7, 5, 6, 6, 7, 6, 7, 6, 5, 12, 12, 11, 10, 7, 6, 5, 19,
+ 18, 14, 10, 8, 6, 4, 2, 2, 3, 3, 3, 3, 2, 1, 1, 2, 2, 2, 2,
+ 2, 1, 1, 0, 0, 0, 0, 2, 4, 3, 3, 4, 4, 4, 5, 6, 8, 7, 7,
+ 8, 7, 6, 12, 14, 12, 11, 10, 8, 7, 19, 20, 16, 13, 11, 10, 9, 7, 6,
+ 6, 6, 6, 5, 2, 8, 8, 7, 7, 8, 6, 2, 8, 9, 9, 9, 9, 7, 4,
+ 8, 13, 12, 12, 12, 11, 7, 11, 17, 17, 16, 16, 14, 9, 15, 21, 23, 20, 19,
+ 16, 11, 19, 24, 26, 23, 21, 18, 13, 15, 17, 15, 16, 12, 8, 4, 15, 18, 18,
+ 17, 13, 9, 5, 15, 20, 19, 19, 15, 11, 7, 15, 21, 23, 23, 19, 15, 11, 18,
+ 25, 28, 26, 23, 18, 12, 20, 26, 33, 31, 26, 19, 14, 23, 29, 33, 33, 28, 22,
+ 16, 22, 28, 27, 21, 15, 11, 6, 22, 28, 30, 22, 17, 12, 8, 23, 28, 32, 25,
+ 19, 15, 11, 23, 29, 34, 28, 22, 18, 15, 24, 31, 37, 34, 28, 21, 16, 27, 34,
+ 39, 37, 31, 25, 18, 30, 35, 40, 40, 33, 26, 20, 9, 13, 16, 19, 19, 17, 14,
+ 8, 12, 15, 18, 19, 16, 13, 7, 10, 14, 17, 18, 15, 13, 6, 9, 12, 15, 17,
+ 15, 13, 6, 9, 11, 15, 17, 15, 13, 8, 9, 11, 14, 16, 16, 13, 14, 14, 12,
+ 13, 16, 15, 13, 7, 11, 14, 17, 16, 13, 10, 6, 9, 13, 16, 16, 13, 9, 5,
+ 8, 11, 14, 14, 11, 8, 4, 7, 10, 12, 12, 12, 9, 5, 7, 10, 12, 12, 12,
+ 9, 9, 10, 11, 12, 11, 11, 9, 17, 15, 13, 11, 10, 10, 9, 5, 8, 9, 10,
+ 11, 9, 6, 4, 6, 8, 9, 10, 9, 5, 3, 5, 7, 7, 7, 7, 4, 2, 6,
+ 6, 6, 6, 7, 5, 6, 7, 7, 6, 6, 6, 5, 12, 12, 11, 9, 7, 5, 5,
+ 19, 17, 13, 10, 7, 5, 4, 3, 2, 3, 4, 4, 5, 3, 1, 2, 2, 3, 3,
+ 3, 3, 1, 1, 0, 0, 0, 0, 2, 4, 3, 3, 3, 3, 3, 4, 6, 8, 7,
+ 7, 7, 7, 5, 12, 14, 12, 11, 10, 8, 7, 19, 20, 16, 13, 11, 10, 8, 7,
+ 6, 6, 7, 7, 6, 3, 8, 8, 7, 8, 8, 7, 3, 8, 9, 9, 9, 9, 7,
+ 4, 8, 13, 12, 12, 12, 11, 7, 11, 17, 17, 16, 16, 14, 9, 15, 21, 22, 21,
+ 18, 16, 11, 19, 24, 25, 23, 21, 18, 12, 15, 17, 16, 16, 13, 9, 5, 15, 19,
+ 18, 17, 14, 9, 5, 15, 20, 19, 18, 14, 11, 7, 15, 22, 24, 22, 19, 15, 10,
+ 18, 24, 28, 26, 23, 18, 12, 21, 26, 34, 32, 25, 20, 14, 24, 29, 34, 33, 27,
+ 22, 16, 23, 28, 27, 21, 16, 12, 7, 23, 29, 29, 22, 17, 12, 8, 23, 28, 32,
+ 24, 19, 15, 10, 22, 29, 35, 29, 22, 18, 14, 23, 30, 36, 34, 27, 22, 16, 27,
+ 32, 39, 38, 31, 24, 18, 30, 36, 40, 40, 33, 26, 20, 10, 14, 18, 20, 21, 19,
+ 15, 8, 12, 16, 20, 21, 17, 13, 7, 10, 15, 18, 19, 16, 13, 6, 9, 12, 15,
+ 19, 16, 13, 6, 9, 12, 15, 18, 16, 14, 8, 9, 11, 14, 18, 17, 13, 14, 13,
+ 12, 13, 16, 17, 14, 7, 11, 15, 18, 17, 14, 11, 6, 10, 13, 16, 17, 13, 9,
+ 5, 8, 12, 14, 14, 11, 9, 4, 7, 10, 13, 13, 12, 10, 5, 7, 10, 12, 12,
+ 12, 9, 10, 10, 11, 12, 12, 11, 10, 17, 15, 12, 12, 10, 11, 9, 5, 8, 10,
+ 11, 12, 10, 6, 4, 7, 9, 10, 10, 9, 5, 3, 6, 7, 7, 7, 7, 4, 1,
+ 6, 6, 6, 7, 7, 5, 6, 7, 7, 6, 6, 6, 5, 13, 12, 11, 9, 7, 6,
+ 5, 19, 17, 13, 10, 7, 5, 4, 3, 3, 3, 4, 5, 6, 3, 1, 1, 2, 3,
+ 3, 3, 2, 1, 1, 0, 0, 0, 0, 1, 4, 3, 4, 3, 3, 3, 3, 6, 8,
+ 7, 7, 7, 6, 5, 13, 14, 12, 11, 9, 8, 6, 19, 21, 15, 13, 11, 9, 8,
+ 7, 6, 6, 6, 7, 6, 3, 9, 8, 7, 7, 8, 6, 2, 9, 10, 9, 8, 8,
+ 7, 3, 9, 13, 12, 12, 12, 11, 7, 12, 18, 17, 16, 16, 13, 8, 15, 21, 22,
+ 20, 18, 15, 10, 19, 24, 26, 23, 21, 17, 12, 15, 16, 15, 15, 12, 9, 4, 15,
+ 19, 17, 17, 13, 9, 4, 15, 20, 19, 18, 14, 10, 7, 15, 21, 23, 21, 18, 14,
+ 10, 18, 24, 29, 26, 23, 17, 12, 20, 27, 33, 31, 25, 19, 14, 24, 29, 33, 33,
+ 28, 21, 15, 22, 27, 26, 20, 15, 11, 7, 23, 27, 27, 21, 16, 12, 7, 22, 27,
+ 29, 23, 18, 14, 10, 23, 28, 33, 27, 23, 18, 13, 25, 30, 35, 33, 26, 22, 16,
+ 27, 32, 38, 38, 30, 23, 18, 29, 34, 38, 37, 32, 25, 20, 10, 14, 17, 21, 21,
+ 18, 15, 9, 12, 15, 20, 20, 17, 13, 7, 11, 14, 17, 19, 15, 13, 6, 9, 12,
+ 16, 18, 16, 14, 6, 9, 12, 15, 19, 17, 14, 9, 10, 11, 14, 18, 17, 14, 14,
+ 13, 12, 14, 17, 17, 13, 7, 11, 15, 18, 17, 15, 11, 6, 10, 13, 16, 17, 13,
+ 9, 5, 8, 12, 15, 14, 11, 9, 4, 8, 11, 13, 13, 12, 9, 5, 7, 10, 12,
+ 13, 12, 10, 10, 10, 11, 12, 12, 12, 10, 16, 14, 12, 12, 11, 11, 10, 5, 8,
+ 10, 11, 12, 10, 6, 4, 7, 9, 10, 10, 9, 5, 3, 6, 7, 8, 7, 7, 4,
+ 2, 6, 7, 7, 7, 7, 5, 6, 7, 7, 7, 7, 6, 5, 13, 12, 11, 9, 7,
+ 5, 5, 17, 16, 12, 10, 7, 5, 4, 3, 3, 3, 4, 5, 6, 4, 1, 1, 2,
+ 3, 3, 3, 2, 1, 1, 0, 0, 0, 0, 1, 4, 4, 4, 3, 3, 3, 3, 7,
+ 9, 8, 7, 8, 6, 5, 13, 14, 12, 10, 9, 8, 6, 18, 19, 15, 13, 11, 9,
+ 8, 7, 6, 6, 6, 7, 6, 4, 9, 8, 7, 7, 8, 6, 2, 9, 10, 9, 8,
+ 8, 7, 3, 9, 14, 13, 12, 12, 10, 7, 12, 18, 17, 16, 16, 14, 9, 15, 21,
+ 22, 20, 18, 15, 10, 18, 23, 24, 22, 19, 17, 12, 15, 15, 14, 13, 11, 9, 4,
+ 16, 17, 15, 14, 12, 9, 4, 15, 19, 17, 15, 12, 10, 7, 15, 20, 21, 18, 16,
+ 14, 10, 18, 23, 26, 23, 20, 17, 12, 21, 25, 31, 27, 22, 18, 14, 23, 28, 31,
+ 29, 24, 20, 15, 20, 23, 20, 15, 13, 11, 7, 21, 23, 22, 17, 13, 11, 7, 20,
+ 23, 23, 19, 15, 13, 10, 20, 24, 28, 22, 18, 17, 14, 23, 26, 30, 28, 23, 19,
+ 16, 26, 29, 33, 32, 25, 21, 17, 28, 31, 34, 34, 27, 22, 18, 11, 13, 16, 19,
+ 19, 16, 13, 10, 12, 15, 18, 18, 15, 11, 8, 11, 14, 16, 17, 14, 11, 7, 9,
+ 12, 15, 17, 15, 12, 8, 10, 12, 15, 18, 15, 12, 8, 9, 12, 14, 17, 16, 12,
+ 12, 12, 11, 13, 16, 16, 12, 9, 11, 14, 16, 15, 12, 9, 7, 10, 12, 15, 14,
+ 11, 8, 7, 9, 12, 13, 12, 10, 7, 6, 9, 11, 13, 12, 10, 8, 6, 8, 10,
+ 12, 12, 11, 9, 10, 9, 10, 12, 11, 11, 8, 15, 13, 11, 11, 10, 9, 8, 7,
+ 9, 10, 10, 11, 9, 6, 6, 8, 9, 9, 9, 7, 4, 4, 7, 8, 7, 6, 6,
+ 4, 4, 8, 7, 7, 6, 6, 5, 6, 8, 7, 7, 6, 6, 5, 12, 11, 10, 8,
+ 6, 5, 5, 16, 15, 11, 9, 6, 5, 4, 5, 4, 4, 4, 5, 6, 4, 3, 3,
+ 4, 4, 3, 3, 2, 2, 2, 2, 2, 1, 1, 0, 4, 2, 3, 3, 2, 2, 2,
+ 7, 7, 6, 6, 6, 5, 3, 12, 13, 11, 9, 7, 6, 4, 17, 18, 13, 10, 8,
+ 7, 5, 4, 4, 3, 3, 3, 4, 4, 5, 5, 3, 3, 3, 3, 2, 6, 5, 4,
+ 4, 4, 3, 2, 5, 9, 8, 7, 7, 6, 4, 8, 14, 13, 12, 12, 9, 5, 13,
+ 17, 18, 16, 14, 11, 7, 16, 20, 21, 18, 15, 13, 8, 10, 10, 9, 9, 7, 4,
+ 3, 9, 12, 11, 10, 8, 4, 2, 9, 13, 12, 12, 8, 5, 3, 9, 15, 16, 15,
+ 12, 9, 6, 13, 18, 22, 20, 17, 12, 8, 16, 21, 27, 24, 19, 14, 10, 20, 24,
+ 27, 27, 21, 16, 11, 15, 19, 18, 13, 9, 6, 3, 15, 20, 20, 15, 10, 6, 3,
+ 15, 20, 22, 16, 12, 8, 5, 15, 20, 25, 20, 16, 13, 9, 18, 23, 28, 26, 21,
+ 16, 11, 21, 26, 31, 30, 23, 17, 13, 24, 29, 31, 32, 25, 20, 14, 13, 16, 20,
+ 25, 25, 24, 19, 11, 14, 18, 23, 25, 21, 17, 10, 14, 17, 20, 23, 19, 16, 8,
+ 12, 14, 17, 20, 18, 15, 6, 9, 12, 15, 17, 18, 15, 5, 8, 11, 13, 16, 18,
+ 15, 7, 8, 9, 13, 15, 18, 15, 9, 14, 17, 20, 21, 19, 15, 8, 13, 15, 19,
+ 21, 18, 14, 7, 11, 14, 17, 17, 15, 12, 6, 9, 12, 14, 14, 14, 11, 3, 7,
+ 10, 12, 13, 14, 11, 4, 6, 9, 11, 12, 12, 11, 9, 7, 8, 10, 10, 11, 11,
+ 7, 11, 13, 14, 16, 15, 11, 5, 10, 11, 13, 13, 14, 9, 4, 8, 10, 11, 11,
+ 11, 7, 3, 5, 7, 8, 8, 8, 5, 2, 4, 6, 6, 6, 6, 5, 6, 6, 5,
+ 5, 5, 5, 5, 10, 9, 7, 4, 3, 4, 4, 4, 6, 7, 7, 9, 11, 11, 3,
+ 4, 6, 6, 7, 8, 7, 1, 3, 4, 4, 4, 4, 3, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 2, 6, 7, 6, 5, 4, 4, 3, 10, 12, 8, 6,
+ 5, 4, 4, 4, 4, 4, 4, 6, 8, 10, 4, 5, 5, 5, 5, 5, 7, 4, 5,
+ 6, 5, 5, 5, 2, 4, 7, 6, 6, 6, 5, 3, 5, 9, 8, 8, 8, 7, 4,
+ 7, 11, 11, 11, 9, 8, 5, 10, 13, 13, 12, 11, 9, 6, 9, 10, 9, 9, 8,
+ 6, 8, 9, 11, 10, 10, 8, 6, 4, 9, 12, 11, 11, 9, 6, 4, 9, 12, 12,
+ 12, 10, 7, 5, 9, 13, 15, 14, 12, 9, 6, 11, 14, 18, 16, 13, 10, 7, 13,
+ 16, 18, 18, 14, 11, 8, 14, 17, 16, 12, 10, 7, 6, 14, 18, 17, 14, 10, 7,
+ 5, 14, 17, 19, 14, 11, 8, 5, 13, 16, 20, 15, 12, 9, 7, 13, 17, 20, 17,
+ 15, 11, 8, 14, 18, 21, 20, 16, 12, 9, 16, 19, 22, 22, 17, 14, 10, 10, 11,
+ 14, 17, 17, 14, 12, 9, 11, 13, 16, 17, 14, 11, 9, 11, 12, 13, 14, 13, 10,
+ 8, 9, 10, 12, 13, 10, 8, 6, 7, 8, 9, 11, 9, 8, 6, 7, 8, 8, 10,
+ 9, 8, 12, 12, 9, 8, 9, 9, 8, 9, 10, 12, 14, 14, 12, 10, 8, 10, 11,
+ 13, 14, 11, 9, 7, 9, 10, 11, 11, 10, 8, 6, 8, 9, 9, 9, 8, 7, 4,
+ 6, 7, 8, 7, 7, 7, 7, 8, 9, 8, 7, 7, 7, 15, 13, 11, 8, 6, 7,
+ 7, 7, 9, 10, 9, 10, 9, 8, 5, 8, 9, 9, 9, 9, 7, 4, 8, 9, 9,
+ 8, 8, 7, 3, 6, 6, 7, 7, 7, 6, 3, 4, 5, 6, 6, 6, 6, 9, 9,
+ 10, 8, 6, 6, 6, 17, 16, 12, 9, 6, 5, 5, 4, 5, 6, 6, 6, 7, 3,
+ 3, 4, 5, 5, 5, 5, 3, 2, 2, 3, 3, 4, 4, 2, 0, 0, 0, 0, 0,
+ 0, 0, 4, 5, 4, 4, 4, 4, 3, 9, 11, 10, 9, 7, 5, 4, 17, 19, 14,
+ 10, 9, 7, 6, 5, 5, 6, 6, 6, 5, 3, 6, 7, 7, 7, 8, 6, 3, 6,
+ 8, 9, 9, 9, 7, 3, 6, 10, 9, 9, 10, 9, 4, 8, 14, 14, 14, 14, 12,
+ 6, 11, 17, 19, 17, 16, 14, 8, 16, 21, 21, 19, 17, 16, 10, 13, 16, 16, 16,
+ 13, 8, 3, 14, 18, 17, 17, 14, 9, 5, 14, 19, 20, 18, 15, 10, 6, 14, 19,
+ 20, 19, 17, 13, 8, 14, 20, 22, 21, 18, 16, 10, 17, 21, 26, 23, 21, 17, 12,
+ 20, 23, 26, 25, 21, 19, 14, 22, 26, 25, 20, 16, 11, 6, 21, 26, 26, 21, 17,
+ 13, 8, 22, 26, 28, 23, 19, 14, 9, 21, 26, 28, 23, 19, 16, 12, 21, 25, 28,
+ 25, 20, 18, 14, 22, 26, 29, 28, 23, 19, 16, 23, 26, 30, 28, 24, 21, 17, 13,
+ 16, 18, 20, 19, 17, 16, 11, 14, 17, 19, 20, 17, 15, 10, 14, 17, 18, 18, 15,
+ 13, 8, 11, 14, 16, 17, 14, 12, 6, 9, 12, 13, 15, 13, 12, 5, 8, 11, 13,
+ 15, 14, 12, 11, 11, 10, 13, 14, 14, 12, 10, 13, 16, 18, 17, 16, 13, 9, 12,
+ 16, 18, 17, 16, 13, 7, 11, 14, 16, 16, 14, 11, 6, 9, 12, 14, 13, 12, 10,
+ 4, 7, 10, 12, 12, 12, 10, 7, 8, 9, 11, 11, 11, 10, 14, 12, 10, 10, 10,
+ 10, 10, 7, 11, 13, 14, 15, 13, 9, 6, 10, 12, 13, 13, 12, 8, 5, 8, 11,
+ 11, 11, 11, 7, 3, 6, 7, 7, 8, 8, 5, 3, 5, 6, 6, 6, 7, 5, 9,
+ 9, 9, 7, 5, 5, 5, 16, 15, 11, 8, 5, 5, 4, 5, 5, 6, 7, 8, 8,
+ 5, 3, 4, 5, 6, 6, 6, 4, 2, 2, 3, 4, 4, 4, 3, 0, 0, 0, 0,
+ 0, 0, 0, 4, 4, 4, 4, 4, 3, 2, 9, 11, 9, 8, 6, 5, 4, 16, 18,
+ 12, 9, 8, 6, 5, 5, 5, 6, 6, 7, 6, 5, 7, 7, 7, 7, 8, 6, 4,
+ 7, 8, 8, 8, 8, 6, 3, 7, 10, 9, 9, 9, 7, 4, 8, 14, 13, 13, 13,
+ 11, 5, 11, 17, 18, 17, 15, 12, 7, 15, 20, 21, 19, 17, 15, 9, 14, 15, 15,
+ 16, 13, 8, 5, 14, 17, 17, 16, 14, 9, 4, 14, 20, 19, 18, 14, 9, 5, 14,
+ 19, 21, 19, 15, 11, 7, 14, 20, 24, 23, 19, 14, 9, 17, 23, 29, 28, 22, 16,
+ 11, 20, 25, 30, 30, 24, 19, 13, 22, 28, 27, 21, 16, 11, 7, 22, 28, 29, 23,
+ 16, 12, 7, 22, 28, 32, 24, 17, 12, 8, 22, 28, 33, 25, 20, 15, 11, 21, 27,
+ 33, 30, 24, 19, 13, 23, 30, 35, 34, 27, 21, 15, 25, 31, 35, 36, 29, 23, 17,
+ 13, 16, 20, 23, 24, 21, 18, 11, 15, 19, 23, 23, 19, 16, 10, 14, 17, 21, 21,
+ 19, 15, 9, 11, 15, 18, 20, 16, 14, 6, 9, 12, 15, 18, 16, 13, 6, 8, 11,
+ 14, 17, 16, 14, 11, 11, 11, 13, 16, 16, 13, 10, 14, 17, 20, 20, 17, 14, 9,
+ 13, 16, 20, 20, 16, 13, 7, 11, 15, 18, 17, 15, 11, 6, 9, 12, 14, 14, 13,
+ 10, 4, 7, 10, 13, 13, 13, 10, 7, 7, 9, 11, 12, 12, 10, 14, 12, 10, 11,
+ 11, 11, 10, 8, 11, 13, 14, 15, 14, 9, 6, 10, 12, 13, 14, 13, 8, 5, 8,
+ 11, 10, 11, 11, 7, 4, 6, 7, 7, 8, 8, 5, 4, 5, 6, 6, 6, 6, 5,
+ 9, 9, 8, 7, 5, 5, 5, 16, 14, 10, 7, 5, 4, 4, 5, 6, 6, 7, 8,
+ 9, 6, 3, 4, 5, 6, 6, 6, 5, 2, 3, 3, 4, 3, 4, 3, 0, 0, 0,
+ 0, 0, 0, 0, 4, 5, 4, 4, 4, 3, 2, 9, 11, 9, 7, 6, 5, 3, 16,
+ 17, 12, 9, 7, 6, 5, 6, 6, 6, 6, 7, 6, 6, 7, 7, 7, 7, 8, 6,
+ 5, 7, 8, 8, 8, 8, 6, 3, 7, 10, 9, 9, 9, 7, 4, 9, 14, 13, 13,
+ 13, 10, 5, 11, 17, 19, 17, 15, 12, 7, 15, 19, 22, 19, 17, 14, 9, 14, 15,
+ 15, 15, 12, 9, 6, 14, 18, 17, 16, 13, 9, 4, 14, 19, 19, 18, 14, 9, 5,
+ 14, 19, 20, 19, 15, 11, 7, 14, 20, 25, 23, 19, 14, 9, 17, 23, 29, 28, 21,
+ 16, 10, 20, 26, 30, 30, 24, 18, 12, 22, 27, 26, 20, 15, 11, 7, 22, 28, 29,
+ 22, 16, 12, 7, 21, 28, 31, 23, 17, 12, 7, 22, 27, 31, 24, 19, 15, 11, 21,
+ 28, 33, 29, 24, 18, 12, 24, 29, 35, 34, 27, 20, 14, 26, 31, 36, 36, 29, 22,
+ 16, 13, 17, 21, 24, 24, 21, 18, 12, 15, 19, 23, 24, 20, 16, 10, 14, 17, 21,
+ 22, 18, 15, 9, 12, 15, 18, 21, 17, 14, 6, 9, 12, 15, 19, 17, 14, 6, 8,
+ 11, 14, 18, 17, 14, 11, 10, 10, 13, 16, 16, 14, 10, 14, 18, 22, 20, 18, 14,
+ 9, 13, 17, 20, 20, 16, 12, 8, 11, 15, 18, 17, 14, 11, 7, 9, 12, 14, 14,
+ 13, 9, 5, 7, 10, 12, 13, 12, 10, 7, 8, 9, 11, 12, 12, 10, 13, 11, 10,
+ 11, 11, 11, 10, 8, 11, 13, 14, 15, 14, 10, 6, 10, 12, 13, 14, 12, 8, 5,
+ 9, 10, 11, 10, 11, 6, 4, 7, 7, 7, 7, 7, 5, 4, 5, 6, 6, 6, 6,
+ 5, 10, 9, 8, 7, 5, 5, 5, 15, 13, 10, 7, 5, 4, 4, 5, 6, 6, 7,
+ 8, 9, 6, 4, 4, 5, 6, 6, 6, 4, 2, 3, 4, 3, 3, 3, 2, 0, 0,
+ 0, 0, 0, 0, 0, 4, 5, 4, 4, 4, 3, 2, 9, 11, 9, 7, 6, 5, 3,
+ 15, 16, 12, 9, 7, 6, 5, 6, 6, 6, 6, 7, 6, 6, 7, 7, 7, 7, 8,
+ 6, 4, 7, 8, 8, 8, 8, 6, 2, 7, 10, 9, 9, 9, 7, 4, 9, 14, 14,
+ 12, 13, 10, 5, 12, 17, 19, 17, 15, 12, 7, 15, 20, 22, 19, 17, 14, 9, 14,
+ 16, 15, 15, 12, 8, 6, 15, 18, 17, 17, 14, 9, 4, 15, 19, 19, 18, 14, 9,
+ 5, 14, 19, 20, 19, 15, 10, 7, 15, 21, 24, 23, 19, 14, 9, 17, 23, 30, 27,
+ 21, 16, 11, 20, 25, 30, 29, 24, 18, 12, 22, 27, 26, 20, 15, 11, 7, 22, 27,
+ 27, 21, 16, 11, 7, 22, 27, 30, 23, 17, 12, 7, 22, 27, 30, 24, 19, 15, 11,
+ 22, 26, 32, 29, 23, 18, 13, 24, 29, 34, 34, 26, 20, 14, 26, 31, 35, 35, 28,
+ 22, 16, 13, 17, 20, 24, 25, 22, 19, 12, 16, 19, 24, 24, 21, 16, 10, 14, 18,
+ 21, 23, 19, 15, 9, 12, 15, 19, 21, 17, 14, 7, 10, 12, 16, 19, 16, 14, 6,
+ 9, 11, 15, 18, 18, 14, 9, 9, 10, 13, 17, 17, 14, 11, 14, 18, 21, 21, 18,
+ 14, 9, 13, 17, 20, 20, 17, 13, 8, 11, 15, 17, 18, 15, 11, 7, 9, 12, 15,
+ 14, 13, 9, 5, 8, 10, 13, 13, 13, 10, 7, 7, 9, 12, 12, 12, 10, 10, 9,
+ 9, 11, 11, 11, 10, 8, 12, 13, 15, 16, 14, 10, 7, 10, 12, 13, 14, 12, 8,
+ 5, 9, 11, 11, 10, 10, 6, 4, 7, 8, 7, 7, 8, 5, 4, 5, 7, 6, 6,
+ 6, 5, 9, 8, 7, 6, 5, 5, 5, 11, 10, 8, 6, 4, 4, 4, 6, 6, 6,
+ 7, 9, 9, 6, 4, 4, 5, 6, 6, 7, 4, 2, 3, 4, 4, 3, 3, 2, 0,
+ 0, 0, 0, 0, 0, 0, 4, 5, 4, 4, 4, 3, 2, 9, 9, 8, 6, 6, 5,
+ 3, 12, 13, 10, 8, 7, 6, 5, 6, 6, 6, 6, 7, 6, 6, 7, 7, 7, 8,
+ 8, 6, 4, 7, 9, 8, 8, 8, 6, 2, 7, 11, 9, 9, 9, 7, 3, 9, 15,
+ 13, 13, 13, 10, 5, 12, 16, 17, 16, 14, 12, 7, 13, 18, 19, 18, 16, 13, 8,
+ 14, 15, 14, 13, 12, 8, 6, 15, 17, 15, 14, 12, 9, 4, 15, 18, 17, 15, 12,
+ 9, 5, 14, 18, 18, 15, 14, 11, 7, 15, 20, 22, 20, 17, 13, 8, 17, 22, 25,
+ 22, 18, 15, 10, 18, 23, 26, 24, 21, 16, 12, 20, 22, 20, 15, 13, 10, 7, 20,
+ 23, 22, 17, 14, 11, 7, 20, 23, 23, 17, 14, 11, 7, 20, 23, 24, 19, 16, 14,
+ 10, 20, 23, 27, 24, 20, 16, 12, 22, 26, 29, 29, 22, 18, 14, 24, 27, 29, 29,
+ 24, 19, 15, 12, 15, 18, 21, 20, 18, 15, 11, 13, 17, 20, 20, 17, 13, 10, 13,
+ 15, 18, 18, 15, 12, 9, 11, 13, 15, 18, 14, 11, 7, 9, 11, 14, 17, 14, 11,
+ 6, 8, 10, 12, 16, 14, 11, 8, 9, 10, 12, 14, 14, 11, 11, 13, 16, 18, 17,
+ 15, 11, 10, 12, 14, 17, 16, 13, 10, 8, 11, 14, 15, 14, 11, 8, 8, 9, 11,
+ 13, 12, 10, 7, 6, 8, 10, 11, 11, 10, 7, 5, 7, 9, 11, 10, 10, 7, 10,
+ 9, 9, 10, 9, 9, 7, 8, 11, 12, 12, 13, 11, 8, 8, 10, 11, 11, 11, 10,
+ 6, 7, 9, 10, 9, 8, 8, 5, 5, 8, 7, 6, 6, 6, 4, 3, 5, 6, 5,
+ 5, 5, 4, 7, 7, 7, 6, 5, 4, 4, 11, 11, 8, 6, 5, 3, 3, 7, 6,
+ 6, 6, 7, 8, 6, 4, 5, 5, 6, 6, 5, 4, 2, 3, 4, 4, 3, 3, 2,
+ 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 3, 3, 3, 2, 7, 9, 7, 6, 5,
+ 4, 3, 12, 13, 10, 8, 6, 5, 4, 4, 4, 5, 5, 6, 6, 6, 5, 6, 5,
+ 6, 6, 5, 4, 6, 7, 7, 6, 6, 5, 2, 6, 8, 7, 7, 7, 6, 3, 7,
+ 12, 11, 11, 11, 8, 4, 10, 15, 16, 14, 12, 10, 6, 13, 17, 19, 16, 14, 12,
+ 7, 11, 13, 12, 12, 10, 7, 6, 11, 14, 13, 13, 10, 7, 4, 12, 16, 16, 14,
+ 11, 7, 4, 11, 16, 16, 15, 12, 9, 6, 12, 17, 21, 19, 15, 11, 7, 15, 20,
+ 24, 23, 18, 13, 8, 17, 21, 25, 25, 20, 15, 10, 18, 22, 21, 16, 12, 9, 5,
+ 18, 22, 23, 17, 13, 9, 5, 18, 22, 25, 18, 13, 10, 6, 18, 22, 26, 21, 16,
+ 12, 9, 18, 23, 27, 24, 19, 15, 10, 20, 25, 30, 28, 21, 16, 11, 22, 26, 30,
+ 30, 24, 18, 13, 13, 17, 21, 26, 25, 22, 19, 11, 15, 19, 23, 25, 22, 19, 10,
+ 14, 18, 21, 24, 21, 17, 9, 12, 15, 18, 21, 19, 15, 6, 9, 12, 15, 16, 18,
+ 15, 3, 6, 10, 13, 16, 17, 15, 4, 6, 8, 12, 15, 18, 15, 10, 14, 18, 21,
+ 21, 18, 16, 9, 13, 16, 20, 21, 18, 14, 7, 11, 15, 17, 18, 18, 12, 6, 9,
+ 12, 15, 15, 15, 10, 3, 6, 9, 12, 12, 14, 10, 2, 4, 7, 10, 12, 11, 10,
+ 6, 5, 6, 9, 10, 10, 10, 7, 11, 14, 15, 16, 15, 12, 6, 10, 12, 13, 15,
+ 14, 10, 5, 8, 11, 11, 12, 12, 8, 5, 6, 8, 8, 9, 9, 5, 1, 3, 4,
+ 5, 5, 6, 5, 4, 3, 3, 3, 3, 4, 5, 8, 7, 4, 2, 2, 2, 3, 6,
+ 6, 8, 9, 10, 11, 9, 5, 6, 7, 8, 8, 9, 8, 4, 5, 6, 6, 6, 7,
+ 7, 3, 4, 4, 4, 4, 4, 3, 0, 2, 1, 1, 2, 1, 3, 4, 5, 4, 3,
+ 2, 2, 3, 8, 9, 6, 4, 3, 2, 3, 4, 6, 6, 6, 7, 8, 9, 5, 6,
+ 6, 6, 7, 7, 8, 5, 6, 7, 7, 7, 6, 6, 5, 7, 6, 6, 6, 5, 3,
+ 4, 7, 6, 6, 6, 5, 3, 5, 9, 9, 8, 7, 6, 4, 8, 11, 11, 9, 9,
+ 7, 4, 9, 11, 11, 11, 9, 7, 8, 9, 12, 11, 12, 10, 7, 7, 10, 13, 12,
+ 12, 10, 8, 6, 9, 12, 12, 12, 9, 7, 4, 8, 11, 13, 12, 10, 7, 5, 9,
+ 12, 16, 15, 11, 8, 5, 11, 13, 16, 16, 12, 9, 6, 14, 18, 17, 14, 11, 8,
+ 7, 14, 18, 19, 14, 12, 9, 7, 14, 19, 21, 14, 12, 9, 7, 14, 17, 20, 15,
+ 11, 8, 5, 13, 16, 19, 16, 12, 9, 6, 13, 17, 19, 18, 14, 10, 7, 14, 17,
+ 20, 19, 15, 11, 8, 15, 17, 19, 22, 22, 19, 17, 15, 16, 18, 21, 22, 19, 16,
+ 14, 16, 18, 19, 20, 18, 14, 13, 14, 15, 17, 18, 15, 10, 10, 11, 12, 13, 14,
+ 12, 10, 6, 8, 9, 9, 12, 12, 10, 8, 8, 8, 9, 11, 12, 10, 13, 16, 17,
+ 19, 19, 18, 16, 13, 14, 17, 18, 18, 16, 15, 11, 14, 16, 17, 16, 15, 13, 10,
+ 12, 14, 14, 14, 13, 9, 7, 9, 10, 11, 10, 9, 9, 3, 6, 7, 8, 9, 9,
+ 9, 10, 9, 7, 8, 8, 8, 9, 12, 14, 16, 15, 16, 16, 14, 10, 13, 15, 15,
+ 15, 15, 13, 9, 13, 14, 14, 14, 13, 12, 7, 10, 11, 11, 12, 11, 9, 3, 6,
+ 8, 8, 8, 8, 8, 5, 5, 5, 6, 7, 7, 8, 12, 12, 8, 5, 6, 6, 8,
+ 9, 10, 11, 12, 12, 13, 10, 7, 8, 9, 10, 11, 11, 9, 6, 7, 8, 8, 8,
+ 9, 8, 3, 4, 4, 5, 5, 5, 4, 2, 0, 0, 0, 0, 2, 3, 5, 7, 6,
+ 4, 2, 1, 3, 12, 14, 9, 6, 4, 3, 3, 4, 5, 7, 8, 9, 9, 10, 5,
+ 6, 6, 7, 8, 8, 9, 5, 7, 7, 7, 7, 6, 7, 5, 8, 8, 8, 8, 6,
+ 3, 4, 10, 10, 10, 10, 9, 3, 7, 12, 13, 12, 12, 10, 5, 12, 14, 15, 13,
+ 12, 11, 7, 12, 14, 14, 15, 11, 8, 9, 12, 16, 15, 16, 13, 8, 8, 12, 18,
+ 18, 17, 14, 9, 6, 12, 16, 18, 16, 14, 10, 5, 12, 16, 17, 16, 14, 11, 7,
+ 12, 16, 19, 17, 15, 12, 9, 14, 17, 19, 18, 15, 13, 10, 20, 23, 22, 19, 14,
+ 10, 8, 19, 23, 23, 19, 15, 12, 7, 19, 23, 25, 20, 16, 12, 7, 19, 22, 25,
+ 19, 16, 13, 9, 18, 21, 23, 20, 16, 14, 10, 17, 19, 23, 22, 17, 13, 12, 18,
+ 21, 23, 23, 18, 14, 12, 17, 20, 22, 25, 24, 23, 20, 15, 19, 21, 24, 24, 21,
+ 19, 14, 17, 21, 22, 22, 20, 17, 13, 15, 18, 20, 21, 18, 13, 9, 12, 15, 17,
+ 17, 15, 13, 6, 9, 11, 14, 16, 15, 13, 7, 8, 10, 13, 15, 15, 13, 14, 17,
+ 20, 22, 21, 20, 18, 13, 16, 21, 22, 21, 19, 16, 11, 15, 18, 19, 20, 17, 15,
+ 10, 12, 16, 17, 17, 16, 11, 7, 9, 12, 14, 13, 12, 11, 4, 7, 9, 12, 12,
+ 12, 11, 10, 9, 8, 11, 11, 12, 11, 11, 15, 17, 18, 19, 18, 14, 10, 13, 16,
+ 17, 18, 16, 12, 8, 12, 14, 14, 15, 15, 11, 7, 10, 11, 11, 11, 11, 7, 4,
+ 6, 7, 8, 7, 8, 7, 4, 5, 5, 6, 6, 7, 7, 11, 11, 7, 4, 5, 5,
+ 6, 9, 9, 10, 11, 13, 13, 10, 7, 8, 9, 10, 10, 11, 9, 6, 7, 7, 7,
+ 7, 8, 6, 3, 4, 4, 4, 4, 4, 3, 1, 0, 0, 0, 0, 1, 2, 5, 6,
+ 5, 4, 2, 2, 2, 11, 13, 8, 6, 4, 3, 3, 4, 5, 6, 8, 9, 10, 10,
+ 6, 6, 6, 7, 8, 8, 9, 6, 7, 7, 7, 7, 6, 6, 6, 9, 8, 8, 8,
+ 6, 2, 5, 10, 10, 9, 9, 8, 3, 7, 13, 14, 13, 12, 9, 5, 11, 16, 18,
+ 15, 14, 11, 6, 13, 15, 15, 15, 11, 9, 10, 12, 16, 16, 16, 12, 8, 8, 13,
+ 18, 18, 17, 13, 9, 5, 13, 18, 19, 18, 15, 10, 5, 12, 18, 21, 20, 16, 11,
+ 6, 12, 19, 25, 24, 19, 13, 8, 16, 21, 26, 26, 21, 15, 10, 20, 27, 26, 20,
+ 15, 10, 9, 21, 27, 28, 22, 16, 11, 7, 20, 28, 31, 23, 17, 12, 7, 21, 26,
+ 31, 24, 18, 13, 8, 20, 25, 31, 27, 21, 15, 10, 20, 26, 31, 31, 23, 17, 11,
+ 22, 28, 32, 32, 25, 19, 13, 17, 21, 24, 28, 27, 25, 22, 15, 20, 23, 26, 26,
+ 24, 20, 14, 18, 21, 24, 25, 22, 19, 13, 16, 19, 21, 23, 20, 15, 9, 12, 15,
+ 18, 20, 18, 15, 6, 9, 12, 15, 18, 17, 15, 7, 7, 11, 14, 17, 18, 14, 14,
+ 18, 21, 25, 24, 22, 18, 13, 16, 21, 24, 24, 21, 17, 11, 15, 18, 21, 21, 18,
+ 14, 10, 13, 15, 17, 18, 16, 11, 7, 10, 12, 14, 15, 14, 11, 4, 7, 10, 12,
+ 13, 13, 11, 9, 8, 9, 11, 11, 12, 11, 11, 15, 17, 18, 20, 18, 14, 10, 14,
+ 16, 17, 18, 16, 12, 8, 12, 14, 14, 15, 15, 10, 8, 10, 11, 11, 11, 11, 7,
+ 4, 6, 7, 7, 8, 7, 7, 5, 5, 6, 6, 6, 6, 7, 11, 10, 7, 4, 5,
+ 5, 6, 9, 9, 10, 11, 13, 13, 10, 7, 8, 9, 10, 10, 10, 8, 6, 6, 7,
+ 7, 7, 7, 6, 3, 4, 4, 4, 4, 4, 3, 1, 0, 0, 0, 0, 1, 2, 5,
+ 6, 5, 4, 2, 2, 2, 10, 11, 8, 5, 4, 3, 3, 5, 5, 6, 8, 8, 10,
+ 10, 6, 6, 6, 7, 8, 8, 8, 6, 7, 8, 7, 7, 6, 5, 6, 9, 8, 8,
+ 8, 6, 2, 5, 10, 10, 9, 9, 7, 3, 7, 13, 14, 13, 11, 9, 4, 10, 15,
+ 18, 15, 13, 11, 6, 13, 14, 14, 15, 11, 9, 10, 13, 17, 16, 16, 12, 8, 7,
+ 13, 19, 18, 17, 13, 8, 5, 13, 18, 19, 18, 14, 9, 4, 12, 17, 21, 19, 15,
+ 10, 6, 13, 19, 24, 23, 18, 12, 8, 16, 22, 26, 26, 20, 14, 9, 21, 27, 26,
+ 20, 15, 10, 8, 21, 27, 28, 21, 16, 11, 6, 20, 26, 31, 22, 17, 12, 6, 20,
+ 26, 31, 23, 18, 13, 7, 19, 26, 30, 27, 20, 14, 9, 20, 25, 31, 30, 23, 16,
+ 11, 22, 27, 32, 32, 25, 19, 12, 17, 20, 24, 28, 29, 26, 23, 16, 20, 24, 28,
+ 28, 24, 20, 14, 18, 22, 25, 26, 23, 19, 13, 16, 19, 22, 25, 21, 15, 10, 13,
+ 15, 19, 21, 19, 15, 7, 9, 13, 15, 20, 18, 16, 5, 8, 12, 15, 17, 19, 15,
+ 14, 18, 22, 26, 25, 22, 19, 13, 17, 20, 24, 24, 21, 17, 11, 15, 19, 22, 21,
+ 19, 15, 10, 13, 16, 18, 18, 17, 12, 7, 10, 12, 14, 15, 14, 11, 4, 7, 10,
+ 12, 13, 14, 12, 5, 6, 9, 12, 12, 12, 11, 11, 16, 17, 18, 20, 18, 14, 10,
+ 14, 16, 17, 18, 16, 12, 9, 13, 15, 14, 15, 14, 10, 8, 11, 11, 11, 12, 11,
+ 7, 4, 7, 8, 8, 8, 8, 7, 4, 5, 6, 6, 6, 6, 7, 6, 5, 5, 5,
+ 5, 5, 6, 9, 9, 10, 12, 13, 14, 10, 8, 8, 9, 10, 10, 10, 8, 7, 7,
+ 8, 7, 7, 7, 6, 3, 4, 4, 4, 4, 4, 3, 2, 0, 0, 0, 0, 1, 2,
+ 5, 5, 3, 2, 2, 1, 1, 6, 7, 4, 4, 3, 2, 2, 5, 5, 6, 8, 9,
+ 10, 10, 6, 6, 6, 7, 8, 8, 8, 6, 7, 7, 7, 7, 5, 5, 6, 9, 8,
+ 7, 8, 6, 2, 6, 11, 9, 9, 9, 7, 3, 7, 12, 13, 12, 10, 8, 4, 7,
+ 12, 15, 14, 12, 10, 5, 13, 15, 14, 14, 11, 9, 10, 13, 17, 16, 15, 12, 8,
+ 7, 13, 19, 18, 16, 13, 8, 4, 13, 18, 19, 18, 13, 9, 4, 13, 17, 20, 19,
+ 15, 10, 5, 13, 18, 24, 22, 18, 11, 7, 13, 18, 24, 25, 19, 14, 8, 20, 26,
+ 24, 19, 14, 10, 9, 20, 26, 27, 21, 15, 10, 6, 21, 26, 28, 21, 16, 11, 6,
+ 21, 25, 29, 23, 17, 12, 7, 20, 25, 28, 25, 19, 14, 9, 20, 26, 30, 27, 21,
+ 15, 10, 20, 26, 30, 30, 24, 17, 12, 16, 20, 24, 28, 28, 26, 21, 15, 19, 23,
+ 27, 28, 24, 20, 13, 17, 21, 24, 26, 22, 18, 12, 15, 18, 21, 24, 20, 15, 9,
+ 12, 15, 17, 21, 18, 15, 7, 10, 12, 16, 19, 18, 16, 5, 8, 11, 15, 18, 18,
+ 15, 14, 17, 21, 25, 24, 21, 18, 12, 16, 20, 23, 23, 20, 16, 11, 14, 18, 20,
+ 21, 18, 14, 9, 12, 15, 18, 18, 16, 11, 7, 9, 11, 14, 14, 14, 11, 4, 7,
+ 10, 13, 13, 14, 11, 5, 6, 9, 12, 12, 12, 11, 11, 15, 17, 17, 19, 17, 13,
+ 9, 13, 15, 16, 17, 16, 11, 8, 12, 14, 14, 14, 14, 9, 7, 10, 10, 10, 11,
+ 11, 7, 3, 6, 7, 7, 7, 8, 6, 4, 5, 6, 6, 6, 6, 7, 7, 5, 5,
+ 5, 5, 5, 5, 8, 9, 10, 11, 12, 13, 9, 7, 7, 8, 9, 10, 9, 7, 5,
+ 6, 7, 7, 6, 6, 5, 3, 4, 3, 3, 3, 3, 3, 1, 2, 1, 1, 1, 0,
+ 1, 4, 5, 3, 3, 2, 2, 1, 7, 8, 5, 4, 3, 2, 2, 5, 5, 5, 7,
+ 8, 9, 9, 7, 6, 6, 7, 7, 7, 7, 7, 8, 7, 7, 7, 5, 4, 7, 10,
+ 8, 7, 7, 6, 2, 6, 11, 10, 9, 9, 7, 2, 8, 12, 12, 11, 10, 8, 4,
+ 8, 12, 15, 12, 11, 10, 5, 14, 14, 13, 12, 11, 8, 9, 14, 16, 15, 14, 11,
+ 8, 6, 14, 18, 16, 14, 11, 8, 4, 14, 18, 17, 14, 12, 8, 4, 12, 17, 19,
+ 16, 13, 10, 5, 13, 17, 21, 18, 14, 11, 7, 14, 18, 21, 20, 15, 12, 8, 19,
+ 22, 19, 15, 12, 10, 7, 19, 22, 21, 17, 14, 10, 6, 20, 22, 23, 17, 13, 10,
+ 6, 19, 22, 23, 18, 14, 11, 7, 18, 21, 23, 20, 16, 12, 8, 18, 21, 23, 23,
+ 17, 13, 10, 19, 22, 24, 24, 19, 15, 11, 14, 18, 21, 23, 24, 21, 18, 14, 17,
+ 20, 23, 23, 20, 16, 12, 15, 19, 21, 22, 18, 15, 11, 14, 16, 19, 20, 17, 14,
+ 8, 11, 13, 16, 20, 18, 14, 7, 10, 13, 15, 19, 18, 14, 6, 8, 12, 15, 18,
+ 17, 14, 13, 16, 18, 21, 20, 18, 15, 11, 15, 17, 20, 19, 16, 13, 10, 13, 16,
+ 18, 17, 15, 12, 9, 11, 14, 16, 15, 14, 11, 6, 9, 12, 14, 14, 13, 10, 5,
+ 8, 11, 13, 13, 12, 11, 7, 7, 9, 12, 12, 12, 11, 10, 14, 15, 15, 16, 14,
+ 11, 8, 12, 14, 15, 14, 13, 10, 7, 11, 13, 12, 12, 12, 8, 6, 9, 9, 9,
+ 9, 9, 6, 3, 7, 8, 7, 7, 7, 6, 4, 5, 6, 6, 6, 6, 6, 8, 7,
+ 6, 5, 5, 5, 5, 8, 8, 9, 9, 10, 11, 7, 6, 6, 7, 8, 8, 8, 5,
+ 4, 5, 6, 5, 5, 5, 3, 2, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2,
+ 1, 0, 5, 5, 4, 3, 2, 2, 1, 7, 10, 6, 4, 3, 2, 2, 4, 4, 4,
+ 5, 6, 7, 7, 5, 5, 4, 4, 5, 5, 5, 5, 4, 4, 3, 3, 2, 2, 4,
+ 6, 4, 4, 4, 3, 1, 5, 8, 8, 7, 7, 5, 2, 6, 11, 12, 11, 9, 7,
+ 3, 9, 13, 15, 12, 11, 8, 4, 8, 9, 9, 9, 7, 6, 7, 8, 11, 10, 10,
+ 7, 4, 4, 8, 12, 12, 11, 7, 4, 2, 8, 12, 13, 12, 9, 6, 3, 9, 13,
+ 17, 15, 12, 8, 4, 11, 16, 21, 19, 14, 10, 5, 13, 18, 21, 21, 16, 11, 7,
+ 15, 19, 17, 13, 9, 6, 6, 14, 18, 19, 14, 9, 6, 3, 14, 19, 21, 15, 10,
+ 6, 3, 14, 18, 22, 16, 12, 9, 6, 14, 18, 23, 21, 16, 11, 7, 16, 21, 25,
+ 25, 19, 13, 8, 19, 23, 25, 26, 20, 15, 10, 14, 17, 22, 25, 25, 23, 20, 13,
+ 16, 20, 24, 25, 22, 18, 13, 15, 18, 21, 24, 19, 16, 12, 13, 16, 19, 21, 17,
+ 14, 9, 10, 12, 14, 15, 16, 13, 5, 6, 8, 11, 13, 15, 13, 3, 3, 6, 9,
+ 13, 15, 13, 13, 15, 18, 22, 22, 19, 17, 12, 14, 17, 21, 21, 18, 16, 11, 13,
+ 16, 18, 18, 16, 12, 11, 11, 13, 15, 15, 13, 7, 8, 8, 9, 11, 10, 11, 8,
+ 3, 3, 5, 8, 9, 9, 8, 4, 3, 4, 7, 8, 8, 7, 12, 13, 15, 16, 17,
+ 17, 16, 11, 13, 14, 15, 16, 16, 14, 10, 12, 13, 13, 13, 14, 12, 10, 10, 10,
+ 10, 11, 10, 6, 6, 6, 6, 6, 5, 5, 5, 0, 2, 1, 2, 4, 4, 5, 5,
+ 4, 2, 1, 3, 4, 5, 11, 12, 13, 13, 15, 16, 16, 10, 11, 12, 14, 14, 15,
+ 14, 9, 10, 12, 12, 13, 13, 12, 6, 9, 9, 9, 9, 9, 7, 4, 5, 5, 5,
+ 5, 4, 4, 0, 2, 2, 1, 2, 3, 5, 5, 6, 3, 2, 3, 3, 4, 9, 11,
+ 12, 13, 14, 15, 16, 8, 9, 11, 12, 13, 14, 14, 8, 9, 10, 11, 11, 12, 12,
+ 8, 8, 8, 8, 8, 8, 5, 5, 7, 7, 6, 6, 5, 4, 3, 6, 7, 7, 7,
+ 6, 4, 5, 8, 9, 8, 8, 7, 5, 10, 11, 12, 12, 12, 14, 15, 10, 12, 12,
+ 13, 12, 12, 14, 10, 13, 13, 13, 11, 10, 11, 10, 12, 13, 12, 11, 8, 5, 8,
+ 11, 12, 12, 9, 7, 5, 7, 10, 14, 13, 10, 8, 5, 8, 11, 14, 14, 11, 9,
+ 6, 14, 19, 17, 15, 12, 12, 14, 15, 19, 19, 16, 13, 11, 12, 15, 19, 21, 15,
+ 13, 10, 9, 15, 18, 21, 15, 12, 9, 6, 13, 16, 18, 15, 11, 9, 7, 12, 15,
+ 18, 17, 13, 9, 7, 12, 16, 18, 19, 14, 11, 8, 21, 23, 24, 27, 27, 25, 23,
+ 20, 23, 25, 26, 26, 23, 21, 20, 22, 23, 24, 24, 22, 18, 18, 20, 21, 21, 21,
+ 18, 12, 15, 17, 18, 17, 16, 13, 12, 11, 13, 13, 12, 13, 13, 12, 6, 8, 10,
+ 12, 13, 13, 12, 19, 22, 23, 25, 25, 24, 23, 18, 21, 23, 25, 24, 22, 21, 17,
+ 21, 22, 22, 21, 20, 18, 16, 19, 20, 20, 19, 16, 11, 12, 15, 16, 16, 12, 12,
+ 11, 8, 11, 12, 10, 11, 11, 11, 4, 6, 9, 10, 10, 11, 11, 17, 20, 21, 23,
+ 23, 23, 20, 15, 19, 21, 22, 22, 21, 18, 14, 18, 20, 20, 19, 20, 16, 13, 15,
+ 16, 16, 16, 15, 11, 8, 12, 13, 13, 10, 10, 10, 2, 7, 8, 8, 9, 9, 10,
+ 5, 6, 6, 7, 8, 9, 10, 14, 15, 17, 18, 19, 20, 18, 12, 13, 16, 17, 17,
+ 17, 16, 10, 12, 13, 14, 14, 14, 13, 7, 11, 11, 11, 11, 9, 9, 4, 7, 6,
+ 6, 4, 5, 5, 2, 0, 0, 2, 3, 4, 6, 5, 7, 3, 2, 2, 3, 4, 11,
+ 12, 13, 15, 16, 17, 18, 8, 11, 13, 14, 15, 15, 16, 8, 10, 11, 11, 12, 13,
+ 12, 8, 8, 8, 8, 8, 7, 5, 6, 7, 7, 7, 8, 6, 4, 3, 8, 9, 8,
+ 8, 8, 3, 5, 8, 9, 9, 9, 8, 5, 10, 12, 12, 13, 13, 16, 18, 10, 14,
+ 14, 15, 12, 14, 14, 10, 15, 15, 14, 11, 10, 11, 9, 14, 15, 13, 12, 7, 3,
+ 9, 13, 14, 13, 10, 9, 5, 9, 12, 14, 13, 11, 9, 7, 9, 11, 14, 14, 12,
+ 10, 8, 17, 20, 19, 17, 13, 14, 16, 17, 20, 20, 18, 14, 11, 13, 17, 20, 22,
+ 17, 14, 9, 9, 17, 19, 21, 16, 13, 11, 7, 15, 17, 19, 16, 12, 10, 8, 13,
+ 16, 18, 17, 13, 10, 8, 12, 15, 18, 18, 14, 11, 9, 21, 24, 28, 30, 29, 29,
+ 26, 20, 24, 27, 28, 30, 27, 23, 18, 23, 26, 27, 27, 24, 20, 17, 20, 23, 24,
+ 25, 21, 15, 14, 17, 20, 21, 19, 17, 15, 10, 13, 15, 16, 18, 17, 15, 6, 9,
+ 12, 15, 17, 17, 15, 19, 23, 25, 28, 28, 26, 23, 17, 21, 25, 27, 27, 24, 21,
+ 16, 19, 24, 25, 24, 22, 18, 15, 17, 21, 22, 21, 18, 13, 12, 14, 17, 18, 15,
+ 14, 13, 7, 10, 12, 14, 14, 14, 13, 4, 6, 10, 13, 13, 13, 13, 16, 20, 22,
+ 23, 25, 22, 18, 15, 18, 20, 22, 22, 21, 17, 14, 17, 19, 19, 19, 19, 14, 12,
+ 15, 16, 16, 15, 14, 9, 7, 11, 12, 12, 10, 10, 9, 2, 7, 7, 8, 8, 8,
+ 9, 5, 5, 6, 6, 7, 7, 8, 14, 14, 15, 16, 18, 18, 16, 12, 13, 14, 15,
+ 16, 16, 13, 9, 12, 12, 12, 12, 12, 10, 6, 10, 9, 9, 9, 7, 8, 4, 6,
+ 5, 5, 3, 3, 4, 1, 0, 0, 1, 2, 3, 3, 5, 6, 3, 2, 2, 2, 2,
+ 10, 11, 12, 13, 14, 15, 16, 7, 10, 11, 12, 13, 13, 14, 7, 9, 10, 10, 10,
+ 10, 10, 7, 7, 7, 7, 7, 6, 3, 5, 7, 7, 7, 8, 6, 2, 3, 8, 10,
+ 9, 9, 8, 3, 5, 11, 13, 11, 11, 10, 5, 10, 13, 13, 13, 12, 14, 15, 10,
+ 14, 14, 15, 11, 12, 13, 10, 16, 16, 16, 11, 9, 8, 10, 15, 17, 17, 12, 7,
+ 3, 9, 15, 19, 18, 15, 10, 5, 9, 15, 22, 21, 17, 11, 7, 11, 17, 22, 23,
+ 20, 14, 8, 18, 25, 24, 18, 13, 13, 14, 19, 25, 26, 19, 14, 11, 11, 18, 24,
+ 29, 21, 15, 10, 7, 18, 25, 29, 22, 17, 11, 6, 18, 23, 28, 25, 19, 13, 8,
+ 17, 23, 28, 27, 21, 15, 10, 18, 23, 28, 29, 22, 18, 12, 20, 24, 27, 31, 31,
+ 28, 26, 19, 23, 27, 30, 30, 27, 23, 18, 21, 25, 27, 29, 26, 21, 16, 19, 22,
+ 25, 26, 23, 17, 13, 16, 18, 21, 22, 19, 16, 10, 12, 15, 17, 20, 19, 16, 6,
+ 9, 12, 16, 18, 19, 16, 18, 21, 25, 28, 28, 26, 22, 16, 20, 24, 27, 27, 23,
+ 19, 15, 18, 22, 24, 24, 22, 17, 14, 16, 19, 22, 21, 19, 13, 11, 13, 16, 18,
+ 16, 15, 13, 7, 9, 12, 14, 14, 14, 12, 4, 7, 10, 13, 13, 14, 12, 15, 18,
+ 21, 22, 24, 21, 18, 14, 17, 20, 21, 21, 19, 16, 13, 16, 18, 18, 18, 17, 13,
+ 11, 13, 15, 14, 15, 14, 8, 7, 10, 11, 11, 10, 9, 8, 2, 6, 7, 7, 8,
+ 8, 8, 3, 5, 6, 6, 7, 7, 7, 13, 13, 14, 15, 16, 17, 14, 11, 11, 13,
+ 14, 14, 14, 11, 8, 10, 11, 11, 11, 10, 9, 5, 8, 7, 7, 7, 6, 6, 3,
+ 4, 4, 4, 2, 2, 3, 1, 2, 1, 0, 1, 2, 3, 3, 4, 2, 2, 2, 2,
+ 2, 9, 9, 10, 11, 12, 14, 13, 6, 8, 9, 10, 11, 11, 11, 6, 8, 8, 8,
+ 9, 9, 8, 6, 7, 6, 6, 6, 5, 3, 4, 8, 8, 8, 8, 6, 2, 3, 9,
+ 10, 10, 9, 7, 3, 5, 9, 12, 11, 11, 9, 5, 11, 13, 13, 13, 11, 12, 13,
+ 11, 15, 15, 15, 11, 10, 10, 11, 16, 16, 16, 11, 8, 7, 11, 16, 17, 16, 12,
+ 8, 3, 10, 15, 19, 17, 14, 9, 5, 10, 15, 22, 21, 16, 10, 6, 11, 16, 21,
+ 23, 18, 13, 8, 19, 25, 24, 18, 13, 11, 12, 19, 25, 27, 20, 14, 9, 9, 18,
+ 25, 29, 21, 15, 10, 6, 19, 24, 29, 22, 16, 11, 6, 18, 24, 29, 24, 18, 13,
+ 8, 18, 23, 29, 27, 20, 14, 9, 18, 24, 30, 29, 22, 16, 11, 19, 23, 26, 31,
+ 30, 27, 24, 17, 22, 26, 29, 30, 27, 22, 16, 20, 23, 27, 28, 25, 21, 15, 17,
+ 21, 24, 27, 23, 17, 12, 15, 17, 20, 22, 20, 17, 8, 11, 13, 17, 21, 20, 16,
+ 6, 9, 13, 16, 19, 20, 17, 16, 20, 24, 28, 27, 25, 21, 15, 19, 22, 26, 27,
+ 23, 19, 14, 18, 21, 24, 23, 21, 17, 12, 15, 18, 20, 20, 18, 13, 9, 12, 14,
+ 17, 16, 16, 13, 6, 9, 12, 14, 14, 15, 12, 4, 7, 10, 13, 13, 14, 13, 14,
+ 18, 19, 20, 22, 20, 17, 12, 15, 19, 19, 20, 19, 14, 11, 15, 17, 16, 16, 17,
+ 12, 10, 13, 13, 13, 13, 13, 8, 6, 9, 10, 10, 9, 9, 8, 3, 6, 7, 7,
+ 8, 8, 8, 4, 5, 6, 6, 7, 7, 7, 11, 12, 12, 14, 15, 16, 12, 10, 10,
+ 11, 12, 13, 13, 10, 8, 9, 10, 9, 9, 9, 7, 4, 7, 6, 6, 6, 6, 5,
+ 2, 2, 2, 2, 2, 2, 3, 2, 4, 2, 1, 0, 1, 2, 4, 6, 3, 2, 2,
+ 1, 2, 6, 7, 8, 9, 10, 11, 12, 5, 6, 7, 9, 9, 9, 10, 5, 6, 7,
+ 6, 6, 7, 6, 5, 7, 6, 6, 6, 5, 3, 4, 9, 8, 7, 7, 5, 2, 5,
+ 9, 10, 9, 9, 7, 3, 6, 10, 12, 11, 10, 9, 4, 11, 13, 13, 13, 10, 10,
+ 11, 12, 15, 14, 14, 11, 8, 9, 11, 17, 16, 15, 11, 7, 5, 11, 16, 17, 16,
+ 12, 8, 3, 11, 16, 19, 18, 14, 9, 4, 11, 16, 22, 20, 15, 10, 6, 11, 16,
+ 22, 22, 17, 12, 7, 19, 25, 23, 17, 13, 9, 10, 19, 25, 25, 19, 14, 9, 7,
+ 20, 25, 27, 20, 15, 10, 5, 19, 24, 28, 22, 16, 11, 6, 18, 24, 28, 23, 17,
+ 12, 7, 18, 23, 27, 25, 20, 14, 9, 18, 23, 27, 28, 22, 16, 10, 18, 22, 26,
+ 29, 29, 26, 23, 16, 20, 24, 29, 29, 25, 21, 15, 19, 23, 25, 28, 23, 19, 14,
+ 16, 19, 23, 25, 22, 16, 10, 13, 16, 19, 23, 20, 16, 8, 11, 14, 17, 21, 20,
+ 17, 7, 10, 13, 16, 19, 20, 16, 15, 19, 23, 26, 26, 23, 19, 14, 17, 22, 25,
+ 25, 21, 18, 12, 16, 20, 22, 23, 20, 16, 11, 14, 16, 19, 19, 17, 13, 8, 11,
+ 13, 16, 16, 15, 13, 6, 9, 12, 14, 14, 14, 13, 5, 7, 11, 13, 13, 13, 13,
+ 13, 16, 18, 19, 21, 19, 15, 11, 15, 17, 18, 19, 17, 13, 10, 13, 16, 15, 16,
+ 15, 11, 9, 11, 12, 12, 12, 12, 8, 5, 8, 9, 9, 9, 9, 8, 3, 6, 7,
+ 8, 7, 7, 8, 5, 5, 6, 6, 7, 7, 7, 10, 10, 11, 12, 14, 14, 10, 9,
+ 9, 10, 11, 11, 11, 8, 7, 8, 8, 8, 8, 8, 6, 3, 5, 5, 5, 5, 5,
+ 4, 2, 1, 2, 2, 1, 2, 2, 3, 4, 3, 2, 1, 0, 1, 5, 7, 4, 3,
+ 2, 2, 2, 4, 4, 6, 7, 8, 9, 10, 5, 5, 5, 7, 7, 7, 8, 5, 6,
+ 6, 6, 5, 5, 5, 5, 8, 7, 6, 6, 5, 1, 5, 9, 8, 7, 8, 5, 2,
+ 6, 10, 11, 10, 9, 7, 3, 7, 10, 13, 11, 11, 9, 4, 12, 13, 12, 12, 10,
+ 8, 9, 12, 15, 14, 13, 11, 7, 7, 12, 17, 16, 13, 11, 6, 4, 13, 16, 16,
+ 14, 12, 7, 3, 11, 16, 18, 15, 13, 9, 4, 11, 16, 20, 18, 14, 10, 6, 12,
+ 16, 21, 20, 15, 12, 7, 18, 21, 19, 15, 12, 9, 8, 18, 21, 20, 16, 13, 9,
+ 5, 18, 21, 23, 16, 13, 9, 5, 18, 21, 23, 17, 14, 10, 6, 18, 20, 23, 20,
+ 15, 12, 8, 18, 20, 23, 21, 17, 13, 9, 18, 21, 23, 23, 18, 13, 10, 17, 20,
+ 24, 27, 27, 24, 21, 16, 19, 23, 26, 27, 23, 20, 14, 18, 21, 24, 26, 22, 18,
+ 13, 16, 18, 21, 24, 21, 17, 10, 12, 15, 18, 22, 20, 16, 8, 11, 14, 17, 21,
+ 20, 16, 7, 10, 13, 16, 20, 19, 17, 14, 17, 21, 24, 23, 21, 18, 13, 17, 20,
+ 23, 23, 20, 16, 11, 15, 19, 21, 20, 18, 14, 10, 13, 16, 19, 17, 16, 12, 7,
+ 11, 13, 15, 16, 15, 12, 6, 9, 12, 14, 15, 14, 12, 6, 8, 11, 13, 13, 13,
+ 12, 12, 15, 17, 17, 19, 17, 13, 10, 13, 16, 17, 17, 16, 11, 9, 12, 14, 14,
+ 14, 14, 10, 8, 10, 11, 11, 11, 11, 7, 5, 8, 9, 9, 8, 8, 7, 5, 7,
+ 8, 8, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 9, 9, 10, 11, 12, 13, 8,
+ 8, 8, 9, 9, 9, 10, 6, 6, 7, 7, 7, 6, 6, 4, 3, 4, 4, 3, 3,
+ 3, 3, 3, 3, 2, 2, 1, 1, 1, 5, 5, 4, 2, 2, 1, 0, 7, 7, 4,
+ 3, 2, 2, 2, 3, 3, 4, 5, 6, 8, 8, 4, 4, 4, 5, 5, 5, 6, 4,
+ 5, 4, 3, 3, 3, 3, 4, 6, 4, 3, 3, 3, 0, 5, 6, 5, 4, 4, 3,
+ 2, 6, 8, 9, 7, 6, 4, 2, 7, 10, 11, 8, 7, 5, 2, 6, 6, 6, 6,
+ 5, 7, 7, 6, 8, 7, 7, 5, 4, 5, 6, 9, 8, 7, 4, 2, 2, 6, 8,
+ 9, 8, 5, 3, 2, 7, 10, 13, 12, 9, 5, 2, 8, 12, 17, 15, 11, 7, 3,
+ 10, 14, 18, 17, 12, 8, 4, 11, 15, 14, 9, 6, 6, 6, 10, 15, 16, 10, 6,
+ 3, 3, 10, 15, 18, 11, 7, 3, 2, 10, 14, 18, 12, 8, 5, 3, 10, 15, 20,
+ 17, 12, 8, 4, 12, 17, 22, 20, 15, 10, 5, 14, 20, 23, 22, 17, 11, 7, 20,
+ 21, 23, 26, 26, 25, 23, 19, 21, 23, 25, 26, 23, 21, 18, 20, 21, 23, 23, 19,
+ 16, 18, 18, 19, 19, 20, 15, 11, 15, 15, 15, 14, 14, 14, 10, 11, 11, 8, 10,
+ 12, 14, 10, 5, 3, 5, 8, 11, 14, 10, 19, 20, 22, 23, 24, 23, 22, 18, 20,
+ 21, 24, 24, 21, 19, 18, 19, 21, 21, 20, 19, 16, 17, 17, 18, 18, 16, 13, 8,
+ 14, 14, 14, 13, 9, 9, 8, 9, 9, 7, 6, 8, 9, 9, 2, 2, 4, 5, 7,
+ 8, 8, 18, 20, 20, 21, 23, 23, 22, 17, 18, 20, 21, 22, 21, 19, 17, 18, 19,
+ 20, 19, 18, 16, 16, 17, 16, 16, 15, 12, 9, 11, 12, 12, 11, 7, 8, 8, 4,
+ 7, 6, 4, 6, 8, 8, 0, 2, 2, 4, 6, 6, 8, 17, 18, 19, 21, 23, 24,
+ 23, 16, 18, 20, 20, 21, 21, 20, 14, 18, 19, 19, 19, 18, 17, 10, 17, 16, 16,
+ 15, 12, 12, 7, 12, 11, 11, 6, 7, 8, 5, 5, 5, 3, 4, 5, 6, 0, 3,
+ 3, 3, 4, 5, 6, 15, 17, 19, 20, 22, 23, 23, 12, 16, 18, 19, 20, 20, 21,
+ 12, 16, 17, 17, 17, 17, 15, 12, 13, 13, 13, 12, 10, 7, 10, 9, 8, 8, 7,
+ 6, 6, 6, 7, 7, 6, 7, 7, 5, 4, 6, 8, 7, 7, 8, 6, 13, 14, 15,
+ 16, 19, 22, 23, 13, 14, 14, 16, 17, 18, 19, 13, 15, 15, 14, 14, 15, 14, 13,
+ 13, 13, 13, 12, 9, 6, 11, 12, 13, 12, 9, 8, 6, 8, 10, 13, 13, 10, 8,
+ 7, 7, 10, 13, 14, 11, 8, 7, 16, 19, 18, 16, 17, 20, 21, 16, 18, 19, 17,
+ 16, 17, 18, 16, 18, 20, 16, 14, 13, 13, 16, 17, 20, 15, 12, 10, 7, 14, 16,
+ 18, 16, 11, 8, 7, 12, 15, 17, 17, 12, 10, 8, 11, 15, 18, 18, 14, 10, 8,
+ 27, 30, 31, 32, 32, 31, 30, 26, 29, 31, 32, 32, 29, 27, 25, 28, 29, 30, 29,
+ 26, 23, 24, 26, 27, 27, 25, 21, 15, 21, 24, 23, 21, 18, 16, 15, 17, 19, 16,
+ 15, 17, 17, 15, 11, 11, 13, 15, 16, 16, 15, 25, 28, 30, 31, 30, 30, 29, 24,
+ 27, 30, 31, 30, 29, 26, 22, 26, 29, 28, 27, 25, 22, 22, 24, 25, 25, 23, 20,
+ 14, 18, 20, 22, 20, 15, 15, 14, 13, 16, 15, 14, 14, 14, 14, 7, 9, 12, 13,
+ 13, 14, 14, 23, 26, 27, 29, 30, 29, 26, 21, 25, 27, 29, 29, 27, 23, 20, 24,
+ 26, 26, 25, 24, 20, 18, 21, 22, 22, 21, 18, 14, 13, 17, 18, 17, 14, 14, 13,
+ 6, 13, 12, 10, 12, 12, 13, 3, 7, 8, 10, 11, 11, 13, 20, 21, 22, 24, 25,
+ 26, 25, 18, 20, 22, 23, 23, 22, 21, 15, 20, 20, 21, 20, 19, 18, 11, 19, 17,
+ 17, 16, 12, 13, 9, 14, 13, 11, 7, 8, 9, 6, 7, 6, 4, 6, 7, 7, 3,
+ 0, 3, 4, 5, 6, 8, 16, 19, 20, 21, 22, 24, 24, 12, 18, 20, 21, 21, 21,
+ 21, 12, 18, 18, 18, 18, 17, 16, 12, 14, 15, 14, 13, 10, 8, 10, 8, 9, 8,
+ 5, 4, 7, 6, 5, 5, 5, 5, 4, 6, 3, 3, 5, 5, 6, 5, 5, 13, 14,
+ 16, 17, 20, 22, 24, 13, 13, 14, 16, 18, 19, 20, 13, 13, 13, 14, 15, 16, 14,
+ 13, 12, 12, 12, 10, 9, 6, 10, 10, 11, 9, 7, 5, 5, 7, 8, 10, 9, 7,
+ 6, 4, 5, 7, 10, 10, 8, 7, 4, 14, 17, 16, 15, 18, 21, 22, 14, 16, 17,
+ 15, 16, 18, 18, 14, 17, 18, 14, 13, 13, 13, 14, 15, 17, 13, 11, 8, 4, 12,
+ 13, 15, 12, 8, 6, 5, 10, 12, 14, 13, 9, 7, 5, 8, 11, 14, 14, 10, 8,
+ 6, 25, 28, 31, 33, 33, 32, 29, 23, 27, 30, 32, 33, 30, 26, 21, 26, 29, 30,
+ 30, 27, 23, 21, 23, 26, 27, 28, 22, 17, 17, 20, 22, 23, 21, 19, 16, 13, 16,
+ 17, 17, 20, 19, 17, 8, 11, 14, 17, 19, 19, 16, 22, 25, 29, 31, 31, 29, 27,
+ 20, 25, 28, 30, 29, 28, 24, 19, 23, 26, 28, 27, 25, 21, 18, 21, 24, 25, 23,
+ 20, 15, 15, 17, 19, 20, 17, 16, 15, 11, 13, 15, 15, 15, 16, 15, 5, 9, 12,
+ 14, 15, 15, 15, 20, 23, 26, 27, 28, 26, 22, 18, 22, 24, 25, 26, 24, 20, 17,
+ 21, 23, 22, 22, 22, 17, 15, 18, 19, 19, 19, 17, 11, 9, 14, 15, 15, 12, 12,
+ 12, 3, 10, 11, 10, 10, 11, 11, 3, 6, 8, 8, 9, 9, 10, 17, 18, 18, 19,
+ 21, 22, 19, 14, 16, 17, 18, 19, 19, 16, 11, 15, 16, 16, 15, 15, 13, 8, 13,
+ 12, 12, 11, 10, 10, 6, 9, 8, 8, 5, 5, 6, 3, 3, 3, 2, 3, 4, 4,
+ 3, 3, 0, 2, 3, 4, 5, 12, 14, 15, 16, 17, 18, 19, 8, 13, 14, 15, 16,
+ 16, 16, 8, 12, 13, 13, 13, 13, 11, 8, 10, 10, 10, 9, 7, 4, 6, 6, 5,
+ 5, 6, 4, 4, 4, 6, 8, 8, 8, 6, 3, 2, 7, 10, 10, 10, 8, 3, 9,
+ 11, 11, 13, 15, 17, 18, 9, 12, 12, 13, 13, 15, 16, 9, 14, 14, 14, 11, 11,
+ 10, 9, 13, 15, 15, 11, 7, 3, 7, 12, 17, 17, 13, 8, 3, 7, 13, 19, 19,
+ 15, 10, 5, 8, 14, 20, 20, 17, 12, 6, 16, 22, 22, 16, 13, 16, 17, 16, 23,
+ 24, 18, 12, 13, 14, 17, 23, 26, 19, 13, 9, 10, 17, 22, 26, 20, 14, 9, 5,
+ 15, 21, 25, 23, 17, 12, 6, 15, 21, 25, 23, 18, 14, 8, 16, 21, 24, 24, 20,
+ 15, 10, 23, 26, 30, 33, 32, 30, 27, 21, 25, 29, 32, 32, 29, 26, 19, 24, 27,
+ 31, 31, 27, 22, 18, 21, 24, 27, 28, 24, 18, 15, 18, 20, 23, 23, 21, 18, 11,
+ 14, 17, 18, 22, 21, 18, 8, 11, 14, 17, 20, 21, 18, 19, 23, 27, 31, 29, 27,
+ 25, 18, 22, 26, 30, 29, 25, 22, 17, 20, 25, 26, 26, 24, 19, 16, 19, 22, 24,
+ 23, 20, 15, 13, 15, 18, 19, 18, 17, 14, 9, 11, 14, 16, 16, 16, 14, 5, 8,
+ 12, 15, 15, 15, 14, 17, 21, 23, 24, 26, 23, 20, 16, 19, 22, 23, 23, 21, 18,
+ 15, 18, 20, 20, 20, 20, 15, 13, 16, 16, 17, 17, 15, 10, 8, 12, 13, 13, 12,
+ 11, 10, 3, 8, 9, 9, 9, 10, 10, 3, 6, 7, 8, 8, 9, 8, 15, 15, 16,
+ 17, 19, 19, 15, 13, 14, 15, 16, 17, 17, 13, 10, 12, 13, 13, 13, 13, 10, 6,
+ 10, 9, 9, 9, 8, 8, 4, 6, 6, 6, 4, 3, 4, 2, 2, 2, 2, 2, 3,
+ 3, 3, 4, 2, 0, 2, 2, 3, 9, 10, 11, 12, 13, 15, 15, 6, 10, 11, 12,
+ 13, 13, 13, 6, 9, 9, 9, 10, 9, 9, 6, 7, 6, 6, 6, 5, 3, 4, 6,
+ 6, 6, 6, 4, 3, 2, 7, 9, 8, 8, 6, 2, 4, 8, 11, 10, 9, 8, 3,
+ 9, 11, 11, 12, 12, 14, 15, 9, 13, 13, 13, 11, 11, 11, 9, 15, 15, 14, 10,
+ 8, 8, 9, 14, 15, 15, 11, 6, 2, 8, 13, 18, 16, 12, 8, 3, 8, 14, 20,
+ 19, 14, 9, 5, 9, 14, 20, 21, 16, 11, 6, 17, 23, 22, 17, 11, 12, 13, 17,
+ 23, 24, 18, 12, 10, 10, 17, 23, 27, 19, 13, 8, 7, 17, 22, 27, 20, 15, 9,
+ 5, 16, 21, 27, 22, 16, 11, 6, 16, 22, 27, 25, 18, 13, 8, 16, 22, 27, 27,
+ 21, 15, 9, 20, 25, 28, 32, 32, 30, 27, 20, 23, 27, 31, 32, 27, 24, 17, 22,
+ 25, 29, 30, 26, 22, 17, 19, 22, 25, 28, 24, 18, 14, 16, 19, 21, 24, 22, 18,
+ 10, 12, 15, 18, 22, 21, 18, 8, 10, 14, 17, 20, 21, 18, 18, 22, 26, 29, 29,
+ 25, 22, 17, 20, 23, 27, 28, 24, 20, 15, 19, 23, 25, 25, 22, 19, 14, 17, 20,
+ 22, 22, 20, 14, 11, 14, 15, 18, 18, 17, 14, 7, 10, 13, 15, 16, 17, 14, 5,
+ 8, 12, 14, 15, 15, 14, 16, 19, 20, 22, 24, 22, 18, 14, 17, 20, 21, 22, 20,
+ 15, 13, 17, 18, 18, 19, 17, 13, 12, 15, 15, 14, 15, 14, 10, 8, 11, 11, 11,
+ 11, 10, 9, 3, 8, 9, 9, 9, 9, 9, 4, 6, 7, 7, 8, 8, 8, 13, 14,
+ 14, 15, 17, 18, 13, 12, 12, 13, 14, 14, 14, 11, 9, 11, 11, 11, 11, 11, 8,
+ 5, 9, 8, 7, 7, 7, 6, 3, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2,
+ 2, 2, 4, 5, 3, 2, 0, 1, 2, 7, 7, 8, 9, 11, 12, 12, 5, 7, 8,
+ 9, 9, 10, 10, 5, 6, 7, 7, 7, 7, 7, 5, 6, 5, 5, 5, 4, 2, 3,
+ 7, 6, 6, 6, 4, 2, 3, 8, 9, 8, 8, 6, 2, 4, 8, 11, 10, 10, 7,
+ 3, 10, 12, 12, 11, 9, 11, 12, 10, 14, 13, 13, 10, 8, 9, 10, 16, 15, 14,
+ 10, 6, 6, 10, 15, 16, 15, 11, 6, 2, 9, 14, 18, 17, 12, 8, 3, 9, 15,
+ 20, 19, 14, 9, 5, 10, 15, 20, 21, 16, 11, 6, 18, 24, 23, 16, 12, 10, 10,
+ 18, 23, 24, 18, 13, 8, 8, 18, 24, 26, 19, 13, 8, 5, 18, 23, 28, 21, 15,
+ 10, 4, 17, 22, 27, 23, 16, 11, 6, 17, 22, 27, 26, 18, 13, 8, 17, 22, 27,
+ 27, 21, 15, 9, 20, 24, 27, 31, 30, 28, 25, 18, 22, 25, 29, 30, 27, 23, 16,
+ 20, 24, 27, 28, 25, 21, 15, 18, 21, 24, 27, 23, 18, 12, 15, 17, 21, 24, 21,
+ 18, 9, 12, 15, 18, 22, 21, 18, 8, 11, 14, 17, 21, 21, 18, 17, 20, 24, 28,
+ 28, 25, 21, 15, 20, 23, 26, 27, 23, 19, 14, 17, 21, 24, 24, 21, 17, 13, 15,
+ 19, 20, 20, 19, 14, 10, 12, 15, 17, 17, 17, 14, 7, 10, 13, 15, 16, 16, 14,
+ 6, 9, 12, 15, 14, 14, 14, 14, 17, 20, 21, 22, 20, 16, 13, 16, 18, 19, 20,
+ 19, 14, 12, 15, 17, 17, 17, 16, 12, 11, 13, 13, 13, 14, 13, 9, 7, 9, 10,
+ 10, 10, 10, 9, 4, 8, 9, 9, 9, 9, 9, 5, 7, 7, 7, 8, 8, 8, 12,
+ 12, 13, 14, 15, 16, 11, 10, 11, 11, 12, 13, 13, 9, 9, 9, 10, 10, 9, 9,
+ 7, 5, 7, 6, 6, 6, 6, 5, 2, 3, 3, 3, 2, 3, 3, 3, 3, 2, 2,
+ 1, 1, 2, 5, 6, 4, 3, 1, 0, 1, 5, 5, 6, 8, 8, 10, 11, 4, 5,
+ 6, 7, 8, 8, 9, 4, 5, 5, 5, 5, 5, 5, 4, 6, 5, 5, 5, 3, 2,
+ 3, 8, 7, 6, 6, 4, 1, 4, 9, 10, 8, 8, 6, 2, 5, 9, 12, 10, 10,
+ 8, 3, 10, 12, 11, 11, 9, 9, 10, 10, 14, 13, 12, 10, 7, 7, 10, 16, 14,
+ 13, 10, 5, 4, 10, 15, 15, 14, 10, 6, 2, 10, 14, 17, 15, 12, 8, 3, 10,
+ 15, 19, 17, 13, 9, 5, 10, 15, 20, 19, 15, 11, 6, 17, 21, 19, 15, 11, 8,
+ 8, 17, 21, 20, 16, 12, 8, 6, 18, 21, 22, 16, 12, 8, 4, 17, 20, 22, 17,
+ 13, 9, 5, 17, 20, 23, 20, 15, 11, 6, 16, 20, 23, 21, 16, 13, 8, 16, 20,
+ 23, 23, 18, 13, 9, 19, 23, 26, 29, 30, 28, 24, 17, 21, 24, 29, 29, 26, 22,
+ 16, 20, 23, 27, 27, 24, 20, 14, 17, 20, 24, 26, 22, 18, 11, 14, 16, 20, 23,
+ 21, 18, 10, 13, 15, 19, 22, 21, 18, 8, 11, 15, 18, 21, 21, 18, 16, 20, 23,
+ 27, 26, 23, 20, 14, 19, 22, 26, 25, 22, 18, 13, 17, 20, 23, 23, 20, 16, 12,
+ 15, 17, 21, 20, 18, 14, 9, 12, 14, 17, 17, 17, 14, 8, 11, 13, 16, 16, 16,
+ 14, 6, 9, 12, 15, 15, 15, 14, 13, 17, 19, 20, 21, 19, 15, 12, 16, 18, 19,
+ 19, 18, 13, 11, 14, 16, 16, 16, 16, 11, 10, 12, 13, 12, 13, 13, 9, 6, 9,
+ 10, 10, 10, 10, 9, 5, 8, 9, 9, 9, 9, 9, 6, 7, 8, 8, 8, 8, 8,
+ 11, 11, 12, 13, 14, 15, 9, 9, 9, 10, 11, 12, 11, 7, 8, 8, 9, 9, 8,
+ 8, 6, 4, 6, 5, 5, 5, 5, 4, 3, 3, 3, 3, 3, 3, 2, 4, 4, 3,
+ 2, 2, 2, 2, 6, 8, 5, 3, 2, 1, 0, 2, 3, 5, 6, 7, 8, 9, 2,
+ 3, 4, 5, 6, 6, 7, 2, 3, 3, 3, 3, 4, 4, 2, 5, 3, 2, 2, 2,
+ 1, 3, 7, 5, 4, 4, 3, 0, 5, 8, 7, 5, 3, 3, 2, 7, 8, 8, 6,
+ 5, 3, 2, 6, 6, 5, 5, 6, 7, 9, 6, 8, 5, 5, 5, 5, 6, 6, 8,
+ 6, 5, 3, 3, 3, 6, 7, 7, 5, 4, 3, 1, 7, 9, 10, 8, 6, 3, 2,
+ 8, 10, 13, 11, 7, 4, 3, 9, 11, 14, 14, 9, 5, 3, 8, 11, 10, 6, 5,
+ 7, 7, 8, 11, 11, 7, 4, 4, 4, 8, 11, 13, 7, 4, 3, 2, 8, 11, 14,
+ 9, 6, 4, 3, 9, 11, 15, 13, 8, 5, 3, 9, 13, 18, 16, 11, 6, 3, 11,
+ 15, 18, 17, 12, 7, 4, 14, 17, 20, 24, 23, 22, 19, 13, 16, 19, 23, 23, 21,
+ 17, 12, 14, 17, 20, 21, 18, 16, 11, 13, 15, 17, 20, 18, 15, 11, 13, 14, 15,
+ 19, 17, 15, 9, 11, 13, 15, 17, 17, 15, 12, 12, 12, 14, 16, 17, 15, 12, 15,
+ 17, 20, 21, 19, 16, 11, 13, 16, 19, 21, 18, 14, 11, 13, 15, 17, 18, 16, 13,
+ 9, 12, 14, 15, 15, 14, 13, 9, 11, 13, 14, 14, 14, 13, 7, 10, 11, 13, 13,
+ 13, 13, 14, 14, 11, 12, 12, 12, 12, 10, 13, 14, 15, 16, 15, 12, 9, 12, 13,
+ 13, 15, 14, 11, 8, 11, 12, 12, 12, 13, 11, 7, 10, 11, 11, 12, 11, 11, 6,
+ 9, 11, 11, 11, 11, 11, 9, 10, 10, 9, 10, 11, 11, 15, 16, 12, 9, 9, 10,
+ 11, 8, 8, 9, 10, 10, 11, 4, 7, 7, 8, 8, 8, 9, 5, 6, 6, 6, 7,
+ 7, 7, 4, 4, 5, 5, 6, 6, 6, 4, 4, 4, 4, 5, 5, 5, 4, 9, 11,
+ 10, 8, 6, 3, 3, 15, 16, 12, 9, 7, 4, 2, 0, 1, 1, 2, 2, 2, 4,
+ 2, 2, 2, 2, 2, 1, 5, 2, 3, 3, 3, 4, 2, 4, 2, 6, 5, 6, 6,
+ 5, 2, 4, 9, 8, 7, 7, 7, 3, 9, 11, 11, 9, 9, 8, 4, 14, 14, 13,
+ 10, 9, 8, 6, 8, 8, 8, 8, 7, 2, 3, 8, 10, 9, 9, 7, 3, 2, 7,
+ 11, 10, 9, 8, 5, 0, 8, 10, 11, 10, 8, 7, 4, 8, 11, 14, 13, 11, 8,
+ 6, 10, 13, 17, 15, 12, 9, 7, 12, 15, 17, 16, 13, 10, 8, 12, 16, 14, 11,
+ 8, 6, 2, 12, 16, 16, 12, 9, 6, 2, 12, 16, 18, 12, 9, 7, 4, 12, 15,
+ 19, 14, 11, 8, 7, 12, 16, 19, 17, 13, 10, 7, 13, 17, 20, 19, 15, 11, 8,
+ 15, 18, 20, 21, 16, 12, 9, 15, 17, 19, 20, 21, 18, 17, 14, 16, 18, 20, 20,
+ 19, 17, 12, 15, 18, 19, 20, 18, 17, 11, 14, 17, 18, 20, 19, 17, 11, 14, 17,
+ 19, 21, 19, 17, 10, 14, 16, 18, 20, 19, 17, 13, 13, 15, 18, 20, 19, 17, 13,
+ 15, 18, 19, 18, 16, 14, 12, 15, 17, 19, 18, 16, 14, 11, 14, 16, 17, 17, 16,
+ 14, 9, 13, 16, 17, 17, 17, 15, 9, 12, 15, 17, 17, 17, 15, 8, 11, 14, 16,
+ 16, 16, 15, 16, 14, 13, 15, 15, 15, 15, 10, 14, 14, 15, 15, 13, 10, 9, 12,
+ 14, 14, 14, 13, 10, 8, 11, 12, 13, 13, 13, 10, 7, 11, 12, 12, 13, 13, 11,
+ 7, 10, 11, 12, 12, 12, 11, 10, 11, 10, 11, 11, 11, 11, 17, 17, 12, 10, 10,
+ 10, 10, 8, 8, 8, 9, 9, 9, 3, 7, 7, 7, 7, 8, 8, 3, 6, 6, 6,
+ 6, 6, 6, 4, 4, 5, 5, 6, 6, 6, 4, 6, 6, 5, 5, 5, 5, 4, 10,
+ 12, 10, 9, 6, 5, 3, 17, 19, 14, 10, 7, 5, 3, 1, 0, 1, 1, 2, 2,
+ 3, 2, 2, 1, 2, 2, 1, 3, 2, 3, 3, 3, 3, 1, 3, 2, 7, 6, 6,
+ 6, 5, 3, 5, 11, 10, 10, 11, 8, 3, 10, 14, 16, 15, 13, 10, 5, 16, 19,
+ 20, 16, 15, 12, 7, 9, 10, 10, 10, 7, 2, 2, 8, 12, 12, 11, 8, 3, 2,
+ 8, 14, 14, 14, 9, 5, 1, 8, 15, 17, 17, 13, 9, 5, 11, 17, 22, 21, 17,
+ 12, 7, 14, 20, 26, 25, 20, 15, 9, 18, 23, 27, 25, 21, 17, 11, 17, 22, 21,
+ 15, 10, 5, 1, 16, 22, 24, 17, 12, 6, 2, 16, 22, 25, 18, 13, 9, 4, 16,
+ 22, 27, 22, 17, 13, 9, 18, 24, 29, 26, 21, 17, 11, 20, 26, 30, 29, 23, 18,
+ 13, 23, 28, 30, 30, 25, 21, 15, 14, 17, 20, 22, 23, 20, 18, 13, 16, 19, 22,
+ 23, 20, 18, 12, 15, 18, 21, 23, 20, 18, 11, 14, 17, 21, 23, 22, 19, 12, 14,
+ 18, 20, 24, 23, 19, 11, 14, 17, 20, 23, 22, 19, 14, 14, 16, 19, 22, 21, 19,
+ 12, 15, 18, 21, 19, 17, 14, 11, 14, 18, 19, 19, 16, 14, 10, 13, 16, 19, 18,
+ 17, 15, 9, 13, 16, 18, 18, 18, 16, 10, 13, 15, 18, 18, 18, 15, 10, 11, 15,
+ 17, 18, 18, 16, 17, 16, 14, 16, 17, 16, 16, 10, 13, 15, 15, 15, 13, 9, 9,
+ 12, 13, 13, 14, 12, 9, 8, 11, 12, 12, 12, 13, 10, 8, 11, 12, 12, 12, 13,
+ 11, 7, 10, 12, 12, 12, 12, 11, 12, 12, 11, 11, 11, 11, 11, 19, 18, 14, 10,
+ 10, 10, 10, 8, 8, 8, 8, 8, 8, 2, 7, 7, 7, 7, 7, 7, 2, 6, 6,
+ 6, 6, 6, 6, 3, 4, 6, 6, 6, 6, 6, 4, 6, 7, 6, 6, 6, 5, 4,
+ 12, 13, 12, 10, 8, 6, 4, 19, 20, 15, 11, 8, 6, 5, 1, 1, 0, 1, 1,
+ 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 4, 3, 4, 4, 2, 3, 2, 7, 7,
+ 7, 7, 6, 4, 6, 12, 12, 11, 11, 9, 5, 11, 15, 17, 16, 14, 11, 6, 18,
+ 21, 20, 17, 16, 13, 7, 9, 11, 9, 9, 6, 2, 2, 9, 13, 11, 11, 7, 3,
+ 1, 9, 14, 14, 14, 10, 6, 2, 9, 16, 18, 17, 14, 10, 6, 12, 18, 23, 21,
+ 18, 13, 7, 15, 21, 28, 26, 20, 15, 9, 19, 25, 29, 27, 23, 17, 11, 16, 22,
+ 21, 15, 9, 5, 1, 17, 22, 23, 16, 11, 6, 2, 16, 22, 26, 19, 13, 9, 5,
+ 16, 23, 29, 23, 18, 14, 10, 18, 25, 31, 28, 22, 17, 11, 22, 28, 33, 33, 26,
+ 19, 13, 25, 30, 34, 34, 28, 21, 15, 14, 17, 21, 23, 24, 20, 18, 14, 16, 19,
+ 23, 24, 21, 18, 12, 15, 18, 22, 23, 22, 19, 11, 15, 18, 22, 25, 23, 20, 12,
+ 15, 18, 22, 26, 23, 20, 11, 14, 17, 21, 25, 23, 20, 16, 15, 17, 20, 23, 22,
+ 19, 12, 15, 18, 20, 20, 17, 14, 12, 14, 17, 20, 19, 17, 14, 10, 13, 17, 19,
+ 19, 18, 15, 9, 13, 17, 20, 19, 18, 16, 10, 13, 16, 18, 19, 19, 16, 11, 12,
+ 15, 18, 18, 18, 16, 18, 17, 15, 17, 17, 17, 16, 10, 13, 14, 15, 15, 12, 9,
+ 9, 12, 13, 13, 14, 12, 9, 9, 11, 13, 13, 13, 13, 10, 8, 11, 13, 13, 13,
+ 14, 11, 7, 10, 12, 12, 12, 12, 11, 13, 13, 13, 12, 12, 11, 11, 20, 19, 15,
+ 12, 10, 11, 10, 9, 8, 8, 8, 8, 8, 2, 8, 7, 7, 7, 7, 6, 2, 6,
+ 6, 6, 7, 6, 6, 3, 4, 6, 6, 6, 6, 6, 5, 6, 8, 8, 8, 8, 6,
+ 5, 13, 15, 13, 11, 9, 7, 5, 21, 21, 16, 12, 9, 7, 6, 2, 1, 1, 0,
+ 1, 1, 2, 3, 2, 2, 2, 2, 0, 2, 2, 4, 4, 4, 4, 3, 3, 2, 8,
+ 8, 8, 8, 7, 5, 7, 13, 12, 12, 13, 10, 6, 13, 17, 18, 17, 14, 12, 7,
+ 19, 22, 22, 19, 17, 14, 8, 9, 11, 9, 9, 6, 2, 2, 10, 12, 11, 11, 7,
+ 3, 2, 10, 15, 14, 14, 11, 6, 3, 9, 17, 18, 18, 15, 10, 7, 13, 19, 24,
+ 22, 18, 13, 8, 16, 22, 29, 27, 21, 16, 10, 21, 26, 30, 30, 25, 17, 12, 17,
+ 22, 20, 14, 9, 5, 1, 17, 22, 23, 16, 11, 6, 3, 17, 22, 25, 19, 14, 10,
+ 6, 17, 24, 29, 24, 18, 14, 10, 20, 26, 31, 29, 23, 18, 12, 23, 30, 35, 33,
+ 26, 19, 14, 25, 32, 35, 36, 28, 22, 16, 15, 18, 21, 24, 24, 21, 18, 14, 17,
+ 19, 23, 24, 22, 19, 12, 15, 19, 23, 25, 23, 20, 11, 16, 19, 22, 26, 24, 20,
+ 12, 16, 19, 23, 26, 24, 21, 12, 15, 18, 22, 26, 24, 21, 17, 17, 18, 20, 24,
+ 24, 21, 12, 16, 19, 22, 20, 17, 14, 12, 15, 18, 20, 20, 17, 15, 10, 14, 17,
+ 20, 20, 19, 16, 10, 14, 17, 20, 20, 19, 16, 10, 14, 17, 19, 20, 20, 17, 12,
+ 14, 16, 19, 19, 19, 17, 20, 18, 16, 18, 18, 18, 17, 10, 14, 15, 14, 15, 13,
+ 9, 10, 12, 13, 14, 14, 13, 10, 9, 12, 13, 14, 14, 14, 11, 9, 12, 14, 14,
+ 14, 14, 12, 8, 11, 13, 13, 13, 13, 12, 14, 14, 14, 13, 13, 12, 12, 22, 20,
+ 16, 12, 11, 11, 10, 9, 8, 8, 8, 8, 8, 2, 9, 7, 7, 7, 7, 7, 3,
+ 6, 6, 6, 7, 7, 7, 4, 6, 6, 7, 7, 7, 7, 6, 7, 8, 9, 9, 9,
+ 8, 6, 14, 16, 14, 12, 10, 8, 6, 22, 22, 17, 13, 10, 8, 7, 2, 2, 1,
+ 1, 0, 1, 2, 3, 2, 2, 2, 2, 1, 3, 3, 4, 4, 5, 5, 4, 3, 3,
+ 8, 8, 9, 9, 7, 6, 7, 14, 13, 13, 13, 11, 7, 14, 18, 19, 18, 15, 12,
+ 8, 20, 23, 23, 19, 18, 14, 9, 10, 10, 9, 8, 5, 2, 2, 10, 12, 10, 9,
+ 7, 4, 2, 10, 13, 12, 13, 10, 7, 4, 10, 15, 17, 16, 15, 11, 7, 13, 19,
+ 23, 21, 18, 14, 9, 17, 23, 28, 26, 20, 16, 11, 21, 27, 29, 28, 23, 18, 13,
+ 15, 17, 14, 10, 8, 4, 1, 15, 17, 15, 11, 9, 7, 3, 15, 17, 18, 15, 13,
+ 11, 7, 15, 19, 23, 20, 17, 15, 11, 18, 23, 27, 25, 22, 18, 13, 23, 27, 31,
+ 30, 24, 19, 15, 27, 30, 32, 32, 26, 21, 17, 13, 16, 20, 23, 23, 20, 17, 13,
+ 16, 18, 22, 23, 21, 19, 12, 14, 18, 22, 25, 22, 19, 11, 15, 19, 22, 26, 23,
+ 20, 12, 15, 18, 21, 25, 23, 20, 12, 15, 18, 21, 25, 23, 20, 18, 18, 17, 20,
+ 23, 23, 20, 12, 15, 17, 20, 18, 15, 13, 11, 14, 17, 19, 19, 17, 14, 10, 13,
+ 16, 19, 20, 17, 15, 9, 12, 16, 20, 19, 18, 16, 9, 13, 16, 19, 20, 19, 16,
+ 13, 14, 16, 18, 18, 18, 15, 21, 19, 17, 17, 17, 17, 16, 10, 13, 13, 13, 14,
+ 11, 8, 9, 12, 12, 12, 13, 12, 9, 8, 11, 12, 13, 13, 13, 10, 7, 11, 12,
+ 13, 13, 13, 11, 7, 11, 12, 13, 13, 13, 11, 15, 16, 15, 13, 12, 12, 11, 23,
+ 22, 17, 14, 11, 10, 10, 8, 7, 7, 7, 7, 7, 2, 7, 6, 6, 6, 6, 6,
+ 2, 4, 5, 5, 6, 6, 6, 4, 8, 5, 6, 6, 6, 7, 6, 8, 9, 10, 10,
+ 10, 9, 7, 15, 17, 16, 14, 11, 9, 8, 23, 24, 18, 15, 12, 10, 8, 2, 2,
+ 2, 1, 1, 0, 2, 4, 2, 2, 2, 2, 2, 2, 4, 3, 3, 4, 5, 5, 4,
+ 4, 7, 7, 8, 8, 8, 8, 8, 13, 13, 13, 13, 11, 8, 15, 19, 19, 17, 14,
+ 12, 9, 22, 24, 22, 18, 15, 13, 10, 6, 6, 4, 3, 3, 2, 1, 6, 7, 5,
+ 4, 3, 3, 2, 6, 9, 6, 7, 6, 6, 6, 6, 11, 12, 12, 11, 10, 9, 11,
+ 15, 19, 17, 15, 13, 10, 17, 21, 25, 22, 17, 13, 11, 22, 25, 26, 24, 19, 15,
+ 12, 10, 12, 8, 5, 3, 2, 2, 10, 12, 10, 6, 4, 4, 4, 10, 12, 13, 9,
+ 9, 8, 7, 10, 14, 18, 16, 13, 12, 10, 14, 18, 23, 22, 18, 15, 12, 19, 23,
+ 27, 27, 21, 16, 13, 24, 27, 28, 29, 23, 18, 13, 9, 11, 13, 15, 16, 13, 11,
+ 9, 11, 12, 15, 16, 14, 12, 8, 10, 12, 16, 18, 15, 13, 7, 10, 13, 16, 19,
+ 17, 15, 8, 11, 14, 17, 20, 17, 14, 11, 13, 15, 16, 19, 17, 14, 18, 18, 16,
+ 16, 18, 17, 15, 8, 10, 11, 14, 11, 9, 7, 7, 9, 11, 13, 12, 10, 8, 7,
+ 8, 11, 14, 13, 11, 10, 6, 9, 12, 14, 13, 12, 11, 6, 10, 12, 14, 14, 13,
+ 11, 13, 14, 15, 16, 14, 13, 11, 21, 19, 17, 15, 13, 12, 11, 7, 9, 8, 7,
+ 7, 5, 3, 6, 8, 8, 7, 7, 7, 5, 5, 7, 7, 8, 8, 8, 6, 3, 7,
+ 8, 9, 9, 9, 8, 7, 10, 10, 10, 10, 9, 8, 16, 16, 15, 13, 11, 9, 8,
+ 23, 22, 18, 14, 12, 10, 8, 5, 4, 3, 3, 3, 2, 0, 3, 2, 3, 2, 2,
+ 3, 2, 6, 2, 2, 3, 3, 3, 4, 10, 3, 5, 6, 6, 6, 6, 9, 10, 10,
+ 10, 10, 9, 7, 16, 18, 16, 14, 12, 10, 8, 23, 24, 19, 15, 12, 11, 9, 4,
+ 3, 2, 2, 2, 2, 0, 6, 4, 3, 2, 2, 3, 2, 6, 4, 4, 5, 5, 5,
+ 5, 6, 8, 8, 9, 10, 9, 8, 9, 15, 15, 15, 15, 12, 9, 15, 21, 21, 19,
+ 16, 14, 10, 22, 25, 25, 21, 18, 15, 11, 8, 7, 5, 5, 3, 2, 1, 8, 10,
+ 7, 6, 4, 4, 3, 8, 11, 10, 11, 9, 7, 6, 8, 13, 16, 16, 15, 12, 10,
+ 12, 19, 23, 22, 19, 16, 11, 18, 24, 30, 27, 22, 16, 13, 23, 28, 31, 30, 24,
+ 18, 14, 12, 16, 14, 8, 5, 3, 2, 13, 16, 16, 10, 6, 5, 4, 12, 16, 19,
+ 15, 12, 10, 8, 13, 18, 25, 21, 18, 15, 12, 17, 23, 29, 28, 23, 19, 14, 22,
+ 27, 33, 33, 26, 20, 16, 27, 32, 34, 34, 28, 23, 17, 16, 19, 23, 26, 26, 25,
+ 22, 15, 19, 22, 25, 26, 23, 21, 14, 17, 20, 23, 24, 22, 19, 13, 15, 17, 20,
+ 22, 20, 18, 12, 14, 16, 18, 21, 19, 18, 10, 12, 15, 17, 20, 20, 18, 10, 11,
+ 13, 16, 19, 20, 18, 14, 17, 20, 24, 24, 23, 18, 13, 16, 19, 22, 24, 22, 17,
+ 12, 14, 18, 20, 20, 18, 15, 11, 13, 15, 17, 18, 16, 14, 10, 12, 14, 15, 16,
+ 17, 14, 8, 11, 13, 14, 15, 15, 15, 11, 11, 12, 13, 14, 15, 14, 12, 14, 16,
+ 17, 19, 19, 14, 11, 13, 15, 16, 16, 17, 13, 10, 12, 14, 14, 15, 15, 12, 9,
+ 12, 12, 12, 12, 13, 12, 7, 10, 12, 12, 11, 12, 12, 8, 9, 10, 10, 11, 11,
+ 12, 12, 12, 10, 9, 10, 11, 12, 10, 10, 11, 11, 12, 14, 6, 8, 9, 9, 10,
+ 10, 11, 6, 7, 7, 8, 8, 9, 9, 5, 4, 6, 7, 7, 7, 7, 6, 5, 5,
+ 5, 6, 6, 7, 4, 8, 8, 7, 6, 5, 5, 4, 12, 12, 8, 6, 5, 4, 2,
+ 2, 2, 2, 2, 3, 4, 6, 0, 1, 1, 2, 1, 2, 5, 0, 2, 2, 1, 1,
+ 1, 4, 0, 2, 2, 1, 1, 1, 4, 2, 4, 3, 3, 4, 2, 2, 5, 7, 7,
+ 6, 5, 3, 2, 9, 10, 9, 7, 6, 4, 2, 4, 5, 5, 5, 3, 2, 4, 4,
+ 6, 6, 6, 3, 1, 3, 4, 7, 7, 6, 4, 1, 2, 4, 7, 8, 7, 5, 3,
+ 2, 4, 8, 10, 9, 7, 4, 2, 6, 10, 14, 11, 9, 6, 2, 9, 12, 14, 13,
+ 10, 6, 3, 9, 12, 11, 8, 5, 2, 2, 9, 12, 12, 8, 5, 2, 1, 9, 12,
+ 14, 9, 6, 3, 1, 9, 12, 15, 10, 7, 5, 2, 9, 12, 15, 13, 10, 7, 4,
+ 10, 13, 17, 16, 11, 8, 5, 12, 15, 16, 17, 13, 9, 6, 16, 19, 20, 22, 22,
+ 20, 18, 15, 18, 20, 21, 22, 20, 17, 14, 16, 18, 21, 22, 19, 18, 13, 15, 19,
+ 20, 22, 20, 18, 13, 16, 18, 20, 22, 21, 19, 11, 15, 18, 19, 21, 20, 18, 12,
+ 13, 17, 19, 20, 20, 18, 14, 17, 19, 21, 19, 18, 16, 13, 16, 18, 20, 19, 18,
+ 16, 12, 15, 17, 19, 18, 17, 16, 11, 14, 17, 18, 17, 18, 16, 11, 14, 17, 19,
+ 18, 18, 17, 9, 12, 15, 17, 18, 18, 16, 15, 14, 14, 16, 16, 17, 16, 12, 15,
+ 16, 16, 16, 15, 12, 11, 14, 15, 15, 15, 15, 12, 10, 13, 14, 14, 15, 15, 12,
+ 9, 12, 14, 13, 14, 14, 12, 8, 11, 13, 13, 13, 13, 12, 10, 10, 11, 12, 13,
+ 13, 12, 17, 16, 12, 10, 11, 11, 12, 10, 9, 10, 10, 10, 11, 4, 9, 8, 9,
+ 9, 9, 9, 4, 7, 7, 7, 8, 8, 8, 5, 5, 7, 7, 7, 7, 7, 6, 6,
+ 6, 6, 6, 6, 6, 5, 10, 11, 10, 9, 6, 5, 4, 17, 18, 13, 10, 7, 5,
+ 3, 2, 2, 2, 2, 2, 2, 4, 1, 0, 1, 1, 1, 2, 4, 1, 2, 2, 2,
+ 1, 0, 4, 1, 5, 5, 5, 5, 4, 3, 4, 9, 9, 9, 9, 7, 3, 9, 13,
+ 15, 14, 12, 9, 4, 16, 18, 18, 15, 14, 11, 5, 7, 9, 8, 9, 5, 1, 3,
+ 7, 11, 10, 10, 7, 2, 3, 7, 13, 13, 12, 8, 3, 2, 7, 13, 15, 15, 12,
+ 7, 4, 9, 16, 19, 18, 16, 11, 5, 12, 18, 22, 20, 17, 13, 7, 17, 21, 23,
+ 22, 18, 15, 9, 15, 20, 18, 14, 9, 4, 2, 15, 19, 20, 15, 11, 5, 1, 15,
+ 19, 21, 16, 12, 7, 3, 15, 20, 23, 19, 16, 12, 7, 16, 21, 24, 22, 18, 15,
+ 9, 18, 22, 25, 24, 20, 16, 12, 21, 23, 26, 25, 21, 18, 13, 16, 19, 21, 24,
+ 24, 22, 19, 15, 18, 20, 23, 25, 21, 19, 13, 17, 20, 23, 24, 21, 20, 13, 16,
+ 19, 22, 24, 22, 20, 13, 16, 19, 22, 25, 23, 20, 12, 15, 18, 21, 24, 23, 21,
+ 13, 14, 17, 20, 23, 24, 21, 13, 17, 20, 22, 21, 18, 16, 12, 16, 18, 21, 20,
+ 18, 15, 12, 14, 17, 20, 20, 18, 16, 10, 14, 17, 21, 19, 19, 17, 11, 14, 17,
+ 19, 20, 20, 17, 9, 13, 16, 18, 19, 19, 17, 16, 15, 15, 18, 17, 18, 17, 11,
+ 14, 16, 16, 16, 14, 11, 10, 13, 15, 15, 15, 14, 11, 10, 12, 14, 13, 14, 14,
+ 11, 9, 12, 14, 14, 14, 14, 12, 8, 11, 13, 13, 13, 13, 12, 11, 11, 12, 12,
+ 12, 12, 12, 18, 17, 13, 11, 11, 11, 11, 10, 9, 9, 9, 10, 9, 3, 9, 8,
+ 8, 8, 8, 8, 3, 8, 7, 7, 7, 7, 7, 3, 5, 7, 7, 7, 7, 7, 5,
+ 6, 6, 6, 6, 6, 6, 4, 11, 13, 11, 9, 7, 5, 4, 18, 20, 14, 10, 8,
+ 6, 4, 2, 1, 2, 2, 2, 2, 3, 1, 1, 0, 1, 1, 1, 3, 1, 2, 2,
+ 2, 2, 1, 3, 1, 6, 6, 6, 6, 5, 4, 5, 10, 10, 10, 10, 8, 4, 11,
+ 14, 16, 14, 12, 9, 5, 17, 19, 19, 16, 14, 12, 6, 7, 9, 8, 8, 5, 1,
+ 2, 7, 11, 10, 10, 6, 2, 2, 7, 13, 12, 12, 8, 4, 2, 8, 14, 16, 16,
+ 12, 8, 5, 10, 17, 21, 20, 16, 11, 6, 13, 20, 26, 25, 19, 13, 8, 17, 23,
+ 26, 27, 22, 16, 9, 15, 20, 19, 13, 8, 4, 1, 16, 21, 22, 15, 10, 5, 0,
+ 15, 20, 24, 17, 12, 8, 4, 15, 22, 27, 21, 16, 12, 8, 17, 24, 29, 27, 21,
+ 15, 10, 20, 26, 31, 32, 24, 18, 12, 23, 29, 33, 33, 26, 19, 14, 16, 19, 22,
+ 25, 25, 22, 20, 15, 18, 21, 25, 25, 22, 19, 13, 16, 20, 23, 26, 22, 21, 13,
+ 16, 19, 23, 26, 24, 21, 13, 16, 19, 22, 26, 25, 21, 12, 16, 19, 22, 25, 24,
+ 22, 15, 15, 17, 21, 25, 25, 21, 14, 16, 20, 22, 21, 19, 15, 13, 15, 19, 21,
+ 21, 19, 15, 12, 14, 17, 20, 21, 19, 17, 11, 15, 18, 21, 21, 20, 17, 12, 14,
+ 17, 20, 20, 21, 17, 11, 13, 16, 19, 20, 19, 17, 18, 16, 15, 18, 18, 18, 17,
+ 12, 14, 16, 16, 17, 14, 11, 11, 13, 15, 15, 15, 14, 10, 10, 12, 14, 15, 14,
+ 15, 11, 9, 13, 14, 14, 15, 15, 12, 9, 12, 13, 14, 14, 14, 12, 12, 13, 12,
+ 12, 12, 13, 12, 19, 18, 14, 11, 12, 12, 11, 10, 9, 9, 9, 9, 9, 2, 9,
+ 8, 8, 8, 8, 8, 2, 8, 7, 7, 8, 7, 8, 3, 5, 7, 7, 7, 7, 7,
+ 6, 7, 7, 7, 7, 7, 7, 4, 13, 14, 13, 11, 8, 6, 5, 19, 21, 16, 12,
+ 9, 7, 5, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 0, 1, 1, 3, 2, 2,
+ 2, 3, 3, 2, 3, 2, 6, 6, 6, 7, 5, 5, 6, 12, 11, 11, 11, 8, 5,
+ 12, 16, 17, 15, 13, 10, 6, 18, 21, 20, 17, 15, 12, 7, 8, 9, 8, 8, 5,
+ 1, 2, 8, 11, 10, 9, 6, 2, 2, 8, 13, 13, 13, 9, 5, 3, 8, 15, 17,
+ 17, 13, 9, 6, 11, 18, 22, 21, 17, 12, 7, 14, 20, 26, 26, 19, 14, 9, 19,
+ 24, 28, 28, 22, 16, 10, 15, 21, 19, 13, 8, 3, 1, 15, 20, 21, 15, 9, 5,
+ 1, 15, 21, 24, 18, 13, 9, 5, 15, 22, 28, 23, 17, 13, 9, 18, 24, 30, 27,
+ 21, 16, 11, 20, 27, 32, 32, 24, 18, 12, 24, 30, 34, 34, 27, 20, 14, 16, 19,
+ 23, 26, 26, 23, 20, 15, 18, 21, 25, 26, 23, 20, 14, 17, 20, 23, 25, 24, 22,
+ 13, 17, 20, 24, 26, 25, 22, 14, 17, 20, 24, 27, 25, 21, 12, 16, 18, 23, 27,
+ 25, 22, 16, 16, 18, 22, 25, 25, 22, 14, 17, 20, 23, 22, 19, 16, 13, 16, 19,
+ 22, 22, 18, 16, 12, 15, 18, 21, 20, 20, 17, 11, 15, 18, 22, 21, 20, 17, 12,
+ 15, 18, 20, 21, 21, 17, 11, 14, 17, 20, 20, 20, 18, 18, 17, 16, 19, 18, 19,
+ 17, 12, 15, 15, 16, 17, 15, 11, 11, 14, 15, 15, 15, 14, 11, 10, 13, 14, 15,
+ 15, 15, 12, 10, 13, 15, 15, 15, 15, 12, 9, 13, 14, 14, 14, 14, 12, 13, 14,
+ 14, 13, 13, 13, 12, 20, 19, 15, 12, 12, 12, 12, 10, 9, 9, 9, 10, 10, 3,
+ 9, 8, 8, 8, 8, 8, 3, 8, 8, 8, 8, 8, 8, 3, 5, 7, 8, 8, 8,
+ 8, 6, 7, 8, 8, 8, 8, 7, 4, 13, 15, 13, 11, 9, 7, 5, 20, 21, 16,
+ 12, 10, 8, 6, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, 2, 3, 1,
+ 2, 3, 3, 3, 2, 3, 1, 6, 7, 7, 7, 6, 5, 6, 11, 11, 11, 11, 8,
+ 6, 12, 17, 18, 16, 13, 10, 7, 19, 21, 21, 17, 16, 12, 7, 8, 9, 8, 7,
+ 4, 1, 2, 8, 11, 9, 8, 6, 2, 2, 8, 12, 11, 12, 9, 5, 3, 8, 14,
+ 16, 15, 13, 9, 6, 11, 17, 21, 20, 18, 13, 7, 15, 21, 27, 25, 19, 14, 9,
+ 20, 24, 28, 26, 21, 16, 11, 14, 16, 14, 10, 7, 3, 1, 13, 16, 15, 11, 9,
+ 5, 2, 14, 16, 18, 14, 12, 9, 5, 14, 18, 23, 19, 16, 12, 9, 17, 22, 25,
+ 24, 20, 16, 11, 21, 25, 29, 29, 23, 18, 13, 24, 29, 31, 30, 25, 19, 14, 15,
+ 18, 21, 26, 25, 22, 18, 14, 17, 20, 24, 25, 22, 19, 13, 16, 19, 23, 24, 23,
+ 19, 12, 15, 19, 23, 25, 23, 20, 13, 15, 19, 22, 26, 24, 21, 11, 14, 17, 21,
+ 25, 24, 20, 16, 15, 16, 20, 23, 23, 21, 13, 16, 18, 22, 21, 19, 15, 12, 15,
+ 17, 21, 21, 17, 14, 11, 14, 17, 20, 19, 18, 15, 10, 13, 17, 20, 20, 19, 16,
+ 10, 14, 16, 19, 19, 19, 16, 11, 13, 16, 18, 18, 18, 16, 18, 17, 16, 17, 16,
+ 17, 16, 11, 14, 15, 15, 16, 14, 10, 10, 12, 13, 13, 14, 13, 9, 9, 11, 13,
+ 14, 13, 13, 10, 8, 12, 13, 13, 13, 13, 11, 7, 11, 12, 12, 12, 13, 11, 14,
+ 14, 13, 12, 11, 11, 11, 20, 19, 15, 12, 10, 10, 10, 9, 8, 8, 8, 9, 9,
+ 3, 8, 7, 7, 7, 7, 7, 2, 6, 6, 6, 7, 6, 6, 2, 5, 6, 6, 6,
+ 6, 6, 5, 7, 8, 8, 8, 8, 7, 5, 14, 16, 13, 11, 9, 7, 5, 21, 22,
+ 16, 12, 10, 8, 6, 1, 1, 1, 0, 1, 2, 3, 2, 2, 1, 1, 2, 0, 2,
+ 2, 3, 3, 4, 3, 3, 3, 2, 6, 6, 6, 6, 6, 5, 7, 12, 11, 10, 10,
+ 8, 6, 13, 16, 17, 14, 11, 9, 7, 19, 21, 20, 15, 13, 10, 7, 6, 6, 4,
+ 3, 3, 2, 2, 6, 7, 5, 4, 3, 2, 2, 6, 9, 6, 6, 4, 4, 3, 6,
+ 10, 10, 9, 8, 7, 7, 9, 13, 16, 14, 13, 10, 8, 14, 19, 22, 19, 14, 11,
+ 9, 19, 22, 23, 21, 16, 12, 9, 10, 11, 8, 5, 3, 2, 1, 10, 12, 10, 5,
+ 4, 3, 2, 10, 12, 12, 8, 7, 5, 5, 10, 13, 16, 13, 10, 9, 8, 12, 15,
+ 20, 19, 15, 12, 9, 16, 20, 24, 24, 17, 13, 10, 20, 24, 25, 25, 19, 14, 11,
+ 9, 11, 14, 17, 17, 14, 11, 9, 11, 13, 16, 17, 13, 11, 8, 10, 12, 15, 17,
+ 15, 12, 8, 10, 13, 16, 18, 16, 14, 8, 11, 13, 16, 19, 16, 13, 10, 11, 13,
+ 15, 18, 17, 13, 16, 15, 14, 15, 17, 17, 13, 8, 10, 12, 14, 13, 11, 7, 8,
+ 9, 11, 13, 13, 9, 7, 7, 8, 11, 13, 12, 10, 8, 6, 9, 12, 14, 13, 12,
+ 9, 6, 9, 11, 13, 13, 12, 10, 12, 12, 13, 13, 12, 12, 10, 19, 17, 14, 13,
+ 11, 11, 10, 7, 9, 8, 8, 9, 7, 4, 6, 8, 8, 7, 7, 6, 4, 5, 8,
+ 7, 8, 7, 7, 5, 4, 7, 8, 8, 7, 7, 6, 7, 9, 9, 8, 8, 8, 6,
+ 14, 14, 13, 11, 9, 7, 6, 21, 19, 15, 12, 9, 7, 6, 5, 4, 3, 3, 3,
+ 4, 2, 3, 3, 3, 3, 2, 2, 0, 3, 2, 2, 3, 2, 2, 2, 7, 3, 4,
+ 5, 4, 4, 4, 8, 9, 9, 8, 8, 7, 5, 14, 16, 14, 12, 10, 8, 6, 21,
+ 22, 16, 13, 10, 9, 7, 5, 3, 2, 2, 3, 2, 2, 5, 4, 3, 2, 3, 2,
+ 0, 5, 5, 4, 4, 4, 4, 3, 5, 8, 8, 8, 8, 8, 6, 9, 14, 14, 13,
+ 13, 10, 7, 14, 18, 19, 18, 14, 11, 8, 20, 22, 23, 19, 16, 13, 9, 9, 9,
+ 7, 6, 4, 3, 2, 8, 10, 8, 7, 5, 3, 2, 9, 12, 11, 11, 9, 6, 4,
+ 9, 14, 16, 16, 13, 10, 8, 12, 18, 22, 20, 18, 14, 9, 16, 22, 28, 26, 20,
+ 15, 10, 21, 26, 29, 28, 22, 17, 12, 14, 18, 15, 10, 6, 3, 2, 13, 17, 18,
+ 12, 8, 5, 3, 13, 17, 20, 15, 12, 9, 6, 14, 19, 25, 21, 16, 14, 10, 18,
+ 23, 28, 26, 21, 17, 12, 21, 27, 32, 32, 25, 19, 14, 26, 30, 32, 33, 26, 21,
+ 15, 16, 19, 23, 26, 26, 25, 23, 15, 18, 21, 25, 26, 23, 21, 14, 17, 20, 23,
+ 24, 22, 19, 13, 15, 17, 20, 22, 20, 18, 12, 14, 15, 18, 21, 20, 18, 11, 12,
+ 14, 17, 20, 20, 17, 10, 11, 13, 16, 19, 20, 18, 13, 17, 21, 24, 24, 23, 18,
+ 13, 15, 19, 22, 24, 21, 17, 12, 14, 17, 20, 21, 18, 15, 10, 13, 15, 17, 17,
+ 17, 15, 10, 12, 14, 15, 15, 17, 14, 8, 11, 13, 15, 15, 15, 14, 11, 11, 12,
+ 14, 14, 15, 14, 12, 14, 16, 18, 19, 19, 15, 11, 13, 15, 16, 17, 17, 13, 10,
+ 13, 13, 15, 14, 15, 12, 9, 12, 12, 12, 13, 13, 12, 7, 10, 11, 11, 11, 12,
+ 12, 8, 9, 9, 10, 11, 11, 12, 12, 12, 10, 9, 10, 11, 12, 10, 10, 10, 11,
+ 13, 13, 6, 8, 9, 9, 10, 10, 10, 5, 7, 7, 8, 8, 9, 9, 5, 4, 6,
+ 6, 7, 7, 7, 6, 5, 5, 6, 6, 6, 7, 5, 8, 8, 7, 6, 5, 5, 4,
+ 12, 12, 8, 6, 5, 4, 2, 2, 2, 2, 3, 3, 4, 6, 0, 1, 1, 2, 1,
+ 2, 5, 0, 2, 2, 1, 1, 1, 5, 0, 2, 2, 1, 2, 1, 3, 2, 4, 4,
+ 3, 4, 2, 2, 5, 7, 7, 6, 5, 3, 2, 9, 10, 10, 7, 6, 4, 2, 4,
+ 5, 4, 5, 3, 2, 4, 4, 6, 6, 6, 3, 1, 3, 4, 7, 7, 6, 4, 1,
+ 2, 4, 7, 8, 7, 5, 3, 2, 4, 8, 10, 9, 7, 4, 2, 6, 10, 13, 12,
+ 9, 6, 2, 9, 12, 14, 13, 10, 7, 3, 9, 12, 11, 8, 5, 2, 2, 9, 12,
+ 13, 8, 5, 2, 1, 9, 13, 14, 9, 6, 3, 1, 9, 12, 15, 10, 7, 5, 2,
+ 9, 12, 15, 13, 10, 7, 3, 10, 14, 17, 16, 11, 8, 5, 12, 15, 17, 17, 13,
+ 9, 6, 18, 19, 22, 24, 24, 22, 19, 17, 20, 21, 24, 24, 22, 19, 15, 18, 20,
+ 22, 24, 22, 20, 15, 18, 20, 21, 23, 22, 19, 14, 17, 19, 21, 24, 22, 21, 13,
+ 16, 19, 21, 23, 22, 20, 12, 14, 17, 20, 22, 22, 20, 15, 18, 20, 23, 22, 20,
+ 17, 14, 17, 20, 22, 20, 19, 17, 13, 17, 19, 21, 21, 18, 18, 12, 16, 18, 20,
+ 19, 18, 17, 12, 15, 18, 19, 19, 20, 18, 11, 13, 17, 19, 18, 19, 17, 14, 13,
+ 15, 17, 18, 18, 18, 13, 17, 17, 18, 18, 17, 14, 12, 15, 16, 16, 17, 16, 13,
+ 11, 14, 16, 16, 16, 17, 14, 10, 13, 15, 15, 16, 16, 14, 9, 12, 14, 14, 15,
+ 15, 14, 9, 11, 12, 13, 13, 14, 14, 16, 16, 12, 12, 13, 13, 13, 11, 11, 12,
+ 12, 12, 13, 4, 10, 10, 11, 11, 11, 11, 5, 9, 9, 9, 9, 10, 10, 5, 5,
+ 8, 8, 8, 8, 9, 7, 6, 7, 7, 7, 8, 8, 5, 9, 10, 9, 8, 6, 6,
+ 5, 16, 18, 13, 9, 6, 5, 3, 3, 3, 4, 4, 4, 3, 4, 1, 2, 2, 2,
+ 2, 2, 5, 1, 0, 1, 1, 1, 2, 5, 1, 3, 3, 3, 4, 2, 5, 3, 8,
+ 8, 8, 8, 6, 3, 8, 13, 14, 12, 10, 8, 3, 15, 17, 16, 13, 11, 9, 4,
+ 6, 8, 8, 8, 4, 2, 4, 6, 10, 9, 9, 6, 1, 4, 6, 11, 11, 10, 7,
+ 2, 3, 6, 12, 12, 12, 10, 6, 4, 8, 13, 15, 14, 12, 9, 4, 11, 15, 18,
+ 16, 13, 11, 6, 15, 17, 19, 17, 14, 12, 8, 13, 16, 15, 12, 8, 2, 2, 13,
+ 16, 16, 12, 9, 4, 2, 13, 16, 18, 13, 10, 6, 1, 13, 16, 19, 14, 12, 10,
+ 6, 13, 16, 20, 17, 14, 12, 8, 15, 17, 21, 20, 15, 13, 10, 17, 19, 22, 21,
+ 17, 14, 11, 18, 21, 24, 26, 26, 24, 21, 17, 20, 23, 26, 26, 24, 21, 15, 19,
+ 22, 26, 25, 23, 22, 14, 17, 21, 24, 26, 24, 22, 14, 17, 21, 23, 26, 25, 22,
+ 13, 16, 20, 23, 26, 25, 21, 13, 15, 18, 21, 24, 24, 22, 15, 19, 21, 24, 23,
+ 21, 17, 15, 18, 21, 24, 23, 20, 17, 13, 17, 20, 22, 22, 20, 17, 12, 16, 19,
+ 22, 22, 20, 18, 12, 15, 18, 21, 21, 22, 18, 11, 14, 17, 20, 21, 20, 18, 15,
+ 14, 16, 19, 19, 19, 18, 13, 17, 18, 18, 19, 17, 13, 12, 15, 17, 17, 17, 17,
+ 13, 11, 14, 16, 16, 16, 16, 13, 10, 13, 15, 15, 16, 16, 13, 10, 13, 15, 15,
+ 15, 15, 14, 10, 11, 13, 13, 14, 14, 13, 16, 16, 12, 12, 13, 13, 13, 11, 11,
+ 11, 11, 12, 12, 4, 10, 10, 10, 11, 10, 11, 4, 8, 9, 9, 9, 9, 9, 5,
+ 6, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 4, 10, 11, 10, 8, 7,
+ 6, 4, 17, 18, 13, 9, 7, 5, 3, 3, 3, 3, 4, 4, 3, 4, 2, 2, 2,
+ 2, 2, 3, 4, 2, 1, 0, 0, 0, 2, 4, 2, 4, 3, 3, 4, 3, 4, 4,
+ 8, 8, 8, 8, 6, 3, 9, 13, 14, 12, 10, 7, 4, 15, 18, 18, 14, 12, 9,
+ 5, 5, 7, 7, 7, 3, 2, 3, 5, 9, 9, 8, 5, 1, 3, 5, 11, 11, 10,
+ 6, 2, 3, 6, 12, 14, 14, 10, 6, 4, 8, 14, 19, 18, 15, 9, 5, 11, 17,
+ 24, 23, 18, 11, 6, 16, 21, 25, 26, 20, 13, 7, 13, 19, 18, 12, 7, 2, 2,
+ 13, 19, 20, 14, 9, 3, 2, 13, 19, 23, 16, 11, 6, 2, 13, 20, 25, 19, 15,
+ 10, 6, 15, 21, 26, 25, 19, 14, 8, 17, 24, 29, 28, 21, 16, 10, 20, 26, 30,
+ 31, 24, 17, 11, 18, 22, 26, 29, 29, 26, 23, 17, 20, 25, 28, 29, 26, 22, 15,
+ 19, 23, 26, 28, 24, 22, 14, 17, 20, 24, 27, 25, 22, 14, 17, 20, 23, 27, 25,
+ 22, 13, 16, 20, 23, 26, 25, 22, 13, 14, 18, 22, 25, 25, 22, 15, 19, 23, 26,
+ 25, 22, 19, 14, 18, 22, 25, 24, 21, 18, 13, 16, 20, 23, 22, 20, 17, 13, 16,
+ 19, 21, 22, 21, 18, 12, 15, 18, 21, 21, 21, 18, 11, 14, 17, 20, 20, 21, 18,
+ 15, 14, 17, 19, 19, 19, 18, 13, 17, 19, 19, 21, 18, 14, 12, 15, 17, 19, 19,
+ 17, 13, 11, 14, 16, 16, 16, 16, 12, 10, 14, 15, 15, 15, 15, 12, 10, 13, 14,
+ 14, 14, 15, 13, 10, 11, 13, 13, 13, 13, 13, 17, 16, 12, 12, 12, 12, 12, 11,
+ 11, 12, 12, 13, 13, 5, 11, 10, 10, 11, 11, 11, 4, 9, 9, 9, 9, 8, 8,
+ 4, 5, 9, 8, 8, 8, 8, 6, 7, 7, 7, 7, 7, 7, 3, 10, 11, 10, 9,
+ 6, 6, 3, 17, 18, 13, 9, 7, 5, 3, 3, 3, 4, 4, 5, 4, 5, 1, 2,
+ 2, 3, 3, 4, 4, 1, 1, 0, 0, 0, 2, 3, 1, 4, 4, 3, 4, 3, 3,
+ 4, 8, 8, 8, 8, 5, 3, 10, 13, 14, 12, 10, 7, 4, 15, 18, 17, 14, 12,
+ 9, 4, 6, 7, 7, 7, 4, 3, 4, 6, 10, 8, 9, 6, 2, 3, 6, 11, 10,
+ 10, 6, 2, 2, 6, 12, 14, 13, 10, 6, 4, 9, 15, 18, 18, 14, 9, 4, 12,
+ 17, 24, 22, 17, 11, 6, 16, 21, 24, 25, 19, 13, 7, 14, 19, 18, 12, 7, 3,
+ 4, 13, 19, 20, 14, 8, 3, 2, 13, 19, 22, 15, 10, 6, 2, 14, 20, 25, 19,
+ 14, 10, 5, 15, 21, 27, 24, 19, 13, 8, 17, 24, 29, 29, 22, 15, 9, 21, 27,
+ 30, 30, 23, 17, 11, 18, 22, 26, 29, 30, 27, 23, 17, 21, 24, 28, 30, 26, 21,
+ 15, 19, 23, 26, 27, 24, 21, 14, 17, 21, 24, 27, 25, 22, 14, 17, 20, 23, 27,
+ 25, 22, 14, 16, 19, 23, 26, 25, 21, 13, 15, 18, 21, 25, 25, 22, 15, 19, 23,
+ 26, 26, 23, 20, 14, 18, 22, 25, 25, 22, 18, 13, 16, 20, 23, 23, 20, 17, 12,
+ 15, 19, 21, 22, 21, 17, 13, 15, 18, 21, 21, 20, 17, 11, 13, 17, 19, 20, 20,
+ 17, 15, 15, 15, 18, 18, 18, 18, 13, 16, 18, 19, 21, 19, 15, 12, 15, 18, 18,
+ 19, 17, 13, 12, 14, 16, 16, 15, 16, 11, 11, 14, 14, 15, 15, 15, 12, 10, 13,
+ 14, 14, 14, 14, 12, 10, 12, 13, 13, 13, 13, 12, 17, 16, 13, 12, 12, 12, 11,
+ 12, 11, 11, 12, 13, 13, 6, 11, 9, 10, 11, 11, 11, 4, 9, 9, 9, 8, 8,
+ 8, 4, 5, 9, 8, 8, 8, 8, 6, 7, 7, 7, 7, 7, 7, 3, 11, 12, 10,
+ 8, 6, 5, 3, 17, 18, 13, 10, 7, 5, 3, 4, 3, 4, 4, 5, 5, 5, 1,
+ 1, 2, 3, 3, 3, 4, 1, 1, 0, 0, 0, 1, 2, 1, 4, 4, 3, 4, 3,
+ 3, 5, 9, 8, 8, 8, 6, 3, 10, 14, 14, 12, 10, 7, 4, 15, 18, 17, 13,
+ 12, 9, 5, 6, 7, 7, 7, 4, 4, 5, 6, 9, 8, 8, 5, 2, 3, 6, 11,
+ 10, 9, 6, 2, 2, 6, 13, 13, 12, 10, 6, 4, 9, 15, 18, 17, 14, 9, 5,
+ 12, 18, 23, 21, 16, 11, 6, 16, 20, 24, 23, 18, 13, 7, 13, 15, 13, 10, 7,
+ 3, 4, 13, 16, 15, 11, 8, 3, 1, 12, 15, 17, 11, 9, 6, 2, 12, 17, 20,
+ 16, 13, 9, 6, 15, 19, 23, 21, 18, 13, 7, 18, 23, 26, 26, 20, 15, 9, 21,
+ 25, 28, 28, 22, 17, 11, 17, 20, 25, 28, 28, 25, 21, 16, 19, 23, 28, 28, 24,
+ 21, 14, 18, 21, 25, 27, 23, 20, 13, 16, 19, 22, 26, 23, 20, 13, 16, 19, 22,
+ 26, 24, 21, 12, 15, 18, 22, 25, 24, 21, 13, 14, 17, 21, 23, 24, 21, 14, 18,
+ 21, 25, 24, 22, 18, 13, 17, 20, 24, 23, 20, 16, 12, 16, 19, 22, 21, 19, 15,
+ 11, 14, 17, 20, 20, 19, 16, 12, 14, 17, 20, 19, 19, 16, 9, 12, 15, 18, 18,
+ 19, 16, 16, 14, 14, 17, 17, 17, 16, 12, 15, 17, 18, 19, 17, 13, 11, 14, 16,
+ 17, 17, 16, 11, 11, 13, 15, 14, 15, 14, 10, 10, 13, 13, 13, 13, 13, 11, 9,
+ 12, 12, 12, 12, 12, 11, 11, 12, 11, 11, 12, 11, 11, 17, 16, 12, 10, 10, 10,
+ 10, 10, 10, 10, 11, 12, 12, 6, 9, 8, 9, 9, 10, 10, 4, 8, 7, 7, 7,
+ 7, 7, 3, 5, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 6, 5, 2, 11, 12,
+ 10, 9, 7, 5, 3, 17, 17, 13, 10, 7, 5, 3, 2, 1, 2, 3, 4, 5, 5,
+ 1, 0, 1, 2, 2, 3, 3, 1, 2, 2, 2, 1, 0, 2, 1, 5, 4, 4, 4,
+ 3, 3, 5, 9, 8, 8, 8, 6, 3, 11, 14, 14, 11, 9, 7, 4, 16, 17, 17,
+ 13, 10, 8, 5, 5, 5, 4, 3, 3, 3, 5, 5, 7, 5, 4, 3, 2, 2, 5,
+ 7, 5, 4, 2, 2, 1, 5, 8, 8, 7, 6, 5, 4, 8, 11, 13, 11, 10, 8,
+ 5, 12, 15, 18, 16, 11, 8, 6, 16, 18, 19, 18, 13, 9, 7, 8, 9, 7, 5,
+ 3, 3, 3, 8, 9, 8, 6, 3, 2, 1, 8, 9, 10, 6, 4, 3, 2, 7, 10,
+ 13, 10, 8, 6, 6, 10, 13, 17, 16, 12, 9, 7, 13, 17, 20, 19, 14, 10, 8,
+ 17, 20, 21, 21, 16, 11, 8, 13, 16, 19, 22, 22, 20, 16, 12, 15, 18, 22, 22,
+ 19, 15, 11, 15, 18, 20, 21, 18, 15, 10, 12, 15, 18, 21, 19, 16, 9, 12, 15,
+ 18, 21, 20, 16, 8, 11, 14, 17, 21, 19, 16, 11, 11, 13, 16, 20, 19, 16, 11,
+ 14, 17, 20, 18, 17, 14, 10, 13, 16, 19, 18, 15, 12, 8, 12, 15, 17, 16, 14,
+ 12, 7, 10, 13, 16, 16, 14, 12, 7, 10, 12, 15, 15, 15, 12, 9, 10, 11, 14,
+ 14, 14, 12, 14, 12, 11, 13, 13, 13, 12, 8, 12, 13, 14, 15, 13, 10, 7, 10,
+ 13, 13, 13, 13, 8, 6, 9, 11, 11, 11, 10, 7, 5, 9, 9, 9, 9, 9, 7,
+ 6, 8, 9, 9, 9, 8, 7, 12, 11, 9, 8, 7, 7, 7, 15, 13, 10, 8, 7,
+ 6, 6, 6, 6, 7, 8, 9, 9, 5, 5, 4, 5, 6, 6, 7, 3, 3, 3, 4,
+ 4, 3, 3, 2, 2, 3, 3, 3, 2, 2, 2, 6, 7, 6, 5, 5, 4, 2, 12,
+ 12, 9, 8, 6, 5, 3, 15, 16, 11, 9, 7, 5, 4, 4, 3, 3, 2, 3, 4,
+ 5, 4, 4, 3, 3, 3, 3, 3, 4, 5, 4, 3, 2, 2, 0, 4, 8, 5, 5,
+ 4, 4, 3, 8, 12, 9, 9, 8, 6, 4, 11, 14, 14, 12, 10, 7, 5, 15, 17,
+ 17, 14, 12, 9, 5, 8, 7, 6, 5, 4, 4, 4, 7, 9, 6, 6, 4, 3, 2,
+ 8, 11, 8, 7, 5, 3, 2, 8, 11, 12, 11, 9, 6, 5, 10, 14, 17, 16, 13,
+ 9, 5, 13, 18, 22, 20, 15, 10, 7, 16, 20, 23, 22, 17, 12, 8, 12, 15, 13,
+ 9, 5, 4, 3, 11, 15, 16, 11, 6, 3, 2, 12, 15, 18, 12, 8, 5, 3, 12,
+ 16, 21, 16, 12, 9, 6, 14, 19, 24, 21, 16, 12, 8, 16, 21, 26, 26, 19, 13,
+ 9, 20, 24, 27, 27, 22, 15, 10, 15, 19, 23, 26, 26, 25, 22, 14, 18, 22, 25,
+ 25, 23, 21, 13, 17, 20, 23, 24, 21, 19, 13, 15, 18, 20, 22, 20, 18, 12, 14,
+ 16, 18, 21, 20, 18, 10, 12, 15, 17, 20, 20, 18, 10, 11, 13, 15, 19, 19, 18,
+ 14, 17, 20, 23, 24, 23, 19, 13, 16, 19, 22, 24, 21, 17, 12, 14, 17, 20, 20,
+ 19, 15, 11, 13, 16, 17, 17, 17, 15, 10, 12, 14, 16, 16, 17, 14, 8, 11, 12,
+ 14, 14, 15, 15, 11, 11, 12, 14, 14, 14, 14, 12, 14, 16, 17, 19, 19, 15, 11,
+ 13, 15, 16, 17, 17, 12, 10, 13, 14, 14, 14, 15, 12, 9, 12, 12, 12, 13, 13,
+ 12, 7, 10, 12, 12, 12, 12, 12, 8, 9, 9, 10, 11, 12, 12, 12, 13, 10, 9,
+ 10, 11, 11, 10, 10, 10, 11, 13, 14, 6, 8, 9, 9, 10, 10, 11, 5, 7, 8,
+ 8, 8, 9, 9, 5, 4, 6, 6, 7, 7, 7, 5, 5, 5, 6, 6, 6, 7, 5,
+ 8, 8, 7, 6, 5, 5, 4, 12, 12, 8, 6, 5, 4, 2, 2, 2, 2, 2, 3,
+ 4, 6, 0, 1, 1, 2, 1, 2, 5, 0, 1, 1, 1, 1, 1, 5, 0, 2, 2,
+ 1, 2, 1, 4, 2, 4, 4, 3, 4, 2, 2, 5, 7, 7, 6, 5, 3, 2, 9,
+ 10, 10, 7, 6, 4, 2, 4, 5, 4, 5, 3, 2, 5, 4, 6, 6, 5, 3, 1,
+ 3, 4, 7, 7, 6, 4, 1, 2, 4, 7, 8, 7, 5, 3, 2, 4, 8, 11, 9,
+ 7, 4, 2, 6, 10, 14, 12, 9, 6, 2, 9, 12, 14, 13, 10, 7, 3, 9, 12,
+ 11, 7, 5, 2, 2, 9, 12, 13, 8, 5, 2, 1, 9, 12, 14, 9, 6, 3, 1,
+ 9, 12, 15, 10, 7, 5, 2, 8, 12, 15, 13, 9, 7, 4, 10, 14, 17, 16, 11,
+ 8, 5, 12, 15, 17, 17, 13, 9, 6, 21, 24, 26, 29, 28, 27, 25, 21, 23, 26,
+ 28, 29, 26, 23, 19, 22, 25, 26, 27, 25, 23, 18, 21, 23, 26, 27, 24, 21, 16,
+ 19, 21, 23, 25, 23, 22, 15, 19, 21, 22, 24, 23, 21, 12, 15, 19, 22, 24, 23,
+ 22, 20, 23, 25, 27, 26, 24, 22, 18, 21, 24, 26, 26, 23, 21, 17, 20, 23, 25,
+ 23, 23, 20, 16, 18, 21, 23, 22, 21, 19, 14, 17, 19, 22, 21, 21, 19, 12, 15,
+ 18, 20, 21, 20, 19, 12, 12, 17, 19, 20, 19, 20, 17, 21, 22, 22, 22, 21, 18,
+ 15, 20, 21, 22, 21, 20, 17, 14, 18, 20, 20, 20, 20, 17, 12, 16, 17, 17, 18,
+ 18, 16, 11, 14, 16, 16, 17, 17, 16, 8, 12, 14, 14, 16, 16, 16, 13, 13, 11,
+ 13, 15, 15, 15, 14, 15, 16, 16, 17, 17, 8, 13, 13, 14, 15, 15, 15, 8, 10,
+ 12, 13, 13, 13, 14, 8, 7, 10, 10, 10, 10, 11, 9, 7, 8, 9, 9, 9, 10,
+ 6, 8, 8, 7, 7, 7, 8, 6, 13, 14, 10, 7, 6, 6, 5, 6, 6, 7, 8,
+ 8, 6, 8, 2, 5, 6, 6, 6, 6, 8, 2, 3, 4, 4, 4, 5, 9, 2, 0,
+ 0, 0, 0, 2, 6, 3, 5, 4, 5, 5, 3, 5, 5, 9, 9, 8, 6, 4, 3,
+ 11, 12, 11, 8, 6, 5, 2, 4, 6, 6, 6, 3, 5, 7, 4, 7, 7, 7, 4,
+ 5, 6, 4, 8, 8, 8, 6, 3, 6, 4, 8, 8, 7, 5, 3, 3, 4, 8, 9,
+ 8, 7, 5, 2, 7, 9, 12, 11, 8, 6, 3, 11, 12, 13, 12, 9, 6, 4, 9,
+ 12, 11, 9, 6, 3, 6, 9, 12, 13, 9, 7, 3, 5, 9, 13, 15, 10, 7, 4,
+ 3, 10, 12, 15, 9, 7, 6, 3, 8, 11, 14, 12, 8, 6, 5, 9, 13, 15, 14,
+ 10, 7, 6, 11, 14, 16, 16, 12, 8, 6, 22, 26, 28, 31, 31, 29, 26, 21, 24,
+ 28, 31, 31, 28, 25, 19, 23, 26, 29, 29, 27, 23, 18, 20, 24, 27, 29, 26, 22,
+ 15, 18, 21, 24, 27, 25, 22, 14, 16, 20, 23, 27, 25, 22, 12, 15, 18, 22, 25,
+ 25, 22, 19, 23, 26, 30, 27, 26, 22, 18, 21, 25, 28, 28, 24, 22, 16, 20, 24,
+ 27, 25, 24, 20, 15, 18, 21, 23, 23, 21, 19, 13, 16, 19, 22, 22, 21, 19, 11,
+ 15, 17, 21, 21, 21, 19, 12, 12, 16, 19, 20, 20, 19, 16, 20, 22, 23, 24, 22,
+ 18, 15, 18, 21, 22, 22, 21, 17, 14, 17, 20, 20, 20, 20, 15, 13, 15, 16, 16,
+ 17, 17, 14, 10, 13, 15, 15, 15, 16, 14, 8, 12, 13, 14, 14, 14, 14, 13, 13,
+ 12, 12, 13, 13, 13, 13, 14, 15, 16, 17, 17, 9, 12, 13, 14, 15, 15, 15, 8,
+ 9, 11, 12, 13, 12, 13, 8, 6, 9, 9, 9, 9, 9, 7, 6, 8, 8, 8, 8,
+ 8, 4, 8, 8, 7, 6, 6, 7, 4, 13, 15, 10, 7, 5, 5, 3, 5, 6, 7,
+ 8, 8, 7, 8, 2, 5, 5, 6, 7, 6, 8, 2, 3, 3, 4, 4, 4, 5, 2,
+ 0, 0, 0, 0, 2, 4, 3, 5, 5, 4, 5, 3, 3, 6, 10, 11, 9, 7, 4,
+ 2, 12, 15, 14, 11, 9, 6, 2, 4, 6, 7, 7, 4, 6, 7, 4, 8, 8, 9,
+ 5, 5, 6, 4, 10, 10, 10, 6, 2, 4, 4, 10, 11, 11, 7, 3, 2, 5, 11,
+ 15, 15, 12, 6, 2, 8, 14, 20, 19, 14, 8, 3, 13, 17, 21, 21, 16, 10, 4,
+ 12, 19, 18, 12, 7, 5, 6, 13, 19, 21, 14, 8, 3, 5, 13, 19, 23, 15, 10,
+ 4, 2, 13, 18, 23, 17, 11, 7, 3, 12, 18, 23, 21, 16, 10, 4, 14, 20, 25,
+ 24, 19, 12, 6, 17, 23, 25, 25, 20, 14, 8, 22, 26, 29, 32, 33, 30, 26, 20,
+ 24, 28, 33, 33, 29, 26, 19, 23, 27, 30, 31, 28, 23, 18, 20, 24, 27, 30, 26,
+ 23, 15, 18, 21, 24, 28, 26, 23, 14, 17, 19, 23, 27, 26, 22, 12, 15, 18, 22,
+ 26, 25, 22, 19, 23, 27, 29, 29, 27, 23, 18, 21, 26, 29, 29, 25, 22, 16, 20,
+ 24, 27, 26, 24, 20, 15, 18, 21, 24, 23, 22, 19, 13, 16, 19, 21, 22, 21, 19,
+ 12, 15, 18, 20, 21, 21, 18, 12, 12, 17, 19, 20, 19, 19, 16, 20, 22, 23, 24,
+ 22, 19, 15, 18, 20, 22, 23, 22, 17, 13, 17, 19, 19, 20, 19, 15, 13, 15, 15,
+ 16, 16, 17, 13, 10, 13, 15, 15, 14, 15, 13, 8, 12, 13, 14, 14, 13, 13, 13,
+ 13, 12, 12, 13, 13, 12, 14, 14, 15, 16, 17, 18, 10, 13, 13, 14, 15, 15, 15,
+ 8, 10, 11, 12, 12, 12, 12, 7, 6, 10, 9, 9, 9, 9, 7, 6, 8, 8, 8,
+ 7, 7, 4, 8, 8, 7, 6, 6, 6, 3, 13, 14, 9, 6, 5, 5, 2, 6, 6,
+ 7, 8, 9, 8, 9, 1, 5, 6, 6, 7, 6, 8, 1, 3, 3, 3, 4, 4, 5,
+ 1, 0, 0, 0, 0, 2, 3, 3, 5, 4, 4, 4, 2, 2, 6, 10, 11, 9, 6,
+ 3, 2, 12, 15, 14, 10, 9, 5, 2, 4, 6, 7, 7, 5, 7, 8, 4, 8, 8,
+ 8, 5, 5, 6, 4, 10, 10, 9, 5, 2, 3, 4, 9, 11, 10, 6, 2, 2, 5,
+ 11, 15, 14, 11, 5, 2, 8, 14, 20, 18, 13, 7, 2, 12, 17, 21, 21, 15, 10,
+ 4, 13, 19, 17, 12, 7, 5, 7, 13, 18, 20, 13, 8, 3, 4, 13, 19, 21, 14,
+ 9, 4, 1, 13, 17, 22, 16, 10, 6, 2, 12, 17, 24, 21, 15, 9, 4, 14, 20,
+ 25, 25, 18, 11, 6, 17, 22, 26, 26, 20, 14, 8, 22, 26, 30, 34, 33, 30, 28,
+ 21, 24, 29, 33, 33, 30, 26, 19, 23, 27, 31, 32, 28, 24, 18, 20, 24, 28, 30,
+ 27, 23, 15, 18, 21, 25, 29, 26, 23, 14, 17, 20, 23, 27, 27, 23, 12, 15, 19,
+ 23, 26, 26, 22, 19, 23, 28, 30, 29, 26, 24, 18, 21, 25, 29, 30, 26, 22, 17,
+ 20, 24, 27, 27, 23, 20, 15, 18, 21, 23, 24, 22, 18, 14, 16, 19, 22, 22, 22,
+ 18, 12, 15, 17, 20, 20, 21, 19, 12, 13, 17, 20, 19, 20, 18, 17, 20, 22, 23,
+ 24, 23, 18, 15, 19, 21, 22, 23, 21, 17, 15, 17, 20, 19, 20, 19, 15, 13, 16,
+ 16, 17, 17, 16, 13, 10, 14, 15, 15, 15, 15, 13, 9, 12, 14, 14, 14, 14, 13,
+ 12, 12, 12, 12, 13, 13, 12, 15, 15, 15, 16, 17, 18, 10, 13, 13, 14, 15, 15,
+ 15, 8, 10, 12, 12, 12, 12, 12, 7, 6, 10, 9, 9, 9, 9, 7, 6, 8, 8,
+ 8, 7, 8, 4, 8, 8, 7, 7, 6, 6, 3, 12, 12, 9, 6, 5, 5, 2, 6,
+ 6, 7, 8, 9, 8, 10, 2, 5, 6, 7, 7, 6, 8, 1, 4, 4, 4, 4, 4,
+ 4, 1, 0, 0, 0, 0, 1, 3, 3, 5, 4, 4, 4, 2, 2, 6, 10, 10, 8,
+ 6, 3, 2, 11, 13, 13, 10, 8, 5, 1, 5, 7, 7, 7, 5, 7, 8, 5, 9,
+ 8, 8, 5, 5, 6, 5, 10, 9, 8, 5, 2, 3, 5, 10, 10, 9, 6, 2, 2,
+ 5, 11, 14, 13, 10, 5, 1, 8, 14, 19, 17, 12, 7, 2, 12, 16, 20, 20, 14,
+ 9, 3, 12, 15, 13, 10, 6, 6, 7, 12, 15, 15, 11, 7, 4, 4, 12, 15, 16,
+ 11, 8, 3, 2, 12, 15, 17, 13, 10, 6, 2, 11, 16, 19, 17, 14, 9, 4, 14,
+ 19, 23, 23, 16, 11, 5, 16, 21, 24, 23, 19, 13, 7, 21, 24, 28, 32, 33, 29,
+ 25, 19, 23, 27, 31, 32, 28, 25, 18, 21, 25, 29, 30, 27, 23, 17, 20, 22, 25,
+ 28, 25, 21, 14, 17, 20, 23, 27, 24, 21, 13, 16, 18, 22, 26, 25, 21, 11, 14,
+ 17, 21, 24, 24, 21, 17, 22, 25, 29, 28, 26, 23, 17, 20, 24, 28, 28, 24, 20,
+ 15, 19, 22, 26, 26, 23, 18, 14, 16, 20, 22, 22, 21, 17, 12, 15, 18, 20, 20,
+ 20, 17, 10, 13, 16, 19, 19, 19, 17, 10, 12, 15, 18, 18, 18, 17, 16, 19, 21,
+ 21, 24, 21, 17, 14, 17, 20, 21, 21, 20, 15, 13, 16, 18, 18, 18, 18, 14, 12,
+ 14, 15, 15, 15, 15, 11, 10, 13, 14, 13, 13, 13, 12, 8, 11, 12, 12, 12, 12,
+ 11, 10, 10, 10, 11, 11, 11, 11, 13, 13, 14, 15, 16, 17, 9, 11, 12, 13, 14,
+ 14, 14, 7, 9, 11, 10, 11, 10, 10, 6, 5, 9, 8, 7, 7, 7, 6, 5, 6,
+ 6, 6, 6, 6, 3, 8, 7, 6, 5, 4, 5, 3, 10, 10, 7, 5, 4, 3, 2,
+ 5, 5, 6, 7, 8, 8, 9, 1, 4, 5, 5, 6, 6, 7, 1, 2, 3, 3, 3,
+ 3, 4, 1, 2, 2, 2, 1, 0, 2, 2, 6, 5, 4, 4, 2, 2, 6, 9, 9,
+ 7, 5, 3, 1, 9, 11, 10, 7, 6, 4, 2, 5, 4, 4, 4, 5, 7, 8, 5,
+ 6, 4, 4, 4, 4, 6, 5, 8, 5, 4, 2, 2, 3, 5, 7, 7, 4, 3, 2,
+ 1, 5, 8, 10, 8, 6, 4, 2, 8, 11, 13, 10, 7, 5, 3, 10, 12, 13, 12,
+ 8, 6, 3, 9, 11, 8, 5, 5, 6, 6, 9, 11, 9, 5, 4, 4, 4, 9, 11,
+ 11, 6, 4, 2, 1, 8, 11, 11, 7, 5, 3, 2, 8, 10, 13, 11, 8, 5, 4,
+ 10, 13, 15, 14, 9, 7, 4, 11, 14, 15, 15, 11, 7, 5, 17, 21, 24, 28, 27,
+ 25, 22, 16, 20, 24, 27, 27, 23, 20, 14, 18, 21, 24, 26, 23, 18, 13, 16, 19,
+ 22, 25, 20, 17, 10, 13, 15, 19, 22, 20, 17, 9, 11, 14, 18, 22, 21, 17, 7,
+ 10, 14, 16, 20, 20, 17, 14, 18, 21, 25, 24, 22, 18, 13, 17, 21, 24, 23, 20,
+ 16, 12, 15, 20, 21, 21, 19, 14, 11, 13, 16, 19, 18, 17, 13, 8, 11, 13, 16,
+ 16, 16, 13, 7, 9, 12, 15, 15, 15, 12, 6, 8, 12, 14, 13, 14, 13, 12, 16,
+ 17, 18, 19, 18, 14, 10, 14, 16, 17, 17, 16, 12, 9, 13, 15, 14, 14, 14, 10,
+ 9, 11, 11, 11, 11, 11, 8, 5, 8, 9, 9, 9, 9, 8, 5, 7, 8, 8, 8,
+ 8, 8, 6, 6, 7, 6, 7, 7, 6, 10, 10, 10, 11, 12, 13, 9, 8, 8, 9,
+ 10, 10, 10, 6, 6, 7, 7, 7, 7, 7, 4, 3, 4, 4, 3, 4, 4, 3, 3,
+ 3, 2, 2, 2, 2, 2, 5, 5, 3, 3, 2, 1, 0, 6, 7, 4, 3, 2, 2,
+ 1, 2, 3, 4, 5, 6, 8, 8, 4, 3, 4, 5, 5, 5, 6, 4, 5, 4, 3,
+ 3, 3, 3, 4, 6, 4, 3, 3, 2, 0, 4, 6, 5, 4, 4, 2, 1, 6, 7,
+ 8, 7, 5, 3, 2, 7, 9, 11, 8, 7, 5, 2, 7, 6, 5, 5, 5, 7, 7,
+ 7, 8, 6, 6, 4, 4, 5, 7, 8, 7, 7, 4, 2, 2, 7, 8, 8, 8, 5,
+ 3, 2, 6, 9, 12, 11, 8, 5, 2, 7, 11, 16, 15, 10, 6, 3, 9, 13, 17,
+ 17, 12, 7, 3, 10, 14, 13, 8, 5, 6, 6, 10, 14, 15, 10, 6, 3, 3, 10,
+ 14, 17, 10, 6, 3, 2, 10, 13, 17, 12, 8, 5, 2, 10, 14, 19, 16, 11, 8,
+ 4, 12, 16, 21, 20, 14, 9, 5, 14, 18, 22, 22, 16, 11, 6, 19, 22, 24, 28,
+ 28, 25, 22, 18, 21, 23, 26, 28, 25, 22, 17, 20, 22, 24, 26, 23, 20, 16, 18,
+ 20, 22, 24, 21, 17, 13, 15, 17, 18, 21, 19, 16, 11, 12, 14, 16, 19, 18, 16,
+ 8, 10, 12, 15, 17, 18, 16, 17, 20, 23, 25, 25, 23, 20, 17, 19, 22, 24, 24,
+ 22, 19, 15, 18, 21, 22, 22, 20, 18, 14, 16, 18, 19, 19, 18, 14, 10, 13, 14,
+ 15, 15, 15, 14, 8, 10, 12, 14, 14, 15, 14, 9, 9, 11, 12, 13, 13, 14, 15,
+ 18, 19, 20, 20, 20, 16, 13, 17, 18, 19, 19, 18, 16, 12, 16, 17, 17, 17, 17,
+ 15, 11, 14, 15, 15, 15, 15, 13, 7, 10, 12, 11, 12, 12, 13, 5, 8, 9, 10,
+ 11, 12, 12, 10, 10, 8, 8, 10, 11, 11, 12, 14, 14, 15, 15, 16, 9, 11, 12,
+ 13, 13, 13, 14, 9, 9, 10, 11, 11, 12, 12, 9, 6, 8, 8, 9, 9, 9, 7,
+ 4, 5, 5, 5, 6, 6, 6, 5, 6, 5, 4, 4, 5, 5, 10, 10, 6, 4, 3,
+ 3, 3, 4, 5, 6, 7, 7, 8, 9, 2, 4, 5, 6, 6, 7, 9, 2, 3, 4,
+ 4, 4, 5, 8, 2, 3, 3, 3, 3, 2, 4, 0, 3, 2, 2, 2, 1, 3, 3,
+ 4, 5, 4, 3, 1, 1, 7, 7, 7, 5, 4, 3, 1, 5, 6, 6, 7, 5, 6,
+ 8, 5, 7, 7, 7, 5, 5, 7, 5, 8, 8, 8, 6, 4, 6, 5, 7, 8, 7,
+ 5, 2, 1, 3, 6, 9, 8, 5, 2, 1, 4, 8, 11, 10, 7, 4, 1, 6, 10,
+ 12, 11, 8, 5, 2, 10, 13, 13, 9, 6, 5, 6, 10, 14, 14, 10, 7, 5, 6,
+ 10, 14, 15, 10, 7, 5, 3, 10, 13, 15, 10, 7, 4, 1, 9, 11, 14, 12, 8,
+ 5, 2, 8, 12, 15, 14, 9, 6, 3, 10, 13, 15, 15, 11, 7, 4, 27, 29, 32,
+ 35, 35, 32, 30, 25, 29, 31, 34, 34, 31, 28, 25, 27, 31, 32, 33, 30, 26, 22,
+ 26, 28, 30, 32, 28, 24, 20, 23, 25, 26, 28, 26, 23, 16, 19, 21, 24, 26, 25,
+ 23, 13, 17, 21, 23, 26, 26, 23, 24, 28, 31, 33, 32, 29, 28, 23, 26, 29, 32,
+ 32, 29, 26, 21, 25, 28, 30, 30, 28, 25, 20, 23, 26, 28, 26, 25, 21, 16, 20,
+ 22, 24, 24, 22, 21, 14, 17, 20, 21, 22, 22, 21, 10, 13, 18, 21, 21, 21, 21,
+ 21, 25, 28, 28, 28, 27, 24, 20, 24, 26, 27, 27, 27, 23, 18, 22, 24, 25, 26,
+ 25, 22, 16, 20, 21, 22, 22, 23, 18, 11, 16, 17, 18, 18, 18, 18, 7, 13, 16,
+ 16, 16, 17, 18, 9, 10, 13, 15, 15, 16, 17, 18, 19, 21, 22, 22, 22, 15, 16,
+ 18, 20, 20, 20, 21, 14, 13, 16, 17, 18, 18, 18, 14, 9, 14, 14, 14, 15, 15,
+ 12, 7, 10, 10, 10, 10, 11, 8, 7, 7, 7, 8, 9, 9, 6, 9, 9, 6, 6,
+ 7, 8, 7, 9, 11, 12, 14, 14, 13, 14, 4, 9, 11, 12, 12, 11, 14, 4, 7,
+ 8, 8, 9, 9, 12, 4, 5, 5, 5, 5, 6, 6, 3, 0, 0, 0, 0, 3, 6,
+ 3, 3, 3, 2, 1, 1, 6, 6, 6, 5, 2, 2, 2, 5, 4, 5, 6, 6, 9,
+ 12, 13, 4, 5, 6, 6, 8, 10, 11, 4, 6, 6, 6, 5, 7, 9, 4, 5, 5,
+ 5, 3, 3, 6, 2, 3, 5, 4, 2, 2, 4, 2, 4, 7, 6, 3, 2, 2, 5,
+ 5, 8, 7, 4, 2, 1, 7, 10, 9, 7, 7, 10, 12, 7, 10, 11, 8, 6, 8,
+ 10, 7, 10, 12, 7, 5, 5, 6, 7, 9, 12, 7, 4, 2, 2, 5, 8, 10, 7,
+ 4, 2, 1, 4, 7, 10, 9, 5, 2, 1, 5, 9, 11, 11, 7, 3, 2, 27, 30,
+ 34, 37, 37, 34, 32, 25, 29, 32, 36, 36, 34, 29, 23, 27, 32, 34, 35, 32, 28,
+ 22, 25, 28, 31, 33, 29, 24, 19, 22, 25, 27, 30, 28, 24, 16, 19, 21, 24, 29,
+ 27, 24, 13, 17, 20, 24, 27, 27, 24, 24, 27, 31, 34, 33, 31, 28, 22, 26, 30,
+ 33, 33, 31, 27, 20, 24, 29, 31, 30, 29, 25, 19, 22, 25, 28, 28, 27, 22, 16,
+ 18, 22, 25, 24, 23, 21, 13, 16, 19, 23, 22, 23, 21, 10, 14, 18, 21, 21, 21,
+ 21, 21, 24, 27, 29, 29, 28, 23, 19, 23, 26, 27, 28, 26, 22, 18, 21, 24, 24,
+ 25, 24, 20, 16, 20, 20, 20, 21, 22, 17, 10, 16, 17, 17, 17, 18, 16, 7, 13,
+ 15, 16, 16, 16, 16, 8, 11, 13, 13, 15, 15, 15, 18, 19, 20, 21, 22, 23, 15,
+ 15, 17, 19, 20, 19, 19, 14, 12, 16, 17, 17, 17, 17, 13, 8, 13, 13, 13, 14,
+ 14, 11, 6, 9, 9, 9, 9, 9, 8, 6, 7, 7, 8, 8, 8, 5, 8, 9, 5,
+ 6, 6, 7, 5, 8, 10, 12, 13, 13, 13, 15, 3, 9, 10, 11, 11, 11, 14, 3,
+ 8, 8, 8, 8, 8, 9, 3, 5, 4, 4, 4, 5, 5, 2, 0, 0, 0, 0, 2,
+ 4, 3, 5, 6, 5, 3, 1, 4, 7, 10, 10, 6, 5, 2, 4, 4, 5, 6, 7,
+ 9, 11, 13, 4, 7, 7, 7, 8, 9, 11, 4, 9, 9, 8, 5, 7, 8, 4, 8,
+ 10, 10, 5, 3, 4, 2, 7, 12, 12, 7, 2, 3, 3, 9, 15, 15, 10, 4, 2,
+ 8, 12, 16, 16, 12, 6, 1, 11, 17, 16, 11, 7, 10, 12, 11, 18, 19, 13, 7,
+ 8, 9, 11, 17, 21, 14, 8, 4, 6, 11, 17, 21, 15, 9, 4, 2, 10, 16, 21,
+ 17, 12, 6, 1, 10, 16, 20, 19, 14, 8, 2, 13, 18, 20, 20, 16, 10, 4, 27,
+ 30, 33, 37, 36, 35, 31, 25, 29, 32, 36, 37, 35, 30, 23, 27, 31, 35, 35, 32,
+ 28, 22, 25, 29, 31, 34, 30, 24, 19, 22, 24, 27, 31, 28, 25, 16, 18, 21, 25,
+ 29, 28, 25, 13, 16, 20, 23, 27, 27, 25, 23, 28, 30, 34, 33, 31, 29, 22, 26,
+ 30, 33, 34, 29, 26, 20, 24, 28, 30, 31, 28, 23, 19, 22, 24, 27, 28, 26, 20,
+ 17, 19, 21, 24, 24, 23, 20, 14, 16, 19, 22, 21, 22, 20, 10, 14, 18, 20, 21,
+ 21, 21, 20, 24, 26, 27, 29, 27, 23, 19, 22, 25, 26, 26, 25, 21, 18, 21, 23,
+ 24, 24, 24, 19, 15, 20, 20, 20, 21, 20, 16, 10, 16, 16, 17, 16, 16, 16, 7,
+ 14, 14, 15, 15, 15, 16, 8, 11, 13, 14, 14, 14, 14, 18, 18, 19, 20, 22, 22,
+ 15, 15, 17, 18, 19, 20, 20, 13, 11, 16, 16, 16, 16, 16, 12, 8, 14, 12, 13,
+ 13, 13, 11, 6, 10, 9, 9, 9, 9, 7, 6, 7, 7, 7, 7, 8, 4, 8, 8,
+ 5, 6, 6, 6, 4, 7, 10, 12, 13, 13, 13, 14, 3, 9, 10, 11, 11, 10, 13,
+ 3, 8, 8, 8, 8, 8, 9, 3, 5, 4, 4, 4, 4, 4, 2, 0, 0, 0, 0,
+ 2, 3, 3, 5, 6, 4, 2, 1, 3, 6, 9, 9, 6, 4, 2, 2, 4, 5, 6,
+ 7, 9, 12, 13, 4, 7, 7, 7, 8, 9, 10, 4, 8, 9, 8, 5, 6, 7, 4,
+ 8, 9, 9, 5, 3, 3, 2, 7, 11, 11, 7, 2, 3, 3, 9, 15, 15, 9, 3,
+ 2, 7, 12, 17, 17, 11, 5, 1, 11, 17, 16, 11, 7, 10, 11, 11, 17, 19, 12,
+ 7, 8, 9, 11, 17, 20, 14, 8, 4, 5, 11, 17, 21, 14, 9, 3, 2, 10, 15,
+ 21, 17, 11, 5, 1, 10, 16, 21, 21, 14, 7, 2, 12, 18, 22, 22, 16, 10, 4,
+ 26, 30, 33, 39, 37, 35, 31, 25, 29, 32, 37, 37, 33, 30, 23, 26, 32, 34, 36,
+ 32, 28, 22, 24, 28, 31, 33, 30, 25, 19, 21, 25, 27, 30, 28, 25, 16, 19, 21,
+ 25, 28, 28, 25, 14, 17, 20, 24, 27, 28, 25, 23, 28, 30, 34, 34, 31, 27, 22,
+ 26, 29, 32, 33, 30, 26, 21, 24, 28, 30, 31, 28, 24, 20, 22, 25, 28, 29, 26,
+ 20, 17, 19, 21, 23, 24, 23, 20, 14, 16, 19, 21, 22, 23, 20, 12, 15, 18, 21,
+ 21, 21, 20, 21, 24, 27, 27, 29, 27, 23, 19, 23, 26, 26, 26, 25, 21, 18, 22,
+ 23, 23, 24, 24, 19, 15, 20, 20, 20, 20, 20, 15, 10, 16, 17, 17, 17, 16, 15,
+ 7, 14, 15, 15, 15, 15, 14, 7, 12, 14, 14, 14, 14, 14, 18, 19, 20, 20, 22,
+ 21, 15, 15, 17, 18, 20, 20, 19, 13, 12, 16, 16, 16, 16, 16, 12, 8, 14, 13,
+ 12, 13, 13, 11, 6, 10, 9, 9, 9, 9, 7, 6, 8, 8, 7, 7, 8, 4, 7,
+ 5, 6, 6, 6, 6, 4, 7, 11, 12, 12, 13, 13, 15, 4, 9, 10, 11, 11, 10,
+ 13, 4, 8, 8, 8, 8, 8, 8, 4, 5, 5, 4, 4, 4, 4, 2, 0, 0, 0,
+ 0, 2, 3, 3, 4, 4, 3, 2, 2, 3, 4, 5, 5, 4, 4, 2, 2, 4, 5,
+ 6, 7, 9, 11, 13, 4, 7, 7, 7, 8, 9, 10, 4, 9, 8, 7, 5, 6, 7,
+ 4, 8, 9, 8, 5, 3, 3, 2, 7, 11, 9, 6, 2, 2, 3, 9, 14, 12, 8,
+ 3, 2, 4, 9, 14, 14, 10, 5, 1, 10, 14, 12, 9, 8, 10, 11, 10, 14, 14,
+ 10, 7, 8, 8, 10, 14, 15, 10, 7, 4, 5, 10, 13, 15, 11, 8, 3, 2, 10,
+ 13, 16, 14, 10, 5, 1, 10, 15, 18, 17, 12, 7, 2, 11, 15, 18, 18, 13, 9,
+ 3, 24, 27, 31, 35, 36, 33, 29, 22, 26, 30, 34, 36, 32, 28, 21, 25, 28, 32,
+ 33, 29, 25, 19, 22, 26, 29, 31, 27, 23, 17, 19, 21, 25, 29, 26, 23, 15, 17,
+ 19, 23, 27, 26, 22, 13, 16, 19, 22, 26, 26, 23, 21, 25, 28, 32, 31, 28, 25,
+ 20, 22, 27, 31, 31, 28, 23, 19, 22, 26, 28, 28, 25, 21, 17, 20, 23, 25, 25,
+ 23, 18, 15, 17, 19, 22, 22, 21, 18, 13, 15, 17, 20, 20, 21, 19, 10, 14, 17,
+ 19, 19, 19, 18, 19, 22, 23, 25, 27, 24, 20, 18, 21, 23, 24, 24, 23, 18, 17,
+ 19, 21, 22, 21, 20, 16, 15, 17, 18, 18, 18, 18, 13, 10, 14, 15, 14, 14, 15,
+ 13, 6, 13, 14, 13, 13, 13, 13, 6, 12, 12, 12, 12, 12, 12, 17, 17, 17, 18,
+ 19, 19, 13, 14, 15, 16, 16, 17, 17, 10, 11, 14, 14, 14, 14, 13, 9, 7, 12,
+ 11, 10, 10, 10, 9, 5, 8, 8, 7, 7, 7, 5, 5, 6, 6, 6, 6, 6, 3,
+ 6, 4, 4, 4, 4, 4, 3, 7, 8, 9, 10, 11, 11, 13, 2, 7, 8, 8, 9,
+ 8, 10, 2, 6, 6, 5, 6, 6, 6, 2, 3, 3, 2, 2, 3, 3, 1, 3, 2,
+ 2, 2, 0, 2, 2, 5, 5, 4, 2, 1, 2, 3, 6, 7, 4, 3, 2, 2, 3,
+ 4, 5, 7, 8, 10, 11, 3, 4, 5, 6, 7, 7, 8, 3, 6, 5, 4, 4, 4,
+ 5, 3, 5, 5, 3, 2, 1, 2, 3, 7, 7, 5, 4, 2, 1, 5, 7, 10, 7,
+ 4, 3, 0, 6, 8, 10, 8, 5, 3, 1, 6, 8, 7, 5, 7, 8, 9, 6, 8,
+ 7, 6, 6, 6, 6, 6, 8, 9, 5, 3, 3, 3, 6, 8, 10, 7, 4, 2, 0,
+ 7, 10, 11, 8, 5, 3, 2, 8, 10, 11, 10, 6, 4, 2, 9, 10, 11, 11, 7,
+ 4, 3, 19, 22, 26, 30, 30, 27, 23, 17, 21, 25, 29, 29, 25, 22, 16, 20, 23,
+ 26, 28, 24, 20, 15, 17, 21, 24, 26, 23, 18, 12, 14, 17, 20, 24, 22, 18, 10,
+ 13, 16, 19, 22, 22, 18, 8, 11, 15, 18, 20, 21, 18, 16, 20, 23, 27, 25, 23,
+ 20, 15, 18, 22, 26, 26, 22, 18, 14, 17, 21, 23, 23, 20, 16, 12, 15, 18, 21,
+ 20, 19, 14, 9, 12, 15, 17, 17, 17, 14, 8, 11, 14, 16, 16, 16, 14, 6, 9,
+ 13, 15, 14, 15, 14, 14, 17, 19, 19, 21, 20, 15, 12, 15, 17, 18, 19, 18, 13,
+ 11, 14, 16, 16, 16, 16, 11, 10, 12, 13, 12, 13, 13, 9, 6, 9, 10, 10, 10,
+ 10, 9, 5, 8, 9, 9, 9, 9, 9, 6, 7, 8, 8, 8, 8, 8, 11, 11, 12,
+ 13, 14, 15, 9, 10, 10, 10, 11, 11, 12, 7, 8, 9, 9, 9, 8, 8, 5, 4,
+ 6, 5, 5, 5, 5, 4, 3, 3, 3, 3, 3, 2, 2, 4, 3, 2, 2, 2, 2,
+ 1, 6, 7, 4, 3, 2, 1, 0, 3, 3, 5, 6, 7, 8, 9, 2, 3, 4, 5,
+ 6, 6, 7, 2, 3, 3, 3, 3, 3, 4, 2, 5, 3, 2, 2, 2, 1, 3, 6,
+ 4, 3, 3, 2, 0, 4, 7, 6, 4, 3, 2, 2, 6, 8, 8, 6, 4, 3, 2,
+ 6, 6, 5, 5, 6, 7, 8, 6, 7, 5, 5, 5, 5, 5, 6, 8, 6, 4, 3,
+ 2, 2, 6, 8, 6, 5, 4, 3, 1, 6, 7, 9, 8, 5, 3, 2, 7, 9, 13,
+ 11, 7, 4, 2, 8, 10, 14, 13, 9, 5, 3, 8, 11, 9, 6, 5, 7, 7, 8,
+ 11, 11, 7, 4, 4, 4, 8, 11, 13, 7, 4, 3, 2, 8, 10, 14, 8, 5, 3,
+ 2, 8, 11, 15, 13, 8, 5, 3, 9, 13, 17, 17, 10, 6, 3, 11, 15, 18, 18,
+ 12, 7, 4, 23, 25, 27, 31, 31, 29, 25, 23, 24, 26, 29, 30, 27, 25, 21, 24,
+ 27, 27, 28, 25, 22, 20, 21, 24, 25, 26, 22, 16, 17, 19, 20, 21, 20, 18, 16,
+ 12, 14, 16, 16, 18, 18, 16, 8, 11, 14, 16, 18, 18, 16, 21, 24, 25, 28, 27,
+ 26, 24, 20, 23, 25, 27, 27, 24, 23, 18, 22, 25, 24, 25, 22, 20, 17, 20, 22,
+ 22, 21, 20, 15, 14, 16, 18, 19, 16, 15, 14, 9, 12, 14, 15, 14, 15, 15, 6,
+ 8, 12, 14, 14, 15, 15, 19, 22, 23, 24, 24, 24, 21, 16, 20, 22, 23, 24, 23,
+ 21, 15, 19, 21, 22, 22, 21, 19, 14, 17, 18, 18, 18, 19, 14, 9, 13, 14, 15,
+ 14, 14, 13, 4, 9, 10, 11, 12, 13, 13, 7, 7, 8, 10, 11, 12, 13, 15, 17,
+ 18, 20, 20, 21, 16, 14, 15, 16, 18, 18, 18, 14, 11, 13, 15, 15, 15, 15, 12,
+ 7, 11, 11, 11, 12, 11, 10, 5, 7, 7, 7, 6, 7, 6, 3, 3, 3, 3, 5,
+ 6, 6, 6, 6, 4, 2, 3, 4, 5, 8, 10, 11, 13, 14, 15, 16, 5, 9, 10,
+ 12, 12, 13, 15, 5, 8, 9, 9, 10, 10, 11, 5, 6, 6, 6, 6, 6, 5, 3,
+ 3, 3, 3, 3, 2, 4, 0, 3, 3, 2, 2, 2, 5, 4, 4, 5, 3, 3, 3,
+ 3, 7, 8, 8, 9, 11, 14, 15, 7, 9, 8, 9, 9, 11, 13, 7, 9, 9, 9,
+ 7, 8, 10, 7, 8, 8, 8, 6, 5, 5, 5, 7, 9, 7, 5, 3, 2, 3, 5,
+ 10, 8, 6, 3, 2, 4, 7, 10, 10, 7, 4, 2, 10, 13, 13, 10, 9, 12, 13,
+ 10, 14, 14, 11, 9, 9, 11, 10, 13, 16, 11, 8, 7, 8, 10, 13, 15, 10, 8,
+ 6, 2, 9, 11, 14, 11, 7, 4, 2, 7, 10, 13, 12, 8, 5, 3, 7, 11, 13,
+ 13, 9, 6, 3, 30, 34, 36, 38, 39, 38, 34, 29, 33, 36, 38, 38, 35, 33, 27,
+ 31, 33, 36, 37, 34, 30, 26, 29, 31, 35, 35, 30, 24, 23, 26, 27, 30, 29, 27,
+ 24, 18, 22, 23, 25, 27, 26, 24, 14, 18, 21, 24, 26, 26, 24, 27, 31, 35, 37,
+ 36, 35, 31, 25, 30, 33, 36, 36, 33, 29, 24, 28, 31, 34, 34, 31, 28, 23, 26,
+ 30, 32, 29, 28, 22, 19, 23, 25, 27, 25, 24, 22, 15, 18, 20, 22, 23, 24, 22,
+ 11, 15, 19, 22, 22, 22, 22, 24, 29, 30, 32, 33, 32, 28, 22, 26, 30, 31, 30,
+ 31, 26, 22, 25, 28, 28, 28, 28, 23, 19, 23, 24, 25, 25, 25, 18, 13, 19, 21,
+ 21, 19, 19, 19, 7, 15, 16, 16, 18, 18, 19, 7, 11, 14, 15, 16, 17, 17, 21,
+ 23, 24, 26, 27, 27, 21, 18, 21, 22, 24, 24, 24, 19, 14, 20, 20, 21, 21, 21,
+ 17, 11, 17, 17, 17, 17, 17, 15, 9, 12, 12, 13, 12, 12, 11, 6, 8, 8, 9,
+ 9, 10, 8, 7, 5, 6, 7, 8, 8, 8, 11, 14, 16, 17, 18, 19, 20, 7, 13,
+ 14, 16, 17, 16, 19, 7, 13, 13, 13, 14, 14, 15, 7, 9, 10, 9, 9, 9, 8,
+ 5, 3, 5, 5, 4, 5, 7, 3, 0, 2, 2, 1, 3, 7, 3, 3, 3, 2, 2,
+ 2, 5, 7, 9, 10, 12, 15, 18, 20, 7, 7, 9, 11, 13, 16, 16, 7, 8, 8,
+ 8, 10, 12, 12, 7, 7, 7, 7, 6, 7, 6, 5, 5, 6, 5, 3, 2, 5, 2,
+ 3, 5, 4, 3, 2, 4, 3, 5, 6, 6, 4, 2, 3, 9, 11, 11, 9, 12, 16,
+ 17, 9, 11, 12, 10, 10, 13, 15, 9, 11, 13, 9, 7, 9, 11, 9, 10, 12, 8,
+ 6, 5, 4, 7, 9, 10, 8, 4, 2, 3, 5, 7, 9, 8, 4, 3, 2, 4, 6,
+ 9, 9, 5, 3, 2, 32, 36, 40, 42, 43, 41, 37, 31, 35, 39, 42, 42, 39, 35,
+ 29, 33, 38, 40, 41, 37, 33, 28, 30, 35, 37, 39, 34, 27, 25, 27, 30, 32, 33,
+ 30, 27, 21, 23, 26, 28, 31, 31, 27, 16, 20, 24, 27, 30, 30, 27, 29, 34, 37,
+ 39, 39, 37, 34, 28, 33, 35, 38, 39, 35, 32, 26, 30, 34, 36, 36, 33, 28, 25,
+ 28, 31, 33, 34, 30, 24, 21, 24, 27, 29, 27, 26, 24, 16, 20, 23, 25, 25, 27,
+ 24, 13, 17, 21, 24, 24, 25, 24, 26, 30, 32, 34, 35, 34, 29, 25, 28, 31, 33,
+ 33, 31, 26, 22, 26, 30, 30, 29, 29, 24, 19, 25, 26, 26, 27, 25, 20, 13, 21,
+ 22, 23, 20, 21, 20, 8, 17, 18, 18, 18, 19, 20, 7, 14, 16, 16, 17, 17, 18,
+ 23, 24, 25, 26, 28, 29, 21, 19, 22, 24, 25, 26, 26, 19, 15, 21, 22, 22, 22,
+ 22, 18, 11, 18, 18, 18, 18, 17, 16, 9, 13, 15, 14, 13, 12, 12, 7, 8, 10,
+ 10, 10, 11, 9, 7, 5, 8, 9, 9, 10, 7, 11, 16, 17, 18, 19, 19, 21, 7,
+ 15, 16, 17, 18, 17, 20, 7, 13, 14, 14, 14, 14, 14, 7, 9, 11, 10, 10, 9,
+ 8, 5, 3, 6, 6, 4, 5, 6, 3, 2, 0, 2, 3, 4, 6, 4, 3, 3, 2,
+ 2, 3, 5, 7, 10, 12, 13, 16, 18, 20, 7, 9, 11, 12, 14, 16, 16, 7, 7,
+ 9, 9, 11, 13, 12, 7, 6, 7, 7, 7, 7, 6, 5, 4, 9, 9, 5, 3, 5,
+ 3, 5, 11, 11, 7, 2, 5, 1, 7, 11, 12, 9, 4, 4, 9, 15, 14, 10, 14,
+ 17, 18, 8, 15, 16, 10, 12, 14, 14, 9, 14, 18, 11, 8, 10, 11, 8, 14, 18,
+ 12, 7, 5, 5, 7, 13, 17, 14, 9, 4, 4, 7, 13, 16, 14, 11, 6, 3, 8,
+ 13, 15, 15, 12, 8, 2, 30, 33, 38, 42, 43, 38, 36, 29, 33, 37, 41, 41, 38,
+ 35, 28, 31, 35, 39, 40, 36, 31, 26, 29, 33, 35, 38, 33, 27, 23, 26, 28, 30,
+ 32, 30, 27, 19, 22, 25, 27, 31, 30, 27, 16, 19, 22, 26, 30, 29, 27, 27, 31,
+ 34, 39, 38, 35, 32, 26, 30, 34, 38, 37, 34, 30, 26, 29, 32, 35, 34, 31, 26,
+ 23, 25, 30, 32, 31, 29, 23, 20, 23, 26, 28, 26, 26, 22, 16, 19, 22, 23, 23,
+ 25, 23, 12, 17, 20, 23, 23, 24, 23, 25, 29, 30, 31, 34, 32, 27, 23, 27, 29,
+ 31, 31, 29, 25, 22, 26, 28, 28, 28, 27, 22, 18, 23, 25, 25, 25, 23, 18, 12,
+ 20, 21, 21, 20, 19, 18, 7, 16, 17, 17, 17, 18, 18, 6, 14, 16, 16, 16, 16,
+ 16, 21, 23, 24, 25, 26, 26, 20, 18, 22, 23, 23, 24, 23, 17, 14, 20, 21, 20,
+ 21, 21, 16, 10, 17, 17, 17, 17, 16, 14, 8, 12, 13, 13, 12, 11, 11, 7, 8,
+ 10, 10, 9, 10, 7, 6, 5, 8, 8, 8, 8, 5, 9, 15, 15, 17, 17, 17, 19,
+ 6, 13, 14, 15, 15, 14, 17, 6, 12, 12, 12, 12, 11, 12, 6, 8, 9, 9, 8,
+ 7, 7, 4, 2, 5, 4, 3, 4, 5, 2, 2, 2, 0, 2, 3, 4, 3, 2, 3,
+ 2, 2, 2, 4, 6, 9, 10, 11, 13, 16, 17, 6, 7, 9, 10, 12, 13, 14, 6,
+ 7, 7, 8, 9, 10, 9, 6, 6, 7, 7, 5, 6, 4, 4, 5, 9, 9, 4, 2,
+ 3, 2, 5, 11, 11, 6, 1, 3, 2, 6, 11, 13, 8, 3, 3, 9, 15, 14, 9,
+ 12, 14, 15, 9, 15, 17, 10, 10, 12, 12, 9, 15, 18, 11, 7, 9, 9, 9, 14,
+ 19, 12, 7, 4, 3, 7, 13, 19, 15, 8, 3, 2, 7, 13, 18, 17, 10, 5, 2,
+ 8, 14, 19, 18, 13, 7, 2, 29, 31, 36, 40, 40, 38, 34, 27, 30, 35, 39, 38,
+ 36, 32, 25, 29, 33, 37, 38, 33, 30, 24, 27, 31, 34, 36, 32, 26, 21, 24, 26,
+ 30, 32, 30, 25, 18, 20, 23, 27, 30, 28, 26, 16, 18, 22, 25, 29, 29, 26, 26,
+ 29, 33, 37, 35, 34, 30, 25, 28, 32, 35, 36, 32, 27, 22, 27, 30, 33, 33, 30,
+ 25, 22, 24, 26, 30, 30, 27, 21, 19, 21, 23, 26, 25, 25, 22, 16, 18, 20, 23,
+ 24, 24, 21, 12, 16, 19, 22, 22, 23, 21, 23, 26, 28, 29, 31, 29, 25, 22, 25,
+ 27, 29, 28, 27, 23, 20, 24, 26, 26, 26, 25, 20, 17, 22, 22, 22, 23, 22, 16,
+ 11, 18, 19, 19, 18, 18, 16, 7, 16, 17, 16, 16, 17, 16, 7, 15, 15, 15, 15,
+ 16, 15, 20, 21, 21, 22, 24, 24, 17, 17, 20, 20, 21, 21, 21, 15, 13, 19, 19,
+ 18, 18, 18, 13, 9, 16, 15, 15, 15, 14, 12, 7, 11, 11, 11, 10, 10, 9, 7,
+ 8, 10, 9, 9, 9, 6, 7, 5, 8, 8, 8, 8, 4, 8, 13, 14, 14, 15, 14,
+ 16, 5, 12, 12, 13, 13, 11, 15, 5, 10, 10, 10, 10, 9, 10, 5, 6, 7, 6,
+ 6, 5, 5, 3, 1, 3, 2, 2, 2, 3, 2, 1, 3, 2, 0, 2, 3, 4, 2,
+ 4, 2, 2, 1, 3, 4, 6, 7, 9, 10, 13, 14, 4, 5, 6, 8, 9, 10, 11,
+ 4, 7, 7, 6, 7, 7, 7, 4, 6, 7, 7, 3, 4, 3, 2, 5, 10, 8, 5,
+ 1, 2, 0, 6, 11, 11, 6, 2, 2, 3, 7, 12, 12, 8, 3, 2, 9, 12, 11,
+ 8, 9, 11, 12, 9, 13, 12, 9, 8, 9, 9, 9, 13, 14, 9, 6, 6, 7, 9,
+ 12, 14, 10, 7, 2, 2, 8, 12, 15, 13, 8, 3, 2, 8, 13, 16, 15, 10, 5,
+ 1, 8, 13, 16, 16, 11, 7, 2, 26, 28, 32, 36, 37, 34, 31, 24, 27, 31, 36,
+ 36, 33, 29, 23, 26, 29, 33, 34, 32, 27, 21, 24, 27, 31, 33, 29, 24, 18, 21,
+ 24, 27, 31, 27, 24, 16, 18, 22, 25, 28, 27, 24, 15, 17, 21, 23, 27, 27, 24,
+ 23, 27, 30, 35, 33, 31, 27, 21, 26, 29, 32, 32, 28, 25, 21, 23, 28, 30, 31,
+ 28, 23, 20, 22, 24, 27, 27, 25, 20, 17, 18, 21, 24, 24, 23, 20, 15, 17, 19,
+ 22, 22, 22, 20, 12, 16, 18, 20, 20, 21, 19, 21, 24, 25, 27, 28, 27, 22, 19,
+ 22, 25, 25, 26, 24, 20, 18, 21, 23, 23, 23, 22, 18, 16, 19, 20, 20, 20, 19,
+ 15, 10, 16, 16, 16, 16, 16, 14, 7, 15, 16, 15, 15, 15, 14, 7, 14, 14, 13,
+ 14, 14, 13, 18, 19, 18, 20, 21, 21, 14, 15, 17, 18, 18, 19, 18, 12, 12, 16,
+ 16, 16, 15, 15, 11, 8, 14, 13, 12, 12, 11, 10, 6, 10, 9, 9, 8, 8, 7,
+ 6, 8, 8, 7, 7, 7, 4, 7, 4, 6, 6, 6, 6, 3, 8, 10, 11, 12, 12,
+ 12, 13, 3, 9, 9, 10, 11, 9, 11, 3, 8, 7, 7, 7, 7, 7, 3, 4, 4,
+ 3, 3, 3, 3, 1, 1, 1, 1, 2, 1, 2, 2, 3, 4, 3, 2, 0, 3, 3,
+ 5, 5, 3, 3, 2, 2, 3, 5, 6, 7, 8, 10, 11, 3, 4, 6, 7, 7, 8,
+ 8, 3, 4, 4, 4, 5, 5, 6, 3, 4, 4, 3, 2, 2, 2, 2, 5, 6, 4,
+ 3, 2, 2, 3, 6, 8, 6, 3, 2, 1, 5, 7, 8, 7, 4, 3, 0, 5, 7,
+ 6, 6, 8, 9, 10, 5, 7, 7, 6, 6, 7, 7, 6, 7, 8, 4, 3, 4, 4,
+ 5, 7, 8, 5, 3, 2, 1, 5, 8, 9, 7, 4, 2, 0, 6, 8, 10, 9, 5,
+ 3, 2, 7, 9, 10, 10, 6, 4, 3, 20, 24, 29, 32, 32, 29, 25, 20, 23, 27,
+ 31, 31, 28, 25, 18, 21, 25, 29, 30, 25, 22, 16, 19, 22, 26, 28, 23, 20, 13,
+ 16, 19, 22, 26, 23, 19, 11, 14, 17, 20, 24, 23, 20, 10, 13, 16, 19, 22, 23,
+ 20, 18, 21, 25, 29, 28, 26, 22, 16, 20, 24, 28, 28, 24, 20, 15, 19, 23, 25,
+ 24, 23, 18, 14, 17, 20, 22, 22, 20, 16, 11, 13, 16, 18, 19, 18, 16, 10, 12,
+ 15, 17, 18, 17, 15, 7, 11, 14, 16, 16, 16, 16, 15, 19, 21, 21, 23, 21, 17,
+ 14, 17, 20, 21, 21, 20, 15, 13, 16, 18, 17, 18, 18, 14, 12, 14, 15, 15, 15,
+ 15, 11, 8, 11, 12, 12, 12, 12, 11, 5, 10, 11, 10, 10, 10, 11, 5, 8, 9,
+ 9, 10, 9, 9, 14, 13, 14, 14, 16, 17, 10, 11, 11, 12, 13, 13, 14, 8, 9,
+ 10, 11, 11, 10, 10, 7, 5, 8, 7, 7, 7, 7, 6, 4, 5, 5, 4, 4, 4,
+ 3, 5, 3, 3, 3, 3, 3, 3, 6, 5, 3, 2, 2, 2, 2, 4, 5, 6, 7,
+ 8, 9, 10, 2, 4, 5, 6, 6, 7, 8, 2, 3, 4, 4, 4, 4, 5, 2, 3,
+ 2, 2, 2, 1, 2, 1, 6, 4, 3, 3, 2, 2, 4, 7, 7, 5, 3, 2, 0,
+ 6, 8, 8, 5, 4, 3, 1, 5, 5, 5, 5, 6, 8, 9, 4, 6, 5, 5, 5,
+ 6, 6, 5, 7, 5, 4, 3, 3, 3, 5, 7, 7, 5, 4, 3, 0, 6, 8, 8,
+ 6, 4, 3, 1, 7, 9, 10, 8, 5, 3, 2, 8, 9, 11, 10, 6, 4, 2, 8,
+ 10, 7, 5, 6, 7, 7, 8, 9, 9, 6, 5, 5, 5, 8, 10, 10, 5, 4, 2,
+ 2, 8, 10, 11, 7, 5, 3, 2, 9, 10, 12, 10, 6, 4, 3, 9, 10, 14, 13,
+ 8, 5, 3, 9, 11, 14, 14, 9, 5, 3, 27, 30, 32, 34, 33, 31, 30, 26, 29,
+ 32, 33, 33, 30, 28, 25, 29, 30, 31, 31, 27, 24, 24, 25, 27, 28, 28, 23, 17,
+ 20, 23, 24, 23, 21, 18, 17, 17, 19, 19, 17, 19, 18, 17, 11, 13, 16, 18, 18,
+ 18, 17, 25, 27, 31, 32, 31, 30, 30, 24, 28, 30, 31, 31, 29, 26, 22, 25, 28,
+ 30, 28, 26, 23, 21, 24, 26, 26, 25, 21, 16, 18, 20, 22, 22, 17, 16, 16, 13,
+ 16, 17, 16, 16, 16, 16, 7, 11, 14, 16, 15, 16, 16, 22, 26, 28, 29, 30, 29,
+ 26, 21, 25, 27, 28, 28, 27, 24, 19, 23, 25, 26, 26, 25, 20, 18, 21, 22, 22,
+ 22, 20, 15, 11, 17, 18, 18, 15, 15, 14, 5, 12, 13, 13, 13, 13, 15, 4, 7,
+ 10, 11, 12, 13, 13, 19, 20, 22, 23, 25, 25, 22, 17, 19, 20, 22, 23, 23, 20,
+ 14, 18, 19, 19, 19, 18, 16, 11, 16, 15, 15, 15, 13, 13, 8, 11, 11, 10, 8,
+ 8, 9, 5, 5, 5, 5, 6, 7, 7, 4, 3, 2, 4, 5, 5, 7, 13, 16, 18,
+ 19, 20, 22, 22, 9, 15, 17, 18, 18, 19, 20, 9, 15, 15, 16, 16, 16, 14, 9,
+ 11, 12, 12, 11, 9, 7, 7, 6, 7, 6, 4, 3, 7, 4, 3, 4, 3, 4, 3,
+ 6, 0, 3, 4, 3, 4, 4, 4, 10, 11, 13, 14, 17, 20, 21, 10, 10, 12, 13,
+ 16, 17, 18, 10, 11, 11, 11, 12, 14, 13, 10, 10, 10, 9, 8, 7, 6, 8, 8,
+ 9, 8, 5, 4, 5, 5, 7, 9, 8, 5, 4, 3, 4, 5, 8, 9, 7, 5, 3,
+ 12, 14, 14, 13, 15, 19, 20, 12, 14, 15, 13, 13, 15, 17, 12, 14, 16, 12, 10,
+ 11, 11, 12, 13, 15, 11, 9, 6, 3, 10, 12, 14, 11, 7, 4, 3, 9, 10, 13,
+ 12, 8, 5, 4, 7, 10, 12, 13, 9, 6, 4, 34, 37, 39, 42, 42, 40, 38, 32,
+ 35, 39, 42, 42, 39, 36, 31, 34, 37, 39, 39, 36, 31, 29, 32, 34, 37, 36, 31,
+ 25, 26, 29, 30, 31, 30, 27, 25, 22, 24, 25, 25, 28, 27, 25, 16, 19, 21, 25,
+ 27, 27, 25, 30, 34, 38, 41, 40, 37, 35, 29, 33, 37, 39, 40, 36, 33, 27, 32,
+ 35, 37, 36, 33, 30, 26, 29, 33, 34, 32, 28, 23, 23, 26, 28, 29, 27, 24, 23,
+ 17, 21, 23, 22, 24, 24, 23, 11, 16, 20, 22, 23, 24, 23, 27, 31, 34, 35, 36,
+ 35, 30, 26, 29, 33, 34, 35, 33, 29, 23, 29, 31, 31, 31, 30, 25, 21, 26, 27,
+ 28, 27, 25, 20, 15, 22, 24, 23, 20, 20, 20, 9, 18, 18, 17, 17, 18, 20, 6,
+ 13, 15, 15, 16, 17, 18, 25, 26, 27, 28, 30, 31, 25, 20, 24, 26, 27, 27, 27,
+ 23, 17, 23, 24, 24, 24, 23, 21, 13, 20, 20, 20, 20, 18, 17, 11, 14, 15, 15,
+ 12, 12, 13, 8, 8, 11, 9, 10, 11, 10, 6, 4, 7, 7, 8, 9, 9, 13, 19,
+ 20, 22, 22, 24, 25, 10, 19, 19, 21, 21, 21, 22, 10, 17, 18, 18, 18, 17, 17,
+ 10, 12, 15, 14, 13, 11, 9, 7, 6, 10, 9, 5, 6, 7, 4, 3, 3, 2, 2,
+ 5, 8, 3, 0, 3, 2, 2, 3, 7, 10, 14, 15, 17, 20, 22, 24, 10, 12, 14,
+ 16, 18, 19, 20, 10, 10, 12, 12, 15, 16, 14, 10, 9, 8, 9, 10, 9, 7, 8,
+ 7, 7, 6, 4, 3, 7, 5, 5, 7, 5, 4, 2, 6, 2, 4, 6, 6, 4, 3,
+ 5, 10, 13, 13, 13, 17, 21, 22, 10, 13, 13, 12, 16, 18, 19, 10, 13, 14, 11,
+ 11, 13, 13, 10, 12, 13, 10, 8, 7, 6, 8, 10, 11, 9, 5, 3, 5, 7, 8,
+ 9, 8, 5, 3, 3, 5, 7, 9, 9, 6, 4, 2, 36, 39, 42, 47, 46, 43, 40,
+ 33, 38, 41, 46, 46, 42, 38, 33, 35, 40, 43, 43, 39, 35, 31, 33, 37, 39, 41,
+ 36, 31, 27, 30, 34, 35, 35, 32, 30, 23, 26, 28, 30, 33, 33, 30, 19, 22, 26,
+ 29, 32, 32, 30, 32, 36, 41, 44, 42, 41, 38, 31, 34, 39, 42, 42, 39, 35, 29,
+ 34, 37, 39, 40, 38, 32, 28, 31, 35, 36, 36, 32, 26, 23, 27, 30, 32, 30, 29,
+ 26, 18, 23, 26, 27, 27, 27, 27, 13, 20, 23, 26, 26, 26, 26, 30, 34, 35, 37,
+ 38, 38, 32, 27, 31, 35, 36, 36, 35, 30, 25, 30, 34, 34, 33, 32, 27, 21, 28,
+ 29, 29, 29, 28, 22, 15, 24, 26, 25, 23, 23, 22, 9, 20, 21, 20, 20, 21, 22,
+ 8, 17, 18, 19, 19, 20, 20, 25, 28, 29, 31, 31, 32, 26, 20, 26, 28, 29, 29,
+ 29, 23, 17, 24, 25, 26, 25, 25, 21, 14, 21, 22, 21, 22, 20, 18, 11, 15, 18,
+ 18, 15, 14, 14, 9, 10, 13, 13, 13, 13, 11, 8, 5, 10, 10, 11, 12, 8, 13,
+ 20, 20, 22, 23, 22, 25, 10, 18, 19, 21, 21, 20, 23, 9, 16, 18, 17, 17, 17,
+ 17, 10, 11, 14, 13, 13, 10, 10, 7, 5, 10, 9, 6, 7, 8, 5, 3, 3, 3,
+ 3, 5, 8, 4, 3, 0, 2, 3, 5, 7, 8, 14, 15, 17, 19, 22, 23, 9, 12,
+ 14, 15, 17, 19, 19, 9, 9, 12, 12, 14, 15, 14, 9, 8, 8, 8, 10, 9, 7,
+ 6, 5, 7, 7, 3, 5, 7, 4, 3, 8, 7, 5, 4, 7, 2, 4, 8, 8, 6,
+ 2, 5, 9, 12, 12, 13, 17, 20, 21, 9, 12, 14, 11, 15, 17, 18, 9, 12, 15,
+ 9, 11, 13, 13, 9, 11, 14, 10, 7, 7, 6, 7, 10, 13, 11, 6, 2, 5, 5,
+ 10, 11, 10, 7, 4, 4, 5, 8, 10, 10, 8, 6, 3, 32, 36, 39, 43, 44, 41,
+ 38, 31, 35, 38, 43, 44, 39, 35, 29, 33, 37, 40, 40, 38, 33, 28, 30, 34, 37,
+ 38, 34, 29, 25, 28, 30, 33, 35, 31, 29, 22, 24, 26, 29, 32, 31, 28, 18, 21,
+ 24, 28, 31, 32, 29, 29, 34, 38, 40, 41, 37, 34, 28, 32, 35, 39, 39, 36, 31,
+ 27, 30, 35, 38, 37, 33, 29, 25, 28, 31, 34, 33, 31, 24, 21, 25, 27, 29, 28,
+ 27, 24, 17, 21, 23, 25, 26, 27, 24, 13, 18, 22, 24, 24, 25, 25, 27, 30, 33,
+ 34, 35, 33, 29, 25, 29, 31, 33, 34, 32, 27, 23, 28, 30, 30, 30, 29, 24, 19,
+ 25, 25, 26, 26, 26, 20, 13, 21, 22, 23, 21, 20, 19, 8, 17, 19, 19, 19, 19,
+ 19, 7, 16, 17, 18, 18, 19, 18, 23, 25, 26, 27, 29, 28, 21, 18, 23, 24, 26,
+ 26, 25, 19, 15, 22, 23, 22, 22, 21, 18, 12, 19, 19, 19, 18, 17, 16, 9, 13,
+ 15, 15, 13, 12, 12, 8, 9, 11, 11, 11, 11, 9, 8, 5, 10, 9, 10, 10, 6,
+ 11, 16, 18, 19, 20, 18, 21, 7, 15, 16, 17, 17, 16, 19, 7, 12, 14, 14, 13,
+ 13, 14, 7, 8, 11, 10, 10, 7, 8, 5, 2, 6, 6, 4, 4, 6, 3, 2, 2,
+ 2, 2, 3, 5, 3, 2, 2, 0, 2, 3, 4, 6, 10, 11, 13, 15, 16, 19, 6,
+ 9, 10, 11, 13, 14, 15, 6, 7, 8, 9, 10, 11, 10, 6, 5, 6, 5, 6, 7,
+ 5, 4, 3, 7, 7, 3, 3, 4, 2, 3, 10, 10, 5, 2, 4, 1, 4, 10, 12,
+ 7, 2, 3, 7, 13, 12, 10, 13, 16, 16, 7, 13, 15, 9, 11, 13, 13, 7, 13,
+ 17, 10, 8, 10, 10, 7, 12, 17, 11, 5, 5, 4, 6, 11, 17, 13, 7, 2, 3,
+ 5, 12, 17, 16, 9, 4, 3, 6, 12, 17, 17, 11, 6, 2, 30, 35, 39, 42, 42,
+ 39, 36, 29, 34, 38, 41, 42, 38, 34, 28, 31, 36, 39, 41, 36, 33, 27, 28, 32,
+ 36, 38, 33, 28, 24, 25, 29, 33, 34, 31, 28, 20, 22, 26, 28, 32, 31, 28, 18,
+ 20, 24, 27, 30, 31, 28, 28, 31, 35, 40, 39, 35, 32, 26, 30, 34, 38, 39, 34,
+ 30, 25, 28, 32, 36, 36, 32, 27, 24, 26, 29, 33, 33, 30, 23, 20, 23, 26, 28,
+ 28, 26, 23, 16, 20, 23, 25, 26, 26, 24, 13, 19, 21, 24, 24, 24, 23, 25, 29,
+ 30, 32, 33, 31, 27, 23, 27, 29, 31, 30, 30, 25, 21, 26, 28, 29, 28, 27, 22,
+ 18, 25, 25, 25, 25, 24, 18, 12, 20, 22, 21, 21, 19, 18, 8, 18, 18, 19, 19,
+ 18, 18, 8, 16, 18, 17, 18, 18, 16, 20, 24, 24, 25, 26, 25, 19, 17, 22, 22,
+ 23, 24, 22, 17, 14, 20, 21, 20, 20, 20, 15, 11, 17, 17, 17, 17, 16, 14, 8,
+ 12, 14, 14, 13, 12, 11, 7, 9, 11, 11, 11, 11, 7, 7, 6, 10, 9, 9, 10,
+ 5, 9, 15, 16, 17, 18, 15, 18, 6, 14, 15, 15, 16, 13, 16, 6, 11, 12, 12,
+ 12, 10, 12, 6, 6, 9, 9, 8, 6, 7, 4, 2, 5, 4, 4, 3, 4, 3, 2,
+ 2, 2, 2, 2, 4, 4, 2, 3, 2, 0, 2, 3, 5, 8, 9, 10, 12, 14, 16,
+ 5, 6, 8, 9, 11, 11, 12, 5, 5, 6, 6, 8, 9, 8, 4, 4, 6, 5, 4,
+ 5, 4, 2, 4, 7, 7, 3, 2, 3, 2, 4, 10, 9, 4, 1, 3, 2, 5, 10,
+ 11, 6, 2, 2, 7, 11, 10, 7, 11, 13, 14, 7, 11, 11, 8, 9, 11, 11, 7,
+ 11, 13, 8, 6, 7, 8, 7, 11, 13, 9, 5, 3, 3, 6, 10, 14, 12, 7, 2,
+ 3, 6, 11, 15, 14, 8, 3, 2, 7, 12, 15, 15, 10, 5, 1, 27, 31, 36, 39,
+ 39, 36, 33, 27, 30, 34, 38, 39, 36, 32, 24, 27, 34, 36, 37, 33, 30, 24, 26,
+ 29, 32, 36, 32, 26, 21, 23, 26, 29, 32, 29, 26, 18, 20, 23, 26, 30, 29, 26,
+ 17, 19, 22, 25, 28, 29, 26, 24, 28, 32, 37, 35, 33, 29, 24, 27, 32, 34, 36,
+ 30, 27, 23, 26, 29, 32, 31, 30, 25, 22, 23, 27, 29, 29, 27, 22, 18, 20, 23,
+ 26, 25, 24, 21, 16, 18, 20, 23, 23, 24, 22, 12, 17, 20, 22, 22, 23, 21, 23,
+ 26, 28, 29, 30, 28, 23, 21, 25, 27, 28, 28, 27, 22, 20, 23, 26, 25, 26, 25,
+ 20, 17, 22, 21, 21, 21, 21, 16, 11, 18, 18, 18, 18, 18, 16, 8, 16, 17, 16,
+ 17, 16, 16, 8, 15, 15, 15, 15, 15, 14, 20, 21, 21, 22, 23, 23, 15, 16, 19,
+ 20, 20, 21, 19, 14, 13, 18, 18, 18, 17, 17, 12, 9, 15, 14, 14, 13, 13, 12,
+ 7, 11, 11, 10, 10, 10, 8, 7, 9, 10, 9, 9, 9, 5, 8, 5, 8, 8, 8,
+ 8, 3, 8, 12, 13, 14, 14, 13, 15, 4, 11, 12, 12, 12, 10, 13, 4, 9, 9,
+ 9, 9, 8, 9, 4, 5, 6, 5, 5, 4, 5, 3, 2, 2, 2, 2, 2, 3, 3,
+ 2, 3, 2, 1, 2, 3, 4, 3, 5, 3, 2, 0, 3, 3, 6, 7, 8, 9, 11,
+ 13, 3, 5, 7, 8, 8, 9, 10, 3, 4, 5, 5, 6, 6, 6, 3, 3, 3, 2,
+ 2, 3, 3, 1, 4, 6, 4, 3, 0, 3, 2, 6, 8, 5, 4, 2, 2, 4, 7,
+ 8, 7, 4, 2, 2, 4, 6, 6, 7, 9, 10, 11, 4, 6, 7, 6, 7, 8, 8,
+ 4, 6, 7, 4, 4, 4, 6, 4, 6, 8, 4, 2, 1, 2, 3, 8, 9, 7, 4,
+ 2, 2, 6, 9, 9, 9, 5, 3, 0, 7, 9, 9, 9, 6, 4, 2, 22, 26, 29,
+ 33, 33, 30, 27, 21, 24, 29, 33, 32, 29, 26, 19, 23, 27, 30, 32, 28, 24, 18,
+ 21, 24, 27, 30, 26, 21, 15, 17, 21, 24, 27, 24, 21, 13, 15, 18, 22, 25, 25,
+ 21, 12, 15, 18, 20, 24, 24, 21, 20, 23, 27, 31, 29, 26, 23, 18, 22, 26, 29,
+ 29, 26, 21, 17, 20, 24, 27, 27, 24, 20, 16, 18, 21, 24, 23, 22, 17, 13, 15,
+ 17, 20, 20, 20, 17, 12, 13, 16, 18, 19, 19, 16, 9, 12, 16, 18, 17, 18, 17,
+ 18, 20, 23, 24, 25, 23, 19, 17, 19, 21, 22, 22, 21, 17, 15, 18, 20, 20, 20,
+ 19, 15, 14, 16, 16, 16, 16, 16, 12, 9, 13, 14, 13, 13, 13, 12, 6, 12, 13,
+ 12, 12, 12, 12, 6, 10, 10, 11, 11, 11, 10, 15, 15, 16, 17, 18, 18, 11, 14,
+ 14, 14, 15, 15, 15, 9, 11, 12, 13, 12, 12, 11, 8, 6, 11, 9, 9, 9, 9,
+ 7, 4, 7, 6, 6, 5, 5, 4, 5, 5, 5, 5, 4, 4, 2, 6, 4, 3, 3,
+ 3, 3, 2, 6, 7, 7, 8, 9, 10, 11, 2, 5, 6, 7, 7, 8, 9, 2, 4,
+ 5, 4, 5, 5, 5, 2, 2, 2, 2, 1, 2, 2, 1, 4, 3, 3, 2, 1, 2,
+ 3, 5, 5, 3, 3, 2, 1, 4, 7, 6, 4, 3, 3, 0, 4, 4, 5, 6, 7,
+ 8, 10, 3, 5, 5, 6, 6, 6, 7, 4, 6, 5, 4, 4, 3, 4, 4, 6, 5,
+ 4, 3, 2, 1, 4, 7, 8, 5, 4, 3, 0, 5, 7, 9, 7, 4, 3, 2, 6,
+ 8, 9, 8, 5, 3, 2, 7, 9, 7, 5, 6, 8, 8, 7, 9, 8, 5, 5, 5,
+ 5, 7, 9, 9, 5, 3, 2, 3, 7, 8, 11, 6, 4, 3, 1, 8, 9, 11, 9,
+ 5, 3, 2, 8, 9, 11, 11, 6, 4, 2, 8, 10, 12, 12, 8, 5, 3, 24, 27,
+ 29, 32, 31, 29, 26, 23, 26, 28, 30, 32, 29, 25, 22, 24, 27, 29, 31, 29, 25,
+ 21, 23, 26, 28, 31, 28, 27, 20, 23, 25, 28, 31, 29, 26, 19, 23, 25, 27, 30,
+ 29, 27, 16, 20, 23, 26, 29, 28, 27, 22, 24, 27, 30, 28, 25, 24, 21, 24, 26,
+ 29, 28, 26, 24, 19, 22, 25, 28, 27, 25, 24, 18, 22, 24, 27, 26, 25, 23, 18,
+ 21, 24, 27, 26, 26, 24, 16, 19, 22, 24, 25, 25, 24, 13, 16, 21, 24, 25, 24,
+ 24, 19, 22, 23, 24, 24, 23, 19, 18, 20, 23, 23, 24, 23, 19, 17, 20, 22, 22,
+ 22, 23, 19, 16, 19, 21, 21, 22, 23, 20, 14, 18, 19, 20, 21, 22, 19, 11, 16,
+ 18, 19, 19, 20, 20, 13, 14, 16, 17, 19, 19, 18, 17, 18, 17, 18, 18, 17, 8,
+ 15, 15, 16, 16, 17, 16, 9, 13, 14, 15, 15, 15, 15, 10, 9, 14, 14, 14, 15,
+ 15, 11, 9, 12, 12, 13, 13, 14, 8, 10, 10, 10, 11, 11, 12, 6, 13, 13, 10,
+ 9, 10, 10, 6, 8, 9, 9, 9, 10, 6, 8, 4, 7, 7, 8, 8, 6, 9, 4,
+ 6, 5, 6, 6, 5, 7, 4, 4, 4, 4, 5, 5, 7, 5, 4, 4, 4, 4, 3,
+ 6, 7, 7, 7, 6, 4, 3, 4, 10, 10, 8, 6, 5, 3, 4, 0, 2, 2, 2,
+ 2, 5, 7, 0, 3, 2, 2, 1, 4, 8, 0, 4, 3, 2, 1, 3, 6, 0, 3,
+ 3, 2, 1, 2, 5, 2, 3, 5, 5, 3, 3, 4, 5, 6, 9, 8, 5, 3, 3,
+ 8, 9, 10, 9, 6, 4, 3, 4, 7, 6, 3, 2, 3, 6, 4, 7, 7, 4, 2,
+ 2, 5, 4, 7, 9, 4, 2, 0, 5, 4, 7, 10, 6, 3, 2, 3, 4, 7, 11,
+ 9, 5, 3, 3, 5, 9, 12, 11, 7, 4, 3, 7, 11, 12, 13, 8, 5, 3, 25,
+ 29, 32, 33, 34, 31, 29, 25, 27, 31, 34, 34, 32, 29, 23, 26, 29, 32, 34, 31,
+ 29, 21, 24, 28, 32, 34, 33, 30, 21, 24, 28, 32, 35, 33, 30, 20, 23, 27, 31,
+ 34, 33, 30, 18, 23, 25, 30, 33, 33, 31, 23, 25, 29, 31, 30, 27, 25, 21, 25,
+ 28, 31, 30, 27, 25, 21, 24, 27, 30, 29, 27, 25, 19, 22, 27, 28, 29, 29, 25,
+ 20, 22, 26, 29, 29, 28, 26, 19, 21, 24, 28, 28, 28, 25, 15, 19, 23, 27, 27,
+ 27, 26, 21, 25, 25, 26, 26, 24, 19, 19, 22, 25, 24, 25, 24, 19, 18, 22, 23,
+ 23, 24, 24, 20, 17, 21, 22, 23, 23, 23, 20, 14, 20, 22, 21, 22, 22, 21, 12,
+ 18, 20, 21, 21, 22, 20, 13, 16, 18, 19, 20, 20, 18, 19, 19, 19, 19, 19, 18,
+ 7, 16, 17, 18, 17, 18, 16, 9, 13, 16, 16, 17, 16, 15, 10, 10, 16, 16, 15,
+ 16, 15, 12, 11, 14, 15, 15, 14, 14, 9, 11, 12, 13, 13, 13, 13, 6, 14, 14,
+ 10, 11, 12, 12, 6, 8, 10, 10, 11, 10, 6, 7, 5, 9, 9, 9, 9, 6, 9,
+ 5, 8, 7, 7, 7, 5, 6, 5, 6, 6, 6, 7, 4, 6, 6, 5, 5, 5, 5,
+ 4, 6, 8, 9, 10, 9, 6, 5, 5, 11, 14, 14, 11, 8, 6, 4, 2, 0, 1,
+ 1, 3, 5, 6, 2, 2, 2, 2, 2, 4, 6, 2, 4, 4, 4, 1, 4, 7, 2,
+ 5, 7, 7, 4, 3, 5, 3, 7, 12, 11, 9, 6, 4, 6, 12, 16, 13, 11, 7,
+ 4, 12, 16, 16, 14, 12, 8, 5, 6, 11, 11, 6, 1, 3, 5, 6, 12, 12, 8,
+ 2, 3, 5, 6, 11, 13, 9, 4, 2, 5, 6, 12, 14, 12, 8, 4, 4, 8, 13,
+ 16, 15, 12, 8, 5, 10, 15, 17, 16, 13, 10, 6, 14, 17, 18, 17, 14, 11, 7,
+ 24, 27, 31, 33, 34, 31, 28, 23, 27, 29, 33, 34, 31, 28, 22, 25, 29, 32, 33,
+ 31, 28, 21, 25, 28, 31, 35, 32, 29, 22, 24, 28, 31, 35, 33, 30, 21, 24, 26,
+ 30, 34, 33, 29, 18, 21, 25, 29, 33, 33, 30, 21, 24, 28, 31, 29, 26, 24, 21,
+ 24, 27, 30, 30, 26, 23, 20, 23, 26, 28, 30, 27, 25, 19, 22, 26, 29, 29, 28,
+ 24, 20, 22, 26, 28, 28, 28, 25, 18, 21, 24, 27, 28, 27, 25, 16, 19, 23, 26,
+ 26, 27, 24, 20, 23, 24, 24, 24, 22, 17, 19, 21, 23, 24, 23, 22, 17, 18, 21,
+ 22, 23, 23, 21, 18, 16, 21, 22, 22, 23, 22, 18, 14, 20, 22, 22, 22, 22, 18,
+ 12, 18, 20, 20, 21, 21, 19, 15, 17, 19, 19, 19, 19, 17, 18, 17, 17, 17, 18,
+ 15, 6, 16, 16, 16, 16, 17, 14, 7, 12, 15, 16, 15, 15, 14, 9, 9, 16, 15,
+ 15, 15, 14, 12, 10, 14, 14, 15, 14, 13, 9, 12, 12, 12, 13, 13, 12, 6, 15,
+ 16, 11, 11, 12, 11, 5, 8, 10, 10, 10, 9, 4, 6, 4, 9, 8, 8, 8, 4,
+ 7, 4, 8, 7, 7, 7, 4, 6, 4, 6, 7, 6, 7, 4, 5, 6, 6, 6, 6,
+ 6, 5, 5, 8, 10, 12, 10, 7, 6, 5, 12, 16, 15, 12, 9, 7, 5, 2, 1,
+ 0, 1, 2, 3, 4, 2, 2, 2, 2, 2, 3, 4, 2, 4, 4, 4, 1, 3, 5,
+ 2, 6, 8, 8, 5, 4, 5, 4, 8, 13, 13, 9, 7, 5, 8, 13, 19, 18, 12,
+ 8, 5, 13, 18, 20, 19, 14, 9, 6, 6, 12, 11, 5, 1, 2, 4, 6, 12, 13,
+ 7, 1, 2, 4, 6, 12, 15, 9, 5, 2, 4, 6, 13, 18, 13, 9, 6, 5, 9,
+ 15, 21, 19, 13, 9, 6, 12, 18, 24, 23, 16, 10, 7, 16, 21, 25, 25, 18, 12,
+ 8, 24, 27, 30, 33, 33, 31, 26, 23, 26, 30, 33, 33, 31, 27, 21, 24, 28, 32,
+ 33, 31, 28, 21, 24, 29, 32, 35, 32, 29, 21, 24, 28, 31, 35, 33, 30, 20, 23,
+ 27, 30, 34, 32, 28, 19, 21, 26, 29, 33, 33, 29, 21, 25, 27, 31, 28, 26, 22,
+ 21, 23, 27, 30, 28, 26, 23, 19, 22, 26, 28, 29, 28, 23, 19, 23, 26, 29, 29,
+ 28, 24, 20, 23, 25, 28, 29, 28, 25, 18, 22, 24, 28, 28, 27, 25, 16, 19, 23,
+ 27, 27, 26, 24, 20, 23, 23, 24, 23, 21, 16, 19, 21, 23, 23, 23, 21, 16, 18,
+ 20, 22, 22, 22, 22, 17, 16, 21, 22, 22, 22, 22, 18, 15, 20, 22, 22, 22, 21,
+ 17, 13, 19, 20, 20, 21, 20, 18, 16, 18, 19, 19, 19, 19, 17, 18, 17, 17, 17,
+ 17, 14, 5, 16, 17, 16, 16, 15, 13, 6, 13, 15, 16, 15, 15, 13, 9, 9, 16,
+ 15, 15, 15, 13, 12, 11, 15, 14, 15, 14, 13, 8, 12, 13, 13, 13, 13, 12, 6,
+ 16, 17, 13, 11, 12, 11, 5, 8, 10, 10, 9, 8, 3, 5, 5, 9, 8, 8, 7,
+ 3, 6, 5, 8, 7, 7, 7, 3, 5, 5, 6, 7, 7, 7, 4, 5, 6, 6, 7,
+ 7, 7, 7, 5, 9, 12, 13, 11, 9, 7, 5, 14, 17, 17, 13, 10, 8, 6, 2,
+ 1, 1, 0, 2, 3, 4, 2, 3, 2, 2, 2, 3, 3, 2, 4, 4, 5, 2, 3,
+ 4, 2, 6, 9, 9, 6, 5, 5, 4, 9, 14, 13, 10, 8, 6, 9, 14, 20, 18,
+ 12, 9, 7, 15, 19, 21, 20, 15, 10, 7, 6, 9, 7, 4, 0, 2, 3, 6, 9,
+ 8, 5, 2, 2, 3, 6, 9, 10, 8, 5, 3, 4, 6, 11, 15, 12, 9, 7, 6,
+ 10, 14, 19, 18, 14, 10, 8, 13, 19, 23, 23, 16, 11, 8, 18, 22, 24, 24, 19,
+ 13, 9, 20, 23, 27, 30, 30, 28, 24, 19, 23, 26, 29, 29, 27, 24, 18, 21, 25,
+ 28, 31, 29, 26, 17, 21, 25, 28, 31, 29, 26, 18, 22, 24, 28, 32, 29, 26, 18,
+ 21, 24, 27, 32, 29, 25, 16, 19, 23, 26, 29, 29, 26, 18, 21, 24, 27, 27, 22,
+ 19, 18, 20, 23, 26, 26, 23, 20, 17, 19, 22, 26, 26, 24, 21, 16, 19, 23, 26,
+ 26, 25, 22, 17, 20, 23, 26, 25, 25, 21, 15, 18, 22, 24, 24, 24, 21, 17, 18,
+ 20, 23, 23, 23, 21, 17, 19, 19, 20, 21, 17, 13, 16, 18, 19, 19, 19, 18, 14,
+ 15, 18, 19, 20, 20, 19, 14, 15, 18, 20, 19, 20, 19, 15, 13, 17, 19, 18, 19,
+ 19, 16, 12, 16, 17, 18, 17, 18, 15, 19, 19, 16, 16, 17, 16, 15, 15, 14, 13,
+ 14, 14, 12, 3, 14, 13, 13, 13, 12, 11, 4, 11, 12, 12, 13, 12, 11, 7, 8,
+ 13, 13, 12, 12, 12, 9, 9, 12, 12, 11, 11, 10, 7, 12, 14, 12, 11, 10, 10,
+ 5, 19, 20, 15, 12, 9, 9, 6, 7, 6, 6, 6, 5, 2, 3, 3, 5, 5, 4,
+ 4, 3, 4, 3, 4, 3, 4, 4, 3, 4, 3, 3, 4, 5, 5, 5, 5, 5, 9,
+ 9, 9, 9, 8, 6, 10, 15, 16, 13, 10, 8, 6, 17, 20, 19, 15, 12, 9, 7,
+ 2, 3, 2, 2, 0, 2, 3, 2, 4, 3, 2, 2, 2, 3, 2, 6, 4, 4, 4,
+ 3, 4, 2, 7, 8, 8, 7, 6, 6, 7, 12, 14, 13, 12, 9, 7, 12, 16, 20,
+ 18, 13, 10, 8, 18, 21, 22, 19, 15, 11, 8, 7, 9, 5, 3, 2, 1, 2, 7,
+ 9, 7, 3, 2, 2, 3, 7, 9, 9, 6, 5, 5, 4, 7, 9, 13, 11, 9, 8,
+ 8, 9, 14, 17, 17, 14, 11, 8, 15, 18, 21, 22, 16, 13, 9, 19, 23, 23, 23,
+ 18, 14, 10, 16, 20, 23, 26, 25, 23, 20, 15, 18, 21, 25, 25, 24, 20, 14, 17,
+ 21, 25, 26, 24, 21, 14, 18, 21, 24, 28, 25, 22, 14, 18, 20, 25, 28, 26, 22,
+ 13, 17, 20, 23, 27, 26, 23, 17, 17, 19, 22, 25, 26, 22, 14, 17, 20, 23, 22,
+ 19, 15, 14, 16, 19, 22, 22, 20, 17, 12, 15, 18, 22, 22, 20, 17, 12, 15, 19,
+ 22, 22, 21, 18, 12, 16, 18, 21, 22, 21, 18, 12, 15, 18, 21, 21, 20, 18, 19,
+ 18, 17, 19, 19, 20, 18, 13, 15, 16, 16, 17, 14, 11, 12, 14, 15, 15, 16, 15,
+ 11, 11, 13, 14, 16, 16, 16, 12, 11, 13, 15, 15, 15, 15, 13, 9, 13, 15, 14,
+ 15, 15, 13, 14, 15, 14, 14, 14, 14, 13, 22, 20, 17, 13, 13, 13, 12, 11, 10,
+ 9, 9, 9, 9, 2, 10, 9, 9, 8, 9, 8, 3, 8, 8, 8, 9, 9, 9, 4,
+ 6, 8, 8, 9, 9, 8, 7, 7, 8, 9, 9, 9, 8, 6, 14, 16, 14, 13, 10,
+ 8, 7, 21, 23, 18, 13, 11, 9, 7, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1,
+ 1, 1, 2, 3, 2, 2, 2, 3, 4, 3, 4, 2, 5, 6, 7, 7, 7, 7, 6,
+ 11, 12, 11, 11, 9, 7, 13, 18, 19, 15, 13, 10, 8, 20, 22, 21, 17, 14, 11,
+ 9, 5, 5, 3, 3, 2, 0, 2, 5, 6, 4, 3, 2, 2, 3, 5, 8, 6, 6,
+ 5, 5, 4, 5, 9, 11, 10, 9, 9, 8, 9, 14, 17, 15, 14, 12, 8, 15, 19,
+ 23, 20, 15, 12, 10, 21, 23, 24, 21, 17, 13, 10, 9, 11, 7, 4, 3, 2, 1,
+ 9, 11, 9, 5, 3, 3, 3, 9, 11, 11, 8, 7, 6, 6, 9, 12, 15, 13, 11,
+ 10, 10, 12, 16, 20, 19, 16, 13, 11, 17, 21, 24, 24, 19, 15, 11, 21, 24, 25,
+ 25, 20, 16, 12, 12, 15, 18, 20, 20, 17, 15, 11, 14, 17, 20, 20, 18, 16, 10,
+ 13, 16, 20, 21, 20, 17, 10, 13, 17, 20, 23, 20, 18, 10, 14, 16, 20, 24, 21,
+ 18, 11, 13, 16, 19, 23, 22, 18, 18, 17, 16, 18, 21, 22, 18, 11, 13, 16, 18,
+ 17, 14, 11, 9, 12, 15, 17, 16, 15, 13, 8, 11, 15, 18, 17, 16, 14, 7, 11,
+ 15, 18, 17, 17, 14, 8, 11, 14, 17, 17, 16, 14, 12, 14, 15, 16, 16, 16, 14,
+ 20, 19, 17, 16, 15, 15, 14, 8, 11, 12, 12, 12, 10, 7, 7, 10, 11, 11, 11,
+ 10, 7, 7, 9, 10, 11, 11, 11, 8, 6, 9, 11, 11, 11, 11, 9, 7, 10, 11,
+ 11, 11, 11, 9, 16, 16, 15, 13, 11, 9, 9, 22, 21, 17, 14, 11, 9, 8, 6,
+ 6, 5, 5, 5, 6, 1, 6, 5, 4, 4, 4, 4, 2, 5, 3, 4, 5, 4, 4,
+ 3, 8, 3, 5, 6, 6, 6, 6, 8, 9, 9, 10, 10, 9, 7, 16, 17, 15, 14,
+ 11, 9, 7, 23, 24, 18, 15, 12, 10, 8, 3, 2, 2, 2, 2, 1, 1, 5, 3,
+ 2, 2, 2, 2, 2, 4, 4, 3, 4, 5, 5, 4, 5, 7, 7, 8, 9, 8, 7,
+ 8, 13, 13, 13, 12, 11, 8, 15, 19, 20, 17, 14, 12, 9, 22, 24, 23, 18, 16,
+ 13, 10, 7, 6, 4, 3, 3, 2, 0, 7, 8, 5, 4, 3, 3, 3, 7, 10, 7,
+ 8, 7, 6, 6, 7, 11, 13, 13, 11, 10, 9, 11, 16, 20, 19, 16, 13, 10, 17,
+ 21, 26, 24, 19, 14, 11, 22, 25, 28, 25, 21, 16, 12, 10, 13, 10, 6, 3, 2,
+ 2, 11, 13, 12, 7, 4, 4, 4, 11, 13, 16, 11, 9, 8, 7, 11, 15, 21, 17,
+ 14, 12, 11, 14, 21, 24, 24, 20, 16, 12, 19, 24, 30, 30, 22, 17, 13, 25, 29,
+ 31, 30, 25, 19, 14, 23, 27, 29, 32, 32, 30, 27, 22, 25, 28, 31, 31, 29, 26,
+ 21, 24, 27, 29, 31, 28, 26, 20, 23, 26, 29, 30, 29, 27, 20, 23, 26, 28, 30,
+ 29, 26, 19, 21, 25, 27, 30, 28, 27, 16, 20, 23, 27, 29, 28, 27, 22, 24, 27,
+ 29, 29, 26, 24, 20, 24, 27, 28, 28, 26, 24, 20, 22, 26, 28, 26, 25, 22, 18,
+ 22, 24, 27, 26, 26, 24, 18, 21, 24, 26, 26, 26, 24, 16, 19, 22, 24, 25, 25,
+ 24, 13, 17, 21, 24, 24, 24, 24, 19, 22, 23, 25, 25, 23, 20, 18, 21, 22, 23,
+ 23, 23, 19, 17, 20, 22, 22, 22, 22, 19, 15, 19, 21, 21, 22, 22, 20, 14, 18,
+ 20, 20, 21, 21, 20, 11, 16, 18, 18, 19, 20, 20, 13, 14, 16, 17, 18, 19, 19,
+ 17, 17, 17, 18, 18, 18, 8, 15, 15, 16, 16, 17, 16, 9, 13, 15, 15, 15, 16,
+ 15, 9, 9, 13, 14, 14, 14, 14, 12, 9, 12, 13, 13, 13, 13, 8, 10, 10, 10,
+ 11, 12, 12, 6, 13, 13, 9, 9, 10, 10, 6, 7, 9, 9, 9, 10, 6, 7, 4,
+ 7, 8, 8, 8, 6, 9, 4, 6, 6, 6, 6, 5, 7, 4, 4, 4, 4, 5, 4,
+ 7, 5, 4, 4, 4, 4, 3, 6, 7, 7, 7, 6, 4, 3, 5, 10, 10, 8, 6,
+ 5, 3, 3, 0, 2, 2, 2, 2, 5, 7, 0, 3, 2, 2, 2, 4, 8, 0, 4,
+ 3, 2, 1, 3, 6, 0, 3, 3, 2, 1, 2, 5, 2, 3, 5, 5, 3, 3, 3,
+ 5, 6, 9, 8, 5, 3, 3, 8, 8, 10, 9, 6, 4, 3, 4, 7, 6, 3, 2,
+ 3, 6, 4, 7, 7, 4, 2, 2, 5, 4, 7, 9, 4, 2, 0, 4, 4, 7, 10,
+ 5, 3, 2, 3, 4, 7, 11, 9, 5, 3, 3, 5, 9, 12, 11, 7, 4, 3, 7,
+ 11, 12, 12, 8, 5, 3, 28, 31, 34, 36, 36, 33, 31, 26, 29, 33, 36, 37, 35,
+ 32, 25, 29, 32, 35, 37, 34, 31, 24, 27, 31, 34, 36, 34, 32, 24, 27, 31, 34,
+ 37, 36, 31, 23, 25, 30, 33, 36, 35, 32, 20, 24, 28, 32, 35, 35, 32, 25, 29,
+ 32, 34, 34, 31, 27, 24, 27, 30, 33, 32, 30, 27, 22, 26, 29, 32, 32, 30, 28,
+ 22, 25, 29, 32, 32, 31, 28, 23, 24, 28, 32, 31, 31, 28, 20, 24, 27, 30, 30,
+ 31, 29, 17, 20, 25, 29, 29, 29, 28, 23, 26, 27, 28, 28, 26, 21, 22, 25, 27,
+ 26, 27, 25, 21, 21, 24, 25, 26, 25, 27, 22, 18, 23, 26, 24, 26, 25, 22, 16,
+ 22, 24, 24, 25, 24, 23, 13, 20, 22, 23, 23, 24, 22, 14, 17, 20, 22, 22, 23,
+ 21, 20, 20, 21, 22, 22, 19, 10, 18, 19, 20, 20, 21, 19, 11, 15, 18, 18, 18,
+ 19, 17, 12, 11, 18, 18, 18, 18, 17, 14, 12, 16, 17, 17, 17, 16, 11, 12, 14,
+ 14, 15, 15, 15, 8, 14, 13, 12, 13, 14, 13, 8, 10, 12, 13, 13, 12, 7, 10,
+ 6, 11, 11, 11, 11, 7, 10, 6, 10, 9, 9, 9, 7, 9, 6, 8, 8, 8, 9,
+ 6, 7, 7, 5, 7, 7, 7, 4, 7, 8, 7, 9, 8, 5, 4, 6, 10, 12, 12,
+ 9, 7, 5, 5, 3, 2, 2, 3, 4, 6, 8, 3, 0, 1, 1, 3, 7, 8, 3,
+ 2, 2, 2, 2, 5, 8, 3, 3, 5, 5, 2, 3, 6, 4, 5, 8, 7, 7, 5,
+ 5, 5, 9, 11, 9, 8, 6, 4, 11, 13, 12, 10, 8, 7, 4, 4, 8, 7, 4,
+ 3, 4, 7, 4, 8, 7, 5, 2, 4, 7, 4, 7, 9, 6, 2, 4, 6, 4, 8,
+ 10, 7, 6, 4, 4, 6, 9, 10, 9, 8, 7, 4, 8, 10, 12, 12, 9, 7, 5,
+ 11, 12, 13, 13, 10, 8, 6, 26, 29, 33, 35, 36, 33, 29, 25, 29, 32, 35, 35,
+ 33, 30, 23, 27, 31, 33, 35, 35, 30, 22, 26, 30, 34, 37, 34, 31, 23, 25, 29,
+ 33, 37, 34, 31, 23, 25, 29, 33, 37, 35, 31, 20, 24, 27, 32, 34, 34, 31, 23,
+ 27, 30, 33, 32, 28, 25, 23, 26, 29, 32, 32, 29, 25, 22, 24, 28, 31, 31, 29,
+ 26, 21, 25, 28, 31, 31, 29, 27, 21, 23, 27, 31, 31, 30, 26, 20, 23, 26, 29,
+ 30, 30, 26, 17, 21, 25, 27, 28, 29, 27, 22, 25, 26, 26, 26, 23, 19, 21, 24,
+ 25, 25, 25, 24, 18, 20, 22, 24, 24, 24, 24, 19, 17, 23, 24, 24, 25, 24, 20,
+ 15, 22, 23, 23, 24, 23, 20, 13, 20, 22, 22, 22, 22, 20, 15, 18, 20, 21, 21,
+ 21, 19, 19, 19, 19, 19, 19, 16, 7, 17, 18, 18, 18, 18, 15, 9, 13, 17, 17,
+ 17, 17, 15, 10, 10, 17, 17, 17, 17, 15, 13, 12, 16, 16, 16, 16, 14, 10, 12,
+ 14, 14, 14, 15, 14, 7, 15, 15, 12, 13, 13, 13, 5, 9, 11, 12, 11, 10, 5,
+ 7, 6, 11, 10, 10, 9, 5, 8, 6, 9, 9, 9, 8, 5, 7, 5, 7, 8, 8,
+ 8, 4, 6, 7, 5, 7, 7, 7, 5, 5, 9, 9, 11, 9, 7, 6, 5, 12, 14,
+ 14, 10, 8, 7, 5, 2, 2, 2, 2, 3, 4, 5, 2, 1, 0, 1, 2, 4, 5,
+ 2, 2, 2, 2, 2, 4, 6, 2, 4, 6, 6, 4, 4, 5, 4, 7, 11, 11, 9,
+ 7, 5, 7, 12, 17, 15, 11, 8, 5, 12, 16, 19, 18, 13, 9, 6, 4, 10, 9,
+ 4, 2, 3, 4, 4, 10, 12, 6, 1, 3, 4, 4, 10, 14, 8, 3, 3, 4, 4,
+ 11, 17, 12, 7, 5, 5, 7, 13, 19, 17, 12, 9, 6, 10, 17, 22, 21, 15, 10,
+ 7, 15, 19, 23, 23, 17, 11, 8, 26, 28, 32, 35, 35, 32, 29, 25, 27, 31, 34,
+ 35, 31, 29, 23, 26, 30, 34, 35, 33, 29, 22, 25, 30, 33, 36, 34, 31, 23, 25,
+ 29, 33, 37, 35, 29, 23, 25, 28, 32, 35, 34, 32, 20, 23, 27, 31, 34, 34, 31,
+ 23, 26, 29, 32, 31, 27, 23, 22, 25, 29, 32, 30, 27, 24, 22, 24, 28, 31, 31,
+ 29, 25, 21, 24, 27, 31, 31, 30, 25, 21, 24, 27, 30, 30, 29, 26, 20, 23, 26,
+ 30, 29, 29, 25, 18, 21, 24, 28, 27, 28, 25, 22, 24, 25, 25, 25, 23, 17, 20,
+ 22, 25, 25, 24, 22, 17, 19, 22, 24, 24, 24, 22, 17, 17, 23, 23, 23, 24, 23,
+ 19, 15, 23, 23, 24, 23, 23, 19, 13, 20, 22, 22, 22, 22, 19, 15, 19, 20, 20,
+ 21, 21, 18, 20, 19, 18, 18, 18, 15, 6, 17, 18, 18, 17, 17, 14, 8, 13, 17,
+ 17, 17, 16, 14, 10, 10, 17, 17, 17, 17, 14, 13, 12, 16, 16, 16, 15, 14, 10,
+ 13, 14, 14, 14, 14, 13, 7, 16, 16, 13, 13, 13, 13, 5, 9, 12, 11, 11, 9,
+ 4, 6, 6, 10, 10, 9, 8, 4, 8, 6, 9, 8, 9, 8, 4, 6, 5, 7, 9,
+ 8, 8, 4, 6, 7, 6, 7, 7, 7, 6, 5, 9, 10, 12, 10, 8, 7, 5, 13,
+ 16, 15, 12, 9, 8, 6, 2, 2, 2, 2, 2, 3, 4, 2, 1, 1, 0, 2, 3,
+ 4, 2, 2, 3, 3, 2, 3, 4, 2, 4, 7, 7, 5, 5, 5, 4, 8, 12, 11,
+ 9, 8, 6, 8, 13, 18, 16, 11, 8, 6, 14, 18, 20, 18, 13, 9, 7, 5, 8,
+ 7, 3, 1, 2, 3, 5, 8, 8, 4, 0, 2, 4, 5, 8, 10, 7, 4, 3, 4,
+ 5, 10, 14, 11, 8, 6, 6, 8, 13, 18, 17, 12, 9, 7, 11, 17, 22, 22, 15,
+ 11, 8, 16, 21, 23, 23, 18, 12, 8, 22, 25, 28, 31, 32, 29, 26, 21, 23, 27,
+ 31, 32, 27, 25, 19, 23, 26, 29, 32, 29, 27, 19, 23, 26, 30, 32, 30, 27, 20,
+ 22, 26, 29, 32, 31, 28, 19, 22, 25, 29, 32, 30, 27, 17, 20, 24, 27, 31, 31,
+ 27, 20, 23, 26, 29, 28, 24, 21, 18, 22, 25, 28, 27, 24, 21, 18, 20, 24, 27,
+ 27, 26, 21, 17, 21, 25, 27, 26, 25, 22, 19, 21, 24, 26, 26, 26, 22, 16, 20,
+ 22, 25, 26, 26, 23, 16, 18, 21, 24, 25, 24, 22, 18, 20, 21, 22, 23, 19, 15,
+ 17, 19, 21, 21, 21, 20, 15, 17, 19, 20, 20, 20, 20, 15, 15, 19, 20, 20, 21,
+ 20, 16, 14, 19, 20, 20, 20, 19, 16, 12, 17, 18, 19, 19, 18, 16, 17, 17, 17,
+ 17, 17, 17, 16, 16, 15, 15, 15, 16, 13, 4, 14, 14, 14, 14, 14, 12, 5, 12,
+ 14, 13, 14, 13, 12, 8, 8, 14, 14, 13, 13, 12, 10, 10, 13, 13, 13, 12, 11,
+ 7, 12, 12, 11, 11, 11, 11, 5, 17, 18, 14, 10, 10, 10, 5, 7, 8, 7, 7,
+ 7, 3, 4, 3, 7, 6, 6, 6, 3, 5, 3, 6, 5, 6, 5, 3, 4, 3, 4,
+ 5, 5, 5, 4, 4, 5, 7, 8, 8, 8, 7, 5, 9, 13, 14, 12, 9, 7, 6,
+ 15, 18, 18, 13, 11, 8, 6, 1, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 0,
+ 3, 3, 2, 4, 3, 3, 3, 2, 3, 2, 6, 8, 7, 6, 5, 5, 6, 10, 13,
+ 12, 10, 8, 6, 11, 16, 19, 16, 12, 9, 7, 16, 20, 21, 18, 14, 10, 7, 6,
+ 7, 5, 3, 1, 2, 2, 6, 7, 7, 3, 2, 2, 3, 5, 7, 8, 5, 4, 3,
+ 3, 6, 8, 12, 10, 8, 7, 7, 9, 12, 16, 16, 13, 10, 7, 13, 17, 20, 21,
+ 15, 12, 8, 18, 21, 21, 21, 17, 13, 9, 17, 21, 24, 28, 28, 26, 22, 17, 19,
+ 24, 28, 28, 24, 21, 15, 19, 22, 25, 27, 25, 22, 15, 18, 21, 25, 29, 26, 22,
+ 15, 18, 21, 24, 28, 26, 23, 14, 17, 20, 24, 28, 26, 23, 15, 16, 19, 23, 25,
+ 27, 23, 16, 19, 22, 25, 24, 22, 18, 14, 18, 21, 23, 23, 21, 16, 13, 16, 20,
+ 22, 22, 20, 18, 13, 16, 20, 23, 22, 22, 19, 13, 16, 19, 22, 22, 21, 19, 12,
+ 14, 18, 21, 21, 21, 19, 17, 16, 17, 19, 20, 20, 18, 14, 16, 17, 18, 19, 17,
+ 13, 13, 15, 16, 17, 17, 16, 12, 12, 14, 15, 16, 16, 16, 12, 11, 14, 16, 16,
+ 16, 16, 13, 11, 14, 15, 15, 15, 15, 13, 12, 13, 14, 14, 14, 14, 13, 19, 18,
+ 14, 13, 13, 13, 12, 12, 11, 10, 11, 12, 12, 4, 11, 10, 10, 10, 10, 10, 3,
+ 9, 9, 9, 9, 9, 9, 4, 6, 9, 9, 9, 9, 9, 7, 7, 8, 8, 8, 8,
+ 7, 4, 12, 14, 12, 10, 8, 7, 4, 18, 20, 14, 12, 9, 7, 5, 4, 3, 3,
+ 3, 4, 3, 4, 1, 2, 2, 2, 2, 2, 3, 1, 1, 1, 2, 2, 2, 3, 1,
+ 5, 5, 5, 5, 4, 4, 5, 10, 9, 9, 9, 7, 5, 12, 15, 16, 13, 10, 8,
+ 6, 17, 20, 18, 14, 11, 9, 6, 4, 5, 3, 3, 2, 2, 3, 4, 6, 4, 3,
+ 2, 0, 2, 4, 7, 5, 5, 3, 3, 2, 4, 8, 9, 8, 7, 6, 5, 8, 12,
+ 14, 13, 11, 9, 6, 12, 16, 20, 17, 12, 10, 7, 18, 21, 21, 19, 14, 11, 8,
+ 8, 10, 6, 4, 3, 2, 2, 8, 10, 8, 5, 3, 2, 1, 8, 10, 10, 7, 5,
+ 4, 3, 9, 10, 14, 11, 9, 8, 7, 10, 14, 17, 16, 14, 11, 8, 14, 18, 21,
+ 21, 16, 12, 9, 19, 21, 23, 22, 18, 13, 10, 14, 16, 21, 24, 24, 21, 18, 13,
+ 16, 19, 23, 24, 20, 17, 11, 14, 18, 21, 23, 20, 18, 10, 14, 18, 21, 24, 21,
+ 18, 11, 14, 17, 20, 24, 22, 18, 10, 13, 16, 19, 23, 22, 18, 15, 14, 15, 18,
+ 22, 21, 18, 11, 14, 18, 21, 20, 17, 14, 11, 14, 17, 20, 20, 16, 13, 9, 12,
+ 15, 18, 18, 16, 14, 9, 12, 15, 18, 17, 17, 14, 9, 12, 15, 17, 17, 17, 14,
+ 11, 12, 13, 16, 16, 16, 14, 18, 16, 14, 15, 15, 15, 14, 10, 12, 14, 14, 16,
+ 13, 9, 9, 11, 12, 13, 13, 12, 8, 7, 10, 12, 11, 11, 12, 8, 7, 10, 11,
+ 11, 11, 11, 9, 6, 9, 11, 11, 10, 10, 9, 13, 13, 12, 10, 9, 9, 9, 19,
+ 17, 15, 11, 9, 8, 8, 8, 7, 6, 7, 8, 9, 3, 7, 6, 6, 6, 6, 6,
+ 2, 6, 5, 5, 5, 4, 4, 2, 4, 5, 4, 4, 4, 4, 4, 7, 8, 8, 7,
+ 7, 6, 4, 14, 15, 13, 11, 8, 7, 5, 19, 20, 15, 12, 9, 7, 6, 2, 2,
+ 1, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2,
+ 3, 6, 6, 6, 6, 5, 5, 7, 11, 11, 10, 9, 8, 5, 13, 16, 16, 13, 11,
+ 9, 7, 19, 20, 19, 15, 12, 10, 7, 7, 6, 4, 3, 3, 3, 3, 7, 7, 5,
+ 4, 3, 2, 0, 7, 9, 6, 6, 4, 3, 3, 7, 10, 10, 10, 8, 7, 6, 9,
+ 14, 16, 15, 12, 10, 7, 15, 18, 22, 20, 14, 10, 8, 19, 21, 23, 21, 16, 12,
+ 9, 10, 12, 9, 5, 3, 3, 2, 10, 12, 11, 6, 3, 2, 2, 10, 12, 13, 9,
+ 6, 5, 4, 10, 13, 17, 13, 11, 9, 8, 13, 16, 21, 20, 16, 12, 9, 16, 21,
+ 25, 24, 18, 13, 10, 20, 23, 25, 26, 20, 15, 11, 24, 26, 29, 32, 32, 30, 26,
+ 23, 25, 28, 31, 31, 29, 26, 22, 24, 27, 29, 31, 28, 26, 20, 23, 26, 29, 30,
+ 29, 27, 20, 23, 26, 29, 31, 28, 27, 19, 22, 24, 27, 30, 29, 26, 16, 20, 24,
+ 26, 29, 29, 27, 22, 24, 27, 29, 28, 26, 23, 21, 24, 27, 29, 27, 25, 24, 19,
+ 23, 25, 27, 27, 25, 23, 18, 21, 25, 27, 25, 25, 25, 18, 21, 24, 27, 26, 25,
+ 25, 16, 19, 23, 25, 25, 25, 24, 13, 16, 20, 24, 24, 25, 24, 19, 23, 23, 24,
+ 25, 23, 19, 18, 21, 22, 23, 24, 22, 20, 17, 20, 22, 22, 22, 23, 19, 15, 19,
+ 21, 21, 22, 22, 20, 14, 19, 19, 20, 21, 22, 20, 11, 17, 18, 19, 20, 20, 19,
+ 13, 14, 16, 17, 18, 19, 19, 17, 17, 17, 18, 18, 18, 7, 15, 16, 16, 16, 17,
+ 16, 8, 13, 15, 15, 15, 15, 15, 10, 9, 14, 14, 14, 14, 14, 12, 9, 12, 12,
+ 13, 13, 14, 8, 10, 10, 10, 11, 11, 12, 6, 13, 13, 9, 9, 10, 10, 6, 8,
+ 8, 9, 10, 10, 6, 8, 4, 7, 7, 8, 8, 6, 9, 4, 6, 6, 5, 6, 5,
+ 8, 4, 4, 4, 4, 5, 5, 6, 5, 4, 4, 4, 4, 3, 6, 7, 7, 7, 6,
+ 4, 3, 5, 10, 10, 8, 6, 4, 3, 4, 0, 2, 2, 2, 2, 5, 7, 0, 3,
+ 2, 2, 2, 4, 8, 0, 4, 2, 2, 1, 4, 6, 0, 3, 3, 2, 1, 2, 5,
+ 2, 3, 5, 5, 3, 3, 4, 5, 6, 9, 8, 5, 3, 3, 8, 9, 10, 9, 6,
+ 4, 3, 4, 7, 6, 3, 2, 3, 6, 4, 7, 8, 4, 2, 2, 5, 4, 7, 9,
+ 4, 2, 0, 5, 4, 7, 10, 6, 3, 2, 3, 4, 7, 10, 9, 5, 4, 3, 5,
+ 9, 12, 11, 7, 4, 3, 7, 11, 12, 12, 8, 5, 3, 30, 32, 35, 39, 38, 37,
+ 32, 28, 32, 34, 37, 39, 36, 33, 27, 31, 33, 37, 38, 36, 32, 26, 29, 32, 35,
+ 38, 37, 34, 25, 28, 33, 36, 38, 37, 35, 24, 27, 31, 35, 38, 37, 35, 22, 25,
+ 31, 34, 36, 37, 34, 27, 31, 33, 36, 36, 32, 29, 26, 29, 33, 35, 34, 32, 28,
+ 24, 28, 32, 34, 35, 33, 30, 24, 27, 31, 34, 34, 33, 30, 23, 26, 29, 33, 32,
+ 33, 30, 21, 25, 29, 32, 32, 33, 30, 19, 22, 27, 30, 31, 31, 30, 24, 28, 28,
+ 29, 30, 28, 23, 23, 27, 28, 29, 29, 28, 22, 22, 25, 27, 28, 28, 28, 23, 20,
+ 25, 26, 27, 28, 27, 25, 17, 24, 25, 26, 26, 26, 24, 14, 23, 24, 24, 25, 26,
+ 24, 15, 19, 21, 23, 24, 25, 23, 22, 23, 23, 23, 23, 21, 11, 19, 21, 21, 21,
+ 22, 20, 12, 16, 20, 20, 20, 20, 19, 13, 12, 20, 19, 20, 19, 19, 16, 13, 17,
+ 18, 19, 19, 18, 12, 13, 15, 16, 17, 17, 17, 9, 15, 13, 14, 15, 16, 16, 8,
+ 10, 14, 14, 14, 14, 9, 11, 7, 12, 13, 13, 12, 9, 12, 7, 11, 11, 11, 11,
+ 7, 10, 7, 8, 10, 10, 10, 8, 9, 8, 6, 9, 8, 9, 6, 8, 9, 8, 8,
+ 7, 7, 4, 7, 11, 10, 9, 7, 5, 3, 6, 4, 3, 4, 4, 6, 8, 10, 4,
+ 2, 2, 2, 4, 7, 9, 4, 0, 1, 1, 3, 6, 8, 4, 1, 2, 1, 2, 4,
+ 7, 4, 3, 4, 4, 4, 3, 7, 6, 6, 8, 6, 5, 4, 5, 8, 9, 9, 6,
+ 5, 4, 4, 2, 5, 3, 2, 3, 6, 9, 2, 5, 4, 3, 2, 5, 9, 2, 5,
+ 5, 3, 0, 4, 7, 2, 5, 6, 2, 2, 3, 5, 2, 4, 7, 5, 4, 4, 4,
+ 5, 6, 8, 8, 5, 4, 4, 8, 8, 9, 9, 6, 5, 4, 29, 33, 36, 39, 39,
+ 36, 33, 28, 31, 34, 38, 38, 36, 32, 26, 29, 34, 37, 38, 35, 32, 25, 28, 31,
+ 36, 39, 36, 33, 25, 29, 31, 36, 39, 37, 34, 24, 27, 30, 34, 38, 37, 33, 22,
+ 26, 29, 33, 36, 37, 33, 26, 29, 34, 36, 34, 32, 29, 25, 29, 32, 36, 35, 32,
+ 27, 24, 27, 30, 34, 34, 31, 28, 23, 26, 30, 33, 33, 32, 28, 24, 27, 30, 32,
+ 32, 31, 29, 22, 25, 29, 32, 32, 32, 29, 19, 23, 27, 30, 30, 30, 28, 24, 27,
+ 28, 29, 30, 26, 22, 23, 25, 28, 28, 28, 27, 21, 22, 25, 27, 26, 27, 26, 21,
+ 18, 25, 25, 25, 26, 25, 21, 16, 24, 25, 25, 26, 25, 22, 13, 22, 24, 24, 24,
+ 24, 22, 15, 20, 22, 23, 23, 23, 20, 22, 22, 22, 22, 23, 19, 10, 18, 20, 21,
+ 22, 21, 18, 11, 15, 20, 20, 20, 19, 17, 12, 11, 19, 19, 19, 18, 16, 15, 13,
+ 17, 18, 18, 19, 16, 11, 13, 15, 16, 16, 16, 15, 8, 15, 14, 14, 15, 15, 14,
+ 6, 10, 14, 14, 14, 12, 6, 10, 7, 13, 12, 13, 11, 6, 11, 7, 11, 11, 11,
+ 10, 5, 8, 7, 8, 10, 10, 9, 5, 8, 8, 6, 9, 9, 8, 5, 6, 9, 8,
+ 9, 7, 7, 5, 6, 11, 12, 12, 9, 6, 5, 5, 3, 4, 4, 5, 4, 5, 7,
+ 3, 2, 2, 3, 3, 5, 6, 3, 1, 0, 0, 3, 5, 7, 2, 2, 4, 4, 2,
+ 4, 5, 4, 5, 9, 8, 8, 5, 5, 6, 10, 15, 13, 10, 6, 4, 10, 14, 17,
+ 15, 11, 8, 4, 2, 8, 8, 2, 3, 4, 6, 2, 8, 10, 4, 2, 4, 6, 2,
+ 8, 12, 5, 1, 3, 5, 2, 9, 14, 9, 5, 4, 5, 5, 11, 16, 14, 10, 8,
+ 4, 8, 14, 19, 18, 13, 9, 5, 13, 18, 19, 19, 15, 10, 6, 28, 32, 36, 38,
+ 38, 35, 33, 27, 30, 35, 37, 39, 36, 31, 26, 29, 33, 36, 39, 34, 32, 24, 27,
+ 31, 35, 37, 35, 32, 25, 27, 31, 35, 37, 36, 33, 23, 26, 30, 33, 37, 35, 33,
+ 21, 25, 29, 31, 35, 35, 32, 25, 29, 33, 37, 35, 31, 27, 25, 29, 31, 36, 34,
+ 32, 27, 24, 26, 31, 33, 33, 30, 26, 23, 25, 29, 32, 32, 30, 26, 22, 25, 29,
+ 32, 32, 31, 26, 21, 25, 27, 31, 30, 29, 27, 19, 22, 26, 30, 29, 28, 27, 24,
+ 26, 29, 29, 30, 27, 20, 22, 25, 28, 28, 28, 26, 20, 21, 23, 26, 26, 26, 24,
+ 19, 18, 25, 25, 24, 25, 23, 19, 16, 23, 24, 24, 24, 23, 20, 13, 22, 23, 23,
+ 23, 23, 20, 15, 20, 21, 21, 21, 22, 18, 20, 21, 21, 22, 23, 18, 11, 18, 20,
+ 20, 21, 21, 17, 11, 14, 19, 18, 19, 18, 15, 12, 11, 18, 18, 17, 18, 15, 14,
+ 12, 16, 17, 17, 17, 14, 11, 13, 15, 16, 16, 16, 13, 7, 14, 14, 14, 14, 15,
+ 13, 5, 9, 14, 13, 15, 12, 7, 11, 6, 13, 12, 13, 12, 6, 11, 6, 10, 11,
+ 10, 9, 4, 7, 6, 7, 10, 9, 8, 4, 7, 8, 6, 8, 8, 7, 4, 4, 9,
+ 8, 9, 8, 6, 4, 4, 11, 12, 12, 9, 6, 5, 4, 2, 4, 4, 5, 4, 6,
+ 8, 2, 2, 2, 3, 3, 5, 6, 2, 1, 0, 0, 3, 3, 5, 2, 2, 4, 4,
+ 2, 3, 4, 4, 5, 9, 8, 7, 5, 4, 6, 10, 15, 13, 9, 6, 4, 10, 14,
+ 16, 15, 10, 7, 4, 3, 7, 6, 2, 3, 5, 6, 3, 7, 7, 4, 2, 3, 4,
+ 3, 7, 8, 5, 1, 2, 4, 3, 8, 11, 9, 4, 4, 4, 5, 11, 15, 14, 9,
+ 7, 4, 8, 14, 19, 19, 12, 8, 5, 13, 17, 20, 20, 14, 9, 6, 24, 29, 32,
+ 35, 36, 33, 29, 23, 27, 31, 34, 35, 32, 28, 22, 25, 28, 33, 34, 31, 27, 20,
+ 22, 26, 30, 32, 30, 28, 21, 23, 26, 30, 34, 31, 27, 20, 22, 26, 29, 33, 31,
+ 27, 17, 21, 24, 27, 31, 32, 28, 22, 25, 30, 33, 31, 28, 25, 21, 23, 27, 31,
+ 32, 28, 23, 20, 22, 27, 29, 28, 26, 22, 19, 21, 24, 27, 27, 26, 22, 20, 21,
+ 24, 27, 27, 27, 22, 18, 20, 23, 25, 26, 26, 23, 14, 18, 22, 25, 25, 24, 22,
+ 20, 23, 24, 25, 27, 23, 19, 19, 21, 24, 24, 25, 22, 17, 18, 21, 22, 22, 22,
+ 21, 16, 16, 20, 21, 21, 21, 21, 16, 14, 20, 20, 20, 20, 19, 16, 11, 17, 19,
+ 19, 19, 19, 16, 14, 15, 17, 17, 18, 18, 15, 18, 18, 17, 18, 19, 17, 9, 15,
+ 16, 16, 17, 17, 15, 9, 12, 16, 15, 15, 14, 12, 8, 9, 16, 14, 13, 13, 12,
+ 11, 10, 14, 13, 13, 12, 11, 8, 11, 11, 11, 11, 11, 10, 4, 14, 14, 10, 10,
+ 10, 10, 3, 7, 9, 10, 10, 10, 6, 9, 4, 9, 8, 9, 9, 4, 9, 4, 7,
+ 6, 6, 6, 3, 5, 4, 6, 6, 5, 5, 2, 4, 6, 5, 5, 5, 5, 4, 3,
+ 7, 10, 11, 9, 6, 5, 3, 12, 14, 14, 10, 8, 6, 4, 1, 1, 1, 2, 4,
+ 5, 7, 1, 2, 2, 2, 3, 3, 4, 1, 3, 4, 3, 0, 2, 4, 1, 5, 5,
+ 4, 4, 3, 3, 3, 7, 10, 9, 8, 6, 4, 8, 12, 16, 13, 9, 6, 4, 13,
+ 16, 18, 15, 11, 7, 5, 5, 6, 5, 3, 2, 4, 5, 4, 6, 6, 4, 2, 2,
+ 3, 4, 6, 7, 3, 2, 1, 2, 4, 7, 9, 7, 6, 4, 4, 6, 9, 13, 13,
+ 10, 7, 5, 10, 14, 17, 17, 13, 9, 6, 15, 18, 18, 18, 14, 10, 6, 20, 24,
+ 28, 32, 32, 29, 25, 19, 23, 26, 31, 31, 28, 24, 17, 21, 25, 28, 30, 26, 23,
+ 17, 19, 23, 26, 29, 26, 23, 16, 18, 21, 25, 29, 27, 23, 15, 18, 21, 24, 27,
+ 26, 23, 12, 16, 19, 23, 26, 27, 23, 17, 21, 25, 29, 28, 24, 21, 16, 20, 24,
+ 28, 27, 24, 20, 16, 18, 23, 25, 25, 21, 18, 15, 17, 20, 23, 22, 22, 19, 14,
+ 17, 20, 22, 22, 22, 18, 12, 16, 18, 21, 21, 21, 18, 13, 14, 17, 20, 20, 20,
+ 19, 15, 18, 21, 22, 23, 20, 16, 14, 17, 19, 21, 21, 19, 15, 14, 16, 18, 18,
+ 18, 18, 13, 13, 16, 16, 16, 16, 16, 13, 12, 15, 16, 16, 16, 15, 13, 10, 12,
+ 14, 14, 14, 14, 13, 15, 15, 12, 12, 13, 13, 12, 14, 13, 13, 14, 15, 15, 7,
+ 13, 12, 12, 13, 13, 13, 6, 10, 11, 11, 10, 10, 10, 5, 6, 10, 9, 9, 9,
+ 9, 7, 7, 9, 8, 8, 8, 8, 4, 10, 10, 9, 7, 7, 7, 2, 15, 16, 11,
+ 8, 6, 5, 3, 5, 5, 6, 6, 7, 6, 7, 1, 3, 4, 5, 5, 4, 6, 1,
+ 2, 2, 2, 2, 2, 3, 1, 3, 2, 2, 2, 2, 2, 4, 7, 7, 6, 6, 4,
+ 2, 9, 12, 12, 10, 7, 5, 3, 14, 16, 15, 11, 9, 6, 4, 3, 4, 3, 3,
+ 3, 5, 6, 3, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 2, 0, 2, 4, 6,
+ 6, 5, 4, 3, 3, 6, 9, 11, 10, 8, 6, 4, 10, 13, 16, 14, 10, 7, 4,
+ 14, 16, 18, 15, 11, 8, 5, 7, 8, 7, 4, 3, 4, 4, 6, 8, 8, 5, 3,
+ 2, 2, 7, 8, 9, 5, 3, 2, 1, 7, 8, 11, 8, 6, 5, 4, 8, 11, 14,
+ 14, 11, 8, 5, 12, 15, 18, 18, 13, 9, 6, 16, 18, 19, 19, 14, 10, 7, 17,
+ 20, 25, 28, 28, 26, 21, 15, 19, 23, 27, 28, 25, 20, 14, 18, 21, 25, 27, 22,
+ 19, 12, 16, 19, 22, 24, 22, 19, 12, 14, 17, 21, 24, 23, 19, 10, 14, 16, 20,
+ 23, 22, 19, 11, 12, 15, 19, 22, 22, 19, 14, 17, 22, 25, 24, 22, 17, 13, 16,
+ 20, 24, 23, 20, 16, 12, 15, 19, 21, 21, 18, 15, 10, 13, 16, 18, 19, 17, 14,
+ 10, 13, 15, 18, 18, 18, 15, 9, 11, 14, 17, 17, 17, 14, 13, 12, 13, 15, 16,
+ 16, 14, 12, 15, 16, 18, 19, 17, 13, 10, 13, 16, 16, 17, 16, 12, 9, 12, 14,
+ 14, 14, 14, 10, 8, 11, 12, 12, 12, 12, 10, 7, 10, 11, 11, 11, 11, 10, 11,
+ 10, 10, 10, 10, 10, 9, 14, 13, 10, 9, 9, 9, 8, 9, 9, 10, 11, 12, 13,
+ 7, 8, 8, 9, 9, 10, 10, 5, 7, 6, 7, 7, 6, 7, 3, 4, 6, 5, 5,
+ 5, 5, 4, 6, 6, 5, 4, 5, 4, 2, 11, 11, 9, 7, 5, 4, 2, 14, 14,
+ 10, 8, 6, 4, 3, 0, 1, 2, 3, 4, 5, 6, 2, 2, 2, 3, 3, 3, 4,
+ 2, 3, 3, 2, 2, 1, 2, 2, 6, 4, 3, 3, 3, 2, 6, 9, 8, 7, 6,
+ 5, 2, 10, 12, 12, 9, 7, 6, 3, 13, 14, 14, 11, 8, 6, 4, 6, 6, 5,
+ 4, 4, 4, 6, 6, 8, 6, 4, 3, 2, 3, 6, 8, 7, 5, 3, 2, 0, 6,
+ 9, 8, 6, 5, 4, 3, 8, 11, 13, 11, 9, 6, 4, 11, 14, 17, 15, 10, 7,
+ 5, 14, 16, 18, 16, 12, 8, 6, 9, 10, 8, 6, 4, 4, 4, 10, 10, 10, 6,
+ 4, 2, 2, 9, 10, 11, 6, 4, 3, 2, 9, 11, 14, 10, 7, 6, 5, 10, 13,
+ 17, 15, 11, 8, 6, 13, 16, 20, 19, 13, 9, 6, 16, 19, 20, 20, 15, 11, 7,
+ 24, 27, 29, 31, 31, 31, 27, 23, 26, 28, 31, 32, 28, 27, 21, 24, 27, 30, 31,
+ 28, 25, 20, 24, 27, 29, 30, 29, 27, 20, 23, 26, 28, 30, 28, 26, 18, 22, 24,
+ 27, 31, 29, 26, 16, 20, 24, 26, 29, 28, 26, 21, 24, 28, 29, 28, 26, 23, 21,
+ 23, 25, 28, 28, 26, 23, 19, 23, 26, 28, 26, 26, 24, 18, 21, 25, 26, 26, 26,
+ 25, 17, 21, 24, 26, 25, 26, 24, 16, 19, 22, 25, 26, 25, 24, 13, 16, 21, 24,
+ 24, 25, 24, 19, 23, 24, 24, 25, 23, 20, 18, 21, 22, 23, 23, 23, 19, 17, 21,
+ 22, 22, 22, 23, 19, 15, 20, 21, 21, 22, 22, 20, 14, 18, 20, 20, 21, 21, 20,
+ 11, 16, 18, 19, 20, 20, 20, 13, 14, 16, 17, 18, 19, 19, 17, 17, 18, 18, 18,
+ 18, 8, 15, 15, 16, 17, 17, 16, 9, 13, 15, 15, 15, 15, 15, 10, 9, 13, 14,
+ 14, 15, 15, 12, 9, 12, 13, 13, 13, 14, 8, 10, 10, 10, 11, 11, 12, 6, 13,
+ 13, 9, 9, 10, 11, 6, 8, 8, 9, 9, 10, 6, 8, 4, 7, 8, 8, 8, 6,
+ 9, 4, 6, 5, 6, 6, 5, 7, 4, 4, 4, 4, 5, 5, 7, 5, 4, 4, 4,
+ 4, 3, 6, 7, 7, 7, 6, 4, 3, 5, 10, 10, 8, 6, 4, 3, 4, 0, 2,
+ 2, 2, 2, 5, 7, 0, 3, 2, 2, 2, 4, 8, 0, 4, 3, 2, 1, 4, 6,
+ 0, 3, 3, 2, 1, 2, 5, 2, 3, 5, 5, 3, 3, 4, 5, 6, 9, 8, 4,
+ 3, 3, 8, 9, 10, 9, 6, 4, 3, 4, 7, 6, 3, 2, 3, 6, 4, 7, 8,
+ 4, 2, 2, 5, 4, 7, 9, 4, 2, 0, 5, 4, 7, 10, 6, 3, 2, 3, 4,
+ 7, 11, 9, 5, 3, 3, 5, 9, 12, 12, 7, 4, 3, 7, 10, 12, 13, 8, 5,
+ 3, 30, 34, 37, 40, 39, 38, 34, 29, 34, 37, 40, 40, 38, 34, 28, 32, 35, 39,
+ 38, 38, 34, 27, 29, 34, 37, 39, 36, 33, 25, 28, 32, 35, 39, 37, 33, 23, 28,
+ 31, 34, 38, 37, 34, 21, 25, 29, 33, 36, 36, 34, 28, 32, 35, 37, 37, 34, 31,
+ 26, 31, 34, 37, 36, 33, 31, 25, 29, 33, 34, 35, 33, 30, 24, 28, 31, 33, 33,
+ 33, 30, 23, 26, 29, 32, 33, 32, 30, 20, 24, 28, 31, 32, 32, 30, 18, 22, 26,
+ 30, 30, 30, 28, 25, 30, 32, 32, 32, 30, 25, 24, 27, 30, 31, 32, 30, 25, 22,
+ 26, 28, 29, 29, 28, 24, 20, 25, 26, 27, 27, 27, 24, 16, 23, 25, 26, 26, 27,
+ 24, 13, 22, 24, 23, 25, 25, 24, 13, 18, 21, 22, 23, 23, 22, 23, 24, 24, 25,
+ 26, 23, 14, 19, 22, 22, 23, 23, 22, 14, 16, 21, 21, 21, 23, 20, 15, 12, 19,
+ 19, 19, 19, 18, 15, 12, 17, 18, 18, 18, 17, 12, 12, 14, 15, 16, 16, 16, 9,
+ 14, 12, 13, 14, 15, 15, 7, 10, 15, 16, 16, 15, 11, 13, 7, 13, 14, 15, 14,
+ 10, 13, 7, 11, 12, 12, 12, 8, 12, 7, 8, 10, 10, 10, 7, 8, 7, 5, 8,
+ 8, 8, 5, 8, 8, 7, 6, 6, 6, 3, 8, 10, 9, 8, 6, 4, 3, 6, 3,
+ 5, 6, 6, 7, 9, 11, 3, 3, 4, 4, 6, 8, 10, 3, 1, 2, 2, 4, 6,
+ 9, 3, 0, 2, 2, 2, 5, 7, 3, 2, 3, 3, 3, 3, 6, 5, 5, 7, 5,
+ 3, 3, 4, 7, 8, 7, 5, 4, 3, 3, 2, 4, 4, 2, 5, 7, 10, 2, 4,
+ 5, 3, 4, 6, 9, 2, 5, 6, 3, 2, 5, 6, 2, 4, 5, 3, 1, 2, 5,
+ 2, 4, 6, 5, 3, 3, 3, 4, 5, 7, 7, 4, 3, 3, 7, 7, 8, 9, 5,
+ 3, 3, 33, 36, 41, 43, 44, 41, 38, 31, 35, 39, 43, 44, 41, 37, 30, 35, 37,
+ 41, 43, 38, 35, 29, 33, 35, 39, 41, 38, 34, 27, 29, 33, 38, 40, 37, 33, 25,
+ 28, 32, 36, 40, 38, 34, 23, 26, 32, 34, 37, 38, 35, 30, 34, 38, 40, 40, 37,
+ 33, 29, 33, 36, 40, 40, 37, 32, 26, 32, 35, 39, 38, 35, 32, 26, 29, 32, 36,
+ 35, 33, 31, 25, 27, 30, 34, 34, 33, 29, 22, 26, 29, 33, 32, 32, 30, 19, 24,
+ 27, 31, 31, 32, 29, 27, 31, 34, 34, 34, 32, 27, 26, 29, 32, 33, 33, 32, 26,
+ 24, 28, 30, 31, 31, 30, 24, 20, 27, 27, 28, 28, 27, 23, 16, 25, 26, 27, 27,
+ 26, 23, 13, 24, 24, 25, 25, 26, 23, 14, 21, 23, 23, 24, 24, 22, 23, 25, 26,
+ 27, 28, 25, 17, 20, 24, 25, 26, 25, 22, 16, 15, 23, 23, 23, 23, 21, 17, 12,
+ 20, 20, 20, 19, 18, 16, 12, 17, 19, 19, 19, 16, 13, 13, 14, 17, 17, 17, 16,
+ 9, 14, 12, 15, 16, 16, 15, 7, 11, 17, 18, 19, 17, 12, 16, 8, 15, 16, 17,
+ 16, 10, 16, 8, 12, 14, 14, 13, 8, 12, 8, 8, 11, 11, 10, 7, 9, 8, 5,
+ 10, 10, 9, 5, 6, 8, 7, 7, 7, 7, 4, 8, 10, 9, 8, 6, 6, 3, 5,
+ 3, 7, 8, 9, 8, 10, 13, 3, 5, 6, 7, 7, 9, 10, 3, 2, 4, 4, 5,
+ 6, 8, 3, 2, 0, 0, 3, 6, 6, 3, 2, 5, 5, 4, 3, 5, 5, 6, 11,
+ 10, 6, 3, 5, 7, 11, 13, 11, 8, 4, 4, 1, 7, 7, 4, 7, 9, 10, 1,
+ 7, 9, 3, 6, 7, 9, 1, 7, 11, 4, 3, 5, 6, 1, 7, 11, 6, 1, 2,
+ 5, 1, 7, 12, 10, 7, 4, 3, 4, 10, 13, 13, 10, 5, 3, 9, 13, 14, 15,
+ 11, 7, 3, 33, 36, 40, 42, 44, 41, 37, 30, 34, 38, 44, 43, 40, 35, 29, 33,
+ 38, 41, 42, 38, 34, 28, 31, 35, 37, 40, 37, 32, 26, 28, 32, 35, 39, 36, 33,
+ 25, 27, 30, 34, 38, 36, 33, 23, 26, 30, 33, 36, 36, 33, 29, 33, 36, 41, 38,
+ 36, 32, 28, 32, 36, 39, 38, 35, 31, 26, 30, 33, 37, 36, 33, 29, 25, 27, 32,
+ 34, 34, 31, 28, 24, 26, 30, 32, 33, 32, 28, 22, 25, 28, 31, 31, 31, 28, 18,
+ 23, 27, 29, 30, 30, 27, 27, 31, 33, 33, 34, 31, 25, 25, 28, 31, 32, 32, 30,
+ 23, 22, 27, 29, 30, 30, 28, 22, 19, 25, 26, 26, 27, 26, 21, 15, 25, 25, 26,
+ 25, 24, 21, 12, 23, 24, 24, 24, 23, 21, 13, 20, 21, 22, 23, 22, 19, 22, 24,
+ 25, 25, 27, 23, 16, 18, 22, 24, 24, 24, 21, 15, 14, 21, 23, 22, 21, 18, 15,
+ 12, 19, 19, 19, 19, 15, 15, 12, 16, 19, 18, 17, 14, 12, 13, 14, 16, 16, 16,
+ 14, 8, 13, 12, 14, 15, 15, 14, 5, 10, 17, 17, 18, 16, 12, 16, 7, 15, 16,
+ 16, 15, 9, 16, 7, 11, 14, 13, 12, 7, 11, 7, 7, 11, 10, 9, 4, 7, 7,
+ 5, 10, 9, 8, 3, 5, 8, 7, 7, 7, 7, 3, 5, 10, 9, 8, 5, 5, 2,
+ 4, 2, 7, 8, 8, 8, 10, 13, 2, 5, 6, 7, 7, 8, 10, 2, 1, 4, 4,
+ 4, 5, 6, 2, 2, 0, 0, 2, 4, 5, 3, 2, 5, 5, 4, 2, 4, 5, 6,
+ 11, 10, 6, 3, 3, 7, 10, 13, 12, 7, 4, 3, 2, 6, 6, 4, 7, 9, 10,
+ 1, 6, 7, 3, 6, 6, 7, 1, 6, 8, 4, 2, 3, 5, 1, 6, 8, 5, 1,
+ 2, 3, 1, 7, 11, 11, 6, 4, 3, 4, 10, 15, 15, 9, 5, 2, 9, 13, 16,
+ 16, 11, 6, 3, 28, 32, 36, 40, 41, 36, 33, 27, 31, 35, 39, 40, 35, 32, 26,
+ 29, 34, 36, 39, 35, 30, 24, 27, 31, 34, 36, 32, 29, 22, 25, 28, 31, 34, 32,
+ 29, 21, 24, 26, 30, 33, 32, 29, 19, 22, 25, 28, 33, 31, 29, 26, 29, 34, 37,
+ 35, 33, 29, 25, 28, 32, 36, 35, 32, 28, 23, 27, 31, 34, 33, 30, 25, 22, 25,
+ 28, 30, 30, 28, 24, 20, 22, 25, 28, 28, 27, 23, 19, 22, 24, 27, 27, 27, 24,
+ 16, 19, 23, 26, 25, 26, 24, 23, 26, 29, 29, 31, 28, 23, 22, 26, 28, 28, 29,
+ 26, 21, 20, 23, 26, 25, 26, 25, 19, 17, 22, 22, 22, 23, 22, 18, 13, 21, 21,
+ 21, 21, 21, 17, 11, 19, 20, 20, 20, 19, 17, 12, 17, 18, 19, 19, 19, 16, 20,
+ 21, 22, 22, 24, 22, 15, 16, 20, 20, 21, 22, 19, 13, 13, 18, 19, 18, 18, 16,
+ 13, 10, 16, 15, 15, 15, 13, 12, 9, 14, 15, 14, 14, 12, 9, 10, 12, 12, 12,
+ 12, 11, 6, 12, 10, 11, 11, 11, 11, 4, 8, 14, 14, 15, 14, 11, 14, 5, 12,
+ 12, 13, 13, 8, 13, 5, 10, 10, 10, 10, 6, 8, 5, 5, 7, 6, 6, 3, 5,
+ 5, 4, 5, 5, 5, 2, 3, 6, 6, 7, 5, 3, 2, 4, 8, 9, 9, 6, 4,
+ 2, 3, 1, 4, 5, 6, 8, 9, 12, 1, 2, 4, 5, 6, 7, 8, 1, 2, 2,
+ 2, 4, 4, 5, 1, 2, 4, 2, 0, 3, 4, 2, 4, 6, 6, 4, 2, 3, 4,
+ 8, 12, 10, 6, 3, 2, 8, 11, 13, 11, 7, 4, 2, 4, 5, 4, 4, 6, 8,
+ 9, 4, 5, 5, 4, 5, 6, 6, 4, 6, 6, 3, 2, 3, 3, 3, 7, 8, 4,
+ 3, 1, 2, 4, 6, 9, 9, 7, 4, 2, 6, 10, 13, 13, 9, 5, 2, 11, 13,
+ 14, 14, 10, 6, 3, 25, 28, 32, 36, 36, 34, 29, 23, 26, 31, 35, 35, 31, 28,
+ 22, 25, 29, 33, 33, 30, 25, 20, 23, 27, 30, 33, 28, 24, 17, 20, 23, 26, 29,
+ 27, 24, 16, 19, 22, 25, 28, 27, 24, 14, 17, 21, 24, 28, 27, 24, 21, 25, 29,
+ 32, 32, 28, 25, 21, 24, 28, 31, 32, 27, 23, 18, 22, 27, 29, 29, 25, 22, 19,
+ 20, 24, 27, 26, 24, 20, 16, 18, 20, 23, 23, 22, 20, 14, 17, 19, 22, 22, 22,
+ 19, 11, 14, 18, 21, 21, 21, 20, 19, 22, 25, 26, 27, 25, 20, 18, 21, 24, 25,
+ 24, 23, 19, 17, 20, 22, 22, 22, 22, 16, 15, 18, 18, 18, 19, 19, 14, 11, 16,
+ 16, 16, 16, 16, 14, 9, 14, 15, 15, 15, 15, 14, 9, 12, 13, 13, 14, 14, 13,
+ 17, 17, 18, 18, 20, 19, 12, 15, 15, 17, 17, 17, 16, 10, 11, 15, 15, 15, 14,
+ 14, 9, 7, 12, 11, 11, 11, 11, 9, 7, 10, 9, 9, 9, 8, 6, 8, 7, 8,
+ 8, 8, 7, 3, 9, 9, 6, 6, 6, 6, 3, 7, 9, 9, 10, 11, 10, 12, 3,
+ 8, 8, 9, 9, 7, 10, 3, 6, 6, 6, 6, 5, 6, 3, 3, 3, 2, 2, 2,
+ 3, 2, 4, 3, 3, 3, 1, 3, 5, 7, 7, 6, 4, 2, 2, 7, 9, 9, 7,
+ 5, 3, 2, 2, 3, 4, 5, 6, 8, 10, 2, 3, 4, 5, 5, 6, 7, 2, 4,
+ 4, 3, 3, 3, 4, 2, 5, 5, 4, 3, 0, 2, 2, 6, 8, 6, 5, 3, 2,
+ 6, 9, 12, 9, 6, 4, 1, 9, 11, 12, 11, 7, 5, 2, 6, 8, 6, 4, 6,
+ 7, 8, 6, 8, 7, 5, 5, 5, 5, 6, 8, 9, 4, 2, 2, 3, 6, 9, 11,
+ 5, 3, 2, 1, 6, 8, 10, 10, 7, 5, 2, 8, 11, 13, 12, 8, 5, 3, 10,
+ 13, 14, 14, 10, 6, 4, 20, 24, 28, 32, 31, 29, 25, 19, 23, 27, 31, 31, 28,
+ 24, 18, 21, 25, 28, 31, 27, 22, 17, 19, 22, 26, 28, 25, 19, 13, 16, 19, 22,
+ 26, 23, 20, 11, 15, 17, 20, 24, 23, 19, 10, 13, 16, 19, 23, 23, 20, 18, 22,
+ 25, 29, 28, 25, 21, 17, 21, 24, 27, 28, 24, 20, 15, 19, 23, 25, 24, 22, 18,
+ 14, 17, 19, 22, 22, 20, 16, 11, 14, 16, 18, 19, 19, 15, 10, 12, 15, 18, 18,
+ 18, 15, 7, 10, 14, 16, 16, 16, 15, 15, 19, 20, 22, 23, 21, 17, 14, 17, 20,
+ 21, 21, 19, 15, 13, 16, 18, 18, 18, 18, 13, 12, 14, 15, 14, 14, 14, 10, 9,
+ 11, 12, 12, 12, 11, 10, 5, 10, 11, 10, 11, 11, 11, 6, 8, 10, 9, 9, 9,
+ 9, 13, 13, 14, 15, 16, 16, 10, 12, 12, 12, 13, 13, 13, 8, 9, 10, 11, 10,
+ 10, 10, 7, 5, 8, 7, 7, 7, 7, 6, 4, 5, 5, 4, 4, 4, 3, 5, 4,
+ 3, 3, 3, 3, 2, 6, 6, 3, 2, 2, 2, 1, 4, 5, 6, 7, 7, 9, 10,
+ 2, 4, 5, 6, 6, 7, 8, 2, 3, 4, 4, 4, 4, 5, 2, 3, 3, 2, 2,
+ 1, 2, 1, 6, 4, 3, 3, 2, 1, 5, 6, 6, 4, 3, 2, 0, 5, 7, 7,
+ 5, 4, 3, 1, 5, 5, 5, 5, 6, 8, 9, 5, 6, 5, 5, 5, 5, 6, 5,
+ 7, 5, 4, 3, 3, 3, 5, 7, 6, 5, 4, 3, 0, 6, 8, 8, 6, 4, 3,
+ 1, 6, 9, 11, 8, 5, 3, 2, 7, 9, 11, 10, 6, 4, 2, 7, 9, 7, 5,
+ 6, 7, 7, 8, 10, 9, 5, 5, 5, 5, 8, 10, 10, 5, 3, 2, 2, 8, 9,
+ 11, 7, 4, 3, 2, 8, 9, 12, 10, 6, 4, 2, 8, 10, 14, 13, 8, 4, 3,
+ 9, 12, 14, 14, 9, 5, 3, 27, 31, 32, 35, 35, 33, 30, 25, 29, 33, 35, 35,
+ 32, 29, 23, 27, 30, 33, 34, 31, 29, 23, 26, 28, 31, 33, 28, 26, 20, 23, 25,
+ 28, 30, 28, 26, 18, 22, 24, 27, 30, 28, 26, 15, 19, 22, 26, 28, 28, 26, 24,
+ 28, 30, 33, 32, 30, 27, 23, 27, 30, 31, 31, 29, 26, 21, 25, 28, 31, 30, 28,
+ 26, 20, 24, 27, 28, 28, 25, 23, 18, 20, 23, 25, 25, 26, 23, 16, 18, 22, 25,
+ 25, 24, 23, 12, 15, 20, 23, 24, 24, 23, 22, 25, 27, 27, 28, 26, 23, 20, 24,
+ 26, 28, 28, 26, 22, 18, 23, 25, 25, 24, 26, 22, 17, 20, 22, 22, 22, 24, 20,
+ 12, 18, 19, 20, 20, 21, 19, 9, 15, 17, 18, 19, 20, 19, 10, 12, 15, 16, 17,
+ 19, 19, 18, 20, 20, 22, 22, 22, 12, 16, 18, 19, 20, 21, 20, 13, 13, 17, 17,
+ 18, 18, 18, 13, 9, 14, 14, 14, 15, 15, 12, 8, 12, 12, 12, 12, 13, 8, 9,
+ 9, 9, 10, 11, 11, 6, 10, 10, 7, 8, 9, 9, 7, 9, 11, 12, 13, 13, 10,
+ 12, 4, 9, 10, 11, 11, 9, 12, 4, 8, 8, 8, 9, 8, 10, 4, 4, 5, 5,
+ 5, 6, 6, 3, 2, 2, 2, 2, 3, 6, 5, 5, 5, 4, 2, 2, 6, 8, 8,
+ 6, 4, 2, 1, 5, 2, 3, 4, 4, 7, 9, 11, 2, 4, 4, 4, 6, 8, 9,
+ 2, 4, 4, 4, 3, 6, 8, 2, 3, 3, 3, 2, 2, 6, 0, 3, 4, 3, 2,
+ 1, 5, 3, 4, 7, 5, 2, 1, 3, 6, 7, 8, 7, 3, 2, 1, 5, 8, 7,
+ 5, 5, 8, 9, 5, 8, 9, 6, 4, 6, 9, 5, 8, 10, 6, 4, 3, 6, 5,
+ 7, 10, 5, 2, 2, 3, 4, 6, 9, 7, 3, 2, 1, 4, 7, 10, 9, 5, 2,
+ 1, 5, 9, 10, 10, 6, 3, 1, 34, 37, 40, 44, 42, 41, 38, 33, 35, 39, 43,
+ 43, 40, 37, 30, 34, 38, 41, 43, 39, 36, 29, 32, 35, 39, 41, 37, 33, 26, 30,
+ 32, 35, 39, 34, 33, 23, 26, 30, 33, 36, 37, 33, 21, 25, 29, 33, 36, 36, 34,
+ 31, 35, 38, 42, 40, 37, 35, 29, 33, 37, 40, 41, 36, 33, 28, 31, 34, 38, 38,
+ 36, 31, 26, 29, 33, 35, 35, 34, 29, 23, 26, 29, 32, 31, 31, 28, 20, 24, 27,
+ 30, 31, 33, 29, 17, 21, 26, 29, 30, 30, 29, 27, 31, 33, 36, 36, 33, 29, 26,
+ 30, 32, 34, 34, 33, 28, 24, 28, 31, 32, 33, 32, 27, 21, 27, 27, 28, 29, 28,
+ 24, 15, 23, 25, 25, 25, 25, 25, 12, 21, 23, 24, 24, 24, 24, 12, 18, 21, 22,
+ 22, 23, 22, 25, 26, 27, 29, 28, 28, 19, 20, 23, 26, 26, 27, 24, 18, 16, 22,
+ 24, 24, 24, 23, 17, 12, 20, 20, 20, 21, 20, 17, 11, 16, 17, 17, 17, 17, 13,
+ 11, 13, 15, 15, 16, 15, 10, 12, 10, 12, 14, 14, 14, 8, 12, 17, 18, 19, 20,
+ 16, 19, 8, 15, 17, 18, 18, 13, 18, 8, 13, 15, 15, 15, 11, 15, 8, 8, 11,
+ 10, 11, 8, 9, 6, 3, 8, 7, 8, 6, 7, 7, 5, 4, 5, 5, 5, 8, 8,
+ 7, 5, 3, 3, 4, 7, 3, 7, 8, 10, 11, 14, 16, 3, 6, 7, 8, 10, 12,
+ 13, 3, 3, 5, 5, 7, 9, 11, 3, 2, 2, 2, 4, 6, 8, 3, 0, 3, 2,
+ 1, 4, 7, 3, 3, 4, 3, 2, 3, 7, 5, 6, 5, 4, 2, 1, 5, 4, 6,
+ 6, 6, 10, 12, 14, 4, 6, 7, 5, 8, 10, 11, 3, 6, 7, 4, 4, 7, 9,
+ 4, 5, 7, 3, 2, 3, 5, 2, 4, 5, 4, 2, 1, 5, 3, 4, 6, 5, 3,
+ 2, 4, 4, 5, 6, 6, 3, 2, 2, 38, 41, 46, 49, 49, 47, 45, 37, 41, 44,
+ 48, 50, 45, 41, 35, 38, 43, 46, 48, 44, 40, 33, 36, 39, 43, 46, 43, 36, 31,
+ 33, 37, 40, 43, 41, 36, 27, 30, 35, 38, 41, 40, 36, 25, 28, 33, 37, 40, 40,
+ 37, 35, 40, 42, 46, 46, 42, 37, 33, 37, 42, 46, 46, 41, 37, 31, 36, 40, 43,
+ 44, 40, 35, 30, 33, 37, 39, 40, 38, 33, 25, 30, 33, 36, 37, 36, 32, 22, 27,
+ 32, 34, 35, 35, 32, 18, 25, 30, 33, 33, 34, 32, 31, 36, 38, 39, 41, 37, 32,
+ 29, 35, 37, 38, 39, 36, 31, 27, 33, 34, 36, 36, 35, 29, 23, 31, 32, 32, 33,
+ 31, 25, 17, 27, 28, 28, 28, 27, 25, 14, 25, 26, 27, 27, 27, 26, 13, 22, 25,
+ 25, 26, 26, 24, 26, 30, 31, 32, 33, 31, 23, 22, 28, 30, 31, 30, 29, 22, 19,
+ 25, 27, 28, 28, 26, 22, 15, 22, 24, 24, 24, 22, 20, 13, 17, 21, 21, 21, 18,
+ 17, 13, 14, 18, 19, 19, 18, 13, 13, 11, 17, 17, 18, 17, 10, 14, 21, 22, 24,
+ 23, 19, 23, 10, 19, 21, 21, 21, 15, 22, 10, 15, 19, 18, 18, 13, 17, 10, 9,
+ 15, 15, 15, 10, 12, 8, 5, 12, 12, 11, 7, 9, 9, 6, 9, 9, 9, 7, 8,
+ 9, 7, 7, 7, 7, 7, 7, 5, 11, 13, 13, 14, 17, 20, 5, 8, 11, 12, 13,
+ 14, 16, 5, 4, 9, 9, 10, 11, 12, 5, 3, 5, 5, 6, 8, 8, 4, 3, 0,
+ 0, 3, 6, 7, 4, 3, 6, 5, 1, 5, 8, 6, 5, 7, 6, 2, 4, 6, 4,
+ 5, 5, 9, 13, 15, 16, 4, 6, 7, 8, 11, 13, 14, 4, 5, 9, 5, 8, 9,
+ 11, 4, 5, 9, 4, 3, 6, 7, 2, 4, 7, 5, 2, 3, 7, 2, 5, 8, 7,
+ 4, 3, 5, 4, 7, 8, 8, 5, 1, 4, 36, 40, 45, 47, 48, 45, 42, 35, 40,
+ 43, 48, 47, 44, 40, 33, 37, 42, 45, 46, 43, 39, 32, 35, 39, 43, 44, 40, 35,
+ 30, 32, 35, 39, 41, 38, 35, 27, 29, 32, 36, 40, 38, 34, 23, 28, 32, 34, 38,
+ 38, 34, 34, 38, 41, 45, 46, 41, 37, 33, 35, 40, 44, 44, 38, 35, 31, 35, 39,
+ 42, 42, 38, 33, 28, 32, 35, 39, 38, 35, 31, 24, 29, 32, 34, 36, 33, 30, 20,
+ 27, 30, 33, 33, 32, 30, 17, 24, 29, 32, 31, 31, 30, 31, 35, 36, 38, 38, 37,
+ 30, 28, 34, 36, 36, 38, 35, 29, 25, 32, 35, 34, 34, 33, 26, 21, 29, 31, 31,
+ 30, 30, 23, 15, 26, 27, 28, 27, 25, 24, 12, 23, 26, 27, 25, 25, 24, 12, 21,
+ 24, 24, 24, 24, 22, 25, 30, 29, 32, 31, 29, 23, 20, 27, 29, 29, 29, 26, 21,
+ 17, 26, 27, 26, 26, 23, 20, 14, 21, 23, 23, 22, 20, 19, 12, 17, 20, 20, 19,
+ 16, 15, 12, 13, 18, 18, 18, 15, 12, 12, 10, 16, 16, 17, 15, 8, 12, 20, 22,
+ 22, 21, 17, 22, 9, 18, 19, 21, 20, 14, 21, 9, 14, 18, 17, 17, 11, 16, 9,
+ 8, 15, 14, 13, 8, 11, 8, 4, 12, 11, 9, 5, 8, 7, 5, 9, 9, 8, 4,
+ 6, 8, 6, 7, 7, 7, 4, 5, 5, 11, 12, 13, 13, 15, 19, 5, 7, 11, 11,
+ 12, 13, 14, 5, 4, 9, 8, 9, 10, 11, 5, 3, 5, 5, 6, 6, 6, 3, 2,
+ 0, 0, 2, 4, 5, 3, 3, 6, 5, 1, 3, 5, 5, 5, 7, 7, 2, 3, 4,
+ 4, 5, 5, 9, 12, 14, 15, 4, 5, 5, 8, 10, 12, 12, 4, 5, 6, 5, 7,
+ 8, 9, 4, 4, 6, 3, 3, 4, 5, 2, 4, 7, 6, 1, 3, 4, 1, 5, 11,
+ 11, 4, 1, 4, 4, 8, 12, 12, 6, 1, 3, 33, 37, 41, 43, 44, 41, 38, 31,
+ 35, 39, 43, 44, 39, 36, 29, 34, 37, 42, 42, 38, 33, 28, 31, 34, 39, 41, 36,
+ 30, 26, 28, 31, 35, 37, 33, 31, 23, 24, 28, 32, 35, 34, 30, 21, 24, 27, 30,
+ 35, 34, 30, 30, 33, 38, 41, 40, 37, 32, 29, 31, 36, 40, 41, 37, 31, 28, 30,
+ 35, 37, 37, 34, 29, 26, 28, 31, 34, 34, 32, 26, 22, 25, 27, 30, 31, 29, 25,
+ 19, 23, 26, 29, 29, 28, 25, 14, 21, 25, 27, 27, 27, 25, 28, 31, 33, 34, 35,
+ 33, 28, 26, 30, 32, 33, 33, 31, 25, 22, 28, 30, 29, 30, 29, 23, 19, 27, 27,
+ 26, 28, 25, 19, 13, 22, 24, 23, 23, 22, 19, 10, 20, 22, 21, 21, 21, 20, 9,
+ 18, 20, 20, 20, 20, 18, 23, 26, 26, 27, 27, 27, 20, 18, 24, 25, 25, 26, 23,
+ 18, 15, 22, 23, 23, 22, 21, 17, 12, 19, 19, 19, 20, 17, 15, 10, 14, 16, 15,
+ 15, 13, 12, 9, 10, 15, 14, 14, 12, 9, 9, 7, 13, 13, 13, 12, 6, 11, 18,
+ 18, 19, 19, 15, 19, 7, 16, 16, 18, 17, 12, 18, 7, 12, 15, 14, 14, 10, 13,
+ 7, 7, 11, 11, 10, 6, 8, 5, 2, 7, 7, 6, 4, 5, 5, 3, 5, 4, 5,
+ 3, 4, 5, 4, 3, 3, 3, 3, 4, 3, 9, 9, 10, 12, 13, 17, 3, 7, 9,
+ 9, 11, 11, 12, 3, 4, 8, 7, 8, 8, 9, 3, 3, 4, 4, 4, 5, 4, 2,
+ 1, 3, 2, 0, 3, 4, 2, 3, 5, 4, 2, 2, 4, 3, 4, 5, 5, 3, 1,
+ 3, 4, 5, 6, 9, 11, 13, 13, 4, 5, 6, 8, 9, 10, 10, 4, 5, 6, 6,
+ 6, 7, 7, 4, 3, 5, 2, 2, 3, 3, 2, 3, 6, 5, 3, 1, 3, 2, 5,
+ 7, 6, 3, 2, 3, 4, 6, 7, 7, 4, 2, 2, 26, 31, 35, 39, 39, 35, 33,
+ 26, 30, 33, 39, 38, 36, 31, 24, 29, 32, 36, 37, 33, 29, 23, 26, 30, 33, 34,
+ 31, 26, 20, 24, 26, 29, 32, 29, 26, 18, 20, 23, 26, 30, 30, 26, 17, 18, 22,
+ 26, 29, 29, 26, 24, 28, 32, 36, 35, 33, 29, 24, 26, 31, 35, 34, 30, 27, 22,
+ 25, 29, 33, 31, 29, 24, 21, 24, 27, 29, 29, 27, 21, 18, 20, 23, 25, 25, 24,
+ 21, 16, 19, 21, 23, 23, 24, 21, 13, 17, 20, 23, 22, 22, 22, 22, 25, 28, 28,
+ 30, 28, 24, 21, 24, 27, 27, 28, 27, 22, 20, 23, 25, 25, 25, 25, 20, 17, 21,
+ 22, 21, 22, 22, 16, 11, 18, 18, 18, 18, 18, 16, 7, 17, 17, 16, 16, 17, 16,
+ 8, 15, 15, 15, 16, 16, 14, 20, 20, 20, 21, 23, 23, 16, 16, 19, 20, 20, 21,
+ 19, 14, 13, 18, 18, 18, 17, 17, 13, 9, 15, 15, 14, 14, 14, 11, 7, 12, 11,
+ 10, 10, 10, 8, 7, 8, 10, 9, 9, 9, 5, 7, 5, 8, 8, 7, 8, 3, 8,
+ 12, 13, 14, 14, 13, 15, 4, 11, 11, 12, 13, 10, 13, 4, 10, 9, 9, 9, 8,
+ 9, 4, 5, 6, 6, 5, 4, 5, 3, 2, 2, 2, 2, 2, 3, 3, 2, 3, 2,
+ 1, 2, 3, 4, 3, 5, 3, 2, 0, 3, 3, 6, 7, 8, 9, 11, 13, 3, 5,
+ 7, 8, 8, 9, 10, 3, 3, 5, 5, 6, 6, 6, 3, 3, 3, 2, 2, 3, 3,
+ 1, 4, 6, 4, 3, 0, 3, 2, 5, 8, 5, 3, 2, 2, 4, 7, 8, 7, 4,
+ 2, 2, 4, 6, 6, 7, 8, 10, 11, 4, 6, 6, 6, 7, 8, 8, 4, 6, 7,
+ 4, 4, 4, 6, 4, 6, 8, 4, 2, 1, 2, 3, 8, 9, 7, 4, 2, 2, 6,
+ 8, 10, 9, 5, 3, 0, 7, 9, 10, 9, 6, 4, 2, 21, 26, 31, 32, 34, 32,
+ 27, 20, 24, 28, 32, 34, 30, 25, 19, 22, 27, 30, 32, 28, 23, 18, 21, 24, 28,
+ 30, 26, 21, 15, 18, 21, 24, 27, 24, 21, 13, 15, 18, 21, 24, 24, 20, 12, 14,
+ 17, 21, 24, 25, 21, 20, 23, 26, 31, 29, 27, 24, 19, 22, 26, 29, 29, 26, 22,
+ 17, 21, 24, 27, 27, 24, 19, 16, 18, 21, 24, 23, 22, 17, 13, 15, 17, 20, 20,
+ 20, 17, 12, 13, 16, 19, 19, 19, 17, 9, 12, 15, 18, 17, 18, 17, 18, 20, 22,
+ 23, 25, 23, 18, 16, 19, 21, 22, 23, 21, 16, 15, 18, 19, 19, 19, 19, 15, 14,
+ 16, 16, 16, 16, 16, 12, 9, 12, 13, 13, 12, 13, 12, 6, 12, 12, 12, 11, 12,
+ 12, 6, 10, 11, 10, 11, 11, 10, 15, 15, 15, 16, 17, 18, 11, 13, 13, 14, 15,
+ 15, 15, 9, 10, 12, 12, 12, 12, 11, 8, 6, 11, 9, 8, 8, 8, 7, 4, 7,
+ 6, 6, 5, 5, 4, 5, 5, 5, 4, 4, 4, 2, 6, 4, 3, 3, 3, 3, 2,
+ 6, 7, 7, 8, 9, 10, 11, 2, 5, 6, 7, 7, 8, 9, 2, 4, 5, 4, 5,
+ 5, 5, 2, 2, 2, 2, 1, 2, 2, 1, 4, 4, 3, 2, 2, 2, 3, 5, 5,
+ 4, 2, 2, 1, 4, 6, 7, 4, 3, 3, 0, 3, 4, 5, 6, 7, 8, 10, 4,
+ 5, 5, 6, 6, 6, 7, 4, 7, 5, 4, 4, 4, 4, 4, 6, 5, 4, 3, 2,
+ 1, 4, 7, 8, 5, 4, 3, 0, 6, 7, 9, 7, 4, 3, 2, 6, 8, 10, 8,
+ 5, 3, 2, 7, 9, 7, 5, 6, 8, 8, 7, 9, 8, 5, 5, 5, 5, 7, 9,
+ 10, 5, 3, 2, 3, 7, 8, 11, 6, 4, 3, 1, 7, 9, 11, 8, 5, 3, 2,
+ 8, 9, 12, 11, 6, 4, 2, 8, 10, 12, 12, 8, 5, 3, 31, 34, 37, 39, 39,
+ 37, 34, 28, 33, 36, 38, 38, 35, 32, 27, 31, 34, 37, 37, 35, 31, 26, 28, 32,
+ 34, 35, 32, 27, 22, 25, 29, 30, 32, 29, 27, 18, 22, 24, 26, 30, 29, 27, 15,
+ 19, 23, 26, 29, 28, 27, 26, 31, 35, 36, 36, 34, 32, 26, 30, 34, 36, 37, 33,
+ 31, 24, 28, 31, 34, 34, 31, 28, 22, 26, 30, 32, 30, 30, 24, 20, 22, 25, 28,
+ 27, 26, 24, 16, 19, 22, 24, 25, 25, 24, 12, 16, 20, 24, 24, 25, 24, 24, 29,
+ 31, 31, 33, 30, 27, 23, 26, 29, 30, 31, 31, 26, 21, 26, 28, 28, 29, 29, 25,
+ 19, 23, 25, 24, 25, 25, 20, 12, 19, 20, 21, 21, 21, 20, 8, 16, 18, 18, 19,
+ 20, 20, 8, 13, 16, 16, 18, 18, 19, 21, 22, 24, 25, 25, 27, 18, 18, 20, 21,
+ 24, 23, 24, 17, 14, 19, 21, 21, 21, 21, 16, 11, 17, 17, 17, 17, 17, 15, 8,
+ 12, 12, 13, 13, 13, 11, 7, 9, 9, 10, 11, 12, 8, 9, 7, 7, 8, 9, 10,
+ 8, 10, 14, 15, 16, 17, 17, 18, 6, 12, 13, 15, 15, 14, 17, 6, 11, 11, 11,
+ 12, 11, 14, 6, 7, 8, 8, 8, 8, 7, 4, 2, 3, 3, 3, 5, 7, 3, 2,
+ 2, 2, 0, 3, 7, 5, 5, 4, 2, 2, 2, 5, 5, 6, 8, 9, 12, 15, 17,
+ 5, 5, 7, 8, 11, 13, 14, 5, 6, 6, 6, 8, 10, 11, 5, 5, 5, 5, 4,
+ 6, 6, 3, 3, 4, 3, 2, 2, 6, 0, 4, 5, 4, 2, 1, 5, 4, 4, 6,
+ 5, 2, 2, 3, 7, 9, 9, 8, 10, 13, 15, 7, 9, 10, 8, 8, 11, 13, 7,
+ 9, 11, 7, 6, 7, 9, 7, 8, 10, 6, 4, 3, 5, 5, 7, 9, 6, 3, 1,
+ 3, 4, 5, 9, 8, 3, 2, 1, 5, 6, 9, 9, 4, 2, 1, 37, 41, 44, 47,
+ 48, 44, 42, 35, 39, 43, 47, 48, 44, 40, 33, 38, 41, 45, 45, 42, 38, 32, 36,
+ 38, 42, 45, 40, 34, 29, 31, 35, 39, 39, 36, 34, 24, 28, 31, 33, 37, 37, 34,
+ 22, 25, 29, 32, 36, 36, 34, 33, 36, 41, 46, 42, 42, 39, 31, 36, 41, 44, 45,
+ 42, 36, 30, 34, 38, 41, 41, 39, 35, 29, 32, 36, 38, 39, 35, 30, 25, 29, 31,
+ 34, 33, 33, 30, 20, 25, 28, 32, 31, 31, 28, 16, 22, 26, 31, 30, 30, 30, 30,
+ 35, 36, 37, 39, 37, 33, 28, 33, 35, 36, 37, 36, 31, 26, 31, 33, 34, 34, 34,
+ 29, 22, 29, 30, 31, 31, 30, 24, 16, 24, 26, 26, 25, 26, 25, 11, 21, 23, 24,
+ 24, 24, 25, 10, 19, 21, 23, 23, 23, 22, 26, 29, 30, 31, 32, 33, 24, 21, 26,
+ 29, 30, 31, 29, 23, 18, 25, 27, 27, 27, 26, 21, 14, 22, 23, 23, 23, 22, 19,
+ 12, 16, 19, 19, 18, 17, 16, 11, 12, 15, 16, 16, 16, 12, 10, 8, 13, 14, 14,
+ 15, 9, 13, 20, 21, 22, 24, 21, 24, 10, 18, 20, 20, 22, 18, 22, 10, 15, 17,
+ 17, 18, 15, 17, 10, 9, 14, 14, 13, 10, 12, 8, 4, 9, 9, 9, 8, 9, 5,
+ 3, 5, 5, 6, 6, 9, 7, 5, 3, 3, 4, 5, 7, 6, 12, 13, 14, 17, 19,
+ 21, 6, 10, 11, 13, 15, 17, 18, 6, 6, 9, 10, 12, 13, 14, 6, 5, 6, 6,
+ 8, 9, 8, 4, 3, 3, 3, 3, 6, 7, 4, 0, 4, 3, 1, 4, 7, 3, 3,
+ 5, 3, 2, 3, 6, 6, 8, 8, 10, 15, 17, 19, 6, 8, 9, 9, 13, 15, 16,
+ 6, 8, 9, 7, 9, 11, 12, 6, 7, 8, 5, 5, 7, 6, 4, 5, 6, 5, 2,
+ 3, 7, 2, 4, 5, 4, 2, 1, 5, 3, 5, 5, 5, 3, 2, 4, 42, 47, 50,
+ 55, 55, 54, 48, 41, 45, 49, 54, 55, 52, 45, 39, 43, 47, 51, 52, 50, 45, 38,
+ 40, 45, 48, 51, 45, 39, 34, 38, 41, 44, 46, 42, 40, 31, 34, 38, 41, 44, 42,
+ 39, 27, 30, 35, 40, 42, 43, 40, 40, 43, 48, 51, 52, 48, 44, 38, 43, 47, 51,
+ 50, 46, 42, 35, 40, 45, 48, 48, 46, 42, 34, 38, 42, 44, 44, 42, 35, 29, 35,
+ 38, 41, 40, 38, 34, 22, 31, 34, 37, 37, 38, 34, 19, 29, 33, 35, 36, 37, 36,
+ 37, 40, 44, 44, 45, 44, 39, 33, 40, 42, 42, 43, 42, 37, 29, 38, 40, 41, 40,
+ 39, 34, 25, 35, 37, 36, 37, 35, 30, 20, 30, 33, 33, 32, 29, 29, 14, 26, 30,
+ 30, 29, 30, 29, 13, 23, 27, 29, 28, 28, 27, 29, 34, 36, 37, 39, 38, 30, 25,
+ 32, 34, 36, 36, 34, 27, 21, 30, 33, 32, 33, 30, 26, 18, 26, 29, 28, 29, 26,
+ 25, 16, 20, 25, 25, 24, 20, 21, 14, 14, 22, 21, 21, 20, 17, 14, 10, 19, 20,
+ 20, 19, 13, 17, 27, 28, 29, 29, 25, 30, 13, 22, 27, 27, 27, 22, 28, 13, 18,
+ 24, 23, 24, 18, 22, 13, 12, 20, 20, 19, 13, 17, 11, 7, 16, 15, 14, 9, 12,
+ 9, 5, 11, 11, 11, 8, 10, 9, 6, 8, 10, 10, 8, 9, 9, 15, 18, 20, 20,
+ 23, 26, 9, 12, 17, 18, 19, 20, 22, 9, 8, 15, 15, 16, 17, 17, 9, 7, 11,
+ 11, 12, 11, 11, 7, 5, 6, 6, 5, 8, 9, 5, 4, 0, 1, 4, 6, 9, 5,
+ 3, 2, 2, 3, 6, 8, 7, 8, 11, 16, 19, 21, 22, 7, 7, 9, 14, 18, 18,
+ 18, 8, 7, 8, 11, 14, 15, 15, 7, 6, 6, 7, 10, 10, 9, 6, 4, 5, 3,
+ 3, 5, 8, 4, 2, 4, 4, 2, 5, 7, 3, 2, 4, 4, 2, 4, 6, 42, 45,
+ 48, 52, 53, 51, 46, 40, 42, 47, 52, 52, 48, 43, 38, 42, 46, 49, 52, 47, 42,
+ 35, 40, 44, 46, 48, 45, 38, 32, 37, 39, 44, 44, 42, 38, 29, 33, 36, 39, 42,
+ 41, 37, 26, 30, 34, 38, 41, 41, 38, 38, 42, 46, 49, 48, 46, 43, 37, 40, 45,
+ 49, 48, 44, 40, 35, 38, 43, 47, 46, 42, 35, 33, 38, 40, 43, 41, 39, 33, 26,
+ 34, 36, 39, 38, 36, 32, 22, 29, 32, 36, 35, 35, 32, 17, 28, 32, 35, 34, 34,
+ 33, 35, 40, 42, 42, 44, 41, 35, 31, 39, 39, 42, 42, 39, 33, 28, 37, 39, 38,
+ 38, 37, 30, 24, 33, 34, 35, 35, 32, 28, 18, 28, 31, 31, 30, 29, 28, 13, 24,
+ 29, 28, 29, 28, 28, 13, 21, 27, 27, 27, 27, 25, 27, 34, 34, 35, 37, 33, 27,
+ 23, 30, 33, 34, 33, 31, 26, 20, 27, 32, 31, 30, 27, 24, 16, 24, 28, 28, 27,
+ 23, 23, 14, 17, 24, 23, 23, 18, 19, 13, 13, 21, 21, 20, 17, 16, 12, 9, 19,
+ 20, 19, 17, 11, 16, 24, 26, 27, 26, 23, 27, 12, 20, 25, 26, 24, 19, 26, 12,
+ 16, 23, 23, 21, 15, 20, 12, 10, 19, 19, 17, 10, 15, 10, 6, 15, 15, 12, 7,
+ 11, 9, 5, 11, 11, 11, 6, 8, 8, 5, 7, 9, 9, 6, 7, 8, 14, 18, 18,
+ 18, 19, 24, 8, 9, 16, 16, 17, 17, 19, 8, 6, 14, 13, 14, 14, 14, 8, 5,
+ 10, 9, 10, 9, 9, 6, 3, 5, 5, 4, 6, 7, 4, 3, 1, 0, 3, 5, 7,
+ 4, 3, 1, 2, 2, 4, 6, 6, 7, 11, 14, 17, 19, 20, 6, 7, 10, 13, 15,
+ 16, 16, 6, 6, 9, 10, 12, 13, 13, 6, 5, 5, 6, 8, 8, 7, 4, 4, 4,
+ 3, 3, 4, 6, 3, 2, 6, 6, 1, 4, 5, 2, 3, 6, 6, 2, 3, 4, 34,
+ 39, 42, 47, 46, 43, 40, 34, 37, 42, 46, 46, 43, 37, 32, 35, 40, 44, 45, 41,
+ 36, 31, 33, 37, 40, 42, 38, 32, 28, 30, 33, 37, 38, 36, 33, 25, 27, 29, 33,
+ 37, 36, 32, 23, 25, 28, 32, 35, 36, 32, 32, 35, 40, 44, 44, 40, 36, 32, 35,
+ 38, 43, 42, 38, 33, 30, 33, 38, 40, 40, 36, 31, 28, 31, 34, 37, 36, 34, 28,
+ 22, 29, 30, 34, 33, 30, 27, 19, 25, 27, 30, 30, 30, 28, 15, 25, 27, 29, 29,
+ 30, 27, 30, 34, 37, 36, 36, 34, 29, 27, 32, 34, 35, 36, 33, 28, 24, 30, 33,
+ 32, 32, 30, 25, 21, 29, 29, 30, 30, 27, 23, 15, 24, 26, 26, 25, 23, 22, 11,
+ 22, 24, 23, 23, 22, 22, 10, 19, 22, 22, 22, 22, 20, 25, 28, 28, 29, 30, 29,
+ 23, 20, 26, 27, 28, 28, 25, 20, 16, 24, 26, 25, 25, 22, 19, 13, 20, 22, 21,
+ 22, 18, 18, 11, 15, 19, 18, 17, 14, 14, 10, 11, 17, 15, 15, 14, 11, 10, 7,
+ 15, 14, 14, 13, 7, 12, 20, 20, 21, 21, 17, 22, 9, 17, 19, 20, 19, 14, 20,
+ 9, 13, 17, 17, 16, 11, 15, 9, 8, 14, 13, 12, 7, 10, 7, 3, 10, 9, 8,
+ 4, 7, 6, 3, 7, 6, 6, 3, 5, 5, 4, 5, 5, 4, 4, 4, 5, 10, 12,
+ 12, 13, 15, 19, 5, 8, 11, 11, 12, 13, 14, 4, 4, 10, 9, 9, 10, 10, 5,
+ 3, 6, 6, 6, 6, 5, 3, 2, 1, 1, 2, 3, 4, 2, 1, 4, 3, 0, 3,
+ 4, 3, 2, 4, 3, 2, 2, 3, 5, 5, 8, 10, 12, 14, 15, 5, 5, 7, 10,
+ 11, 12, 12, 5, 5, 6, 7, 8, 9, 9, 5, 4, 4, 4, 4, 5, 4, 3, 2,
+ 5, 4, 2, 2, 4, 1, 4, 5, 5, 2, 2, 3, 3, 4, 5, 5, 3, 0, 2,
+ 28, 33, 37, 40, 41, 38, 35, 28, 31, 36, 40, 39, 37, 33, 26, 29, 35, 38, 38,
+ 34, 31, 26, 28, 31, 35, 37, 33, 28, 23, 25, 28, 30, 34, 31, 27, 19, 22, 24,
+ 28, 32, 31, 27, 18, 21, 23, 27, 30, 31, 28, 27, 30, 34, 38, 36, 35, 30, 26,
+ 30, 32, 37, 37, 33, 28, 25, 28, 31, 34, 33, 32, 26, 23, 26, 28, 30, 30, 28,
+ 22, 20, 22, 25, 27, 27, 26, 22, 17, 20, 22, 25, 25, 25, 22, 13, 19, 21, 24,
+ 24, 25, 22, 25, 28, 29, 30, 31, 30, 25, 23, 26, 29, 30, 29, 28, 23, 21, 26,
+ 27, 27, 27, 27, 21, 18, 23, 23, 23, 24, 23, 17, 12, 20, 20, 20, 20, 19, 17,
+ 8, 19, 19, 18, 18, 18, 17, 8, 16, 17, 17, 17, 17, 15, 21, 22, 22, 23, 24,
+ 23, 17, 17, 21, 22, 22, 23, 21, 15, 13, 19, 20, 20, 19, 18, 14, 10, 16, 16,
+ 16, 16, 15, 13, 8, 12, 13, 12, 12, 11, 10, 8, 9, 11, 11, 10, 10, 6, 8,
+ 6, 10, 9, 9, 9, 4, 9, 14, 15, 16, 16, 13, 17, 5, 13, 13, 14, 14, 10,
+ 15, 6, 11, 11, 11, 11, 8, 10, 6, 6, 8, 7, 7, 5, 6, 4, 2, 4, 3,
+ 3, 3, 3, 3, 2, 2, 1, 2, 2, 3, 4, 2, 4, 2, 1, 2, 3, 3, 7,
+ 8, 9, 10, 12, 14, 3, 6, 7, 8, 9, 10, 10, 3, 4, 6, 6, 6, 7, 7,
+ 3, 3, 3, 3, 3, 4, 3, 1, 3, 5, 3, 2, 1, 3, 1, 5, 6, 4, 3,
+ 0, 3, 2, 5, 6, 6, 3, 2, 2, 4, 6, 6, 7, 9, 11, 12, 4, 7, 6,
+ 7, 8, 9, 9, 4, 6, 6, 5, 5, 5, 6, 4, 5, 6, 3, 2, 2, 2, 2,
+ 5, 7, 6, 3, 2, 2, 5, 6, 8, 7, 4, 2, 1, 5, 7, 8, 8, 5, 3,
+ 0, 24, 28, 32, 36, 35, 32, 29, 23, 26, 30, 34, 36, 32, 28, 21, 25, 29, 32,
+ 34, 31, 25, 19, 22, 26, 30, 32, 28, 23, 17, 20, 22, 26, 28, 27, 23, 15, 17,
+ 20, 23, 27, 26, 23, 14, 16, 19, 22, 25, 26, 23, 21, 24, 28, 34, 32, 28, 26,
+ 20, 24, 28, 31, 31, 28, 24, 18, 22, 26, 29, 28, 26, 22, 18, 20, 23, 25, 26,
+ 23, 19, 15, 17, 20, 22, 21, 21, 18, 13, 15, 18, 20, 20, 21, 19, 11, 13, 17,
+ 20, 19, 19, 18, 18, 22, 24, 25, 27, 25, 20, 17, 20, 23, 24, 24, 23, 19, 17,
+ 19, 22, 22, 21, 22, 17, 14, 18, 18, 18, 18, 18, 14, 10, 14, 15, 15, 15, 15,
+ 14, 6, 13, 14, 13, 13, 14, 13, 6, 12, 12, 12, 12, 13, 12, 17, 17, 17, 18,
+ 20, 20, 13, 14, 15, 16, 17, 17, 17, 11, 11, 14, 14, 14, 14, 13, 10, 7, 12,
+ 11, 11, 11, 10, 9, 5, 9, 8, 7, 7, 7, 5, 6, 7, 7, 6, 6, 6, 3,
+ 7, 4, 5, 5, 5, 5, 3, 7, 9, 9, 10, 11, 11, 13, 2, 7, 8, 9, 9,
+ 8, 11, 2, 6, 6, 6, 6, 6, 7, 2, 3, 3, 2, 2, 3, 3, 1, 2, 2,
+ 2, 2, 0, 2, 2, 4, 5, 4, 2, 1, 2, 3, 6, 7, 4, 3, 2, 2, 3,
+ 4, 5, 7, 8, 10, 11, 3, 4, 5, 6, 7, 7, 8, 3, 5, 4, 4, 4, 5,
+ 5, 3, 4, 5, 3, 2, 1, 2, 3, 6, 8, 5, 4, 2, 2, 4, 8, 10, 7,
+ 4, 3, 0, 6, 9, 10, 8, 5, 3, 1, 6, 8, 6, 5, 7, 8, 9, 6, 8,
+ 8, 6, 6, 6, 7, 6, 8, 9, 5, 3, 3, 4, 6, 7, 10, 7, 5, 2, 0,
+ 7, 9, 10, 8, 5, 3, 2, 8, 10, 11, 10, 6, 4, 2, 9, 10, 11, 11, 7,
+ 5, 3, 33, 37, 40, 43, 42, 41, 37, 32, 36, 40, 42, 42, 40, 36, 30, 34, 38,
+ 40, 41, 37, 34, 29, 32, 36, 37, 38, 33, 27, 25, 28, 32, 33, 32, 29, 28, 22,
+ 24, 27, 28, 32, 29, 28, 16, 20, 24, 27, 29, 30, 28, 30, 34, 38, 40, 40, 38,
+ 35, 29, 33, 37, 42, 40, 37, 34, 27, 31, 35, 38, 36, 34, 30, 26, 29, 32, 34,
+ 34, 32, 25, 23, 26, 28, 31, 28, 27, 25, 18, 22, 24, 25, 27, 26, 25, 13, 17,
+ 21, 24, 24, 25, 24, 27, 32, 33, 35, 36, 35, 31, 26, 29, 33, 34, 35, 34, 29,
+ 24, 29, 31, 31, 31, 31, 26, 20, 26, 27, 28, 28, 26, 21, 14, 22, 24, 24, 22,
+ 21, 21, 8, 17, 19, 19, 19, 20, 21, 7, 14, 17, 17, 18, 19, 19, 24, 25, 26,
+ 28, 30, 30, 24, 20, 24, 25, 27, 27, 27, 22, 17, 23, 24, 24, 24, 23, 20, 13,
+ 19, 20, 20, 20, 19, 17, 11, 14, 16, 16, 14, 13, 14, 8, 9, 11, 10, 11, 12,
+ 10, 7, 5, 8, 9, 10, 10, 9, 12, 18, 19, 20, 22, 22, 23, 9, 17, 18, 19,
+ 20, 19, 22, 9, 15, 16, 16, 16, 16, 16, 9, 11, 13, 13, 12, 10, 10, 6, 5,
+ 8, 8, 4, 6, 8, 4, 3, 1, 2, 3, 5, 8, 3, 2, 2, 1, 2, 4, 7,
+ 8, 12, 14, 15, 18, 21, 22, 8, 10, 12, 14, 16, 18, 18, 8, 8, 10, 10, 13,
+ 14, 14, 8, 7, 7, 7, 8, 9, 7, 6, 5, 6, 5, 3, 4, 7, 3, 3, 5,
+ 4, 3, 2, 6, 0, 3, 5, 5, 3, 2, 5, 8, 11, 11, 11, 16, 19, 20, 9,
+ 11, 12, 10, 14, 16, 17, 9, 11, 12, 9, 10, 12, 13, 9, 10, 11, 8, 6, 6,
+ 6, 7, 8, 10, 7, 4, 2, 5, 5, 7, 8, 7, 4, 3, 3, 4, 5, 7, 8,
+ 4, 3, 2, 39, 43, 46, 51, 52, 48, 44, 38, 42, 45, 50, 49, 46, 43, 36, 39,
+ 44, 48, 48, 45, 39, 35, 38, 42, 44, 45, 40, 34, 31, 35, 36, 40, 41, 37, 34,
+ 27, 30, 33, 34, 38, 38, 34, 22, 26, 29, 34, 37, 37, 33, 36, 40, 46, 48, 48,
+ 43, 41, 34, 38, 42, 47, 47, 42, 38, 32, 36, 41, 43, 44, 41, 35, 31, 34, 38,
+ 41, 40, 37, 30, 27, 32, 34, 36, 34, 33, 30, 21, 27, 30, 31, 32, 33, 30, 15,
+ 23, 25, 30, 30, 30, 29, 33, 36, 40, 41, 42, 40, 35, 31, 35, 38, 40, 41, 39,
+ 33, 28, 34, 37, 38, 36, 36, 31, 24, 31, 33, 33, 33, 31, 26, 17, 27, 28, 29,
+ 27, 26, 26, 12, 22, 25, 24, 24, 25, 26, 10, 18, 22, 23, 23, 24, 24, 27, 31,
+ 32, 34, 35, 35, 28, 23, 30, 31, 32, 32, 33, 25, 20, 28, 30, 29, 29, 28, 24,
+ 16, 24, 25, 26, 25, 22, 22, 13, 18, 21, 21, 18, 18, 18, 12, 11, 17, 16, 16,
+ 17, 14, 10, 7, 15, 14, 15, 15, 11, 15, 23, 24, 25, 26, 25, 28, 12, 20, 22,
+ 24, 24, 22, 26, 12, 17, 21, 21, 20, 18, 20, 12, 11, 17, 16, 16, 12, 14, 10,
+ 5, 13, 12, 9, 8, 10, 7, 5, 7, 6, 7, 7, 9, 5, 4, 4, 4, 5, 7,
+ 8, 9, 16, 18, 19, 22, 23, 25, 9, 13, 16, 18, 20, 20, 22, 9, 9, 14, 14,
+ 16, 17, 16, 9, 8, 10, 10, 12, 11, 9, 7, 6, 5, 5, 4, 7, 9, 4, 3,
+ 3, 3, 2, 5, 9, 4, 0, 3, 4, 2, 4, 7, 9, 9, 10, 15, 19, 22, 22,
+ 9, 9, 10, 13, 18, 19, 19, 9, 9, 11, 11, 13, 15, 14, 9, 8, 10, 7, 9,
+ 9, 7, 7, 7, 8, 6, 3, 4, 7, 5, 5, 6, 5, 3, 3, 6, 2, 4, 5,
+ 5, 3, 2, 5, 44, 47, 53, 55, 56, 52, 48, 42, 47, 51, 53, 55, 51, 47, 41,
+ 45, 50, 51, 54, 50, 44, 39, 42, 44, 49, 50, 47, 40, 36, 39, 42, 46, 46, 42,
+ 39, 31, 34, 38, 40, 44, 43, 39, 27, 31, 35, 39, 42, 43, 39, 40, 45, 49, 52,
+ 52, 48, 45, 39, 44, 47, 52, 50, 47, 42, 36, 42, 45, 48, 49, 45, 39, 35, 39,
+ 42, 44, 44, 41, 34, 28, 36, 39, 41, 39, 38, 35, 23, 32, 35, 36, 37, 36, 35,
+ 18, 29, 32, 36, 35, 36, 34, 36, 42, 44, 45, 47, 44, 38, 33, 41, 41, 45, 45,
+ 43, 37, 30, 39, 40, 41, 41, 39, 34, 25, 35, 37, 37, 37, 36, 30, 20, 31, 34,
+ 34, 31, 30, 30, 15, 26, 30, 29, 30, 29, 30, 13, 22, 28, 28, 28, 29, 28, 29,
+ 35, 36, 38, 39, 38, 31, 26, 34, 36, 37, 37, 35, 29, 22, 31, 34, 33, 34, 31,
+ 27, 18, 27, 30, 29, 30, 26, 25, 16, 20, 26, 25, 24, 21, 22, 15, 14, 22, 21,
+ 21, 20, 17, 14, 10, 19, 20, 20, 19, 14, 17, 25, 28, 30, 29, 26, 31, 14, 23,
+ 27, 28, 28, 23, 29, 14, 19, 25, 25, 24, 20, 24, 14, 13, 21, 20, 21, 13, 16,
+ 12, 8, 16, 16, 13, 10, 13, 9, 5, 11, 11, 12, 9, 11, 9, 6, 8, 10, 10,
+ 8, 10, 10, 16, 19, 21, 22, 24, 27, 10, 12, 18, 20, 21, 22, 23, 9, 8, 17,
+ 16, 17, 18, 18, 10, 8, 13, 12, 13, 12, 11, 8, 5, 7, 7, 5, 8, 10, 6,
+ 5, 2, 1, 4, 7, 9, 5, 3, 0, 2, 4, 6, 8, 9, 8, 12, 17, 21, 23,
+ 24, 9, 8, 11, 16, 20, 20, 20, 9, 8, 9, 13, 15, 16, 16, 8, 7, 7, 8,
+ 11, 11, 9, 6, 5, 5, 3, 4, 5, 8, 4, 3, 4, 4, 2, 5, 7, 3, 2,
+ 4, 4, 2, 4, 6, 44, 48, 53, 55, 55, 53, 49, 41, 48, 50, 54, 54, 52, 48,
+ 40, 44, 49, 52, 53, 49, 44, 39, 42, 47, 48, 51, 47, 42, 35, 39, 42, 45, 46,
+ 44, 40, 31, 34, 38, 42, 44, 43, 40, 27, 33, 36, 39, 43, 43, 40, 41, 44, 48,
+ 53, 53, 48, 43, 39, 45, 48, 51, 50, 47, 42, 36, 42, 46, 48, 48, 46, 39, 33,
+ 40, 43, 46, 45, 42, 35, 28, 36, 40, 41, 40, 38, 35, 22, 32, 35, 39, 38, 37,
+ 35, 18, 29, 34, 37, 35, 36, 36, 36, 41, 44, 45, 46, 44, 37, 34, 39, 43, 44,
+ 43, 41, 35, 29, 39, 41, 41, 40, 39, 33, 26, 37, 37, 37, 37, 36, 30, 19, 31,
+ 34, 34, 32, 30, 29, 15, 26, 31, 30, 30, 29, 29, 14, 21, 30, 29, 29, 28, 27,
+ 30, 36, 38, 38, 38, 36, 30, 25, 33, 35, 37, 35, 33, 28, 21, 30, 34, 34, 32,
+ 30, 26, 17, 24, 31, 30, 30, 24, 25, 15, 19, 26, 27, 24, 20, 21, 15, 14, 24,
+ 23, 22, 19, 17, 14, 10, 20, 22, 21, 18, 14, 16, 25, 29, 30, 27, 24, 30, 13,
+ 22, 27, 28, 26, 20, 28, 13, 17, 25, 24, 23, 17, 23, 13, 12, 21, 21, 19, 12,
+ 17, 11, 7, 17, 17, 13, 8, 13, 10, 6, 12, 13, 12, 7, 10, 9, 6, 8, 12,
+ 11, 7, 9, 9, 14, 19, 20, 19, 22, 26, 9, 10, 18, 18, 18, 19, 22, 9, 6,
+ 16, 15, 15, 16, 16, 9, 5, 12, 12, 11, 11, 10, 7, 4, 6, 7, 5, 7, 8,
+ 5, 3, 2, 2, 3, 5, 8, 5, 3, 2, 0, 3, 5, 7, 7, 7, 12, 16, 18,
+ 20, 22, 7, 7, 11, 14, 17, 17, 18, 7, 7, 9, 12, 13, 14, 14, 7, 6, 5,
+ 8, 9, 9, 8, 5, 4, 3, 2, 4, 5, 7, 3, 2, 5, 4, 2, 4, 6, 3,
+ 1, 5, 5, 1, 4, 5, 38, 42, 47, 47, 48, 47, 43, 36, 41, 44, 48, 49, 45,
+ 41, 34, 39, 43, 45, 47, 44, 38, 33, 36, 40, 43, 45, 41, 34, 31, 33, 37, 39,
+ 41, 39, 35, 26, 29, 32, 35, 39, 37, 35, 23, 28, 31, 34, 38, 38, 34, 34, 39,
+ 43, 47, 46, 41, 38, 34, 38, 41, 45, 44, 40, 36, 31, 35, 40, 43, 42, 39, 33,
+ 29, 34, 36, 40, 39, 36, 30, 24, 30, 33, 36, 35, 33, 30, 21, 27, 30, 32, 32,
+ 32, 29, 16, 26, 29, 31, 31, 31, 30, 31, 35, 38, 39, 39, 37, 31, 29, 35, 37,
+ 38, 38, 35, 30, 26, 32, 35, 35, 36, 33, 27, 22, 31, 32, 31, 32, 30, 24, 16,
+ 26, 27, 28, 27, 25, 24, 11, 24, 25, 26, 25, 24, 24, 11, 20, 24, 24, 24, 24,
+ 22, 25, 30, 30, 31, 32, 30, 24, 21, 29, 28, 30, 31, 28, 22, 18, 26, 28, 28,
+ 27, 24, 21, 15, 21, 24, 25, 24, 20, 20, 12, 15, 21, 20, 20, 16, 16, 11, 12,
+ 18, 18, 17, 15, 12, 11, 8, 17, 17, 16, 15, 9, 13, 21, 23, 24, 23, 19, 24,
+ 10, 19, 22, 22, 21, 16, 23, 10, 14, 19, 19, 18, 13, 17, 10, 9, 16, 16, 15,
+ 8, 12, 8, 4, 12, 12, 10, 5, 9, 7, 4, 9, 8, 8, 4, 6, 7, 4, 6,
+ 7, 7, 4, 5, 6, 12, 14, 15, 15, 17, 20, 6, 8, 12, 13, 14, 14, 16, 6,
+ 5, 11, 10, 11, 11, 12, 6, 4, 8, 7, 7, 7, 6, 4, 2, 2, 2, 3, 4,
+ 5, 2, 2, 3, 3, 2, 3, 5, 3, 2, 4, 3, 0, 3, 4, 5, 5, 10, 12,
+ 14, 16, 17, 5, 6, 9, 11, 12, 13, 13, 5, 6, 8, 9, 9, 10, 10, 5, 5,
+ 4, 5, 6, 6, 5, 3, 2, 3, 3, 1, 3, 4, 2, 3, 5, 4, 2, 2, 4,
+ 2, 4, 5, 4, 3, 2, 3, 31, 36, 40, 43, 43, 40, 36, 30, 33, 38, 43, 43,
+ 39, 35, 28, 32, 37, 39, 42, 37, 33, 28, 30, 33, 36, 40, 35, 29, 25, 27, 29,
+ 33, 35, 32, 29, 21, 24, 26, 30, 34, 32, 29, 20, 21, 26, 29, 32, 32, 29, 29,
+ 32, 36, 40, 38, 35, 33, 29, 31, 35, 38, 37, 35, 30, 26, 30, 33, 36, 36, 32,
+ 29, 25, 28, 30, 33, 33, 31, 24, 20, 25, 27, 29, 29, 27, 24, 18, 22, 25, 27,
+ 27, 27, 24, 14, 21, 24, 26, 26, 26, 24, 26, 30, 32, 33, 34, 32, 27, 25, 29,
+ 30, 31, 31, 30, 25, 23, 27, 29, 29, 29, 28, 22, 18, 26, 25, 26, 26, 24, 19,
+ 13, 22, 22, 22, 22, 21, 19, 9, 20, 20, 20, 20, 20, 19, 9, 17, 20, 18, 19,
+ 19, 17, 23, 24, 24, 26, 27, 25, 19, 18, 23, 23, 25, 24, 22, 17, 14, 22, 22,
+ 21, 22, 19, 16, 11, 18, 19, 18, 18, 16, 14, 9, 13, 15, 14, 14, 12, 11, 9,
+ 10, 13, 12, 12, 12, 8, 9, 7, 12, 11, 11, 11, 5, 10, 17, 17, 18, 18, 15,
+ 19, 7, 15, 16, 16, 16, 12, 17, 6, 12, 13, 13, 13, 9, 12, 7, 6, 10, 9,
+ 9, 6, 7, 5, 2, 6, 5, 5, 3, 5, 4, 2, 4, 3, 3, 3, 4, 4, 3,
+ 2, 2, 2, 2, 3, 4, 9, 9, 10, 11, 13, 16, 4, 7, 9, 9, 10, 11, 12,
+ 4, 4, 8, 7, 8, 8, 8, 4, 3, 4, 4, 4, 5, 4, 2, 1, 4, 3, 1,
+ 2, 3, 2, 3, 6, 4, 2, 2, 3, 2, 5, 6, 5, 3, 0, 3, 4, 5, 6,
+ 8, 10, 12, 13, 4, 5, 6, 8, 9, 10, 10, 4, 5, 6, 5, 6, 6, 7, 4,
+ 4, 6, 3, 2, 3, 3, 2, 4, 8, 5, 3, 0, 3, 3, 6, 7, 7, 4, 2,
+ 2, 5, 7, 7, 8, 5, 2, 2, 25, 28, 34, 37, 37, 34, 31, 24, 28, 32, 36,
+ 37, 32, 29, 23, 26, 30, 34, 36, 32, 27, 22, 24, 28, 31, 34, 30, 24, 19, 21,
+ 24, 27, 31, 28, 24, 17, 18, 21, 24, 29, 28, 24, 15, 17, 21, 24, 27, 27, 24,
+ 23, 27, 31, 34, 33, 30, 27, 22, 25, 29, 33, 33, 28, 25, 20, 24, 28, 31, 30,
+ 27, 24, 20, 22, 24, 28, 27, 26, 20, 17, 18, 21, 23, 24, 23, 20, 15, 17, 19,
+ 21, 22, 22, 20, 12, 16, 19, 21, 21, 21, 20, 21, 24, 26, 27, 28, 26, 22, 20,
+ 23, 24, 25, 26, 25, 20, 19, 21, 23, 23, 23, 22, 18, 16, 20, 20, 20, 19, 19,
+ 14, 10, 16, 16, 16, 16, 16, 14, 7, 16, 15, 15, 15, 15, 15, 7, 14, 14, 14,
+ 14, 14, 13, 18, 19, 19, 20, 21, 21, 14, 15, 17, 18, 19, 19, 18, 12, 12, 16,
+ 16, 16, 15, 15, 11, 8, 14, 13, 12, 12, 12, 10, 6, 10, 9, 9, 8, 8, 7,
+ 6, 8, 8, 7, 7, 7, 4, 7, 4, 6, 6, 6, 6, 3, 8, 11, 11, 12, 13,
+ 12, 14, 3, 9, 10, 10, 11, 9, 12, 4, 8, 8, 7, 7, 7, 8, 3, 4, 4,
+ 4, 3, 3, 3, 1, 1, 1, 1, 1, 1, 3, 2, 3, 4, 3, 2, 0, 2, 3,
+ 5, 5, 3, 2, 2, 2, 3, 5, 6, 7, 8, 10, 12, 3, 4, 6, 7, 7, 8,
+ 9, 3, 4, 4, 4, 5, 5, 6, 3, 3, 4, 3, 2, 2, 2, 1, 5, 6, 4,
+ 3, 2, 2, 3, 6, 8, 6, 3, 2, 1, 5, 7, 8, 7, 4, 3, 0, 5, 7,
+ 6, 6, 8, 9, 10, 5, 7, 6, 6, 6, 7, 7, 5, 7, 8, 4, 3, 4, 4,
+ 5, 7, 8, 5, 3, 2, 1, 5, 8, 9, 7, 4, 3, 0, 6, 8, 10, 9, 5,
+ 3, 2, 7, 9, 10, 10, 6, 4, 2, 31, 36, 39, 41, 40, 39, 36, 31, 35, 38,
+ 41, 41, 38, 36, 30, 33, 36, 40, 42, 39, 36, 29, 32, 36, 39, 41, 39, 38, 28,
+ 31, 35, 38, 42, 40, 37, 28, 30, 34, 38, 41, 42, 36, 25, 29, 33, 37, 40, 40,
+ 37, 29, 32, 36, 40, 38, 35, 32, 28, 32, 35, 38, 38, 34, 32, 27, 30, 34, 38,
+ 38, 34, 32, 25, 29, 34, 36, 37, 36, 32, 25, 29, 32, 36, 36, 36, 33, 24, 28,
+ 32, 35, 36, 35, 32, 21, 26, 30, 34, 34, 35, 32, 27, 31, 31, 32, 33, 30, 25,
+ 27, 29, 30, 30, 32, 29, 25, 24, 28, 29, 30, 30, 30, 25, 21, 27, 28, 29, 30,
+ 30, 25, 19, 27, 28, 28, 29, 30, 26, 15, 24, 26, 28, 28, 28, 26, 16, 22, 25,
+ 26, 26, 26, 25, 24, 25, 25, 25, 25, 22, 13, 22, 23, 23, 25, 24, 21, 14, 17,
+ 22, 22, 23, 22, 20, 15, 14, 22, 21, 22, 23, 20, 17, 15, 19, 20, 21, 21, 19,
+ 14, 15, 17, 19, 19, 19, 18, 10, 16, 14, 17, 17, 18, 17, 8, 12, 16, 16, 17,
+ 15, 10, 12, 9, 15, 15, 15, 14, 10, 13, 9, 13, 13, 13, 13, 8, 12, 9, 9,
+ 13, 13, 12, 9, 10, 10, 7, 11, 11, 11, 6, 8, 10, 9, 8, 9, 9, 5, 8,
+ 12, 11, 9, 7, 7, 4, 7, 4, 6, 6, 6, 7, 9, 10, 4, 4, 4, 5, 5,
+ 9, 10, 4, 2, 2, 3, 5, 7, 9, 4, 2, 1, 1, 3, 6, 8, 5, 4, 4,
+ 4, 4, 4, 7, 7, 6, 8, 6, 4, 4, 6, 9, 9, 9, 7, 5, 4, 5, 0,
+ 4, 3, 1, 4, 7, 9, 0, 4, 4, 2, 4, 6, 8, 0, 4, 5, 2, 2, 5,
+ 8, 0, 3, 4, 2, 2, 4, 6, 2, 4, 5, 5, 5, 4, 5, 5, 6, 8, 8,
+ 5, 5, 4, 8, 8, 9, 9, 6, 5, 4, 37, 41, 45, 47, 47, 45, 41, 37, 40,
+ 44, 46, 48, 46, 42, 36, 39, 42, 47, 47, 46, 43, 34, 37, 41, 45, 48, 46, 42,
+ 34, 37, 41, 45, 49, 46, 42, 33, 36, 41, 44, 47, 45, 42, 30, 35, 38, 43, 47,
+ 46, 42, 36, 39, 42, 45, 43, 41, 36, 34, 37, 41, 44, 44, 39, 36, 33, 36, 40,
+ 42, 43, 40, 36, 32, 36, 38, 43, 42, 42, 37, 30, 35, 38, 42, 41, 40, 37, 28,
+ 34, 38, 41, 41, 40, 37, 25, 31, 36, 40, 40, 40, 37, 33, 36, 38, 38, 37, 34,
+ 28, 31, 34, 36, 38, 36, 34, 28, 28, 34, 36, 36, 35, 34, 29, 25, 34, 34, 36,
+ 36, 34, 30, 22, 32, 34, 35, 35, 34, 30, 19, 30, 33, 33, 33, 32, 30, 18, 28,
+ 31, 31, 32, 32, 28, 28, 31, 31, 30, 29, 25, 16, 25, 29, 29, 30, 28, 24, 18,
+ 21, 28, 28, 28, 27, 23, 20, 17, 26, 29, 27, 27, 23, 23, 18, 23, 27, 27, 26,
+ 22, 19, 19, 20, 25, 25, 25, 21, 15, 18, 17, 23, 24, 24, 21, 11, 16, 22, 22,
+ 22, 16, 12, 16, 12, 19, 21, 21, 16, 11, 18, 13, 16, 19, 19, 16, 9, 15, 13,
+ 12, 19, 19, 15, 11, 14, 14, 10, 17, 17, 13, 8, 11, 13, 11, 14, 14, 12, 7,
+ 10, 14, 13, 12, 13, 11, 6, 8, 7, 11, 12, 9, 9, 11, 13, 7, 8, 10, 8,
+ 7, 9, 12, 7, 5, 8, 7, 6, 8, 10, 7, 4, 7, 6, 6, 8, 10, 8, 6,
+ 5, 5, 4, 6, 9, 9, 8, 8, 7, 5, 6, 8, 11, 9, 8, 7, 6, 5, 7,
+ 4, 0, 2, 4, 6, 9, 11, 4, 0, 2, 3, 5, 7, 10, 4, 0, 3, 2, 6,
+ 9, 10, 4, 1, 3, 2, 4, 5, 8, 4, 3, 5, 5, 5, 5, 7, 6, 6, 8,
+ 8, 6, 5, 6, 7, 9, 8, 8, 7, 5, 6, 36, 40, 42, 44, 44, 42, 39, 35,
+ 38, 42, 44, 45, 42, 38, 34, 37, 41, 44, 45, 42, 40, 33, 37, 41, 45, 46, 43,
+ 40, 33, 36, 40, 43, 47, 44, 39, 32, 35, 39, 43, 46, 44, 40, 30, 34, 38, 41,
+ 45, 44, 39, 34, 37, 40, 43, 41, 36, 34, 32, 35, 39, 42, 42, 37, 33, 31, 35,
+ 38, 40, 41, 37, 34, 31, 35, 37, 41, 41, 39, 34, 29, 35, 36, 40, 39, 39, 35,
+ 27, 33, 36, 39, 39, 38, 35, 24, 31, 35, 38, 37, 37, 35, 31, 34, 36, 35, 35,
+ 31, 24, 29, 33, 34, 35, 34, 31, 24, 27, 33, 34, 34, 32, 31, 26, 23, 33, 33,
+ 34, 33, 31, 27, 21, 31, 33, 33, 33, 29, 27, 18, 29, 32, 31, 31, 30, 28, 18,
+ 27, 30, 30, 31, 29, 25, 27, 29, 28, 28, 27, 22, 14, 22, 28, 27, 27, 25, 20,
+ 16, 19, 26, 27, 27, 25, 20, 18, 15, 24, 27, 26, 25, 20, 21, 17, 22, 25, 25,
+ 24, 19, 17, 17, 19, 24, 25, 23, 18, 14, 18, 16, 22, 22, 22, 18, 10, 14, 20,
+ 20, 20, 14, 8, 14, 11, 18, 19, 19, 14, 8, 15, 11, 14, 19, 18, 13, 7, 14,
+ 11, 11, 18, 18, 13, 7, 13, 13, 9, 16, 16, 12, 6, 9, 12, 11, 14, 14, 11,
+ 6, 7, 14, 13, 12, 12, 10, 6, 7, 6, 10, 11, 7, 5, 7, 10, 6, 7, 9,
+ 7, 5, 7, 9, 6, 3, 8, 6, 5, 7, 8, 6, 4, 7, 6, 4, 6, 7, 7,
+ 6, 5, 5, 6, 6, 7, 9, 8, 11, 11, 8, 6, 7, 11, 10, 12, 12, 10, 6,
+ 6, 3, 2, 0, 3, 4, 6, 8, 3, 2, 2, 2, 4, 5, 7, 3, 2, 3, 2,
+ 4, 6, 7, 3, 2, 6, 4, 4, 5, 6, 4, 5, 10, 11, 9, 6, 6, 6, 10,
+ 15, 16, 11, 7, 6, 9, 14, 17, 17, 13, 8, 6, 28, 32, 36, 38, 38, 36, 32,
+ 29, 31, 35, 38, 39, 36, 32, 27, 31, 34, 37, 39, 36, 33, 26, 30, 34, 37, 40,
+ 37, 34, 27, 30, 33, 36, 40, 38, 34, 26, 29, 32, 36, 39, 38, 34, 24, 27, 30,
+ 35, 37, 38, 34, 28, 30, 34, 36, 34, 30, 27, 26, 28, 32, 35, 34, 31, 27, 25,
+ 28, 32, 34, 34, 32, 28, 24, 28, 31, 35, 34, 32, 28, 24, 28, 31, 34, 34, 34,
+ 29, 23, 27, 29, 33, 33, 33, 29, 21, 25, 28, 31, 32, 31, 29, 26, 29, 29, 28,
+ 29, 25, 19, 25, 26, 28, 28, 28, 25, 19, 23, 26, 27, 28, 28, 25, 20, 19, 26,
+ 27, 28, 27, 26, 22, 17, 25, 27, 26, 26, 25, 22, 15, 25, 25, 25, 26, 24, 22,
+ 16, 22, 24, 24, 24, 24, 20, 22, 23, 22, 21, 21, 17, 8, 18, 22, 21, 21, 20,
+ 16, 10, 15, 21, 21, 21, 20, 16, 13, 12, 20, 21, 20, 19, 16, 16, 14, 18, 21,
+ 20, 19, 15, 12, 15, 16, 18, 18, 17, 15, 9, 16, 15, 16, 17, 16, 14, 6, 11,
+ 15, 15, 14, 10, 5, 8, 7, 14, 13, 13, 10, 5, 10, 8, 11, 12, 12, 10, 5,
+ 9, 7, 9, 12, 12, 10, 5, 8, 9, 7, 11, 11, 9, 6, 6, 10, 9, 10, 9,
+ 8, 6, 5, 13, 13, 13, 10, 8, 7, 5, 3, 6, 5, 4, 3, 4, 6, 3, 4,
+ 4, 3, 3, 4, 5, 3, 2, 2, 2, 3, 4, 6, 3, 2, 4, 4, 4, 5, 5,
+ 5, 6, 9, 9, 8, 7, 5, 7, 10, 16, 14, 10, 7, 6, 11, 15, 17, 15, 12,
+ 8, 6, 2, 4, 3, 0, 2, 3, 4, 2, 4, 4, 2, 2, 3, 5, 2, 4, 5,
+ 3, 2, 3, 4, 2, 6, 9, 7, 6, 5, 5, 5, 9, 13, 12, 11, 8, 6, 9,
+ 14, 18, 18, 13, 10, 7, 14, 18, 19, 19, 15, 11, 7, 24, 27, 30, 33, 32, 30,
+ 27, 24, 26, 29, 32, 33, 31, 27, 22, 25, 28, 31, 33, 31, 29, 21, 25, 28, 32,
+ 34, 32, 29, 22, 25, 27, 31, 35, 33, 29, 21, 24, 27, 30, 34, 33, 29, 19, 22,
+ 25, 29, 33, 33, 28, 21, 24, 28, 30, 29, 25, 23, 21, 24, 27, 30, 29, 25, 22,
+ 20, 22, 26, 29, 28, 27, 23, 20, 22, 26, 29, 28, 27, 24, 21, 23, 26, 29, 29,
+ 27, 23, 19, 21, 24, 28, 27, 27, 24, 16, 20, 23, 26, 26, 26, 24, 20, 22, 23,
+ 23, 23, 20, 15, 19, 22, 22, 23, 22, 20, 16, 19, 20, 22, 23, 22, 21, 17, 16,
+ 22, 23, 23, 23, 21, 18, 15, 21, 21, 21, 22, 21, 18, 13, 19, 20, 20, 21, 20,
+ 17, 17, 18, 19, 19, 19, 20, 17, 19, 17, 16, 17, 16, 13, 5, 16, 16, 16, 16,
+ 15, 12, 6, 13, 16, 15, 16, 15, 13, 9, 10, 16, 16, 15, 15, 13, 12, 11, 14,
+ 14, 14, 14, 12, 8, 12, 13, 13, 13, 13, 12, 6, 17, 18, 13, 12, 12, 11, 5,
+ 8, 10, 9, 9, 8, 3, 5, 5, 9, 8, 8, 7, 3, 6, 5, 8, 7, 7, 7,
+ 3, 5, 5, 6, 7, 7, 7, 5, 5, 6, 7, 7, 7, 8, 7, 5, 9, 12, 14,
+ 12, 9, 8, 6, 15, 18, 17, 13, 10, 8, 6, 2, 1, 1, 1, 2, 3, 3, 2,
+ 3, 2, 1, 1, 3, 4, 2, 3, 3, 3, 2, 3, 4, 2, 5, 7, 7, 6, 5,
+ 6, 5, 10, 13, 12, 11, 8, 6, 10, 15, 19, 17, 12, 9, 7, 16, 19, 21, 18,
+ 14, 10, 8, 4, 6, 4, 2, 0, 2, 3, 4, 6, 5, 3, 1, 2, 3, 4, 6,
+ 7, 5, 5, 3, 4, 4, 8, 12, 9, 8, 7, 7, 8, 12, 16, 15, 13, 10, 8,
+ 13, 16, 20, 21, 15, 11, 9, 18, 22, 21, 21, 17, 13, 9, 19, 23, 25, 29, 28,
+ 25, 22, 19, 21, 24, 27, 28, 26, 23, 17, 20, 24, 27, 30, 27, 24, 17, 20, 24,
+ 28, 30, 29, 25, 18, 20, 23, 27, 31, 28, 25, 16, 19, 22, 26, 29, 29, 25, 16,
+ 18, 22, 25, 28, 29, 26, 18, 20, 23, 25, 23, 21, 18, 16, 19, 23, 25, 25, 21,
+ 19, 15, 18, 21, 25, 24, 22, 20, 15, 19, 22, 25, 24, 23, 20, 16, 18, 21, 24,
+ 24, 23, 21, 14, 17, 20, 23, 23, 23, 20, 18, 18, 19, 22, 22, 22, 21, 15, 18,
+ 19, 19, 19, 16, 13, 15, 17, 18, 18, 18, 17, 13, 15, 16, 18, 18, 18, 18, 14,
+ 14, 17, 18, 18, 18, 18, 15, 12, 15, 17, 17, 17, 17, 15, 13, 15, 16, 17, 16,
+ 16, 15, 20, 19, 16, 15, 15, 15, 13, 15, 13, 12, 12, 12, 11, 2, 14, 12, 12,
+ 11, 11, 10, 3, 11, 11, 11, 12, 11, 11, 6, 7, 11, 11, 11, 11, 10, 9, 9,
+ 10, 10, 10, 10, 10, 6, 13, 14, 13, 11, 9, 9, 6, 19, 21, 16, 13, 10, 8,
+ 7, 6, 5, 5, 5, 4, 2, 3, 2, 4, 4, 3, 3, 2, 3, 2, 2, 2, 3,
+ 3, 3, 4, 2, 3, 5, 5, 6, 6, 6, 5, 10, 10, 10, 10, 8, 7, 11, 16,
+ 17, 15, 11, 9, 7, 18, 21, 20, 15, 13, 10, 8, 3, 4, 2, 2, 1, 2, 2,
+ 3, 4, 3, 2, 2, 2, 3, 3, 6, 4, 5, 5, 4, 4, 3, 8, 9, 9, 8,
+ 7, 7, 8, 12, 15, 14, 13, 10, 8, 13, 17, 20, 19, 14, 11, 8, 19, 22, 23,
+ 21, 16, 12, 9, 7, 9, 6, 3, 2, 0, 2, 7, 9, 7, 4, 3, 2, 2, 7,
+ 9, 9, 7, 6, 5, 5, 7, 11, 14, 12, 10, 9, 8, 10, 15, 18, 17, 15, 13,
+ 9, 15, 19, 22, 23, 17, 13, 10, 20, 23, 23, 24, 19, 15, 11, 15, 18, 21, 24,
+ 25, 22, 18, 14, 17, 20, 24, 25, 22, 20, 13, 16, 20, 23, 26, 24, 21, 12, 16,
+ 20, 23, 26, 24, 21, 13, 16, 19, 23, 27, 24, 21, 12, 16, 18, 22, 25, 24, 21,
+ 17, 16, 17, 21, 24, 24, 21, 13, 16, 19, 21, 21, 18, 15, 12, 15, 18, 20, 20,
+ 18, 15, 11, 14, 17, 20, 21, 19, 16, 10, 14, 18, 21, 21, 19, 17, 11, 14, 17,
+ 20, 20, 20, 17, 12, 13, 16, 19, 19, 19, 16, 19, 17, 16, 18, 18, 18, 17, 11,
+ 14, 15, 15, 16, 14, 10, 10, 13, 14, 14, 14, 13, 10, 9, 11, 13, 14, 14, 14,
+ 11, 9, 12, 14, 14, 14, 14, 12, 8, 11, 13, 13, 13, 13, 12, 14, 14, 14, 13,
+ 12, 12, 12, 22, 20, 16, 13, 11, 11, 11, 9, 9, 8, 8, 9, 9, 2, 8, 7,
+ 7, 7, 7, 7, 2, 6, 6, 7, 7, 7, 7, 3, 6, 6, 7, 7, 7, 7, 6,
+ 7, 8, 9, 9, 9, 7, 6, 14, 16, 14, 12, 10, 8, 6, 21, 22, 17, 13, 10,
+ 8, 7, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2,
+ 4, 4, 3, 3, 2, 6, 6, 7, 7, 7, 6, 6, 11, 12, 11, 11, 9, 7, 13,
+ 17, 18, 15, 12, 10, 7, 20, 22, 21, 16, 13, 11, 8, 6, 5, 4, 3, 2, 1,
+ 2, 5, 7, 4, 3, 3, 2, 2, 6, 9, 6, 6, 5, 4, 4, 6, 10, 10, 10,
+ 9, 8, 7, 9, 14, 16, 15, 13, 11, 8, 15, 19, 22, 19, 15, 12, 9, 20, 23,
+ 24, 22, 16, 13, 10, 9, 11, 7, 4, 3, 2, 0, 10, 11, 9, 5, 3, 3, 3,
+ 9, 11, 12, 8, 7, 6, 5, 9, 13, 16, 13, 11, 10, 9, 12, 16, 20, 19, 16,
+ 13, 10, 17, 20, 24, 24, 18, 14, 11, 21, 25, 25, 25, 20, 16, 12, 32, 36, 39,
+ 42, 41, 39, 35, 31, 35, 37, 41, 41, 40, 35, 29, 33, 36, 39, 41, 39, 36, 29,
+ 32, 35, 39, 42, 40, 37, 29, 31, 35, 39, 42, 41, 37, 27, 31, 34, 38, 42, 40,
+ 36, 24, 28, 33, 37, 40, 41, 37, 30, 33, 36, 38, 38, 35, 31, 28, 31, 36, 38,
+ 37, 34, 32, 27, 31, 34, 37, 37, 35, 31, 25, 30, 34, 37, 36, 35, 33, 26, 29,
+ 33, 36, 36, 36, 33, 24, 29, 31, 35, 36, 35, 32, 21, 26, 30, 34, 34, 34, 32,
+ 27, 30, 31, 32, 33, 30, 24, 25, 29, 31, 32, 31, 30, 25, 25, 27, 28, 30, 31,
+ 30, 25, 21, 27, 28, 30, 29, 30, 26, 19, 26, 29, 30, 29, 28, 25, 15, 25, 26,
+ 28, 27, 27, 25, 16, 23, 24, 25, 27, 27, 25, 24, 24, 25, 25, 25, 22, 13, 21,
+ 23, 24, 24, 24, 21, 14, 17, 22, 22, 23, 22, 20, 15, 14, 22, 21, 22, 22, 20,
+ 18, 14, 19, 20, 21, 21, 19, 14, 15, 17, 19, 19, 19, 18, 11, 16, 14, 16, 18,
+ 18, 17, 8, 12, 16, 17, 17, 15, 10, 12, 9, 15, 15, 15, 14, 10, 13, 9, 13,
+ 13, 13, 12, 8, 11, 9, 10, 13, 13, 12, 9, 10, 10, 7, 11, 11, 10, 6, 8,
+ 10, 9, 8, 9, 9, 5, 8, 12, 11, 9, 7, 7, 4, 7, 4, 6, 6, 6, 7,
+ 9, 11, 4, 4, 4, 5, 6, 9, 10, 4, 2, 2, 3, 4, 7, 9, 4, 2, 1,
+ 1, 4, 6, 8, 5, 4, 4, 4, 4, 4, 7, 7, 6, 8, 6, 5, 4, 6, 8,
+ 9, 9, 7, 5, 4, 5, 0, 4, 3, 2, 4, 7, 9, 0, 4, 4, 2, 3, 7,
+ 9, 0, 4, 5, 2, 2, 6, 8, 0, 4, 5, 2, 2, 4, 6, 2, 4, 5, 5,
+ 5, 4, 5, 4, 6, 8, 8, 5, 5, 4, 8, 8, 9, 9, 6, 5, 4, 37, 41,
+ 45, 47, 47, 44, 41, 36, 40, 43, 47, 47, 44, 41, 35, 38, 43, 46, 47, 44, 41,
+ 33, 37, 41, 45, 48, 45, 42, 35, 37, 41, 45, 48, 46, 43, 33, 37, 40, 43, 47,
+ 46, 43, 31, 35, 39, 43, 46, 46, 43, 34, 39, 43, 44, 44, 39, 36, 34, 37, 42,
+ 44, 43, 41, 36, 33, 36, 40, 43, 43, 39, 36, 31, 36, 40, 43, 43, 41, 37, 30,
+ 36, 39, 42, 42, 42, 38, 28, 34, 37, 40, 40, 41, 37, 25, 32, 37, 40, 39, 39,
+ 37, 32, 36, 38, 37, 37, 34, 28, 31, 35, 37, 37, 38, 34, 28, 28, 33, 34, 36,
+ 36, 34, 28, 25, 34, 35, 34, 35, 34, 30, 23, 33, 35, 34, 35, 34, 29, 18, 30,
+ 32, 34, 34, 32, 30, 18, 28, 32, 31, 33, 32, 28, 29, 30, 31, 31, 30, 25, 16,
+ 25, 30, 30, 30, 28, 23, 18, 21, 28, 28, 29, 27, 22, 20, 17, 26, 28, 28, 27,
+ 23, 22, 18, 23, 27, 27, 27, 22, 18, 19, 20, 25, 25, 25, 21, 15, 18, 17, 22,
+ 23, 24, 21, 11, 16, 22, 23, 22, 17, 12, 16, 12, 20, 21, 21, 16, 11, 18, 13,
+ 16, 20, 19, 15, 9, 15, 12, 12, 19, 19, 15, 11, 14, 14, 10, 17, 17, 13, 8,
+ 11, 13, 11, 15, 15, 13, 7, 10, 14, 13, 12, 13, 11, 6, 9, 7, 11, 12, 9,
+ 9, 11, 13, 7, 8, 10, 8, 7, 10, 12, 7, 5, 8, 7, 6, 8, 10, 7, 4,
+ 7, 6, 6, 8, 10, 8, 6, 5, 5, 5, 6, 9, 9, 8, 7, 7, 5, 6, 8,
+ 11, 9, 8, 7, 6, 5, 7, 4, 0, 2, 4, 6, 9, 11, 4, 0, 2, 3, 5,
+ 7, 10, 4, 0, 3, 2, 5, 9, 10, 4, 1, 3, 2, 4, 5, 8, 4, 3, 5,
+ 5, 5, 5, 7, 6, 6, 8, 8, 6, 5, 6, 7, 8, 8, 8, 6, 5, 6, 39,
+ 41, 46, 47, 47, 45, 41, 37, 41, 43, 47, 46, 43, 40, 37, 39, 42, 46, 48, 45,
+ 42, 35, 38, 43, 46, 48, 46, 43, 36, 39, 43, 45, 49, 46, 44, 35, 38, 42, 45,
+ 48, 47, 43, 32, 35, 40, 43, 47, 47, 43, 36, 39, 43, 45, 43, 39, 36, 35, 38,
+ 42, 43, 44, 40, 35, 34, 37, 42, 44, 42, 40, 36, 32, 37, 41, 43, 42, 40, 37,
+ 31, 37, 40, 43, 43, 41, 37, 29, 35, 39, 42, 42, 40, 37, 25, 33, 38, 41, 40,
+ 39, 37, 35, 37, 37, 38, 38, 33, 26, 31, 36, 37, 37, 36, 33, 27, 29, 35, 37,
+ 37, 36, 33, 28, 25, 34, 36, 37, 36, 33, 30, 23, 34, 36, 36, 35, 32, 30, 19,
+ 31, 34, 35, 35, 32, 30, 19, 29, 33, 33, 33, 31, 27, 29, 31, 31, 31, 30, 24,
+ 16, 25, 30, 31, 30, 27, 22, 18, 21, 28, 29, 30, 27, 22, 20, 18, 26, 29, 28,
+ 28, 22, 23, 19, 23, 28, 28, 26, 21, 19, 19, 20, 26, 26, 26, 20, 16, 19, 17,
+ 24, 24, 24, 20, 12, 16, 23, 23, 22, 16, 10, 16, 13, 20, 22, 21, 15, 10, 17,
+ 13, 16, 21, 20, 15, 9, 16, 12, 13, 21, 19, 15, 9, 15, 14, 11, 19, 19, 13,
+ 7, 11, 15, 12, 16, 16, 12, 7, 9, 15, 14, 14, 15, 11, 7, 8, 7, 12, 13,
+ 8, 7, 9, 12, 8, 7, 12, 8, 6, 8, 10, 7, 4, 10, 7, 6, 8, 10, 7,
+ 5, 9, 7, 5, 7, 9, 9, 7, 7, 5, 6, 7, 8, 10, 9, 9, 10, 7, 6,
+ 7, 12, 10, 11, 11, 9, 6, 7, 4, 2, 2, 3, 5, 7, 9, 4, 2, 0, 3,
+ 5, 6, 9, 4, 2, 2, 2, 5, 8, 9, 4, 2, 5, 3, 4, 6, 8, 5, 4,
+ 9, 10, 8, 6, 7, 7, 8, 14, 14, 11, 7, 6, 8, 12, 15, 15, 12, 8, 6,
+ 31, 35, 38, 40, 41, 38, 34, 30, 34, 37, 40, 41, 37, 34, 29, 31, 36, 39, 41,
+ 39, 35, 28, 32, 36, 38, 42, 39, 36, 29, 32, 35, 39, 42, 40, 36, 28, 32, 34,
+ 38, 40, 40, 36, 25, 29, 33, 36, 40, 40, 35, 30, 33, 36, 38, 36, 32, 28, 28,
+ 31, 34, 37, 36, 32, 29, 27, 30, 34, 36, 36, 34, 30, 26, 30, 34, 36, 36, 34,
+ 30, 26, 30, 33, 36, 36, 35, 31, 24, 29, 32, 34, 35, 34, 30, 22, 26, 31, 34,
+ 34, 33, 30, 28, 30, 31, 31, 31, 27, 20, 26, 29, 29, 30, 29, 27, 21, 24, 29,
+ 29, 30, 30, 27, 22, 20, 28, 30, 30, 29, 27, 24, 18, 28, 29, 29, 29, 27, 23,
+ 16, 26, 28, 28, 28, 26, 23, 17, 24, 25, 26, 27, 26, 21, 24, 25, 24, 24, 22,
+ 18, 10, 20, 23, 23, 24, 22, 17, 12, 16, 22, 22, 22, 21, 16, 15, 13, 21, 22,
+ 22, 21, 17, 18, 14, 19, 22, 21, 20, 16, 14, 15, 17, 19, 20, 19, 16, 10, 17,
+ 15, 18, 18, 18, 16, 7, 12, 17, 16, 16, 11, 5, 11, 8, 15, 15, 15, 11, 6,
+ 12, 9, 12, 14, 14, 11, 5, 10, 9, 9, 14, 13, 11, 5, 10, 10, 8, 13, 12,
+ 10, 6, 7, 11, 10, 10, 10, 9, 5, 6, 13, 12, 11, 9, 8, 6, 5, 4, 7,
+ 7, 5, 4, 5, 7, 4, 5, 5, 5, 3, 5, 6, 4, 3, 4, 4, 4, 5, 6,
+ 4, 3, 3, 3, 4, 5, 5, 6, 5, 8, 8, 8, 6, 5, 8, 9, 14, 13, 10,
+ 7, 5, 10, 13, 16, 14, 11, 8, 5, 2, 3, 2, 2, 3, 4, 5, 2, 3, 3,
+ 0, 2, 4, 5, 2, 3, 4, 2, 2, 4, 5, 2, 5, 8, 6, 5, 5, 5, 4,
+ 8, 12, 12, 10, 8, 6, 7, 12, 17, 18, 13, 9, 6, 12, 17, 19, 18, 14, 10,
+ 7, 25, 29, 32, 35, 35, 31, 29, 24, 28, 30, 35, 35, 32, 28, 23, 26, 30, 33,
+ 35, 32, 30, 23, 26, 30, 33, 36, 33, 30, 24, 25, 29, 32, 36, 34, 30, 22, 25,
+ 28, 32, 35, 33, 30, 20, 23, 27, 31, 33, 34, 30, 24, 26, 30, 33, 30, 28, 23,
+ 23, 25, 28, 32, 31, 28, 24, 22, 23, 28, 31, 30, 27, 24, 21, 24, 27, 30, 30,
+ 28, 25, 21, 25, 27, 30, 29, 29, 25, 20, 23, 25, 29, 29, 29, 25, 17, 20, 24,
+ 27, 28, 27, 25, 22, 24, 25, 26, 26, 22, 17, 21, 22, 24, 25, 24, 23, 17, 20,
+ 22, 24, 24, 24, 22, 17, 17, 23, 24, 23, 24, 23, 18, 15, 22, 23, 22, 23, 22,
+ 18, 13, 20, 21, 21, 22, 21, 18, 15, 18, 19, 20, 20, 21, 17, 20, 19, 18, 18,
+ 19, 15, 7, 16, 18, 18, 17, 17, 14, 8, 14, 18, 17, 16, 17, 14, 10, 10, 17,
+ 17, 16, 16, 14, 13, 12, 16, 16, 15, 16, 13, 9, 12, 14, 14, 14, 14, 12, 6,
+ 15, 16, 12, 12, 13, 12, 5, 9, 11, 11, 11, 9, 4, 6, 5, 10, 9, 9, 8,
+ 3, 8, 5, 9, 8, 8, 8, 3, 6, 5, 7, 9, 8, 7, 4, 6, 7, 6, 7,
+ 7, 7, 6, 4, 9, 10, 12, 10, 8, 6, 5, 13, 16, 16, 11, 9, 7, 5, 2,
+ 2, 1, 2, 2, 3, 4, 2, 2, 1, 0, 2, 3, 4, 2, 2, 2, 2, 2, 3,
+ 4, 2, 4, 6, 6, 5, 5, 5, 4, 8, 11, 10, 9, 7, 5, 8, 13, 18, 15,
+ 11, 8, 6, 14, 18, 19, 17, 12, 9, 7, 4, 5, 3, 2, 1, 2, 3, 4, 5,
+ 4, 2, 0, 2, 4, 4, 5, 6, 4, 3, 2, 3, 4, 7, 10, 8, 7, 6, 6,
+ 7, 11, 14, 14, 11, 9, 7, 11, 15, 19, 19, 14, 10, 7, 16, 19, 20, 20, 16,
+ 12, 8, 21, 24, 27, 31, 32, 29, 25, 19, 23, 27, 30, 31, 28, 24, 18, 22, 26,
+ 29, 30, 28, 25, 18, 21, 24, 28, 31, 28, 25, 19, 21, 24, 27, 31, 29, 25, 17,
+ 20, 23, 26, 30, 29, 25, 15, 19, 22, 26, 29, 29, 26, 19, 21, 25, 29, 28, 25,
+ 21, 18, 20, 24, 28, 27, 24, 20, 17, 20, 22, 26, 25, 23, 21, 16, 20, 22, 25,
+ 25, 24, 21, 17, 19, 22, 24, 24, 24, 21, 15, 18, 21, 23, 24, 23, 21, 16, 16,
+ 19, 22, 22, 22, 21, 17, 19, 21, 22, 22, 20, 16, 16, 18, 19, 21, 21, 19, 14,
+ 16, 17, 19, 19, 19, 18, 15, 14, 18, 18, 18, 18, 18, 16, 13, 17, 18, 18, 17,
+ 18, 15, 11, 15, 17, 17, 17, 16, 15, 17, 16, 15, 15, 16, 16, 14, 16, 14, 14,
+ 14, 15, 14, 6, 14, 13, 13, 13, 13, 12, 5, 11, 12, 12, 12, 11, 11, 6, 8,
+ 12, 12, 12, 11, 11, 9, 9, 11, 11, 11, 10, 10, 6, 11, 11, 11, 9, 9, 9,
+ 4, 17, 18, 13, 10, 8, 8, 4, 7, 7, 6, 6, 7, 4, 5, 2, 5, 5, 5,
+ 5, 3, 5, 2, 4, 3, 3, 3, 2, 3, 2, 3, 3, 3, 4, 4, 4, 5, 8,
+ 8, 7, 8, 6, 4, 9, 13, 14, 12, 9, 7, 5, 16, 18, 17, 13, 10, 8, 5,
+ 2, 3, 2, 2, 2, 3, 4, 2, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 2,
+ 2, 2, 2, 6, 7, 6, 6, 5, 5, 6, 10, 13, 11, 10, 8, 5, 11, 15, 18,
+ 16, 12, 9, 6, 16, 19, 19, 18, 13, 10, 7, 6, 8, 5, 3, 2, 2, 3, 6,
+ 7, 7, 4, 2, 0, 2, 6, 7, 8, 5, 4, 3, 3, 6, 9, 12, 9, 8, 7,
+ 6, 8, 12, 16, 15, 12, 10, 7, 13, 16, 20, 21, 15, 11, 8, 18, 21, 20, 21,
+ 16, 12, 9, 17, 20, 24, 28, 28, 25, 22, 16, 19, 23, 27, 28, 24, 20, 14, 17,
+ 21, 24, 26, 24, 20, 13, 17, 20, 23, 27, 24, 21, 14, 17, 20, 23, 27, 25, 21,
+ 12, 15, 19, 22, 26, 24, 21, 14, 14, 18, 21, 25, 24, 21, 14, 18, 22, 25, 24,
+ 21, 18, 13, 17, 20, 23, 23, 20, 16, 13, 15, 18, 21, 21, 19, 16, 12, 15, 18,
+ 20, 21, 19, 16, 12, 15, 18, 20, 20, 20, 17, 10, 13, 16, 19, 20, 19, 17, 16,
+ 15, 15, 18, 18, 18, 17, 13, 16, 17, 18, 19, 17, 13, 12, 14, 16, 16, 17, 15,
+ 11, 10, 13, 14, 14, 14, 14, 11, 10, 13, 14, 14, 14, 14, 12, 9, 12, 14, 13,
+ 13, 14, 12, 12, 12, 12, 12, 13, 12, 12, 18, 17, 13, 11, 11, 11, 11, 11, 10,
+ 10, 11, 12, 12, 5, 10, 9, 9, 9, 10, 10, 3, 8, 8, 8, 8, 7, 7, 3,
+ 5, 8, 7, 7, 7, 7, 5, 7, 7, 7, 6, 6, 6, 3, 12, 13, 11, 9, 7,
+ 6, 4, 18, 18, 14, 10, 8, 6, 4, 2, 2, 2, 3, 3, 4, 4, 1, 1, 0,
+ 1, 2, 2, 3, 1, 2, 2, 2, 1, 1, 2, 1, 5, 5, 4, 4, 4, 3, 5,
+ 10, 9, 8, 8, 6, 4, 11, 14, 14, 12, 10, 7, 5, 17, 19, 17, 13, 10, 8,
+ 5, 5, 5, 4, 3, 3, 3, 4, 5, 7, 4, 4, 3, 1, 2, 5, 8, 6, 4,
+ 3, 2, 2, 5, 9, 9, 7, 6, 6, 5, 9, 12, 14, 12, 10, 8, 5, 12, 16,
+ 19, 16, 12, 9, 6, 17, 19, 20, 18, 14, 10, 7, 9, 10, 7, 5, 3, 2, 3,
+ 10, 10, 9, 5, 4, 2, 0, 9, 10, 11, 7, 5, 4, 3, 10, 11, 14, 10, 8,
+ 7, 6, 10, 14, 17, 16, 13, 10, 8, 14, 17, 21, 20, 15, 11, 8, 18, 20, 22,
+ 22, 17, 12, 9, 32, 35, 38, 41, 41, 38, 36, 30, 34, 37, 41, 41, 39, 37, 29,
+ 32, 37, 40, 42, 39, 37, 28, 32, 36, 39, 42, 39, 37, 28, 31, 35, 39, 42, 41,
+ 36, 28, 30, 34, 38, 41, 40, 36, 25, 29, 33, 37, 40, 39, 37, 29, 33, 36, 39,
+ 38, 35, 32, 28, 32, 35, 39, 37, 35, 31, 27, 31, 34, 37, 37, 35, 31, 25, 30,
+ 33, 36, 36, 36, 33, 25, 30, 33, 36, 35, 36, 32, 24, 27, 31, 35, 36, 35, 33,
+ 21, 26, 30, 34, 34, 34, 32, 27, 31, 31, 32, 32, 30, 25, 26, 29, 31, 32, 32,
+ 30, 25, 24, 28, 30, 30, 30, 30, 24, 21, 28, 28, 30, 30, 29, 26, 18, 26, 28,
+ 29, 29, 29, 25, 15, 25, 27, 27, 28, 28, 25, 16, 22, 25, 26, 26, 27, 25, 24,
+ 25, 24, 25, 25, 23, 13, 20, 23, 24, 24, 24, 21, 14, 18, 22, 23, 22, 22, 20,
+ 15, 14, 21, 21, 22, 22, 20, 18, 14, 19, 20, 21, 21, 19, 14, 15, 17, 18, 19,
+ 19, 18, 11, 16, 14, 16, 17, 18, 17, 8, 12, 16, 17, 17, 15, 10, 13, 9, 15,
+ 15, 15, 13, 10, 14, 9, 13, 13, 13, 12, 8, 12, 9, 9, 12, 12, 12, 9, 10,
+ 10, 7, 11, 11, 10, 6, 8, 10, 9, 8, 8, 9, 5, 8, 12, 10, 9, 7, 7,
+ 4, 7, 4, 6, 6, 6, 7, 9, 11, 4, 4, 4, 5, 6, 9, 10, 4, 2, 2,
+ 3, 4, 7, 9, 4, 2, 1, 1, 3, 6, 8, 5, 4, 4, 4, 4, 4, 7, 7,
+ 6, 8, 6, 5, 4, 6, 9, 9, 9, 7, 5, 4, 6, 0, 4, 3, 2, 4, 7,
+ 9, 0, 4, 4, 2, 4, 6, 8, 0, 4, 5, 2, 2, 6, 8, 0, 4, 4, 2,
+ 2, 4, 6, 2, 4, 5, 5, 5, 4, 5, 4, 6, 8, 8, 6, 5, 4, 8, 8,
+ 9, 9, 6, 5, 4, 38, 41, 44, 47, 47, 44, 41, 37, 40, 43, 47, 47, 45, 42,
+ 35, 39, 42, 46, 47, 45, 42, 34, 37, 42, 45, 48, 46, 42, 34, 38, 41, 45, 49,
+ 46, 43, 34, 36, 41, 44, 48, 46, 42, 32, 35, 38, 42, 46, 46, 42, 35, 39, 43,
+ 44, 42, 39, 36, 34, 38, 41, 45, 43, 39, 36, 33, 36, 39, 43, 42, 40, 36, 31,
+ 36, 39, 43, 41, 40, 37, 31, 35, 39, 43, 41, 41, 37, 28, 34, 38, 41, 40, 40,
+ 37, 24, 31, 36, 39, 40, 39, 37, 33, 36, 38, 38, 37, 34, 27, 32, 34, 37, 38,
+ 37, 33, 28, 28, 33, 36, 35, 36, 34, 28, 25, 34, 35, 36, 35, 34, 30, 22, 33,
+ 35, 35, 35, 33, 30, 19, 31, 32, 33, 33, 32, 29, 19, 28, 31, 32, 33, 31, 28,
+ 29, 31, 30, 30, 29, 25, 16, 24, 29, 29, 29, 28, 24, 18, 21, 28, 29, 29, 27,
+ 23, 19, 17, 26, 27, 28, 28, 23, 22, 18, 23, 27, 26, 26, 22, 19, 19, 19, 25,
+ 25, 24, 22, 14, 19, 17, 23, 24, 24, 20, 11, 16, 22, 21, 22, 17, 12, 16, 13,
+ 20, 21, 20, 16, 12, 17, 12, 16, 20, 19, 16, 9, 15, 12, 12, 19, 19, 15, 10,
+ 14, 14, 10, 18, 17, 14, 8, 11, 14, 11, 15, 15, 12, 7, 10, 15, 13, 12, 13,
+ 11, 6, 9, 7, 11, 12, 9, 9, 10, 13, 7, 8, 10, 8, 7, 10, 12, 7, 5,
+ 8, 7, 6, 8, 10, 7, 5, 7, 6, 6, 8, 9, 8, 6, 6, 5, 5, 6, 9,
+ 9, 8, 7, 7, 5, 6, 8, 11, 9, 8, 7, 6, 5, 7, 4, 0, 2, 4, 6,
+ 9, 11, 4, 0, 2, 3, 5, 7, 10, 4, 0, 3, 2, 5, 9, 9, 4, 1, 3,
+ 2, 4, 5, 8, 4, 3, 5, 5, 5, 5, 7, 6, 6, 8, 8, 6, 5, 6, 7,
+ 9, 8, 8, 6, 5, 6, 41, 44, 47, 50, 50, 47, 43, 40, 43, 48, 50, 51, 47,
+ 44, 39, 42, 46, 48, 51, 46, 44, 37, 41, 45, 48, 51, 48, 45, 38, 41, 45, 49,
+ 51, 49, 45, 37, 40, 44, 47, 51, 49, 46, 34, 38, 42, 46, 49, 48, 44, 39, 42,
+ 46, 48, 46, 42, 38, 38, 41, 45, 48, 46, 42, 37, 37, 40, 43, 46, 45, 43, 39,
+ 33, 40, 43, 46, 46, 43, 39, 33, 40, 43, 45, 45, 44, 39, 30, 38, 40, 44, 44,
+ 43, 38, 27, 36, 40, 43, 42, 41, 39, 37, 40, 41, 40, 40, 37, 29, 34, 39, 39,
+ 41, 38, 36, 29, 31, 38, 40, 38, 38, 36, 30, 27, 37, 38, 40, 37, 36, 32, 25,
+ 35, 38, 38, 37, 35, 32, 21, 33, 36, 36, 36, 34, 32, 21, 30, 35, 35, 36, 33,
+ 29, 31, 34, 33, 34, 31, 27, 19, 26, 32, 34, 33, 31, 25, 20, 23, 30, 32, 31,
+ 30, 24, 22, 19, 27, 31, 32, 29, 23, 25, 20, 25, 31, 30, 28, 22, 21, 21, 22,
+ 29, 28, 27, 22, 17, 21, 18, 26, 27, 26, 21, 14, 18, 26, 26, 25, 18, 13, 19,
+ 14, 22, 25, 24, 17, 12, 20, 14, 18, 23, 23, 16, 10, 18, 14, 15, 22, 22, 15,
+ 10, 17, 15, 12, 21, 20, 14, 9, 13, 16, 13, 18, 18, 14, 8, 10, 16, 14, 15,
+ 17, 12, 8, 9, 9, 13, 15, 10, 9, 11, 15, 9, 9, 14, 10, 8, 10, 13, 9,
+ 5, 12, 8, 7, 9, 11, 9, 6, 11, 8, 7, 9, 10, 11, 8, 9, 6, 6, 7,
+ 9, 11, 9, 8, 8, 6, 7, 9, 12, 11, 9, 9, 8, 6, 7, 5, 3, 3, 5,
+ 7, 9, 12, 5, 3, 2, 4, 6, 8, 11, 5, 3, 0, 4, 7, 9, 11, 5, 3,
+ 3, 3, 4, 7, 9, 6, 4, 7, 8, 7, 6, 8, 7, 6, 10, 11, 8, 6, 7,
+ 9, 10, 11, 11, 9, 7, 6, 34, 38, 42, 44, 45, 41, 37, 32, 37, 41, 44, 44,
+ 41, 37, 31, 35, 39, 43, 43, 41, 36, 30, 33, 37, 40, 43, 40, 37, 30, 33, 37,
+ 40, 43, 40, 38, 29, 32, 35, 40, 42, 41, 36, 26, 31, 35, 38, 42, 41, 38, 32,
+ 35, 39, 43, 40, 36, 33, 31, 34, 38, 41, 40, 37, 32, 30, 32, 36, 39, 38, 35,
+ 30, 27, 31, 34, 37, 38, 35, 31, 27, 31, 34, 38, 37, 36, 31, 25, 30, 33, 36,
+ 37, 35, 31, 21, 27, 32, 35, 35, 34, 31, 29, 33, 34, 35, 33, 31, 25, 27, 31,
+ 33, 35, 33, 30, 24, 24, 30, 31, 32, 31, 29, 23, 21, 30, 30, 30, 30, 28, 24,
+ 19, 28, 30, 30, 29, 28, 24, 16, 26, 28, 28, 29, 26, 25, 16, 24, 27, 26, 28,
+ 26, 22, 23, 27, 26, 28, 27, 22, 15, 20, 25, 26, 26, 26, 21, 15, 17, 23, 24,
+ 24, 23, 18, 16, 14, 23, 23, 23, 21, 18, 19, 15, 19, 23, 22, 21, 17, 15, 15,
+ 17, 21, 21, 20, 16, 11, 16, 15, 19, 19, 20, 16, 7, 13, 19, 18, 19, 15, 9,
+ 15, 9, 17, 18, 17, 14, 8, 15, 9, 13, 16, 15, 12, 6, 12, 9, 10, 15, 14,
+ 11, 6, 10, 10, 8, 14, 13, 10, 5, 7, 11, 9, 11, 11, 9, 4, 5, 12, 11,
+ 9, 10, 8, 4, 5, 4, 9, 9, 8, 6, 8, 11, 4, 6, 8, 7, 5, 7, 9,
+ 4, 3, 5, 5, 3, 5, 6, 4, 3, 4, 4, 3, 4, 5, 6, 4, 5, 5, 6,
+ 4, 5, 7, 6, 11, 10, 7, 5, 5, 9, 11, 12, 12, 9, 6, 4, 2, 2, 2,
+ 3, 5, 7, 8, 2, 2, 2, 2, 4, 5, 7, 2, 2, 3, 0, 3, 5, 6, 2,
+ 3, 6, 4, 3, 3, 4, 3, 5, 9, 10, 8, 5, 4, 5, 9, 15, 15, 11, 7,
+ 4, 9, 14, 17, 17, 12, 8, 5, 27, 33, 36, 39, 39, 37, 33, 27, 30, 35, 38,
+ 40, 37, 32, 25, 29, 34, 37, 38, 34, 30, 25, 27, 32, 35, 37, 34, 32, 25, 27,
+ 30, 34, 37, 35, 31, 24, 26, 29, 33, 36, 34, 31, 21, 24, 28, 32, 35, 34, 32,
+ 26, 29, 34, 37, 35, 32, 28, 24, 29, 32, 35, 36, 32, 27, 24, 26, 30, 33, 33,
+ 30, 25, 23, 25, 28, 31, 31, 29, 26, 23, 25, 28, 31, 31, 28, 26, 21, 24, 27,
+ 30, 30, 29, 26, 18, 22, 25, 28, 29, 28, 26, 24, 26, 29, 30, 30, 27, 22, 22,
+ 25, 28, 28, 29, 26, 20, 21, 24, 26, 26, 26, 25, 18, 17, 24, 24, 24, 25, 24,
+ 19, 16, 23, 23, 23, 23, 22, 19, 13, 21, 22, 22, 22, 20, 19, 14, 19, 21, 21,
+ 21, 21, 17, 21, 22, 21, 22, 23, 20, 13, 17, 20, 21, 21, 21, 18, 12, 14, 19,
+ 19, 18, 19, 15, 12, 11, 19, 17, 17, 17, 14, 13, 12, 16, 16, 17, 16, 13, 10,
+ 13, 14, 15, 15, 15, 13, 7, 14, 13, 13, 13, 13, 13, 4, 9, 14, 14, 15, 13,
+ 9, 13, 6, 13, 12, 13, 12, 6, 12, 6, 10, 10, 10, 9, 4, 8, 6, 7, 9,
+ 9, 8, 4, 6, 7, 5, 8, 7, 7, 3, 4, 8, 7, 8, 7, 6, 3, 4, 10,
+ 11, 11, 8, 5, 4, 3, 2, 4, 5, 5, 5, 7, 9, 2, 2, 3, 4, 4, 5,
+ 7, 2, 0, 1, 1, 2, 3, 4, 2, 2, 3, 2, 2, 2, 3, 4, 5, 8, 7,
+ 6, 4, 3, 5, 9, 14, 12, 8, 5, 3, 10, 13, 16, 13, 9, 6, 3, 3, 6,
+ 4, 2, 5, 6, 7, 2, 5, 5, 2, 3, 4, 5, 3, 6, 7, 3, 0, 3, 4,
+ 2, 5, 7, 5, 4, 3, 3, 4, 7, 11, 11, 8, 6, 4, 7, 11, 15, 15, 11,
+ 7, 4, 12, 16, 16, 16, 12, 8, 5, 24, 29, 32, 36, 35, 32, 29, 23, 27, 31,
+ 35, 34, 31, 28, 21, 25, 29, 33, 34, 30, 26, 20, 22, 26, 30, 32, 29, 27, 19,
+ 22, 24, 28, 32, 30, 27, 18, 21, 23, 27, 31, 30, 27, 16, 19, 23, 26, 29, 30,
+ 26, 22, 25, 28, 33, 31, 28, 25, 20, 24, 28, 31, 31, 27, 24, 19, 22, 26, 30,
+ 29, 26, 22, 18, 20, 23, 26, 26, 25, 21, 18, 20, 22, 26, 26, 25, 22, 16, 19,
+ 22, 25, 24, 24, 22, 13, 17, 20, 23, 23, 24, 22, 19, 22, 24, 26, 26, 24, 20,
+ 18, 21, 23, 24, 25, 23, 18, 17, 20, 22, 21, 22, 21, 16, 15, 19, 19, 19, 20,
+ 19, 15, 13, 17, 19, 18, 18, 18, 15, 11, 16, 17, 17, 18, 17, 16, 13, 14, 15,
+ 16, 16, 17, 14, 17, 17, 17, 18, 19, 18, 10, 15, 16, 17, 17, 17, 15, 9, 11,
+ 15, 15, 15, 14, 13, 8, 8, 14, 13, 12, 12, 11, 10, 9, 12, 12, 11, 11, 10,
+ 6, 10, 10, 10, 10, 10, 9, 3, 13, 14, 10, 8, 9, 8, 3, 7, 9, 10, 10,
+ 11, 8, 10, 3, 7, 8, 9, 9, 5, 9, 3, 6, 6, 6, 6, 3, 5, 3, 4,
+ 4, 4, 3, 2, 3, 5, 5, 4, 4, 4, 3, 3, 7, 9, 10, 8, 6, 4, 2,
+ 11, 14, 13, 10, 7, 4, 2, 0, 2, 2, 3, 4, 6, 8, 0, 4, 3, 3, 3,
+ 4, 5, 0, 4, 3, 2, 1, 2, 3, 0, 5, 5, 3, 3, 2, 2, 3, 7, 9,
+ 8, 7, 4, 2, 7, 12, 15, 12, 9, 5, 3, 12, 15, 16, 14, 10, 7, 4, 6,
+ 9, 6, 3, 3, 5, 6, 6, 9, 8, 4, 2, 3, 4, 6, 9, 11, 5, 3, 0,
+ 3, 6, 7, 9, 6, 4, 4, 3, 6, 9, 12, 12, 9, 6, 4, 9, 13, 16, 16,
+ 11, 8, 4, 14, 17, 17, 17, 13, 9, 5, 20, 23, 27, 31, 30, 28, 24, 19, 22,
+ 26, 31, 31, 27, 24, 17, 21, 25, 28, 29, 26, 22, 16, 19, 22, 25, 27, 24, 21,
+ 14, 17, 20, 23, 27, 25, 22, 14, 16, 19, 23, 26, 25, 21, 11, 14, 18, 22, 25,
+ 25, 22, 17, 20, 25, 29, 28, 25, 21, 16, 20, 24, 28, 27, 23, 20, 15, 18, 22,
+ 24, 24, 22, 18, 14, 16, 19, 21, 21, 19, 17, 13, 16, 18, 20, 20, 21, 17, 11,
+ 14, 17, 20, 20, 20, 17, 12, 12, 16, 19, 19, 18, 17, 15, 18, 21, 22, 23, 21,
+ 16, 14, 17, 19, 20, 21, 20, 15, 13, 16, 18, 18, 18, 17, 13, 12, 14, 14, 14,
+ 15, 15, 12, 10, 13, 14, 14, 14, 14, 12, 9, 11, 12, 12, 13, 12, 12, 13, 12,
+ 11, 11, 11, 11, 11, 13, 13, 13, 14, 15, 15, 8, 11, 11, 12, 13, 13, 13, 7,
+ 9, 10, 11, 10, 10, 10, 6, 5, 9, 8, 7, 7, 7, 6, 7, 7, 7, 7, 6,
+ 6, 3, 9, 9, 8, 6, 5, 5, 2, 13, 13, 9, 7, 5, 4, 2, 4, 5, 5,
+ 6, 7, 7, 8, 1, 3, 4, 5, 5, 5, 6, 1, 1, 2, 2, 2, 2, 3, 1,
+ 3, 2, 1, 2, 1, 2, 3, 6, 6, 5, 5, 3, 2, 8, 11, 11, 9, 6, 4,
+ 2, 12, 14, 13, 10, 8, 6, 3, 5, 5, 4, 4, 4, 6, 7, 5, 7, 4, 4,
+ 4, 3, 4, 5, 7, 5, 4, 2, 1, 2, 5, 7, 6, 5, 3, 3, 2, 6, 9,
+ 11, 9, 7, 6, 3, 9, 12, 15, 13, 9, 6, 4, 13, 15, 16, 14, 10, 7, 4,
+ 8, 10, 7, 4, 4, 5, 5, 8, 10, 9, 5, 3, 3, 3, 8, 10, 11, 6, 4,
+ 3, 0, 8, 9, 11, 7, 5, 4, 3, 8, 10, 14, 13, 9, 7, 5, 11, 14, 17,
+ 16, 12, 8, 6, 14, 16, 17, 17, 13, 9, 6, 32, 35, 38, 42, 42, 39, 35, 31,
+ 35, 38, 41, 41, 39, 37, 29, 33, 37, 40, 41, 39, 37, 29, 31, 35, 38, 42, 39,
+ 37, 28, 31, 35, 39, 42, 40, 37, 27, 31, 35, 37, 41, 40, 36, 24, 28, 33, 36,
+ 41, 39, 36, 29, 33, 37, 39, 38, 34, 32, 29, 32, 35, 38, 37, 35, 31, 27, 30,
+ 33, 38, 37, 34, 32, 26, 29, 33, 36, 36, 35, 33, 26, 29, 33, 35, 36, 36, 33,
+ 23, 28, 31, 35, 35, 35, 33, 21, 25, 29, 33, 34, 34, 32, 27, 31, 32, 32, 33,
+ 30, 24, 26, 28, 32, 31, 32, 29, 25, 24, 28, 29, 30, 30, 29, 24, 21, 28, 28,
+ 29, 30, 30, 26, 19, 26, 29, 28, 29, 28, 26, 15, 24, 27, 27, 28, 27, 26, 16,
+ 22, 25, 25, 27, 26, 25, 24, 25, 25, 25, 25, 22, 13, 21, 23, 24, 24, 24, 21,
+ 14, 18, 22, 23, 23, 22, 20, 15, 13, 22, 22, 22, 23, 20, 17, 15, 20, 21, 21,
+ 21, 19, 14, 15, 17, 19, 19, 19, 18, 11, 16, 14, 16, 17, 18, 17, 8, 12, 17,
+ 16, 17, 14, 10, 13, 9, 15, 15, 15, 14, 10, 14, 9, 12, 13, 13, 13, 8, 12,
+ 9, 10, 13, 12, 12, 9, 10, 10, 7, 11, 11, 10, 6, 8, 10, 9, 8, 9, 9,
+ 5, 8, 12, 10, 9, 7, 7, 4, 7, 4, 6, 6, 6, 7, 9, 10, 4, 4, 4,
+ 5, 5, 9, 10, 4, 2, 2, 3, 4, 7, 9, 4, 2, 1, 1, 4, 6, 8, 5,
+ 4, 4, 4, 4, 4, 7, 7, 6, 8, 6, 4, 4, 6, 9, 9, 8, 7, 5, 4,
+ 5, 0, 4, 3, 2, 4, 7, 9, 0, 4, 4, 2, 4, 6, 8, 0, 4, 5, 2,
+ 2, 6, 8, 0, 4, 4, 2, 2, 4, 6, 2, 4, 6, 5, 5, 4, 5, 4, 6,
+ 8, 8, 6, 5, 4, 8, 8, 9, 9, 6, 5, 4, 38, 42, 46, 49, 49, 46, 42,
+ 37, 41, 46, 48, 50, 45, 42, 36, 39, 44, 47, 48, 45, 40, 34, 38, 41, 45, 48,
+ 44, 41, 34, 37, 41, 45, 48, 45, 41, 32, 37, 40, 43, 47, 46, 42, 30, 34, 39,
+ 43, 46, 46, 42, 36, 40, 44, 46, 44, 41, 37, 34, 38, 42, 45, 45, 40, 37, 33,
+ 37, 42, 43, 44, 41, 38, 30, 36, 39, 42, 40, 39, 37, 30, 35, 38, 42, 42, 40,
+ 36, 27, 33, 36, 40, 41, 39, 38, 24, 31, 35, 39, 39, 37, 37, 32, 36, 39, 39,
+ 39, 36, 29, 32, 35, 37, 39, 37, 35, 29, 28, 34, 36, 37, 36, 35, 28, 25, 34,
+ 33, 34, 35, 33, 29, 22, 32, 34, 34, 34, 33, 30, 18, 29, 31, 33, 33, 32, 29,
+ 17, 27, 30, 31, 32, 31, 27, 28, 31, 32, 31, 31, 27, 19, 24, 30, 31, 31, 30,
+ 25, 19, 20, 27, 29, 28, 28, 24, 21, 16, 26, 27, 27, 26, 22, 22, 17, 22, 26,
+ 26, 25, 22, 18, 18, 19, 24, 24, 24, 21, 14, 17, 15, 22, 23, 23, 20, 11, 15,
+ 22, 23, 24, 18, 14, 19, 12, 20, 22, 21, 18, 13, 19, 12, 16, 19, 19, 17, 10,
+ 16, 12, 12, 18, 18, 15, 10, 13, 13, 9, 17, 16, 13, 8, 10, 12, 10, 14, 14,
+ 12, 7, 10, 13, 12, 11, 12, 10, 6, 8, 7, 11, 13, 11, 9, 12, 15, 7, 7,
+ 11, 10, 8, 11, 13, 7, 5, 9, 8, 7, 8, 11, 7, 4, 7, 6, 7, 9, 9,
+ 7, 5, 5, 4, 4, 6, 8, 8, 7, 6, 6, 4, 5, 8, 10, 8, 8, 6, 5,
+ 4, 6, 4, 1, 2, 6, 8, 10, 13, 4, 1, 2, 5, 7, 9, 10, 4, 1, 3,
+ 3, 5, 7, 9, 4, 0, 3, 1, 3, 5, 7, 4, 2, 4, 4, 4, 4, 6, 5,
+ 5, 7, 7, 5, 4, 6, 7, 7, 7, 7, 5, 4, 5, 45, 49, 52, 55, 56, 52,
+ 48, 43, 47, 51, 55, 54, 51, 47, 41, 45, 50, 52, 53, 50, 46, 40, 44, 47, 51,
+ 52, 49, 46, 38, 41, 45, 49, 52, 50, 46, 37, 41, 44, 48, 51, 50, 46, 34, 39,
+ 43, 47, 50, 49, 47, 42, 45, 49, 53, 51, 48, 43, 40, 45, 49, 53, 51, 47, 42,
+ 37, 43, 47, 51, 49, 46, 40, 35, 40, 44, 48, 46, 45, 40, 33, 41, 44, 46, 45,
+ 45, 40, 30, 39, 42, 45, 45, 44, 40, 26, 36, 40, 44, 43, 42, 40, 38, 43, 45,
+ 46, 45, 42, 34, 34, 41, 44, 44, 44, 40, 34, 31, 40, 42, 41, 41, 39, 33, 28,
+ 37, 39, 39, 38, 36, 33, 24, 36, 38, 40, 38, 35, 33, 21, 32, 37, 37, 37, 34,
+ 33, 19, 30, 34, 35, 35, 34, 30, 31, 37, 38, 37, 36, 32, 25, 27, 34, 36, 35,
+ 35, 30, 25, 24, 31, 35, 34, 33, 27, 25, 20, 28, 31, 32, 30, 25, 26, 20, 25,
+ 31, 31, 29, 23, 22, 21, 21, 29, 29, 28, 23, 19, 20, 17, 26, 28, 27, 22, 14,
+ 18, 27, 29, 29, 23, 19, 25, 15, 23, 27, 27, 22, 16, 25, 15, 19, 25, 25, 20,
+ 13, 20, 15, 15, 23, 23, 17, 11, 17, 15, 12, 21, 21, 15, 10, 14, 16, 12, 18,
+ 19, 15, 8, 12, 15, 13, 14, 17, 13, 8, 12, 10, 14, 19, 15, 13, 16, 21, 10,
+ 10, 17, 13, 12, 14, 18, 10, 6, 15, 11, 9, 11, 14, 10, 5, 11, 8, 7, 10,
+ 11, 10, 6, 9, 6, 5, 8, 10, 10, 8, 6, 5, 4, 6, 10, 11, 9, 7, 5,
+ 4, 6, 8, 5, 3, 6, 9, 12, 14, 16, 5, 3, 5, 8, 10, 12, 14, 5, 3,
+ 3, 6, 7, 9, 11, 5, 3, 0, 3, 6, 10, 10, 5, 3, 3, 3, 3, 5, 8,
+ 6, 5, 5, 6, 4, 5, 7, 8, 6, 6, 6, 5, 4, 6, 38, 43, 47, 49, 51,
+ 47, 43, 36, 41, 43, 50, 49, 46, 41, 35, 39, 44, 46, 47, 45, 39, 34, 37, 40,
+ 44, 46, 42, 38, 31, 34, 38, 42, 44, 42, 38, 30, 34, 36, 40, 44, 43, 37, 28,
+ 31, 35, 39, 42, 42, 38, 34, 40, 44, 47, 45, 42, 38, 34, 38, 42, 46, 45, 41,
+ 37, 32, 36, 40, 43, 43, 39, 34, 31, 34, 37, 40, 39, 38, 33, 27, 32, 35, 38,
+ 38, 37, 33, 24, 32, 34, 37, 37, 36, 33, 20, 29, 33, 36, 36, 35, 34, 33, 36,
+ 38, 38, 39, 36, 30, 29, 34, 38, 39, 39, 35, 29, 26, 33, 36, 36, 36, 34, 27,
+ 23, 31, 32, 33, 33, 31, 26, 19, 29, 32, 32, 31, 29, 25, 15, 28, 30, 31, 31,
+ 28, 25, 15, 25, 28, 29, 29, 27, 24, 26, 30, 31, 31, 32, 28, 21, 22, 29, 30,
+ 31, 30, 25, 20, 18, 26, 28, 29, 27, 23, 20, 16, 22, 25, 25, 25, 19, 20, 14,
+ 19, 25, 24, 23, 17, 16, 15, 16, 22, 22, 21, 18, 12, 15, 13, 20, 20, 20, 17,
+ 9, 14, 22, 23, 24, 20, 15, 20, 10, 19, 21, 22, 18, 13, 21, 11, 14, 19, 19,
+ 16, 10, 16, 10, 9, 17, 16, 12, 7, 12, 10, 7, 15, 15, 11, 7, 9, 11, 8,
+ 12, 12, 10, 5, 7, 11, 9, 10, 11, 9, 4, 6, 5, 11, 14, 12, 11, 13, 17,
+ 5, 7, 12, 11, 10, 11, 14, 6, 3, 9, 8, 7, 8, 10, 5, 3, 6, 5, 4,
+ 5, 7, 5, 3, 4, 3, 2, 4, 6, 6, 5, 7, 6, 4, 3, 7, 8, 7, 8,
+ 8, 5, 3, 4, 2, 2, 4, 7, 9, 12, 13, 2, 2, 3, 6, 8, 9, 10, 2,
+ 2, 3, 4, 5, 6, 8, 2, 1, 3, 0, 3, 5, 6, 2, 1, 5, 6, 4, 3,
+ 5, 3, 5, 11, 11, 7, 3, 4, 5, 9, 12, 13, 8, 4, 3, 32, 37, 41, 44,
+ 43, 41, 38, 30, 35, 39, 44, 44, 41, 36, 30, 34, 39, 41, 42, 38, 34, 28, 32,
+ 35, 38, 41, 37, 32, 26, 29, 31, 35, 38, 36, 32, 24, 27, 30, 34, 38, 36, 33,
+ 22, 25, 29, 34, 36, 36, 32, 30, 35, 38, 41, 41, 37, 33, 30, 32, 36, 40, 38,
+ 36, 31, 27, 31, 35, 38, 37, 34, 30, 25, 29, 32, 35, 35, 32, 27, 23, 26, 30,
+ 32, 32, 31, 28, 21, 25, 28, 30, 31, 30, 27, 18, 23, 27, 30, 29, 29, 28, 27,
+ 31, 33, 34, 35, 33, 26, 25, 29, 31, 33, 33, 30, 24, 23, 28, 31, 30, 31, 29,
+ 23, 19, 26, 27, 26, 28, 26, 21, 15, 24, 25, 25, 25, 24, 21, 13, 23, 24, 23,
+ 23, 23, 21, 12, 21, 22, 22, 23, 23, 19, 22, 25, 26, 27, 27, 25, 18, 19, 24,
+ 24, 25, 25, 22, 17, 15, 22, 23, 23, 22, 19, 16, 12, 19, 19, 19, 20, 16, 16,
+ 11, 16, 18, 17, 17, 14, 12, 12, 13, 16, 16, 16, 13, 9, 12, 11, 15, 14, 15,
+ 13, 6, 10, 17, 18, 18, 17, 13, 18, 7, 16, 16, 17, 16, 10, 17, 7, 12, 15,
+ 14, 13, 8, 12, 7, 7, 11, 10, 10, 5, 8, 7, 4, 9, 9, 8, 4, 5, 7,
+ 6, 6, 7, 6, 3, 5, 9, 8, 7, 5, 5, 2, 4, 3, 8, 9, 9, 9, 11,
+ 15, 3, 6, 7, 8, 8, 9, 11, 3, 2, 5, 4, 6, 6, 7, 3, 1, 1, 1,
+ 3, 3, 4, 2, 2, 3, 3, 2, 2, 4, 4, 5, 9, 8, 4, 2, 5, 6, 9,
+ 11, 9, 6, 2, 3, 2, 4, 4, 6, 8, 10, 11, 2, 4, 4, 5, 7, 8, 8,
+ 2, 4, 5, 3, 4, 4, 5, 2, 3, 7, 3, 0, 3, 4, 1, 4, 7, 7, 5,
+ 2, 3, 3, 8, 11, 12, 7, 3, 2, 8, 12, 13, 12, 8, 4, 2, 27, 32, 36,
+ 39, 40, 36, 33, 27, 30, 35, 39, 38, 35, 32, 25, 29, 33, 37, 38, 34, 30, 25,
+ 26, 30, 34, 36, 32, 27, 21, 24, 27, 30, 34, 31, 27, 19, 22, 25, 28, 32, 31,
+ 28, 18, 20, 24, 27, 30, 31, 27, 26, 29, 34, 37, 35, 33, 28, 24, 27, 31, 35,
+ 36, 31, 28, 23, 26, 30, 33, 32, 29, 24, 21, 24, 28, 30, 29, 28, 23, 19, 21,
+ 24, 26, 26, 26, 22, 17, 20, 22, 25, 26, 25, 22, 14, 18, 22, 25, 24, 24, 22,
+ 23, 26, 28, 29, 31, 28, 24, 22, 25, 27, 28, 28, 27, 21, 20, 25, 25, 26, 26,
+ 25, 19, 17, 22, 22, 22, 22, 22, 17, 13, 19, 20, 19, 20, 19, 16, 10, 18, 19,
+ 19, 18, 18, 17, 10, 15, 17, 17, 18, 17, 15, 20, 21, 21, 22, 23, 22, 15, 17,
+ 20, 19, 21, 21, 20, 14, 13, 19, 19, 18, 18, 17, 13, 9, 16, 15, 15, 14, 13,
+ 12, 8, 13, 13, 12, 12, 11, 8, 9, 11, 11, 11, 11, 10, 6, 10, 8, 9, 9,
+ 10, 9, 4, 8, 13, 13, 14, 15, 12, 15, 5, 12, 12, 13, 13, 9, 13, 5, 10,
+ 10, 9, 10, 7, 9, 5, 5, 6, 6, 6, 3, 5, 4, 2, 4, 3, 3, 3, 3,
+ 5, 5, 5, 4, 2, 2, 4, 6, 7, 7, 5, 3, 1, 3, 2, 4, 6, 7, 8,
+ 10, 12, 2, 3, 5, 6, 7, 8, 9, 2, 3, 4, 4, 4, 5, 6, 2, 2, 2,
+ 2, 1, 2, 3, 2, 3, 6, 4, 3, 1, 3, 3, 7, 10, 8, 5, 2, 3, 6,
+ 9, 10, 9, 6, 3, 2, 4, 6, 5, 5, 7, 9, 10, 4, 6, 6, 5, 6, 7,
+ 7, 3, 5, 7, 3, 3, 4, 5, 4, 5, 10, 5, 3, 0, 3, 4, 6, 8, 8,
+ 5, 3, 1, 6, 9, 12, 11, 7, 4, 1, 9, 11, 12, 12, 8, 5, 2, 24, 27,
+ 32, 36, 36, 33, 29, 23, 26, 30, 34, 35, 32, 28, 21, 25, 29, 32, 33, 30, 26,
+ 20, 22, 26, 29, 32, 28, 23, 17, 19, 22, 26, 28, 26, 23, 15, 17, 20, 23, 27,
+ 26, 22, 14, 16, 19, 22, 26, 26, 22, 21, 25, 28, 33, 31, 29, 25, 20, 24, 28,
+ 31, 31, 27, 23, 19, 22, 26, 28, 28, 25, 22, 18, 20, 23, 25, 25, 24, 19, 15,
+ 17, 19, 21, 22, 22, 18, 13, 15, 18, 20, 20, 21, 18, 11, 14, 17, 20, 19, 19,
+ 18, 19, 22, 24, 25, 27, 25, 20, 18, 21, 23, 24, 24, 23, 18, 17, 20, 21, 22,
+ 22, 21, 17, 15, 17, 18, 18, 18, 18, 13, 10, 14, 15, 15, 15, 15, 13, 6, 13,
+ 14, 14, 14, 14, 13, 7, 12, 13, 12, 12, 12, 12, 17, 17, 17, 18, 19, 19, 13,
+ 15, 15, 16, 16, 17, 17, 11, 11, 14, 15, 14, 14, 13, 10, 7, 12, 11, 10, 10,
+ 10, 9, 5, 9, 8, 8, 7, 7, 6, 6, 7, 6, 6, 6, 6, 3, 7, 4, 5,
+ 5, 5, 5, 3, 7, 9, 9, 10, 11, 11, 13, 2, 7, 8, 9, 9, 8, 11, 2,
+ 6, 6, 5, 6, 6, 6, 2, 3, 3, 2, 2, 2, 3, 1, 2, 2, 2, 2, 0,
+ 2, 2, 5, 4, 3, 2, 1, 2, 3, 6, 6, 4, 3, 2, 1, 3, 4, 5, 7,
+ 8, 9, 11, 3, 4, 5, 6, 6, 7, 8, 3, 6, 4, 4, 4, 4, 5, 3, 5,
+ 4, 3, 2, 1, 2, 3, 6, 6, 5, 3, 2, 1, 5, 7, 9, 7, 4, 2, 0,
+ 6, 7, 9, 8, 5, 3, 1, 6, 7, 6, 5, 7, 8, 9, 6, 8, 7, 5, 6,
+ 6, 6, 6, 8, 9, 4, 3, 3, 3, 6, 8, 9, 6, 4, 2, 0, 6, 8, 10,
+ 8, 4, 3, 2, 7, 9, 11, 10, 6, 3, 2, 7, 9, 11, 10, 7, 4, 2, 33,
+ 38, 42, 45, 45, 42, 39, 33, 37, 41, 45, 45, 43, 37, 30, 35, 39, 42, 43, 41,
+ 38, 30, 33, 36, 40, 43, 39, 36, 27, 30, 34, 38, 41, 40, 36, 26, 30, 33, 36,
+ 40, 39, 35, 23, 27, 32, 36, 39, 38, 36, 31, 36, 39, 42, 41, 38, 35, 29, 33,
+ 38, 41, 41, 37, 33, 28, 32, 36, 40, 39, 37, 32, 27, 30, 34, 36, 36, 36, 31,
+ 25, 28, 32, 34, 35, 34, 30, 22, 27, 29, 33, 34, 33, 31, 20, 24, 28, 33, 32,
+ 33, 31, 28, 32, 35, 34, 36, 34, 28, 27, 30, 32, 35, 35, 32, 28, 24, 29, 32,
+ 33, 31, 32, 27, 21, 28, 28, 30, 29, 29, 25, 17, 25, 27, 28, 28, 28, 25, 14,
+ 24, 26, 26, 26, 27, 26, 14, 21, 24, 25, 24, 25, 24, 24, 26, 27, 28, 29, 26,
+ 17, 20, 25, 26, 28, 28, 25, 17, 17, 23, 25, 24, 24, 23, 18, 13, 20, 21, 21,
+ 21, 19, 18, 13, 18, 20, 19, 19, 18, 14, 14, 15, 17, 18, 18, 18, 10, 14, 12,
+ 15, 16, 17, 16, 9, 12, 18, 19, 20, 19, 14, 17, 9, 16, 17, 18, 17, 12, 17,
+ 8, 13, 15, 15, 15, 10, 14, 9, 8, 12, 12, 12, 8, 10, 8, 5, 10, 10, 9,
+ 7, 8, 9, 7, 7, 8, 8, 5, 10, 10, 8, 7, 6, 6, 3, 8, 4, 8, 9,
+ 9, 9, 12, 14, 4, 6, 7, 8, 9, 10, 13, 4, 2, 5, 5, 6, 8, 10, 4,
+ 2, 1, 1, 4, 6, 8, 4, 2, 2, 2, 2, 3, 8, 5, 4, 6, 4, 3, 2,
+ 6, 7, 7, 6, 5, 3, 2, 5, 2, 4, 4, 5, 8, 10, 12, 2, 4, 5, 4,
+ 7, 8, 10, 2, 4, 5, 3, 4, 6, 7, 2, 4, 5, 2, 1, 4, 7, 0, 4,
+ 5, 3, 3, 2, 5, 3, 4, 6, 6, 4, 3, 4, 5, 6, 6, 6, 4, 3, 2,
+ 41, 45, 50, 51, 52, 50, 46, 40, 43, 48, 51, 53, 48, 44, 37, 41, 46, 50, 51,
+ 48, 43, 36, 39, 43, 46, 50, 46, 41, 33, 36, 41, 44, 47, 45, 41, 32, 35, 39,
+ 42, 46, 45, 42, 28, 34, 37, 41, 45, 45, 41, 37, 41, 47, 49, 48, 44, 41, 35,
+ 41, 44, 49, 48, 44, 40, 33, 39, 43, 47, 44, 42, 38, 33, 37, 40, 44, 42, 41,
+ 36, 29, 34, 37, 40, 41, 39, 36, 25, 33, 36, 39, 40, 38, 36, 22, 30, 35, 38,
+ 39, 38, 36, 34, 39, 42, 42, 42, 39, 34, 32, 37, 40, 41, 42, 38, 32, 29, 36,
+ 37, 38, 39, 37, 31, 25, 33, 35, 35, 35, 34, 29, 20, 31, 33, 33, 34, 32, 30,
+ 16, 29, 31, 31, 32, 31, 29, 16, 26, 30, 30, 31, 30, 27, 28, 33, 34, 34, 34,
+ 32, 23, 24, 31, 32, 34, 33, 29, 23, 20, 29, 31, 30, 30, 27, 23, 17, 24, 27,
+ 27, 27, 24, 23, 15, 20, 25, 26, 25, 21, 19, 16, 18, 23, 23, 24, 20, 15, 16,
+ 14, 21, 22, 22, 20, 11, 16, 24, 25, 26, 23, 18, 24, 12, 21, 23, 24, 22, 16,
+ 23, 12, 17, 21, 21, 19, 13, 19, 12, 11, 18, 17, 15, 10, 14, 11, 8, 16, 15,
+ 13, 9, 11, 12, 9, 13, 13, 12, 8, 10, 12, 10, 11, 12, 11, 8, 9, 7, 13,
+ 15, 14, 14, 16, 20, 7, 9, 14, 13, 12, 14, 16, 7, 4, 11, 11, 9, 11, 13,
+ 7, 4, 7, 7, 6, 8, 10, 6, 4, 4, 4, 3, 8, 9, 7, 5, 4, 3, 2,
+ 5, 9, 8, 7, 5, 4, 2, 4, 8, 4, 3, 5, 9, 12, 14, 16, 4, 3, 4,
+ 8, 11, 12, 14, 4, 3, 4, 5, 7, 9, 11, 4, 2, 3, 1, 4, 7, 8, 4,
+ 0, 4, 3, 2, 4, 8, 3, 3, 4, 5, 3, 3, 7, 5, 5, 5, 5, 3, 2,
+ 5, 47, 50, 55, 58, 58, 55, 52, 45, 50, 53, 58, 57, 54, 50, 43, 48, 52, 54,
+ 56, 52, 48, 42, 45, 49, 51, 55, 51, 45, 39, 42, 45, 49, 52, 50, 45, 36, 40,
+ 43, 47, 50, 49, 45, 32, 38, 43, 46, 49, 51, 45, 42, 47, 51, 55, 54, 50, 47,
+ 42, 45, 51, 55, 54, 49, 44, 40, 44, 48, 53, 51, 47, 43, 36, 43, 47, 49, 48,
+ 46, 40, 32, 39, 42, 46, 46, 44, 39, 28, 36, 41, 45, 43, 44, 40, 24, 35, 40,
+ 44, 43, 41, 40, 38, 43, 47, 47, 48, 45, 38, 36, 43, 46, 48, 47, 43, 37, 32,
+ 40, 44, 44, 44, 43, 35, 28, 38, 40, 40, 40, 38, 34, 22, 34, 37, 38, 37, 36,
+ 33, 19, 32, 37, 36, 36, 35, 33, 18, 28, 34, 35, 35, 33, 31, 32, 39, 39, 42,
+ 40, 36, 30, 28, 36, 38, 39, 38, 34, 28, 24, 33, 37, 36, 35, 29, 28, 21, 28,
+ 33, 33, 33, 27, 27, 18, 23, 31, 30, 29, 23, 23, 19, 19, 28, 28, 28, 23, 20,
+ 18, 15, 25, 27, 27, 22, 15, 18, 28, 31, 31, 27, 23, 29, 16, 24, 30, 30, 26,
+ 20, 28, 16, 20, 27, 26, 23, 17, 23, 16, 14, 23, 23, 19, 13, 19, 14, 10, 20,
+ 20, 16, 11, 15, 14, 10, 16, 18, 15, 9, 12, 13, 11, 13, 17, 14, 9, 11, 11,
+ 15, 21, 18, 17, 20, 25, 10, 10, 19, 18, 16, 17, 21, 11, 6, 16, 15, 13, 14,
+ 17, 10, 6, 12, 12, 9, 11, 12, 9, 5, 7, 7, 7, 9, 11, 9, 7, 5, 4,
+ 4, 7, 11, 10, 8, 5, 3, 3, 8, 9, 6, 5, 10, 13, 15, 18, 20, 6, 5,
+ 9, 12, 14, 16, 17, 5, 5, 7, 9, 10, 12, 14, 5, 4, 3, 5, 7, 8, 10,
+ 5, 4, 0, 2, 4, 7, 9, 5, 3, 3, 4, 3, 6, 8, 6, 4, 4, 4, 3,
+ 4, 7, 44, 47, 51, 55, 56, 53, 48, 43, 46, 50, 54, 55, 52, 45, 40, 44, 49,
+ 51, 54, 48, 45, 40, 42, 46, 50, 52, 48, 42, 35, 39, 42, 45, 48, 45, 41, 32,
+ 37, 39, 42, 46, 45, 41, 29, 34, 39, 42, 45, 46, 41, 42, 45, 49, 53, 51, 47,
+ 44, 40, 44, 48, 51, 50, 46, 42, 36, 41, 45, 47, 47, 45, 40, 33, 39, 43, 46,
+ 46, 43, 37, 28, 35, 39, 42, 41, 40, 36, 25, 34, 37, 40, 40, 40, 37, 21, 32,
+ 36, 39, 39, 38, 36, 36, 42, 43, 44, 46, 42, 37, 33, 39, 42, 44, 43, 41, 33,
+ 29, 38, 40, 40, 41, 40, 33, 26, 35, 37, 37, 38, 36, 29, 20, 31, 34, 34, 34,
+ 32, 31, 16, 28, 31, 33, 33, 30, 30, 15, 24, 31, 31, 31, 30, 27, 30, 35, 36,
+ 37, 37, 35, 29, 25, 33, 34, 36, 36, 31, 26, 22, 30, 34, 34, 32, 28, 26, 17,
+ 25, 30, 29, 29, 24, 25, 16, 19, 26, 26, 24, 21, 21, 15, 16, 25, 25, 25, 20,
+ 17, 15, 12, 22, 23, 23, 20, 13, 16, 26, 28, 29, 25, 22, 28, 13, 22, 26, 28,
+ 25, 19, 27, 13, 17, 25, 24, 22, 15, 21, 13, 12, 21, 21, 18, 11, 17, 12, 7,
+ 17, 17, 14, 8, 13, 11, 8, 14, 15, 13, 7, 10, 11, 9, 10, 13, 12, 7, 9,
+ 9, 14, 18, 18, 17, 19, 24, 9, 9, 17, 17, 16, 16, 19, 9, 6, 15, 14, 12,
+ 13, 15, 8, 5, 10, 10, 9, 10, 10, 7, 4, 5, 6, 5, 7, 8, 6, 5, 3,
+ 3, 4, 6, 8, 7, 6, 3, 2, 3, 6, 7, 5, 5, 10, 13, 15, 18, 20, 5,
+ 5, 9, 12, 14, 15, 16, 5, 5, 8, 10, 11, 11, 13, 5, 4, 3, 6, 7, 8,
+ 8, 3, 3, 2, 0, 3, 5, 7, 3, 2, 4, 5, 2, 5, 6, 4, 4, 6, 6,
+ 2, 4, 6, 37, 42, 45, 48, 48, 46, 42, 36, 40, 43, 47, 48, 44, 40, 34, 37,
+ 42, 46, 46, 42, 38, 32, 36, 41, 43, 44, 41, 34, 29, 33, 36, 39, 40, 37, 35,
+ 27, 29, 33, 35, 39, 37, 33, 24, 27, 30, 35, 37, 39, 34, 34, 38, 41, 46, 45,
+ 42, 37, 34, 37, 40, 45, 44, 40, 35, 31, 35, 39, 42, 41, 38, 34, 29, 33, 36,
+ 39, 38, 36, 29, 25, 30, 32, 35, 35, 33, 29, 20, 27, 29, 32, 32, 32, 29, 15,
+ 26, 29, 32, 31, 31, 29, 31, 34, 37, 39, 40, 37, 30, 28, 34, 36, 37, 37, 35,
+ 29, 25, 32, 35, 35, 34, 34, 27, 21, 30, 31, 31, 31, 29, 25, 16, 25, 28, 28,
+ 27, 25, 24, 12, 23, 25, 25, 25, 24, 24, 11, 19, 25, 23, 24, 24, 21, 25, 29,
+ 30, 31, 31, 30, 24, 21, 28, 29, 30, 30, 27, 21, 18, 25, 27, 27, 27, 23, 20,
+ 15, 22, 24, 23, 23, 20, 19, 12, 15, 21, 21, 19, 15, 16, 11, 12, 19, 18, 18,
+ 15, 12, 11, 8, 17, 16, 16, 15, 9, 13, 21, 23, 23, 22, 19, 24, 9, 18, 21,
+ 22, 21, 15, 22, 10, 14, 19, 18, 17, 12, 17, 10, 8, 16, 15, 14, 8, 11, 8,
+ 4, 12, 11, 10, 5, 8, 7, 4, 9, 8, 8, 4, 6, 6, 5, 6, 7, 7, 4,
+ 5, 5, 11, 13, 14, 14, 16, 20, 5, 8, 12, 13, 13, 14, 16, 5, 4, 11, 10,
+ 10, 11, 11, 5, 3, 7, 6, 7, 7, 6, 3, 2, 2, 1, 3, 4, 5, 3, 2,
+ 3, 3, 2, 3, 5, 4, 3, 4, 4, 1, 3, 4, 5, 5, 9, 11, 13, 15, 16,
+ 5, 5, 8, 10, 12, 12, 13, 5, 5, 7, 8, 8, 9, 10, 5, 4, 3, 4, 5,
+ 6, 4, 3, 2, 4, 3, 0, 3, 4, 2, 3, 5, 5, 2, 2, 3, 2, 5, 6,
+ 6, 3, 1, 3, 32, 35, 39, 42, 42, 40, 37, 30, 34, 38, 42, 43, 39, 35, 29,
+ 31, 37, 40, 41, 37, 33, 28, 29, 33, 38, 39, 35, 28, 25, 27, 30, 33, 36, 33,
+ 29, 22, 23, 26, 30, 34, 32, 29, 20, 22, 25, 29, 32, 32, 28, 29, 33, 36, 40,
+ 39, 36, 32, 28, 31, 35, 38, 39, 34, 30, 26, 30, 34, 36, 35, 32, 28, 26, 26,
+ 30, 33, 33, 30, 24, 21, 23, 27, 30, 29, 28, 23, 17, 22, 24, 27, 27, 26, 24,
+ 14, 20, 23, 26, 26, 26, 24, 27, 30, 31, 32, 35, 31, 27, 25, 29, 31, 32, 31,
+ 29, 24, 22, 27, 29, 28, 29, 28, 22, 19, 26, 26, 25, 25, 25, 19, 13, 22, 22,
+ 22, 22, 20, 18, 9, 20, 20, 20, 19, 20, 19, 8, 17, 19, 18, 18, 19, 17, 22,
+ 25, 25, 25, 27, 26, 19, 18, 23, 24, 24, 25, 23, 17, 14, 22, 22, 22, 21, 19,
+ 16, 11, 18, 18, 18, 18, 16, 14, 9, 13, 15, 14, 14, 12, 11, 9, 10, 13, 13,
+ 12, 12, 8, 8, 6, 12, 11, 11, 11, 5, 10, 17, 17, 18, 18, 15, 19, 7, 15,
+ 15, 16, 16, 12, 17, 7, 12, 13, 13, 13, 9, 12, 7, 6, 10, 9, 9, 5, 8,
+ 5, 2, 6, 5, 5, 3, 5, 4, 2, 4, 3, 3, 3, 4, 4, 3, 2, 2, 2,
+ 2, 3, 3, 9, 9, 10, 11, 13, 16, 3, 7, 8, 9, 10, 11, 12, 3, 4, 7,
+ 7, 7, 8, 8, 3, 3, 4, 4, 4, 4, 3, 2, 1, 4, 3, 1, 2, 3, 1,
+ 3, 5, 4, 2, 2, 3, 2, 4, 5, 5, 3, 0, 2, 4, 5, 6, 8, 10, 12,
+ 13, 4, 5, 6, 8, 9, 10, 10, 4, 5, 6, 5, 6, 6, 7, 4, 4, 5, 3,
+ 2, 3, 3, 2, 4, 7, 5, 3, 0, 3, 3, 5, 7, 6, 3, 2, 2, 4, 6,
+ 7, 7, 4, 2, 2, 26, 30, 34, 38, 38, 34, 31, 24, 29, 32, 36, 37, 33, 29,
+ 23, 26, 31, 35, 35, 32, 28, 22, 25, 28, 31, 33, 29, 24, 19, 21, 24, 28, 30,
+ 28, 24, 17, 19, 22, 25, 29, 28, 25, 16, 17, 20, 24, 27, 28, 24, 23, 27, 31,
+ 35, 33, 31, 27, 22, 25, 30, 33, 33, 30, 26, 21, 24, 28, 30, 31, 28, 24, 20,
+ 21, 25, 27, 28, 26, 20, 17, 19, 21, 24, 24, 23, 20, 15, 17, 20, 22, 22, 22,
+ 20, 12, 16, 19, 21, 21, 21, 20, 22, 24, 27, 27, 29, 26, 22, 20, 23, 25, 26,
+ 26, 25, 20, 18, 22, 23, 23, 24, 23, 18, 16, 20, 20, 20, 20, 20, 15, 11, 16,
+ 17, 17, 17, 16, 15, 7, 16, 15, 15, 15, 15, 14, 7, 14, 14, 14, 14, 14, 14,
+ 18, 18, 19, 20, 22, 21, 14, 15, 18, 18, 19, 19, 19, 13, 12, 17, 17, 16, 16,
+ 15, 11, 8, 15, 13, 12, 13, 12, 10, 6, 10, 10, 9, 9, 9, 7, 6, 8, 8,
+ 8, 7, 8, 4, 7, 4, 7, 6, 6, 6, 3, 7, 11, 11, 12, 13, 12, 14, 4,
+ 9, 10, 10, 11, 10, 12, 4, 8, 8, 7, 7, 7, 8, 4, 5, 4, 4, 4, 4,
+ 4, 2, 1, 1, 1, 1, 2, 3, 2, 3, 4, 3, 2, 0, 3, 3, 4, 5, 3,
+ 3, 2, 2, 3, 5, 6, 8, 9, 11, 12, 3, 4, 6, 7, 7, 8, 9, 3, 4,
+ 4, 5, 5, 5, 6, 3, 3, 4, 3, 2, 2, 2, 1, 5, 6, 4, 3, 2, 2,
+ 3, 7, 8, 6, 4, 2, 2, 5, 7, 9, 8, 4, 3, 0, 5, 7, 6, 6, 8,
+ 9, 10, 5, 7, 7, 6, 7, 7, 7, 5, 7, 8, 4, 3, 4, 5, 5, 6, 8,
+ 5, 3, 1, 2, 5, 8, 10, 8, 4, 3, 0, 7, 9, 10, 9, 5, 3, 1, 8,
+ 9, 10, 10, 6, 4, 2, 36, 41, 47, 48, 47, 47, 42, 36, 39, 44, 48, 49, 45,
+ 41, 34, 38, 42, 45, 47, 44, 39, 32, 35, 39, 42, 45, 41, 36, 29, 33, 35, 39,
+ 41, 39, 37, 26, 29, 32, 37, 41, 39, 36, 23, 27, 32, 34, 38, 39, 35, 33, 38,
+ 42, 45, 44, 42, 39, 31, 37, 41, 45, 44, 40, 38, 31, 35, 40, 42, 42, 40, 35,
+ 29, 33, 36, 39, 38, 38, 31, 25, 28, 32, 36, 35, 35, 32, 22, 27, 30, 32, 34,
+ 34, 31, 18, 24, 28, 32, 33, 32, 31, 31, 36, 37, 38, 39, 37, 32, 29, 33, 35,
+ 37, 38, 36, 31, 26, 32, 36, 35, 35, 35, 30, 22, 29, 31, 31, 31, 31, 26, 17,
+ 26, 27, 28, 27, 27, 26, 13, 24, 26, 26, 26, 27, 26, 12, 21, 23, 25, 24, 25,
+ 24, 27, 29, 30, 31, 32, 31, 23, 21, 27, 29, 30, 29, 28, 22, 19, 25, 27, 26,
+ 27, 25, 22, 14, 21, 24, 23, 23, 22, 20, 13, 17, 20, 19, 20, 18, 16, 12, 13,
+ 17, 18, 18, 17, 12, 12, 10, 15, 16, 17, 17, 10, 13, 20, 22, 22, 22, 19, 23,
+ 10, 18, 20, 20, 21, 16, 21, 10, 15, 18, 18, 18, 13, 17, 10, 9, 14, 14, 14,
+ 10, 12, 8, 4, 10, 10, 10, 8, 9, 7, 5, 7, 7, 8, 6, 9, 8, 7, 5,
+ 5, 6, 6, 8, 5, 11, 12, 13, 15, 17, 20, 5, 8, 10, 11, 13, 14, 16, 5,
+ 5, 8, 8, 10, 12, 13, 5, 4, 4, 4, 6, 8, 8, 4, 3, 2, 1, 2, 6,
+ 8, 4, 2, 4, 3, 1, 5, 8, 5, 5, 4, 3, 2, 4, 6, 4, 6, 6, 9,
+ 13, 16, 17, 4, 6, 7, 7, 11, 13, 14, 5, 6, 7, 4, 8, 9, 11, 4, 5,
+ 6, 3, 3, 5, 7, 3, 3, 5, 3, 2, 3, 7, 0, 4, 5, 5, 2, 1, 5,
+ 3, 5, 5, 5, 3, 1, 4, 42, 48, 52, 54, 55, 52, 49, 41, 46, 50, 54, 53,
+ 50, 46, 40, 44, 48, 52, 53, 50, 45, 38, 41, 46, 50, 52, 47, 41, 35, 39, 41,
+ 46, 47, 46, 42, 31, 35, 37, 42, 46, 44, 41, 28, 33, 38, 41, 44, 44, 41, 39,
+ 45, 48, 53, 51, 47, 44, 39, 43, 47, 50, 50, 47, 42, 36, 43, 46, 49, 48, 44,
+ 40, 34, 39, 44, 45, 46, 42, 36, 29, 35, 38, 41, 41, 40, 37, 24, 33, 36, 39,
+ 39, 39, 36, 20, 31, 34, 38, 38, 37, 37, 36, 40, 43, 43, 46, 43, 37, 34, 39,
+ 42, 43, 43, 41, 36, 30, 39, 40, 41, 41, 39, 33, 25, 35, 37, 37, 37, 35, 30,
+ 20, 31, 33, 33, 33, 32, 31, 15, 28, 31, 31, 31, 31, 30, 15, 25, 29, 30, 30,
+ 30, 27, 30, 35, 37, 37, 38, 36, 28, 25, 33, 34, 36, 35, 32, 27, 21, 30, 34,
+ 32, 32, 29, 26, 18, 26, 30, 29, 30, 26, 25, 16, 19, 26, 25, 25, 21, 21, 15,
+ 16, 23, 24, 24, 21, 17, 15, 12, 21, 22, 22, 20, 13, 17, 25, 27, 29, 27, 23,
+ 29, 14, 22, 26, 27, 25, 20, 27, 13, 18, 23, 23, 22, 17, 21, 13, 12, 20, 20,
+ 18, 12, 16, 12, 7, 16, 16, 14, 9, 13, 11, 7, 13, 13, 13, 8, 10, 10, 8,
+ 10, 12, 11, 8, 9, 9, 15, 18, 19, 18, 21, 24, 9, 10, 17, 17, 17, 18, 20,
+ 9, 6, 14, 14, 14, 15, 16, 9, 5, 10, 10, 10, 11, 11, 7, 4, 5, 5, 5,
+ 8, 10, 6, 4, 2, 2, 4, 6, 10, 7, 5, 3, 2, 3, 7, 8, 6, 6, 9,
+ 14, 16, 19, 21, 6, 6, 8, 13, 15, 16, 18, 6, 6, 6, 10, 12, 13, 14, 6,
+ 5, 5, 5, 8, 9, 9, 4, 3, 3, 2, 3, 5, 9, 4, 0, 3, 4, 1, 6,
+ 7, 3, 3, 4, 4, 2, 4, 6, 49, 54, 58, 61, 61, 58, 53, 48, 51, 57, 60,
+ 60, 57, 53, 46, 50, 54, 57, 59, 54, 51, 44, 47, 51, 55, 56, 51, 46, 40, 44,
+ 47, 51, 53, 49, 46, 36, 41, 44, 46, 50, 50, 46, 32, 38, 42, 46, 49, 48, 47,
+ 45, 49, 54, 58, 56, 54, 48, 44, 48, 52, 58, 56, 52, 47, 41, 47, 51, 55, 54,
+ 50, 44, 38, 44, 48, 52, 50, 48, 41, 33, 42, 44, 48, 46, 46, 41, 27, 37, 41,
+ 44, 45, 43, 40, 23, 34, 39, 43, 42, 42, 41, 41, 46, 50, 50, 51, 49, 41, 38,
+ 45, 48, 50, 49, 46, 40, 33, 44, 46, 47, 46, 44, 37, 30, 40, 43, 43, 43, 41,
+ 34, 24, 34, 39, 39, 39, 35, 34, 19, 30, 36, 36, 36, 35, 35, 17, 26, 34, 35,
+ 34, 34, 32, 34, 42, 41, 43, 42, 41, 34, 29, 38, 41, 41, 40, 36, 33, 25, 34,
+ 39, 39, 36, 33, 31, 21, 29, 36, 35, 33, 28, 29, 19, 23, 31, 32, 29, 24, 26,
+ 18, 18, 28, 29, 27, 23, 22, 17, 14, 25, 26, 26, 23, 17, 20, 29, 33, 34, 30,
+ 28, 33, 17, 25, 32, 32, 29, 24, 31, 17, 21, 29, 30, 26, 20, 26, 17, 15, 25,
+ 26, 22, 15, 21, 15, 10, 20, 22, 17, 11, 17, 13, 9, 16, 19, 15, 10, 14, 13,
+ 9, 11, 17, 15, 9, 11, 12, 17, 24, 23, 22, 24, 30, 12, 12, 22, 22, 20, 21,
+ 25, 12, 9, 19, 19, 17, 18, 20, 12, 8, 14, 16, 13, 13, 14, 10, 6, 7, 11,
+ 7, 10, 12, 9, 5, 4, 6, 5, 8, 10, 8, 6, 4, 5, 5, 7, 10, 8, 7,
+ 16, 18, 20, 23, 24, 8, 8, 13, 17, 19, 20, 20, 8, 7, 11, 14, 16, 16, 17,
+ 8, 6, 5, 11, 11, 12, 10, 6, 4, 3, 4, 5, 7, 10, 5, 3, 0, 1, 3,
+ 6, 9, 5, 3, 2, 2, 3, 5, 8, 48, 52, 55, 59, 59, 57, 52, 47, 50, 55,
+ 59, 59, 56, 50, 44, 48, 52, 56, 58, 53, 49, 43, 46, 50, 53, 54, 51, 44, 38,
+ 44, 46, 49, 52, 49, 44, 34, 40, 43, 45, 50, 48, 43, 30, 37, 41, 44, 48, 47,
+ 43, 45, 51, 53, 56, 56, 51, 47, 44, 47, 53, 55, 56, 50, 45, 40, 47, 51, 54,
+ 52, 48, 44, 36, 43, 48, 50, 49, 44, 40, 32, 39, 45, 47, 44, 43, 39, 26, 36,
+ 40, 43, 42, 42, 39, 21, 33, 38, 42, 42, 41, 40, 40, 45, 47, 48, 50, 48, 40,
+ 37, 44, 48, 46, 49, 46, 38, 32, 42, 46, 45, 46, 43, 37, 28, 40, 42, 43, 41,
+ 40, 33, 23, 35, 37, 38, 36, 34, 33, 17, 29, 35, 35, 35, 34, 34, 16, 24, 33,
+ 33, 33, 32, 31, 32, 39, 40, 43, 42, 40, 34, 28, 38, 40, 41, 40, 36, 32, 24,
+ 33, 38, 38, 37, 33, 30, 20, 28, 34, 34, 33, 28, 28, 19, 21, 31, 30, 28, 24,
+ 25, 17, 17, 27, 27, 26, 22, 21, 16, 13, 23, 26, 26, 21, 17, 19, 29, 33, 34,
+ 30, 27, 33, 16, 24, 32, 32, 29, 24, 31, 16, 21, 29, 29, 26, 20, 26, 16, 15,
+ 24, 25, 22, 14, 20, 14, 10, 19, 21, 17, 10, 17, 12, 8, 14, 17, 15, 9, 13,
+ 12, 8, 10, 16, 14, 9, 11, 11, 17, 23, 23, 22, 24, 29, 12, 12, 21, 22, 21,
+ 21, 24, 12, 9, 19, 19, 17, 18, 20, 11, 7, 14, 15, 13, 12, 13, 10, 5, 7,
+ 10, 7, 9, 11, 8, 5, 4, 6, 5, 7, 10, 7, 5, 4, 4, 4, 7, 9, 8,
+ 8, 16, 18, 21, 23, 24, 8, 8, 14, 18, 20, 20, 20, 8, 8, 11, 16, 15, 15,
+ 16, 8, 7, 6, 11, 11, 11, 10, 6, 5, 4, 5, 5, 6, 9, 4, 4, 1, 0,
+ 3, 6, 8, 4, 3, 2, 2, 2, 5, 7, 41, 45, 48, 52, 51, 50, 45, 39, 42,
+ 46, 52, 51, 47, 43, 37, 41, 45, 49, 49, 46, 41, 36, 39, 41, 46, 47, 44, 36,
+ 33, 36, 38, 42, 43, 40, 37, 29, 32, 35, 39, 42, 41, 37, 25, 30, 34, 37, 40,
+ 41, 37, 37, 42, 45, 49, 48, 44, 40, 36, 41, 44, 47, 47, 42, 37, 33, 38, 43,
+ 45, 44, 42, 36, 31, 37, 39, 41, 41, 38, 32, 26, 33, 35, 38, 38, 35, 32, 21,
+ 30, 33, 35, 34, 34, 31, 16, 28, 31, 34, 34, 33, 32, 34, 39, 40, 43, 42, 40,
+ 33, 31, 37, 40, 41, 40, 37, 33, 26, 35, 38, 39, 37, 36, 30, 24, 32, 33, 34,
+ 34, 32, 26, 17, 27, 31, 30, 30, 27, 26, 13, 24, 29, 28, 27, 26, 27, 12, 20,
+ 27, 27, 27, 26, 24, 27, 33, 32, 34, 34, 33, 27, 22, 30, 33, 32, 32, 29, 24,
+ 20, 27, 31, 31, 30, 26, 23, 17, 23, 27, 27, 26, 21, 22, 13, 17, 24, 23, 21,
+ 18, 18, 12, 12, 21, 20, 19, 17, 15, 12, 9, 19, 19, 19, 17, 11, 15, 23, 26,
+ 26, 24, 21, 26, 11, 20, 24, 25, 23, 18, 24, 11, 15, 22, 22, 20, 15, 19, 11,
+ 10, 19, 18, 16, 10, 13, 9, 5, 14, 14, 12, 6, 10, 8, 4, 10, 11, 10, 5,
+ 8, 8, 5, 7, 9, 8, 5, 6, 7, 13, 16, 17, 16, 19, 23, 7, 9, 15, 15,
+ 15, 16, 18, 7, 5, 13, 12, 13, 13, 13, 7, 4, 10, 9, 9, 9, 8, 5, 2,
+ 4, 4, 4, 5, 6, 3, 2, 2, 1, 2, 4, 6, 4, 3, 2, 2, 2, 4, 5,
+ 6, 6, 11, 13, 15, 17, 18, 6, 6, 11, 13, 14, 15, 15, 6, 6, 8, 10, 11,
+ 11, 11, 5, 5, 4, 6, 7, 7, 6, 3, 3, 3, 2, 2, 3, 5, 2, 1, 3,
+ 3, 0, 3, 4, 2, 3, 4, 4, 2, 3, 4, 33, 38, 42, 46, 45, 43, 37, 32,
+ 36, 40, 45, 44, 41, 37, 31, 34, 39, 42, 43, 39, 34, 30, 32, 36, 39, 40, 37,
+ 31, 27, 29, 31, 36, 37, 35, 31, 23, 26, 29, 33, 36, 34, 31, 22, 25, 28, 30,
+ 34, 34, 31, 31, 34, 38, 42, 42, 37, 34, 30, 33, 38, 41, 40, 36, 32, 29, 32,
+ 36, 38, 38, 36, 28, 27, 29, 32, 36, 35, 32, 27, 22, 26, 30, 32, 31, 30, 26,
+ 18, 23, 26, 29, 29, 29, 26, 15, 23, 25, 28, 28, 28, 26, 28, 31, 35, 34, 37,
+ 34, 28, 26, 31, 31, 34, 34, 32, 26, 23, 30, 31, 31, 31, 30, 23, 19, 28, 28,
+ 28, 28, 26, 21, 14, 24, 24, 24, 23, 23, 21, 10, 21, 23, 21, 22, 22, 21, 10,
+ 19, 21, 20, 21, 21, 18, 24, 26, 27, 27, 29, 27, 21, 19, 25, 26, 27, 27, 24,
+ 18, 16, 23, 24, 24, 24, 21, 18, 12, 19, 21, 20, 21, 18, 17, 10, 14, 17, 17,
+ 16, 13, 13, 10, 10, 15, 15, 14, 13, 10, 9, 7, 14, 13, 13, 12, 6, 11, 18,
+ 19, 20, 20, 16, 21, 8, 16, 18, 18, 18, 13, 19, 8, 12, 15, 15, 15, 11, 14,
+ 8, 7, 12, 12, 11, 6, 9, 6, 2, 8, 8, 7, 4, 6, 5, 3, 6, 5, 5,
+ 3, 5, 5, 3, 4, 4, 3, 3, 4, 4, 10, 10, 11, 13, 14, 18, 4, 8, 10,
+ 10, 12, 12, 13, 4, 4, 9, 8, 9, 9, 9, 4, 3, 5, 5, 5, 5, 4, 2,
+ 2, 2, 2, 2, 3, 4, 2, 1, 5, 4, 2, 2, 4, 3, 3, 5, 4, 2, 2,
+ 3, 5, 5, 8, 10, 11, 13, 14, 5, 5, 7, 9, 10, 11, 11, 5, 5, 6, 7,
+ 7, 8, 8, 5, 4, 5, 3, 3, 4, 3, 3, 3, 7, 5, 2, 2, 3, 1, 5,
+ 6, 6, 3, 0, 3, 4, 6, 6, 6, 4, 2, 2, 27, 31, 35, 38, 39, 36, 33,
+ 25, 30, 34, 39, 38, 35, 30, 25, 29, 32, 36, 37, 34, 29, 24, 26, 29, 32, 36,
+ 31, 26, 21, 24, 26, 29, 33, 30, 26, 18, 20, 23, 27, 30, 30, 25, 17, 19, 22,
+ 25, 29, 29, 26, 25, 28, 33, 35, 35, 33, 29, 24, 28, 32, 35, 35, 32, 27, 23,
+ 26, 30, 32, 32, 30, 25, 22, 24, 27, 29, 29, 26, 21, 19, 20, 23, 26, 26, 25,
+ 21, 16, 18, 21, 24, 23, 24, 21, 13, 17, 20, 22, 23, 22, 21, 22, 26, 28, 29,
+ 31, 28, 23, 22, 24, 26, 28, 28, 27, 22, 20, 23, 25, 25, 25, 25, 19, 17, 22,
+ 22, 22, 22, 21, 16, 11, 18, 19, 18, 18, 17, 16, 8, 17, 17, 17, 17, 16, 16,
+ 8, 16, 16, 15, 15, 16, 14, 20, 21, 20, 22, 24, 22, 16, 16, 20, 20, 21, 21,
+ 20, 14, 13, 18, 18, 18, 17, 17, 13, 9, 16, 15, 14, 14, 14, 12, 7, 12, 11,
+ 11, 10, 10, 8, 7, 9, 10, 9, 9, 9, 5, 8, 5, 8, 8, 8, 8, 3, 8,
+ 13, 13, 14, 15, 13, 15, 5, 11, 12, 12, 13, 10, 14, 5, 10, 10, 9, 9, 8,
+ 9, 5, 5, 6, 6, 5, 4, 5, 3, 1, 2, 2, 2, 2, 3, 3, 2, 3, 2,
+ 1, 2, 3, 4, 3, 4, 3, 2, 0, 2, 3, 6, 7, 8, 9, 11, 13, 3, 5,
+ 7, 8, 8, 9, 10, 3, 4, 5, 5, 6, 6, 6, 3, 3, 3, 2, 2, 3, 3,
+ 1, 4, 5, 4, 3, 0, 2, 1, 5, 7, 5, 3, 1, 2, 3, 6, 7, 6, 4,
+ 2, 2, 4, 6, 6, 7, 9, 10, 11, 4, 6, 6, 6, 8, 8, 8, 4, 6, 7,
+ 4, 4, 4, 6, 4, 6, 7, 4, 2, 1, 2, 3, 7, 8, 6, 3, 2, 1, 5,
+ 7, 9, 8, 4, 3, 0, 6, 7, 9, 9, 5, 3, 2, 38, 44, 48, 51, 51, 48,
+ 46, 38, 42, 46, 50, 51, 48, 44, 37, 41, 45, 47, 49, 44, 41, 34, 38, 41, 45,
+ 47, 43, 36, 32, 34, 38, 42, 42, 38, 37, 28, 30, 33, 36, 41, 38, 37, 23, 26,
+ 32, 35, 39, 40, 36, 37, 39, 45, 49, 49, 44, 41, 36, 39, 43, 47, 48, 44, 39,
+ 34, 37, 42, 45, 44, 42, 36, 31, 36, 38, 41, 42, 38, 32, 27, 31, 35, 38, 36,
+ 36, 31, 22, 28, 31, 33, 34, 35, 32, 18, 25, 29, 32, 33, 33, 32, 34, 36, 40,
+ 41, 43, 41, 37, 31, 34, 39, 40, 40, 39, 34, 28, 35, 37, 37, 37, 37, 32, 23,
+ 33, 34, 34, 34, 32, 27, 18, 28, 29, 30, 29, 28, 27, 13, 24, 26, 26, 27, 27,
+ 27, 11, 21, 24, 24, 25, 25, 25, 28, 32, 33, 34, 36, 35, 27, 23, 30, 31, 34,
+ 33, 31, 25, 20, 28, 29, 30, 30, 28, 24, 16, 23, 26, 26, 26, 24, 23, 14, 17,
+ 22, 22, 21, 19, 18, 12, 13, 17, 19, 18, 18, 15, 11, 9, 16, 16, 17, 17, 11,
+ 15, 23, 25, 26, 27, 23, 27, 12, 20, 23, 25, 25, 21, 25, 12, 16, 21, 21, 21,
+ 17, 20, 12, 11, 17, 17, 17, 12, 14, 10, 5, 13, 12, 11, 8, 11, 7, 4, 8,
+ 8, 9, 7, 10, 7, 5, 5, 6, 7, 7, 9, 7, 14, 16, 17, 19, 22, 24, 8,
+ 11, 15, 16, 18, 19, 20, 8, 7, 13, 13, 15, 15, 16, 7, 6, 9, 9, 11, 10,
+ 9, 5, 4, 4, 4, 4, 7, 9, 5, 3, 3, 2, 3, 5, 8, 4, 2, 3, 3,
+ 1, 5, 7, 8, 7, 9, 14, 18, 20, 21, 7, 7, 9, 12, 16, 17, 18, 7, 7,
+ 9, 9, 12, 14, 14, 8, 6, 8, 5, 7, 9, 7, 5, 5, 6, 4, 2, 4, 8,
+ 3, 3, 5, 4, 2, 4, 6, 0, 4, 5, 5, 3, 3, 5, 45, 50, 54, 59, 58,
+ 56, 50, 44, 48, 52, 57, 58, 51, 48, 42, 46, 51, 55, 54, 52, 46, 41, 44, 46,
+ 51, 53, 48, 41, 36, 41, 44, 47, 48, 45, 41, 32, 37, 40, 42, 45, 46, 42, 28,
+ 33, 37, 42, 45, 46, 42, 42, 47, 50, 54, 54, 50, 46, 39, 44, 50, 53, 53, 49,
+ 45, 39, 43, 48, 51, 50, 46, 41, 35, 41, 45, 47, 46, 43, 36, 30, 37, 41, 43,
+ 41, 40, 37, 24, 33, 38, 38, 40, 40, 37, 19, 31, 35, 38, 39, 38, 36, 38, 43,
+ 46, 46, 48, 45, 41, 34, 41, 46, 46, 47, 44, 38, 31, 41, 42, 44, 43, 40, 36,
+ 27, 38, 39, 40, 38, 37, 32, 21, 33, 35, 35, 34, 32, 31, 16, 26, 32, 31, 32,
+ 30, 32, 15, 24, 29, 31, 31, 30, 29, 31, 38, 40, 39, 40, 39, 32, 27, 35, 37,
+ 39, 38, 35, 30, 24, 31, 37, 36, 35, 32, 29, 19, 27, 31, 32, 32, 27, 27, 17,
+ 21, 28, 27, 26, 22, 22, 16, 15, 24, 23, 23, 21, 19, 15, 12, 21, 22, 22, 21,
+ 15, 18, 28, 30, 31, 30, 27, 31, 15, 24, 29, 30, 29, 24, 30, 15, 19, 26, 27,
+ 25, 19, 24, 15, 14, 22, 23, 21, 14, 19, 13, 8, 18, 18, 15, 10, 15, 11, 6,
+ 12, 14, 13, 8, 12, 10, 7, 9, 12, 11, 8, 10, 11, 16, 21, 22, 22, 24, 29,
+ 11, 12, 20, 20, 21, 22, 24, 11, 8, 17, 17, 18, 18, 18, 10, 7, 13, 13, 13,
+ 12, 12, 8, 5, 7, 8, 6, 9, 10, 6, 5, 2, 3, 4, 7, 10, 5, 4, 2,
+ 1, 4, 7, 9, 8, 8, 14, 18, 21, 23, 24, 8, 8, 12, 17, 20, 21, 21, 8,
+ 8, 10, 14, 16, 16, 16, 9, 7, 6, 9, 12, 11, 9, 6, 5, 4, 4, 5, 6,
+ 9, 4, 3, 3, 3, 3, 5, 8, 4, 0, 3, 3, 2, 5, 7, 49, 54, 57, 61,
+ 61, 57, 54, 47, 52, 57, 60, 62, 56, 53, 46, 50, 55, 58, 58, 55, 50, 45, 49,
+ 52, 55, 57, 52, 46, 40, 45, 49, 52, 53, 50, 46, 35, 41, 44, 47, 50, 50, 46,
+ 31, 38, 43, 45, 50, 51, 45, 47, 49, 55, 59, 57, 54, 50, 44, 50, 55, 58, 57,
+ 52, 46, 41, 47, 53, 55, 54, 51, 44, 39, 46, 50, 51, 50, 48, 40, 32, 41, 45,
+ 47, 46, 45, 40, 27, 37, 41, 43, 44, 44, 41, 22, 34, 40, 44, 42, 41, 41, 41,
+ 49, 50, 52, 52, 49, 43, 37, 46, 50, 50, 50, 47, 41, 33, 42, 47, 47, 47, 44,
+ 38, 29, 41, 43, 44, 42, 41, 35, 23, 35, 39, 40, 37, 36, 35, 19, 29, 37, 36,
+ 37, 34, 36, 18, 26, 35, 35, 34, 33, 32, 33, 40, 43, 45, 43, 41, 35, 30, 38,
+ 41, 42, 42, 38, 34, 25, 35, 40, 40, 39, 33, 32, 22, 30, 36, 35, 35, 30, 30,
+ 20, 23, 31, 32, 30, 24, 26, 18, 18, 28, 29, 28, 23, 23, 18, 14, 24, 27, 26,
+ 23, 18, 21, 29, 34, 36, 33, 29, 34, 17, 26, 33, 34, 31, 25, 33, 17, 21, 30,
+ 30, 28, 21, 27, 17, 16, 25, 27, 23, 15, 21, 15, 10, 20, 23, 18, 11, 17, 13,
+ 9, 15, 19, 16, 10, 14, 13, 9, 11, 18, 15, 10, 12, 12, 17, 25, 24, 23, 26,
+ 31, 12, 13, 23, 23, 22, 22, 26, 12, 9, 20, 20, 19, 19, 21, 12, 8, 14, 16,
+ 14, 14, 14, 11, 6, 8, 11, 7, 9, 12, 9, 5, 4, 6, 5, 8, 11, 7, 5,
+ 4, 5, 4, 7, 10, 9, 8, 17, 19, 22, 24, 26, 9, 8, 15, 19, 20, 21, 21,
+ 9, 8, 11, 16, 16, 17, 17, 9, 7, 7, 13, 12, 12, 11, 6, 5, 4, 6, 6,
+ 7, 10, 5, 4, 2, 2, 3, 7, 9, 4, 3, 0, 0, 3, 5, 8, 49, 53, 57,
+ 61, 62, 59, 55, 48, 53, 57, 60, 61, 57, 52, 45, 51, 53, 58, 59, 56, 51, 44,
+ 47, 52, 55, 57, 52, 46, 42, 45, 48, 51, 54, 49, 45, 35, 41, 45, 47, 50, 49,
+ 45, 31, 38, 41, 46, 49, 50, 46, 46, 52, 55, 59, 57, 54, 50, 46, 50, 54, 57,
+ 55, 53, 48, 41, 48, 52, 56, 53, 50, 44, 38, 46, 50, 52, 50, 47, 42, 31, 41,
+ 46, 48, 45, 45, 40, 27, 37, 41, 43, 43, 43, 40, 22, 35, 40, 42, 43, 41, 41,
+ 41, 48, 50, 51, 51, 49, 42, 36, 46, 48, 50, 49, 46, 41, 33, 43, 47, 48, 46,
+ 45, 38, 30, 41, 44, 44, 44, 40, 35, 24, 34, 39, 40, 38, 36, 35, 19, 30, 36,
+ 36, 36, 35, 35, 17, 24, 34, 35, 35, 33, 32, 33, 41, 43, 44, 44, 41, 35, 29,
+ 38, 42, 43, 40, 38, 33, 26, 34, 40, 40, 39, 33, 31, 22, 30, 36, 36, 34, 29,
+ 30, 20, 23, 31, 32, 30, 24, 26, 19, 18, 28, 29, 27, 23, 22, 17, 14, 24, 27,
+ 27, 22, 18, 21, 31, 34, 35, 32, 29, 35, 17, 26, 33, 33, 30, 25, 33, 17, 21,
+ 30, 30, 28, 21, 27, 17, 16, 25, 27, 24, 15, 22, 15, 11, 20, 22, 17, 11, 17,
+ 14, 9, 15, 18, 16, 10, 14, 13, 9, 10, 17, 15, 9, 12, 13, 17, 25, 24, 23,
+ 25, 31, 13, 13, 22, 23, 22, 23, 26, 13, 9, 20, 20, 18, 19, 21, 12, 8, 14,
+ 16, 14, 13, 14, 10, 6, 8, 12, 7, 10, 12, 9, 5, 4, 7, 5, 8, 10, 7,
+ 6, 4, 5, 5, 8, 10, 9, 8, 17, 19, 21, 24, 25, 9, 8, 15, 18, 20, 21,
+ 22, 9, 8, 11, 17, 17, 17, 17, 9, 7, 6, 12, 12, 12, 11, 6, 5, 4, 6,
+ 6, 7, 10, 5, 4, 2, 2, 4, 6, 9, 5, 3, 0, 0, 3, 5, 8, 43, 47,
+ 51, 55, 55, 53, 49, 40, 45, 50, 53, 53, 50, 45, 39, 44, 47, 51, 52, 48, 43,
+ 39, 42, 46, 47, 49, 46, 39, 35, 38, 41, 45, 46, 43, 39, 30, 34, 37, 40, 44,
+ 43, 38, 27, 32, 36, 39, 42, 43, 40, 40, 43, 48, 51, 51, 47, 43, 39, 42, 47,
+ 50, 50, 47, 41, 36, 41, 45, 47, 48, 44, 39, 33, 38, 42, 44, 44, 40, 34, 27,
+ 36, 38, 42, 39, 38, 35, 22, 32, 35, 37, 36, 37, 34, 18, 29, 34, 37, 37, 35,
+ 34, 36, 40, 43, 44, 45, 42, 37, 32, 38, 42, 44, 42, 41, 33, 28, 38, 40, 40,
+ 40, 38, 33, 25, 35, 36, 36, 36, 34, 29, 19, 30, 33, 33, 32, 30, 29, 14, 26,
+ 30, 29, 30, 28, 29, 13, 21, 29, 28, 29, 28, 26, 28, 36, 36, 37, 37, 35, 29,
+ 24, 32, 35, 36, 35, 31, 27, 20, 30, 33, 33, 32, 28, 25, 17, 24, 29, 28, 28,
+ 24, 24, 15, 18, 25, 26, 24, 19, 20, 14, 14, 23, 22, 22, 19, 17, 13, 10, 20,
+ 21, 21, 18, 12, 16, 25, 28, 29, 26, 23, 28, 13, 21, 26, 27, 25, 19, 27, 13,
+ 17, 24, 24, 22, 16, 21, 13, 12, 20, 19, 18, 11, 16, 11, 7, 16, 16, 13, 7,
+ 12, 10, 5, 12, 13, 12, 6, 9, 9, 6, 8, 11, 10, 6, 8, 8, 14, 19, 19,
+ 18, 20, 24, 8, 10, 17, 18, 17, 17, 20, 8, 6, 14, 14, 14, 14, 15, 8, 5,
+ 11, 11, 10, 10, 10, 6, 3, 5, 6, 4, 6, 8, 4, 3, 2, 2, 3, 5, 7,
+ 4, 3, 2, 1, 3, 4, 6, 6, 6, 13, 15, 17, 19, 20, 6, 6, 12, 14, 16,
+ 16, 17, 6, 6, 9, 12, 12, 12, 13, 6, 5, 5, 8, 8, 8, 7, 4, 3, 3,
+ 2, 3, 4, 6, 3, 2, 3, 2, 2, 4, 5, 3, 2, 3, 3, 0, 4, 5, 36,
+ 40, 45, 47, 47, 44, 40, 34, 38, 42, 46, 46, 43, 38, 32, 36, 41, 44, 45, 42,
+ 36, 31, 34, 38, 40, 43, 39, 33, 29, 32, 33, 37, 39, 36, 32, 25, 27, 31, 33,
+ 37, 36, 33, 23, 26, 29, 33, 36, 37, 33, 33, 36, 41, 45, 43, 40, 35, 31, 35,
+ 39, 44, 43, 39, 35, 30, 33, 38, 41, 39, 36, 32, 29, 31, 34, 37, 37, 35, 29,
+ 24, 29, 31, 34, 32, 32, 29, 19, 26, 28, 31, 30, 32, 28, 15, 24, 27, 30, 30,
+ 29, 28, 31, 34, 36, 37, 37, 36, 30, 28, 32, 34, 36, 36, 35, 28, 25, 31, 34,
+ 34, 34, 31, 25, 20, 29, 29, 29, 30, 28, 23, 15, 24, 26, 26, 25, 24, 23, 11,
+ 21, 23, 23, 24, 23, 23, 10, 19, 24, 23, 22, 23, 20, 25, 29, 28, 30, 30, 29,
+ 23, 20, 27, 28, 29, 29, 26, 21, 17, 24, 27, 26, 26, 22, 19, 14, 20, 23, 22,
+ 22, 19, 18, 11, 15, 19, 19, 18, 14, 15, 11, 11, 17, 16, 16, 14, 11, 10, 7,
+ 16, 15, 15, 14, 8, 12, 20, 21, 22, 21, 18, 22, 9, 17, 20, 20, 20, 15, 21,
+ 9, 14, 18, 17, 17, 12, 15, 9, 8, 15, 14, 13, 7, 10, 7, 3, 10, 10, 9,
+ 5, 7, 6, 3, 8, 7, 7, 4, 5, 6, 4, 5, 6, 5, 4, 5, 5, 11, 12,
+ 13, 14, 16, 19, 5, 8, 11, 12, 13, 13, 15, 5, 5, 10, 9, 10, 10, 10, 5,
+ 3, 7, 6, 6, 6, 5, 3, 2, 1, 1, 2, 4, 4, 2, 2, 4, 3, 0, 3,
+ 5, 3, 2, 4, 4, 2, 2, 4, 5, 5, 9, 11, 13, 15, 15, 5, 5, 8, 10,
+ 12, 12, 12, 5, 5, 7, 8, 8, 9, 9, 5, 4, 4, 4, 4, 5, 4, 3, 2,
+ 4, 4, 1, 2, 4, 1, 4, 5, 5, 3, 2, 3, 2, 5, 5, 5, 3, 0, 3,
+ 29, 34, 38, 41, 41, 39, 34, 28, 31, 36, 40, 40, 37, 33, 27, 31, 34, 38, 39,
+ 36, 30, 26, 28, 31, 34, 37, 32, 27, 23, 25, 27, 31, 33, 31, 27, 20, 22, 25,
+ 28, 33, 31, 27, 19, 21, 23, 27, 30, 30, 28, 27, 30, 34, 38, 38, 34, 31, 26,
+ 29, 32, 37, 36, 34, 29, 25, 27, 32, 35, 33, 31, 26, 23, 25, 28, 31, 30, 28,
+ 23, 20, 23, 25, 28, 27, 26, 22, 17, 20, 23, 25, 25, 25, 23, 14, 19, 22, 24,
+ 24, 24, 24, 25, 28, 29, 31, 32, 30, 26, 23, 27, 28, 29, 30, 27, 23, 22, 25,
+ 28, 27, 27, 26, 21, 18, 23, 24, 23, 23, 23, 17, 12, 20, 20, 19, 20, 18, 17,
+ 8, 19, 19, 18, 18, 18, 17, 8, 16, 18, 17, 17, 18, 15, 21, 23, 23, 23, 25,
+ 24, 17, 18, 21, 22, 22, 22, 22, 15, 14, 20, 20, 19, 20, 18, 14, 10, 17, 17,
+ 16, 16, 15, 13, 8, 13, 13, 12, 12, 11, 10, 8, 9, 12, 11, 10, 10, 7, 8,
+ 6, 10, 9, 9, 9, 4, 9, 15, 15, 16, 17, 14, 17, 6, 13, 13, 14, 14, 11,
+ 15, 6, 11, 11, 11, 11, 8, 10, 6, 6, 8, 8, 7, 5, 6, 4, 2, 4, 4,
+ 3, 3, 4, 3, 2, 2, 2, 2, 3, 4, 4, 2, 3, 2, 1, 2, 3, 3, 7,
+ 8, 9, 10, 12, 14, 3, 6, 8, 9, 9, 10, 10, 3, 4, 6, 6, 6, 7, 7,
+ 3, 3, 3, 3, 3, 4, 3, 1, 3, 5, 3, 2, 2, 3, 1, 4, 6, 4, 3,
+ 0, 3, 2, 5, 6, 5, 3, 2, 2, 4, 6, 6, 8, 9, 11, 12, 4, 6, 6,
+ 7, 8, 9, 9, 4, 6, 6, 5, 5, 5, 6, 4, 4, 6, 3, 2, 2, 3, 2,
+ 5, 7, 6, 3, 2, 2, 4, 6, 8, 7, 4, 3, 2, 5, 7, 8, 8, 5, 3,
+ 0,
+};
diff --git a/extras/sharpyuv_risk_table.h b/extras/sharpyuv_risk_table.h
new file mode 100644
index 00000000..32f276e3
--- /dev/null
+++ b/extras/sharpyuv_risk_table.h
@@ -0,0 +1,27 @@
+// Copyright 2023 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Precomputed data for 420 risk estimation.
+
+#ifndef WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
+#define WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
+
+#include "src/webp/types.h"
+
+extern const int kSharpYuvPrecomputedRiskYuvSampling;
+// Table of precomputed risk scores when chroma subsampling images with two
+// given colors.
+// Since precomputing values for all possible YUV colors would create a huge
+// table, the YUV space (i.e. [0, 255]^3) is reduced to
+// [0, kSharpYuvPrecomputedRiskYuvSampling-1]^3
+// where 255 maps to kSharpYuvPrecomputedRiskYuvSampling-1.
+// Table size: kSharpYuvPrecomputedRiskYuvSampling^6 bytes or 114 KiB
+extern const uint8_t kSharpYuvPrecomputedRisk[];
+
+#endif // WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
diff --git a/extras/vwebp_sdl.c b/extras/vwebp_sdl.c
index e9554eb1..acf48909 100644
--- a/extras/vwebp_sdl.c
+++ b/extras/vwebp_sdl.c
@@ -30,7 +30,7 @@
#if defined(WEBP_HAVE_JUST_SDL_H)
#include <SDL.h>
#else
-#include <SDL/SDL.h>
+#include <SDL2/SDL.h>
#endif
static void ProcessEvents(void) {
diff --git a/extras/webp_to_sdl.c b/extras/webp_to_sdl.c
index 1e526811..971ffc88 100644
--- a/extras/webp_to_sdl.c
+++ b/extras/webp_to_sdl.c
@@ -20,88 +20,75 @@
#include "webp_to_sdl.h"
#include <stdio.h>
+
#include "src/webp/decode.h"
#if defined(WEBP_HAVE_JUST_SDL_H)
#include <SDL.h>
#else
-#include <SDL/SDL.h>
+#include <SDL2/SDL.h>
#endif
static int init_ok = 0;
int WebPToSDL(const char* data, unsigned int data_size) {
int ok = 0;
VP8StatusCode status;
- WebPDecoderConfig config;
- WebPBitstreamFeatures* const input = &config.input;
- WebPDecBuffer* const output = &config.output;
- SDL_Surface* screen = NULL;
- SDL_Surface* surface = NULL;
-
- if (!WebPInitDecoderConfig(&config)) {
- fprintf(stderr, "Library version mismatch!\n");
- return 0;
- }
+ WebPBitstreamFeatures input;
+ uint8_t* output = NULL;
+ SDL_Window* window = NULL;
+ SDL_Renderer* renderer = NULL;
+ SDL_Texture* texture = NULL;
+ int width, height;
if (!init_ok) {
SDL_Init(SDL_INIT_VIDEO);
init_ok = 1;
}
- status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &config.input);
+ status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &input);
if (status != VP8_STATUS_OK) goto Error;
+ width = input.width;
+ height = input.height;
- screen = SDL_SetVideoMode(input->width, input->height, 32, SDL_SWSURFACE);
- if (screen == NULL) {
- fprintf(stderr, "Unable to set video mode (32bpp %dx%d)!\n",
- input->width, input->height);
+ SDL_CreateWindowAndRenderer(width, height, 0, &window, &renderer);
+ if (window == NULL || renderer == NULL) {
+ fprintf(stderr, "Unable to create window or renderer!\n");
goto Error;
}
-
- surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
- input->width, input->height, 32,
- 0x000000ffu, // R mask
- 0x0000ff00u, // G mask
- 0x00ff0000u, // B mask
- 0xff000000u); // A mask
-
- if (surface == NULL) {
- fprintf(stderr, "Unable to create %dx%d RGBA surface!\n",
- input->width, input->height);
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,
+ "linear"); // make the scaled rendering look smoother.
+ SDL_RenderSetLogicalSize(renderer, width, height);
+
+ texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
+ SDL_TEXTUREACCESS_STREAMING, width, height);
+ if (texture == NULL) {
+ fprintf(stderr, "Unable to create %dx%d RGBA texture!\n", width, height);
goto Error;
}
- if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- output->colorspace = MODE_BGRA;
+ output = WebPDecodeBGRA((const uint8_t*)data, (size_t)data_size, &width,
+ &height);
#else
- output->colorspace = MODE_RGBA;
+ output = WebPDecodeRGBA((const uint8_t*)data, (size_t)data_size, &width,
+ &height);
#endif
- output->width = surface->w;
- output->height = surface->h;
- output->u.RGBA.rgba = surface->pixels;
- output->u.RGBA.stride = surface->pitch;
- output->u.RGBA.size = surface->pitch * surface->h;
- output->is_external_memory = 1;
-
- status = WebPDecode((const uint8_t*)data, (size_t)data_size, &config);
- if (status != VP8_STATUS_OK) {
+ if (output == NULL) {
fprintf(stderr, "Error decoding image (%d)\n", status);
goto Error;
}
- if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
- if (SDL_BlitSurface(surface, NULL, screen, NULL) ||
- SDL_Flip(screen)) {
- goto Error;
- }
-
+ SDL_UpdateTexture(texture, NULL, output, width * sizeof(uint32_t));
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, texture, NULL, NULL);
+ SDL_RenderPresent(renderer);
ok = 1;
Error:
- SDL_FreeSurface(surface);
- SDL_FreeSurface(screen);
- WebPFreeDecBuffer(output);
+ // We should call SDL_DestroyWindow(window) but that makes .js fail.
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyTexture(texture);
+ WebPFree(output);
return ok;
}
diff --git a/imageio/image_enc.c b/imageio/image_enc.c
index e06bcaf5..d58477f3 100644
--- a/imageio/image_enc.c
+++ b/imageio/image_enc.c
@@ -260,14 +260,20 @@ int WebPWritePAM(FILE* fout, const WebPDecBuffer* const buffer) {
// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose.
int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {
- const uint32_t width = buffer->width;
- const uint32_t height = buffer->height;
- const uint8_t* rgba = buffer->u.RGBA.rgba;
- const int stride = buffer->u.RGBA.stride;
+ uint32_t width, height;
+ uint8_t* rgba;
+ int stride;
const uint32_t bytes_per_px = 2;
uint32_t y;
- if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
+ if (fout == NULL || buffer == NULL) return 0;
+
+ width = buffer->width;
+ height = buffer->height;
+ rgba = buffer->u.RGBA.rgba;
+ stride = buffer->u.RGBA.stride;
+
+ if (rgba == NULL) return 0;
fprintf(fout, "P5\n%u %u\n255\n", width * bytes_per_px, height);
for (y = 0; y < height; ++y) {
@@ -295,22 +301,29 @@ static void PutLE32(uint8_t* const dst, uint32_t value) {
#define BMP_HEADER_SIZE 54
#define BMP_HEADER_ALPHA_EXTRA_SIZE 16 // for alpha info
int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
- const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
- const int header_size =
- BMP_HEADER_SIZE + (has_alpha ? BMP_HEADER_ALPHA_EXTRA_SIZE : 0);
- const uint32_t width = buffer->width;
- const uint32_t height = buffer->height;
- const uint8_t* rgba = buffer->u.RGBA.rgba;
- const int stride = buffer->u.RGBA.stride;
- const uint32_t bytes_per_px = has_alpha ? 4 : 3;
+ int has_alpha, header_size;
+ uint32_t width, height;
+ uint8_t* rgba;
+ int stride;
uint32_t y;
- const uint32_t line_size = bytes_per_px * width;
- const uint32_t bmp_stride = (line_size + 3) & ~3; // pad to 4
- const uint32_t image_size = bmp_stride * height;
- const uint32_t total_size = image_size + header_size;
+ uint32_t bytes_per_px, line_size, image_size, bmp_stride, total_size;
uint8_t bmp_header[BMP_HEADER_SIZE + BMP_HEADER_ALPHA_EXTRA_SIZE] = { 0 };
- if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
+ if (fout == NULL || buffer == NULL) return 0;
+
+ has_alpha = WebPIsAlphaMode(buffer->colorspace);
+ header_size = BMP_HEADER_SIZE + (has_alpha ? BMP_HEADER_ALPHA_EXTRA_SIZE : 0);
+ width = buffer->width;
+ height = buffer->height;
+ rgba = buffer->u.RGBA.rgba;
+ stride = buffer->u.RGBA.stride;
+ bytes_per_px = has_alpha ? 4 : 3;
+ line_size = bytes_per_px * width;
+ bmp_stride = (line_size + 3) & ~3; // pad to 4
+ image_size = bmp_stride * height;
+ total_size = image_size + header_size;
+
+ if (rgba == NULL) return 0;
// bitmap file header
PutLE16(bmp_header + 0, 0x4d42); // signature 'BM'
@@ -372,17 +385,14 @@ int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {
#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE)
int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
- const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
- const uint32_t width = buffer->width;
- const uint32_t height = buffer->height;
- const uint8_t* rgba = buffer->u.RGBA.rgba;
- const int stride = buffer->u.RGBA.stride;
- const uint8_t bytes_per_px = has_alpha ? 4 : 3;
- const uint8_t assoc_alpha =
- WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
+ int has_alpha;
+ uint32_t width, height;
+ uint8_t* rgba;
+ int stride;
+ uint8_t bytes_per_px = 0;
+ const uint8_t assoc_alpha = 0;
// For non-alpha case, we omit tag 0x152 (ExtraSamples).
- const uint8_t num_ifd_entries = has_alpha ? NUM_IFD_ENTRIES
- : NUM_IFD_ENTRIES - 1;
+ const uint8_t num_ifd_entries = 0;
uint8_t tiff_header[TIFF_HEADER_SIZE] = {
0x49, 0x49, 0x2a, 0x00, // little endian signature
8, 0, 0, 0, // offset to the unique IFD that follows
@@ -416,7 +426,20 @@ int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {
};
uint32_t y;
- if (fout == NULL || buffer == NULL || rgba == NULL) return 0;
+ if (fout == NULL || buffer == NULL) return 0;
+
+ has_alpha = WebPIsAlphaMode(buffer->colorspace);
+ width = buffer->width;
+ height = buffer->height;
+ rgba = buffer->u.RGBA.rgba;
+ stride = buffer->u.RGBA.stride;
+
+ if (rgba == NULL) return 0;
+
+ // Update bytes_per_px, num_ifd_entries and assoc_alpha.
+ tiff_header[38] = tiff_header[102] = bytes_per_px = has_alpha ? 4 : 3;
+ tiff_header[8] = has_alpha ? NUM_IFD_ENTRIES : NUM_IFD_ENTRIES - 1;
+ tiff_header[186] = WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2;
// Fill placeholders in IFD:
PutLE32(tiff_header + 10 + 8, width);
diff --git a/imageio/pngdec.c b/imageio/pngdec.c
index 6a1543bd..cdd99883 100644
--- a/imageio/pngdec.c
+++ b/imageio/pngdec.c
@@ -235,7 +235,7 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
volatile png_infop end_info = NULL;
PNGReadContext context = { NULL, 0, 0 };
int color_type, bit_depth, interlaced;
- int has_alpha;
+ int num_channels;
int num_passes;
int p;
volatile int ok = 0;
@@ -293,9 +293,6 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
}
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png);
- has_alpha = 1;
- } else {
- has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
}
// Apply gamma correction if needed.
@@ -310,13 +307,16 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
if (!keep_alpha) {
png_set_strip_alpha(png);
- has_alpha = 0;
}
num_passes = png_set_interlace_handling(png);
png_read_update_info(png, info);
- stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb);
+ num_channels = png_get_channels(png, info);
+ if (num_channels != 3 && num_channels != 4) {
+ goto Error;
+ }
+ stride = (int64_t)num_channels * width * sizeof(*rgb);
if (stride != (int)stride ||
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
goto Error;
@@ -341,8 +341,8 @@ int ReadPNG(const uint8_t* const data, size_t data_size,
pic->width = (int)width;
pic->height = (int)height;
- ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, (int)stride)
- : WebPPictureImportRGB(pic, rgb, (int)stride);
+ ok = (num_channels == 4) ? WebPPictureImportRGBA(pic, rgb, (int)stride)
+ : WebPPictureImportRGB(pic, rgb, (int)stride);
if (!ok) {
goto Error;
diff --git a/iosbuild.sh b/iosbuild.sh
index cd3a24cf..d0fb5572 100755
--- a/iosbuild.sh
+++ b/iosbuild.sh
@@ -41,6 +41,7 @@ readonly TARGETDIR="${TOPDIR}/WebP.framework"
readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.framework"
readonly MUXTARGETDIR="${TOPDIR}/WebPMux.framework"
readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.framework"
+readonly SHARPYUVTARGETDIR="${TOPDIR}/SharpYuv.framework"
readonly DEVELOPER=$(xcode-select --print-path)
readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
@@ -63,7 +64,8 @@ echo "Xcode Version: ${XCODE}"
echo "iOS SDK Version: ${SDK}"
if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \
- || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" ]]; then
+ || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" \
+ || -e "${SHARPYUVTARGETDIR}" ]]; then
cat << EOF
WARNING: The following directories will be deleted:
WARNING: ${BUILDDIR}
@@ -71,14 +73,16 @@ WARNING: ${TARGETDIR}
WARNING: ${DECTARGETDIR}
WARNING: ${MUXTARGETDIR}
WARNING: ${DEMUXTARGETDIR}
+WARNING: ${SHARPYUVTARGETDIR}
WARNING: The build will continue in 5 seconds...
EOF
sleep 5
fi
rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \
- ${MUXTARGETDIR} ${DEMUXTARGETDIR}
+ ${MUXTARGETDIR} ${DEMUXTARGETDIR} ${SHARPYUVTARGETDIR}
mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/ \
- ${MUXTARGETDIR}/Headers/ ${DEMUXTARGETDIR}/Headers/
+ ${MUXTARGETDIR}/Headers/ ${DEMUXTARGETDIR}/Headers/ \
+ ${SHARPYUVTARGETDIR}/Headers/
if [[ ! -e ${SRCDIR}/configure ]]; then
if ! (cd ${SRCDIR} && sh autogen.sh); then
@@ -134,13 +138,14 @@ for PLATFORM in ${PLATFORMS}; do
set +x
# Build only the libraries, skip the examples.
- make V=0 -C sharpyuv
+ make V=0 -C sharpyuv install
make V=0 -C src install
LIBLIST+=" ${ROOTDIR}/lib/libwebp.a"
DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a"
MUXLIBLIST+=" ${ROOTDIR}/lib/libwebpmux.a"
DEMUXLIBLIST+=" ${ROOTDIR}/lib/libwebpdemux.a"
+ SHARPYUVLIBLIST+=" ${ROOTDIR}/lib/libsharpyuv.a"
make clean
@@ -165,4 +170,9 @@ cp -a ${SRCDIR}/src/webp/{decode,types,mux_types,demux}.h \
${DEMUXTARGETDIR}/Headers/
${LIPO} -create ${DEMUXLIBLIST} -output ${DEMUXTARGETDIR}/WebPDemux
+echo "SHARPYUVLIBLIST = ${SHARPYUVLIBLIST}"
+cp -a ${SRCDIR}/sharpyuv/{sharpyuv,sharpyuv_csp}.h \
+ ${SHARPYUVTARGETDIR}/Headers/
+${LIPO} -create ${SHARPYUVLIBLIST} -output ${SHARPYUVTARGETDIR}/SharpYuv
+
echo "SUCCESS"
diff --git a/makefile.unix b/makefile.unix
index 8348d108..70f97ff2 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -37,13 +37,13 @@ else
endif
# SDL flags: use sdl-config if it exists
-SDL_CONFIG = $(shell sdl-config --version 2> /dev/null)
+SDL_CONFIG = $(shell sdl2-config --version 2> /dev/null)
ifneq ($(SDL_CONFIG),)
- SDL_LIBS = $(shell sdl-config --libs)
- SDL_FLAGS = $(shell sdl-config --cflags)
+ SDL_LIBS = $(shell sdl2-config --libs)
+ SDL_FLAGS = $(shell sdl2-config --cflags)
else
# use best-guess
- SDL_LIBS = -lSDL
+ SDL_LIBS = -lSDL2
SDL_FLAGS =
endif
@@ -276,6 +276,7 @@ UTILS_DEC_OBJS = \
src/utils/color_cache_utils.o \
src/utils/filters_utils.o \
src/utils/huffman_utils.o \
+ src/utils/palette.o \
src/utils/quant_levels_dec_utils.o \
src/utils/random_utils.o \
src/utils/rescaler_utils.o \
@@ -290,6 +291,7 @@ UTILS_ENC_OBJS = \
EXTRA_OBJS = \
extras/extras.o \
extras/quality_estimate.o \
+ extras/sharpyuv_risk_table.o \
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
@@ -343,6 +345,7 @@ HDRS = \
src/utils/filters_utils.h \
src/utils/huffman_utils.h \
src/utils/huffman_encode_utils.h \
+ src/utils/palette.h \
src/utils/quant_levels_utils.h \
src/utils/quant_levels_dec_utils.h \
src/utils/random_utils.h \
diff --git a/man/cwebp.1 b/man/cwebp.1
index 28de4c94..f8d88143 100644
--- a/man/cwebp.1
+++ b/man/cwebp.1
@@ -1,5 +1,5 @@
.\" Hey, EMACS: -*- nroff -*-
-.TH CWEBP 1 "March 17, 2022"
+.TH CWEBP 1 "March 26, 2024"
.SH NAME
cwebp \- compress an image file to a WebP file
.SH SYNOPSIS
@@ -135,7 +135,9 @@ are used, \fB\-size\fP value will prevail.
Set a maximum number of passes to use during the dichotomy used by
options \fB\-size\fP or \fB\-psnr\fP. Maximum value is 10, default is 1.
If options \fB\-size\fP or \fB\-psnr\fP were used, but \fB\-pass\fP wasn't
-specified, a default value of '6' passes will be used.
+specified, a default value of '6' passes will be used. If \fB\-pass\fP is
+specified, but neither \fB-size\fP nor \fB-psnr\fP are, a target PSNR of 40dB
+will be used.
.TP
.BI \-qrange " int int
Specifies the permissible interval for the quality factor. This is particularly
@@ -202,7 +204,8 @@ In the VP8 format, the so\-called control partition has a limit of 512k and
is used to store the following information: whether the macroblock is skipped,
which segment it belongs to, whether it is coded as intra 4x4 or intra 16x16
mode, and finally the prediction modes to use for each of the sub\-blocks.
-For a very large image, 512k only leaves room to few bits per 16x16 macroblock.
+For a very large image, 512k only leaves room for a few bits per 16x16
+macroblock.
The absolute minimum is 4 bits per macroblock. Skip, segment, and mode
information can use up almost all these 4 bits (although the case is unlikely),
which is problematic for very large images. The partition_limit factor controls
@@ -211,7 +214,8 @@ useful in case the 512k limit is reached and the following message is displayed:
\fIError code: 6 (PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k)\fP.
If using \fB\-partition_limit\fP is not enough to meet the 512k constraint, one
should use less segments in order to save more header bits per macroblock.
-See the \fB\-segments\fP option.
+See the \fB\-segments\fP option. Note the \fB-m\fP and \fB-q\fP options also
+influence the encoder's decisions and ability to hit this limit.
.SS LOGGING OPTIONS
These options control the level of output:
diff --git a/man/img2webp.1 b/man/img2webp.1
index 5b28cede..fc493e12 100644
--- a/man/img2webp.1
+++ b/man/img2webp.1
@@ -1,10 +1,10 @@
.\" Hey, EMACS: -*- nroff -*-
-.TH IMG2WEBP 1 "January 5, 2022"
+.TH IMG2WEBP 1 "March 17, 2023"
.SH NAME
img2webp \- create animated WebP file from a sequence of input images.
.SH SYNOPSIS
.B img2webp
-[file_options] [[frame_options] frame_file]...
+[file_options] [[frame_options] frame_file]... [\-o webp_file]
.br
.B img2webp argument_file_name
.br
@@ -44,6 +44,18 @@ Mixed compression mode: optimize compression of the image by picking either
lossy or lossless compression for each frame heuristically. This global
option disables the local option \fB-lossy\fP and \fB-lossless\fP .
.TP
+.BI \-near_lossless " int
+Specify the level of near\-lossless image preprocessing. This option adjusts
+pixel values to help compressibility, but has minimal impact on the visual
+quality. It triggers lossless compression mode automatically. The range is 0
+(maximum preprocessing) to 100 (no preprocessing, the default). The typical
+value is around 60. Note that lossy with \fB\-q 100\fP can at times yield
+better results.
+.TP
+.B \-sharp_yuv
+Use more accurate and sharper RGB->YUV conversion if needed. Note that this
+process is slower than the default 'fast' RGB->YUV conversion.
+.TP
.BI \-loop " int
Specifies the number of times the animation should loop. Using '0'
means 'loop indefinitely'.
diff --git a/sharpyuv/Makefile.am b/sharpyuv/Makefile.am
index b6b46758..1a94d467 100644
--- a/sharpyuv/Makefile.am
+++ b/sharpyuv/Makefile.am
@@ -33,7 +33,7 @@ libsharpyuv_la_SOURCES += sharpyuv_gamma.c sharpyuv_gamma.h
libsharpyuv_la_SOURCES += sharpyuv.c sharpyuv.h
libsharpyuv_la_CPPFLAGS = $(AM_CPPFLAGS)
-libsharpyuv_la_LDFLAGS = -no-undefined -version-info 0:0:0 -lm
+libsharpyuv_la_LDFLAGS = -no-undefined -version-info 1:0:1 -lm
libsharpyuv_la_LIBADD =
libsharpyuv_la_LIBADD += libsharpyuv_sse2.la
libsharpyuv_la_LIBADD += libsharpyuv_neon.la
diff --git a/sharpyuv/libsharpyuv.rc b/sharpyuv/libsharpyuv.rc
index 7f1df723..e0027aa4 100644
--- a/sharpyuv/libsharpyuv.rc
+++ b/sharpyuv/libsharpyuv.rc
@@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,0,2,0
- PRODUCTVERSION 0,0,2,0
+ FILEVERSION 0,0,4,0
+ PRODUCTVERSION 0,0,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -24,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libsharpyuv DLL"
- VALUE "FileVersion", "0.2.0"
+ VALUE "FileVersion", "0.4.0"
VALUE "InternalName", "libsharpyuv.dll"
- VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "LegalCopyright", "Copyright (C) 2024"
VALUE "OriginalFilename", "libsharpyuv.dll"
VALUE "ProductName", "SharpYuv Library"
- VALUE "ProductVersion", "0.2.0"
+ VALUE "ProductVersion", "0.4.0"
END
END
BLOCK "VarFileInfo"
diff --git a/sharpyuv/sharpyuv.c b/sharpyuv/sharpyuv.c
index 7de34fb0..7cbf668f 100644
--- a/sharpyuv/sharpyuv.c
+++ b/sharpyuv/sharpyuv.c
@@ -75,41 +75,48 @@ static int RGBToGray(int64_t r, int64_t g, int64_t b) {
}
static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
- int rgb_bit_depth) {
+ int rgb_bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
- const uint32_t A = SharpYuvGammaToLinear(a, bit_depth);
- const uint32_t B = SharpYuvGammaToLinear(b, bit_depth);
- const uint32_t C = SharpYuvGammaToLinear(c, bit_depth);
- const uint32_t D = SharpYuvGammaToLinear(d, bit_depth);
- return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth);
+ const uint32_t A = SharpYuvGammaToLinear(a, bit_depth, transfer_type);
+ const uint32_t B = SharpYuvGammaToLinear(b, bit_depth, transfer_type);
+ const uint32_t C = SharpYuvGammaToLinear(c, bit_depth, transfer_type);
+ const uint32_t D = SharpYuvGammaToLinear(d, bit_depth, transfer_type);
+ return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth,
+ transfer_type);
}
static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w,
- int rgb_bit_depth) {
+ int rgb_bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
- int i;
- for (i = 0; i < w; ++i) {
- const uint32_t R = SharpYuvGammaToLinear(src[0 * w + i], bit_depth);
- const uint32_t G = SharpYuvGammaToLinear(src[1 * w + i], bit_depth);
- const uint32_t B = SharpYuvGammaToLinear(src[2 * w + i], bit_depth);
+ int i = 0;
+ do {
+ const uint32_t R =
+ SharpYuvGammaToLinear(src[0 * w + i], bit_depth, transfer_type);
+ const uint32_t G =
+ SharpYuvGammaToLinear(src[1 * w + i], bit_depth, transfer_type);
+ const uint32_t B =
+ SharpYuvGammaToLinear(src[2 * w + i], bit_depth, transfer_type);
const uint32_t Y = RGBToGray(R, G, B);
- dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth);
- }
+ dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth, transfer_type);
+ } while (++i < w);
}
static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
- fixed_t* dst, int uv_w, int rgb_bit_depth) {
- int i;
- for (i = 0; i < uv_w; ++i) {
+ fixed_t* dst, int uv_w, int rgb_bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
+ int i = 0;
+ do {
const int r =
ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0],
- src2[0 * uv_w + 1], rgb_bit_depth);
+ src2[0 * uv_w + 1], rgb_bit_depth, transfer_type);
const int g =
ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0],
- src2[2 * uv_w + 1], rgb_bit_depth);
+ src2[2 * uv_w + 1], rgb_bit_depth, transfer_type);
const int b =
ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0],
- src2[4 * uv_w + 1], rgb_bit_depth);
+ src2[4 * uv_w + 1], rgb_bit_depth, transfer_type);
const int W = RGBToGray(r, g, b);
dst[0 * uv_w] = (fixed_t)(r - W);
dst[1 * uv_w] = (fixed_t)(g - W);
@@ -117,15 +124,15 @@ static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
dst += 1;
src1 += 2;
src2 += 2;
- }
+ } while (++i < uv_w);
}
static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
- int i;
+ int i = 0;
assert(w > 0);
- for (i = 0; i < w; ++i) {
+ do {
y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
- }
+ } while (++i < w);
}
//------------------------------------------------------------------------------
@@ -151,9 +158,9 @@ static void ImportOneRow(const uint8_t* const r_ptr,
// Convert the rgb_step from a number of bytes to a number of uint8_t or
// uint16_t values depending the bit depth.
const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step;
- int i;
+ int i = 0;
const int w = (pic_width + 1) & ~1;
- for (i = 0; i < pic_width; ++i) {
+ do {
const int off = i * step;
const int shift = GetPrecisionShift(rgb_bit_depth);
if (rgb_bit_depth == 8) {
@@ -165,7 +172,7 @@ static void ImportOneRow(const uint8_t* const r_ptr,
dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift);
dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift);
}
- }
+ } while (++i < pic_width);
if (pic_width & 1) { // replicate rightmost pixel
dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
@@ -233,8 +240,11 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
const int sfix = GetPrecisionShift(rgb_bit_depth);
const int yuv_max = (1 << yuv_bit_depth) - 1;
- for (best_uv = best_uv_base, j = 0; j < height; ++j) {
- for (i = 0; i < width; ++i) {
+ best_uv = best_uv_base;
+ j = 0;
+ do {
+ i = 0;
+ do {
const int off = (i >> 1);
const int W = best_y[i];
const int r = best_uv[off + 0 * uv_w] + W;
@@ -246,19 +256,22 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
} else {
((uint16_t*)y_ptr)[i] = clip(y, yuv_max);
}
- }
+ } while (++i < width);
best_y += w;
best_uv += (j & 1) * 3 * uv_w;
y_ptr += y_stride;
- }
- for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
- for (i = 0; i < uv_w; ++i) {
- const int off = i;
+ } while (++j < height);
+
+ best_uv = best_uv_base;
+ j = 0;
+ do {
+ i = 0;
+ do {
// Note r, g and b values here are off by W, but a constant offset on all
// 3 components doesn't change the value of u and v with a YCbCr matrix.
- const int r = best_uv[off + 0 * uv_w];
- const int g = best_uv[off + 1 * uv_w];
- const int b = best_uv[off + 2 * uv_w];
+ const int r = best_uv[i + 0 * uv_w];
+ const int g = best_uv[i + 1 * uv_w];
+ const int b = best_uv[i + 2 * uv_w];
const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix);
const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix);
if (yuv_bit_depth <= 8) {
@@ -268,11 +281,11 @@ static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
((uint16_t*)u_ptr)[i] = clip(u, yuv_max);
((uint16_t*)v_ptr)[i] = clip(v, yuv_max);
}
- }
+ } while (++i < uv_w);
best_uv += 3 * uv_w;
u_ptr += u_stride;
v_ptr += v_stride;
- }
+ } while (++j < uv_h);
return 1;
}
@@ -285,7 +298,7 @@ static void* SafeMalloc(uint64_t nmemb, size_t size) {
return malloc((size_t)total_size);
}
-#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((W) * (H), sizeof(T)))
+#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((uint64_t)(W) * (H), sizeof(T)))
static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
const uint8_t* b_ptr, int rgb_step, int rgb_stride,
@@ -293,12 +306,14 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
uint8_t* u_ptr, int u_stride, uint8_t* v_ptr,
int v_stride, int yuv_bit_depth, int width,
int height,
- const SharpYuvConversionMatrix* yuv_matrix) {
+ const SharpYuvConversionMatrix* yuv_matrix,
+ SharpYuvTransferFunctionType transfer_type) {
// we expand the right/bottom border if needed
const int w = (width + 1) & ~1;
const int h = (height + 1) & ~1;
const int uv_w = w >> 1;
const int uv_h = h >> 1;
+ const int y_bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
uint64_t prev_diff_y_sum = ~0;
int j, iter;
@@ -346,9 +361,9 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
StoreGray(src1, best_y + 0, w);
StoreGray(src2, best_y + w, w);
- UpdateW(src1, target_y, w, rgb_bit_depth);
- UpdateW(src2, target_y + w, w, rgb_bit_depth);
- UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth);
+ UpdateW(src1, target_y, w, rgb_bit_depth, transfer_type);
+ UpdateW(src2, target_y + w, w, rgb_bit_depth, transfer_type);
+ UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth, transfer_type);
memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
best_y += 2 * w;
best_uv += 3 * uv_w;
@@ -369,7 +384,8 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
best_uv = best_uv_base;
target_y = target_y_base;
target_uv = target_uv_base;
- for (j = 0; j < h; j += 2) {
+ j = 0;
+ do {
fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w;
{
@@ -380,21 +396,21 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
cur_uv = next_uv;
}
- UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth);
- UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth);
- UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth);
+ UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth, transfer_type);
+ UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth, transfer_type);
+ UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth, transfer_type);
// update two rows of Y and one row of RGB
diff_y_sum +=
- SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w,
- rgb_bit_depth + GetPrecisionShift(rgb_bit_depth));
+ SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w, y_bit_depth);
SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
best_y += 2 * w;
best_uv += 3 * uv_w;
target_y += 2 * w;
target_uv += 3 * uv_w;
- }
+ j += 2;
+ } while (j < h);
// test exit condition
if (iter > 0) {
if (diff_y_sum < diff_y_threshold) break;
@@ -418,6 +434,7 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
free(tmp_buffer);
return ok;
}
+
#undef SAFE_ALLOC
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
@@ -440,6 +457,7 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
// By default SharpYuvConvert calls it with SharpYuvGetCPUInfo. If needed,
// users can declare it as extern and call it with an alternate VP8CPUInfo
// function.
+extern VP8CPUInfo SharpYuvGetCPUInfo;
SHARPYUV_EXTERN void SharpYuvInit(VP8CPUInfo cpu_info_func);
void SharpYuvInit(VP8CPUInfo cpu_info_func) {
static volatile VP8CPUInfo sharpyuv_last_cpuinfo_used =
@@ -461,12 +479,42 @@ void SharpYuvInit(VP8CPUInfo cpu_info_func) {
UNLOCK_ACCESS_AND_RETURN;
}
-int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
- const void* b_ptr, int rgb_step, int rgb_stride,
- int rgb_bit_depth, void* y_ptr, int y_stride,
- void* u_ptr, int u_stride, void* v_ptr,
- int v_stride, int yuv_bit_depth, int width,
+int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr,
+ int rgb_step, int rgb_stride, int rgb_bit_depth,
+ void* y_ptr, int y_stride, void* u_ptr, int u_stride,
+ void* v_ptr, int v_stride, int yuv_bit_depth, int width,
int height, const SharpYuvConversionMatrix* yuv_matrix) {
+ SharpYuvOptions options;
+ options.yuv_matrix = yuv_matrix;
+ options.transfer_type = kSharpYuvTransferFunctionSrgb;
+ return SharpYuvConvertWithOptions(
+ r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride, rgb_bit_depth, y_ptr, y_stride,
+ u_ptr, u_stride, v_ptr, v_stride, yuv_bit_depth, width, height, &options);
+}
+
+int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix* yuv_matrix,
+ SharpYuvOptions* options, int version) {
+ const int major = (version >> 24);
+ const int minor = (version >> 16) & 0xff;
+ if (options == NULL || yuv_matrix == NULL ||
+ (major == SHARPYUV_VERSION_MAJOR && major == 0 &&
+ minor != SHARPYUV_VERSION_MINOR) ||
+ (major != SHARPYUV_VERSION_MAJOR)) {
+ return 0;
+ }
+ options->yuv_matrix = yuv_matrix;
+ options->transfer_type = kSharpYuvTransferFunctionSrgb;
+ return 1;
+}
+
+int SharpYuvConvertWithOptions(const void* r_ptr, const void* g_ptr,
+ const void* b_ptr, int rgb_step, int rgb_stride,
+ int rgb_bit_depth, void* y_ptr, int y_stride,
+ void* u_ptr, int u_stride, void* v_ptr,
+ int v_stride, int yuv_bit_depth, int width,
+ int height, const SharpYuvOptions* options) {
+ const SharpYuvConversionMatrix* yuv_matrix = options->yuv_matrix;
+ SharpYuvTransferFunctionType transfer_type = options->transfer_type;
SharpYuvConversionMatrix scaled_matrix;
const int rgb_max = (1 << rgb_bit_depth) - 1;
const int rgb_round = 1 << (rgb_bit_depth - 1);
@@ -485,7 +533,7 @@ int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) {
return 0;
}
- if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride %2 != 0)) {
+ if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride % 2 != 0)) {
// Step/stride should be even for uint16_t buffers.
return 0;
}
@@ -520,7 +568,7 @@ int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride,
rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride,
v_ptr, v_stride, yuv_bit_depth, width, height,
- &scaled_matrix);
+ &scaled_matrix, transfer_type);
}
//------------------------------------------------------------------------------
diff --git a/sharpyuv/sharpyuv.h b/sharpyuv/sharpyuv.h
index 181b20a0..fe958915 100644
--- a/sharpyuv/sharpyuv.h
+++ b/sharpyuv/sharpyuv.h
@@ -22,21 +22,36 @@ extern "C" {
#else
// This explicitly marks library functions and allows for changing the
// signature for e.g., Windows DLL builds.
-#if defined(__GNUC__) && __GNUC__ >= 4
-#define SHARPYUV_EXTERN extern __attribute__((visibility("default")))
-#else
-#if defined(_MSC_VER) && defined(WEBP_DLL)
+#if defined(_WIN32) && defined(WEBP_DLL)
#define SHARPYUV_EXTERN __declspec(dllexport)
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define SHARPYUV_EXTERN extern __attribute__((visibility("default")))
#else
#define SHARPYUV_EXTERN extern
-#endif /* _MSC_VER && WEBP_DLL */
-#endif /* __GNUC__ >= 4 */
+#endif /* defined(_WIN32) && defined(WEBP_DLL) */
#endif /* WEBP_EXTERN */
#endif /* SHARPYUV_EXTERN */
+#ifndef SHARPYUV_INLINE
+#ifdef WEBP_INLINE
+#define SHARPYUV_INLINE WEBP_INLINE
+#else
+#ifndef _MSC_VER
+#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
+#define SHARPYUV_INLINE inline
+#else
+#define SHARPYUV_INLINE
+#endif
+#else
+#define SHARPYUV_INLINE __forceinline
+#endif /* _MSC_VER */
+#endif /* WEBP_INLINE */
+#endif /* SHARPYUV_INLINE */
+
// SharpYUV API version following the convention from semver.org
#define SHARPYUV_VERSION_MAJOR 0
-#define SHARPYUV_VERSION_MINOR 2
+#define SHARPYUV_VERSION_MINOR 4
#define SHARPYUV_VERSION_PATCH 0
// Version as a uint32_t. The major number is the high 8 bits.
// The minor number is the middle 8 bits. The patch number is the low 16 bits.
@@ -61,6 +76,33 @@ typedef struct {
int rgb_to_v[4];
} SharpYuvConversionMatrix;
+typedef struct SharpYuvOptions SharpYuvOptions;
+
+// Enums for transfer functions, as defined in H.273,
+// https://www.itu.int/rec/T-REC-H.273-202107-I/en
+typedef enum SharpYuvTransferFunctionType {
+ // 0 is reserved
+ kSharpYuvTransferFunctionBt709 = 1,
+ // 2 is unspecified
+ // 3 is reserved
+ kSharpYuvTransferFunctionBt470M = 4,
+ kSharpYuvTransferFunctionBt470Bg = 5,
+ kSharpYuvTransferFunctionBt601 = 6,
+ kSharpYuvTransferFunctionSmpte240 = 7,
+ kSharpYuvTransferFunctionLinear = 8,
+ kSharpYuvTransferFunctionLog100 = 9,
+ kSharpYuvTransferFunctionLog100_Sqrt10 = 10,
+ kSharpYuvTransferFunctionIec61966 = 11,
+ kSharpYuvTransferFunctionBt1361 = 12,
+ kSharpYuvTransferFunctionSrgb = 13,
+ kSharpYuvTransferFunctionBt2020_10Bit = 14,
+ kSharpYuvTransferFunctionBt2020_12Bit = 15,
+ kSharpYuvTransferFunctionSmpte2084 = 16, // PQ
+ kSharpYuvTransferFunctionSmpte428 = 17,
+ kSharpYuvTransferFunctionHlg = 18,
+ kSharpYuvTransferFunctionNum
+} SharpYuvTransferFunctionType;
+
// Converts RGB to YUV420 using a downsampling algorithm that minimizes
// artefacts caused by chroma subsampling.
// This is slower than standard downsampling (averaging of 4 UV values).
@@ -85,6 +127,8 @@ typedef struct {
// adjacent pixels on the y, u and v channels. If yuv_bit_depth > 8, they
// should be multiples of 2.
// width, height: width and height of the image in pixels
+// This function calls SharpYuvConvertWithOptions with a default transfer
+// function of kSharpYuvTransferFunctionSrgb.
SHARPYUV_EXTERN int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
const void* b_ptr, int rgb_step,
int rgb_stride, int rgb_bit_depth,
@@ -93,6 +137,31 @@ SHARPYUV_EXTERN int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
int yuv_bit_depth, int width, int height,
const SharpYuvConversionMatrix* yuv_matrix);
+struct SharpYuvOptions {
+ // This matrix cannot be NULL and can be initialized by
+ // SharpYuvComputeConversionMatrix.
+ const SharpYuvConversionMatrix* yuv_matrix;
+ SharpYuvTransferFunctionType transfer_type;
+};
+
+// Internal, version-checked, entry point
+SHARPYUV_EXTERN int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix*,
+ SharpYuvOptions*, int);
+
+// Should always be called, to initialize a fresh SharpYuvOptions
+// structure before modification. SharpYuvOptionsInit() must have succeeded
+// before using the 'options' object.
+static SHARPYUV_INLINE int SharpYuvOptionsInit(
+ const SharpYuvConversionMatrix* yuv_matrix, SharpYuvOptions* options) {
+ return SharpYuvOptionsInitInternal(yuv_matrix, options, SHARPYUV_VERSION);
+}
+
+SHARPYUV_EXTERN int SharpYuvConvertWithOptions(
+ const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step,
+ int rgb_stride, int rgb_bit_depth, void* y_ptr, int y_stride, void* u_ptr,
+ int u_stride, void* v_ptr, int v_stride, int yuv_bit_depth, int width,
+ int height, const SharpYuvOptions* options);
+
// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422
// support (it's rarely used in practice, especially for images).
diff --git a/sharpyuv/sharpyuv_dsp.c b/sharpyuv/sharpyuv_dsp.c
index 31c272c4..94a40ec6 100644
--- a/sharpyuv/sharpyuv_dsp.c
+++ b/sharpyuv/sharpyuv_dsp.c
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include "sharpyuv/sharpyuv_cpu.h"
+#include "src/webp/types.h"
//-----------------------------------------------------------------------------
@@ -69,9 +70,9 @@ uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst,
int len);
void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out,
- int bit_depth);
+ const uint16_t* best_y, uint16_t* out, int bit_depth);
+extern VP8CPUInfo SharpYuvGetCPUInfo;
extern void InitSharpYuvSSE2(void);
extern void InitSharpYuvNEON(void);
diff --git a/sharpyuv/sharpyuv_gamma.c b/sharpyuv/sharpyuv_gamma.c
index 20ab2da6..09028428 100644
--- a/sharpyuv/sharpyuv_gamma.c
+++ b/sharpyuv/sharpyuv_gamma.c
@@ -12,6 +12,7 @@
#include "sharpyuv/sharpyuv_gamma.h"
#include <assert.h>
+#include <float.h>
#include <math.h>
#include "src/webp/types.h"
@@ -97,7 +98,7 @@ static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab,
return result;
}
-uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) {
+static uint32_t ToLinearSrgb(uint16_t v, int bit_depth) {
const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth;
if (shift > 0) {
return kGammaToLinearTabS[v << shift];
@@ -105,9 +106,314 @@ uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) {
return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0);
}
-uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth) {
+static uint16_t FromLinearSrgb(uint32_t value, int bit_depth) {
return FixedPointInterpolation(
value, kLinearToGammaTabS,
(GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS),
bit_depth - GAMMA_TO_LINEAR_BITS);
}
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define CLAMP(x, low, high) \
+ (((x) < (low)) ? (low) : (((high) < (x)) ? (high) : (x)))
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+static WEBP_INLINE float Roundf(float x) {
+ if (x < 0)
+ return (float)ceil((double)(x - 0.5f));
+ else
+ return (float)floor((double)(x + 0.5f));
+}
+
+static WEBP_INLINE float Powf(float base, float exp) {
+ return (float)pow((double)base, (double)exp);
+}
+
+static WEBP_INLINE float Log10f(float x) { return (float)log10((double)x); }
+
+static float ToLinear709(float gamma) {
+ if (gamma < 0.f) {
+ return 0.f;
+ } else if (gamma < 4.5f * 0.018053968510807f) {
+ return gamma / 4.5f;
+ } else if (gamma < 1.f) {
+ return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
+ }
+ return 1.f;
+}
+
+static float FromLinear709(float linear) {
+ if (linear < 0.f) {
+ return 0.f;
+ } else if (linear < 0.018053968510807f) {
+ return linear * 4.5f;
+ } else if (linear < 1.f) {
+ return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
+ }
+ return 1.f;
+}
+
+static float ToLinear470M(float gamma) {
+ return Powf(CLAMP(gamma, 0.f, 1.f), 2.2f);
+}
+
+static float FromLinear470M(float linear) {
+ return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.2f);
+}
+
+static float ToLinear470Bg(float gamma) {
+ return Powf(CLAMP(gamma, 0.f, 1.f), 2.8f);
+}
+
+static float FromLinear470Bg(float linear) {
+ return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.8f);
+}
+
+static float ToLinearSmpte240(float gamma) {
+ if (gamma < 0.f) {
+ return 0.f;
+ } else if (gamma < 4.f * 0.022821585529445f) {
+ return gamma / 4.f;
+ } else if (gamma < 1.f) {
+ return Powf((gamma + 0.111572195921731f) / 1.111572195921731f, 1.f / 0.45f);
+ }
+ return 1.f;
+}
+
+static float FromLinearSmpte240(float linear) {
+ if (linear < 0.f) {
+ return 0.f;
+ } else if (linear < 0.022821585529445f) {
+ return linear * 4.f;
+ } else if (linear < 1.f) {
+ return 1.111572195921731f * Powf(linear, 0.45f) - 0.111572195921731f;
+ }
+ return 1.f;
+}
+
+static float ToLinearLog100(float gamma) {
+ // The function is non-bijective so choose the middle of [0, 0.01].
+ const float mid_interval = 0.01f / 2.f;
+ return (gamma <= 0.0f) ? mid_interval
+ : Powf(10.0f, 2.f * (MIN(gamma, 1.f) - 1.0f));
+}
+
+static float FromLinearLog100(float linear) {
+ return (linear < 0.01f) ? 0.0f : 1.0f + Log10f(MIN(linear, 1.f)) / 2.0f;
+}
+
+static float ToLinearLog100Sqrt10(float gamma) {
+ // The function is non-bijective so choose the middle of [0, 0.00316227766f[.
+ const float mid_interval = 0.00316227766f / 2.f;
+ return (gamma <= 0.0f) ? mid_interval
+ : Powf(10.0f, 2.5f * (MIN(gamma, 1.f) - 1.0f));
+}
+
+static float FromLinearLog100Sqrt10(float linear) {
+ return (linear < 0.00316227766f) ? 0.0f
+ : 1.0f + Log10f(MIN(linear, 1.f)) / 2.5f;
+}
+
+static float ToLinearIec61966(float gamma) {
+ if (gamma <= -4.5f * 0.018053968510807f) {
+ return Powf((-gamma + 0.09929682680944f) / -1.09929682680944f, 1.f / 0.45f);
+ } else if (gamma < 4.5f * 0.018053968510807f) {
+ return gamma / 4.5f;
+ }
+ return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
+}
+
+static float FromLinearIec61966(float linear) {
+ if (linear <= -0.018053968510807f) {
+ return -1.09929682680944f * Powf(-linear, 0.45f) + 0.09929682680944f;
+ } else if (linear < 0.018053968510807f) {
+ return linear * 4.5f;
+ }
+ return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
+}
+
+static float ToLinearBt1361(float gamma) {
+ if (gamma < -0.25f) {
+ return -0.25f;
+ } else if (gamma < 0.f) {
+ return Powf((gamma - 0.02482420670236f) / -0.27482420670236f, 1.f / 0.45f) /
+ -4.f;
+ } else if (gamma < 4.5f * 0.018053968510807f) {
+ return gamma / 4.5f;
+ } else if (gamma < 1.f) {
+ return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f);
+ }
+ return 1.f;
+}
+
+static float FromLinearBt1361(float linear) {
+ if (linear < -0.25f) {
+ return -0.25f;
+ } else if (linear < 0.f) {
+ return -0.27482420670236f * Powf(-4.f * linear, 0.45f) + 0.02482420670236f;
+ } else if (linear < 0.018053968510807f) {
+ return linear * 4.5f;
+ } else if (linear < 1.f) {
+ return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f;
+ }
+ return 1.f;
+}
+
+static float ToLinearPq(float gamma) {
+ if (gamma > 0.f) {
+ const float pow_gamma = Powf(gamma, 32.f / 2523.f);
+ const float num = MAX(pow_gamma - 107.f / 128.f, 0.0f);
+ const float den = MAX(2413.f / 128.f - 2392.f / 128.f * pow_gamma, FLT_MIN);
+ return Powf(num / den, 4096.f / 653.f);
+ }
+ return 0.f;
+}
+
+static float FromLinearPq(float linear) {
+ if (linear > 0.f) {
+ const float pow_linear = Powf(linear, 653.f / 4096.f);
+ const float num = 107.f / 128.f + 2413.f / 128.f * pow_linear;
+ const float den = 1.0f + 2392.f / 128.f * pow_linear;
+ return Powf(num / den, 2523.f / 32.f);
+ }
+ return 0.f;
+}
+
+static float ToLinearSmpte428(float gamma) {
+ return Powf(MAX(gamma, 0.f), 2.6f) / 0.91655527974030934f;
+}
+
+static float FromLinearSmpte428(float linear) {
+ return Powf(0.91655527974030934f * MAX(linear, 0.f), 1.f / 2.6f);
+}
+
+// Conversion in BT.2100 requires RGB info. Simplify to gamma correction here.
+static float ToLinearHlg(float gamma) {
+ if (gamma < 0.f) {
+ return 0.f;
+ } else if (gamma <= 0.5f) {
+ return Powf((gamma * gamma) * (1.f / 3.f), 1.2f);
+ }
+ return Powf((expf((gamma - 0.55991073f) / 0.17883277f) + 0.28466892f) / 12.0f,
+ 1.2f);
+}
+
+static float FromLinearHlg(float linear) {
+ linear = Powf(linear, 1.f / 1.2f);
+ if (linear < 0.f) {
+ return 0.f;
+ } else if (linear <= (1.f / 12.f)) {
+ return sqrtf(3.f * linear);
+ }
+ return 0.17883277f * logf(12.f * linear - 0.28466892f) + 0.55991073f;
+}
+
+uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
+ float v_float, linear;
+ if (transfer_type == kSharpYuvTransferFunctionSrgb) {
+ return ToLinearSrgb(v, bit_depth);
+ }
+ v_float = (float)v / ((1 << bit_depth) - 1);
+ switch (transfer_type) {
+ case kSharpYuvTransferFunctionBt709:
+ case kSharpYuvTransferFunctionBt601:
+ case kSharpYuvTransferFunctionBt2020_10Bit:
+ case kSharpYuvTransferFunctionBt2020_12Bit:
+ linear = ToLinear709(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt470M:
+ linear = ToLinear470M(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt470Bg:
+ linear = ToLinear470Bg(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte240:
+ linear = ToLinearSmpte240(v_float);
+ break;
+ case kSharpYuvTransferFunctionLinear:
+ return v;
+ case kSharpYuvTransferFunctionLog100:
+ linear = ToLinearLog100(v_float);
+ break;
+ case kSharpYuvTransferFunctionLog100_Sqrt10:
+ linear = ToLinearLog100Sqrt10(v_float);
+ break;
+ case kSharpYuvTransferFunctionIec61966:
+ linear = ToLinearIec61966(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt1361:
+ linear = ToLinearBt1361(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte2084:
+ linear = ToLinearPq(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte428:
+ linear = ToLinearSmpte428(v_float);
+ break;
+ case kSharpYuvTransferFunctionHlg:
+ linear = ToLinearHlg(v_float);
+ break;
+ default:
+ assert(0);
+ linear = 0;
+ break;
+ }
+ return (uint32_t)Roundf(linear * ((1 << 16) - 1));
+}
+
+uint16_t SharpYuvLinearToGamma(uint32_t v, int bit_depth,
+ SharpYuvTransferFunctionType transfer_type) {
+ float v_float, linear;
+ if (transfer_type == kSharpYuvTransferFunctionSrgb) {
+ return FromLinearSrgb(v, bit_depth);
+ }
+ v_float = (float)v / ((1 << 16) - 1);
+ switch (transfer_type) {
+ case kSharpYuvTransferFunctionBt709:
+ case kSharpYuvTransferFunctionBt601:
+ case kSharpYuvTransferFunctionBt2020_10Bit:
+ case kSharpYuvTransferFunctionBt2020_12Bit:
+ linear = FromLinear709(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt470M:
+ linear = FromLinear470M(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt470Bg:
+ linear = FromLinear470Bg(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte240:
+ linear = FromLinearSmpte240(v_float);
+ break;
+ case kSharpYuvTransferFunctionLinear:
+ return v;
+ case kSharpYuvTransferFunctionLog100:
+ linear = FromLinearLog100(v_float);
+ break;
+ case kSharpYuvTransferFunctionLog100_Sqrt10:
+ linear = FromLinearLog100Sqrt10(v_float);
+ break;
+ case kSharpYuvTransferFunctionIec61966:
+ linear = FromLinearIec61966(v_float);
+ break;
+ case kSharpYuvTransferFunctionBt1361:
+ linear = FromLinearBt1361(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte2084:
+ linear = FromLinearPq(v_float);
+ break;
+ case kSharpYuvTransferFunctionSmpte428:
+ linear = FromLinearSmpte428(v_float);
+ break;
+ case kSharpYuvTransferFunctionHlg:
+ linear = FromLinearHlg(v_float);
+ break;
+ default:
+ assert(0);
+ linear = 0;
+ break;
+ }
+ return (uint16_t)Roundf(linear * ((1 << bit_depth) - 1));
+}
diff --git a/sharpyuv/sharpyuv_gamma.h b/sharpyuv/sharpyuv_gamma.h
index d13aff59..b8ba7e98 100644
--- a/sharpyuv/sharpyuv_gamma.h
+++ b/sharpyuv/sharpyuv_gamma.h
@@ -12,6 +12,7 @@
#ifndef WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
#define WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
+#include "sharpyuv/sharpyuv.h"
#include "src/webp/types.h"
#ifdef __cplusplus
@@ -22,11 +23,13 @@ extern "C" {
// SharpYuvGammaToLinear or SharpYuvLinearToGamma.
void SharpYuvInitGammaTables(void);
-// Converts a gamma color value on 'bit_depth' bits to a 16 bit linear value.
-uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth);
+// Converts a 'bit_depth'-bit gamma color value to a 16-bit linear value.
+uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth,
+ SharpYuvTransferFunctionType transfer_type);
-// Converts a 16 bit linear color value to a gamma value on 'bit_depth' bits.
-uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth);
+// Converts a 16-bit linear color value to a 'bit_depth'-bit gamma value.
+uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth,
+ SharpYuvTransferFunctionType transfer_type);
#ifdef __cplusplus
} // extern "C"
diff --git a/src/Makefile.am b/src/Makefile.am
index b2979fbf..1dafadd1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,7 +36,7 @@ libwebp_la_LIBADD += utils/libwebputils.la
# other than the ones listed on the command line, i.e., after linking, it will
# not have unresolved symbols. Some platforms (Windows among them) require all
# symbols in shared libraries to be resolved at library creation.
-libwebp_la_LDFLAGS = -no-undefined -version-info 8:6:1
+libwebp_la_LDFLAGS = -no-undefined -version-info 8:9:1
libwebpincludedir = $(includedir)/webp
pkgconfig_DATA = libwebp.pc
@@ -48,7 +48,7 @@ if BUILD_LIBWEBPDECODER
libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la
libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la
- libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:6:1
+ libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:9:1
pkgconfig_DATA += libwebpdecoder.pc
endif
diff --git a/src/dec/alpha_dec.c b/src/dec/alpha_dec.c
index 0b93a30b..b6c874fb 100644
--- a/src/dec/alpha_dec.c
+++ b/src/dec/alpha_dec.c
@@ -13,18 +13,20 @@
#include <stdlib.h>
#include "src/dec/alphai_dec.h"
+#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h"
#include "src/dsp/dsp.h"
#include "src/utils/quant_levels_dec_utils.h"
#include "src/utils/utils.h"
#include "src/webp/format_constants.h"
+#include "src/webp/types.h"
//------------------------------------------------------------------------------
// ALPHDecoder object.
// Allocates a new alpha decoder instance.
-static ALPHDecoder* ALPHNew(void) {
+WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {
ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
return dec;
}
@@ -45,9 +47,9 @@ static void ALPHDelete(ALPHDecoder* const dec) {
// header for alpha data stored using lossless compression.
// Returns false in case of error in alpha header (data too short, invalid
// compression method or filter, error in lossless header data etc).
-static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
- size_t data_size, const VP8Io* const src_io,
- uint8_t* output) {
+WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
+ size_t data_size, const VP8Io* const src_io,
+ uint8_t* output) {
int ok = 0;
const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
@@ -79,7 +81,9 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
}
// Copy the necessary parameters from src_io to io
- VP8InitIo(io);
+ if (!VP8InitIo(io)) {
+ return 0;
+ }
WebPInitCustomIo(NULL, io);
io->opaque = dec;
io->width = src_io->width;
@@ -107,7 +111,8 @@ static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
// starting from row number 'row'. It assumes that rows up to (row - 1) have
// already been decoded.
// Returns false in case of bitstream error.
-static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
+WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row,
+ int num_rows) {
ALPHDecoder* const alph_dec = dec->alph_dec_;
const int width = alph_dec->width_;
const int height = alph_dec->io_.crop_bottom;
@@ -117,21 +122,12 @@ static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width;
uint8_t* dst = dec->alpha_plane_ + row * width;
assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]);
- if (alph_dec->filter_ != WEBP_FILTER_NONE) {
- assert(WebPUnfilters[alph_dec->filter_] != NULL);
- for (y = 0; y < num_rows; ++y) {
- WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width);
- prev_line = dst;
- dst += width;
- deltas += width;
- }
- } else {
- for (y = 0; y < num_rows; ++y) {
- memcpy(dst, deltas, width * sizeof(*dst));
- prev_line = dst;
- dst += width;
- deltas += width;
- }
+ assert(WebPUnfilters[alph_dec->filter_] != NULL);
+ for (y = 0; y < num_rows; ++y) {
+ WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width);
+ prev_line = dst;
+ dst += width;
+ deltas += width;
}
dec->alpha_prev_line_ = prev_line;
} else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION
@@ -147,7 +143,8 @@ static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
return 1;
}
-static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) {
+WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,
+ const VP8Io* const io) {
const int stride = io->width;
const int height = io->crop_bottom;
const uint64_t alpha_size = (uint64_t)stride * height;
@@ -155,7 +152,8 @@ static int AllocateAlphaPlane(VP8Decoder* const dec, const VP8Io* const io) {
dec->alpha_plane_mem_ =
(uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_));
if (dec->alpha_plane_mem_ == NULL) {
- return 0;
+ return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
+ "Alpha decoder initialization failed.");
}
dec->alpha_plane_ = dec->alpha_plane_mem_;
dec->alpha_prev_line_ = NULL;
@@ -174,9 +172,9 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
//------------------------------------------------------------------------------
// Main entry point.
-const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
- const VP8Io* const io,
- int row, int num_rows) {
+WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
+ const VP8Io* const io,
+ int row, int num_rows) {
const int width = io->width;
const int height = io->crop_bottom;
@@ -189,10 +187,19 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
if (!dec->is_alpha_decoded_) {
if (dec->alph_dec_ == NULL) { // Initialize decoder.
dec->alph_dec_ = ALPHNew();
- if (dec->alph_dec_ == NULL) return NULL;
+ if (dec->alph_dec_ == NULL) {
+ VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
+ "Alpha decoder initialization failed.");
+ return NULL;
+ }
if (!AllocateAlphaPlane(dec, io)) goto Error;
if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,
io, dec->alpha_plane_)) {
+ VP8LDecoder* const vp8l_dec = dec->alph_dec_->vp8l_dec_;
+ VP8SetError(dec,
+ (vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY
+ : vp8l_dec->status_,
+ "Alpha decoder initialization failed.");
goto Error;
}
// if we allowed use of alpha dithering, check whether it's needed at all
diff --git a/src/dec/buffer_dec.c b/src/dec/buffer_dec.c
index 4786cf0d..11ce76f1 100644
--- a/src/dec/buffer_dec.c
+++ b/src/dec/buffer_dec.c
@@ -75,7 +75,7 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
const int stride = abs(buf->stride);
const uint64_t size =
- MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
+ MIN_BUFFER_SIZE((uint64_t)width * kModeBpp[mode], height, stride);
ok &= (size <= buf->size);
ok &= (stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL);
diff --git a/src/dec/idec_dec.c b/src/dec/idec_dec.c
index 9035df56..ad042a1f 100644
--- a/src/dec/idec_dec.c
+++ b/src/dec/idec_dec.c
@@ -17,8 +17,10 @@
#include "src/dec/alphai_dec.h"
#include "src/dec/webpi_dec.h"
+#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h"
#include "src/utils/utils.h"
+#include "src/webp/decode.h"
// In append mode, buffer allocations increase as multiples of this value.
// Needs to be a power of 2.
@@ -161,8 +163,9 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
// Appends data to the end of MemBuffer->buf_. It expands the allocated memory
// size if required and also updates VP8BitReader's if new memory is allocated.
-static int AppendToMemBuffer(WebPIDecoder* const idec,
- const uint8_t* const data, size_t data_size) {
+WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec,
+ const uint8_t* const data,
+ size_t data_size) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
MemBuffer* const mem = &idec->mem_;
const int need_compressed_alpha = NeedCompressedAlpha(idec);
@@ -203,8 +206,9 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
return 1;
}
-static int RemapMemBuffer(WebPIDecoder* const idec,
- const uint8_t* const data, size_t data_size) {
+WEBP_NODISCARD static int RemapMemBuffer(WebPIDecoder* const idec,
+ const uint8_t* const data,
+ size_t data_size) {
MemBuffer* const mem = &idec->mem_;
const uint8_t* const old_buf = mem->buf_;
const uint8_t* const old_start =
@@ -237,7 +241,8 @@ static void ClearMemBuffer(MemBuffer* const mem) {
}
}
-static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
+WEBP_NODISCARD static int CheckMemBufferMode(MemBuffer* const mem,
+ MemBufferMode expected) {
if (mem->mode_ == MEM_MODE_NONE) {
mem->mode_ = expected; // switch to the expected mode
} else if (mem->mode_ != expected) {
@@ -248,7 +253,7 @@ static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
}
// To be called last.
-static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
+WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
const WebPDecoderOptions* const options = idec->params_.options;
WebPDecBuffer* const output = idec->params_.output;
@@ -258,8 +263,10 @@ static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
if (status != VP8_STATUS_OK) return status;
}
if (idec->final_output_ != NULL) {
- WebPCopyDecBufferPixels(output, idec->final_output_); // do the slow-copy
+ const VP8StatusCode status = WebPCopyDecBufferPixels(
+ output, idec->final_output_); // do the slow-copy
WebPFreeDecBuffer(&idec->output_);
+ if (status != VP8_STATUS_OK) return status;
*output = *idec->final_output_;
idec->final_output_ = NULL;
}
@@ -288,7 +295,7 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
if (idec->state_ == STATE_VP8_DATA) {
// Synchronize the thread, clean-up and check for errors.
- VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
+ (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
}
idec->state_ = STATE_ERROR;
return error;
@@ -329,6 +336,7 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
if (dec == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
}
+ dec->incremental_ = 1;
idec->dec_ = dec;
dec->alpha_data_ = headers.alpha_data;
dec->alpha_data_size_ = headers.alpha_data_size;
@@ -601,8 +609,9 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
//------------------------------------------------------------------------------
// Internal constructor
-static WebPIDecoder* NewDecoder(WebPDecBuffer* const output_buffer,
- const WebPBitstreamFeatures* const features) {
+WEBP_NODISCARD static WebPIDecoder* NewDecoder(
+ WebPDecBuffer* const output_buffer,
+ const WebPBitstreamFeatures* const features) {
WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
if (idec == NULL) {
return NULL;
@@ -614,8 +623,10 @@ static WebPIDecoder* NewDecoder(WebPDecBuffer* const output_buffer,
idec->last_mb_y_ = -1;
InitMemBuffer(&idec->mem_);
- WebPInitDecBuffer(&idec->output_);
- VP8InitIo(&idec->io_);
+ if (!WebPInitDecBuffer(&idec->output_) || !VP8InitIo(&idec->io_)) {
+ WebPSafeFree(idec);
+ return NULL;
+ }
WebPResetDecParams(&idec->params_);
if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) {
@@ -674,7 +685,8 @@ void WebPIDelete(WebPIDecoder* idec) {
if (!idec->is_lossless_) {
if (idec->state_ == STATE_VP8_DATA) {
// Synchronize the thread, clean-up and check for errors.
- VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
+ // TODO(vrabaud) do we care about the return result?
+ (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
}
VP8Delete((VP8Decoder*)idec->dec_);
} else {
@@ -851,8 +863,8 @@ const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
return src;
}
-uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
- int* width, int* height, int* stride) {
+WEBP_NODISCARD uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
+ int* width, int* height, int* stride) {
const WebPDecBuffer* const src = GetOutputBuffer(idec);
if (src == NULL) return NULL;
if (src->colorspace >= MODE_YUV) {
@@ -867,10 +879,10 @@ uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
return src->u.RGBA.rgba;
}
-uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
- uint8_t** u, uint8_t** v, uint8_t** a,
- int* width, int* height,
- int* stride, int* uv_stride, int* a_stride) {
+WEBP_NODISCARD uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
+ uint8_t** u, uint8_t** v, uint8_t** a,
+ int* width, int* height, int* stride,
+ int* uv_stride, int* a_stride) {
const WebPDecBuffer* const src = GetOutputBuffer(idec);
if (src == NULL) return NULL;
if (src->colorspace < MODE_YUV) {
diff --git a/src/dec/tree_dec.c b/src/dec/tree_dec.c
index 1c6fdea2..24346059 100644
--- a/src/dec/tree_dec.c
+++ b/src/dec/tree_dec.c
@@ -12,10 +12,11 @@
// Author: Skal (pascal.massimino@gmail.com)
#include "src/dec/vp8i_dec.h"
+#include "src/dsp/cpu.h"
#include "src/utils/bit_reader_inl_utils.h"
#if !defined(USE_GENERIC_TREE)
-#if !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)
+#if !defined(__arm__) && !defined(_M_ARM) && !WEBP_AARCH64
// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then.
#define USE_GENERIC_TREE 1 // ALTERNATE_CODE
#else
diff --git a/src/dec/vp8_dec.c b/src/dec/vp8_dec.c
index 2003935e..2ee89006 100644
--- a/src/dec/vp8_dec.c
+++ b/src/dec/vp8_dec.c
@@ -86,6 +86,8 @@ void VP8Delete(VP8Decoder* const dec) {
int VP8SetError(VP8Decoder* const dec,
VP8StatusCode error, const char* const msg) {
+ // VP8_STATUS_SUSPENDED is only meaningful in incremental decoding.
+ assert(dec->incremental_ || error != VP8_STATUS_SUSPENDED);
// The oldest error reported takes precedence over the new one.
if (dec->status_ == VP8_STATUS_OK) {
dec->status_ = error;
@@ -190,12 +192,12 @@ static int ParseSegmentHeader(VP8BitReader* br,
}
// Paragraph 9.5
-// This function returns VP8_STATUS_SUSPENDED if we don't have all the
-// necessary data in 'buf'.
-// This case is not necessarily an error (for incremental decoding).
-// Still, no bitreader is ever initialized to make it possible to read
-// unavailable memory.
-// If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA
+// If we don't have all the necessary data in 'buf', this function returns
+// VP8_STATUS_SUSPENDED in incremental decoding, VP8_STATUS_NOT_ENOUGH_DATA
+// otherwise.
+// In incremental decoding, this case is not necessarily an error. Still, no
+// bitreader is ever initialized to make it possible to read unavailable memory.
+// If we don't even have the partitions' sizes, then VP8_STATUS_NOT_ENOUGH_DATA
// is returned, and this is an unrecoverable error.
// If the partitions were positioned ok, VP8_STATUS_OK is returned.
static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
@@ -225,8 +227,10 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
sz += 3;
}
VP8InitBitReader(dec->parts_ + last_part, part_start, size_left);
- return (part_start < buf_end) ? VP8_STATUS_OK :
- VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data
+ if (part_start < buf_end) return VP8_STATUS_OK;
+ return dec->incremental_
+ ? VP8_STATUS_SUSPENDED // Init is ok, but there's not enough data
+ : VP8_STATUS_NOT_ENOUGH_DATA;
}
// Paragraph 9.4
@@ -494,6 +498,8 @@ static int GetCoeffsAlt(VP8BitReader* const br,
return 16;
}
+extern VP8CPUInfo VP8GetCPUInfo;
+
WEBP_DSP_INIT_FUNC(InitGetCoeffs) {
if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
GetCoeffs = GetCoeffsAlt;
diff --git a/src/dec/vp8_dec.h b/src/dec/vp8_dec.h
index a05405df..91fe1040 100644
--- a/src/dec/vp8_dec.h
+++ b/src/dec/vp8_dec.h
@@ -15,6 +15,7 @@
#define WEBP_DEC_VP8_DEC_H_
#include "src/webp/decode.h"
+#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@@ -108,16 +109,14 @@ struct VP8Io {
};
// Internal, version-checked, entry point
-int VP8InitIoInternal(VP8Io* const, int);
+WEBP_NODISCARD int VP8InitIoInternal(VP8Io* const, int);
// Set the custom IO function pointers and user-data. The setter for IO hooks
// should be called before initiating incremental decoding. Returns true if
// WebPIDecoder object is successfully modified, false otherwise.
-int WebPISetIOHooks(WebPIDecoder* const idec,
- VP8IoPutHook put,
- VP8IoSetupHook setup,
- VP8IoTeardownHook teardown,
- void* user_data);
+WEBP_NODISCARD int WebPISetIOHooks(WebPIDecoder* const idec, VP8IoPutHook put,
+ VP8IoSetupHook setup,
+ VP8IoTeardownHook teardown, void* user_data);
// Main decoding object. This is an opaque structure.
typedef struct VP8Decoder VP8Decoder;
@@ -128,17 +127,17 @@ VP8Decoder* VP8New(void);
// Must be called to make sure 'io' is initialized properly.
// Returns false in case of version mismatch. Upon such failure, no other
// decoding function should be called (VP8Decode, VP8GetHeaders, ...)
-static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
+WEBP_NODISCARD static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
}
// Decode the VP8 frame header. Returns true if ok.
// Note: 'io->data' must be pointing to the start of the VP8 frame header.
-int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
// Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
// Returns false in case of error.
-int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
// Return current status of the decoder:
VP8StatusCode VP8Status(VP8Decoder* const dec);
diff --git a/src/dec/vp8i_dec.h b/src/dec/vp8i_dec.h
index 83791ecd..cb21d475 100644
--- a/src/dec/vp8i_dec.h
+++ b/src/dec/vp8i_dec.h
@@ -21,6 +21,7 @@
#include "src/utils/random_utils.h"
#include "src/utils/thread_utils.h"
#include "src/dsp/dsp.h"
+#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@@ -31,7 +32,7 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
-#define DEC_MIN_VERSION 3
+#define DEC_MIN_VERSION 4
#define DEC_REV_VERSION 0
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
@@ -186,6 +187,7 @@ struct VP8Decoder {
// Main data source
VP8BitReader br_;
+ int incremental_; // if true, incremental decoding is expected
// headers
VP8FrameHeader frm_hdr_;
@@ -281,7 +283,7 @@ int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec);
void VP8ParseQuant(VP8Decoder* const dec);
// in frame.c
-int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
// Call io->setup() and finish setting up scan parameters.
// After this call returns, one must always call VP8ExitCritical() with the
// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK
@@ -289,7 +291,7 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
// Must always be called in pair with VP8EnterCritical().
// Returns false in case of error.
-int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
// Return the multi-threading method to use (0=off), depending
// on options and bitstream size. Only for lossy decoding.
int VP8GetThreadMethod(const WebPDecoderOptions* const options,
@@ -299,11 +301,12 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options,
void VP8InitDithering(const WebPDecoderOptions* const options,
VP8Decoder* const dec);
// Process the last decoded row (filtering + output).
-int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
// To be called at the start of a new scanline, to initialize predictors.
void VP8InitScanline(VP8Decoder* const dec);
// Decode one macroblock. Returns false if there is not enough data.
-int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br);
+WEBP_NODISCARD int VP8DecodeMB(VP8Decoder* const dec,
+ VP8BitReader* const token_br);
// in alpha.c
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c
index c0ea0181..11c00ea9 100644
--- a/src/dec/vp8l_dec.c
+++ b/src/dec/vp8l_dec.c
@@ -12,6 +12,7 @@
// Authors: Vikas Arora (vikaas.arora@gmail.com)
// Jyrki Alakuijala (jyrki@google.com)
+#include <assert.h>
#include <stdlib.h>
#include "src/dec/alphai_dec.h"
@@ -101,6 +102,14 @@ static const uint16_t kTableSize[12] = {
FIXED_TABLE_SIZE + 2704
};
+static int VP8LSetError(VP8LDecoder* const dec, VP8StatusCode error) {
+ // The oldest error reported takes precedence over the new one.
+ if (dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED) {
+ dec->status_ = error;
+ }
+ return 0;
+}
+
static int DecodeImageStream(int xsize, int ysize,
int is_level0,
VP8LDecoder* const dec,
@@ -253,11 +262,11 @@ static int ReadHuffmanCodeLengths(
int symbol;
int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH;
- HuffmanCode table[1 << LENGTHS_TABLE_BITS];
+ HuffmanTables tables;
- if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
- code_length_code_lengths,
- NUM_CODE_LENGTH_CODES)) {
+ if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
+ !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
+ code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
goto End;
}
@@ -277,7 +286,7 @@ static int ReadHuffmanCodeLengths(
int code_len;
if (max_symbol-- == 0) break;
VP8LFillBitWindow(br);
- p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
+ p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
VP8LSetBitPos(br, br->bit_pos_ + p->bits);
code_len = p->value;
if (code_len < kCodeLengthLiterals) {
@@ -300,14 +309,16 @@ static int ReadHuffmanCodeLengths(
ok = 1;
End:
- if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LHuffmanTablesDeallocate(&tables);
+ if (!ok) return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
return ok;
}
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
// tree.
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
- int* const code_lengths, HuffmanCode* const table) {
+ int* const code_lengths,
+ HuffmanTables* const table) {
int ok = 0;
int size = 0;
VP8LBitReader* const br = &dec->br_;
@@ -331,10 +342,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
int i;
int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
const int num_codes = VP8LReadBits(br, 4) + 4;
- if (num_codes > NUM_CODE_LENGTH_CODES) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
- }
+ assert(num_codes <= NUM_CODE_LENGTH_CODES);
for (i = 0; i < num_codes; ++i) {
code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
@@ -349,36 +357,35 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
code_lengths, alphabet_size);
}
if (!ok || size == 0) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
}
return size;
}
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int color_cache_bits, int allow_recursion) {
- int i, j;
+ int i;
VP8LBitReader* const br = &dec->br_;
VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL;
- HuffmanCode* huffman_tables = NULL;
- HuffmanCode* huffman_table = NULL;
+ HuffmanTables* huffman_tables = &hdr->huffman_tables_;
int num_htree_groups = 1;
int num_htree_groups_max = 1;
- int max_alphabet_size = 0;
- int* code_lengths = NULL;
- const int table_size = kTableSize[color_cache_bits];
int* mapping = NULL;
int ok = 0;
+ // Check the table has been 0 initialized (through InitMetadata).
+ assert(huffman_tables->root.start == NULL);
+ assert(huffman_tables->curr_segment == NULL);
+
if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes.
const int huffman_precision = VP8LReadBits(br, 3) + 2;
const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision);
const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision);
const int huffman_pixs = huffman_xsize * huffman_ysize;
- if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
+ if (!DecodeImageStream(huffman_xsize, huffman_ysize, /*is_level0=*/0, dec,
&huffman_image)) {
goto Error;
}
@@ -402,7 +409,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
// values [0, num_htree_groups)
mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping));
if (mapping == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto Error;
}
// -1 means a value is unmapped, and therefore unused in the Huffman
@@ -421,29 +428,55 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
if (br->eos_) goto Error;
- // Find maximum alphabet size for the htree group.
- for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
- int alphabet_size = kAlphabetSize[j];
- if (j == 0 && color_cache_bits > 0) {
- alphabet_size += 1 << color_cache_bits;
- }
- if (max_alphabet_size < alphabet_size) {
- max_alphabet_size = alphabet_size;
- }
+ if (!ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups,
+ num_htree_groups_max, mapping, dec,
+ huffman_tables, &htree_groups)) {
+ goto Error;
}
+ ok = 1;
- code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
- sizeof(*code_lengths));
- huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
- sizeof(*huffman_tables));
- htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
+ // All OK. Finalize pointers.
+ hdr->huffman_image_ = huffman_image;
+ hdr->num_htree_groups_ = num_htree_groups;
+ hdr->htree_groups_ = htree_groups;
- if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ Error:
+ WebPSafeFree(mapping);
+ if (!ok) {
+ WebPSafeFree(huffman_image);
+ VP8LHuffmanTablesDeallocate(huffman_tables);
+ VP8LHtreeGroupsFree(htree_groups);
+ }
+ return ok;
+}
+
+int ReadHuffmanCodesHelper(int color_cache_bits, int num_htree_groups,
+ int num_htree_groups_max, const int* const mapping,
+ VP8LDecoder* const dec,
+ HuffmanTables* const huffman_tables,
+ HTreeGroup** const htree_groups) {
+ int i, j, ok = 0;
+ const int max_alphabet_size =
+ kAlphabetSize[0] + ((color_cache_bits > 0) ? 1 << color_cache_bits : 0);
+ const int table_size = kTableSize[color_cache_bits];
+ int* code_lengths = NULL;
+
+ if ((mapping == NULL && num_htree_groups != num_htree_groups_max) ||
+ num_htree_groups > num_htree_groups_max) {
+ goto Error;
+ }
+
+ code_lengths =
+ (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, sizeof(*code_lengths));
+ *htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
+
+ if (*htree_groups == NULL || code_lengths == NULL ||
+ !VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
+ huffman_tables)) {
+ VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto Error;
}
- huffman_table = huffman_tables;
for (i = 0; i < num_htree_groups_max; ++i) {
// If the index "i" is unused in the Huffman image, just make sure the
// coefficients are valid but do not store them.
@@ -460,7 +493,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
} else {
HTreeGroup* const htree_group =
- &htree_groups[(mapping == NULL) ? i : mapping[i]];
+ &(*htree_groups)[(mapping == NULL) ? i : mapping[i]];
HuffmanCode** const htrees = htree_group->htrees;
int size;
int total_size = 0;
@@ -468,19 +501,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int max_bits = 0;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j];
- htrees[j] = huffman_table;
if (j == 0 && color_cache_bits > 0) {
alphabet_size += (1 << color_cache_bits);
}
- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
+ size =
+ ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables);
+ htrees[j] = huffman_tables->curr_segment->curr_table;
if (size == 0) {
goto Error;
}
if (is_trivial_literal && kLiteralMap[j] == 1) {
- is_trivial_literal = (huffman_table->bits == 0);
+ is_trivial_literal = (htrees[j]->bits == 0);
}
- total_size += huffman_table->bits;
- huffman_table += size;
+ total_size += htrees[j]->bits;
+ huffman_tables->curr_segment->curr_table += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
@@ -511,19 +545,12 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
ok = 1;
- // All OK. Finalize pointers.
- hdr->huffman_image_ = huffman_image;
- hdr->num_htree_groups_ = num_htree_groups;
- hdr->htree_groups_ = htree_groups;
- hdr->huffman_tables_ = huffman_tables;
-
Error:
WebPSafeFree(code_lengths);
- WebPSafeFree(mapping);
if (!ok) {
- WebPSafeFree(huffman_image);
- WebPSafeFree(huffman_tables);
- VP8LHtreeGroupsFree(htree_groups);
+ VP8LHuffmanTablesDeallocate(huffman_tables);
+ VP8LHtreeGroupsFree(*htree_groups);
+ *htree_groups = NULL;
}
return ok;
}
@@ -547,8 +574,7 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
scaled_data_size * sizeof(*scaled_data);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
if (memory == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
}
assert(dec->rescaler_memory == NULL);
dec->rescaler_memory = memory;
@@ -1082,12 +1108,10 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
End:
br->eos_ = VP8LIsEndOfStream(br);
if (!ok || (br->eos_ && pos < end)) {
- ok = 0;
- dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
- : VP8_STATUS_BITSTREAM_ERROR;
- } else {
- dec->last_pixel_ = pos;
+ return VP8LSetError(
+ dec, br->eos_ ? VP8_STATUS_SUSPENDED : VP8_STATUS_BITSTREAM_ERROR);
}
+ dec->last_pixel_ = pos;
return ok;
}
@@ -1237,9 +1261,20 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
}
br->eos_ = VP8LIsEndOfStream(br);
- if (dec->incremental_ && br->eos_ && src < src_end) {
+ // In incremental decoding:
+ // br->eos_ && src < src_last: if 'br' reached the end of the buffer and
+ // 'src_last' has not been reached yet, there is not enough data. 'dec' has to
+ // be reset until there is more data.
+ // !br->eos_ && src < src_last: this cannot happen as either the buffer is
+ // fully read, either enough has been read to reach 'src_last'.
+ // src >= src_last: 'src_last' is reached, all is fine. 'src' can actually go
+ // beyond 'src_last' in case the image is cropped and an LZ77 goes further.
+ // The buffer might have been enough or there is some left. 'br->eos_' does
+ // not matter.
+ assert(!dec->incremental_ || (br->eos_ && src < src_last) || src >= src_last);
+ if (dec->incremental_ && br->eos_ && src < src_last) {
RestoreState(dec);
- } else if (!br->eos_) {
+ } else if ((dec->incremental_ && src >= src_last) || !br->eos_) {
// Process the remaining rows corresponding to last row-block.
if (process_func != NULL) {
process_func(dec, row > last_row ? last_row : row);
@@ -1254,8 +1289,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
return 1;
Error:
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
}
// -----------------------------------------------------------------------------
@@ -1322,7 +1356,7 @@ static int ReadTransform(int* const xsize, int const* ysize,
transform->bits_),
VP8LSubSampleSize(transform->ysize_,
transform->bits_),
- 0, dec, &transform->data_);
+ /*is_level0=*/0, dec, &transform->data_);
break;
case COLOR_INDEXING_TRANSFORM: {
const int num_colors = VP8LReadBits(br, 8) + 1;
@@ -1332,8 +1366,11 @@ static int ReadTransform(int* const xsize, int const* ysize,
: 3;
*xsize = VP8LSubSampleSize(transform->xsize_, bits);
transform->bits_ = bits;
- ok = DecodeImageStream(num_colors, 1, 0, dec, &transform->data_);
- ok = ok && ExpandColorMap(num_colors, transform);
+ ok = DecodeImageStream(num_colors, /*ysize=*/1, /*is_level0=*/0, dec,
+ &transform->data_);
+ if (ok && !ExpandColorMap(num_colors, transform)) {
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
+ }
break;
}
case SUBTRACT_GREEN_TRANSFORM:
@@ -1358,7 +1395,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
assert(hdr != NULL);
WebPSafeFree(hdr->huffman_image_);
- WebPSafeFree(hdr->huffman_tables_);
+ VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_);
VP8LHtreeGroupsFree(hdr->htree_groups_);
VP8LColorCacheClear(&hdr->color_cache_);
VP8LColorCacheClear(&hdr->saved_color_cache_);
@@ -1439,7 +1476,7 @@ static int DecodeImageStream(int xsize, int ysize,
color_cache_bits = VP8LReadBits(br, 4);
ok = (color_cache_bits >= 1 && color_cache_bits <= MAX_CACHE_BITS);
if (!ok) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto End;
}
}
@@ -1448,7 +1485,7 @@ static int DecodeImageStream(int xsize, int ysize,
ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize,
color_cache_bits, is_level0);
if (!ok) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto End;
}
@@ -1456,8 +1493,7 @@ static int DecodeImageStream(int xsize, int ysize,
if (color_cache_bits > 0) {
hdr->color_cache_size_ = 1 << color_cache_bits;
if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- ok = 0;
+ ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto End;
}
} else {
@@ -1474,8 +1510,7 @@ static int DecodeImageStream(int xsize, int ysize,
const uint64_t total_size = (uint64_t)transform_xsize * transform_ysize;
data = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*data));
if (data == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- ok = 0;
+ ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto End;
}
}
@@ -1520,8 +1555,7 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
if (dec->pixels_ == NULL) {
dec->argb_cache_ = NULL; // for soundness
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
}
dec->argb_cache_ = dec->pixels_ + num_pixels + cache_top_pixels;
return 1;
@@ -1532,8 +1566,7 @@ static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
dec->argb_cache_ = NULL; // for soundness
dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
if (dec->pixels_ == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
}
return 1;
}
@@ -1588,7 +1621,8 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
dec->status_ = VP8_STATUS_OK;
VP8LInitBitReader(&dec->br_, data, data_size);
- if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, 1, dec, NULL)) {
+ if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, /*is_level0=*/1,
+ dec, /*decoded_data=*/NULL)) {
goto Err;
}
@@ -1643,22 +1677,24 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
if (dec == NULL) return 0;
if (io == NULL) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
- return 0;
+ return VP8LSetError(dec, VP8_STATUS_INVALID_PARAM);
}
dec->io_ = io;
dec->status_ = VP8_STATUS_OK;
VP8LInitBitReader(&dec->br_, io->data, io->data_size);
if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
goto Error;
}
dec->state_ = READ_DIM;
io->width = width;
io->height = height;
- if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error;
+ if (!DecodeImageStream(width, height, /*is_level0=*/1, dec,
+ /*decoded_data=*/NULL)) {
+ goto Error;
+ }
return 1;
Error:
@@ -1673,7 +1709,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (dec == NULL) return 0;
- assert(dec->hdr_.huffman_tables_ != NULL);
+ assert(dec->hdr_.huffman_tables_.root.start != NULL);
assert(dec->hdr_.htree_groups_ != NULL);
assert(dec->hdr_.num_htree_groups_ > 0);
@@ -1688,7 +1724,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
assert(dec->output_ != NULL);
if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
+ VP8LSetError(dec, VP8_STATUS_INVALID_PARAM);
goto Err;
}
@@ -1698,7 +1734,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
#else
if (io->use_scaling) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
+ VP8LSetError(dec, VP8_STATUS_INVALID_PARAM);
goto Err;
}
#endif
@@ -1716,7 +1752,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
dec->hdr_.saved_color_cache_.colors_ == NULL) {
if (!VP8LColorCacheInit(&dec->hdr_.saved_color_cache_,
dec->hdr_.color_cache_.hash_bits_)) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
goto Err;
}
}
diff --git a/src/dec/vp8li_dec.h b/src/dec/vp8li_dec.h
index 72b2e861..9a13bcc9 100644
--- a/src/dec/vp8li_dec.h
+++ b/src/dec/vp8li_dec.h
@@ -20,6 +20,7 @@
#include "src/utils/bit_reader_utils.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/huffman_utils.h"
+#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@@ -51,7 +52,7 @@ typedef struct {
uint32_t* huffman_image_;
int num_htree_groups_;
HTreeGroup* htree_groups_;
- HuffmanCode* huffman_tables_;
+ HuffmanTables huffman_tables_;
} VP8LMetadata;
typedef struct VP8LDecoder VP8LDecoder;
@@ -99,25 +100,26 @@ struct ALPHDecoder; // Defined in dec/alphai.h.
// Decodes image header for alpha data stored using lossless compression.
// Returns false in case of error.
-int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
- const uint8_t* const data, size_t data_size);
+WEBP_NODISCARD int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
+ const uint8_t* const data,
+ size_t data_size);
// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are
// already decoded in previous call(s), it will resume decoding from where it
// was paused.
// Returns false in case of bitstream error.
-int VP8LDecodeAlphaImageStream(struct ALPHDecoder* const alph_dec,
- int last_row);
+WEBP_NODISCARD int VP8LDecodeAlphaImageStream(
+ struct ALPHDecoder* const alph_dec, int last_row);
// Allocates and initialize a new lossless decoder instance.
-VP8LDecoder* VP8LNew(void);
+WEBP_NODISCARD VP8LDecoder* VP8LNew(void);
// Decodes the image header. Returns false in case of error.
-int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
+WEBP_NODISCARD int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
// Decodes an image. It's required to decode the lossless header before calling
// this function. Returns false in case of error, with updated dec->status_.
-int VP8LDecodeImage(VP8LDecoder* const dec);
+WEBP_NODISCARD int VP8LDecodeImage(VP8LDecoder* const dec);
// Resets the decoder in its initial state, reclaiming memory.
// Preserves the dec->status_ value.
@@ -126,6 +128,18 @@ void VP8LClear(VP8LDecoder* const dec);
// Clears and deallocate a lossless decoder instance.
void VP8LDelete(VP8LDecoder* const dec);
+// Helper function for reading the different Huffman codes and storing them in
+// 'huffman_tables' and 'htree_groups'.
+// If mapping is NULL 'num_htree_groups_max' must equal 'num_htree_groups'.
+// If it is not NULL, it maps 'num_htree_groups_max' indices to the
+// 'num_htree_groups' groups. If 'num_htree_groups_max' > 'num_htree_groups',
+// some of those indices map to -1. This is used for non-balanced codes to
+// limit memory usage.
+WEBP_NODISCARD int ReadHuffmanCodesHelper(
+ int color_cache_bits, int num_htree_groups, int num_htree_groups_max,
+ const int* const mapping, VP8LDecoder* const dec,
+ HuffmanTables* const huffman_tables, HTreeGroup** const htree_groups);
+
//------------------------------------------------------------------------------
#ifdef __cplusplus
diff --git a/src/dec/webp_dec.c b/src/dec/webp_dec.c
index 3f4f7bb6..49ef205c 100644
--- a/src/dec/webp_dec.c
+++ b/src/dec/webp_dec.c
@@ -13,11 +13,14 @@
#include <stdlib.h>
+#include "src/dec/vp8_dec.h"
#include "src/dec/vp8i_dec.h"
#include "src/dec/vp8li_dec.h"
#include "src/dec/webpi_dec.h"
#include "src/utils/utils.h"
#include "src/webp/mux_types.h" // ALPHA_FLAG
+#include "src/webp/decode.h"
+#include "src/webp/types.h"
//------------------------------------------------------------------------------
// RIFF layout is:
@@ -444,8 +447,9 @@ void WebPResetDecParams(WebPDecParams* const params) {
// "Into" decoding variants
// Main flow
-static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
- WebPDecParams* const params) {
+WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
+ size_t data_size,
+ WebPDecParams* const params) {
VP8StatusCode status;
VP8Io io;
WebPHeaderStructure headers;
@@ -459,7 +463,9 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
}
assert(params != NULL);
- VP8InitIo(&io);
+ if (!VP8InitIo(&io)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
io.data = headers.data + headers.offset;
io.data_size = headers.data_size - headers.offset;
WebPInitCustomIo(params, &io); // Plug the I/O functions.
@@ -523,17 +529,16 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
}
// Helpers
-static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
- const uint8_t* const data,
- size_t data_size,
- uint8_t* const rgba,
- int stride, size_t size) {
+WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
+ const uint8_t* const data,
+ size_t data_size,
+ uint8_t* const rgba,
+ int stride, size_t size) {
WebPDecParams params;
WebPDecBuffer buf;
- if (rgba == NULL) {
+ if (rgba == NULL || !WebPInitDecBuffer(&buf)) {
return NULL;
}
- WebPInitDecBuffer(&buf);
WebPResetDecParams(&params);
params.output = &buf;
buf.colorspace = colorspace;
@@ -578,8 +583,7 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
uint8_t* v, size_t v_size, int v_stride) {
WebPDecParams params;
WebPDecBuffer output;
- if (luma == NULL) return NULL;
- WebPInitDecBuffer(&output);
+ if (luma == NULL || !WebPInitDecBuffer(&output)) return NULL;
WebPResetDecParams(&params);
params.output = &output;
output.colorspace = MODE_YUV;
@@ -601,13 +605,17 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
//------------------------------------------------------------------------------
-static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data,
- size_t data_size, int* const width, int* const height,
- WebPDecBuffer* const keep_info) {
+WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode,
+ const uint8_t* const data,
+ size_t data_size, int* const width,
+ int* const height,
+ WebPDecBuffer* const keep_info) {
WebPDecParams params;
WebPDecBuffer output;
- WebPInitDecBuffer(&output);
+ if (!WebPInitDecBuffer(&output)) {
+ return NULL;
+ }
WebPResetDecParams(&params);
params.output = &output;
output.colorspace = mode;
@@ -658,19 +666,26 @@ uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
int* width, int* height, uint8_t** u, uint8_t** v,
int* stride, int* uv_stride) {
- WebPDecBuffer output; // only to preserve the side-infos
- uint8_t* const out = Decode(MODE_YUV, data, data_size,
- width, height, &output);
-
- if (out != NULL) {
- const WebPYUVABuffer* const buf = &output.u.YUVA;
- *u = buf->u;
- *v = buf->v;
- *stride = buf->y_stride;
- *uv_stride = buf->u_stride;
- assert(buf->u_stride == buf->v_stride);
- }
- return out;
+ // data, width and height are checked by Decode().
+ if (u == NULL || v == NULL || stride == NULL || uv_stride == NULL) {
+ return NULL;
+ }
+
+ {
+ WebPDecBuffer output; // only to preserve the side-infos
+ uint8_t* const out = Decode(MODE_YUV, data, data_size,
+ width, height, &output);
+
+ if (out != NULL) {
+ const WebPYUVABuffer* const buf = &output.u.YUVA;
+ *u = buf->u;
+ *v = buf->v;
+ *stride = buf->y_stride;
+ *uv_stride = buf->u_stride;
+ assert(buf->u_stride == buf->v_stride);
+ }
+ return out;
+ }
}
static void DefaultFeatures(WebPBitstreamFeatures* const features) {
@@ -726,7 +741,9 @@ int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
}
memset(config, 0, sizeof(*config));
DefaultFeatures(&config->input);
- WebPInitDecBuffer(&config->output);
+ if (!WebPInitDecBuffer(&config->output)) {
+ return 0;
+ }
return 1;
}
@@ -765,7 +782,9 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
if (WebPAvoidSlowMemory(params.output, &config->input)) {
// decoding to slow memory: use a temporary in-mem buffer to decode into.
WebPDecBuffer in_mem_buffer;
- WebPInitDecBuffer(&in_mem_buffer);
+ if (!WebPInitDecBuffer(&in_mem_buffer)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
in_mem_buffer.colorspace = config->output.colorspace;
in_mem_buffer.width = config->input.width;
in_mem_buffer.height = config->input.height;
diff --git a/src/dec/webpi_dec.h b/src/dec/webpi_dec.h
index 3b97388c..77bf5264 100644
--- a/src/dec/webpi_dec.h
+++ b/src/dec/webpi_dec.h
@@ -20,6 +20,7 @@ extern "C" {
#include "src/utils/rescaler_utils.h"
#include "src/dec/vp8_dec.h"
+#include "src/webp/decode.h"
//------------------------------------------------------------------------------
// WebPDecParams: Decoding output parameters. Transient internal object.
@@ -87,8 +88,9 @@ void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
// Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers
// to the *compressed* format, not the output one.
-int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
- VP8Io* const io, WEBP_CSP_MODE src_colorspace);
+WEBP_NODISCARD int WebPIoInitFromOptions(
+ const WebPDecoderOptions* const options, VP8Io* const io,
+ WEBP_CSP_MODE src_colorspace);
//------------------------------------------------------------------------------
// Internal functions regarding WebPDecBuffer memory (in buffer.c).
diff --git a/src/demux/Makefile.am b/src/demux/Makefile.am
index d7392b3e..9ecff146 100644
--- a/src/demux/Makefile.am
+++ b/src/demux/Makefile.am
@@ -13,6 +13,6 @@ noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h
libwebpdemux_la_LIBADD = ../libwebp.la
-libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:12:0
+libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:15:0
libwebpdemuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpdemux.pc
diff --git a/src/demux/anim_decode.c b/src/demux/anim_decode.c
index e077ffb5..27f0e2b0 100644
--- a/src/demux/anim_decode.c
+++ b/src/demux/anim_decode.c
@@ -20,6 +20,7 @@
#include "src/utils/utils.h"
#include "src/webp/decode.h"
#include "src/webp/demux.h"
+#include "src/webp/types.h"
#define NUM_CHANNELS 4
@@ -68,8 +69,9 @@ int WebPAnimDecoderOptionsInitInternal(WebPAnimDecoderOptions* dec_options,
return 1;
}
-static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options,
- WebPAnimDecoder* const dec) {
+WEBP_NODISCARD static int ApplyDecoderOptions(
+ const WebPAnimDecoderOptions* const dec_options,
+ WebPAnimDecoder* const dec) {
WEBP_CSP_MODE mode;
WebPDecoderConfig* config = &dec->config_;
assert(dec_options != NULL);
@@ -82,7 +84,9 @@ static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options,
dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA)
? &BlendPixelRowNonPremult
: &BlendPixelRowPremult;
- WebPInitDecoderConfig(config);
+ if (!WebPInitDecoderConfig(config)) {
+ return 0;
+ }
config->output.colorspace = mode;
config->output.is_external_memory = 1;
config->options.use_threads = dec_options->use_threads;
@@ -157,8 +161,8 @@ static int IsFullFrame(int width, int height, int canvas_width,
}
// Clear the canvas to transparent.
-static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
- uint32_t canvas_height) {
+WEBP_NODISCARD static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
+ uint32_t canvas_height) {
const uint64_t size =
(uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
if (!CheckSizeOverflow(size)) return 0;
@@ -179,8 +183,8 @@ static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
}
// Copy width * height pixels from 'src' to 'dst'.
-static int CopyCanvas(const uint8_t* src, uint8_t* dst,
- uint32_t width, uint32_t height) {
+WEBP_NODISCARD static int CopyCanvas(const uint8_t* src, uint8_t* dst,
+ uint32_t width, uint32_t height) {
const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
if (!CheckSizeOverflow(size)) return 0;
assert(src != NULL && dst != NULL);
@@ -424,7 +428,9 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
WebPDemuxReleaseIterator(&dec->prev_iter_);
dec->prev_iter_ = iter;
dec->prev_frame_was_keyframe_ = is_key_frame;
- CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height);
+ if (!CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height)) {
+ goto Error;
+ }
if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS,
dec->prev_iter_.x_offset, dec->prev_iter_.y_offset,
diff --git a/src/demux/demux.c b/src/demux/demux.c
index 324e5eb9..d01c6a74 100644
--- a/src/demux/demux.c
+++ b/src/demux/demux.c
@@ -24,7 +24,7 @@
#include "src/webp/format_constants.h"
#define DMUX_MAJ_VERSION 1
-#define DMUX_MIN_VERSION 3
+#define DMUX_MIN_VERSION 4
#define DMUX_REV_VERSION 0
typedef struct {
diff --git a/src/demux/libwebpdemux.rc b/src/demux/libwebpdemux.rc
index 18353e59..bc57c408 100644
--- a/src/demux/libwebpdemux.rc
+++ b/src/demux/libwebpdemux.rc
@@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,3,0
- PRODUCTVERSION 1,0,3,0
+ FILEVERSION 1,0,4,0
+ PRODUCTVERSION 1,0,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -24,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebpdemux DLL"
- VALUE "FileVersion", "1.3.0"
+ VALUE "FileVersion", "1.4.0"
VALUE "InternalName", "libwebpdemux.dll"
- VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "LegalCopyright", "Copyright (C) 2024"
VALUE "OriginalFilename", "libwebpdemux.dll"
VALUE "ProductName", "WebP Image Demuxer"
- VALUE "ProductVersion", "1.3.0"
+ VALUE "ProductVersion", "1.4.0"
END
END
BLOCK "VarFileInfo"
diff --git a/src/dsp/alpha_processing.c b/src/dsp/alpha_processing.c
index 1892929a..1d152f24 100644
--- a/src/dsp/alpha_processing.c
+++ b/src/dsp/alpha_processing.c
@@ -425,6 +425,7 @@ void (*WebPAlphaReplace)(uint32_t* src, int length, uint32_t color);
//------------------------------------------------------------------------------
// Init function
+extern VP8CPUInfo VP8GetCPUInfo;
extern void WebPInitAlphaProcessingMIPSdspR2(void);
extern void WebPInitAlphaProcessingSSE2(void);
extern void WebPInitAlphaProcessingSSE41(void);
diff --git a/src/dsp/alpha_processing_sse2.c b/src/dsp/alpha_processing_sse2.c
index f0843d0f..aa0cc284 100644
--- a/src/dsp/alpha_processing_sse2.c
+++ b/src/dsp/alpha_processing_sse2.c
@@ -144,6 +144,46 @@ static int ExtractAlpha_SSE2(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
return (alpha_and == 0xff);
}
+static void ExtractGreen_SSE2(const uint32_t* WEBP_RESTRICT argb,
+ uint8_t* WEBP_RESTRICT alpha, int size) {
+ int i;
+ const __m128i mask = _mm_set1_epi32(0xff);
+ const __m128i* src = (const __m128i*)argb;
+
+ for (i = 0; i + 16 <= size; i += 16, src += 4) {
+ const __m128i a0 = _mm_loadu_si128(src + 0);
+ const __m128i a1 = _mm_loadu_si128(src + 1);
+ const __m128i a2 = _mm_loadu_si128(src + 2);
+ const __m128i a3 = _mm_loadu_si128(src + 3);
+ const __m128i b0 = _mm_srli_epi32(a0, 8);
+ const __m128i b1 = _mm_srli_epi32(a1, 8);
+ const __m128i b2 = _mm_srli_epi32(a2, 8);
+ const __m128i b3 = _mm_srli_epi32(a3, 8);
+ const __m128i c0 = _mm_and_si128(b0, mask);
+ const __m128i c1 = _mm_and_si128(b1, mask);
+ const __m128i c2 = _mm_and_si128(b2, mask);
+ const __m128i c3 = _mm_and_si128(b3, mask);
+ const __m128i d0 = _mm_packs_epi32(c0, c1);
+ const __m128i d1 = _mm_packs_epi32(c2, c3);
+ const __m128i e = _mm_packus_epi16(d0, d1);
+ // store
+ _mm_storeu_si128((__m128i*)&alpha[i], e);
+ }
+ if (i + 8 <= size) {
+ const __m128i a0 = _mm_loadu_si128(src + 0);
+ const __m128i a1 = _mm_loadu_si128(src + 1);
+ const __m128i b0 = _mm_srli_epi32(a0, 8);
+ const __m128i b1 = _mm_srli_epi32(a1, 8);
+ const __m128i c0 = _mm_and_si128(b0, mask);
+ const __m128i c1 = _mm_and_si128(b1, mask);
+ const __m128i d = _mm_packs_epi32(c0, c1);
+ const __m128i e = _mm_packus_epi16(d, d);
+ _mm_storel_epi64((__m128i*)&alpha[i], e);
+ i += 8;
+ }
+ for (; i < size; ++i) alpha[i] = argb[i] >> 8;
+}
+
//------------------------------------------------------------------------------
// Non-dither premultiplied modes
@@ -354,6 +394,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) {
WebPDispatchAlpha = DispatchAlpha_SSE2;
WebPDispatchAlphaToGreen = DispatchAlphaToGreen_SSE2;
WebPExtractAlpha = ExtractAlpha_SSE2;
+ WebPExtractGreen = ExtractGreen_SSE2;
WebPHasAlpha8b = HasAlpha8b_SSE2;
WebPHasAlpha32b = HasAlpha32b_SSE2;
diff --git a/src/dsp/cost.c b/src/dsp/cost.c
index 460ec4f2..73d21401 100644
--- a/src/dsp/cost.c
+++ b/src/dsp/cost.c
@@ -374,6 +374,7 @@ static void SetResidualCoeffs_C(const int16_t* const coeffs,
VP8GetResidualCostFunc VP8GetResidualCost;
VP8SetResidualCoeffsFunc VP8SetResidualCoeffs;
+extern VP8CPUInfo VP8GetCPUInfo;
extern void VP8EncDspCostInitMIPS32(void);
extern void VP8EncDspCostInitMIPSdspR2(void);
extern void VP8EncDspCostInitSSE2(void);
diff --git a/src/dsp/cost_neon.c b/src/dsp/cost_neon.c
index 8cc8ce58..6582669c 100644
--- a/src/dsp/cost_neon.c
+++ b/src/dsp/cost_neon.c
@@ -29,7 +29,7 @@ static void SetResidualCoeffs_NEON(const int16_t* const coeffs,
const uint8x16_t eob = vcombine_u8(vqmovn_u16(eob_0), vqmovn_u16(eob_1));
const uint8x16_t masked = vandq_u8(eob, vld1q_u8(position));
-#ifdef __aarch64__
+#if WEBP_AARCH64
res->last = vmaxvq_u8(masked) - 1;
#else
const uint8x8_t eob_8x8 = vmax_u8(vget_low_u8(masked), vget_high_u8(masked));
@@ -43,7 +43,7 @@ static void SetResidualCoeffs_NEON(const int16_t* const coeffs,
vst1_lane_s32(&res->last, vreinterpret_s32_u32(eob_32x2), 0);
--res->last;
-#endif // __aarch64__
+#endif // WEBP_AARCH64
res->coeffs = coeffs;
}
diff --git a/src/dsp/cpu.c b/src/dsp/cpu.c
index 62de73f7..8ba8f683 100644
--- a/src/dsp/cpu.c
+++ b/src/dsp/cpu.c
@@ -36,18 +36,6 @@ static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type), "c"(0));
}
-#elif defined(__x86_64__) && \
- (defined(__code_model_medium__) || defined(__code_model_large__)) && \
- defined(__PIC__)
-static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
- __asm__ volatile (
- "xchg{q}\t{%%rbx}, %q1\n"
- "cpuid\n"
- "xchg{q}\t{%%rbx}, %q1\n"
- : "=a"(cpu_info[0]), "=&r"(cpu_info[1]), "=c"(cpu_info[2]),
- "=d"(cpu_info[3])
- : "a"(info_type), "c"(0));
-}
#elif defined(__i386__) || defined(__x86_64__)
static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile (
@@ -173,6 +161,7 @@ static int x86CPUInfo(CPUFeature feature) {
}
return 0;
}
+WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
VP8CPUInfo VP8GetCPUInfo = x86CPUInfo;
#elif defined(WEBP_ANDROID_NEON) // NB: needs to be before generic NEON test.
static int AndroidCPUInfo(CPUFeature feature) {
@@ -184,6 +173,7 @@ static int AndroidCPUInfo(CPUFeature feature) {
}
return 0;
}
+WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo;
#elif defined(EMSCRIPTEN) // also needs to be before generic NEON test
// Use compile flags as an indicator of SIMD support instead of a runtime check.
@@ -208,6 +198,7 @@ static int wasmCPUInfo(CPUFeature feature) {
}
return 0;
}
+WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
VP8CPUInfo VP8GetCPUInfo = wasmCPUInfo;
#elif defined(WEBP_HAVE_NEON)
// In most cases this function doesn't check for NEON support (it's assumed by
@@ -236,6 +227,7 @@ static int armCPUInfo(CPUFeature feature) {
return 1;
#endif
}
+WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
VP8CPUInfo VP8GetCPUInfo = armCPUInfo;
#elif defined(WEBP_USE_MIPS32) || defined(WEBP_USE_MIPS_DSP_R2) || \
defined(WEBP_USE_MSA)
@@ -247,7 +239,9 @@ static int mipsCPUInfo(CPUFeature feature) {
}
}
+WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
VP8CPUInfo VP8GetCPUInfo = mipsCPUInfo;
#else
+WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
VP8CPUInfo VP8GetCPUInfo = NULL;
#endif
diff --git a/src/dsp/cpu.h b/src/dsp/cpu.h
index be80727c..c86540f2 100644
--- a/src/dsp/cpu.h
+++ b/src/dsp/cpu.h
@@ -43,6 +43,9 @@
#define __has_builtin(x) 0
#endif
+//------------------------------------------------------------------------------
+// x86 defines.
+
#if !defined(HAVE_CONFIG_H)
#if defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
@@ -80,6 +83,9 @@
#undef WEBP_MSC_SSE41
#undef WEBP_MSC_SSE2
+//------------------------------------------------------------------------------
+// Arm defines.
+
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
// inline assembly would need to be modified for use with Native Client.
#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
@@ -98,16 +104,26 @@
// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in
// arm_neon.h. Compile errors were seen with Visual Studio 2019 16.4 with
// vtbl4_u8(); a fix was made in 16.6.
-#if defined(_MSC_VER) && ((_MSC_VER >= 1700 && defined(_M_ARM)) || \
- (_MSC_VER >= 1926 && defined(_M_ARM64)))
+#if defined(_MSC_VER) && \
+ ((_MSC_VER >= 1700 && defined(_M_ARM)) || \
+ (_MSC_VER >= 1926 && (defined(_M_ARM64) || defined(_M_ARM64EC))))
#define WEBP_USE_NEON
#define WEBP_USE_INTRINSICS
#endif
+#if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
+#define WEBP_AARCH64 1
+#else
+#define WEBP_AARCH64 0
+#endif
+
#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
#define WEBP_HAVE_NEON
#endif
+//------------------------------------------------------------------------------
+// MIPS defines.
+
#if defined(__mips__) && !defined(__mips64) && defined(__mips_isa_rev) && \
(__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
#define WEBP_USE_MIPS32
@@ -123,6 +139,8 @@
#define WEBP_USE_MSA
#endif
+//------------------------------------------------------------------------------
+
#ifndef WEBP_DSP_OMIT_C_CODE
#define WEBP_DSP_OMIT_C_CODE 1
#endif
@@ -133,13 +151,14 @@
#define WEBP_NEON_OMIT_C_CODE 0
#endif
-#if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || \
- defined(__aarch64__))
+#if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || WEBP_AARCH64)
#define WEBP_NEON_WORK_AROUND_GCC 1
#else
#define WEBP_NEON_WORK_AROUND_GCC 0
#endif
+//------------------------------------------------------------------------------
+
// This macro prevents thread_sanitizer from reporting known concurrent writes.
#define WEBP_TSAN_IGNORE_FUNCTION
#if defined(__has_feature)
@@ -241,16 +260,7 @@ typedef enum {
kMSA
} CPUFeature;
-#ifdef __cplusplus
-extern "C" {
-#endif
-
// returns true if the CPU supports the feature.
typedef int (*VP8CPUInfo)(CPUFeature feature);
-WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
#endif // WEBP_DSP_CPU_H_
diff --git a/src/dsp/dec.c b/src/dsp/dec.c
index 537c7012..451d649d 100644
--- a/src/dsp/dec.c
+++ b/src/dsp/dec.c
@@ -37,9 +37,6 @@ static WEBP_INLINE uint8_t clip_8b(int v) {
STORE(3, y, DC - (d)); \
} while (0)
-#define MUL1(a) ((((a) * 20091) >> 16) + (a))
-#define MUL2(a) (((a) * 35468) >> 16)
-
#if !WEBP_NEON_OMIT_C_CODE
static void TransformOne_C(const int16_t* in, uint8_t* dst) {
int C[4 * 4], *tmp;
@@ -48,8 +45,10 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) {
for (i = 0; i < 4; ++i) { // vertical pass
const int a = in[0] + in[8]; // [-4096, 4094]
const int b = in[0] - in[8]; // [-4095, 4095]
- const int c = MUL2(in[4]) - MUL1(in[12]); // [-3783, 3783]
- const int d = MUL1(in[4]) + MUL2(in[12]); // [-3785, 3781]
+ const int c = WEBP_TRANSFORM_AC3_MUL2(in[4]) -
+ WEBP_TRANSFORM_AC3_MUL1(in[12]); // [-3783, 3783]
+ const int d = WEBP_TRANSFORM_AC3_MUL1(in[4]) +
+ WEBP_TRANSFORM_AC3_MUL2(in[12]); // [-3785, 3781]
tmp[0] = a + d; // [-7881, 7875]
tmp[1] = b + c; // [-7878, 7878]
tmp[2] = b - c; // [-7878, 7878]
@@ -69,8 +68,10 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) {
const int dc = tmp[0] + 4;
const int a = dc + tmp[8];
const int b = dc - tmp[8];
- const int c = MUL2(tmp[4]) - MUL1(tmp[12]);
- const int d = MUL1(tmp[4]) + MUL2(tmp[12]);
+ const int c =
+ WEBP_TRANSFORM_AC3_MUL2(tmp[4]) - WEBP_TRANSFORM_AC3_MUL1(tmp[12]);
+ const int d =
+ WEBP_TRANSFORM_AC3_MUL1(tmp[4]) + WEBP_TRANSFORM_AC3_MUL2(tmp[12]);
STORE(0, 0, a + d);
STORE(1, 0, b + c);
STORE(2, 0, b - c);
@@ -83,17 +84,15 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) {
// Simplified transform when only in[0], in[1] and in[4] are non-zero
static void TransformAC3_C(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4;
- const int c4 = MUL2(in[4]);
- const int d4 = MUL1(in[4]);
- const int c1 = MUL2(in[1]);
- const int d1 = MUL1(in[1]);
+ const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]);
+ const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]);
+ const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
STORE2(0, a + d4, d1, c1);
STORE2(1, a + c4, d1, c1);
STORE2(2, a - c4, d1, c1);
STORE2(3, a - d4, d1, c1);
}
-#undef MUL1
-#undef MUL2
#undef STORE2
static void TransformTwo_C(const int16_t* in, uint8_t* dst, int do_two) {
@@ -734,6 +733,7 @@ VP8SimpleFilterFunc VP8SimpleHFilter16i;
void (*VP8DitherCombine8x8)(const uint8_t* dither, uint8_t* dst,
int dst_stride);
+extern VP8CPUInfo VP8GetCPUInfo;
extern void VP8DspInitSSE2(void);
extern void VP8DspInitSSE41(void);
extern void VP8DspInitNEON(void);
diff --git a/src/dsp/dec_mips32.c b/src/dsp/dec_mips32.c
index e4e70966..f0e7de4a 100644
--- a/src/dsp/dec_mips32.c
+++ b/src/dsp/dec_mips32.c
@@ -18,8 +18,8 @@
#include "src/dsp/mips_macro.h"
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
+static const int kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int kC2 = WEBP_TRANSFORM_AC3_C2;
static WEBP_INLINE int abs_mips32(int x) {
const int sign = x >> 31;
@@ -219,7 +219,7 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
int temp0, temp1, temp2, temp3, temp4;
int temp5, temp6, temp7, temp8, temp9;
int temp10, temp11, temp12, temp13, temp14;
- int temp15, temp16, temp17, temp18;
+ int temp15, temp16, temp17, temp18, temp19;
int16_t* p_in = (int16_t*)in;
// loops unrolled and merged to avoid usage of tmp buffer
@@ -233,16 +233,14 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
"addu %[temp16], %[temp0], %[temp8] \n\t"
"subu %[temp0], %[temp0], %[temp8] \n\t"
"mul %[temp8], %[temp4], %[kC2] \n\t"
- "mul %[temp17], %[temp12], %[kC1] \n\t"
- "mul %[temp4], %[temp4], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp12)
+ MUL_SHIFT_C1_IO(temp4, temp19)
"mul %[temp12], %[temp12], %[kC2] \n\t"
"lh %[temp1], 2(%[in]) \n\t"
"lh %[temp5], 10(%[in]) \n\t"
"lh %[temp9], 18(%[in]) \n\t"
"lh %[temp13], 26(%[in]) \n\t"
"sra %[temp8], %[temp8], 16 \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
- "sra %[temp4], %[temp4], 16 \n\t"
"sra %[temp12], %[temp12], 16 \n\t"
"lh %[temp2], 4(%[in]) \n\t"
"lh %[temp6], 12(%[in]) \n\t"
@@ -261,49 +259,43 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
"addu %[temp12], %[temp0], %[temp17] \n\t"
"subu %[temp0], %[temp0], %[temp17] \n\t"
"mul %[temp9], %[temp5], %[kC2] \n\t"
- "mul %[temp17], %[temp13], %[kC1] \n\t"
- "mul %[temp5], %[temp5], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp13)
+ MUL_SHIFT_C1_IO(temp5, temp19)
"mul %[temp13], %[temp13], %[kC2] \n\t"
"sra %[temp9], %[temp9], 16 \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
"subu %[temp17], %[temp9], %[temp17] \n\t"
- "sra %[temp5], %[temp5], 16 \n\t"
"sra %[temp13], %[temp13], 16 \n\t"
"addu %[temp5], %[temp5], %[temp13] \n\t"
"addu %[temp13], %[temp1], %[temp17] \n\t"
"subu %[temp1], %[temp1], %[temp17] \n\t"
- "mul %[temp17], %[temp14], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp14)
"mul %[temp14], %[temp14], %[kC2] \n\t"
"addu %[temp9], %[temp16], %[temp5] \n\t"
"subu %[temp5], %[temp16], %[temp5] \n\t"
"addu %[temp16], %[temp2], %[temp10] \n\t"
"subu %[temp2], %[temp2], %[temp10] \n\t"
"mul %[temp10], %[temp6], %[kC2] \n\t"
- "mul %[temp6], %[temp6], %[kC1] \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
+ MUL_SHIFT_C1_IO(temp6, temp19)
"sra %[temp14], %[temp14], 16 \n\t"
"sra %[temp10], %[temp10], 16 \n\t"
- "sra %[temp6], %[temp6], 16 \n\t"
"subu %[temp17], %[temp10], %[temp17] \n\t"
"addu %[temp6], %[temp6], %[temp14] \n\t"
"addu %[temp10], %[temp16], %[temp6] \n\t"
"subu %[temp6], %[temp16], %[temp6] \n\t"
"addu %[temp14], %[temp2], %[temp17] \n\t"
"subu %[temp2], %[temp2], %[temp17] \n\t"
- "mul %[temp17], %[temp15], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp15)
"mul %[temp15], %[temp15], %[kC2] \n\t"
"addu %[temp16], %[temp3], %[temp11] \n\t"
"subu %[temp3], %[temp3], %[temp11] \n\t"
"mul %[temp11], %[temp7], %[kC2] \n\t"
- "mul %[temp7], %[temp7], %[kC1] \n\t"
+ MUL_SHIFT_C1_IO(temp7, temp19)
"addiu %[temp8], %[temp8], 4 \n\t"
"addiu %[temp12], %[temp12], 4 \n\t"
"addiu %[temp0], %[temp0], 4 \n\t"
"addiu %[temp4], %[temp4], 4 \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
"sra %[temp15], %[temp15], 16 \n\t"
"sra %[temp11], %[temp11], 16 \n\t"
- "sra %[temp7], %[temp7], 16 \n\t"
"subu %[temp17], %[temp11], %[temp17] \n\t"
"addu %[temp7], %[temp7], %[temp15] \n\t"
"addu %[temp15], %[temp3], %[temp17] \n\t"
@@ -313,48 +305,40 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
"addu %[temp16], %[temp8], %[temp10] \n\t"
"subu %[temp8], %[temp8], %[temp10] \n\t"
"mul %[temp10], %[temp9], %[kC2] \n\t"
- "mul %[temp17], %[temp11], %[kC1] \n\t"
- "mul %[temp9], %[temp9], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp17, temp11)
+ MUL_SHIFT_C1_IO(temp9, temp19)
"mul %[temp11], %[temp11], %[kC2] \n\t"
"sra %[temp10], %[temp10], 16 \n\t"
- "sra %[temp17], %[temp17], 16 \n\t"
- "sra %[temp9], %[temp9], 16 \n\t"
"sra %[temp11], %[temp11], 16 \n\t"
"subu %[temp17], %[temp10], %[temp17] \n\t"
"addu %[temp11], %[temp9], %[temp11] \n\t"
"addu %[temp10], %[temp12], %[temp14] \n\t"
"subu %[temp12], %[temp12], %[temp14] \n\t"
"mul %[temp14], %[temp13], %[kC2] \n\t"
- "mul %[temp9], %[temp15], %[kC1] \n\t"
- "mul %[temp13], %[temp13], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp9, temp15)
+ MUL_SHIFT_C1_IO(temp13, temp19)
"mul %[temp15], %[temp15], %[kC2] \n\t"
"sra %[temp14], %[temp14], 16 \n\t"
- "sra %[temp9], %[temp9], 16 \n\t"
- "sra %[temp13], %[temp13], 16 \n\t"
"sra %[temp15], %[temp15], 16 \n\t"
"subu %[temp9], %[temp14], %[temp9] \n\t"
"addu %[temp15], %[temp13], %[temp15] \n\t"
"addu %[temp14], %[temp0], %[temp2] \n\t"
"subu %[temp0], %[temp0], %[temp2] \n\t"
"mul %[temp2], %[temp1], %[kC2] \n\t"
- "mul %[temp13], %[temp3], %[kC1] \n\t"
- "mul %[temp1], %[temp1], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp13, temp3)
+ MUL_SHIFT_C1_IO(temp1, temp19)
"mul %[temp3], %[temp3], %[kC2] \n\t"
"sra %[temp2], %[temp2], 16 \n\t"
- "sra %[temp13], %[temp13], 16 \n\t"
- "sra %[temp1], %[temp1], 16 \n\t"
"sra %[temp3], %[temp3], 16 \n\t"
"subu %[temp13], %[temp2], %[temp13] \n\t"
"addu %[temp3], %[temp1], %[temp3] \n\t"
"addu %[temp2], %[temp4], %[temp6] \n\t"
"subu %[temp4], %[temp4], %[temp6] \n\t"
"mul %[temp6], %[temp5], %[kC2] \n\t"
- "mul %[temp1], %[temp7], %[kC1] \n\t"
- "mul %[temp5], %[temp5], %[kC1] \n\t"
+ MUL_SHIFT_C1(temp1, temp7)
+ MUL_SHIFT_C1_IO(temp5, temp19)
"mul %[temp7], %[temp7], %[kC2] \n\t"
"sra %[temp6], %[temp6], 16 \n\t"
- "sra %[temp1], %[temp1], 16 \n\t"
- "sra %[temp5], %[temp5], 16 \n\t"
"sra %[temp7], %[temp7], 16 \n\t"
"subu %[temp1], %[temp6], %[temp1] \n\t"
"addu %[temp7], %[temp5], %[temp7] \n\t"
@@ -542,7 +526,7 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
[temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11),
[temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14),
[temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17),
- [temp18]"=&r"(temp18)
+ [temp18]"=&r"(temp18), [temp19]"=&r"(temp19)
: [in]"r"(p_in), [kC1]"r"(kC1), [kC2]"r"(kC2), [dst]"r"(dst)
: "memory", "hi", "lo"
);
diff --git a/src/dsp/dec_mips_dsp_r2.c b/src/dsp/dec_mips_dsp_r2.c
index b0936bc4..0ba706a2 100644
--- a/src/dsp/dec_mips_dsp_r2.c
+++ b/src/dsp/dec_mips_dsp_r2.c
@@ -18,10 +18,8 @@
#include "src/dsp/mips_macro.h"
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
-
-#define MUL(a, b) (((a) * (b)) >> 16)
+static const int kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int kC2 = WEBP_TRANSFORM_AC3_C2;
static void TransformDC(const int16_t* in, uint8_t* dst) {
int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10;
@@ -49,10 +47,10 @@ static void TransformDC(const int16_t* in, uint8_t* dst) {
static void TransformAC3(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4;
- int c4 = MUL(in[4], kC2);
- const int d4 = MUL(in[4], kC1);
- const int c1 = MUL(in[1], kC2);
- const int d1 = MUL(in[1], kC1);
+ int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]);
+ const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]);
+ const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18;
@@ -479,8 +477,6 @@ static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
}
-#undef MUL
-
//------------------------------------------------------------------------------
// Simple In-loop filtering (Paragraph 15.2)
diff --git a/src/dsp/dec_msa.c b/src/dsp/dec_msa.c
index 8090622b..58d17301 100644
--- a/src/dsp/dec_msa.c
+++ b/src/dsp/dec_msa.c
@@ -37,8 +37,6 @@
d1_m = d_tmp1_m + d_tmp2_m; \
BUTTERFLY_4(a1_m, b1_m, c1_m, d1_m, out0, out1, out2, out3); \
}
-#define MULT1(a) ((((a) * 20091) >> 16) + (a))
-#define MULT2(a) (((a) * 35468) >> 16)
static void TransformOne(const int16_t* in, uint8_t* dst) {
v8i16 input0, input1;
@@ -124,10 +122,10 @@ static void TransformDC(const int16_t* in, uint8_t* dst) {
static void TransformAC3(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4;
- const int c4 = MULT2(in[4]);
- const int d4 = MULT1(in[4]);
- const int in2 = MULT2(in[1]);
- const int in3 = MULT1(in[1]);
+ const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]);
+ const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]);
+ const int in2 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int in3 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
v4i32 tmp0 = { 0 };
v4i32 out0 = __msa_fill_w(a + d4);
v4i32 out1 = __msa_fill_w(a + c4);
diff --git a/src/dsp/dec_neon.c b/src/dsp/dec_neon.c
index fa851707..83b3a1f9 100644
--- a/src/dsp/dec_neon.c
+++ b/src/dsp/dec_neon.c
@@ -1000,8 +1000,9 @@ static void HFilter8i_NEON(uint8_t* u, uint8_t* v, int stride,
// libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the
// same issue with kC1 and vqdmulh that we work around by down shifting kC2
-static const int16_t kC1 = 20091;
-static const int16_t kC2 = 17734; // half of kC2, actually. See comment above.
+static const int16_t kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int16_t kC2 =
+ WEBP_TRANSFORM_AC3_C2 / 2; // half of kC2, actually. See comment above.
#if defined(WEBP_USE_INTRINSICS)
static WEBP_INLINE void Transpose8x2_NEON(const int16x8_t in0,
@@ -1255,15 +1256,12 @@ static void TransformWHT_NEON(const int16_t* in, int16_t* out) {
//------------------------------------------------------------------------------
-#define MUL(a, b) (((a) * (b)) >> 16)
static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) {
- static const int kC1_full = 20091 + (1 << 16);
- static const int kC2_full = 35468;
const int16x4_t A = vld1_dup_s16(in);
- const int16x4_t c4 = vdup_n_s16(MUL(in[4], kC2_full));
- const int16x4_t d4 = vdup_n_s16(MUL(in[4], kC1_full));
- const int c1 = MUL(in[1], kC2_full);
- const int d1 = MUL(in[1], kC1_full);
+ const int16x4_t c4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL2(in[4]));
+ const int16x4_t d4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL1(in[4]));
+ const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
const uint64_t cd = (uint64_t)( d1 & 0xffff) << 0 |
(uint64_t)( c1 & 0xffff) << 16 |
(uint64_t)(-c1 & 0xffff) << 32 |
@@ -1274,7 +1272,6 @@ static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) {
const int16x8_t m2_m3 = vcombine_s16(vqsub_s16(B, c4), vqsub_s16(B, d4));
Add4x4_NEON(m0_m1, m2_m3, dst);
}
-#undef MUL
//------------------------------------------------------------------------------
// 4x4
@@ -1428,7 +1425,7 @@ static WEBP_INLINE void DC8_NEON(uint8_t* dst, int do_top, int do_left) {
if (do_top) {
const uint8x8_t A = vld1_u8(dst - BPS); // top row
-#if defined(__aarch64__)
+#if WEBP_AARCH64
const uint16_t p2 = vaddlv_u8(A);
sum_top = vdupq_n_u16(p2);
#else
@@ -1511,7 +1508,7 @@ static WEBP_INLINE void DC16_NEON(uint8_t* dst, int do_top, int do_left) {
if (do_top) {
const uint8x16_t A = vld1q_u8(dst - BPS); // top row
-#if defined(__aarch64__)
+#if WEBP_AARCH64
const uint16_t p3 = vaddlvq_u8(A);
sum_top = vdupq_n_u16(p3);
#else
diff --git a/src/dsp/dec_sse2.c b/src/dsp/dec_sse2.c
index 01e6bcb6..ff3a2855 100644
--- a/src/dsp/dec_sse2.c
+++ b/src/dsp/dec_sse2.c
@@ -196,15 +196,13 @@ static void Transform_SSE2(const int16_t* in, uint8_t* dst, int do_two) {
}
#if (USE_TRANSFORM_AC3 == 1)
-#define MUL(a, b) (((a) * (b)) >> 16)
+
static void TransformAC3(const int16_t* in, uint8_t* dst) {
- static const int kC1 = 20091 + (1 << 16);
- static const int kC2 = 35468;
const __m128i A = _mm_set1_epi16(in[0] + 4);
- const __m128i c4 = _mm_set1_epi16(MUL(in[4], kC2));
- const __m128i d4 = _mm_set1_epi16(MUL(in[4], kC1));
- const int c1 = MUL(in[1], kC2);
- const int d1 = MUL(in[1], kC1);
+ const __m128i c4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL2(in[4]));
+ const __m128i d4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL1(in[4]));
+ const int c1 = WEBP_TRANSFORM_AC3_MUL2(in[1]);
+ const int d1 = WEBP_TRANSFORM_AC3_MUL1(in[1]);
const __m128i CD = _mm_set_epi16(0, 0, 0, 0, -d1, -c1, c1, d1);
const __m128i B = _mm_adds_epi16(A, CD);
const __m128i m0 = _mm_adds_epi16(B, d4);
@@ -238,7 +236,7 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(dst2));
WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(dst3));
}
-#undef MUL
+
#endif // USE_TRANSFORM_AC3
//------------------------------------------------------------------------------
@@ -259,15 +257,15 @@ static WEBP_INLINE void SignedShift8b_SSE2(__m128i* const x) {
*x = _mm_packs_epi16(lo_1, hi_1);
}
-#define FLIP_SIGN_BIT2(a, b) { \
+#define FLIP_SIGN_BIT2(a, b) do { \
(a) = _mm_xor_si128(a, sign_bit); \
(b) = _mm_xor_si128(b, sign_bit); \
-}
+} while (0)
-#define FLIP_SIGN_BIT4(a, b, c, d) { \
+#define FLIP_SIGN_BIT4(a, b, c, d) do { \
FLIP_SIGN_BIT2(a, b); \
FLIP_SIGN_BIT2(c, d); \
-}
+} while (0)
// input/output is uint8_t
static WEBP_INLINE void GetNotHEV_SSE2(const __m128i* const p1,
@@ -645,12 +643,12 @@ static void SimpleHFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
(m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \
} while (0)
-#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \
+#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) do { \
(e1) = _mm_loadu_si128((__m128i*)&(p)[0 * (stride)]); \
(e2) = _mm_loadu_si128((__m128i*)&(p)[1 * (stride)]); \
(e3) = _mm_loadu_si128((__m128i*)&(p)[2 * (stride)]); \
(e4) = _mm_loadu_si128((__m128i*)&(p)[3 * (stride)]); \
-}
+} while (0)
#define LOADUV_H_EDGE(p, u, v, stride) do { \
const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
@@ -658,18 +656,18 @@ static void SimpleHFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
(p) = _mm_unpacklo_epi64(U, V); \
} while (0)
-#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \
+#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) do { \
LOADUV_H_EDGE(e1, u, v, 0 * (stride)); \
LOADUV_H_EDGE(e2, u, v, 1 * (stride)); \
LOADUV_H_EDGE(e3, u, v, 2 * (stride)); \
LOADUV_H_EDGE(e4, u, v, 3 * (stride)); \
-}
+} while (0)
-#define STOREUV(p, u, v, stride) { \
+#define STOREUV(p, u, v, stride) do { \
_mm_storel_epi64((__m128i*)&(u)[(stride)], p); \
(p) = _mm_srli_si128(p, 8); \
_mm_storel_epi64((__m128i*)&(v)[(stride)], p); \
-}
+} while (0)
static WEBP_INLINE void ComplexMask_SSE2(const __m128i* const p1,
const __m128i* const p0,
diff --git a/src/dsp/dsp.h b/src/dsp/dsp.h
index d2000b8e..23bc2965 100644
--- a/src/dsp/dsp.h
+++ b/src/dsp/dsp.h
@@ -203,6 +203,11 @@ extern VP8DecIdct VP8TransformDC;
extern VP8DecIdct VP8TransformDCUV;
extern VP8WHT VP8TransformWHT;
+#define WEBP_TRANSFORM_AC3_C1 20091
+#define WEBP_TRANSFORM_AC3_C2 35468
+#define WEBP_TRANSFORM_AC3_MUL1(a) ((((a) * WEBP_TRANSFORM_AC3_C1) >> 16) + (a))
+#define WEBP_TRANSFORM_AC3_MUL2(a) (((a) * WEBP_TRANSFORM_AC3_C2) >> 16)
+
// *dst is the destination block, with stride BPS. Boundary samples are
// assumed accessible when needed.
typedef void (*VP8PredFunc)(uint8_t* dst);
diff --git a/src/dsp/enc.c b/src/dsp/enc.c
index ea47a3fd..395ad05b 100644
--- a/src/dsp/enc.c
+++ b/src/dsp/enc.c
@@ -109,10 +109,6 @@ static WEBP_TSAN_IGNORE_FUNCTION void InitTables(void) {
#define STORE(x, y, v) \
dst[(x) + (y) * BPS] = clip_8b(ref[(x) + (y) * BPS] + ((v) >> 3))
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
-#define MUL(a, b) (((a) * (b)) >> 16)
-
static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
uint8_t* dst) {
int C[4 * 4], *tmp;
@@ -121,8 +117,10 @@ static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
for (i = 0; i < 4; ++i) { // vertical pass
const int a = in[0] + in[8];
const int b = in[0] - in[8];
- const int c = MUL(in[4], kC2) - MUL(in[12], kC1);
- const int d = MUL(in[4], kC1) + MUL(in[12], kC2);
+ const int c =
+ WEBP_TRANSFORM_AC3_MUL2(in[4]) - WEBP_TRANSFORM_AC3_MUL1(in[12]);
+ const int d =
+ WEBP_TRANSFORM_AC3_MUL1(in[4]) + WEBP_TRANSFORM_AC3_MUL2(in[12]);
tmp[0] = a + d;
tmp[1] = b + c;
tmp[2] = b - c;
@@ -134,10 +132,12 @@ static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
tmp = C;
for (i = 0; i < 4; ++i) { // horizontal pass
const int dc = tmp[0] + 4;
- const int a = dc + tmp[8];
- const int b = dc - tmp[8];
- const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1);
- const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2);
+ const int a = dc + tmp[8];
+ const int b = dc - tmp[8];
+ const int c =
+ WEBP_TRANSFORM_AC3_MUL2(tmp[4]) - WEBP_TRANSFORM_AC3_MUL1(tmp[12]);
+ const int d =
+ WEBP_TRANSFORM_AC3_MUL1(tmp[4]) + WEBP_TRANSFORM_AC3_MUL2(tmp[12]);
STORE(0, i, a + d);
STORE(1, i, b + c);
STORE(2, i, b - c);
@@ -222,7 +222,6 @@ static void FTransformWHT_C(const int16_t* in, int16_t* out) {
}
#endif // !WEBP_NEON_OMIT_C_CODE
-#undef MUL
#undef STORE
//------------------------------------------------------------------------------
@@ -732,6 +731,7 @@ VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT;
VP8BlockCopy VP8Copy4x4;
VP8BlockCopy VP8Copy16x8;
+extern VP8CPUInfo VP8GetCPUInfo;
extern void VP8EncDspInitSSE2(void);
extern void VP8EncDspInitSSE41(void);
extern void VP8EncDspInitNEON(void);
diff --git a/src/dsp/enc_mips32.c b/src/dsp/enc_mips32.c
index 618f0fc0..50518a5f 100644
--- a/src/dsp/enc_mips32.c
+++ b/src/dsp/enc_mips32.c
@@ -21,8 +21,8 @@
#include "src/enc/vp8i_enc.h"
#include "src/enc/cost_enc.h"
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
+static const int kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int kC2 = WEBP_TRANSFORM_AC3_C2;
// macro for one vertical pass in ITransformOne
// MUL macro inlined
@@ -30,7 +30,7 @@ static const int kC2 = 35468;
// A..D - offsets in bytes to load from in buffer
// TEMP0..TEMP3 - registers for corresponding tmp elements
// TEMP4..TEMP5 - temporary registers
-#define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \
+#define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \
"lh %[temp16], " #A "(%[temp20]) \n\t" \
"lh %[temp18], " #B "(%[temp20]) \n\t" \
"lh %[temp17], " #C "(%[temp20]) \n\t" \
@@ -38,12 +38,10 @@ static const int kC2 = 35468;
"addu %[" #TEMP4 "], %[temp16], %[temp18] \n\t" \
"subu %[temp16], %[temp16], %[temp18] \n\t" \
"mul %[" #TEMP0 "], %[temp17], %[kC2] \n\t" \
- "mul %[temp18], %[temp19], %[kC1] \n\t" \
- "mul %[temp17], %[temp17], %[kC1] \n\t" \
+ MUL_SHIFT_C1_IO(temp17, temp18) \
+ MUL_SHIFT_C1(temp18, temp19) \
"mul %[temp19], %[temp19], %[kC2] \n\t" \
"sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\n" \
- "sra %[temp18], %[temp18], 16 \n\n" \
- "sra %[temp17], %[temp17], 16 \n\n" \
"sra %[temp19], %[temp19], 16 \n\n" \
"subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp18] \n\t" \
"addu %[" #TEMP3 "], %[temp17], %[temp19] \n\t" \
@@ -58,17 +56,15 @@ static const int kC2 = 35468;
// temp0..temp15 holds tmp[0]..tmp[15]
// A - offset in bytes to load from ref and store to dst buffer
// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements
-#define HORIZONTAL_PASS(A, TEMP0, TEMP4, TEMP8, TEMP12) \
+#define HORIZONTAL_PASS(A, TEMP0, TEMP4, TEMP8, TEMP12) \
"addiu %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \
"addu %[temp16], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
"subu %[temp17], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
"mul %[" #TEMP0 "], %[" #TEMP4 "], %[kC2] \n\t" \
- "mul %[" #TEMP8 "], %[" #TEMP12 "], %[kC1] \n\t" \
- "mul %[" #TEMP4 "], %[" #TEMP4 "], %[kC1] \n\t" \
+ MUL_SHIFT_C1_IO(TEMP4, TEMP8) \
+ MUL_SHIFT_C1(TEMP8, TEMP12) \
"mul %[" #TEMP12 "], %[" #TEMP12 "], %[kC2] \n\t" \
"sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \
- "sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \
- "sra %[" #TEMP4 "], %[" #TEMP4 "], 16 \n\t" \
"sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \
"subu %[temp18], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
"addu %[temp19], %[" #TEMP4 "], %[" #TEMP12 "] \n\t" \
diff --git a/src/dsp/enc_mips_dsp_r2.c b/src/dsp/enc_mips_dsp_r2.c
index 9ddd8950..e1431f3b 100644
--- a/src/dsp/enc_mips_dsp_r2.c
+++ b/src/dsp/enc_mips_dsp_r2.c
@@ -20,8 +20,8 @@
#include "src/enc/cost_enc.h"
#include "src/enc/vp8i_enc.h"
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
+static const int kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int kC2 = WEBP_TRANSFORM_AC3_C2;
// O - output
// I - input (macro doesn't change it)
diff --git a/src/dsp/enc_neon.c b/src/dsp/enc_neon.c
index 3a04111c..6f641c9a 100644
--- a/src/dsp/enc_neon.c
+++ b/src/dsp/enc_neon.c
@@ -27,8 +27,9 @@
// This code is pretty much the same as TransformOne in the dec_neon.c, except
// for subtraction to *ref. See the comments there for algorithmic explanations.
-static const int16_t kC1 = 20091;
-static const int16_t kC2 = 17734; // half of kC2, actually. See comment above.
+static const int16_t kC1 = WEBP_TRANSFORM_AC3_C1;
+static const int16_t kC2 =
+ WEBP_TRANSFORM_AC3_C2 / 2; // half of kC2, actually. See comment above.
// This code works but is *slower* than the inlined-asm version below
// (with gcc-4.6). So we disable it for now. Later, it'll be conditional to
@@ -764,7 +765,7 @@ static WEBP_INLINE void AccumulateSSE16_NEON(const uint8_t* const a,
// Horizontal sum of all four uint32_t values in 'sum'.
static int SumToInt_NEON(uint32x4_t sum) {
-#if defined(__aarch64__)
+#if WEBP_AARCH64
return (int)vaddvq_u32(sum);
#else
const uint64x2_t sum2 = vpaddlq_u32(sum);
@@ -865,7 +866,7 @@ static int QuantizeBlock_NEON(int16_t in[16], int16_t out[16],
uint8x8x4_t shuffles;
// vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use
// non-standard versions there.
-#if defined(__APPLE__) && defined(__aarch64__) && \
+#if defined(__APPLE__) && WEBP_AARCH64 && \
defined(__apple_build_version__) && (__apple_build_version__< 6020037)
uint8x16x2_t all_out;
INIT_VECTOR2(all_out, vreinterpretq_u8_s16(out0), vreinterpretq_u8_s16(out1));
diff --git a/src/dsp/enc_sse2.c b/src/dsp/enc_sse2.c
index 1d105566..010624a2 100644
--- a/src/dsp/enc_sse2.c
+++ b/src/dsp/enc_sse2.c
@@ -25,9 +25,160 @@
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
-// Does one or two inverse transforms.
-static void ITransform_SSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
- int do_two) {
+// Does one inverse transform.
+static void ITransform_One_SSE2(const uint8_t* ref, const int16_t* in,
+ uint8_t* dst) {
+ // This implementation makes use of 16-bit fixed point versions of two
+ // multiply constants:
+ // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
+ // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16
+ //
+ // To be able to use signed 16-bit integers, we use the following trick to
+ // have constants within range:
+ // - Associated constants are obtained by subtracting the 16-bit fixed point
+ // version of one:
+ // k = K - (1 << 16) => K = k + (1 << 16)
+ // K1 = 85267 => k1 = 20091
+ // K2 = 35468 => k2 = -30068
+ // - The multiplication of a variable by a constant become the sum of the
+ // variable and the multiplication of that variable by the associated
+ // constant:
+ // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x
+ const __m128i k1k2 = _mm_set_epi16(-30068, -30068, -30068, -30068,
+ 20091, 20091, 20091, 20091);
+ const __m128i k2k1 = _mm_set_epi16(20091, 20091, 20091, 20091,
+ -30068, -30068, -30068, -30068);
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i zero_four = _mm_set_epi16(0, 0, 0, 0, 4, 4, 4, 4);
+ __m128i T01, T23;
+
+ // Load and concatenate the transform coefficients.
+ const __m128i in01 = _mm_loadu_si128((const __m128i*)&in[0]);
+ const __m128i in23 = _mm_loadu_si128((const __m128i*)&in[8]);
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // a02 a12 a22 a32 a03 a13 a23 a33
+
+ // Vertical pass and subsequent transpose.
+ {
+ const __m128i in1 = _mm_unpackhi_epi64(in01, in01);
+ const __m128i in3 = _mm_unpackhi_epi64(in23, in23);
+
+ // First pass, c and d calculations are longer because of the "trick"
+ // multiplications.
+ // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3
+ // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3
+ const __m128i a_d3 = _mm_add_epi16(in01, in23);
+ const __m128i b_c3 = _mm_sub_epi16(in01, in23);
+ const __m128i c1d1 = _mm_mulhi_epi16(in1, k2k1);
+ const __m128i c2d2 = _mm_mulhi_epi16(in3, k1k2);
+ const __m128i c3 = _mm_unpackhi_epi64(b_c3, b_c3);
+ const __m128i c4 = _mm_sub_epi16(c1d1, c2d2);
+ const __m128i c = _mm_add_epi16(c3, c4);
+ const __m128i d4u = _mm_add_epi16(c1d1, c2d2);
+ const __m128i du = _mm_add_epi16(a_d3, d4u);
+ const __m128i d = _mm_unpackhi_epi64(du, du);
+
+ // Second pass.
+ const __m128i comb_ab = _mm_unpacklo_epi64(a_d3, b_c3);
+ const __m128i comb_dc = _mm_unpacklo_epi64(d, c);
+
+ const __m128i tmp01 = _mm_add_epi16(comb_ab, comb_dc);
+ const __m128i tmp32 = _mm_sub_epi16(comb_ab, comb_dc);
+ const __m128i tmp23 = _mm_shuffle_epi32(tmp32, _MM_SHUFFLE(1, 0, 3, 2));
+
+ const __m128i transpose_0 = _mm_unpacklo_epi16(tmp01, tmp23);
+ const __m128i transpose_1 = _mm_unpackhi_epi16(tmp01, tmp23);
+ // a00 a20 a01 a21 a02 a22 a03 a23
+ // a10 a30 a11 a31 a12 a32 a13 a33
+
+ T01 = _mm_unpacklo_epi16(transpose_0, transpose_1);
+ T23 = _mm_unpackhi_epi16(transpose_0, transpose_1);
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // a02 a12 a22 a32 a03 a13 a23 a33
+ }
+
+ // Horizontal pass and subsequent transpose.
+ {
+ const __m128i T1 = _mm_unpackhi_epi64(T01, T01);
+ const __m128i T3 = _mm_unpackhi_epi64(T23, T23);
+
+ // First pass, c and d calculations are longer because of the "trick"
+ // multiplications.
+ const __m128i dc = _mm_add_epi16(T01, zero_four);
+
+ // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3
+ // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3
+ const __m128i a_d3 = _mm_add_epi16(dc, T23);
+ const __m128i b_c3 = _mm_sub_epi16(dc, T23);
+ const __m128i c1d1 = _mm_mulhi_epi16(T1, k2k1);
+ const __m128i c2d2 = _mm_mulhi_epi16(T3, k1k2);
+ const __m128i c3 = _mm_unpackhi_epi64(b_c3, b_c3);
+ const __m128i c4 = _mm_sub_epi16(c1d1, c2d2);
+ const __m128i c = _mm_add_epi16(c3, c4);
+ const __m128i d4u = _mm_add_epi16(c1d1, c2d2);
+ const __m128i du = _mm_add_epi16(a_d3, d4u);
+ const __m128i d = _mm_unpackhi_epi64(du, du);
+
+ // Second pass.
+ const __m128i comb_ab = _mm_unpacklo_epi64(a_d3, b_c3);
+ const __m128i comb_dc = _mm_unpacklo_epi64(d, c);
+
+ const __m128i tmp01 = _mm_add_epi16(comb_ab, comb_dc);
+ const __m128i tmp32 = _mm_sub_epi16(comb_ab, comb_dc);
+ const __m128i tmp23 = _mm_shuffle_epi32(tmp32, _MM_SHUFFLE(1, 0, 3, 2));
+
+ const __m128i shifted01 = _mm_srai_epi16(tmp01, 3);
+ const __m128i shifted23 = _mm_srai_epi16(tmp23, 3);
+ // a00 a01 a02 a03 a10 a11 a12 a13
+ // a20 a21 a22 a23 a30 a31 a32 a33
+
+ const __m128i transpose_0 = _mm_unpacklo_epi16(shifted01, shifted23);
+ const __m128i transpose_1 = _mm_unpackhi_epi16(shifted01, shifted23);
+ // a00 a20 a01 a21 a02 a22 a03 a23
+ // a10 a30 a11 a31 a12 a32 a13 a33
+
+ T01 = _mm_unpacklo_epi16(transpose_0, transpose_1);
+ T23 = _mm_unpackhi_epi16(transpose_0, transpose_1);
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // a02 a12 a22 a32 a03 a13 a23 a33
+ }
+
+ // Add inverse transform to 'ref' and store.
+ {
+ // Load the reference(s).
+ __m128i ref01, ref23, ref0123;
+ int32_t buf[4];
+
+ // Load four bytes/pixels per line.
+ const __m128i ref0 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[0 * BPS]));
+ const __m128i ref1 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[1 * BPS]));
+ const __m128i ref2 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[2 * BPS]));
+ const __m128i ref3 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[3 * BPS]));
+ ref01 = _mm_unpacklo_epi32(ref0, ref1);
+ ref23 = _mm_unpacklo_epi32(ref2, ref3);
+
+ // Convert to 16b.
+ ref01 = _mm_unpacklo_epi8(ref01, zero);
+ ref23 = _mm_unpacklo_epi8(ref23, zero);
+ // Add the inverse transform(s).
+ ref01 = _mm_add_epi16(ref01, T01);
+ ref23 = _mm_add_epi16(ref23, T23);
+ // Unsigned saturate to 8b.
+ ref0123 = _mm_packus_epi16(ref01, ref23);
+
+ _mm_storeu_si128((__m128i *)buf, ref0123);
+
+ // Store four bytes/pixels per line.
+ WebPInt32ToMem(&dst[0 * BPS], buf[0]);
+ WebPInt32ToMem(&dst[1 * BPS], buf[1]);
+ WebPInt32ToMem(&dst[2 * BPS], buf[2]);
+ WebPInt32ToMem(&dst[3 * BPS], buf[3]);
+ }
+}
+
+// Does two inverse transforms.
+static void ITransform_Two_SSE2(const uint8_t* ref, const int16_t* in,
+ uint8_t* dst) {
// This implementation makes use of 16-bit fixed point versions of two
// multiply constants:
// K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
@@ -49,33 +200,21 @@ static void ITransform_SSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
__m128i T0, T1, T2, T3;
// Load and concatenate the transform coefficients (we'll do two inverse
- // transforms in parallel). In the case of only one inverse transform, the
- // second half of the vectors will just contain random value we'll never
- // use nor store.
+ // transforms in parallel).
__m128i in0, in1, in2, in3;
{
- in0 = _mm_loadl_epi64((const __m128i*)&in[0]);
- in1 = _mm_loadl_epi64((const __m128i*)&in[4]);
- in2 = _mm_loadl_epi64((const __m128i*)&in[8]);
- in3 = _mm_loadl_epi64((const __m128i*)&in[12]);
- // a00 a10 a20 a30 x x x x
- // a01 a11 a21 a31 x x x x
- // a02 a12 a22 a32 x x x x
- // a03 a13 a23 a33 x x x x
- if (do_two) {
- const __m128i inB0 = _mm_loadl_epi64((const __m128i*)&in[16]);
- const __m128i inB1 = _mm_loadl_epi64((const __m128i*)&in[20]);
- const __m128i inB2 = _mm_loadl_epi64((const __m128i*)&in[24]);
- const __m128i inB3 = _mm_loadl_epi64((const __m128i*)&in[28]);
- in0 = _mm_unpacklo_epi64(in0, inB0);
- in1 = _mm_unpacklo_epi64(in1, inB1);
- in2 = _mm_unpacklo_epi64(in2, inB2);
- in3 = _mm_unpacklo_epi64(in3, inB3);
- // a00 a10 a20 a30 b00 b10 b20 b30
- // a01 a11 a21 a31 b01 b11 b21 b31
- // a02 a12 a22 a32 b02 b12 b22 b32
- // a03 a13 a23 a33 b03 b13 b23 b33
- }
+ const __m128i tmp0 = _mm_loadu_si128((const __m128i*)&in[0]);
+ const __m128i tmp1 = _mm_loadu_si128((const __m128i*)&in[8]);
+ const __m128i tmp2 = _mm_loadu_si128((const __m128i*)&in[16]);
+ const __m128i tmp3 = _mm_loadu_si128((const __m128i*)&in[24]);
+ in0 = _mm_unpacklo_epi64(tmp0, tmp2);
+ in1 = _mm_unpackhi_epi64(tmp0, tmp2);
+ in2 = _mm_unpacklo_epi64(tmp1, tmp3);
+ in3 = _mm_unpackhi_epi64(tmp1, tmp3);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
}
// Vertical pass and subsequent transpose.
@@ -148,19 +287,11 @@ static void ITransform_SSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
const __m128i zero = _mm_setzero_si128();
// Load the reference(s).
__m128i ref0, ref1, ref2, ref3;
- if (do_two) {
- // Load eight bytes/pixels per line.
- ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]);
- ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]);
- ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]);
- ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]);
- } else {
- // Load four bytes/pixels per line.
- ref0 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[0 * BPS]));
- ref1 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[1 * BPS]));
- ref2 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[2 * BPS]));
- ref3 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[3 * BPS]));
- }
+ // Load eight bytes/pixels per line.
+ ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]);
+ ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]);
+ ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]);
+ ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]);
// Convert to 16b.
ref0 = _mm_unpacklo_epi8(ref0, zero);
ref1 = _mm_unpacklo_epi8(ref1, zero);
@@ -176,20 +307,21 @@ static void ITransform_SSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
ref1 = _mm_packus_epi16(ref1, ref1);
ref2 = _mm_packus_epi16(ref2, ref2);
ref3 = _mm_packus_epi16(ref3, ref3);
- // Store the results.
- if (do_two) {
- // Store eight bytes/pixels per line.
- _mm_storel_epi64((__m128i*)&dst[0 * BPS], ref0);
- _mm_storel_epi64((__m128i*)&dst[1 * BPS], ref1);
- _mm_storel_epi64((__m128i*)&dst[2 * BPS], ref2);
- _mm_storel_epi64((__m128i*)&dst[3 * BPS], ref3);
- } else {
- // Store four bytes/pixels per line.
- WebPInt32ToMem(&dst[0 * BPS], _mm_cvtsi128_si32(ref0));
- WebPInt32ToMem(&dst[1 * BPS], _mm_cvtsi128_si32(ref1));
- WebPInt32ToMem(&dst[2 * BPS], _mm_cvtsi128_si32(ref2));
- WebPInt32ToMem(&dst[3 * BPS], _mm_cvtsi128_si32(ref3));
- }
+ // Store eight bytes/pixels per line.
+ _mm_storel_epi64((__m128i*)&dst[0 * BPS], ref0);
+ _mm_storel_epi64((__m128i*)&dst[1 * BPS], ref1);
+ _mm_storel_epi64((__m128i*)&dst[2 * BPS], ref2);
+ _mm_storel_epi64((__m128i*)&dst[3 * BPS], ref3);
+ }
+}
+
+// Does one or two inverse transforms.
+static void ITransform_SSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
+ int do_two) {
+ if (do_two) {
+ ITransform_Two_SSE2(ref, in, dst);
+ } else {
+ ITransform_One_SSE2(ref, in, dst);
}
}
diff --git a/src/dsp/filters.c b/src/dsp/filters.c
index 4506567b..c9232ff1 100644
--- a/src/dsp/filters.c
+++ b/src/dsp/filters.c
@@ -19,14 +19,16 @@
//------------------------------------------------------------------------------
// Helpful macro.
-# define SANITY_CHECK(in, out) \
- assert((in) != NULL); \
- assert((out) != NULL); \
- assert(width > 0); \
- assert(height > 0); \
- assert(stride >= width); \
- assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
- (void)height; // Silence unused warning.
+#define DCHECK(in, out) \
+ do { \
+ assert((in) != NULL); \
+ assert((out) != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(stride >= width); \
+ assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
+ (void)height; /* Silence unused warning. */ \
+ } while (0)
#if !WEBP_NEON_OMIT_C_CODE
static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred,
@@ -49,7 +51,7 @@ static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = inverse ? out : in;
@@ -86,7 +88,7 @@ static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = inverse ? out : in;
@@ -131,7 +133,7 @@ static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = inverse ? out : in;
@@ -165,7 +167,7 @@ static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
}
#endif // !WEBP_NEON_OMIT_C_CODE
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
@@ -189,6 +191,12 @@ static void GradientFilter_C(const uint8_t* data, int width, int height,
//------------------------------------------------------------------------------
+static void NoneUnfilter_C(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
+ (void)prev;
+ if (out != in) memcpy(out, in, width * sizeof(*out));
+}
+
static void HorizontalUnfilter_C(const uint8_t* prev, const uint8_t* in,
uint8_t* out, int width) {
uint8_t pred = (prev == NULL) ? 0 : prev[0];
@@ -233,13 +241,14 @@ static void GradientUnfilter_C(const uint8_t* prev, const uint8_t* in,
WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST];
+extern VP8CPUInfo VP8GetCPUInfo;
extern void VP8FiltersInitMIPSdspR2(void);
extern void VP8FiltersInitMSA(void);
extern void VP8FiltersInitNEON(void);
extern void VP8FiltersInitSSE2(void);
WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
- WebPUnfilters[WEBP_FILTER_NONE] = NULL;
+ WebPUnfilters[WEBP_FILTER_NONE] = NoneUnfilter_C;
#if !WEBP_NEON_OMIT_C_CODE
WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_C;
WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_C;
@@ -278,6 +287,7 @@ WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
}
#endif
+ assert(WebPUnfilters[WEBP_FILTER_NONE] != NULL);
assert(WebPUnfilters[WEBP_FILTER_HORIZONTAL] != NULL);
assert(WebPUnfilters[WEBP_FILTER_VERTICAL] != NULL);
assert(WebPUnfilters[WEBP_FILTER_GRADIENT] != NULL);
diff --git a/src/dsp/filters_mips_dsp_r2.c b/src/dsp/filters_mips_dsp_r2.c
index 9382b128..eca866f5 100644
--- a/src/dsp/filters_mips_dsp_r2.c
+++ b/src/dsp/filters_mips_dsp_r2.c
@@ -24,14 +24,16 @@
//------------------------------------------------------------------------------
// Helpful macro.
-# define SANITY_CHECK(in, out) \
- assert(in != NULL); \
- assert(out != NULL); \
- assert(width > 0); \
- assert(height > 0); \
- assert(stride >= width); \
- assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
- (void)height; // Silence unused warning.
+#define DCHECK(in, out) \
+ do { \
+ assert(in != NULL); \
+ assert(out != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(stride >= width); \
+ assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
+ (void)height; /* Silence unused warning. */ \
+ } while (0)
#define DO_PREDICT_LINE(SRC, DST, LENGTH, INVERSE) do { \
const uint8_t* psrc = (uint8_t*)(SRC); \
@@ -200,7 +202,7 @@ static WEBP_INLINE void DoHorizontalFilter_MIPSdspR2(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = in;
@@ -248,7 +250,7 @@ static WEBP_INLINE void DoVerticalFilter_MIPSdspR2(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = in;
@@ -316,7 +318,7 @@ static void DoGradientFilter_MIPSdspR2(const uint8_t* in,
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
preds = in;
@@ -378,7 +380,7 @@ static void GradientUnfilter_MIPSdspR2(const uint8_t* prev, const uint8_t* in,
#undef DO_PREDICT_LINE_VERTICAL
#undef PREDICT_LINE_ONE_PASS
#undef DO_PREDICT_LINE
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
// Entry point
diff --git a/src/dsp/filters_msa.c b/src/dsp/filters_msa.c
index 14c437d1..33a1b20b 100644
--- a/src/dsp/filters_msa.c
+++ b/src/dsp/filters_msa.c
@@ -56,12 +56,14 @@ static WEBP_INLINE void PredictLineInverse0(const uint8_t* src,
//------------------------------------------------------------------------------
// Helpful macro.
-#define SANITY_CHECK(in, out) \
- assert(in != NULL); \
- assert(out != NULL); \
- assert(width > 0); \
- assert(height > 0); \
- assert(stride >= width);
+#define DCHECK(in, out) \
+ do { \
+ assert(in != NULL); \
+ assert(out != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(stride >= width); \
+ } while (0)
//------------------------------------------------------------------------------
// Horrizontal filter
@@ -72,7 +74,7 @@ static void HorizontalFilter_MSA(const uint8_t* data, int width, int height,
const uint8_t* in = data;
uint8_t* out = filtered_data;
int row = 1;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
// Leftmost pixel is the same as input for topmost scanline.
out[0] = in[0];
@@ -135,7 +137,7 @@ static void GradientFilter_MSA(const uint8_t* data, int width, int height,
const uint8_t* preds = data;
uint8_t* out = filtered_data;
int row = 1;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
// left prediction for top scan-line
out[0] = in[0];
@@ -163,7 +165,7 @@ static void VerticalFilter_MSA(const uint8_t* data, int width, int height,
const uint8_t* preds = data;
uint8_t* out = filtered_data;
int row = 1;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
// Very first top-left pixel is copied.
out[0] = in[0];
@@ -182,7 +184,7 @@ static void VerticalFilter_MSA(const uint8_t* data, int width, int height,
}
}
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
// Entry point
diff --git a/src/dsp/filters_neon.c b/src/dsp/filters_neon.c
index 3e6a578e..b49e515a 100644
--- a/src/dsp/filters_neon.c
+++ b/src/dsp/filters_neon.c
@@ -21,14 +21,16 @@
//------------------------------------------------------------------------------
// Helpful macros.
-# define SANITY_CHECK(in, out) \
- assert(in != NULL); \
- assert(out != NULL); \
- assert(width > 0); \
- assert(height > 0); \
- assert(stride >= width); \
- assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
- (void)height; // Silence unused warning.
+#define DCHECK(in, out) \
+ do { \
+ assert(in != NULL); \
+ assert(out != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(stride >= width); \
+ assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
+ (void)height; /* Silence unused warning. */ \
+ } while (0)
// load eight u8 and widen to s16
#define U8_TO_S16(A) vreinterpretq_s16_u16(vmovl_u8(A))
@@ -71,7 +73,7 @@ static WEBP_INLINE void DoHorizontalFilter_NEON(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -110,7 +112,7 @@ static WEBP_INLINE void DoVerticalFilter_NEON(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -172,7 +174,7 @@ static WEBP_INLINE void DoGradientFilter_NEON(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -201,7 +203,7 @@ static void GradientFilter_NEON(const uint8_t* data, int width, int height,
filtered_data);
}
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
// Inverse transforms
diff --git a/src/dsp/filters_sse2.c b/src/dsp/filters_sse2.c
index 5c33ec15..bb4b5d58 100644
--- a/src/dsp/filters_sse2.c
+++ b/src/dsp/filters_sse2.c
@@ -23,14 +23,16 @@
//------------------------------------------------------------------------------
// Helpful macro.
-# define SANITY_CHECK(in, out) \
- assert((in) != NULL); \
- assert((out) != NULL); \
- assert(width > 0); \
- assert(height > 0); \
- assert(stride >= width); \
- assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
- (void)height; // Silence unused warning.
+#define DCHECK(in, out) \
+ do { \
+ assert((in) != NULL); \
+ assert((out) != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(stride >= width); \
+ assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
+ (void)height; /* Silence unused warning. */ \
+ } while (0)
static void PredictLineTop_SSE2(const uint8_t* src, const uint8_t* pred,
uint8_t* dst, int length) {
@@ -78,7 +80,7 @@ static WEBP_INLINE void DoHorizontalFilter_SSE2(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -111,7 +113,7 @@ static WEBP_INLINE void DoVerticalFilter_SSE2(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -174,7 +176,7 @@ static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
- SANITY_CHECK(in, out);
+ DCHECK(in, out);
in += start_offset;
out += start_offset;
@@ -197,7 +199,7 @@ static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
}
}
-#undef SANITY_CHECK
+#undef DCHECK
//------------------------------------------------------------------------------
diff --git a/src/dsp/lossless.c b/src/dsp/lossless.c
index fb86e58d..9f812094 100644
--- a/src/dsp/lossless.c
+++ b/src/dsp/lossless.c
@@ -588,6 +588,7 @@ VP8LConvertFunc VP8LConvertBGRAToBGR;
VP8LMapARGBFunc VP8LMapColor32b;
VP8LMapAlphaFunc VP8LMapColor8b;
+extern VP8CPUInfo VP8GetCPUInfo;
extern void VP8LDspInitSSE2(void);
extern void VP8LDspInitSSE41(void);
extern void VP8LDspInitNEON(void);
diff --git a/src/dsp/lossless.h b/src/dsp/lossless.h
index de60d95d..0bf10a1a 100644
--- a/src/dsp/lossless.h
+++ b/src/dsp/lossless.h
@@ -182,9 +182,9 @@ extern VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16];
// -----------------------------------------------------------------------------
// Huffman-cost related functions.
-typedef float (*VP8LCostFunc)(const uint32_t* population, int length);
-typedef float (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
- int length);
+typedef uint32_t (*VP8LCostFunc)(const uint32_t* population, int length);
+typedef uint32_t (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
+ int length);
typedef float (*VP8LCombinedShannonEntropyFunc)(const int X[256],
const int Y[256]);
diff --git a/src/dsp/lossless_common.h b/src/dsp/lossless_common.h
index 6a2f736b..d6139b2b 100644
--- a/src/dsp/lossless_common.h
+++ b/src/dsp/lossless_common.h
@@ -16,9 +16,9 @@
#ifndef WEBP_DSP_LOSSLESS_COMMON_H_
#define WEBP_DSP_LOSSLESS_COMMON_H_
-#include "src/webp/types.h"
-
+#include "src/dsp/cpu.h"
#include "src/utils/utils.h"
+#include "src/webp/types.h"
#ifdef __cplusplus
extern "C" {
@@ -166,7 +166,7 @@ uint32_t VP8LSubPixels(uint32_t a, uint32_t b) {
}
//------------------------------------------------------------------------------
-// Transform-related functions use din both encoding and decoding.
+// Transform-related functions used in both encoding and decoding.
// Macros used to create a batch predictor that iteratively uses a
// one-pixel predictor.
diff --git a/src/dsp/lossless_enc.c b/src/dsp/lossless_enc.c
index b1f9f26d..997d56c2 100644
--- a/src/dsp/lossless_enc.c
+++ b/src/dsp/lossless_enc.c
@@ -636,20 +636,25 @@ void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits,
//------------------------------------------------------------------------------
-static float ExtraCost_C(const uint32_t* population, int length) {
+static uint32_t ExtraCost_C(const uint32_t* population, int length) {
int i;
- float cost = 0.f;
- for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2];
+ uint32_t cost = population[4] + population[5];
+ assert(length % 2 == 0);
+ for (i = 2; i < length / 2 - 1; ++i) {
+ cost += i * (population[2 * i + 2] + population[2 * i + 3]);
+ }
return cost;
}
-static float ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
- int length) {
+static uint32_t ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
+ int length) {
int i;
- float cost = 0.f;
- for (i = 2; i < length - 2; ++i) {
- const int xy = X[i + 2] + Y[i + 2];
- cost += (i >> 1) * xy;
+ uint32_t cost = X[4] + Y[4] + X[5] + Y[5];
+ assert(length % 2 == 0);
+ for (i = 2; i < length / 2 - 1; ++i) {
+ const int xy0 = X[2 * i + 2] + Y[2 * i + 2];
+ const int xy1 = X[2 * i + 3] + Y[2 * i + 3];
+ cost += i * (xy0 + xy1);
}
return cost;
}
@@ -791,6 +796,7 @@ VP8LBundleColorMapFunc VP8LBundleColorMap;
VP8LPredictorAddSubFunc VP8LPredictorsSub[16];
VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16];
+extern VP8CPUInfo VP8GetCPUInfo;
extern void VP8LEncDspInitSSE2(void);
extern void VP8LEncDspInitSSE41(void);
extern void VP8LEncDspInitNEON(void);
diff --git a/src/dsp/lossless_enc_mips32.c b/src/dsp/lossless_enc_mips32.c
index 639f7866..e10f12da 100644
--- a/src/dsp/lossless_enc_mips32.c
+++ b/src/dsp/lossless_enc_mips32.c
@@ -103,8 +103,8 @@ static float FastLog2Slow_MIPS32(uint32_t v) {
// cost += i * *(pop + 1);
// pop += 2;
// }
-// return (float)cost;
-static float ExtraCost_MIPS32(const uint32_t* const population, int length) {
+// return cost;
+static uint32_t ExtraCost_MIPS32(const uint32_t* const population, int length) {
int i, temp0, temp1;
const uint32_t* pop = &population[4];
const uint32_t* const LoopEnd = &population[length];
@@ -130,7 +130,7 @@ static float ExtraCost_MIPS32(const uint32_t* const population, int length) {
: "memory", "hi", "lo"
);
- return (float)((int64_t)temp0 << 32 | temp1);
+ return ((int64_t)temp0 << 32 | temp1);
}
// C version of this function:
@@ -148,9 +148,9 @@ static float ExtraCost_MIPS32(const uint32_t* const population, int length) {
// pX += 2;
// pY += 2;
// }
-// return (float)cost;
-static float ExtraCostCombined_MIPS32(const uint32_t* const X,
- const uint32_t* const Y, int length) {
+// return cost;
+static uint32_t ExtraCostCombined_MIPS32(const uint32_t* const X,
+ const uint32_t* const Y, int length) {
int i, temp0, temp1, temp2, temp3;
const uint32_t* pX = &X[4];
const uint32_t* pY = &Y[4];
@@ -183,7 +183,7 @@ static float ExtraCostCombined_MIPS32(const uint32_t* const X,
: "memory", "hi", "lo"
);
- return (float)((int64_t)temp0 << 32 | temp1);
+ return ((int64_t)temp0 << 32 | temp1);
}
#define HUFFMAN_COST_PASS \
diff --git a/src/dsp/lossless_enc_neon.c b/src/dsp/lossless_enc_neon.c
index 7c7b73f8..e32c7961 100644
--- a/src/dsp/lossless_enc_neon.c
+++ b/src/dsp/lossless_enc_neon.c
@@ -25,7 +25,7 @@
// vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use
// non-standard versions there.
-#if defined(__APPLE__) && defined(__aarch64__) && \
+#if defined(__APPLE__) && WEBP_AARCH64 && \
defined(__apple_build_version__) && (__apple_build_version__< 6020037)
#define USE_VTBLQ
#endif
diff --git a/src/dsp/lossless_enc_sse41.c b/src/dsp/lossless_enc_sse41.c
index ad358a6f..7ab83c26 100644
--- a/src/dsp/lossless_enc_sse41.c
+++ b/src/dsp/lossless_enc_sse41.c
@@ -18,8 +18,53 @@
#include <smmintrin.h>
#include "src/dsp/lossless.h"
-// For sign-extended multiplying constants, pre-shifted by 5:
-#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5)
+//------------------------------------------------------------------------------
+// Cost operations.
+
+static WEBP_INLINE uint32_t HorizontalSum_SSE41(__m128i cost) {
+ cost = _mm_add_epi32(cost, _mm_srli_si128(cost, 8));
+ cost = _mm_add_epi32(cost, _mm_srli_si128(cost, 4));
+ return _mm_cvtsi128_si32(cost);
+}
+
+static uint32_t ExtraCost_SSE41(const uint32_t* const a, int length) {
+ int i;
+ __m128i cost = _mm_set_epi32(2 * a[7], 2 * a[6], a[5], a[4]);
+ assert(length % 8 == 0);
+
+ for (i = 8; i + 8 <= length; i += 8) {
+ const int j = (i - 2) >> 1;
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i]);
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
+ const __m128i w = _mm_set_epi32(j + 3, j + 2, j + 1, j);
+ const __m128i a2 = _mm_hadd_epi32(a0, a1);
+ const __m128i mul = _mm_mullo_epi32(a2, w);
+ cost = _mm_add_epi32(mul, cost);
+ }
+ return HorizontalSum_SSE41(cost);
+}
+
+static uint32_t ExtraCostCombined_SSE41(const uint32_t* const a,
+ const uint32_t* const b, int length) {
+ int i;
+ __m128i cost = _mm_add_epi32(_mm_set_epi32(2 * a[7], 2 * a[6], a[5], a[4]),
+ _mm_set_epi32(2 * b[7], 2 * b[6], b[5], b[4]));
+ assert(length % 8 == 0);
+
+ for (i = 8; i + 8 <= length; i += 8) {
+ const int j = (i - 2) >> 1;
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i]);
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
+ const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[i]);
+ const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[i + 4]);
+ const __m128i w = _mm_set_epi32(j + 3, j + 2, j + 1, j);
+ const __m128i a2 = _mm_hadd_epi32(a0, a1);
+ const __m128i b2 = _mm_hadd_epi32(b0, b1);
+ const __m128i mul = _mm_mullo_epi32(_mm_add_epi32(a2, b2), w);
+ cost = _mm_add_epi32(mul, cost);
+ }
+ return HorizontalSum_SSE41(cost);
+}
//------------------------------------------------------------------------------
// Subtract-Green Transform
@@ -44,6 +89,9 @@ static void SubtractGreenFromBlueAndRed_SSE41(uint32_t* argb_data,
//------------------------------------------------------------------------------
// Color Transform
+// For sign-extended multiplying constants, pre-shifted by 5:
+#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5)
+
#define MK_CST_16(HI, LO) \
_mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff)))
@@ -143,6 +191,8 @@ static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride,
extern void VP8LEncDspInitSSE41(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE41(void) {
+ VP8LExtraCost = ExtraCost_SSE41;
+ VP8LExtraCostCombined = ExtraCostCombined_SSE41;
VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_SSE41;
VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE41;
VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE41;
diff --git a/src/dsp/lossless_neon.c b/src/dsp/lossless_neon.c
index 89e3e013..e9960db3 100644
--- a/src/dsp/lossless_neon.c
+++ b/src/dsp/lossless_neon.c
@@ -146,9 +146,9 @@ static void ConvertBGRAToRGB_NEON(const uint32_t* src,
#define LOAD_U32P_AS_U8(IN) vreinterpret_u8_u32(vld1_u32((IN)))
#define LOADQ_U32_AS_U8(IN) vreinterpretq_u8_u32(vdupq_n_u32((IN)))
#define LOADQ_U32P_AS_U8(IN) vreinterpretq_u8_u32(vld1q_u32((IN)))
-#define GET_U8_AS_U32(IN) vget_lane_u32(vreinterpret_u32_u8((IN)), 0);
-#define GETQ_U8_AS_U32(IN) vgetq_lane_u32(vreinterpretq_u32_u8((IN)), 0);
-#define STOREQ_U8_AS_U32P(OUT, IN) vst1q_u32((OUT), vreinterpretq_u32_u8((IN)));
+#define GET_U8_AS_U32(IN) vget_lane_u32(vreinterpret_u32_u8((IN)), 0)
+#define GETQ_U8_AS_U32(IN) vgetq_lane_u32(vreinterpretq_u32_u8((IN)), 0)
+#define STOREQ_U8_AS_U32P(OUT, IN) vst1q_u32((OUT), vreinterpretq_u32_u8((IN)))
#define ROTATE32_LEFT(L) vextq_u8((L), (L), 12) // D|C|B|A -> C|B|A|D
static WEBP_INLINE uint8x8_t Average2_u8_NEON(uint32_t a0, uint32_t a1) {
@@ -498,7 +498,7 @@ static void PredictorAdd13_NEON(const uint32_t* in, const uint32_t* upper,
// vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use
// non-standard versions there.
-#if defined(__APPLE__) && defined(__aarch64__) && \
+#if defined(__APPLE__) && WEBP_AARCH64 && \
defined(__apple_build_version__) && (__apple_build_version__< 6020037)
#define USE_VTBLQ
#endif
diff --git a/src/dsp/mips_macro.h b/src/dsp/mips_macro.h
index 44aba9b7..e810d3d3 100644
--- a/src/dsp/mips_macro.h
+++ b/src/dsp/mips_macro.h
@@ -45,28 +45,38 @@
"ulw %[" #O2 "], " #I3 "+" XSTR(I9) "*" #I7 "(%[" #I0 "]) \n\t" \
"ulw %[" #O3 "], " #I4 "+" XSTR(I9) "*" #I8 "(%[" #I0 "]) \n\t"
+
+// O - output
+// I - input (macro doesn't change it so it should be different from I)
+#define MUL_SHIFT_C1(O, I) \
+ "mul %[" #O "], %[" #I "], %[kC1] \n\t" \
+ "sra %[" #O "], %[" #O "], 16 \n\t" \
+ "addu %[" #O "], %[" #O "], %[" #I "] \n\t"
+#define MUL_SHIFT_C2(O, I) \
+ "mul %[" #O "], %[" #I "], %[kC2] \n\t" \
+ "sra %[" #O "], %[" #O "], 16 \n\t"
+
+// Same as #define MUL_SHIFT_C1 but I and O are the same. It stores the
+// intermediary result in TMP.
+#define MUL_SHIFT_C1_IO(IO, TMP) \
+ "mul %[" #TMP "], %[" #IO "], %[kC1] \n\t" \
+ "sra %[" #TMP "], %[" #TMP "], 16 \n\t" \
+ "addu %[" #IO "], %[" #TMP "], %[" #IO "] \n\t"
+
// O - output
// IO - input/output
// I - input (macro doesn't change it)
#define MUL_SHIFT_SUM(O0, O1, O2, O3, O4, O5, O6, O7, \
IO0, IO1, IO2, IO3, \
I0, I1, I2, I3, I4, I5, I6, I7) \
- "mul %[" #O0 "], %[" #I0 "], %[kC2] \n\t" \
- "mul %[" #O1 "], %[" #I0 "], %[kC1] \n\t" \
- "mul %[" #O2 "], %[" #I1 "], %[kC2] \n\t" \
- "mul %[" #O3 "], %[" #I1 "], %[kC1] \n\t" \
- "mul %[" #O4 "], %[" #I2 "], %[kC2] \n\t" \
- "mul %[" #O5 "], %[" #I2 "], %[kC1] \n\t" \
- "mul %[" #O6 "], %[" #I3 "], %[kC2] \n\t" \
- "mul %[" #O7 "], %[" #I3 "], %[kC1] \n\t" \
- "sra %[" #O0 "], %[" #O0 "], 16 \n\t" \
- "sra %[" #O1 "], %[" #O1 "], 16 \n\t" \
- "sra %[" #O2 "], %[" #O2 "], 16 \n\t" \
- "sra %[" #O3 "], %[" #O3 "], 16 \n\t" \
- "sra %[" #O4 "], %[" #O4 "], 16 \n\t" \
- "sra %[" #O5 "], %[" #O5 "], 16 \n\t" \
- "sra %[" #O6 "], %[" #O6 "], 16 \n\t" \
- "sra %[" #O7 "], %[" #O7 "], 16 \n\t" \
+ MUL_SHIFT_C2(O0, I0) \
+ MUL_SHIFT_C1(O1, I0) \
+ MUL_SHIFT_C2(O2, I1) \
+ MUL_SHIFT_C1(O3, I1) \
+ MUL_SHIFT_C2(O4, I2) \
+ MUL_SHIFT_C1(O5, I2) \
+ MUL_SHIFT_C2(O6, I3) \
+ MUL_SHIFT_C1(O7, I3) \
"addu %[" #IO0 "], %[" #IO0 "], %[" #I4 "] \n\t" \
"addu %[" #IO1 "], %[" #IO1 "], %[" #I5 "] \n\t" \
"subu %[" #IO2 "], %[" #IO2 "], %[" #I6 "] \n\t" \
diff --git a/src/dsp/msa_macro.h b/src/dsp/msa_macro.h
index 51f6c643..90adbbc3 100644
--- a/src/dsp/msa_macro.h
+++ b/src/dsp/msa_macro.h
@@ -73,27 +73,25 @@
#define ST_UW(...) ST_W(v4u32, __VA_ARGS__)
#define ST_SW(...) ST_W(v4i32, __VA_ARGS__)
-#define MSA_LOAD_FUNC(TYPE, INSTR, FUNC_NAME) \
- static inline TYPE FUNC_NAME(const void* const psrc) { \
- const uint8_t* const psrc_m = (const uint8_t*)psrc; \
- TYPE val_m; \
- asm volatile ( \
- "" #INSTR " %[val_m], %[psrc_m] \n\t" \
- : [val_m] "=r" (val_m) \
- : [psrc_m] "m" (*psrc_m)); \
- return val_m; \
+#define MSA_LOAD_FUNC(TYPE, INSTR, FUNC_NAME) \
+ static inline TYPE FUNC_NAME(const void* const psrc) { \
+ const uint8_t* const psrc_m = (const uint8_t*)psrc; \
+ TYPE val_m; \
+ __asm__ volatile("" #INSTR " %[val_m], %[psrc_m] \n\t" \
+ : [val_m] "=r"(val_m) \
+ : [psrc_m] "m"(*psrc_m)); \
+ return val_m; \
}
#define MSA_LOAD(psrc, FUNC_NAME) FUNC_NAME(psrc)
-#define MSA_STORE_FUNC(TYPE, INSTR, FUNC_NAME) \
- static inline void FUNC_NAME(TYPE val, void* const pdst) { \
- uint8_t* const pdst_m = (uint8_t*)pdst; \
- TYPE val_m = val; \
- asm volatile ( \
- " " #INSTR " %[val_m], %[pdst_m] \n\t" \
- : [pdst_m] "=m" (*pdst_m) \
- : [val_m] "r" (val_m)); \
+#define MSA_STORE_FUNC(TYPE, INSTR, FUNC_NAME) \
+ static inline void FUNC_NAME(TYPE val, void* const pdst) { \
+ uint8_t* const pdst_m = (uint8_t*)pdst; \
+ TYPE val_m = val; \
+ __asm__ volatile(" " #INSTR " %[val_m], %[pdst_m] \n\t" \
+ : [pdst_m] "=m"(*pdst_m) \
+ : [val_m] "r"(val_m)); \
}
#define MSA_STORE(val, pdst, FUNC_NAME) FUNC_NAME(val, pdst)
diff --git a/src/dsp/neon.h b/src/dsp/neon.h
index c591f9b9..14acb404 100644
--- a/src/dsp/neon.h
+++ b/src/dsp/neon.h
@@ -21,7 +21,7 @@
// Right now, some intrinsics functions seem slower, so we disable them
// everywhere except newer clang/gcc or aarch64 where the inline assembly is
// incompatible.
-#if LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,9) || defined(__aarch64__)
+#if LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 9) || WEBP_AARCH64
#define WEBP_USE_INTRINSICS // use intrinsics when possible
#endif
@@ -46,7 +46,7 @@
// if using intrinsics, this flag avoids some functions that make gcc-4.6.3
// crash ("internal compiler error: in immed_double_const, at emit-rtl.").
// (probably similar to gcc.gnu.org/bugzilla/show_bug.cgi?id=48183)
-#if !(LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
+#if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || WEBP_AARCH64)
#define WORK_AROUND_GCC
#endif
diff --git a/src/dsp/quant.h b/src/dsp/quant.h
index fc099bf9..dcbc11c7 100644
--- a/src/dsp/quant.h
+++ b/src/dsp/quant.h
@@ -22,7 +22,7 @@
#define IsFlat IsFlat_NEON
static uint32_t horizontal_add_uint32x4(const uint32x4_t a) {
-#if defined(__aarch64__)
+#if WEBP_AARCH64
return vaddvq_u32(a);
#else
const uint64x2_t b = vpaddlq_u32(a);
@@ -36,8 +36,9 @@ static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks,
int thresh) {
const int16x8_t tst_ones = vdupq_n_s16(-1);
uint32x4_t sum = vdupq_n_u32(0);
+ int i;
- for (int i = 0; i < num_blocks; ++i) {
+ for (i = 0; i < num_blocks; ++i) {
// Set DC to zero.
const int16x8_t a_0 = vsetq_lane_s16(0, vld1q_s16(levels), 0);
const int16x8_t a_1 = vld1q_s16(levels + 8);
diff --git a/src/dsp/rescaler.c b/src/dsp/rescaler.c
index 14620ce4..325d8be1 100644
--- a/src/dsp/rescaler.c
+++ b/src/dsp/rescaler.c
@@ -197,6 +197,7 @@ WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
+extern VP8CPUInfo VP8GetCPUInfo;
extern void WebPRescalerDspInitSSE2(void);
extern void WebPRescalerDspInitMIPS32(void);
extern void WebPRescalerDspInitMIPSdspR2(void);
diff --git a/src/dsp/rescaler_neon.c b/src/dsp/rescaler_neon.c
index b976a852..957a92db 100644
--- a/src/dsp/rescaler_neon.c
+++ b/src/dsp/rescaler_neon.c
@@ -32,7 +32,7 @@
#define STORE_32x8(SRC0, SRC1, DST) do { \
vst1q_u32((DST) + 0, SRC0); \
vst1q_u32((DST) + 4, SRC1); \
-} while (0);
+} while (0)
#if (WEBP_RESCALER_RFIX == 32)
#define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1))
diff --git a/src/dsp/ssim.c b/src/dsp/ssim.c
index f85c2e6e..9a1341ed 100644
--- a/src/dsp/ssim.c
+++ b/src/dsp/ssim.c
@@ -137,6 +137,7 @@ VP8SSIMGetClippedFunc VP8SSIMGetClipped;
VP8AccumulateSSEFunc VP8AccumulateSSE;
#endif
+extern VP8CPUInfo VP8GetCPUInfo;
extern void VP8SSIMDspInitSSE2(void);
WEBP_DSP_INIT_FUNC(VP8SSIMDspInit) {
diff --git a/src/dsp/upsampling.c b/src/dsp/upsampling.c
index 87f771f3..983b9c42 100644
--- a/src/dsp/upsampling.c
+++ b/src/dsp/upsampling.c
@@ -215,6 +215,7 @@ static void EmptyYuv444Func(const uint8_t* y,
WebPYUV444Converter WebPYUV444Converters[MODE_LAST];
+extern VP8CPUInfo VP8GetCPUInfo;
extern void WebPInitYUV444ConvertersMIPSdspR2(void);
extern void WebPInitYUV444ConvertersSSE2(void);
extern void WebPInitYUV444ConvertersSSE41(void);
diff --git a/src/dsp/upsampling_neon.c b/src/dsp/upsampling_neon.c
index 6ba71a7d..bbc000ca 100644
--- a/src/dsp/upsampling_neon.c
+++ b/src/dsp/upsampling_neon.c
@@ -111,7 +111,7 @@ static const int16_t kCoeffs1[4] = { 19077, 26149, 6419, 13320 };
vst4_u8(out, v255_r_g_b); \
} while (0)
-#if !defined(WEBP_SWAP_16BIT_CSP)
+#if (WEBP_SWAP_16BIT_CSP == 0)
#define ZIP_U8(lo, hi) vzip_u8((lo), (hi))
#else
#define ZIP_U8(lo, hi) vzip_u8((hi), (lo))
diff --git a/src/dsp/upsampling_sse2.c b/src/dsp/upsampling_sse2.c
index 08b6d0b1..77b4f722 100644
--- a/src/dsp/upsampling_sse2.c
+++ b/src/dsp/upsampling_sse2.c
@@ -58,7 +58,7 @@
} while (0)
// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
-#define UPSAMPLE_32PIXELS(r1, r2, out) { \
+#define UPSAMPLE_32PIXELS(r1, r2, out) do { \
const __m128i one = _mm_set1_epi8(1); \
const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \
const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \
@@ -85,7 +85,7 @@
/* pack the alternate pixels */ \
PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
-}
+} while (0)
// Turn the macro into a function for reducing code-size when non-critical
static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[],
@@ -229,11 +229,11 @@ static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
} \
}
-YUV444_FUNC(Yuv444ToRgba_SSE2, VP8YuvToRgba32_SSE2, WebPYuv444ToRgba_C, 4);
-YUV444_FUNC(Yuv444ToBgra_SSE2, VP8YuvToBgra32_SSE2, WebPYuv444ToBgra_C, 4);
+YUV444_FUNC(Yuv444ToRgba_SSE2, VP8YuvToRgba32_SSE2, WebPYuv444ToRgba_C, 4)
+YUV444_FUNC(Yuv444ToBgra_SSE2, VP8YuvToBgra32_SSE2, WebPYuv444ToBgra_C, 4)
#if !defined(WEBP_REDUCE_CSP)
-YUV444_FUNC(Yuv444ToRgb_SSE2, VP8YuvToRgb32_SSE2, WebPYuv444ToRgb_C, 3);
-YUV444_FUNC(Yuv444ToBgr_SSE2, VP8YuvToBgr32_SSE2, WebPYuv444ToBgr_C, 3);
+YUV444_FUNC(Yuv444ToRgb_SSE2, VP8YuvToRgb32_SSE2, WebPYuv444ToRgb_C, 3)
+YUV444_FUNC(Yuv444ToBgr_SSE2, VP8YuvToBgr32_SSE2, WebPYuv444ToBgr_C, 3)
YUV444_FUNC(Yuv444ToArgb_SSE2, VP8YuvToArgb32_SSE2, WebPYuv444ToArgb_C, 4)
YUV444_FUNC(Yuv444ToRgba4444_SSE2, VP8YuvToRgba444432_SSE2, \
WebPYuv444ToRgba4444_C, 2)
diff --git a/src/dsp/upsampling_sse41.c b/src/dsp/upsampling_sse41.c
index 648d4560..e38c88d5 100644
--- a/src/dsp/upsampling_sse41.c
+++ b/src/dsp/upsampling_sse41.c
@@ -60,7 +60,7 @@
} while (0)
// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
-#define UPSAMPLE_32PIXELS(r1, r2, out) { \
+#define UPSAMPLE_32PIXELS(r1, r2, out) do { \
const __m128i one = _mm_set1_epi8(1); \
const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \
const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \
@@ -87,7 +87,7 @@
/* pack the alternate pixels */ \
PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
-}
+} while (0)
// Turn the macro into a function for reducing code-size when non-critical
static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[],
@@ -217,8 +217,8 @@ static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
}
#if !defined(WEBP_REDUCE_CSP)
-YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3);
-YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3);
+YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3)
+YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3)
#endif // WEBP_REDUCE_CSP
WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE41(void) {
diff --git a/src/dsp/yuv.c b/src/dsp/yuv.c
index d16c13d3..8a04b85d 100644
--- a/src/dsp/yuv.c
+++ b/src/dsp/yuv.c
@@ -70,6 +70,7 @@ void WebPSamplerProcessPlane(const uint8_t* y, int y_stride,
WebPSamplerRowFunc WebPSamplers[MODE_LAST];
+extern VP8CPUInfo VP8GetCPUInfo;
extern void WebPInitSamplersSSE2(void);
extern void WebPInitSamplersSSE41(void);
extern void WebPInitSamplersMIPS32(void);
diff --git a/src/enc/alpha_enc.c b/src/enc/alpha_enc.c
index 7d205586..c11a261c 100644
--- a/src/enc/alpha_enc.c
+++ b/src/enc/alpha_enc.c
@@ -20,6 +20,7 @@
#include "src/utils/filters_utils.h"
#include "src/utils/quant_levels_utils.h"
#include "src/utils/utils.h"
+#include "src/webp/encode.h"
#include "src/webp/format_constants.h"
// -----------------------------------------------------------------------------
@@ -55,7 +56,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
WebPConfig config;
WebPPicture picture;
- WebPPictureInit(&picture);
+ if (!WebPPictureInit(&picture)) return 0;
picture.width = width;
picture.height = height;
picture.use_argb = 1;
@@ -66,7 +67,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
WebPDispatchAlphaToGreen(data, width, picture.width, picture.height,
picture.argb, picture.argb_stride);
- WebPConfigInit(&config);
+ if (!WebPConfigInit(&config)) return 0;
config.lossless = 1;
// Enable exact, or it would alter RGB values of transparent alpha, which is
// normally OK but not here since we are not encoding the input image but an
@@ -83,11 +84,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
(use_quality_100 && effort_level == 6) ? 100 : 8.f * effort_level;
assert(config.quality >= 0 && config.quality <= 100.f);
- // TODO(urvang): Temporary fix to avoid generating images that trigger
- // a decoder bug related to alpha with color cache.
- // See: https://code.google.com/p/webp/issues/detail?id=239
- // Need to re-enable this later.
- ok = VP8LEncodeStream(&config, &picture, bw, /*use_cache=*/0);
+ ok = VP8LEncodeStream(&config, &picture, bw);
WebPPictureFree(&picture);
ok = ok && !bw->error_;
if (!ok) {
@@ -141,6 +138,11 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
!reduce_levels, &tmp_bw, &result->stats);
if (ok) {
output = VP8LBitWriterFinish(&tmp_bw);
+ if (tmp_bw.error_) {
+ VP8LBitWriterWipeOut(&tmp_bw);
+ memset(&result->bw, 0, sizeof(result->bw));
+ return 0;
+ }
output_size = VP8LBitWriterNumBytes(&tmp_bw);
if (output_size > data_size) {
// compressed size is larger than source! Revert to uncompressed mode.
@@ -314,11 +316,11 @@ static int EncodeAlpha(VP8Encoder* const enc,
assert(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST);
if (quality < 0 || quality > 100) {
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
if (method < ALPHA_NO_COMPRESSION || method > ALPHA_LOSSLESS_COMPRESSION) {
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
if (method == ALPHA_NO_COMPRESSION) {
@@ -328,7 +330,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
quant_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
if (quant_alpha == NULL) {
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
// Extract alpha data (width x height) from raw_data (stride x height).
@@ -348,6 +350,9 @@ static int EncodeAlpha(VP8Encoder* const enc,
ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method,
filter, reduce_levels, effort_level, output,
output_size, pic->stats);
+ if (!ok) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); // imprecise
+ }
#if !defined(WEBP_DISABLE_STATS)
if (pic->stats != NULL) { // need stats?
pic->stats->coded_size += (int)(*output_size);
@@ -407,7 +412,7 @@ int VP8EncStartAlpha(VP8Encoder* const enc) {
WebPWorker* const worker = &enc->alpha_worker_;
// Makes sure worker is good to go.
if (!WebPGetWorkerInterface()->Reset(worker)) {
- return 0;
+ return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
WebPGetWorkerInterface()->Launch(worker);
return 1;
diff --git a/src/enc/analysis_enc.c b/src/enc/analysis_enc.c
index a0001ac0..962eaa99 100644
--- a/src/enc/analysis_enc.c
+++ b/src/enc/analysis_enc.c
@@ -474,6 +474,10 @@ int VP8EncAnalyze(VP8Encoder* const enc) {
} else { // Use only one default segment.
ResetAllMBInfo(enc);
}
+ if (!ok) {
+ return WebPEncodingSetError(enc->pic_,
+ VP8_ENC_ERROR_OUT_OF_MEMORY); // imprecise
+ }
return ok;
}
diff --git a/src/enc/backward_references_enc.c b/src/enc/backward_references_enc.c
index 49a0fac0..dc98bf17 100644
--- a/src/enc/backward_references_enc.c
+++ b/src/enc/backward_references_enc.c
@@ -283,8 +283,7 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
hash_to_first_index =
(int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index));
if (hash_to_first_index == NULL) {
- WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
percent_range = remaining_percent / 2;
@@ -1050,8 +1049,7 @@ int VP8LGetBackwardReferences(
refs_best = GetBackwardReferencesLowEffort(
width, height, argb, cache_bits_best, hash_chain, refs);
if (refs_best == NULL) {
- WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
// Set it in first position.
BackwardRefsSwap(refs_best, &refs[0]);
@@ -1059,8 +1057,7 @@ int VP8LGetBackwardReferences(
if (!GetBackwardReferences(width, height, argb, quality, lz77_types_to_try,
cache_bits_max, do_no_cache, hash_chain, refs,
cache_bits_best)) {
- WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
}
diff --git a/src/enc/frame_enc.c b/src/enc/frame_enc.c
index b93d9e5b..01860ca7 100644
--- a/src/enc/frame_enc.c
+++ b/src/enc/frame_enc.c
@@ -578,7 +578,7 @@ static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt,
uint64_t size = 0;
uint64_t size_p0 = 0;
uint64_t distortion = 0;
- const uint64_t pixel_count = nb_mbs * 384;
+ const uint64_t pixel_count = (uint64_t)nb_mbs * 384;
VP8IteratorInit(enc, &it);
SetLoopParams(enc, s->q);
@@ -689,7 +689,7 @@ static int PreLoopInitialize(VP8Encoder* const enc) {
}
if (!ok) {
VP8EncFreeBitWriters(enc); // malloc error occurred
- WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
return ok;
}
@@ -719,6 +719,7 @@ static int PostLoopFinalize(VP8EncIterator* const it, int ok) {
} else {
// Something bad happened -> need to do some memory cleanup.
VP8EncFreeBitWriters(enc);
+ return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
return ok;
}
@@ -754,6 +755,11 @@ int VP8EncLoop(VP8Encoder* const enc) {
// *then* decide how to code the skip decision if there's one.
if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) {
CodeResiduals(it.bw_, &it, &info);
+ if (it.bw_->error_) {
+ // enc->pic_->error_code is set in PostLoopFinalize().
+ ok = 0;
+ break;
+ }
} else { // reset predictors after a skip
ResetAfterSkip(&it);
}
@@ -783,7 +789,7 @@ int VP8EncTokenLoop(VP8Encoder* const enc) {
VP8EncIterator it;
VP8EncProba* const proba = &enc->proba_;
const VP8RDLevel rd_opt = enc->rd_opt_level_;
- const uint64_t pixel_count = enc->mb_w_ * enc->mb_h_ * 384;
+ const uint64_t pixel_count = (uint64_t)enc->mb_w_ * enc->mb_h_ * 384;
PassStats stats;
int ok;
diff --git a/src/enc/histogram_enc.c b/src/enc/histogram_enc.c
index 8418def2..3ca67b3a 100644
--- a/src/enc/histogram_enc.c
+++ b/src/enc/histogram_enc.c
@@ -358,15 +358,17 @@ static WEBP_INLINE float GetCombinedEntropy(const uint32_t* const X,
// Estimates the Entropy + Huffman + other block overhead size cost.
float VP8LHistogramEstimateBits(VP8LHistogram* const p) {
- return
- PopulationCost(p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_),
- NULL, &p->is_used_[0])
- + PopulationCost(p->red_, NUM_LITERAL_CODES, NULL, &p->is_used_[1])
- + PopulationCost(p->blue_, NUM_LITERAL_CODES, NULL, &p->is_used_[2])
- + PopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL, &p->is_used_[3])
- + PopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL, &p->is_used_[4])
- + VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES)
- + VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES);
+ return PopulationCost(p->literal_,
+ VP8LHistogramNumCodes(p->palette_code_bits_), NULL,
+ &p->is_used_[0]) +
+ PopulationCost(p->red_, NUM_LITERAL_CODES, NULL, &p->is_used_[1]) +
+ PopulationCost(p->blue_, NUM_LITERAL_CODES, NULL, &p->is_used_[2]) +
+ PopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL, &p->is_used_[3]) +
+ PopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL,
+ &p->is_used_[4]) +
+ (float)VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES,
+ NUM_LENGTH_CODES) +
+ (float)VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES);
}
// -----------------------------------------------------------------------------
@@ -381,9 +383,9 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
*cost += GetCombinedEntropy(a->literal_, b->literal_,
VP8LHistogramNumCodes(palette_code_bits),
a->is_used_[0], b->is_used_[0], 0);
- *cost += VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES,
- b->literal_ + NUM_LITERAL_CODES,
- NUM_LENGTH_CODES);
+ *cost += (float)VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES,
+ b->literal_ + NUM_LITERAL_CODES,
+ NUM_LENGTH_CODES);
if (*cost > cost_threshold) return 0;
if (a->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM &&
@@ -417,8 +419,8 @@ static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
*cost +=
GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES,
a->is_used_[4], b->is_used_[4], 0);
- *cost +=
- VP8LExtraCostCombined(a->distance_, b->distance_, NUM_DISTANCE_CODES);
+ *cost += (float)VP8LExtraCostCombined(a->distance_, b->distance_,
+ NUM_DISTANCE_CODES);
if (*cost > cost_threshold) return 0;
return 1;
@@ -506,11 +508,11 @@ static void UpdateHistogramCost(VP8LHistogram* const h) {
PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, &h->is_used_[3]);
const float distance_cost =
PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) +
- VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
+ (float)VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_);
h->literal_cost_ =
PopulationCost(h->literal_, num_codes, NULL, &h->is_used_[0]) +
- VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES);
+ (float)VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES);
h->red_cost_ =
PopulationCost(h->red_, NUM_LITERAL_CODES, &red_sym, &h->is_used_[1]);
h->blue_cost_ =
@@ -1179,7 +1181,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
int entropy_combine;
uint16_t* const map_tmp =
- WebPSafeMalloc(2 * image_histo_raw_size, sizeof(map_tmp));
+ WebPSafeMalloc(2 * image_histo_raw_size, sizeof(*map_tmp));
uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size;
int num_used = image_histo_raw_size;
if (orig_histo == NULL || map_tmp == NULL) {
diff --git a/src/enc/picture_csp_enc.c b/src/enc/picture_csp_enc.c
index 78c8ca47..a9280e6c 100644
--- a/src/enc/picture_csp_enc.c
+++ b/src/enc/picture_csp_enc.c
@@ -98,6 +98,7 @@ static int kLinearToGammaTab[GAMMA_TAB_SIZE + 1];
static uint16_t kGammaToLinearTab[256];
static volatile int kGammaTablesOk = 0;
static void InitGammaTables(void);
+extern VP8CPUInfo VP8GetCPUInfo;
WEBP_DSP_INIT_FUNC(InitGammaTables) {
if (!kGammaTablesOk) {
@@ -534,7 +535,9 @@ static int ImportYUVAFromRGBA(const uint8_t* r_ptr,
WebPInitConvertARGBToYUV();
InitGammaTables();
- if (tmp_rgb == NULL) return 0; // malloc error
+ if (tmp_rgb == NULL) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ }
// Downsample Y/U/V planes, two rows at a time
for (y = 0; y < (height >> 1); ++y) {
diff --git a/src/enc/picture_enc.c b/src/enc/picture_enc.c
index 3af6383d..5a270354 100644
--- a/src/enc/picture_enc.c
+++ b/src/enc/picture_enc.c
@@ -12,10 +12,10 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
+#include <limits.h>
#include <stdlib.h>
#include "src/enc/vp8i_enc.h"
-#include "src/dsp/dsp.h"
#include "src/utils/utils.h"
//------------------------------------------------------------------------------
diff --git a/src/enc/picture_rescale_enc.c b/src/enc/picture_rescale_enc.c
index 839f91ca..ea90d825 100644
--- a/src/enc/picture_rescale_enc.c
+++ b/src/enc/picture_rescale_enc.c
@@ -137,7 +137,9 @@ int WebPPictureCrop(WebPPicture* pic,
PictureGrabSpecs(pic, &tmp);
tmp.width = width;
tmp.height = height;
- if (!WebPPictureAlloc(&tmp)) return 0;
+ if (!WebPPictureAlloc(&tmp)) {
+ return WebPEncodingSetError(pic, tmp.error_code);
+ }
if (!pic->use_argb) {
const int y_offset = top * pic->y_stride + left;
@@ -212,26 +214,28 @@ int WebPPictureRescale(WebPPicture* picture, int width, int height) {
prev_height = picture->height;
if (!WebPRescalerGetScaledDimensions(
prev_width, prev_height, &width, &height)) {
- return 0;
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
PictureGrabSpecs(picture, &tmp);
tmp.width = width;
tmp.height = height;
- if (!WebPPictureAlloc(&tmp)) return 0;
+ if (!WebPPictureAlloc(&tmp)) {
+ return WebPEncodingSetError(picture, tmp.error_code);
+ }
if (!picture->use_argb) {
work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
if (work == NULL) {
WebPPictureFree(&tmp);
- return 0;
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
// If present, we need to rescale alpha first (for AlphaMultiplyY).
if (picture->a != NULL) {
WebPInitAlphaProcessing();
if (!RescalePlane(picture->a, prev_width, prev_height, picture->a_stride,
tmp.a, width, height, tmp.a_stride, work, 1)) {
- return 0;
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
}
@@ -246,14 +250,14 @@ int WebPPictureRescale(WebPPicture* picture, int width, int height) {
!RescalePlane(picture->v, HALVE(prev_width), HALVE(prev_height),
picture->uv_stride, tmp.v, HALVE(width), HALVE(height),
tmp.uv_stride, work, 1)) {
- return 0;
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
AlphaMultiplyY(&tmp, 1);
} else {
work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
if (work == NULL) {
WebPPictureFree(&tmp);
- return 0;
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
// In order to correctly interpolate colors, we need to apply the alpha
// weighting first (black-matting), scale the RGB values, and remove
@@ -263,7 +267,7 @@ int WebPPictureRescale(WebPPicture* picture, int width, int height) {
if (!RescalePlane((const uint8_t*)picture->argb, prev_width, prev_height,
picture->argb_stride * 4, (uint8_t*)tmp.argb, width,
height, tmp.argb_stride * 4, work, 4)) {
- return 0;
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
AlphaMultiplyARGB(&tmp, 1);
}
diff --git a/src/enc/syntax_enc.c b/src/enc/syntax_enc.c
index e18cf650..9b8f524d 100644
--- a/src/enc/syntax_enc.c
+++ b/src/enc/syntax_enc.c
@@ -258,7 +258,10 @@ static int EmitPartitionsSize(const VP8Encoder* const enc,
buf[3 * p + 1] = (part_size >> 8) & 0xff;
buf[3 * p + 2] = (part_size >> 16) & 0xff;
}
- return p ? pic->writer(buf, 3 * p, pic) : 1;
+ if (p && !pic->writer(buf, 3 * p, pic)) {
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
+ }
+ return 1;
}
//------------------------------------------------------------------------------
@@ -381,6 +384,7 @@ int VP8EncWrite(VP8Encoder* const enc) {
enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size);
ok = ok && WebPReportProgress(pic, final_percent, &enc->percent_);
+ if (!ok) WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
return ok;
}
diff --git a/src/enc/vp8i_enc.h b/src/enc/vp8i_enc.h
index c9927c47..00ff1be7 100644
--- a/src/enc/vp8i_enc.h
+++ b/src/enc/vp8i_enc.h
@@ -31,7 +31,7 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 1
-#define ENC_MIN_VERSION 3
+#define ENC_MIN_VERSION 4
#define ENC_REV_VERSION 0
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
diff --git a/src/enc/vp8l_enc.c b/src/enc/vp8l_enc.c
index cb5549af..40eafa41 100644
--- a/src/enc/vp8l_enc.c
+++ b/src/enc/vp8l_enc.c
@@ -23,6 +23,7 @@
#include "src/enc/vp8li_enc.h"
#include "src/utils/bit_writer_utils.h"
#include "src/utils/huffman_encode_utils.h"
+#include "src/utils/palette.h"
#include "src/utils/utils.h"
#include "src/webp/encode.h"
#include "src/webp/format_constants.h"
@@ -30,300 +31,6 @@
// Maximum number of histogram images (sub-blocks).
#define MAX_HUFF_IMAGE_SIZE 2600
-// Palette reordering for smaller sum of deltas (and for smaller storage).
-
-static int PaletteCompareColorsForQsort(const void* p1, const void* p2) {
- const uint32_t a = WebPMemToUint32((uint8_t*)p1);
- const uint32_t b = WebPMemToUint32((uint8_t*)p2);
- assert(a != b);
- return (a < b) ? -1 : 1;
-}
-
-static WEBP_INLINE uint32_t PaletteComponentDistance(uint32_t v) {
- return (v <= 128) ? v : (256 - v);
-}
-
-// Computes a value that is related to the entropy created by the
-// palette entry diff.
-//
-// Note that the last & 0xff is a no-operation in the next statement, but
-// removed by most compilers and is here only for regularity of the code.
-static WEBP_INLINE uint32_t PaletteColorDistance(uint32_t col1, uint32_t col2) {
- const uint32_t diff = VP8LSubPixels(col1, col2);
- const int kMoreWeightForRGBThanForAlpha = 9;
- uint32_t score;
- score = PaletteComponentDistance((diff >> 0) & 0xff);
- score += PaletteComponentDistance((diff >> 8) & 0xff);
- score += PaletteComponentDistance((diff >> 16) & 0xff);
- score *= kMoreWeightForRGBThanForAlpha;
- score += PaletteComponentDistance((diff >> 24) & 0xff);
- return score;
-}
-
-static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
- const uint32_t tmp = *col1;
- *col1 = *col2;
- *col2 = tmp;
-}
-
-static WEBP_INLINE int SearchColorNoIdx(const uint32_t sorted[], uint32_t color,
- int num_colors) {
- int low = 0, hi = num_colors;
- if (sorted[low] == color) return low; // loop invariant: sorted[low] != color
- while (1) {
- const int mid = (low + hi) >> 1;
- if (sorted[mid] == color) {
- return mid;
- } else if (sorted[mid] < color) {
- low = mid;
- } else {
- hi = mid;
- }
- }
- assert(0);
- return 0;
-}
-
-// The palette has been sorted by alpha. This function checks if the other
-// components of the palette have a monotonic development with regards to
-// position in the palette. If all have monotonic development, there is
-// no benefit to re-organize them greedily. A monotonic development
-// would be spotted in green-only situations (like lossy alpha) or gray-scale
-// images.
-static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette,
- int num_colors) {
- uint32_t predict = 0x000000;
- int i;
- uint8_t sign_found = 0x00;
- for (i = 0; i < num_colors; ++i) {
- const uint32_t diff = VP8LSubPixels(palette[i], predict);
- const uint8_t rd = (diff >> 16) & 0xff;
- const uint8_t gd = (diff >> 8) & 0xff;
- const uint8_t bd = (diff >> 0) & 0xff;
- if (rd != 0x00) {
- sign_found |= (rd < 0x80) ? 1 : 2;
- }
- if (gd != 0x00) {
- sign_found |= (gd < 0x80) ? 8 : 16;
- }
- if (bd != 0x00) {
- sign_found |= (bd < 0x80) ? 64 : 128;
- }
- predict = palette[i];
- }
- return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
-}
-
-static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
- int num_colors, uint32_t* const palette) {
- uint32_t predict = 0x00000000;
- int i, k;
- memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
- if (!PaletteHasNonMonotonousDeltas(palette_sorted, num_colors)) return;
- // Find greedily always the closest color of the predicted color to minimize
- // deltas in the palette. This reduces storage needs since the
- // palette is stored with delta encoding.
- for (i = 0; i < num_colors; ++i) {
- int best_ix = i;
- uint32_t best_score = ~0U;
- for (k = i; k < num_colors; ++k) {
- const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
- if (best_score > cur_score) {
- best_score = cur_score;
- best_ix = k;
- }
- }
- SwapColor(&palette[best_ix], &palette[i]);
- predict = palette[i];
- }
-}
-
-// Sort palette in increasing order and prepare an inverse mapping array.
-static void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
- uint32_t sorted[], uint32_t idx_map[]) {
- uint32_t i;
- memcpy(sorted, palette, num_colors * sizeof(*sorted));
- qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
- for (i = 0; i < num_colors; ++i) {
- idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
- }
-}
-
-// -----------------------------------------------------------------------------
-// Modified Zeng method from "A Survey on Palette Reordering
-// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
-// Pinho and Antonio J. R. Neves.
-
-// Finds the biggest cooccurrence in the matrix.
-static void CoOccurrenceFindMax(const uint32_t* const cooccurrence,
- uint32_t num_colors, uint8_t* const c1,
- uint8_t* const c2) {
- // Find the index that is most frequently located adjacent to other
- // (different) indexes.
- uint32_t best_sum = 0u;
- uint32_t i, j, best_cooccurrence;
- *c1 = 0u;
- for (i = 0; i < num_colors; ++i) {
- uint32_t sum = 0;
- for (j = 0; j < num_colors; ++j) sum += cooccurrence[i * num_colors + j];
- if (sum > best_sum) {
- best_sum = sum;
- *c1 = i;
- }
- }
- // Find the index that is most frequently found adjacent to *c1.
- *c2 = 0u;
- best_cooccurrence = 0u;
- for (i = 0; i < num_colors; ++i) {
- if (cooccurrence[*c1 * num_colors + i] > best_cooccurrence) {
- best_cooccurrence = cooccurrence[*c1 * num_colors + i];
- *c2 = i;
- }
- }
- assert(*c1 != *c2);
-}
-
-// Builds the cooccurrence matrix
-static int CoOccurrenceBuild(const WebPPicture* const pic,
- const uint32_t* const palette, uint32_t num_colors,
- uint32_t* cooccurrence) {
- uint32_t *lines, *line_top, *line_current, *line_tmp;
- int x, y;
- const uint32_t* src = pic->argb;
- uint32_t prev_pix = ~src[0];
- uint32_t prev_idx = 0u;
- uint32_t idx_map[MAX_PALETTE_SIZE] = {0};
- uint32_t palette_sorted[MAX_PALETTE_SIZE];
- lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines));
- if (lines == NULL) {
- WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
- return 0;
- }
- line_top = &lines[0];
- line_current = &lines[pic->width];
- PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map);
- for (y = 0; y < pic->height; ++y) {
- for (x = 0; x < pic->width; ++x) {
- const uint32_t pix = src[x];
- if (pix != prev_pix) {
- prev_idx = idx_map[SearchColorNoIdx(palette_sorted, pix, num_colors)];
- prev_pix = pix;
- }
- line_current[x] = prev_idx;
- // 4-connectivity is what works best as mentioned in "On the relation
- // between Memon's and the modified Zeng's palette reordering methods".
- if (x > 0 && prev_idx != line_current[x - 1]) {
- const uint32_t left_idx = line_current[x - 1];
- ++cooccurrence[prev_idx * num_colors + left_idx];
- ++cooccurrence[left_idx * num_colors + prev_idx];
- }
- if (y > 0 && prev_idx != line_top[x]) {
- const uint32_t top_idx = line_top[x];
- ++cooccurrence[prev_idx * num_colors + top_idx];
- ++cooccurrence[top_idx * num_colors + prev_idx];
- }
- }
- line_tmp = line_top;
- line_top = line_current;
- line_current = line_tmp;
- src += pic->argb_stride;
- }
- WebPSafeFree(lines);
- return 1;
-}
-
-struct Sum {
- uint8_t index;
- uint32_t sum;
-};
-
-// Implements the modified Zeng method from "A Survey on Palette Reordering
-// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
-// Pinho and Antonio J. R. Neves.
-static int PaletteSortModifiedZeng(
- const WebPPicture* const pic, const uint32_t* const palette_sorted,
- uint32_t num_colors, uint32_t* const palette) {
- uint32_t i, j, ind;
- uint8_t remapping[MAX_PALETTE_SIZE];
- uint32_t* cooccurrence;
- struct Sum sums[MAX_PALETTE_SIZE];
- uint32_t first, last;
- uint32_t num_sums;
- // TODO(vrabaud) check whether one color images should use palette or not.
- if (num_colors <= 1) return 1;
- // Build the co-occurrence matrix.
- cooccurrence =
- (uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence));
- if (cooccurrence == NULL) {
- WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
- return 0;
- }
- if (!CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence)) {
- WebPSafeFree(cooccurrence);
- return 0;
- }
-
- // Initialize the mapping list with the two best indices.
- CoOccurrenceFindMax(cooccurrence, num_colors, &remapping[0], &remapping[1]);
-
- // We need to append and prepend to the list of remapping. To this end, we
- // actually define the next start/end of the list as indices in a vector (with
- // a wrap around when the end is reached).
- first = 0;
- last = 1;
- num_sums = num_colors - 2; // -2 because we know the first two values
- if (num_sums > 0) {
- // Initialize the sums with the first two remappings and find the best one
- struct Sum* best_sum = &sums[0];
- best_sum->index = 0u;
- best_sum->sum = 0u;
- for (i = 0, j = 0; i < num_colors; ++i) {
- if (i == remapping[0] || i == remapping[1]) continue;
- sums[j].index = i;
- sums[j].sum = cooccurrence[i * num_colors + remapping[0]] +
- cooccurrence[i * num_colors + remapping[1]];
- if (sums[j].sum > best_sum->sum) best_sum = &sums[j];
- ++j;
- }
-
- while (num_sums > 0) {
- const uint8_t best_index = best_sum->index;
- // Compute delta to know if we need to prepend or append the best index.
- int32_t delta = 0;
- const int32_t n = num_colors - num_sums;
- for (ind = first, j = 0; (ind + j) % num_colors != last + 1; ++j) {
- const uint16_t l_j = remapping[(ind + j) % num_colors];
- delta += (n - 1 - 2 * (int32_t)j) *
- (int32_t)cooccurrence[best_index * num_colors + l_j];
- }
- if (delta > 0) {
- first = (first == 0) ? num_colors - 1 : first - 1;
- remapping[first] = best_index;
- } else {
- ++last;
- remapping[last] = best_index;
- }
- // Remove best_sum from sums.
- *best_sum = sums[num_sums - 1];
- --num_sums;
- // Update all the sums and find the best one.
- best_sum = &sums[0];
- for (i = 0; i < num_sums; ++i) {
- sums[i].sum += cooccurrence[best_index * num_colors + sums[i].index];
- if (sums[i].sum > best_sum->sum) best_sum = &sums[i];
- }
- }
- }
- assert((last + 1) % num_colors == first);
- WebPSafeFree(cooccurrence);
-
- // Re-map the palette.
- for (i = 0; i < num_colors; ++i) {
- palette[i] = palette_sorted[remapping[(first + i) % num_colors]];
- }
- return 1;
-}
-
// -----------------------------------------------------------------------------
// Palette
@@ -339,13 +46,6 @@ typedef enum {
} EntropyIx;
typedef enum {
- kSortedDefault = 0,
- kMinimizeDelta = 1,
- kModifiedZeng = 2,
- kUnusedPalette = 3,
-} PaletteSorting;
-
-typedef enum {
kHistoAlpha = 0,
kHistoAlphaPred,
kHistoGreen,
@@ -567,7 +267,7 @@ typedef struct {
// +2 because we add a palette sorting configuration for kPalette and
// kPaletteAndSpatial.
-#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2)
+#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2 * kPaletteSortingNum)
static int EncoderAnalyze(VP8LEncoder* const enc,
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX],
@@ -588,13 +288,10 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
assert(pic != NULL && pic->argb != NULL);
// Check whether a palette is possible.
- enc->palette_size_ = WebPGetColorPalette(pic, enc->palette_sorted_);
+ enc->palette_size_ = GetColorPalette(pic, enc->palette_sorted_);
use_palette = (enc->palette_size_ <= MAX_PALETTE_SIZE);
if (!use_palette) {
enc->palette_size_ = 0;
- } else {
- qsort(enc->palette_sorted_, enc->palette_size_,
- sizeof(*enc->palette_sorted_), PaletteCompareColorsForQsort);
}
// Empirical bit sizes.
@@ -627,20 +324,29 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
// a palette.
if ((i != kPalette && i != kPaletteAndSpatial) || use_palette) {
assert(*crunch_configs_size < CRUNCH_CONFIGS_MAX);
- crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
if (use_palette && (i == kPalette || i == kPaletteAndSpatial)) {
- crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
- kMinimizeDelta;
- ++*crunch_configs_size;
- // Also add modified Zeng's method.
- crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
- crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
- kModifiedZeng;
+ int sorting_method;
+ for (sorting_method = 0; sorting_method < kPaletteSortingNum;
+ ++sorting_method) {
+ const PaletteSorting typed_sorting_method =
+ (PaletteSorting)sorting_method;
+ // TODO(vrabaud) kSortedDefault should be tested. It is omitted
+ // for now for backward compatibility.
+ if (typed_sorting_method == kUnusedPalette ||
+ typed_sorting_method == kSortedDefault) {
+ continue;
+ }
+ crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
+ crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
+ typed_sorting_method;
+ ++*crunch_configs_size;
+ }
} else {
+ crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
kUnusedPalette;
+ ++*crunch_configs_size;
}
- ++*crunch_configs_size;
}
}
} else {
@@ -1013,8 +719,7 @@ static int StoreImageToBitMask(
VP8LRefsCursorNext(&c);
}
if (bw->error_) {
- WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
return 1;
}
@@ -1115,10 +820,10 @@ static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
static int EncodeImageInternal(
VP8LBitWriter* const bw, const uint32_t* const argb,
VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width,
- int height, int quality, int low_effort, int use_cache,
- const CrunchConfig* const config, int* cache_bits, int histogram_bits,
- size_t init_byte_position, int* const hdr_size, int* const data_size,
- const WebPPicture* const pic, int percent_range, int* const percent) {
+ int height, int quality, int low_effort, const CrunchConfig* const config,
+ int* cache_bits, int histogram_bits, size_t init_byte_position,
+ int* const hdr_size, int* const data_size, const WebPPicture* const pic,
+ int percent_range, int* const percent) {
const uint32_t histogram_image_xysize =
VP8LSubSampleSize(width, histogram_bits) *
VP8LSubSampleSize(height, histogram_bits);
@@ -1166,13 +871,9 @@ static int EncodeImageInternal(
percent_start += percent_range;
remaining_percent -= percent_range;
- if (use_cache) {
- // If the value is different from zero, it has been set during the
- // palette analysis.
- cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits;
- } else {
- cache_bits_init = 0;
- }
+ // If the value is different from zero, it has been set during the palette
+ // analysis.
+ cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits;
// If several iterations will happen, clone into bw_best.
if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) &&
!VP8LBitWriterClone(bw, &bw_best)) {
@@ -1298,7 +999,10 @@ static int EncodeImageInternal(
}
}
tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
- if (tokens == NULL) goto Error;
+ if (tokens == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
for (i = 0; i < 5 * histogram_image_size; ++i) {
HuffmanTreeCode* const codes = &huffman_codes[i];
StoreHuffmanCode(bw, huff_tree, tokens, codes);
@@ -1449,18 +1153,21 @@ static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw,
const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
const size_t pad = vp8l_size & 1;
const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
+ *coded_size = 0;
+
+ if (bw->error_) {
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ }
if (!WriteRiffHeader(pic, riff_size, vp8l_size) ||
!pic->writer(webpll_data, webpll_size, pic)) {
- WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
}
if (pad) {
const uint8_t pad_byte[1] = { 0 };
if (!pic->writer(pad_byte, 1, pic)) {
- WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
}
}
*coded_size = CHUNK_HEADER_SIZE + riff_size;
@@ -1482,7 +1189,7 @@ static void ClearTransformBuffer(VP8LEncoder* const enc) {
// enc->use_predict_, enc->use_cross_color_
static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
int height) {
- const uint64_t image_size = width * height;
+ const uint64_t image_size = (uint64_t)width * height;
// VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
// pixel in each, plus 2 regular scanlines of bytes.
// TODO(skal): Clean up by using arithmetic in bytes instead of words.
@@ -1492,7 +1199,7 @@ static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
: 0;
const uint64_t transform_data_size =
(enc->use_predict_ || enc->use_cross_color_)
- ? VP8LSubSampleSize(width, enc->transform_bits_) *
+ ? (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) *
VP8LSubSampleSize(height, enc->transform_bits_)
: 0;
const uint64_t max_alignment_in_words =
@@ -1505,8 +1212,7 @@ static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
ClearTransformBuffer(enc);
mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem));
if (mem == NULL) {
- WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
- return 0;
+ return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
enc->transform_mem_ = mem;
enc->transform_mem_size_ = (size_t)mem_size;
@@ -1614,8 +1320,7 @@ static int ApplyPalette(const uint32_t* src, uint32_t src_stride, uint32_t* dst,
int x, y;
if (tmp_row == NULL) {
- WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
if (palette_size < APPLY_PALETTE_GREEDY_MAX) {
@@ -1757,7 +1462,6 @@ typedef struct {
const WebPPicture* picture_;
VP8LBitWriter* bw_;
VP8LEncoder* enc_;
- int use_cache_;
CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX];
int num_crunch_configs_;
int red_and_blue_always_zero_;
@@ -1770,7 +1474,6 @@ static int EncodeStreamHook(void* input, void* data2) {
const WebPPicture* const picture = params->picture_;
VP8LBitWriter* const bw = params->bw_;
VP8LEncoder* const enc = params->enc_;
- const int use_cache = params->use_cache_;
const CrunchConfig* const crunch_configs = params->crunch_configs_;
const int num_crunch_configs = params->num_crunch_configs_;
const int red_and_blue_always_zero = params->red_and_blue_always_zero_;
@@ -1844,19 +1547,11 @@ static int EncodeStreamHook(void* input, void* data2) {
// Encode palette
if (enc->use_palette_) {
- if (crunch_configs[idx].palette_sorting_type_ == kSortedDefault) {
- // Nothing to do, we have already sorted the palette.
- memcpy(enc->palette_, enc->palette_sorted_,
- enc->palette_size_ * sizeof(*enc->palette_));
- } else if (crunch_configs[idx].palette_sorting_type_ == kMinimizeDelta) {
- PaletteSortMinimizeDeltas(enc->palette_sorted_, enc->palette_size_,
- enc->palette_);
- } else {
- assert(crunch_configs[idx].palette_sorting_type_ == kModifiedZeng);
- if (!PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
- enc->palette_size_, enc->palette_)) {
- goto Error;
- }
+ if (!PaletteSort(crunch_configs[idx].palette_sorting_type_, enc->pic_,
+ enc->palette_sorted_, enc->palette_size_,
+ enc->palette_)) {
+ WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
}
percent_range = remaining_percent / 4;
if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) {
@@ -1866,7 +1561,7 @@ static int EncodeStreamHook(void* input, void* data2) {
if (!MapImageFromPalette(enc, use_delta_palette)) goto Error;
// If using a color cache, do not have it bigger than the number of
// colors.
- if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
+ if (enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1;
}
}
@@ -1910,7 +1605,7 @@ static int EncodeStreamHook(void* input, void* data2) {
// Encode and write the transformed image.
if (!EncodeImageInternal(
bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_,
- height, quality, low_effort, use_cache, &crunch_configs[idx],
+ height, quality, low_effort, &crunch_configs[idx],
&enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size,
&data_size, picture, remaining_percent, &percent)) {
goto Error;
@@ -1952,7 +1647,7 @@ static int EncodeStreamHook(void* input, void* data2) {
int VP8LEncodeStream(const WebPConfig* const config,
const WebPPicture* const picture,
- VP8LBitWriter* const bw_main, int use_cache) {
+ VP8LBitWriter* const bw_main) {
VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture);
VP8LEncoder* enc_side = NULL;
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX];
@@ -1969,13 +1664,14 @@ int VP8LEncodeStream(const WebPConfig* const config,
int ok_main;
if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) {
- WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
VP8LEncoderDelete(enc_main);
- return 0;
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
// Avoid "garbage value" error from Clang's static analysis tool.
- WebPPictureInit(&picture_side);
+ if (!WebPPictureInit(&picture_side)) {
+ goto Error;
+ }
// Analyze image (entropy, num_palettes etc)
if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main,
@@ -2010,7 +1706,6 @@ int VP8LEncodeStream(const WebPConfig* const config,
StreamEncodeContext* const param =
(idx == 0) ? &params_main : &params_side;
param->config_ = config;
- param->use_cache_ = use_cache;
param->red_and_blue_always_zero_ = red_and_blue_always_zero;
if (idx == 0) {
param->picture_ = picture;
@@ -2118,8 +1813,7 @@ int VP8LEncodeImage(const WebPConfig* const config,
if (picture == NULL) return 0;
if (config == NULL || picture->argb == NULL) {
- WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
- return 0;
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
}
width = picture->width;
@@ -2165,7 +1859,7 @@ int VP8LEncodeImage(const WebPConfig* const config,
if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort;
// Encode main image stream.
- if (!VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/)) goto Error;
+ if (!VP8LEncodeStream(config, picture, &bw)) goto Error;
if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort;
diff --git a/src/enc/vp8li_enc.h b/src/enc/vp8li_enc.h
index 3d35e161..c5b60dcb 100644
--- a/src/enc/vp8li_enc.h
+++ b/src/enc/vp8li_enc.h
@@ -88,11 +88,9 @@ int VP8LEncodeImage(const WebPConfig* const config,
const WebPPicture* const picture);
// Encodes the main image stream using the supplied bit writer.
-// If 'use_cache' is false, disables the use of color cache.
// Returns false in case of error (stored in picture->error_code).
int VP8LEncodeStream(const WebPConfig* const config,
- const WebPPicture* const picture, VP8LBitWriter* const bw,
- int use_cache);
+ const WebPPicture* const picture, VP8LBitWriter* const bw);
#if (WEBP_NEAR_LOSSLESS == 1)
// in near_lossless.c
diff --git a/src/enc/webp_enc.c b/src/enc/webp_enc.c
index 9620e050..583fe6a8 100644
--- a/src/enc/webp_enc.c
+++ b/src/enc/webp_enc.c
@@ -307,7 +307,10 @@ int WebPEncodingSetError(const WebPPicture* const pic,
WebPEncodingError error) {
assert((int)error < VP8_ENC_ERROR_LAST);
assert((int)error >= VP8_ENC_OK);
- ((WebPPicture*)pic)->error_code = error;
+ // The oldest error reported takes precedence over the new one.
+ if (pic->error_code == VP8_ENC_OK) {
+ ((WebPPicture*)pic)->error_code = error;
+ }
return 0;
}
@@ -317,8 +320,7 @@ int WebPReportProgress(const WebPPicture* const pic,
*percent_store = percent;
if (pic->progress_hook && !pic->progress_hook(percent, pic)) {
// user abort requested
- WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT);
- return 0;
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT);
}
}
return 1; // ok
@@ -329,7 +331,7 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
int ok = 0;
if (pic == NULL) return 0;
- WebPEncodingSetError(pic, VP8_ENC_OK); // all ok so far
+ pic->error_code = VP8_ENC_OK; // all ok so far
if (config == NULL) { // bad params
return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
}
diff --git a/src/libwebp.rc b/src/libwebp.rc
index 6b11dc83..d51536f5 100644
--- a/src/libwebp.rc
+++ b/src/libwebp.rc
@@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,3,0
- PRODUCTVERSION 1,0,3,0
+ FILEVERSION 1,0,4,0
+ PRODUCTVERSION 1,0,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -24,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebp DLL"
- VALUE "FileVersion", "1.3.0"
+ VALUE "FileVersion", "1.4.0"
VALUE "InternalName", "libwebp.dll"
- VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "LegalCopyright", "Copyright (C) 2024"
VALUE "OriginalFilename", "libwebp.dll"
VALUE "ProductName", "WebP Image Codec"
- VALUE "ProductVersion", "1.3.0"
+ VALUE "ProductVersion", "1.4.0"
END
END
BLOCK "VarFileInfo"
diff --git a/src/libwebpdecoder.rc b/src/libwebpdecoder.rc
index 44e4f26e..3891488c 100644
--- a/src/libwebpdecoder.rc
+++ b/src/libwebpdecoder.rc
@@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,3,0
- PRODUCTVERSION 1,0,3,0
+ FILEVERSION 1,0,4,0
+ PRODUCTVERSION 1,0,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -24,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebpdecoder DLL"
- VALUE "FileVersion", "1.3.0"
+ VALUE "FileVersion", "1.4.0"
VALUE "InternalName", "libwebpdecoder.dll"
- VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "LegalCopyright", "Copyright (C) 2024"
VALUE "OriginalFilename", "libwebpdecoder.dll"
VALUE "ProductName", "WebP Image Decoder"
- VALUE "ProductVersion", "1.3.0"
+ VALUE "ProductVersion", "1.4.0"
END
END
BLOCK "VarFileInfo"
diff --git a/src/mux/Makefile.am b/src/mux/Makefile.am
index 8f7f7395..18bc90e9 100644
--- a/src/mux/Makefile.am
+++ b/src/mux/Makefile.am
@@ -17,6 +17,6 @@ noinst_HEADERS =
noinst_HEADERS += ../webp/format_constants.h
libwebpmux_la_LIBADD = ../libwebp.la
-libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:11:0 -lm
+libwebpmux_la_LDFLAGS = -no-undefined -version-info 4:0:1 -lm
libwebpmuxincludedir = $(includedir)/webp
pkgconfig_DATA = libwebpmux.pc
diff --git a/src/mux/anim_encode.c b/src/mux/anim_encode.c
index 7078d9ae..31bd0457 100644
--- a/src/mux/anim_encode.c
+++ b/src/mux/anim_encode.c
@@ -22,6 +22,7 @@
#include "src/webp/encode.h"
#include "src/webp/format_constants.h"
#include "src/webp/mux.h"
+#include "src/webp/types.h"
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
@@ -593,16 +594,17 @@ int WebPAnimEncoderRefineRect(
int is_lossless, float quality, int* const x_offset, int* const y_offset,
int* const width, int* const height) {
FrameRectangle rect;
- const int right = clip(*x_offset + *width, 0, curr_canvas->width);
- const int left = clip(*x_offset, 0, curr_canvas->width - 1);
- const int bottom = clip(*y_offset + *height, 0, curr_canvas->height);
- const int top = clip(*y_offset, 0, curr_canvas->height - 1);
+ int right, left, bottom, top;
if (prev_canvas == NULL || curr_canvas == NULL ||
prev_canvas->width != curr_canvas->width ||
prev_canvas->height != curr_canvas->height ||
!prev_canvas->use_argb || !curr_canvas->use_argb) {
return 0;
}
+ right = clip(*x_offset + *width, 0, curr_canvas->width);
+ left = clip(*x_offset, 0, curr_canvas->width - 1);
+ bottom = clip(*y_offset + *height, 0, curr_canvas->height);
+ top = clip(*y_offset, 0, curr_canvas->height - 1);
rect.x_offset_ = left;
rect.y_offset_ = top;
rect.width_ = clip(right - left, 0, curr_canvas->width - rect.x_offset_);
@@ -1397,7 +1399,10 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
}
config = *encoder_config;
} else {
- WebPConfigInit(&config);
+ if (!WebPConfigInit(&config)) {
+ MarkError(enc, "Cannot Init config");
+ return 0;
+ }
config.lossless = 1;
}
assert(enc->curr_canvas_ == NULL);
@@ -1418,12 +1423,14 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
// -----------------------------------------------------------------------------
// Bitstream assembly.
-static int DecodeFrameOntoCanvas(const WebPMuxFrameInfo* const frame,
- WebPPicture* const canvas) {
+WEBP_NODISCARD static int DecodeFrameOntoCanvas(
+ const WebPMuxFrameInfo* const frame, WebPPicture* const canvas) {
const WebPData* const image = &frame->bitstream;
WebPPicture sub_image;
WebPDecoderConfig config;
- WebPInitDecoderConfig(&config);
+ if (!WebPInitDecoderConfig(&config)) {
+ return 0;
+ }
WebPUtilClearPic(canvas, NULL);
if (WebPGetFeatures(image->bytes, image->size, &config.input) !=
VP8_STATUS_OK) {
@@ -1582,4 +1589,23 @@ const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc) {
return enc->error_str_;
}
+WebPMuxError WebPAnimEncoderSetChunk(
+ WebPAnimEncoder* enc, const char fourcc[4], const WebPData* chunk_data,
+ int copy_data) {
+ if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ return WebPMuxSetChunk(enc->mux_, fourcc, chunk_data, copy_data);
+}
+
+WebPMuxError WebPAnimEncoderGetChunk(
+ const WebPAnimEncoder* enc, const char fourcc[4], WebPData* chunk_data) {
+ if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ return WebPMuxGetChunk(enc->mux_, fourcc, chunk_data);
+}
+
+WebPMuxError WebPAnimEncoderDeleteChunk(
+ WebPAnimEncoder* enc, const char fourcc[4]) {
+ if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ return WebPMuxDeleteChunk(enc->mux_, fourcc);
+}
+
// -----------------------------------------------------------------------------
diff --git a/src/mux/libwebpmux.rc b/src/mux/libwebpmux.rc
index a61f5371..1b20fac1 100644
--- a/src/mux/libwebpmux.rc
+++ b/src/mux/libwebpmux.rc
@@ -6,8 +6,8 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,3,0
- PRODUCTVERSION 1,0,3,0
+ FILEVERSION 1,0,4,0
+ PRODUCTVERSION 1,0,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -24,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Google, Inc."
VALUE "FileDescription", "libwebpmux DLL"
- VALUE "FileVersion", "1.3.0"
+ VALUE "FileVersion", "1.4.0"
VALUE "InternalName", "libwebpmux.dll"
- VALUE "LegalCopyright", "Copyright (C) 2022"
+ VALUE "LegalCopyright", "Copyright (C) 2024"
VALUE "OriginalFilename", "libwebpmux.dll"
VALUE "ProductName", "WebP Image Muxer"
- VALUE "ProductVersion", "1.3.0"
+ VALUE "ProductVersion", "1.4.0"
END
END
BLOCK "VarFileInfo"
diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c
index 63e71a0a..48c6834a 100644
--- a/src/mux/muxedit.c
+++ b/src/mux/muxedit.c
@@ -66,14 +66,16 @@ void WebPMuxDelete(WebPMux* mux) {
// Handy MACRO, makes MuxSet() very symmetric to MuxGet().
#define SWITCH_ID_LIST(INDEX, LIST) \
- if (idx == (INDEX)) { \
- err = ChunkAssignData(&chunk, data, copy_data, tag); \
- if (err == WEBP_MUX_OK) { \
- err = ChunkSetHead(&chunk, (LIST)); \
- if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \
+ do { \
+ if (idx == (INDEX)) { \
+ err = ChunkAssignData(&chunk, data, copy_data, tag); \
+ if (err == WEBP_MUX_OK) { \
+ err = ChunkSetHead(&chunk, (LIST)); \
+ if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \
+ } \
+ return err; \
} \
- return err; \
- }
+ } while (0)
static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag,
const WebPData* const data, int copy_data) {
@@ -555,7 +557,8 @@ static WebPMuxError MuxCleanup(WebPMux* const mux) {
if (num_frames == 1) {
WebPMuxImage* frame = NULL;
err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame);
- assert(err == WEBP_MUX_OK); // We know that one frame does exist.
+ if (err != WEBP_MUX_OK) return err;
+ // We know that one frame does exist.
assert(frame != NULL);
if (frame->header_ != NULL &&
((mux->canvas_width_ == 0 && mux->canvas_height_ == 0) ||
diff --git a/src/mux/muxi.h b/src/mux/muxi.h
index 7929138c..74ae3fac 100644
--- a/src/mux/muxi.h
+++ b/src/mux/muxi.h
@@ -28,7 +28,7 @@ extern "C" {
// Defines and constants.
#define MUX_MAJ_VERSION 1
-#define MUX_MIN_VERSION 3
+#define MUX_MIN_VERSION 4
#define MUX_REV_VERSION 0
// Chunk object.
diff --git a/src/mux/muxread.c b/src/mux/muxread.c
index 80050396..afd3542e 100644
--- a/src/mux/muxread.c
+++ b/src/mux/muxread.c
@@ -21,20 +21,23 @@
// Handy MACRO.
#define SWITCH_ID_LIST(INDEX, LIST) \
- if (idx == (INDEX)) { \
- const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \
- kChunks[(INDEX)].tag); \
- if (chunk) { \
- *data = chunk->data_; \
- return WEBP_MUX_OK; \
- } else { \
- return WEBP_MUX_NOT_FOUND; \
+ do { \
+ if (idx == (INDEX)) { \
+ const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \
+ kChunks[(INDEX)].tag); \
+ if (chunk) { \
+ *data = chunk->data_; \
+ return WEBP_MUX_OK; \
+ } else { \
+ return WEBP_MUX_NOT_FOUND; \
+ } \
} \
- }
+ } while (0)
static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
uint32_t nth, WebPData* const data) {
assert(mux != NULL);
+ assert(idx != IDX_LAST_CHUNK);
assert(!IsWPI(kChunks[idx].id));
WebPDataInit(data);
@@ -116,9 +119,12 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
// Each of ANMF chunk contain a header at the beginning. So, its size should
// be at least 'hdr_size'.
if (size < hdr_size) goto Fail;
- ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_);
+ if (ChunkAssignData(&subchunk, &temp, copy_data,
+ chunk->tag_) != WEBP_MUX_OK) {
+ goto Fail;
+ }
}
- ChunkSetHead(&subchunk, &wpi->header_);
+ if (ChunkSetHead(&subchunk, &wpi->header_) != WEBP_MUX_OK) goto Fail;
wpi->is_partial_ = 1; // Waiting for ALPH and/or VP8/VP8L chunks.
// Rest of the chunks.
@@ -426,6 +432,7 @@ WebPMuxError WebPMuxGetChunk(const WebPMux* mux, const char fourcc[4],
return WEBP_MUX_INVALID_ARGUMENT;
}
idx = ChunkGetIndexFromFourCC(fourcc);
+ assert(idx != IDX_LAST_CHUNK);
if (IsWPI(kChunks[idx].id)) { // An image chunk.
return WEBP_MUX_INVALID_ARGUMENT;
} else if (idx != IDX_UNKNOWN) { // A known chunk type.
diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
index a4bff8b9..a0b7fe35 100644
--- a/src/utils/Makefile.am
+++ b/src/utils/Makefile.am
@@ -26,6 +26,8 @@ COMMON_SOURCES += filters_utils.c
COMMON_SOURCES += filters_utils.h
COMMON_SOURCES += huffman_utils.c
COMMON_SOURCES += huffman_utils.h
+COMMON_SOURCES += palette.c
+COMMON_SOURCES += palette.h
COMMON_SOURCES += quant_levels_dec_utils.c
COMMON_SOURCES += quant_levels_dec_utils.h
COMMON_SOURCES += rescaler_utils.c
diff --git a/src/utils/bit_reader_utils.c b/src/utils/bit_reader_utils.c
index 857cd609..a26557aa 100644
--- a/src/utils/bit_reader_utils.c
+++ b/src/utils/bit_reader_utils.c
@@ -15,6 +15,7 @@
#include "src/webp/config.h"
#endif
+#include "src/dsp/cpu.h"
#include "src/utils/bit_reader_inl_utils.h"
#include "src/utils/utils.h"
@@ -121,7 +122,7 @@ int32_t VP8GetSignedValue(VP8BitReader* const br, int bits,
#define VP8L_LOG8_WBITS 4 // Number of bytes needed to store VP8L_WBITS bits.
-#if defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || \
+#if defined(__arm__) || defined(_M_ARM) || WEBP_AARCH64 || \
defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64__) || defined(_M_X64)
#define VP8L_USE_FAST_LOAD
diff --git a/src/utils/bit_reader_utils.h b/src/utils/bit_reader_utils.h
index e64156e3..25ff31e5 100644
--- a/src/utils/bit_reader_utils.h
+++ b/src/utils/bit_reader_utils.h
@@ -19,6 +19,7 @@
#ifdef _MSC_VER
#include <stdlib.h> // _byteswap_ulong
#endif
+#include "src/dsp/cpu.h"
#include "src/webp/types.h"
// Warning! This macro triggers quite some MACRO wizardry around func signature!
@@ -64,7 +65,7 @@ extern "C" {
#define BITS 56
#elif defined(__arm__) || defined(_M_ARM) // ARM
#define BITS 24
-#elif defined(__aarch64__) // ARM 64bit
+#elif WEBP_AARCH64 // ARM 64bit
#define BITS 56
#elif defined(__mips__) // MIPS
#define BITS 24
diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c
index 90c2fbf7..16f9faaa 100644
--- a/src/utils/huffman_utils.c
+++ b/src/utils/huffman_utils.c
@@ -122,6 +122,9 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
const int symbol_code_length = code_lengths[symbol];
if (code_lengths[symbol] > 0) {
if (sorted != NULL) {
+ if(offset[symbol_code_length] >= code_lengths_size) {
+ return 0;
+ }
sorted[offset[symbol_code_length]++] = symbol;
} else {
offset[symbol_code_length]++;
@@ -177,21 +180,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
if (num_open < 0) {
return 0;
}
- if (root_table == NULL) continue;
for (; count[len] > 0; --count[len]) {
HuffmanCode code;
if ((key & mask) != low) {
- table += table_size;
+ if (root_table != NULL) table += table_size;
table_bits = NextTableBitSize(count, len, root_bits);
table_size = 1 << table_bits;
total_size += table_size;
low = key & mask;
- root_table[low].bits = (uint8_t)(table_bits + root_bits);
- root_table[low].value = (uint16_t)((table - root_table) - low);
+ if (root_table != NULL) {
+ root_table[low].bits = (uint8_t)(table_bits + root_bits);
+ root_table[low].value = (uint16_t)((table - root_table) - low);
+ }
+ }
+ if (root_table != NULL) {
+ code.bits = (uint8_t)(len - root_bits);
+ code.value = (uint16_t)sorted[symbol++];
+ ReplicateValue(&table[key >> root_bits], step, table_size, code);
}
- code.bits = (uint8_t)(len - root_bits);
- code.value = (uint16_t)sorted[symbol++];
- ReplicateValue(&table[key >> root_bits], step, table_size, code);
key = GetNextKey(key, len);
}
}
@@ -211,25 +217,83 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES)
// Cut-off value for switching between heap and stack allocation.
#define SORTED_SIZE_CUTOFF 512
-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
+int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size) {
- int total_size;
+ const int total_size =
+ BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL);
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
- if (root_table == NULL) {
- total_size = BuildHuffmanTable(NULL, root_bits,
- code_lengths, code_lengths_size, NULL);
- } else if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
+ if (total_size == 0 || root_table == NULL) return total_size;
+
+ if (root_table->curr_segment->curr_table + total_size >=
+ root_table->curr_segment->start + root_table->curr_segment->size) {
+ // If 'root_table' does not have enough memory, allocate a new segment.
+ // The available part of root_table->curr_segment is left unused because we
+ // need a contiguous buffer.
+ const int segment_size = root_table->curr_segment->size;
+ struct HuffmanTablesSegment* next =
+ (HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next));
+ if (next == NULL) return 0;
+ // Fill the new segment.
+ // We need at least 'total_size' but if that value is small, it is better to
+ // allocate a big chunk to prevent more allocations later. 'segment_size' is
+ // therefore chosen (any other arbitrary value could be chosen).
+ next->size = total_size > segment_size ? total_size : segment_size;
+ next->start =
+ (HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start));
+ if (next->start == NULL) {
+ WebPSafeFree(next);
+ return 0;
+ }
+ next->curr_table = next->start;
+ next->next = NULL;
+ // Point to the new segment.
+ root_table->curr_segment->next = next;
+ root_table->curr_segment = next;
+ }
+ if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
// use local stack-allocated array.
uint16_t sorted[SORTED_SIZE_CUTOFF];
- total_size = BuildHuffmanTable(root_table, root_bits,
- code_lengths, code_lengths_size, sorted);
- } else { // rare case. Use heap allocation.
+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
+ code_lengths, code_lengths_size, sorted);
+ } else { // rare case. Use heap allocation.
uint16_t* const sorted =
(uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
if (sorted == NULL) return 0;
- total_size = BuildHuffmanTable(root_table, root_bits,
- code_lengths, code_lengths_size, sorted);
+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
+ code_lengths, code_lengths_size, sorted);
WebPSafeFree(sorted);
}
return total_size;
}
+
+int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
+ // Have 'segment' point to the first segment for now, 'root'.
+ HuffmanTablesSegment* const root = &huffman_tables->root;
+ huffman_tables->curr_segment = root;
+ root->next = NULL;
+ // Allocate root.
+ root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
+ if (root->start == NULL) return 0;
+ root->curr_table = root->start;
+ root->size = size;
+ return 1;
+}
+
+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) {
+ HuffmanTablesSegment *current, *next;
+ if (huffman_tables == NULL) return;
+ // Free the root node.
+ current = &huffman_tables->root;
+ next = current->next;
+ WebPSafeFree(current->start);
+ current->start = NULL;
+ current->next = NULL;
+ current = next;
+ // Free the following nodes.
+ while (current != NULL) {
+ next = current->next;
+ WebPSafeFree(current->start);
+ WebPSafeFree(current);
+ current = next;
+ }
+}
diff --git a/src/utils/huffman_utils.h b/src/utils/huffman_utils.h
index 13b7ad1a..d511dc05 100644
--- a/src/utils/huffman_utils.h
+++ b/src/utils/huffman_utils.h
@@ -43,6 +43,30 @@ typedef struct {
// or non-literal symbol otherwise
} HuffmanCode32;
+// Contiguous memory segment of HuffmanCodes.
+typedef struct HuffmanTablesSegment {
+ HuffmanCode* start;
+ // Pointer to where we are writing into the segment. Starts at 'start' and
+ // cannot go beyond 'start' + 'size'.
+ HuffmanCode* curr_table;
+ // Pointer to the next segment in the chain.
+ struct HuffmanTablesSegment* next;
+ int size;
+} HuffmanTablesSegment;
+
+// Chained memory segments of HuffmanCodes.
+typedef struct HuffmanTables {
+ HuffmanTablesSegment root;
+ // Currently processed segment. At first, this is 'root'.
+ HuffmanTablesSegment* curr_segment;
+} HuffmanTables;
+
+// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on
+// memory allocation error, 1 otherwise.
+WEBP_NODISCARD int VP8LHuffmanTablesAllocate(int size,
+ HuffmanTables* huffman_tables);
+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables);
+
#define HUFFMAN_PACKED_BITS 6
#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS)
@@ -68,7 +92,7 @@ struct HTreeGroup {
};
// Creates the instance of HTreeGroup with specified number of tree-groups.
-HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups);
+WEBP_NODISCARD HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups);
// Releases the memory allocated for HTreeGroup.
void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
@@ -78,10 +102,10 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
// the huffman table.
// Returns built table size or 0 in case of error (invalid tree or
// memory error).
-// If root_table is NULL, it returns 0 if a lookup cannot be built, something
-// > 0 otherwise (but not the table size).
-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
- const int code_lengths[], int code_lengths_size);
+WEBP_NODISCARD int VP8LBuildHuffmanTable(HuffmanTables* const root_table,
+ int root_bits,
+ const int code_lengths[],
+ int code_lengths_size);
#ifdef __cplusplus
} // extern "C"
diff --git a/src/utils/palette.c b/src/utils/palette.c
new file mode 100644
index 00000000..515da210
--- /dev/null
+++ b/src/utils/palette.c
@@ -0,0 +1,402 @@
+// Copyright 2023 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Utilities for palette analysis.
+//
+// Author: Vincent Rabaud (vrabaud@google.com)
+
+#include "src/utils/palette.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "src/dsp/lossless_common.h"
+#include "src/utils/color_cache_utils.h"
+#include "src/utils/utils.h"
+#include "src/webp/encode.h"
+#include "src/webp/format_constants.h"
+
+// -----------------------------------------------------------------------------
+
+// Palette reordering for smaller sum of deltas (and for smaller storage).
+
+static int PaletteCompareColorsForQsort(const void* p1, const void* p2) {
+ const uint32_t a = WebPMemToUint32((uint8_t*)p1);
+ const uint32_t b = WebPMemToUint32((uint8_t*)p2);
+ assert(a != b);
+ return (a < b) ? -1 : 1;
+}
+
+static WEBP_INLINE uint32_t PaletteComponentDistance(uint32_t v) {
+ return (v <= 128) ? v : (256 - v);
+}
+
+// Computes a value that is related to the entropy created by the
+// palette entry diff.
+//
+// Note that the last & 0xff is a no-operation in the next statement, but
+// removed by most compilers and is here only for regularity of the code.
+static WEBP_INLINE uint32_t PaletteColorDistance(uint32_t col1, uint32_t col2) {
+ const uint32_t diff = VP8LSubPixels(col1, col2);
+ const int kMoreWeightForRGBThanForAlpha = 9;
+ uint32_t score;
+ score = PaletteComponentDistance((diff >> 0) & 0xff);
+ score += PaletteComponentDistance((diff >> 8) & 0xff);
+ score += PaletteComponentDistance((diff >> 16) & 0xff);
+ score *= kMoreWeightForRGBThanForAlpha;
+ score += PaletteComponentDistance((diff >> 24) & 0xff);
+ return score;
+}
+
+static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
+ const uint32_t tmp = *col1;
+ *col1 = *col2;
+ *col2 = tmp;
+}
+
+int SearchColorNoIdx(const uint32_t sorted[], uint32_t color, int num_colors) {
+ int low = 0, hi = num_colors;
+ if (sorted[low] == color) return low; // loop invariant: sorted[low] != color
+ while (1) {
+ const int mid = (low + hi) >> 1;
+ if (sorted[mid] == color) {
+ return mid;
+ } else if (sorted[mid] < color) {
+ low = mid;
+ } else {
+ hi = mid;
+ }
+ }
+ assert(0);
+ return 0;
+}
+
+void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
+ uint32_t sorted[], uint32_t idx_map[]) {
+ uint32_t i;
+ memcpy(sorted, palette, num_colors * sizeof(*sorted));
+ qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
+ for (i = 0; i < num_colors; ++i) {
+ idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+#define COLOR_HASH_SIZE (MAX_PALETTE_SIZE * 4)
+#define COLOR_HASH_RIGHT_SHIFT 22 // 32 - log2(COLOR_HASH_SIZE).
+
+int GetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
+ int i;
+ int x, y;
+ int num_colors = 0;
+ uint8_t in_use[COLOR_HASH_SIZE] = {0};
+ uint32_t colors[COLOR_HASH_SIZE] = {0};
+ const uint32_t* argb = pic->argb;
+ const int width = pic->width;
+ const int height = pic->height;
+ uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
+ assert(pic != NULL);
+ assert(pic->use_argb);
+
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ int key;
+ if (argb[x] == last_pix) {
+ continue;
+ }
+ last_pix = argb[x];
+ key = VP8LHashPix(last_pix, COLOR_HASH_RIGHT_SHIFT);
+ while (1) {
+ if (!in_use[key]) {
+ colors[key] = last_pix;
+ in_use[key] = 1;
+ ++num_colors;
+ if (num_colors > MAX_PALETTE_SIZE) {
+ return MAX_PALETTE_SIZE + 1; // Exact count not needed.
+ }
+ break;
+ } else if (colors[key] == last_pix) {
+ break; // The color is already there.
+ } else {
+ // Some other color sits here, so do linear conflict resolution.
+ ++key;
+ key &= (COLOR_HASH_SIZE - 1); // Key mask.
+ }
+ }
+ }
+ argb += pic->argb_stride;
+ }
+
+ if (palette != NULL) { // Fill the colors into palette.
+ num_colors = 0;
+ for (i = 0; i < COLOR_HASH_SIZE; ++i) {
+ if (in_use[i]) {
+ palette[num_colors] = colors[i];
+ ++num_colors;
+ }
+ }
+ qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
+ }
+ return num_colors;
+}
+
+#undef COLOR_HASH_SIZE
+#undef COLOR_HASH_RIGHT_SHIFT
+
+// -----------------------------------------------------------------------------
+
+// The palette has been sorted by alpha. This function checks if the other
+// components of the palette have a monotonic development with regards to
+// position in the palette. If all have monotonic development, there is
+// no benefit to re-organize them greedily. A monotonic development
+// would be spotted in green-only situations (like lossy alpha) or gray-scale
+// images.
+static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette,
+ int num_colors) {
+ uint32_t predict = 0x000000;
+ int i;
+ uint8_t sign_found = 0x00;
+ for (i = 0; i < num_colors; ++i) {
+ const uint32_t diff = VP8LSubPixels(palette[i], predict);
+ const uint8_t rd = (diff >> 16) & 0xff;
+ const uint8_t gd = (diff >> 8) & 0xff;
+ const uint8_t bd = (diff >> 0) & 0xff;
+ if (rd != 0x00) {
+ sign_found |= (rd < 0x80) ? 1 : 2;
+ }
+ if (gd != 0x00) {
+ sign_found |= (gd < 0x80) ? 8 : 16;
+ }
+ if (bd != 0x00) {
+ sign_found |= (bd < 0x80) ? 64 : 128;
+ }
+ predict = palette[i];
+ }
+ return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
+}
+
+static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
+ int num_colors, uint32_t* const palette) {
+ uint32_t predict = 0x00000000;
+ int i, k;
+ memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
+ if (!PaletteHasNonMonotonousDeltas(palette_sorted, num_colors)) return;
+ // Find greedily always the closest color of the predicted color to minimize
+ // deltas in the palette. This reduces storage needs since the
+ // palette is stored with delta encoding.
+ for (i = 0; i < num_colors; ++i) {
+ int best_ix = i;
+ uint32_t best_score = ~0U;
+ for (k = i; k < num_colors; ++k) {
+ const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
+ if (best_score > cur_score) {
+ best_score = cur_score;
+ best_ix = k;
+ }
+ }
+ SwapColor(&palette[best_ix], &palette[i]);
+ predict = palette[i];
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Modified Zeng method from "A Survey on Palette Reordering
+// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
+// Pinho and Antonio J. R. Neves.
+
+// Finds the biggest cooccurrence in the matrix.
+static void CoOccurrenceFindMax(const uint32_t* const cooccurrence,
+ uint32_t num_colors, uint8_t* const c1,
+ uint8_t* const c2) {
+ // Find the index that is most frequently located adjacent to other
+ // (different) indexes.
+ uint32_t best_sum = 0u;
+ uint32_t i, j, best_cooccurrence;
+ *c1 = 0u;
+ for (i = 0; i < num_colors; ++i) {
+ uint32_t sum = 0;
+ for (j = 0; j < num_colors; ++j) sum += cooccurrence[i * num_colors + j];
+ if (sum > best_sum) {
+ best_sum = sum;
+ *c1 = i;
+ }
+ }
+ // Find the index that is most frequently found adjacent to *c1.
+ *c2 = 0u;
+ best_cooccurrence = 0u;
+ for (i = 0; i < num_colors; ++i) {
+ if (cooccurrence[*c1 * num_colors + i] > best_cooccurrence) {
+ best_cooccurrence = cooccurrence[*c1 * num_colors + i];
+ *c2 = i;
+ }
+ }
+ assert(*c1 != *c2);
+}
+
+// Builds the cooccurrence matrix
+static int CoOccurrenceBuild(const WebPPicture* const pic,
+ const uint32_t* const palette, uint32_t num_colors,
+ uint32_t* cooccurrence) {
+ uint32_t *lines, *line_top, *line_current, *line_tmp;
+ int x, y;
+ const uint32_t* src = pic->argb;
+ uint32_t prev_pix = ~src[0];
+ uint32_t prev_idx = 0u;
+ uint32_t idx_map[MAX_PALETTE_SIZE] = {0};
+ uint32_t palette_sorted[MAX_PALETTE_SIZE];
+ lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines));
+ if (lines == NULL) {
+ return 0;
+ }
+ line_top = &lines[0];
+ line_current = &lines[pic->width];
+ PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map);
+ for (y = 0; y < pic->height; ++y) {
+ for (x = 0; x < pic->width; ++x) {
+ const uint32_t pix = src[x];
+ if (pix != prev_pix) {
+ prev_idx = idx_map[SearchColorNoIdx(palette_sorted, pix, num_colors)];
+ prev_pix = pix;
+ }
+ line_current[x] = prev_idx;
+ // 4-connectivity is what works best as mentioned in "On the relation
+ // between Memon's and the modified Zeng's palette reordering methods".
+ if (x > 0 && prev_idx != line_current[x - 1]) {
+ const uint32_t left_idx = line_current[x - 1];
+ ++cooccurrence[prev_idx * num_colors + left_idx];
+ ++cooccurrence[left_idx * num_colors + prev_idx];
+ }
+ if (y > 0 && prev_idx != line_top[x]) {
+ const uint32_t top_idx = line_top[x];
+ ++cooccurrence[prev_idx * num_colors + top_idx];
+ ++cooccurrence[top_idx * num_colors + prev_idx];
+ }
+ }
+ line_tmp = line_top;
+ line_top = line_current;
+ line_current = line_tmp;
+ src += pic->argb_stride;
+ }
+ WebPSafeFree(lines);
+ return 1;
+}
+
+struct Sum {
+ uint8_t index;
+ uint32_t sum;
+};
+
+static int PaletteSortModifiedZeng(const WebPPicture* const pic,
+ const uint32_t* const palette_in,
+ uint32_t num_colors,
+ uint32_t* const palette) {
+ uint32_t i, j, ind;
+ uint8_t remapping[MAX_PALETTE_SIZE];
+ uint32_t* cooccurrence;
+ struct Sum sums[MAX_PALETTE_SIZE];
+ uint32_t first, last;
+ uint32_t num_sums;
+ // TODO(vrabaud) check whether one color images should use palette or not.
+ if (num_colors <= 1) return 1;
+ // Build the co-occurrence matrix.
+ cooccurrence =
+ (uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence));
+ if (cooccurrence == NULL) {
+ return 0;
+ }
+ if (!CoOccurrenceBuild(pic, palette_in, num_colors, cooccurrence)) {
+ WebPSafeFree(cooccurrence);
+ return 0;
+ }
+
+ // Initialize the mapping list with the two best indices.
+ CoOccurrenceFindMax(cooccurrence, num_colors, &remapping[0], &remapping[1]);
+
+ // We need to append and prepend to the list of remapping. To this end, we
+ // actually define the next start/end of the list as indices in a vector (with
+ // a wrap around when the end is reached).
+ first = 0;
+ last = 1;
+ num_sums = num_colors - 2; // -2 because we know the first two values
+ if (num_sums > 0) {
+ // Initialize the sums with the first two remappings and find the best one
+ struct Sum* best_sum = &sums[0];
+ best_sum->index = 0u;
+ best_sum->sum = 0u;
+ for (i = 0, j = 0; i < num_colors; ++i) {
+ if (i == remapping[0] || i == remapping[1]) continue;
+ sums[j].index = i;
+ sums[j].sum = cooccurrence[i * num_colors + remapping[0]] +
+ cooccurrence[i * num_colors + remapping[1]];
+ if (sums[j].sum > best_sum->sum) best_sum = &sums[j];
+ ++j;
+ }
+
+ while (num_sums > 0) {
+ const uint8_t best_index = best_sum->index;
+ // Compute delta to know if we need to prepend or append the best index.
+ int32_t delta = 0;
+ const int32_t n = num_colors - num_sums;
+ for (ind = first, j = 0; (ind + j) % num_colors != last + 1; ++j) {
+ const uint16_t l_j = remapping[(ind + j) % num_colors];
+ delta += (n - 1 - 2 * (int32_t)j) *
+ (int32_t)cooccurrence[best_index * num_colors + l_j];
+ }
+ if (delta > 0) {
+ first = (first == 0) ? num_colors - 1 : first - 1;
+ remapping[first] = best_index;
+ } else {
+ ++last;
+ remapping[last] = best_index;
+ }
+ // Remove best_sum from sums.
+ *best_sum = sums[num_sums - 1];
+ --num_sums;
+ // Update all the sums and find the best one.
+ best_sum = &sums[0];
+ for (i = 0; i < num_sums; ++i) {
+ sums[i].sum += cooccurrence[best_index * num_colors + sums[i].index];
+ if (sums[i].sum > best_sum->sum) best_sum = &sums[i];
+ }
+ }
+ }
+ assert((last + 1) % num_colors == first);
+ WebPSafeFree(cooccurrence);
+
+ // Re-map the palette.
+ for (i = 0; i < num_colors; ++i) {
+ palette[i] = palette_in[remapping[(first + i) % num_colors]];
+ }
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic,
+ const uint32_t* const palette_sorted, uint32_t num_colors,
+ uint32_t* const palette) {
+ switch (method) {
+ case kSortedDefault:
+ // Nothing to do, we have already sorted the palette.
+ memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
+ return 1;
+ case kMinimizeDelta:
+ PaletteSortMinimizeDeltas(palette_sorted, num_colors, palette);
+ return 1;
+ case kModifiedZeng:
+ return PaletteSortModifiedZeng(pic, palette_sorted, num_colors, palette);
+ case kUnusedPalette:
+ case kPaletteSortingNum:
+ break;
+ }
+
+ assert(0);
+ return 0;
+}
diff --git a/src/utils/palette.h b/src/utils/palette.h
new file mode 100644
index 00000000..34479e46
--- /dev/null
+++ b/src/utils/palette.h
@@ -0,0 +1,60 @@
+// Copyright 2023 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Utilities for palette analysis.
+//
+// Author: Vincent Rabaud (vrabaud@google.com)
+
+#ifndef WEBP_UTILS_PALETTE_H_
+#define WEBP_UTILS_PALETTE_H_
+
+#include "src/webp/types.h"
+
+struct WebPPicture;
+
+// The different ways a palette can be sorted.
+typedef enum PaletteSorting {
+ kSortedDefault = 0,
+ // Sorts by minimizing L1 deltas between consecutive colors, giving more
+ // weight to RGB colors.
+ kMinimizeDelta = 1,
+ // Implements the modified Zeng method from "A Survey on Palette Reordering
+ // Methods for Improving the Compression of Color-Indexed Images" by Armando
+ // J. Pinho and Antonio J. R. Neves.
+ kModifiedZeng = 2,
+ kUnusedPalette = 3,
+ kPaletteSortingNum = 4
+} PaletteSorting;
+
+// Returns the index of 'color' in the sorted palette 'sorted' of size
+// 'num_colors'.
+int SearchColorNoIdx(const uint32_t sorted[], uint32_t color, int num_colors);
+
+// Sort palette in increasing order and prepare an inverse mapping array.
+void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
+ uint32_t sorted[], uint32_t idx_map[]);
+
+// Returns count of unique colors in 'pic', assuming pic->use_argb is true.
+// If the unique color count is more than MAX_PALETTE_SIZE, returns
+// MAX_PALETTE_SIZE+1.
+// If 'palette' is not NULL and the number of unique colors is less than or
+// equal to MAX_PALETTE_SIZE, also outputs the actual unique colors into
+// 'palette' in a sorted order. Note: 'palette' is assumed to be an array
+// already allocated with at least MAX_PALETTE_SIZE elements.
+int GetColorPalette(const struct WebPPicture* const pic,
+ uint32_t* const palette);
+
+// Sorts the palette according to the criterion defined by 'method'.
+// 'palette_sorted' is the input palette sorted lexicographically, as done in
+// PrepareMapToPalette. Returns 0 on memory allocation error.
+int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic,
+ const uint32_t* const palette_sorted, uint32_t num_colors,
+ uint32_t* const palette);
+
+#endif // WEBP_UTILS_PALETTE_H_
diff --git a/src/utils/utils.c b/src/utils/utils.c
index a7c3a70f..408ce88f 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -11,13 +11,13 @@
//
// Author: Skal (pascal.massimino@gmail.com)
+#include "src/utils/utils.h"
+
#include <stdlib.h>
#include <string.h> // for memcpy()
-#include "src/webp/decode.h"
+
+#include "src/utils/palette.h"
#include "src/webp/encode.h"
-#include "src/webp/format_constants.h" // for MAX_PALETTE_SIZE
-#include "src/utils/color_cache_utils.h"
-#include "src/utils/utils.h"
// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow,
@@ -252,66 +252,10 @@ void WebPCopyPixels(const WebPPicture* const src, WebPPicture* const dst) {
//------------------------------------------------------------------------------
-#define COLOR_HASH_SIZE (MAX_PALETTE_SIZE * 4)
-#define COLOR_HASH_RIGHT_SHIFT 22 // 32 - log2(COLOR_HASH_SIZE).
-
int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
- int i;
- int x, y;
- int num_colors = 0;
- uint8_t in_use[COLOR_HASH_SIZE] = { 0 };
- uint32_t colors[COLOR_HASH_SIZE];
- const uint32_t* argb = pic->argb;
- const int width = pic->width;
- const int height = pic->height;
- uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
- assert(pic != NULL);
- assert(pic->use_argb);
-
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- int key;
- if (argb[x] == last_pix) {
- continue;
- }
- last_pix = argb[x];
- key = VP8LHashPix(last_pix, COLOR_HASH_RIGHT_SHIFT);
- while (1) {
- if (!in_use[key]) {
- colors[key] = last_pix;
- in_use[key] = 1;
- ++num_colors;
- if (num_colors > MAX_PALETTE_SIZE) {
- return MAX_PALETTE_SIZE + 1; // Exact count not needed.
- }
- break;
- } else if (colors[key] == last_pix) {
- break; // The color is already there.
- } else {
- // Some other color sits here, so do linear conflict resolution.
- ++key;
- key &= (COLOR_HASH_SIZE - 1); // Key mask.
- }
- }
- }
- argb += pic->argb_stride;
- }
-
- if (palette != NULL) { // Fill the colors into palette.
- num_colors = 0;
- for (i = 0; i < COLOR_HASH_SIZE; ++i) {
- if (in_use[i]) {
- palette[num_colors] = colors[i];
- ++num_colors;
- }
- }
- }
- return num_colors;
+ return GetColorPalette(pic, palette);
}
-#undef COLOR_HASH_SIZE
-#undef COLOR_HASH_RIGHT_SHIFT
-
//------------------------------------------------------------------------------
#if defined(WEBP_NEED_LOG_TABLE_8BIT)
diff --git a/src/utils/utils.h b/src/utils/utils.h
index c5ee8733..b2241fbf 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -20,9 +20,7 @@
#endif
#include <assert.h>
-#include <limits.h>
-#include "src/dsp/dsp.h"
#include "src/webp/types.h"
#ifdef __cplusplus
@@ -198,6 +196,7 @@ WEBP_EXTERN void WebPCopyPixels(const struct WebPPicture* const src,
// MAX_PALETTE_SIZE, also outputs the actual unique colors into 'palette'.
// Note: 'palette' is assumed to be an array already allocated with at least
// MAX_PALETTE_SIZE elements.
+// TODO(vrabaud) remove whenever we can break the ABI.
WEBP_EXTERN int WebPGetColorPalette(const struct WebPPicture* const pic,
uint32_t* const palette);
diff --git a/src/webp/decode.h b/src/webp/decode.h
index d9824750..d6895f5c 100644
--- a/src/webp/decode.h
+++ b/src/webp/decode.h
@@ -48,48 +48,47 @@ WEBP_EXTERN int WebPGetDecoderVersion(void);
// RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
-WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN int WebPGetInfo(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
// with the dimensions in *width and *height. The ordering of samples in
// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
// The returned pointer should be deleted calling WebPFree().
// Returns NULL in case of error.
-WEBP_EXTERN uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
-WEBP_EXTERN uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGB(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
-WEBP_EXTERN uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRA(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
// If the bitstream contains transparency, it is ignored.
-WEBP_EXTERN uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
-WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
- int* width, int* height);
-
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(
+ const uint8_t* data, size_t data_size, int* width, int* height);
// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
// returned is the Y samples buffer. Upon return, *u and *v will point to
// the U and V chroma data. These U and V buffers need NOT be passed to
// WebPFree(), unlike the returned Y luma one. The dimension of the U and V
-// planes are both (*width + 1) / 2 and (*height + 1)/ 2.
+// planes are both (*width + 1) / 2 and (*height + 1) / 2.
// Upon return, the Y buffer has a stride returned as '*stride', while U and V
// have a common stride returned as '*uv_stride'.
-// Return NULL in case of error.
+// 'width' and 'height' may be NULL, the other pointers must not be.
+// Returns NULL in case of error.
// (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr
-WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
- int* width, int* height,
- uint8_t** u, uint8_t** v,
- int* stride, int* uv_stride);
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(
+ const uint8_t* data, size_t data_size, int* width, int* height,
+ uint8_t** u, uint8_t** v, int* stride, int* uv_stride);
// These five functions are variants of the above ones, that decode the image
// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
@@ -99,22 +98,22 @@ WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
// The parameter 'output_stride' specifies the distance (in bytes)
// between scanlines. Hence, output_buffer_size is expected to be at least
// output_stride x picture-height.
-WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
// RGB and BGR variants. Here too the transparency information, if present,
// will be dropped and ignored.
-WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
@@ -125,7 +124,7 @@ WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
// 'u_size' and 'v_size' respectively.
// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
// during decoding (or because some buffers were found to be too small).
-WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
const uint8_t* data, size_t data_size,
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
@@ -216,11 +215,11 @@ struct WebPDecBuffer {
};
// Internal, version-checked, entry point
-WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int);
+WEBP_NODISCARD WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int);
// Initialize the structure as empty. Must be called before any other use.
// Returns false in case of version mismatch
-static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
+WEBP_NODISCARD static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
return WebPInitDecBufferInternal(buffer, WEBP_DECODER_ABI_VERSION);
}
@@ -231,7 +230,7 @@ WEBP_EXTERN void WebPFreeDecBuffer(WebPDecBuffer* buffer);
//------------------------------------------------------------------------------
// Enumeration of the status codes
-typedef enum VP8StatusCode {
+typedef enum WEBP_NODISCARD VP8StatusCode {
VP8_STATUS_OK = 0,
VP8_STATUS_OUT_OF_MEMORY,
VP8_STATUS_INVALID_PARAM,
@@ -250,23 +249,24 @@ typedef enum VP8StatusCode {
// WebPIDecoder object. This object can be left in a SUSPENDED state if the
// picture is only partially decoded, pending additional input.
// Code example:
-//
-// WebPInitDecBuffer(&output_buffer);
-// output_buffer.colorspace = mode;
-// ...
-// WebPIDecoder* idec = WebPINewDecoder(&output_buffer);
-// while (additional_data_is_available) {
-// // ... (get additional data in some new_data[] buffer)
-// status = WebPIAppend(idec, new_data, new_data_size);
-// if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
-// break; // an error occurred.
-// }
-//
-// // The above call decodes the current available buffer.
-// // Part of the image can now be refreshed by calling
-// // WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
-// }
-// WebPIDelete(idec);
+/*
+ WebPInitDecBuffer(&output_buffer);
+ output_buffer.colorspace = mode;
+ ...
+ WebPIDecoder* idec = WebPINewDecoder(&output_buffer);
+ while (additional_data_is_available) {
+ // ... (get additional data in some new_data[] buffer)
+ status = WebPIAppend(idec, new_data, new_data_size);
+ if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
+ break; // an error occurred.
+ }
+
+ // The above call decodes the current available buffer.
+ // Part of the image can now be refreshed by calling
+ // WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
+ }
+ WebPIDelete(idec);
+*/
// Creates a new incremental decoder with the supplied buffer parameter.
// This output_buffer can be passed NULL, in which case a default output buffer
@@ -280,7 +280,8 @@ typedef enum VP8StatusCode {
// within valid bounds.
// All other fields of WebPDecBuffer MUST remain constant between calls.
// Returns NULL if the allocation failed.
-WEBP_EXTERN WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer);
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewDecoder(
+ WebPDecBuffer* output_buffer);
// This function allocates and initializes an incremental-decoder object, which
// will output the RGB/A samples specified by 'csp' into a preallocated
@@ -292,7 +293,7 @@ WEBP_EXTERN WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer);
// colorspace 'csp' is taken into account for allocating this buffer. All other
// parameters are ignored.
// Returns NULL if the allocation failed, or if some parameters are invalid.
-WEBP_EXTERN WebPIDecoder* WebPINewRGB(
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(
WEBP_CSP_MODE csp,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
@@ -307,7 +308,7 @@ WEBP_EXTERN WebPIDecoder* WebPINewRGB(
// In this case, the output buffer will be automatically allocated (using
// MODE_YUVA) when decoding starts. All parameters are then ignored.
// Returns NULL if the allocation failed or if a parameter is invalid.
-WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride,
@@ -315,7 +316,7 @@ WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
// Deprecated version of the above, without the alpha plane.
// Kept for backward compatibility.
-WEBP_EXTERN WebPIDecoder* WebPINewYUV(
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUV(
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride);
@@ -345,21 +346,21 @@ WEBP_EXTERN VP8StatusCode WebPIUpdate(
// (*last_y, *width etc.) can be NULL if corresponding information is not
// needed. The values in these pointers are only valid on successful (non-NULL)
// return.
-WEBP_EXTERN uint8_t* WebPIDecGetRGB(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPIDecGetRGB(
const WebPIDecoder* idec, int* last_y,
int* width, int* height, int* stride);
// Same as above function to get a YUVA image. Returns pointer to the luma
// plane or NULL in case of error. If there is no alpha information
// the alpha pointer '*a' will be returned NULL.
-WEBP_EXTERN uint8_t* WebPIDecGetYUVA(
+WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPIDecGetYUVA(
const WebPIDecoder* idec, int* last_y,
uint8_t** u, uint8_t** v, uint8_t** a,
int* width, int* height, int* stride, int* uv_stride, int* a_stride);
// Deprecated alpha-less version of WebPIDecGetYUVA(): it will ignore the
// alpha information (if present). Kept for backward compatibility.
-static WEBP_INLINE uint8_t* WebPIDecGetYUV(
+WEBP_NODISCARD static WEBP_INLINE uint8_t* WebPIDecGetYUV(
const WebPIDecoder* idec, int* last_y, uint8_t** u, uint8_t** v,
int* width, int* height, int* stride, int* uv_stride) {
return WebPIDecGetYUVA(idec, last_y, u, v, NULL, width, height,
@@ -372,7 +373,7 @@ static WEBP_INLINE uint8_t* WebPIDecGetYUV(
// Returns NULL in case the incremental decoder object is in an invalid state.
// Otherwise returns the pointer to the internal representation. This structure
// is read-only, tied to WebPIDecoder's lifespan and should not be modified.
-WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
+WEBP_NODISCARD WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
const WebPIDecoder* idec, int* left, int* top, int* width, int* height);
//------------------------------------------------------------------------------
@@ -388,7 +389,7 @@ WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK);
// C) Adjust 'config', if needed
- config.no_fancy_upsampling = 1;
+ config.options.no_fancy_upsampling = 1;
config.output.colorspace = MODE_BGRA;
// etc.
@@ -467,12 +468,14 @@ struct WebPDecoderConfig {
};
// Internal, version-checked, entry point
-WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*, int);
+WEBP_NODISCARD WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*,
+ int);
// Initialize the configuration as empty. This function must always be
// called first, unless WebPGetFeatures() is to be called.
// Returns false in case of mismatched version.
-static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {
+WEBP_NODISCARD static WEBP_INLINE int WebPInitDecoderConfig(
+ WebPDecoderConfig* config) {
return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION);
}
@@ -487,8 +490,8 @@ static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {
// The return WebPIDecoder object must always be deleted calling WebPIDelete().
// Returns NULL in case of error (and config->status will then reflect
// the error condition, if available).
-WEBP_EXTERN WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
- WebPDecoderConfig* config);
+WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode(
+ const uint8_t* data, size_t data_size, WebPDecoderConfig* config);
// Non-incremental version. This version decodes the full data at once, taking
// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
diff --git a/src/webp/demux.h b/src/webp/demux.h
index 846eeb15..8d246550 100644
--- a/src/webp/demux.h
+++ b/src/webp/demux.h
@@ -50,6 +50,7 @@
#include "./decode.h" // for WEBP_CSP_MODE
#include "./mux_types.h"
+#include "./types.h"
#ifdef __cplusplus
extern "C" {
@@ -85,13 +86,13 @@ typedef enum WebPDemuxState {
} WebPDemuxState;
// Internal, version-checked, entry point
-WEBP_EXTERN WebPDemuxer* WebPDemuxInternal(
+WEBP_NODISCARD WEBP_EXTERN WebPDemuxer* WebPDemuxInternal(
const WebPData*, int, WebPDemuxState*, int);
// Parses the full WebP file given by 'data'. For single images the WebP file
// header alone or the file header and the chunk header may be absent.
// Returns a WebPDemuxer object on successful parse, NULL otherwise.
-static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
+WEBP_NODISCARD static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION);
}
@@ -103,7 +104,7 @@ static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
// If this data is volatile, the demuxer object should be deleted (by calling
// WebPDemuxDelete()) and WebPDemuxPartial() called again on the new data.
// This is usually an inexpensive operation.
-static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
+WEBP_NODISCARD static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
const WebPData* data, WebPDemuxState* state) {
return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION);
}
@@ -164,14 +165,14 @@ struct WebPIterator {
// Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
// Call WebPDemuxReleaseIterator() when use of the iterator is complete.
// NOTE: 'dmux' must persist for the lifetime of 'iter'.
-WEBP_EXTERN int WebPDemuxGetFrame(
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxGetFrame(
const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or
// previous ('iter->frame_num' - 1) frame. These functions do not loop.
// Returns true on success, false otherwise.
-WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter);
-WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter);
// Releases any memory associated with 'iter'.
// Must be called before any subsequent calls to WebPDemuxGetChunk() on the same
@@ -202,15 +203,16 @@ struct WebPChunkIterator {
// payloads are accessed through WebPDemuxGetFrame() and related functions.
// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
// NOTE: 'dmux' must persist for the lifetime of the iterator.
-WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux,
- const char fourcc[4], int chunk_number,
- WebPChunkIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux,
+ const char fourcc[4],
+ int chunk_number,
+ WebPChunkIterator* iter);
// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous
// ('iter->chunk_num' - 1) chunk. These functions do not loop.
// Returns true on success, false otherwise.
-WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter);
-WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter);
+WEBP_NODISCARD WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter);
// Releases any memory associated with 'iter'.
// Must be called before destroying the associated WebPDemuxer with
@@ -257,21 +259,21 @@ struct WebPAnimDecoderOptions {
};
// Internal, version-checked, entry point.
-WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal(
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal(
WebPAnimDecoderOptions*, int);
// Should always be called, to initialize a fresh WebPAnimDecoderOptions
// structure before modification. Returns false in case of version mismatch.
// WebPAnimDecoderOptionsInit() must have succeeded before using the
// 'dec_options' object.
-static WEBP_INLINE int WebPAnimDecoderOptionsInit(
+WEBP_NODISCARD static WEBP_INLINE int WebPAnimDecoderOptionsInit(
WebPAnimDecoderOptions* dec_options) {
return WebPAnimDecoderOptionsInitInternal(dec_options,
WEBP_DEMUX_ABI_VERSION);
}
// Internal, version-checked, entry point.
-WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
+WEBP_NODISCARD WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
const WebPData*, const WebPAnimDecoderOptions*, int);
// Creates and initializes a WebPAnimDecoder object.
@@ -284,7 +286,7 @@ WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
// Returns:
// A pointer to the newly created WebPAnimDecoder object, or NULL in case of
// parsing error, invalid option or memory error.
-static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew(
+WEBP_NODISCARD static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew(
const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options) {
return WebPAnimDecoderNewInternal(webp_data, dec_options,
WEBP_DEMUX_ABI_VERSION);
@@ -306,8 +308,8 @@ struct WebPAnimInfo {
// info - (out) global information fetched from the animation.
// Returns:
// True on success.
-WEBP_EXTERN int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
- WebPAnimInfo* info);
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderGetInfo(
+ const WebPAnimDecoder* dec, WebPAnimInfo* info);
// Fetch the next frame from 'dec' based on options supplied to
// WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size
@@ -321,8 +323,9 @@ WEBP_EXTERN int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
// Returns:
// False if any of the arguments are NULL, or if there is a parsing or
// decoding error, or if there are no more frames. Otherwise, returns true.
-WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
- uint8_t** buf, int* timestamp);
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
+ uint8_t** buf,
+ int* timestamp);
// Check if there are more frames left to decode.
// Parameters:
@@ -330,7 +333,8 @@ WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
// Returns:
// True if 'dec' is not NULL and some frames are yet to be decoded.
// Otherwise, returns false.
-WEBP_EXTERN int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimDecoderHasMoreFrames(
+ const WebPAnimDecoder* dec);
// Resets the WebPAnimDecoder object, so that next call to
// WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be
@@ -348,7 +352,7 @@ WEBP_EXTERN void WebPAnimDecoderReset(WebPAnimDecoder* dec);
//
// Parameters:
// dec - (in) decoder instance from which the demuxer object is to be fetched.
-WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer(
+WEBP_NODISCARD WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer(
const WebPAnimDecoder* dec);
// Deletes the WebPAnimDecoder object.
diff --git a/src/webp/encode.h b/src/webp/encode.h
index 56b68e2f..f3d59297 100644
--- a/src/webp/encode.h
+++ b/src/webp/encode.h
@@ -164,13 +164,14 @@ typedef enum WebPPreset {
} WebPPreset;
// Internal, version-checked, entry point
-WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int);
+WEBP_NODISCARD WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset,
+ float, int);
// Should always be called, to initialize a fresh WebPConfig structure before
// modification. Returns false in case of version mismatch. WebPConfigInit()
// must have succeeded before using the 'config' object.
// Note that the default values are lossless=0 and quality=75.
-static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
+WEBP_NODISCARD static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
return WebPConfigInitInternal(config, WEBP_PRESET_DEFAULT, 75.f,
WEBP_ENCODER_ABI_VERSION);
}
@@ -179,8 +180,9 @@ static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
// set of parameters (referred to by 'preset') and a given quality factor.
// This function can be called as a replacement to WebPConfigInit(). Will
// return false in case of error.
-static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
- WebPPreset preset, float quality) {
+WEBP_NODISCARD static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
+ WebPPreset preset,
+ float quality) {
return WebPConfigInitInternal(config, preset, quality,
WEBP_ENCODER_ABI_VERSION);
}
@@ -191,11 +193,12 @@ static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
// speed and final compressed size.
// This function will overwrite several fields from config: 'method', 'quality'
// and 'lossless'. Returns false in case of parameter error.
-WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config, int level);
+WEBP_NODISCARD WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config,
+ int level);
// Returns true if 'config' is non-NULL and all configuration parameters are
// within their valid ranges.
-WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config);
+WEBP_NODISCARD WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config);
//------------------------------------------------------------------------------
// Input / Output
@@ -255,8 +258,8 @@ WEBP_EXTERN void WebPMemoryWriterClear(WebPMemoryWriter* writer);
// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
// completion, writer.mem and writer.size will hold the coded data.
// writer.mem must be freed by calling WebPMemoryWriterClear.
-WEBP_EXTERN int WebPMemoryWrite(const uint8_t* data, size_t data_size,
- const WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPMemoryWrite(
+ const uint8_t* data, size_t data_size, const WebPPicture* picture);
// Progress hook, called from time to time to report progress. It can return
// false to request an abort of the encoding process, or true otherwise if
@@ -364,13 +367,13 @@ struct WebPPicture {
};
// Internal, version-checked, entry point
-WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int);
// Should always be called, to initialize the structure. Returns false in case
// of version mismatch. WebPPictureInit() must have succeeded before using the
// 'picture' object.
// Note that, by default, use_argb is false and colorspace is WEBP_YUV420.
-static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
+WEBP_NODISCARD static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
return WebPPictureInitInternal(picture, WEBP_ENCODER_ABI_VERSION);
}
@@ -381,7 +384,7 @@ static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
// Allocate y/u/v buffers as per colorspace/width/height specification.
// Note! This function will free the previous buffer if needed.
// Returns false in case of memory error.
-WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture);
// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
// Note that this function does _not_ free the memory used by the 'picture'
@@ -394,7 +397,8 @@ WEBP_EXTERN void WebPPictureFree(WebPPicture* picture);
// will fully own the copied pixels (this is not a view). The 'dst' picture need
// not be initialized as its content is overwritten.
// Returns false in case of memory allocation error.
-WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src,
+ WebPPicture* dst);
// Compute the single distortion for packed planes of samples.
// 'src' will be compared to 'ref', and the raw distortion stored into
@@ -403,19 +407,18 @@ WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
// 'x_step' is the horizontal stride (in bytes) between samples.
// 'src/ref_stride' is the byte distance between rows.
// Returns false in case of error (bad parameter, memory allocation error, ...).
-WEBP_EXTERN int WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
- const uint8_t* ref, size_t ref_stride,
- int width, int height,
- size_t x_step,
- int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
- float* distortion, float* result);
+WEBP_NODISCARD WEBP_EXTERN int WebPPlaneDistortion(
+ const uint8_t* src, size_t src_stride,
+ const uint8_t* ref, size_t ref_stride, int width, int height, size_t x_step,
+ int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
+ float* distortion, float* result);
// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results
// are in dB, stored in result[] in the B/G/R/A/All order. The distortion is
// always performed using ARGB samples. Hence if the input is YUV(A), the
// picture will be internally converted to ARGB (just for the measurement).
// Warning: this function is rather CPU-intensive.
-WEBP_EXTERN int WebPPictureDistortion(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureDistortion(
const WebPPicture* src, const WebPPicture* ref,
int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
float result[5]);
@@ -428,8 +431,8 @@ WEBP_EXTERN int WebPPictureDistortion(
// must be fully be comprised inside the 'src' source picture. If the source
// picture uses the YUV420 colorspace, the top and left coordinates will be
// snapped to even values.
-WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
- int left, int top, int width, int height);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureCrop(
+ WebPPicture* picture, int left, int top, int width, int height);
// Extracts a view from 'src' picture into 'dst'. The rectangle for the view
// is defined by the top-left corner pixel coordinates (left, top) as well
@@ -442,9 +445,9 @@ WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
// with WebPPictureInit() if it is different from 'src', since its content will
// be overwritten.
// Returns false in case of invalid parameters.
-WEBP_EXTERN int WebPPictureView(const WebPPicture* src,
- int left, int top, int width, int height,
- WebPPicture* dst);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureView(
+ const WebPPicture* src, int left, int top, int width, int height,
+ WebPPicture* dst);
// Returns true if the 'picture' is actually a view and therefore does
// not own the memory for pixels.
@@ -455,29 +458,30 @@ WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture);
// dimension will be calculated preserving the aspect ratio.
// No gamma correction is applied.
// Returns false in case of error (invalid parameter or insufficient memory).
-WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture, int width, int height);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture,
+ int width, int height);
// Colorspace conversion function to import RGB samples.
// Previous buffer will be free'd, if any.
// *rgb buffer should have a size of at least height * rgb_stride.
// Returns false in case of memory error.
-WEBP_EXTERN int WebPPictureImportRGB(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGB(
WebPPicture* picture, const uint8_t* rgb, int rgb_stride);
// Same, but for RGBA buffer.
-WEBP_EXTERN int WebPPictureImportRGBA(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGBA(
WebPPicture* picture, const uint8_t* rgba, int rgba_stride);
// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format
// input buffer ignoring the alpha channel. Avoids needing to copy the data
// to a temporary 24-bit RGB buffer to import the RGB only.
-WEBP_EXTERN int WebPPictureImportRGBX(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportRGBX(
WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride);
// Variants of the above, but taking BGR(A|X) input.
-WEBP_EXTERN int WebPPictureImportBGR(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGR(
WebPPicture* picture, const uint8_t* bgr, int bgr_stride);
-WEBP_EXTERN int WebPPictureImportBGRA(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGRA(
WebPPicture* picture, const uint8_t* bgra, int bgra_stride);
-WEBP_EXTERN int WebPPictureImportBGRX(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureImportBGRX(
WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride);
// Converts picture->argb data to the YUV420A format. The 'colorspace'
@@ -486,24 +490,24 @@ WEBP_EXTERN int WebPPictureImportBGRX(
// non-opaque transparent values is detected, and 'colorspace' will be
// adjusted accordingly. Note that this method is lossy.
// Returns false in case of error.
-WEBP_EXTERN int WebPPictureARGBToYUVA(WebPPicture* picture,
- WebPEncCSP /*colorspace = WEBP_YUV420*/);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureARGBToYUVA(
+ WebPPicture* picture, WebPEncCSP /*colorspace = WEBP_YUV420*/);
// Same as WebPPictureARGBToYUVA(), but the conversion is done using
// pseudo-random dithering with a strength 'dithering' between
// 0.0 (no dithering) and 1.0 (maximum dithering). This is useful
// for photographic picture.
-WEBP_EXTERN int WebPPictureARGBToYUVADithered(
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureARGBToYUVADithered(
WebPPicture* picture, WebPEncCSP colorspace, float dithering);
-// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion.
+// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion
// Downsampling is handled with extra care in case of color clipping. This
// method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better
// and sharper YUV representation.
// Returns false in case of error.
-WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture);
// kept for backward compatibility:
-WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
// Converts picture->yuv to picture->argb and sets picture->use_argb to true.
// The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to
@@ -511,7 +515,7 @@ WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
// Note that the use of this colorspace is discouraged if one has access to the
// raw ARGB samples, since using YUV420 is comparatively lossy.
// Returns false in case of error.
-WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture);
// Helper function: given a width x height plane of RGBA or YUV(A) samples
// clean-up or smoothen the YUV or RGB samples under fully transparent area,
@@ -541,7 +545,8 @@ WEBP_EXTERN void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb);
// the former for lossy encoding, and the latter for lossless encoding
// (when config.lossless is true). Automatic conversion from one format to
// another is provided but they both incur some loss.
-WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture);
+WEBP_NODISCARD WEBP_EXTERN int WebPEncode(const WebPConfig* config,
+ WebPPicture* picture);
//------------------------------------------------------------------------------
diff --git a/src/webp/mux.h b/src/webp/mux.h
index 7d27489a..8fb067e4 100644
--- a/src/webp/mux.h
+++ b/src/webp/mux.h
@@ -16,12 +16,13 @@
#define WEBP_WEBP_MUX_H_
#include "./mux_types.h"
+#include "./types.h"
#ifdef __cplusplus
extern "C" {
#endif
-#define WEBP_MUX_ABI_VERSION 0x0108 // MAJOR(8b) + MINOR(8b)
+#define WEBP_MUX_ABI_VERSION 0x0109 // MAJOR(8b) + MINOR(8b)
//------------------------------------------------------------------------------
// Mux API
@@ -70,7 +71,7 @@ typedef struct WebPMuxAnimParams WebPMuxAnimParams;
typedef struct WebPAnimEncoderOptions WebPAnimEncoderOptions;
// Error codes
-typedef enum WebPMuxError {
+typedef enum WEBP_NODISCARD WebPMuxError {
WEBP_MUX_OK = 1,
WEBP_MUX_NOT_FOUND = 0,
WEBP_MUX_INVALID_ARGUMENT = -1,
@@ -104,13 +105,13 @@ WEBP_EXTERN int WebPGetMuxVersion(void);
// Life of a Mux object
// Internal, version-checked, entry point
-WEBP_EXTERN WebPMux* WebPNewInternal(int);
+WEBP_NODISCARD WEBP_EXTERN WebPMux* WebPNewInternal(int);
// Creates an empty mux object.
// Returns:
// A pointer to the newly created empty mux object.
// Or NULL in case of memory error.
-static WEBP_INLINE WebPMux* WebPMuxNew(void) {
+WEBP_NODISCARD static WEBP_INLINE WebPMux* WebPMuxNew(void) {
return WebPNewInternal(WEBP_MUX_ABI_VERSION);
}
@@ -123,18 +124,21 @@ WEBP_EXTERN void WebPMuxDelete(WebPMux* mux);
// Mux creation.
// Internal, version-checked, entry point
-WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int, int);
+WEBP_NODISCARD WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int,
+ int);
// Creates a mux object from raw data given in WebP RIFF format.
// Parameters:
// bitstream - (in) the bitstream data in WebP RIFF format
// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist for the lifetime of the
+// mux object.
// Returns:
// A pointer to the mux object created from given data - on success.
// NULL - In case of invalid data or memory error.
-static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
- int copy_data) {
+WEBP_NODISCARD static WEBP_INLINE WebPMux* WebPMuxCreate(
+ const WebPData* bitstream, int copy_data) {
return WebPMuxCreateInternal(bitstream, copy_data, WEBP_MUX_ABI_VERSION);
}
@@ -154,7 +158,9 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
// e.g., "ICCP", "XMP ", "EXIF" etc.
// chunk_data - (in) the chunk data to be added
// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist until a call to
+// WebPMuxAssemble() is made.
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL
// or if fourcc corresponds to an image chunk.
@@ -217,7 +223,9 @@ struct WebPMuxFrameInfo {
// bitstream - (in) can be a raw VP8/VP8L bitstream or a single-image
// WebP file (non-animated)
// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist until a call to
+// WebPMuxAssemble() is made.
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
@@ -235,7 +243,9 @@ WEBP_EXTERN WebPMuxError WebPMuxSetImage(
// mux - (in/out) object to which the frame is to be added
// frame - (in) frame data.
// copy_data - (in) value 1 indicates given data WILL be copied to the mux
-// object and value 0 indicates data will NOT be copied.
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist until a call to
+// WebPMuxAssemble() is made.
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL
// or if content of 'frame' is invalid.
@@ -449,7 +459,7 @@ WEBP_EXTERN int WebPAnimEncoderOptionsInitInternal(
// structure before modification. Returns false in case of version mismatch.
// WebPAnimEncoderOptionsInit() must have succeeded before using the
// 'enc_options' object.
-static WEBP_INLINE int WebPAnimEncoderOptionsInit(
+WEBP_NODISCARD static WEBP_INLINE int WebPAnimEncoderOptionsInit(
WebPAnimEncoderOptions* enc_options) {
return WebPAnimEncoderOptionsInitInternal(enc_options, WEBP_MUX_ABI_VERSION);
}
@@ -490,7 +500,7 @@ static WEBP_INLINE WebPAnimEncoder* WebPAnimEncoderNew(
// Returns:
// On error, returns false and frame->error_code is set appropriately.
// Otherwise, returns true.
-WEBP_EXTERN int WebPAnimEncoderAdd(
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimEncoderAdd(
WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms,
const struct WebPConfig* config);
@@ -503,8 +513,8 @@ WEBP_EXTERN int WebPAnimEncoderAdd(
// webp_data - (out) generated WebP bitstream.
// Returns:
// True on success.
-WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
- WebPData* webp_data);
+WEBP_NODISCARD WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
+ WebPData* webp_data);
// Get error string corresponding to the most recent call using 'enc'. The
// returned string is owned by 'enc' and is valid only until the next call to
@@ -522,6 +532,57 @@ WEBP_EXTERN const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc);
WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
//------------------------------------------------------------------------------
+// Non-image chunks.
+
+// Note: Only non-image related chunks should be managed through chunk APIs.
+// (Image related chunks are: "ANMF", "VP8 ", "VP8L" and "ALPH").
+
+// Adds a chunk with id 'fourcc' and data 'chunk_data' in the enc object.
+// Any existing chunk(s) with the same id will be removed.
+// Parameters:
+// enc - (in/out) object to which the chunk is to be added
+// fourcc - (in) a character array containing the fourcc of the given chunk;
+// e.g., "ICCP", "XMP ", "EXIF", etc.
+// chunk_data - (in) the chunk data to be added
+// copy_data - (in) value 1 indicates given data WILL be copied to the enc
+// object and value 0 indicates data will NOT be copied. If the
+// data is not copied, it must exist until a call to
+// WebPAnimEncoderAssemble() is made.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if enc, fourcc or chunk_data is NULL.
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN WebPMuxError WebPAnimEncoderSetChunk(
+ WebPAnimEncoder* enc, const char fourcc[4], const WebPData* chunk_data,
+ int copy_data);
+
+// Gets a reference to the data of the chunk with id 'fourcc' in the enc object.
+// The caller should NOT free the returned data.
+// Parameters:
+// enc - (in) object from which the chunk data is to be fetched
+// fourcc - (in) a character array containing the fourcc of the chunk;
+// e.g., "ICCP", "XMP ", "EXIF", etc.
+// chunk_data - (out) returned chunk data
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if enc, fourcc or chunk_data is NULL.
+// WEBP_MUX_NOT_FOUND - If enc does not contain a chunk with the given id.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN WebPMuxError WebPAnimEncoderGetChunk(
+ const WebPAnimEncoder* enc, const char fourcc[4], WebPData* chunk_data);
+
+// Deletes the chunk with the given 'fourcc' from the enc object.
+// Parameters:
+// enc - (in/out) object from which the chunk is to be deleted
+// fourcc - (in) a character array containing the fourcc of the chunk;
+// e.g., "ICCP", "XMP ", "EXIF", etc.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if enc or fourcc is NULL.
+// WEBP_MUX_NOT_FOUND - If enc does not contain a chunk with the given fourcc.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN WebPMuxError WebPAnimEncoderDeleteChunk(
+ WebPAnimEncoder* enc, const char fourcc[4]);
+
+//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
diff --git a/src/webp/mux_types.h b/src/webp/mux_types.h
index 2fe81958..c585d208 100644
--- a/src/webp/mux_types.h
+++ b/src/webp/mux_types.h
@@ -79,7 +79,8 @@ static WEBP_INLINE void WebPDataClear(WebPData* webp_data) {
// Allocates necessary storage for 'dst' and copies the contents of 'src'.
// Returns true on success.
-static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) {
+WEBP_NODISCARD static WEBP_INLINE int WebPDataCopy(const WebPData* src,
+ WebPData* dst) {
if (src == NULL || dst == NULL) return 0;
WebPDataInit(dst);
if (src->bytes != NULL && src->size != 0) {
diff --git a/src/webp/types.h b/src/webp/types.h
index f255432e..9c17edec 100644
--- a/src/webp/types.h
+++ b/src/webp/types.h
@@ -36,18 +36,39 @@ typedef long long int int64_t;
#define WEBP_INLINE __forceinline
#endif /* _MSC_VER */
+#ifndef WEBP_NODISCARD
+#if defined(WEBP_ENABLE_NODISCARD) && WEBP_ENABLE_NODISCARD
+#if (defined(__cplusplus) && __cplusplus >= 201700L) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
+#define WEBP_NODISCARD [[nodiscard]]
+#else
+// gcc's __has_attribute does not work for enums.
+#if defined(__clang__) && defined(__has_attribute)
+#if __has_attribute(warn_unused_result)
+#define WEBP_NODISCARD __attribute__((warn_unused_result))
+#else
+#define WEBP_NODISCARD
+#endif /* __has_attribute(warn_unused_result) */
+#else
+#define WEBP_NODISCARD
+#endif /* defined(__clang__) && defined(__has_attribute) */
+#endif /* (defined(__cplusplus) && __cplusplus >= 201700L) ||
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) */
+#else
+#define WEBP_NODISCARD
+#endif /* defined(WEBP_ENABLE_NODISCARD) && WEBP_ENABLE_NODISCARD */
+#endif /* WEBP_NODISCARD */
+
#ifndef WEBP_EXTERN
// This explicitly marks library functions and allows for changing the
// signature for e.g., Windows DLL builds.
-# if defined(__GNUC__) && __GNUC__ >= 4
+# if defined(_WIN32) && defined(WEBP_DLL)
+# define WEBP_EXTERN __declspec(dllexport)
+# elif defined(__GNUC__) && __GNUC__ >= 4
# define WEBP_EXTERN extern __attribute__ ((visibility ("default")))
# else
-# if defined(_MSC_VER) && defined(WEBP_DLL)
-# define WEBP_EXTERN __declspec(dllexport)
-# else
-# define WEBP_EXTERN extern
-# endif
-# endif /* __GNUC__ >= 4 */
+# define WEBP_EXTERN extern
+# endif /* defined(_WIN32) && defined(WEBP_DLL) */
#endif /* WEBP_EXTERN */
// Macro to check ABI compatibility (same major revision number)
@@ -60,7 +81,7 @@ extern "C" {
// Allocates 'size' bytes of memory. Returns NULL upon error. Memory
// must be deallocated by calling WebPFree(). This function is made available
// by the core 'libwebp' library.
-WEBP_EXTERN void* WebPMalloc(size_t size);
+WEBP_NODISCARD WEBP_EXTERN void* WebPMalloc(size_t size);
// Releases memory returned by the WebPDecode*() functions (from decode.h).
WEBP_EXTERN void WebPFree(void* ptr);
diff --git a/tests/fuzzer/advanced_api_fuzzer.c b/tests/fuzzer/advanced_api_fuzzer.c
index 1378d0bc..22c689bb 100644
--- a/tests/fuzzer/advanced_api_fuzzer.c
+++ b/tests/fuzzer/advanced_api_fuzzer.c
@@ -88,10 +88,13 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
fuzz_px_limit /= 2;
}
// A big output canvas can lead to out-of-memory and timeout issues,
- // but a big internal working buffer can too.
- if ((uint64_t)scaled_width * scaled_height > fuzz_px_limit ||
- (uint64_t)config.input.width * config.input.height >
- fuzz_px_limit) {
+ // but a big internal working buffer can too. Also, rescaling from a
+ // very wide input image to a very tall canvas can be as slow as
+ // decoding a huge number of pixels. Avoid timeouts due to these.
+ const uint64_t max_num_operations =
+ (uint64_t)Max(scaled_width, config.input.width) *
+ Max(scaled_height, config.input.height);
+ if (max_num_operations > fuzz_px_limit) {
break;
}
}
@@ -127,7 +130,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
}
WebPIDelete(idec);
} else {
- WebPDecode(data, size, &config);
+ (void)WebPDecode(data, size, &config);
}
WebPFreeDecBuffer(&config.output);
diff --git a/tests/fuzzer/animdecoder_fuzzer.cc b/tests/fuzzer/animdecoder_fuzzer.cc
index a79712dc..c3ea4758 100644
--- a/tests/fuzzer/animdecoder_fuzzer.cc
+++ b/tests/fuzzer/animdecoder_fuzzer.cc
@@ -14,25 +14,34 @@
//
////////////////////////////////////////////////////////////////////////////////
-#include "examples/anim_util.h"
+#include <cstddef>
+#include <cstdint>
+
#include "imageio/imageio_util.h"
+#include "src/webp/decode.h"
#include "src/webp/demux.h"
+#include "src/webp/mux_types.h"
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// WebPAnimDecoderGetInfo() is too late to check the canvas size as
// WebPAnimDecoderNew() will handle the allocations.
+ const size_t kMaxNumBytes = 2684354560; // RSS (resident set size) limit.
+ const size_t kMaxNumPixels = kMaxNumBytes / 4; // At most ARGB.
+ const size_t kMaxNumPixelsSafe = kMaxNumPixels / 2; // Allow one buffer copy.
WebPBitstreamFeatures features;
if (WebPGetFeatures(data, size, &features) == VP8_STATUS_OK) {
if (!ImgIoUtilCheckSizeArgumentsOverflow(features.width * 4,
- features.height)) {
+ features.height) ||
+ static_cast<size_t>(features.width) * features.height >
+ kMaxNumPixelsSafe) {
return 0;
}
}
// decode everything as an animation
- WebPData webp_data = { data, size };
- WebPAnimDecoder* const dec = WebPAnimDecoderNew(&webp_data, NULL);
- if (dec == NULL) return 0;
+ WebPData webp_data = {data, size};
+ WebPAnimDecoder* const dec = WebPAnimDecoderNew(&webp_data, nullptr);
+ if (dec == nullptr) return 0;
WebPAnimInfo info;
if (!WebPAnimDecoderGetInfo(dec, &info)) goto End;
@@ -46,7 +55,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
int timestamp;
if (!WebPAnimDecoderGetNext(dec, &buf, &timestamp)) break;
}
- End:
+End:
WebPAnimDecoderDelete(dec);
return 0;
}
diff --git a/tests/fuzzer/animencoder_fuzzer.cc b/tests/fuzzer/animencoder_fuzzer.cc
index 1bd7871c..ef6ec1e4 100644
--- a/tests/fuzzer/animencoder_fuzzer.cc
+++ b/tests/fuzzer/animencoder_fuzzer.cc
@@ -47,6 +47,7 @@ int AddFrame(WebPAnimEncoder** const enc,
// Read the source picture.
if (!ExtractSourcePicture(&pic, data, size, bit_pos)) {
const WebPEncodingError error_code = pic.error_code;
+ WebPAnimEncoderDelete(*enc);
WebPPictureFree(&pic);
if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
fprintf(stderr, "Can't read input image. Error code: %d\n", error_code);
@@ -108,7 +109,14 @@ int AddFrame(WebPAnimEncoder** const enc,
const WebPEncodingError error_code = pic.error_code;
WebPAnimEncoderDelete(*enc);
WebPPictureFree(&pic);
- if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
+ // Tolerate failures when running under the nallocfuzz engine as
+ // WebPAnimEncoderAdd() may fail due to memory allocation errors outside of
+ // the encoder; in muxer functions that return booleans for instance.
+ if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY ||
+ error_code == VP8_ENC_ERROR_BAD_WRITE ||
+ getenv("NALLOC_FUZZ_VERSION") != nullptr) {
+ return 0;
+ }
fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code);
abort();
}
@@ -163,7 +171,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
}
WebPData webp_data;
WebPDataInit(&webp_data);
- if (!WebPAnimEncoderAssemble(enc, &webp_data)) {
+ // Tolerate failures when running under the nallocfuzz engine as allocations
+ // during assembly may fail.
+ if (!WebPAnimEncoderAssemble(enc, &webp_data) &&
+ getenv("NALLOC_FUZZ_VERSION") == nullptr) {
fprintf(stderr, "WebPAnimEncoderAssemble failed: %s.\n",
WebPAnimEncoderGetError(enc));
WebPAnimEncoderDelete(enc);
diff --git a/tests/fuzzer/enc_dec_fuzzer.cc b/tests/fuzzer/enc_dec_fuzzer.cc
index 187b5162..c5d46ae0 100644
--- a/tests/fuzzer/enc_dec_fuzzer.cc
+++ b/tests/fuzzer/enc_dec_fuzzer.cc
@@ -91,50 +91,70 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
const WebPEncodingError error_code = pic.error_code;
WebPMemoryWriterClear(&memory_writer);
WebPPictureFree(&pic);
- if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
+ if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY ||
+ error_code == VP8_ENC_ERROR_BAD_WRITE) {
+ return 0;
+ }
fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code);
abort();
}
// Try decoding the result.
- int w, h;
const uint8_t* const out_data = memory_writer.mem;
const size_t out_size = memory_writer.size;
- uint8_t* const rgba = WebPDecodeBGRA(out_data, out_size, &w, &h);
- if (rgba == nullptr || w != pic.width || h != pic.height) {
- fprintf(stderr, "WebPDecodeBGRA failed.\n");
- WebPFree(rgba);
+ WebPDecoderConfig dec_config;
+ if (!WebPInitDecoderConfig(&dec_config)) {
+ fprintf(stderr, "WebPInitDecoderConfig failed.\n");
+ WebPMemoryWriterClear(&memory_writer);
+ WebPPictureFree(&pic);
+ abort();
+ }
+
+ dec_config.output.colorspace = MODE_BGRA;
+ const VP8StatusCode status = WebPDecode(out_data, out_size, &dec_config);
+ if ((status != VP8_STATUS_OK && status != VP8_STATUS_OUT_OF_MEMORY &&
+ status != VP8_STATUS_USER_ABORT) ||
+ (status == VP8_STATUS_OK && (dec_config.output.width != pic.width ||
+ dec_config.output.height != pic.height))) {
+ fprintf(stderr, "WebPDecode failed. status: %d.\n", status);
+ WebPFreeDecBuffer(&dec_config.output);
WebPMemoryWriterClear(&memory_writer);
WebPPictureFree(&pic);
abort();
}
- // Compare the results if exact encoding.
- if (pic.use_argb && config.lossless && config.near_lossless == 100) {
- const uint32_t* src1 = (const uint32_t*)rgba;
- const uint32_t* src2 = pic.argb;
- for (int y = 0; y < h; ++y, src1 += w, src2 += pic.argb_stride) {
- for (int x = 0; x < w; ++x) {
- uint32_t v1 = src1[x], v2 = src2[x];
- if (!config.exact) {
- if ((v1 & 0xff000000u) == 0 || (v2 & 0xff000000u) == 0) {
- // Only keep alpha for comparison of fully transparent area.
- v1 &= 0xff000000u;
- v2 &= 0xff000000u;
+ if (status == VP8_STATUS_OK) {
+ const uint8_t* const rgba = dec_config.output.u.RGBA.rgba;
+ const int w = dec_config.output.width;
+ const int h = dec_config.output.height;
+
+ // Compare the results if exact encoding.
+ if (pic.use_argb && config.lossless && config.near_lossless == 100) {
+ const uint32_t* src1 = (const uint32_t*)rgba;
+ const uint32_t* src2 = pic.argb;
+ for (int y = 0; y < h; ++y, src1 += w, src2 += pic.argb_stride) {
+ for (int x = 0; x < w; ++x) {
+ uint32_t v1 = src1[x], v2 = src2[x];
+ if (!config.exact) {
+ if ((v1 & 0xff000000u) == 0 || (v2 & 0xff000000u) == 0) {
+ // Only keep alpha for comparison of fully transparent area.
+ v1 &= 0xff000000u;
+ v2 &= 0xff000000u;
+ }
+ }
+ if (v1 != v2) {
+ fprintf(stderr, "Lossless compression failed pixel-exactness.\n");
+ WebPFreeDecBuffer(&dec_config.output);
+ WebPMemoryWriterClear(&memory_writer);
+ WebPPictureFree(&pic);
+ abort();
}
- }
- if (v1 != v2) {
- fprintf(stderr, "Lossless compression failed pixel-exactness.\n");
- WebPFree(rgba);
- WebPMemoryWriterClear(&memory_writer);
- WebPPictureFree(&pic);
- abort();
}
}
}
}
- WebPFree(rgba);
+ WebPFreeDecBuffer(&dec_config.output);
WebPMemoryWriterClear(&memory_writer);
WebPPictureFree(&pic);
return 0;
diff --git a/tests/fuzzer/fuzz_utils.h b/tests/fuzzer/fuzz_utils.h
index 713a5f40..c3fc366d 100644
--- a/tests/fuzzer/fuzz_utils.h
+++ b/tests/fuzzer/fuzz_utils.h
@@ -28,9 +28,20 @@
//------------------------------------------------------------------------------
// Arbitrary limits to prevent OOM, timeout, or slow execution.
-//
+
// The decoded image size, and for animations additionally the canvas size.
+// Enabling some sanitizers slow down runtime significantly.
+// Use a very low threshold in this case to avoid timeouts.
+#if defined(__SANITIZE_ADDRESS__) // GCC
+static const size_t kFuzzPxLimit = 1024 * 1024 / 10;
+#elif !defined(__has_feature) // Clang
static const size_t kFuzzPxLimit = 1024 * 1024;
+#elif __has_feature(address_sanitizer) || __has_feature(memory_sanitizer)
+static const size_t kFuzzPxLimit = 1024 * 1024 / 18;
+#else
+static const size_t kFuzzPxLimit = 1024 * 1024;
+#endif
+
// Demuxed or decoded animation frames.
static const int kFuzzFrameLimit = 3;
@@ -63,6 +74,11 @@ static WEBP_INLINE uint32_t Extract(uint32_t max_value,
//------------------------------------------------------------------------------
// Some functions to override VP8GetCPUInfo and disable some optimizations.
+#ifdef __cplusplus
+extern "C" VP8CPUInfo VP8GetCPUInfo;
+#else
+extern VP8CPUInfo VP8GetCPUInfo;
+#endif
static VP8CPUInfo GetCPUInfo;
static WEBP_INLINE int GetCPUInfoNoSSE41(CPUFeature feature) {
diff --git a/tests/fuzzer/huffman_fuzzer.c b/tests/fuzzer/huffman_fuzzer.c
new file mode 100644
index 00000000..03e1fdc4
--- /dev/null
+++ b/tests/fuzzer/huffman_fuzzer.c
@@ -0,0 +1,65 @@
+// Copyright 2023 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdint.h>
+#include <string.h>
+
+#include "src/dec/vp8li_dec.h"
+#include "src/utils/bit_reader_utils.h"
+#include "src/utils/huffman_utils.h"
+#include "src/utils/utils.h"
+#include "src/webp/format_constants.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
+ // Number of bits to initialize data.
+ static const int kColorCacheBitsBits = 4;
+ // 'num_htree_groups' is contained in the RG channel, hence 16 bits.
+ static const int kNumHtreeGroupsBits = 16;
+ if (size * sizeof(*data) < kColorCacheBitsBits + kNumHtreeGroupsBits) {
+ return 0;
+ }
+
+ // A non-NULL mapping brings minor changes that are tested by the normal
+ // fuzzer.
+ int* const mapping = NULL;
+ HuffmanTables huffman_tables;
+ memset(&huffman_tables, 0, sizeof(huffman_tables));
+ HTreeGroup* htree_groups = NULL;
+
+ VP8LDecoder* dec = VP8LNew();
+ if (dec == NULL) goto Error;
+ VP8LBitReader* const br = &dec->br_;
+ VP8LInitBitReader(br, data, size);
+
+ const int color_cache_bits = VP8LReadBits(br, kColorCacheBitsBits);
+ if (color_cache_bits < 1 || color_cache_bits > MAX_CACHE_BITS) goto Error;
+
+ const int num_htree_groups = VP8LReadBits(br, kNumHtreeGroupsBits);
+ // 'num_htree_groups' cannot be 0 as it is built from a non-empty image.
+ if (num_htree_groups == 0) goto Error;
+ // This variable is only useful when mapping is not NULL.
+ const int num_htree_groups_max = num_htree_groups;
+ (void)ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups,
+ num_htree_groups_max, mapping, dec,
+ &huffman_tables, &htree_groups);
+
+ Error:
+ WebPSafeFree(mapping);
+ VP8LHtreeGroupsFree(htree_groups);
+ VP8LHuffmanTablesDeallocate(&huffman_tables);
+ VP8LDelete(dec);
+ return 0;
+}
diff --git a/tests/fuzzer/makefile.unix b/tests/fuzzer/makefile.unix
index 4a9bff35..3a3aff0a 100644
--- a/tests/fuzzer/makefile.unix
+++ b/tests/fuzzer/makefile.unix
@@ -11,9 +11,9 @@ LDLIBS = ../../src/mux/libwebpmux.a ../../src/demux/libwebpdemux.a
LDLIBS += ../../src/libwebp.a ../../imageio/libimageio_util.a
LDLIBS += ../../sharpyuv/libsharpyuv.a
-FUZZERS = advanced_api_fuzzer animation_api_fuzzer animencoder_fuzzer
-FUZZERS += animdecoder_fuzzer mux_demux_api_fuzzer enc_dec_fuzzer
-FUZZERS += simple_api_fuzzer
+FUZZERS = advanced_api_fuzzer animation_api_fuzzer animdecoder_fuzzer
+FUZZERS += animencoder_fuzzer enc_dec_fuzzer huffman_fuzzer
+FUZZERS += mux_demux_api_fuzzer simple_api_fuzzer
%.o: fuzz_utils.h img_alpha.h img_grid.h img_peak.h
all: $(FUZZERS)
diff --git a/tests/fuzzer/mux_demux_api_fuzzer.c b/tests/fuzzer/mux_demux_api_fuzzer.c
index 4ed01427..f5983e8d 100644
--- a/tests/fuzzer/mux_demux_api_fuzzer.c
+++ b/tests/fuzzer/mux_demux_api_fuzzer.c
@@ -33,15 +33,15 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
if (!mux) return 0;
WebPData chunk;
- WebPMuxGetChunk(mux, "EXIF", &chunk);
- WebPMuxGetChunk(mux, "ICCP", &chunk);
- WebPMuxGetChunk(mux, "FUZZ", &chunk); // unknown
+ (void)WebPMuxGetChunk(mux, "EXIF", &chunk);
+ (void)WebPMuxGetChunk(mux, "ICCP", &chunk);
+ (void)WebPMuxGetChunk(mux, "FUZZ", &chunk); // unknown
uint32_t flags;
- WebPMuxGetFeatures(mux, &flags);
+ (void)WebPMuxGetFeatures(mux, &flags);
WebPMuxAnimParams params;
- WebPMuxGetAnimationParams(mux, &params);
+ (void)WebPMuxGetAnimationParams(mux, &params);
WebPMuxError status;
WebPMuxFrameInfo info;
@@ -72,11 +72,11 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
WebPChunkIterator chunk_iter;
if (WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
- WebPDemuxNextChunk(&chunk_iter);
+ (void)WebPDemuxNextChunk(&chunk_iter);
}
WebPDemuxReleaseChunkIterator(&chunk_iter);
if (WebPDemuxGetChunk(demux, "ICCP", 0, &chunk_iter)) { // 0 == last
- WebPDemuxPrevChunk(&chunk_iter);
+ (void)WebPDemuxPrevChunk(&chunk_iter);
}
WebPDemuxReleaseChunkIterator(&chunk_iter);
// Skips FUZZ because the Demux API has no concept of (un)known chunks.
diff --git a/tests/fuzzer/simple_api_fuzzer.c b/tests/fuzzer/simple_api_fuzzer.c
index 7d2b7f81..3a4288a4 100644
--- a/tests/fuzzer/simple_api_fuzzer.c
+++ b/tests/fuzzer/simple_api_fuzzer.c
@@ -49,17 +49,17 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
if (value % 0x10 == 0) buf_size--;
uint8_t* const ext_buf = (uint8_t*)malloc(buf_size);
if (value < 0x94) {
- WebPDecodeRGBAInto(data, size, ext_buf, buf_size, stride);
+ (void)WebPDecodeRGBAInto(data, size, ext_buf, buf_size, stride);
#if !defined(WEBP_REDUCE_CSP)
} else if (value < 0xa9) {
- WebPDecodeARGBInto(data, size, ext_buf, buf_size, stride);
+ (void)WebPDecodeARGBInto(data, size, ext_buf, buf_size, stride);
} else if (value < 0xbe) {
- WebPDecodeBGRInto(data, size, ext_buf, buf_size, stride);
+ (void)WebPDecodeBGRInto(data, size, ext_buf, buf_size, stride);
} else if (value < 0xd3) {
- WebPDecodeRGBInto(data, size, ext_buf, buf_size, stride);
+ (void)WebPDecodeRGBInto(data, size, ext_buf, buf_size, stride);
#endif // !defined(WEBP_REDUCE_CSP)
} else {
- WebPDecodeBGRAInto(data, size, ext_buf, buf_size, stride);
+ (void)WebPDecodeBGRAInto(data, size, ext_buf, buf_size, stride);
}
free(ext_buf);
} else {
@@ -75,8 +75,9 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
uint8_t* const luma_buf = (uint8_t*)malloc(luma_size);
uint8_t* const u_buf = (uint8_t*)malloc(u_size);
uint8_t* const v_buf = (uint8_t*)malloc(v_size);
- WebPDecodeYUVInto(data, size, luma_buf, luma_size, w /* luma_stride */,
- u_buf, u_size, uv_stride, v_buf, v_size, uv_stride);
+ (void)WebPDecodeYUVInto(data, size, luma_buf, luma_size,
+ w /* luma_stride */, u_buf, u_size, uv_stride,
+ v_buf, v_size, uv_stride);
free(luma_buf);
free(u_buf);
free(v_buf);
diff --git a/webp_js/README.md b/webp_js/README.md
index 824afa0b..ae9ce8f0 100644
--- a/webp_js/README.md
+++ b/webp_js/README.md
@@ -20,8 +20,7 @@ Emscripten and CMake.
```shell
cd webp_js && \
- emcmake cmake -DWEBP_BUILD_WEBP_JS=ON \
- ../
+ emcmake cmake -DWEBP_BUILD_WEBP_JS=ON ../
```
- compile webp.js using 'emmake make'.
@@ -55,27 +54,7 @@ directory.
See webp_js/index_wasm.html for a simple demo page using the WASM version of the
library.
-You will need a fairly recent version of Emscripten (at least 2.0.18,
-latest-upstream is recommended) and of your WASM-enabled browser to run this
-version.
-
## Caveats
- First decoding using the library is usually slower, due to just-in-time
compilation.
-
-- Some versions of llvm produce the following compile error when SSE2 is
- enabled.
-
- ```
- "Unsupported: %516 = bitcast <8 x i16> %481 to i128
- LLVM ERROR: BitCast Instruction not yet supported for integer types larger than 64 bits"
- ```
-
- The corresponding Emscripten bug is at:
- https://github.com/kripken/emscripten/issues/3788
-
- Therefore, SSE2 optimization is currently disabled in CMakeLists.txt.
-
-- If WEBP_ENABLE_SIMD is set to 1 the JavaScript version (webp.js) will be
- disabled as wasm2js does not support SIMD.
diff --git a/webp_js/index.html b/webp_js/index.html
index 33cacb4c..e7c3b652 100644
--- a/webp_js/index.html
+++ b/webp_js/index.html
@@ -29,6 +29,8 @@ function decode(webp_data, canvas_id) {
// clear previous picture (if any)
Module.canvas = canvas;
canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
+ // Map this canvas to the default selector used by emscripten/SDL2.
+ specialHTMLTargets["#canvas"] = Module.canvas;
// decode and measure timing
var start = new Date();
var ret = WebpToCanvas(webp_data, webp_data.length);
diff --git a/webp_js/index_wasm.html b/webp_js/index_wasm.html
index 5d7c17e8..29933aba 100644
--- a/webp_js/index_wasm.html
+++ b/webp_js/index_wasm.html
@@ -9,6 +9,7 @@
noInitialRun : true
};
</script>
+ <script src="./webp_wasm.js"></script>
<script type="text/javascript">
'use strict';
@@ -16,40 +17,27 @@
// main wrapper for the function decoding a WebP into a canvas object
var WebpToCanvas;
-function init() {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', 'webp_wasm.wasm', true);
- xhr.responseType = 'arraybuffer';
- xhr.onload = function() {
- Module.wasmBinary = xhr.response;
- var script = document.createElement('script');
- script.src = "webp_wasm.js";
- document.body.appendChild(script);
- };
- xhr.send(null);
-}
-window.onload = init;
+Module.onRuntimeInitialized = async () => {
+ // wrapper for the function decoding a WebP into a canvas object
+ WebpToCanvas = Module.cwrap('WebPToSDL', 'number', ['array', 'number']);
+};
function decode(webp_data, canvas_id) {
var result;
- if (Module["asm"] != undefined) {
- // wrapper for the function decoding a WebP into a canvas object
- WebpToCanvas = Module.cwrap('WebPToSDL', 'number', ['array', 'number']);
- // get the canvas to decode into
- var canvas = document.getElementById(canvas_id);
- if (canvas == null) return;
- // clear previous picture (if any)
- Module.canvas = canvas;
- canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
- // decode and measure timing
- var start = new Date();
- var ret = WebpToCanvas(webp_data, webp_data.length);
- var end = new Date();
- var decode_time = end - start;
- result = 'decoding time: ' + decode_time +' ms.';
- } else {
- result = "WASM module not finished loading! Please retry";
- }
+ // get the canvas to decode into
+ var canvas = document.getElementById(canvas_id);
+ if (canvas == null) return;
+ // clear previous picture (if any)
+ Module.canvas = canvas;
+ canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
+ // Map this canvas to the default selector used by emscripten/SDL2.
+ specialHTMLTargets["#canvas"] = Module.canvas;
+ // decode and measure timing
+ var start = new Date();
+ var ret = WebpToCanvas(webp_data, webp_data.length);
+ var end = new Date();
+ var decodeTime = end - start;
+ result = 'decoding time: ' + decodeTime +' ms.';
// display timing result
var speed_result = document.getElementById('timing');
if (speed_result != null) {
diff --git a/xcframeworkbuild.sh b/xcframeworkbuild.sh
index 8d484c2a..14b987d4 100755
--- a/xcframeworkbuild.sh
+++ b/xcframeworkbuild.sh
@@ -69,6 +69,7 @@ readonly TARGETDIR="${TOPDIR}/WebP.xcframework"
readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.xcframework"
readonly MUXTARGETDIR="${TOPDIR}/WebPMux.xcframework"
readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.xcframework"
+readonly SHARPYUVTARGETDIR="${TOPDIR}/SharpYuv.xcframework"
readonly DEVELOPER=$(xcode-select --print-path)
readonly DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain"
readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
@@ -94,8 +95,15 @@ update_headers_path() {
local subdir
for d in $(find "$1" -path "*/Headers"); do
subdir="$d/$framework_name"
- mkdir "$subdir"
- mv "$d/"*.h "$subdir"
+ if [[ -d "$subdir" ]]; then
+ # SharpYuv will have a sharpyuv subdirectory. macOS is case insensitive,
+ # but for consistency with the other frameworks, rename the directory to
+ # match the case of the framework name.
+ mv "$(echo ${subdir} | tr 'A-Z' 'a-z')" "$subdir"
+ else
+ mkdir "$subdir"
+ mv "$d/"*.h "$subdir"
+ fi
done
}
@@ -104,7 +112,8 @@ echo "iOS SDK Version: ${SDK[$IOS]}"
echo "MacOS SDK Version: ${SDK[$MACOS]}"
if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \
- || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" ]]; then
+ || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" \
+ || -e "${SHARPYUVTARGETDIR}" ]]; then
cat << EOF
WARNING: The following directories will be deleted:
WARNING: ${BUILDDIR}
@@ -112,12 +121,13 @@ WARNING: ${TARGETDIR}
WARNING: ${DECTARGETDIR}
WARNING: ${MUXTARGETDIR}
WARNING: ${DEMUXTARGETDIR}
+WARNING: ${SHARPYUVTARGETDIR}
WARNING: The build will continue in 5 seconds...
EOF
sleep 5
fi
rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \
- ${MUXTARGETDIR} ${DEMUXTARGETDIR}
+ ${MUXTARGETDIR} ${DEMUXTARGETDIR} ${SHARPYUVTARGETDIR}
if [[ ! -e ${SRCDIR}/configure ]]; then
if ! (cd ${SRCDIR} && sh autogen.sh); then
@@ -137,6 +147,7 @@ for (( i = 0; i < $NUM_PLATFORMS; ++i )); do
DECLIBLIST=()
MUXLIBLIST=()
DEMUXLIBLIST=()
+ SHARPYUVLIBLIST=()
for PLATFORM in ${PLATFORMS[$i]}; do
ROOTDIR="${BUILDDIR}/${PLATFORM}"
@@ -187,23 +198,26 @@ for (( i = 0; i < $NUM_PLATFORMS; ++i )); do
set +x
# Build only the libraries, skip the examples.
- make V=0 -C sharpyuv
+ make V=0 -C sharpyuv install
make V=0 -C src install
LIBLIST+=("${ROOTDIR}/lib/libwebp.a")
DECLIBLIST+=("${ROOTDIR}/lib/libwebpdecoder.a")
MUXLIBLIST+=("${ROOTDIR}/lib/libwebpmux.a")
DEMUXLIBLIST+=("${ROOTDIR}/lib/libwebpdemux.a")
+ SHARPYUVLIBLIST+=("${ROOTDIR}/lib/libsharpyuv.a")
# xcodebuild requires a directory for the -headers option, these will match
# for all builds.
make -C src install-data DESTDIR="${ROOTDIR}/lib-headers"
make -C src install-commonHEADERS DESTDIR="${ROOTDIR}/dec-headers"
make -C src/demux install-data DESTDIR="${ROOTDIR}/demux-headers"
make -C src/mux install-data DESTDIR="${ROOTDIR}/mux-headers"
+ make -C sharpyuv install-data DESTDIR="${ROOTDIR}/sharpyuv-headers"
LIB_HEADERS="${ROOTDIR}/lib-headers/${ROOTDIR}/include/webp"
DEC_HEADERS="${ROOTDIR}/dec-headers/${ROOTDIR}/include/webp"
DEMUX_HEADERS="${ROOTDIR}/demux-headers/${ROOTDIR}/include/webp"
MUX_HEADERS="${ROOTDIR}/mux-headers/${ROOTDIR}/include/webp"
+ SHARPYUV_HEADERS="${ROOTDIR}/sharpyuv-headers/${ROOTDIR}/include/webp"
make distclean
@@ -220,16 +234,20 @@ for (( i = 0; i < $NUM_PLATFORMS; ++i )); do
target_declib="${target_dir}/$(basename ${DECLIBLIST[0]})"
target_demuxlib="${target_dir}/$(basename ${DEMUXLIBLIST[0]})"
target_muxlib="${target_dir}/$(basename ${MUXLIBLIST[0]})"
+ target_sharpyuvlib="${target_dir}/$(basename ${SHARPYUVLIBLIST[0]})"
mkdir -p "${target_dir}"
${LIPO} -create ${LIBLIST[@]} -output "${target_lib}"
${LIPO} -create ${DECLIBLIST[@]} -output "${target_declib}"
${LIPO} -create ${DEMUXLIBLIST[@]} -output "${target_demuxlib}"
${LIPO} -create ${MUXLIBLIST[@]} -output "${target_muxlib}"
+ ${LIPO} -create ${SHARPYUVLIBLIST[@]} -output "${target_sharpyuvlib}"
FAT_LIBLIST+=(-library "${target_lib}" -headers "${LIB_HEADERS}")
FAT_DECLIBLIST+=(-library "${target_declib}" -headers "${DEC_HEADERS}")
FAT_DEMUXLIBLIST+=(-library "${target_demuxlib}" -headers "${DEMUX_HEADERS}")
FAT_MUXLIBLIST+=(-library "${target_muxlib}" -headers "${MUX_HEADERS}")
+ FAT_SHARPYUVLIBLIST+=(-library "${target_sharpyuvlib}")
+ FAT_SHARPYUVLIBLIST+=(-headers "${SHARPYUV_HEADERS}")
done
# lipo will not put archives with the same architecture (e.g., x86_64
@@ -246,10 +264,13 @@ xcodebuild -create-xcframework "${FAT_DEMUXLIBLIST[@]}" \
-output ${DEMUXTARGETDIR}
xcodebuild -create-xcframework "${FAT_MUXLIBLIST[@]}" \
-output ${MUXTARGETDIR}
+xcodebuild -create-xcframework "${FAT_SHARPYUVLIBLIST[@]}" \
+ -output ${SHARPYUVTARGETDIR}
update_headers_path "${TARGETDIR}"
update_headers_path "${DECTARGETDIR}"
update_headers_path "${DEMUXTARGETDIR}"
update_headers_path "${MUXTARGETDIR}"
+update_headers_path "${SHARPYUVTARGETDIR}"
set +x
echo "SUCCESS"