Bladeren bron

Merge pull request #27 from bmx-ng/task/image-updates

Task/image updates
Brucey 1 jaar geleden
bovenliggende
commit
7db3a5d810
100 gewijzigde bestanden met toevoegingen van 19127 en 4188 verwijderingen
  1. 13 17
      png.mod/libpng/ANNOUNCE
  2. 2 0
      png.mod/libpng/AUTHORS
  3. 14 6
      png.mod/libpng/CHANGES
  4. 201 182
      png.mod/libpng/CMakeLists.txt
  5. 2 2
      png.mod/libpng/LICENSE
  6. 80 82
      png.mod/libpng/README
  7. 1 1
      png.mod/libpng/autogen.sh
  8. 64 53
      png.mod/libpng/ci/ci_verify_cmake.sh
  9. 26 15
      png.mod/libpng/ci/ci_verify_configure.sh
  10. 39 32
      png.mod/libpng/ci/ci_verify_makefiles.sh
  11. 12 12
      png.mod/libpng/configure
  12. 3 3
      png.mod/libpng/configure.ac
  13. 1 1
      png.mod/libpng/contrib/libtests/makepng.c
  14. 1 1
      png.mod/libpng/contrib/libtests/pngstest.c
  15. 2 2
      png.mod/libpng/contrib/libtests/pngvalid.c
  16. 1 1
      png.mod/libpng/contrib/libtests/tarith.c
  17. 1 1
      png.mod/libpng/contrib/pngminus/LICENSE.txt
  18. 1 1
      png.mod/libpng/contrib/tools/pngfix.c
  19. 1 1
      png.mod/libpng/contrib/visupng/VisualPng.c
  20. 3 3
      png.mod/libpng/libpng-manual.txt
  21. 20 30
      png.mod/libpng/libpng.3
  22. 2 2
      png.mod/libpng/libpngpf.3
  23. 4 29
      png.mod/libpng/png.5
  24. 4 4
      png.mod/libpng/png.c
  25. 11 11
      png.mod/libpng/png.h
  26. 1 1
      png.mod/libpng/pngconf.h
  27. 12 1
      png.mod/libpng/pngget.c
  28. 3 3
      png.mod/libpng/pngpriv.h
  29. 24 36
      png.mod/libpng/pngset.c
  30. 1 1
      png.mod/libpng/pngtest.c
  31. 7 3
      png.mod/libpng/pngwrite.c
  32. 3 3
      png.mod/libpng/scripts/genout.cmake.in
  33. 1 1
      png.mod/libpng/scripts/gensrc.cmake.in
  34. 1 1
      png.mod/libpng/scripts/libpng-config-head.in
  35. 1 1
      png.mod/libpng/scripts/libpng.pc.in
  36. 4 4
      png.mod/libpng/scripts/pnglibconf.dfa
  37. 2 2
      png.mod/libpng/scripts/pnglibconf.h.prebuilt
  38. 3 1
      png.mod/png.bmx
  39. 1 1
      stb.mod/common.bmx
  40. 1 1
      stb.mod/glue.c
  41. 4 2
      stb.mod/stb.bmx
  42. 175 191
      stb.mod/stb/stb_image.h
  43. 0 2634
      stb.mod/stb/stb_image_resize.h
  44. 10325 0
      stb.mod/stb/stb_image_resize2.h
  45. 1 1
      svg.mod/common.bmx
  46. 1 1
      svg.mod/glue.c
  47. 75 0
      svg.mod/nanosvg/CMakeLists.txt
  48. 5 0
      svg.mod/nanosvg/Config.cmake.in
  49. 5 4
      svg.mod/nanosvg/src/nanosvgrast.h
  50. 11 1
      svg.mod/svg.bmx
  51. 2 0
      webp.mod/libwebp/Android.mk
  52. 35 10
      webp.mod/libwebp/CMakeLists.txt
  53. 1 0
      webp.mod/libwebp/Makefile.vc
  54. 2 0
      webp.mod/libwebp/build.gradle
  55. 2 1
      webp.mod/libwebp/cmake/WebPConfig.cmake.in
  56. 4 5
      webp.mod/libwebp/configure.ac
  57. 1 1
      webp.mod/libwebp/doc/api.md
  58. 18 0
      webp.mod/libwebp/doc/building.md
  59. 141 137
      webp.mod/libwebp/doc/webp-container-spec.txt
  60. 267 247
      webp.mod/libwebp/doc/webp-lossless-bitstream-spec.txt
  61. 5 1
      webp.mod/libwebp/examples/anim_dump.c
  62. 9 5
      webp.mod/libwebp/examples/cwebp.c
  63. 1 1
      webp.mod/libwebp/examples/vwebp.c
  64. 6 6
      webp.mod/libwebp/examples/webpinfo.c
  65. 1 1
      webp.mod/libwebp/extras/vwebp_sdl.c
  66. 35 48
      webp.mod/libwebp/extras/webp_to_sdl.c
  67. 52 29
      webp.mod/libwebp/imageio/image_enc.c
  68. 14 4
      webp.mod/libwebp/iosbuild.sh
  69. 7 4
      webp.mod/libwebp/makefile.unix
  70. 1 0
      webp.mod/libwebp/sharpyuv/Makefile.am
  71. 207 59
      webp.mod/libwebp/sharpyuv/sharpyuv.c
  72. 103 2
      webp.mod/libwebp/sharpyuv/sharpyuv.h
  73. 64 2
      webp.mod/libwebp/sharpyuv/sharpyuv_dsp.c
  74. 10 0
      webp.mod/libwebp/sharpyuv/sharpyuv_dsp.h
  75. 308 2
      webp.mod/libwebp/sharpyuv/sharpyuv_gamma.c
  76. 7 4
      webp.mod/libwebp/sharpyuv/sharpyuv_gamma.h
  77. 6210 0
      webp.mod/libwebp/sharpyuv/sharpyuv_risk_table.c
  78. 27 0
      webp.mod/libwebp/sharpyuv/sharpyuv_risk_table.h
  79. 34 27
      webp.mod/libwebp/src/dec/alpha_dec.c
  80. 1 1
      webp.mod/libwebp/src/dec/buffer_dec.c
  81. 31 19
      webp.mod/libwebp/src/dec/idec_dec.c
  82. 12 8
      webp.mod/libwebp/src/dec/vp8_dec.c
  83. 8 9
      webp.mod/libwebp/src/dec/vp8_dec.h
  84. 7 4
      webp.mod/libwebp/src/dec/vp8i_dec.h
  85. 100 68
      webp.mod/libwebp/src/dec/vp8l_dec.c
  86. 21 7
      webp.mod/libwebp/src/dec/vp8li_dec.h
  87. 30 18
      webp.mod/libwebp/src/dec/webp_dec.c
  88. 4 2
      webp.mod/libwebp/src/dec/webpi_dec.h
  89. 14 8
      webp.mod/libwebp/src/demux/anim_decode.c
  90. 41 0
      webp.mod/libwebp/src/dsp/alpha_processing_sse2.c
  91. 0 12
      webp.mod/libwebp/src/dsp/cpu.c
  92. 8 1
      webp.mod/libwebp/src/dsp/filters.c
  93. 3 3
      webp.mod/libwebp/src/dsp/lossless.h
  94. 3 3
      webp.mod/libwebp/src/dsp/lossless_common.h
  95. 14 9
      webp.mod/libwebp/src/dsp/lossless_enc.c
  96. 7 7
      webp.mod/libwebp/src/dsp/lossless_enc_mips32.c
  97. 52 2
      webp.mod/libwebp/src/dsp/lossless_enc_sse41.c
  98. 15 17
      webp.mod/libwebp/src/dsp/msa_macro.h
  99. 2 1
      webp.mod/libwebp/src/dsp/quant.h
  100. 4 7
      webp.mod/libwebp/src/enc/alpha_enc.c

+ 13 - 17
png.mod/libpng/ANNOUNCE

@@ -1,5 +1,5 @@
-libpng 1.6.39 - November 20, 2022
-=================================
+libpng 1.6.40 - June 21, 2023
+=============================
 
 This is a public release of libpng, intended for use in production code.
 
@@ -9,13 +9,13 @@ Files available for download
 
 Source files with LF line endings (for Unix/Linux):
 
- * libpng-1.6.39.tar.xz (LZMA-compressed, recommended)
- * libpng-1.6.39.tar.gz
+ * libpng-1.6.40.tar.xz (LZMA-compressed, recommended)
+ * libpng-1.6.40.tar.gz
 
 Source files with CRLF line endings (for Windows):
 
- * lpng1639.7z (LZMA-compressed, recommended)
- * lpng1639.zip
+ * lpng1640.7z (LZMA-compressed, recommended)
+ * lpng1640.zip
 
 Other information:
 
@@ -25,19 +25,15 @@ Other information:
  * TRADEMARK.md
 
 
-Changes from version 1.6.38 to version 1.6.39
+Changes from version 1.6.39 to version 1.6.40
 ---------------------------------------------
 
- * Changed the error handler of oversized chunks (i.e. larger than
-   PNG_USER_CHUNK_MALLOC_MAX) from png_chunk_error to png_benign_error.
- * Fixed a buffer overflow error in contrib/tools/pngfix.
- * Fixed a memory leak (CVE-2019-6129) in contrib/tools/pngcp.
- * Disabled the ARM Neon optimizations by default in the CMake file,
-   following the default behavior of the configure script.
- * Allowed configure.ac to work with the trunk version of autoconf.
- * Removed the support for "install" targets from the legacy makefiles;
-   removed the obsolete makefile.cegcc.
- * Cleaned up the code and updated the internal documentation.
+ * Fixed the eXIf chunk multiplicity checks.
+ * Fixed a memory leak in pCAL processing.
+ * Corrected the validity report about tRNS inside png_get_valid().
+ * Fixed various build issues on *BSD, Mac and Windows.
+ * Updated the configurations and the scripts for continuous integration.
+ * Cleaned up the code, the build scripts, and the documentation.
 
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.

+ 2 - 0
png.mod/libpng/AUTHORS

@@ -22,6 +22,7 @@ Authors, for copyright and licensing purposes.
  * Mike Klein
  * Pascal Massimino
  * Paul Schmidt
+ * Philippe Antoine
  * Qiang Zhou
  * Sam Bushell
  * Samuel Williams
@@ -40,6 +41,7 @@ Authors, for copyright and licensing purposes.
    - Matt Sarett
    - Mike Klein
    - Sami Boukortt
+   - Wan-Teh Chang
 
 The build projects, the build scripts, the test scripts, and other
 files in the "ci", "projects", "scripts" and "tests" directories, have

+ 14 - 6
png.mod/libpng/CHANGES

@@ -204,7 +204,7 @@ Version 0.97 [January, 1998]
   Added simple sRGB support (Glenn R-P)
   Easier conditional compiling, e.g.,
     define PNG_READ/WRITE_NOT_FULLY_SUPPORTED;
-    all configurable options can be selected from command-line instead
+    all configurable options can be selected from command line instead
     of having to edit pngconf.h (Glenn R-P)
   Fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P)
   Added more conditions for png_do_background, to avoid changing
@@ -942,7 +942,7 @@ Version 1.0.8 [July 24, 2000]
 Version 1.0.9beta1 [November 10, 2000]
   Fixed typo in scripts/makefile.hpux
   Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser)
-  Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser)
+  Fixed sequence-point bug in contrib/pngminus/png2pnm (Martin Zinser)
   Changed "cdrom.com" in documentation to "libpng.org"
   Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg).
   Changed type of "params" from voidp to png_voidp in png_read|write_png().
@@ -2295,7 +2295,7 @@ Version 1.4.0beta58 [May 14, 2009]
   Clarified usage of sig_bit versus sig_bit_p in example.c (Vincent Torri)
 
 Version 1.4.0beta59 [May 15, 2009]
-  Reformated sources in libpng style (3-space indentation, comment format)
+  Reformatted sources in libpng style (3-space indentation, comment format)
   Fixed typo in libpng docs (PNG_FILTER_AVE should be PNG_FILTER_AVG)
   Added sections about the git repository and our coding style to the
     documentation
@@ -2661,7 +2661,7 @@ Version 1.4.1beta06 [January 28, 2010]
 
 Version 1.4.1beta07 [February 6, 2010]
   Folded some long lines in the source files.
-  Added defineable PNG_USER_CHUNK_CACHE_MAX, PNG_USER_CHUNK_MALLOC_MAX,
+  Added definable PNG_USER_CHUNK_CACHE_MAX, PNG_USER_CHUNK_MALLOC_MAX,
     and a PNG_USER_LIMITS_SUPPORTED flag.
   Eliminated use of png_ptr->irowbytes and reused the slot in png_ptr as
     png_ptr->png_user_chunk_malloc_max.
@@ -3919,7 +3919,7 @@ Version 1.6.0beta08 [February 1, 2012]
     version checking to configure.ac
   Improved pngstest speed by not doing redundant tests and add const to
     the background parameter of png_image_finish_read. The --background
-    option is now done automagically only when required, so that commandline
+    option is now done automagically only when required, so that command-line
     option no longer exists.
   Cleaned up pngpriv.h to consistently declare all functions and data.
     Also eliminated PNG_CONST_DATA, which is apparently not needed but we
@@ -5927,7 +5927,7 @@ Version 1.6.32beta03 [August 2, 2017]
     (Bug report from the OSS-fuzz project).
 
 Version 1.6.32beta04 [August 2, 2017]
-  Replaced local eXIf_buf with info_ptr-eXIf_buf in png_handle_eXIf().
+  Replaced local eXIf_buf with info_ptr->eXIf_buf in png_handle_eXIf().
   Update libpng.3 and libpng-manual.txt about eXIf functions.
 
 Version 1.6.32beta05 [August 2, 2017]
@@ -6121,6 +6121,14 @@ Version 1.6.39 [November 20, 2022]
     removed the obsolete makefile.cegcc.
   Cleaned up the code and updated the internal documentation.
 
+Version 1.6.40 [June 21, 2023]
+  Fixed the eXIf chunk multiplicity checks.
+  Fixed a memory leak in pCAL processing.
+  Corrected the validity report about tRNS inside png_get_valid().
+  Fixed various build issues on *BSD, Mac and Windows.
+  Updated the configurations and the scripts for continuous integration.
+  Cleaned up the code, the build scripts, and the documentation.
+
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
 Subscription is required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement

+ 201 - 182
png.mod/libpng/CMakeLists.txt

@@ -1,10 +1,11 @@
 # CMakeLists.txt
 
-# Copyright (c) 2018-2022 Cosmin Truta
+# Copyright (c) 2018-2023 Cosmin Truta
 # Copyright (c) 2007,2009-2018 Glenn Randers-Pehrson
 # Written by Christian Ehrlicher, 2007
 # Revised by Roger Lowman, 2009-2010
 # Revised by Clifford Yapp, 2011-2012,2017
+# Revised by Claudio Bley, 2013
 # Revised by Roger Leigh, 2016
 # Revised by Andreas Franek, 2016
 # Revised by Sam Serrels, 2017
@@ -19,7 +20,11 @@
 # Revised by Owen Rudge, 2020
 # Revised by Gleb Mazovetskiy, 2021
 # Revised by Christopher Sean Morrison, 2022
+# Revised by B. Scott Michel, 2022
+# Revised by Jeremy Maitin-Shepard, 2022
 # Revised by Martin Storsjo, 2022
+# Revised by Jon Creighton, 2023
+# Revised by Gunther Nikl, 2023
 
 # This code is released under the libpng license.
 # For conditions of distribution and use, see the disclaimer
@@ -31,22 +36,47 @@ cmake_policy(VERSION 3.1)
 project(libpng C ASM)
 enable_testing()
 
+include(CMakeParseArguments)
+include(CheckCSourceCompiles)
+include(GNUInstallDirs)
+
 set(PNGLIB_MAJOR 1)
 set(PNGLIB_MINOR 6)
-set(PNGLIB_REVISION 39)
+set(PNGLIB_REVISION 40)
 set(PNGLIB_SUBREVISION 0)
 #set(PNGLIB_SUBREVISION "git")
-set(PNGLIB_NAME libpng${PNGLIB_MAJOR}${PNGLIB_MINOR})
 set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_REVISION})
-set(PNGLIB_SHARED_SOVERSION ${PNGLIB_MAJOR}${PNGLIB_MINOR})
-set(PNGLIB_SHARED_VERSION ${PNGLIB_SHARED_SOVERSION}.${PNGLIB_REVISION}.${PNGLIB_SUBREVISION})
-
-include(GNUInstallDirs)
+set(PNGLIB_ABI_VERSION ${PNGLIB_MAJOR}${PNGLIB_MINOR})
+set(PNGLIB_SHARED_VERSION ${PNGLIB_ABI_VERSION}.${PNGLIB_REVISION}.${PNGLIB_SUBREVISION})
+
+# Allow the users to specify an application-specific API prefix for libpng
+# vendoring purposes. A standard libpng build should have no such prefix.
+set(PNG_PREFIX ""
+    CACHE STRING "Prefix to prepend to the API function names")
+
+# Allow the users to override the postfix appended to debug library file names.
+# Previously, we used to set CMAKE_DEBUG_POSTFIX globally. That variable should
+# not be cached, however, because doing so would affect all projects processed
+# after libpng, in unexpected and undesirable ways.
+set(PNG_DEBUG_POSTFIX "d"
+    CACHE STRING "Postfix to append to library file names under the Debug configuration")
+
+# Allow the users to import their own extra configuration settings.
+set(DFA_XTRA ""
+    CACHE FILEPATH "File containing extra configuration settings")
+
+# Allow the users to configure the following build options.
+option(PNG_SHARED "Build libpng as a shared lib" ON)
+option(PNG_STATIC "Build libpng as a static lib" ON)
+option(PNG_FRAMEWORK "Build libpng as a Mac OS X framework" OFF)
+option(PNG_EXECUTABLES "Build libpng executables" ON)
+option(PNG_TESTS "Build libpng tests" ON)
+option(PNG_DEBUG "Enable debug output" OFF)
+option(PNG_HARDWARE_OPTIMIZATIONS "Enable hardware optimizations" ON)
 
-# Allow users to specify location of zlib.
+# Allow the users to specify a location of zlib.
 # Useful if zlib is being built alongside this as a sub-project.
-option(PNG_BUILD_ZLIB "Custom zlib Location, else find_package is used" OFF)
-
+option(PNG_BUILD_ZLIB "Custom zlib location, else find_package is used" OFF)
 if(NOT PNG_BUILD_ZLIB)
   find_package(ZLIB REQUIRED)
   include_directories(${ZLIB_INCLUDE_DIRS})
@@ -62,20 +92,6 @@ else()
   set(M_LIBRARY "")
 endif()
 
-# Public CMake configuration variables.
-option(PNG_SHARED "Build shared lib" ON)
-option(PNG_STATIC "Build static lib" ON)
-option(PNG_EXECUTABLES "Build libpng executables" ON)
-option(PNG_TESTS "Build libpng tests" ON)
-
-# Many more configuration options could be added here.
-option(PNG_FRAMEWORK "Build OS X framework" OFF)
-option(PNG_DEBUG "Build with debug output" OFF)
-option(PNG_HARDWARE_OPTIMIZATIONS "Enable hardware optimizations" ON)
-
-set(PNG_PREFIX "" CACHE STRING "Prefix to add to the API function names")
-set(DFA_XTRA "" CACHE FILEPATH "File containing extra configuration settings")
-
 # CMake currently sets CMAKE_SYSTEM_PROCESSOR to one of x86_64 or arm64 on macOS,
 # based upon the OS architecture, not the target architecture. As such, we need
 # to check CMAKE_OSX_ARCHITECTURES to identify which hardware-specific flags to
@@ -220,50 +236,49 @@ endif()
 
 endif(PNG_HARDWARE_OPTIMIZATIONS)
 
-# Set PNG_LIB_NAME.
-set(PNG_LIB_NAME png${PNGLIB_MAJOR}${PNGLIB_MINOR})
-
-# Distinguish between debug and release builds.
-set(CMAKE_DEBUG_POSTFIX "d")
-
-include(CheckCSourceCompiles)
 option(ld-version-script "Enable linker version script" ON)
 if(ld-version-script AND NOT ANDROID AND NOT APPLE)
   # Check if LD supports linker scripts.
   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map" "
-VERS_1 {
-        global: sym;
-        local: *;
-};
-
-VERS_2 {
-        global: sym2;
-                main;
-} VERS_1;
+VERS_1 { global: sym1; local: *; };
+VERS_2 { global: sym2; main; } VERS_1;
 ")
-  set(CMAKE_REQUIRED_FLAGS_SAVE ${CMAKE_REQUIRED_FLAGS})
-  set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} "-Wl,--version-script='${CMAKE_CURRENT_BINARY_DIR}/conftest.map'")
-  check_c_source_compiles("void sym(void) {}
+  set(_SAVED_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
+  if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "^SunOS")
+    # Avoid using CMAKE_SHARED_LIBRARY_C_FLAGS in version script checks on
+    # Solaris, because of an incompatibility with the Solaris link editor.
+    list(APPEND CMAKE_REQUIRED_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
+  endif()
+  list(APPEND CMAKE_REQUIRED_FLAGS "-Wl,--version-script='${CMAKE_CURRENT_BINARY_DIR}/conftest.map'")
+  check_c_source_compiles("
+void sym1(void) {}
 void sym2(void) {}
-int main(void) {return 0;}
+int main(void) { return 0; }
 " HAVE_LD_VERSION_SCRIPT)
   if(NOT HAVE_LD_VERSION_SCRIPT)
-    set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE} "-Wl,-M -Wl,${CMAKE_CURRENT_BINARY_DIR}/conftest.map")
-  check_c_source_compiles("void sym(void) {}
+    set(CMAKE_REQUIRED_FLAGS ${_SAVED_CMAKE_REQUIRED_FLAGS})
+    if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "^SunOS")
+      # Again, avoid using CMAKE_SHARED_LIBRARY_C_FLAGS in version script
+      # checks on Solaris.
+      list(APPEND CMAKE_REQUIRED_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
+    endif()
+    list(APPEND CMAKE_REQUIRED_FLAGS "-Wl,-M -Wl,${CMAKE_CURRENT_BINARY_DIR}/conftest.map")
+    check_c_source_compiles("
+void sym1(void) {}
 void sym2(void) {}
-int main(void) {return 0;}
+int main(void) { return 0; }
 " HAVE_SOLARIS_LD_VERSION_SCRIPT)
   endif()
-  set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE})
+  set(CMAKE_REQUIRED_FLAGS ${_SAVED_CMAKE_REQUIRED_FLAGS})
   file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map")
 endif()
 
 # Find symbol prefix.  Likely obsolete and unnecessary with recent
 # toolchains (it's not done in many other projects).
-function(symbol_prefix)
+function(find_symbol_prefix)
   set(SYMBOL_PREFIX)
 
-  execute_process(COMMAND "${CMAKE_C_COMPILER}" "-E" "-"
+  execute_process(COMMAND "${CMAKE_C_COMPILER}" -E -
                   INPUT_FILE /dev/null
                   OUTPUT_VARIABLE OUT
                   RESULT_VARIABLE STATUS)
@@ -290,7 +305,7 @@ function(symbol_prefix)
 endfunction()
 
 if(UNIX)
-  symbol_prefix()
+  find_symbol_prefix()
 endif()
 
 find_program(AWK NAMES gawk awk)
@@ -301,7 +316,7 @@ if(NOT AWK OR ANDROID OR IOS)
   # No awk available to generate sources; use pre-built pnglibconf.h
   configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt
                  ${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h)
-  add_custom_target(genfiles) # Dummy
+  add_custom_target(png_genfiles)
 else()
   # Copy the awk scripts, converting their line endings to Unix (LF)
   configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/checksym.awk
@@ -319,7 +334,6 @@ else()
 
   # Generate .chk from .out with awk:
   # generate_chk(INPUT inputfile OUTPUT outputfile [DEPENDS dep1 [dep2...]])
-  include(CMakeParseArguments)
   function(generate_chk)
     set(options)
     set(oneValueArgs INPUT OUTPUT)
@@ -390,6 +404,13 @@ else()
     set(oneValueArgs INPUT OUTPUT)
     set(multiValueArgs DEPENDS)
     cmake_parse_arguments(_GCO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+    if(NOT _GCO_INPUT)
+      message(FATAL_ERROR "generate_copy: Missing INPUT argument")
+    endif()
+    if(NOT _GCO_OUTPUT)
+      message(FATAL_ERROR "generate_copy: Missing OUTPUT argument")
+    endif()
+
     add_custom_command(OUTPUT "${_GCO_OUTPUT}"
                        COMMAND "${CMAKE_COMMAND}"
                                -E remove "${_GCO_OUTPUT}"
@@ -403,14 +424,16 @@ else()
                   DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.dfa"
                           "${CMAKE_CURRENT_BINARY_DIR}/scripts/options.awk"
                           "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h")
-  add_custom_target(scripts_pnglibconf_c DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/pnglibconf.c")
+  add_custom_target(png_scripts_pnglibconf_c
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/pnglibconf.c")
 
   # Generate pnglibconf.c
   generate_source(OUTPUT "pnglibconf.c"
                   DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.dfa"
                           "${CMAKE_CURRENT_BINARY_DIR}/scripts/options.awk"
                           "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h")
-  add_custom_target(pnglibconf_c DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.c")
+  add_custom_target(pnglibconf_c
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.c")
 
   if(PNG_PREFIX)
     set(PNGLIBCONF_H_EXTRA_DEPENDS
@@ -423,92 +446,100 @@ else()
   generate_out(INPUT "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.c"
                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out"
                DEPENDS pnglibconf_c)
-  add_custom_target(pnglibconf_out DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out")
+  add_custom_target(pnglibconf_out
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out")
 
   # Generate pnglibconf.h
   generate_source(OUTPUT "pnglibconf.h"
                   DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out" pnglibconf_out
                           ${PNGLIBCONF_H_EXTRA_DEPENDS})
-  add_custom_target(pnglibconf_h DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h")
+  add_custom_target(pnglibconf_h
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h")
 
   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/intprefix.c"
                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out"
                DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h" pnglibconf_h)
-  add_custom_target(scripts_intprefix_out DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out")
+  add_custom_target(png_scripts_intprefix_out
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out")
 
   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/prefix.c"
                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out"
                DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/png.h"
                        "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h"
                        "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out" pnglibconf_out)
-  add_custom_target(scripts_prefix_out DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out")
+  add_custom_target(png_scripts_prefix_out
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out")
 
   # Generate pngprefix.h
   generate_source(OUTPUT "pngprefix.h"
                   DEPENDS ${PNGPREFIX_H_EXTRA_DEPENDS})
-  add_custom_target(pngprefix_h DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pngprefix.h")
+  add_custom_target(pngprefix_h
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pngprefix.h")
 
   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/sym.c"
                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out"
                DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h" pnglibconf_h)
-  add_custom_target(scripts_sym_out DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out")
+  add_custom_target(png_scripts_sym_out
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out")
 
   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/symbols.c"
                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out"
                DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/png.h"
                        "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h"
                        "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt")
-  add_custom_target(scripts_symbols_out DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out")
+  add_custom_target(png_scripts_symbols_out
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out")
 
   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/vers.c"
                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out"
                DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/png.h"
                        "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h"
                        "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h" pnglibconf_h)
-  add_custom_target(scripts_vers_out DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out")
+  add_custom_target(png_scripts_vers_out
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out")
 
   generate_chk(INPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out"
                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk"
-               DEPENDS scripts_symbols_out
+               DEPENDS png_scripts_symbols_out
                        "${CMAKE_CURRENT_BINARY_DIR}/scripts/checksym.awk"
                        "${CMAKE_CURRENT_SOURCE_DIR}/scripts/symbols.def")
 
-  add_custom_target(scripts_symbols_chk
+  add_custom_target(png_scripts_symbols_chk
                     DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk")
 
   generate_copy(INPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out"
                 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym"
-                DEPENDS scripts_sym_out)
+                DEPENDS png_scripts_sym_out)
   generate_copy(INPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out"
                 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers"
-                DEPENDS scripts_vers_out)
+                DEPENDS png_scripts_vers_out)
 
-  add_custom_target(genvers
+  add_custom_target(png_genvers
                     DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers")
-  add_custom_target(gensym
+  add_custom_target(png_gensym
                     DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym")
 
-  add_custom_target("genprebuilt"
+  add_custom_target(png_genprebuilt
                     COMMAND "${CMAKE_COMMAND}"
                             "-DOUTPUT=scripts/pnglibconf.h.prebuilt"
                             -P "${CMAKE_CURRENT_BINARY_DIR}/scripts/gensrc.cmake"
                     WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
 
   # A single target handles generation of all generated files.
-  add_custom_target(genfiles
-                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym" gensym
-                            "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers" genvers
+  add_custom_target(png_genfiles
+                    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym" png_gensym
+                            "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers" png_genvers
                             "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.c" pnglibconf_c
                             "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h" pnglibconf_h
                             "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out" pnglibconf_out
                             "${CMAKE_CURRENT_BINARY_DIR}/pngprefix.h" pngprefix_h
-                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out" scripts_intprefix_out
-                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/pnglibconf.c" scripts_pnglibconf_c
-                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out" scripts_prefix_out
-                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out" scripts_sym_out
-                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk" scripts_symbols_chk
-                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" scripts_symbols_out
-                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out" scripts_vers_out)
+                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out" png_scripts_intprefix_out
+                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/pnglibconf.c" png_scripts_pnglibconf_c
+                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out" png_scripts_prefix_out
+                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out" png_scripts_sym_out
+                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk" png_scripts_symbols_chk
+                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" png_scripts_symbols_out
+                            "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out" png_scripts_vers_out)
 endif(NOT AWK OR ANDROID OR IOS)
 
 # List the source code files.
@@ -571,7 +602,8 @@ set(png_fix_itxt_sources
     contrib/tools/png-fix-itxt.c
 )
 
-if(MSVC)
+if(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID MATCHES ".*Clang")))
+  add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
   add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
 endif()
 
@@ -579,85 +611,84 @@ if(PNG_DEBUG)
   add_definitions(-DPNG_DEBUG)
 endif()
 
-# Now build our target.
+# Now build our targets.
 include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIRS})
 
-unset(PNG_LIB_TARGETS)
+# Initialize the list of libpng library targets.
+set(PNG_LIBRARY_TARGETS "")
+
+# Initialize the libpng library file names.
+if(UNIX
+   OR (WIN32 AND NOT "${CMAKE_SHARED_LIBRARY_PREFIX}" STREQUAL "")
+   OR (WIN32 AND NOT "${CMAKE_STATIC_LIBRARY_PREFIX}" STREQUAL ""))
+  # We are on a Unix or Unix-like toolchain like the GNU toolchain on Windows.
+  # Library file names are expected to have an implicit prefix such as "lib".
+  # Let CMake prepend and append its usual prefixes and suffixes by default.
+  set(PNG_SHARED_OUTPUT_NAME "png${PNGLIB_ABI_VERSION}")
+  set(PNG_STATIC_OUTPUT_NAME "png${PNGLIB_ABI_VERSION}")
+else()
+  # We are, most likely, on a Windows toolchain like MSVC, Clang on Windows,
+  # Borland/Embarcadero, etc. We need to specify the "libpng" name explicitly.
+  # We also need to use a custom suffix, in order to distinguish between the
+  # shared import library name and the static library name.
+  set(PNG_SHARED_OUTPUT_NAME "libpng${PNGLIB_ABI_VERSION}")
+  set(PNG_STATIC_OUTPUT_NAME "libpng${PNGLIB_ABI_VERSION}_static")
+endif()
 
 if(PNG_SHARED)
-  add_library(png SHARED ${libpng_sources})
-  set(PNG_LIB_TARGETS png)
-  set_target_properties(png PROPERTIES OUTPUT_NAME ${PNG_LIB_NAME})
-  add_dependencies(png genfiles)
-  if(MSVC)
-    # MVC does not append 'lib'. Do it here, to have consistent name.
-    set_target_properties(png PROPERTIES PREFIX "lib")
-    set_target_properties(png PROPERTIES IMPORT_PREFIX "lib")
-  endif()
-  target_link_libraries(png ${ZLIB_LIBRARIES} ${M_LIBRARY})
-
+  add_library(png_shared SHARED ${libpng_sources})
+  add_dependencies(png_shared png_genfiles)
+  list(APPEND PNG_LIBRARY_TARGETS png_shared)
+  set_target_properties(png_shared PROPERTIES
+                        OUTPUT_NAME "${PNG_SHARED_OUTPUT_NAME}"
+                        DEBUG_POSTFIX "${PNG_DEBUG_POSTFIX}"
+                        VERSION "${PNGLIB_SHARED_VERSION}"
+                        SOVERSION "${PNGLIB_ABI_VERSION}")
   if(UNIX AND AWK)
     if(HAVE_LD_VERSION_SCRIPT)
-      set_target_properties(png PROPERTIES
+      set_target_properties(png_shared PROPERTIES
                             LINK_FLAGS "-Wl,--version-script='${CMAKE_CURRENT_BINARY_DIR}/libpng.vers'")
     elseif(HAVE_SOLARIS_LD_VERSION_SCRIPT)
-      set_target_properties(png PROPERTIES
+      set_target_properties(png_shared PROPERTIES
                             LINK_FLAGS "-Wl,-M -Wl,'${CMAKE_CURRENT_BINARY_DIR}/libpng.vers'")
     endif()
   endif()
+  if(WIN32)
+    set_target_properties(png_shared PROPERTIES DEFINE_SYMBOL PNG_BUILD_DLL)
+  endif()
+  target_link_libraries(png_shared ${ZLIB_LIBRARIES} ${M_LIBRARY})
 endif()
 
 if(PNG_STATIC)
-  # does not work without changing name
-  set(PNG_LIB_NAME_STATIC png_static)
   add_library(png_static STATIC ${libpng_sources})
-  add_dependencies(png_static genfiles)
-  # MSVC doesn't use a different file extension for shared vs. static
-  # libs. We are able to change OUTPUT_NAME to remove the _static
-  # for all other platforms.
-  if(NOT MSVC)
-    set_target_properties(png_static PROPERTIES
-                          OUTPUT_NAME "${PNG_LIB_NAME}"
-                          CLEAN_DIRECT_OUTPUT 1)
-  else()
-    set_target_properties(png_static PROPERTIES
-                          OUTPUT_NAME "${PNG_LIB_NAME}_static"
-                          CLEAN_DIRECT_OUTPUT 1)
-  endif()
-  list(APPEND PNG_LIB_TARGETS png_static)
-  if(MSVC)
-    # MSVC does not append 'lib'. Do it here, to have consistent name.
-    set_target_properties(png_static PROPERTIES PREFIX "lib")
-  endif()
+  add_dependencies(png_static png_genfiles)
+  list(APPEND PNG_LIBRARY_TARGETS png_static)
+  set_target_properties(png_static PROPERTIES
+                        OUTPUT_NAME "${PNG_STATIC_OUTPUT_NAME}"
+                        DEBUG_POSTFIX "${PNG_DEBUG_POSTFIX}")
   target_link_libraries(png_static ${ZLIB_LIBRARIES} ${M_LIBRARY})
 endif()
 
 if(PNG_FRAMEWORK)
-  set(PNG_LIB_NAME_FRAMEWORK png_framework)
   add_library(png_framework SHARED ${libpng_sources})
-  add_dependencies(png_framework genfiles)
-  list(APPEND PNG_LIB_TARGETS png_framework)
+  add_dependencies(png_framework png_genfiles)
+  list(APPEND PNG_LIBRARY_TARGETS png_framework)
   set_target_properties(png_framework PROPERTIES
                         FRAMEWORK TRUE
-                        FRAMEWORK_VERSION ${PNGLIB_VERSION}
-                        MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PNGLIB_MAJOR}.${PNGLIB_MINOR}
-                        MACOSX_FRAMEWORK_BUNDLE_VERSION ${PNGLIB_VERSION}
-                        MACOSX_FRAMEWORK_IDENTIFIER org.libpng.libpng
+                        FRAMEWORK_VERSION "${PNGLIB_VERSION}"
+                        MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${PNGLIB_MAJOR}.${PNGLIB_MINOR}"
+                        MACOSX_FRAMEWORK_BUNDLE_VERSION "${PNGLIB_VERSION}"
+                        MACOSX_FRAMEWORK_IDENTIFIER "org.libpng.libpng"
                         XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
                         PUBLIC_HEADER "${libpng_public_hdrs}"
-                        OUTPUT_NAME png)
+                        OUTPUT_NAME "png")
   target_link_libraries(png_framework ${ZLIB_LIBRARIES} ${M_LIBRARY})
 endif()
 
-if(NOT PNG_LIB_TARGETS)
+if(NOT PNG_LIBRARY_TARGETS)
   message(SEND_ERROR "No library variant selected to build. "
                      "Please enable at least one of the following options: "
-                     "PNG_STATIC, PNG_SHARED, PNG_FRAMEWORK")
-endif()
-
-if(PNG_SHARED AND WIN32)
-  set_target_properties(png PROPERTIES
-                        DEFINE_SYMBOL PNG_BUILD_DLL)
+                     "PNG_SHARED, PNG_STATIC, PNG_FRAMEWORK")
 endif()
 
 function(png_add_test)
@@ -665,7 +696,6 @@ function(png_add_test)
   set(oneValueArgs NAME COMMAND)
   set(multiValueArgs OPTIONS FILES)
   cmake_parse_arguments(_PAT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
-
   if(NOT _PAT_NAME)
     message(FATAL_ERROR "png_add_test: Missing NAME argument")
   endif()
@@ -681,7 +711,7 @@ function(png_add_test)
                  @ONLY)
   add_test(NAME "${_PAT_NAME}"
            COMMAND "${CMAKE_COMMAND}"
-                   "-DLIBPNG=$<TARGET_FILE:png>"
+                   "-DLIBPNG=$<TARGET_FILE:png_shared>"
                    "-DTEST_COMMAND=$<TARGET_FILE:${_PAT_COMMAND}>"
                    -P "${CMAKE_CURRENT_BINARY_DIR}/tests/${_PAT_NAME}.cmake")
 endfunction()
@@ -697,14 +727,14 @@ if(PNG_TESTS AND PNG_SHARED)
   set(PNGTEST_PNG "${CMAKE_CURRENT_SOURCE_DIR}/pngtest.png")
 
   add_executable(pngtest ${pngtest_sources})
-  target_link_libraries(pngtest png)
+  target_link_libraries(pngtest png_shared)
 
   png_add_test(NAME pngtest
                COMMAND pngtest
                FILES "${PNGTEST_PNG}")
 
   add_executable(pngvalid ${pngvalid_sources})
-  target_link_libraries(pngvalid png)
+  target_link_libraries(pngvalid png_shared)
 
   png_add_test(NAME pngvalid-gamma-16-to-8
                COMMAND pngvalid
@@ -750,7 +780,7 @@ if(PNG_TESTS AND PNG_SHARED)
                OPTIONS --transform)
 
   add_executable(pngstest ${pngstest_sources})
-  target_link_libraries(pngstest png)
+  target_link_libraries(pngstest png_shared)
 
   foreach(gamma_type 1.8 linear none sRGB)
     foreach(alpha_type none alpha)
@@ -805,7 +835,7 @@ if(PNG_TESTS AND PNG_SHARED)
   endforeach()
 
   add_executable(pngunknown ${pngunknown_sources})
-  target_link_libraries(pngunknown png)
+  target_link_libraries(pngunknown png_shared)
 
   png_add_test(NAME pngunknown-discard
                COMMAND pngunknown
@@ -837,7 +867,7 @@ if(PNG_TESTS AND PNG_SHARED)
                FILES "${PNGTEST_PNG}")
 
   add_executable(pngimage ${pngimage_sources})
-  target_link_libraries(pngimage png)
+  target_link_libraries(pngimage png_shared)
 
   png_add_test(NAME pngimage-quick
                COMMAND pngimage
@@ -851,7 +881,7 @@ endif()
 
 if(PNG_SHARED AND PNG_EXECUTABLES)
   add_executable(pngfix ${pngfix_sources})
-  target_link_libraries(pngfix png)
+  target_link_libraries(pngfix png_shared)
   set(PNG_BIN_TARGETS pngfix)
 
   add_executable(png-fix-itxt ${png_fix_itxt_sources})
@@ -859,56 +889,53 @@ if(PNG_SHARED AND PNG_EXECUTABLES)
   list(APPEND PNG_BIN_TARGETS png-fix-itxt)
 endif()
 
-# Creates a symlink from src to dest (if possible), or, alternatively,
-# copies src to dest if different.
-include(CMakeParseArguments)
+# Create a symlink from src to dest (if possible), or, alternatively,
+# copy src to dest if different.
 function(create_symlink DEST_FILE)
-  cmake_parse_arguments(S "" "FILE;TARGET" "" ${ARGN})
-
-  if(NOT S_TARGET AND NOT S_FILE)
-    message(FATAL_ERROR "create_symlink: Missing TARGET or FILE argument")
+  cmake_parse_arguments(_SYM "" "FILE;TARGET" "" ${ARGN})
+  if(NOT _SYM_FILE AND NOT _SYM_TARGET)
+    message(FATAL_ERROR "create_symlink: Missing FILE or TARGET argument")
   endif()
-
-  if(S_TARGET AND S_FILE)
+  if(_SYM_FILE AND _SYM_TARGET)
     message(FATAL_ERROR "create_symlink: "
-                        "Both source file ${S_FILE} and build target ${S_TARGET} arguments are present; "
-                        "can only have one")
+                        "The arguments FILE (${_SYM_FILE}) and TARGET (${_SYM_TARGET}) "
+                        "are mutually-exclusive")
   endif()
 
-  if(S_FILE)
+  if(_SYM_FILE)
     # If we don't need to symlink something that's coming from a build target,
     # we can go ahead and symlink/copy at configure time.
     if(CMAKE_HOST_WIN32 AND NOT CYGWIN)
       execute_process(COMMAND "${CMAKE_COMMAND}"
                               -E copy_if_different
-                              ${S_FILE} ${DEST_FILE}
+                              ${_SYM_FILE} ${DEST_FILE}
                       WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
     else()
       execute_process(COMMAND "${CMAKE_COMMAND}"
                               -E create_symlink
-                              ${S_FILE} ${DEST_FILE}
+                              ${_SYM_FILE} ${DEST_FILE}
                       WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
     endif()
   endif()
 
-  if(S_TARGET)
+  if(_SYM_TARGET)
     # We need to use generator expressions, which can be a bit tricky.
     # For simplicity, make the symlink a POST_BUILD step, and use the TARGET
     # signature of add_custom_command.
     if(CMAKE_HOST_WIN32 AND NOT CYGWIN)
-      add_custom_command(TARGET ${S_TARGET}
+      add_custom_command(TARGET ${_SYM_TARGET}
                          POST_BUILD
                          COMMAND "${CMAKE_COMMAND}"
                                  -E copy_if_different
-                                 $<TARGET_LINKER_FILE_NAME:${S_TARGET}>
-                                 $<TARGET_LINKER_FILE_DIR:${S_TARGET}>/${DEST_FILE})
+                                 $<TARGET_LINKER_FILE_NAME:${_SYM_TARGET}>
+                                 $<TARGET_LINKER_FILE_DIR:${_SYM_TARGET}>/${DEST_FILE})
     else()
-      add_custom_command(TARGET ${S_TARGET}
+      add_custom_command(TARGET ${_SYM_TARGET}
                          POST_BUILD
                          COMMAND "${CMAKE_COMMAND}"
                                  -E create_symlink
-                                 $<TARGET_LINKER_FILE_NAME:${S_TARGET}>
-                                 $<TARGET_LINKER_FILE_DIR:${S_TARGET}>/${DEST_FILE})
+                                 $<TARGET_LINKER_FILE_NAME:${_SYM_TARGET}>
+                                 $<TARGET_LINKER_FILE_DIR:${_SYM_TARGET}>/${DEST_FILE})
     endif()
   endif()
 endfunction()
@@ -940,26 +967,18 @@ if(NOT WIN32 OR CYGWIN OR MINGW)
   set(includedir  ${CMAKE_INSTALL_FULL_INCLUDEDIR})
   set(LIBS        "-lz -lm")
   configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng.pc.in
-                 ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc
+                 ${CMAKE_CURRENT_BINARY_DIR}/libpng${PNGLIB_ABI_VERSION}.pc
                  @ONLY)
-  create_symlink(libpng.pc FILE ${PNGLIB_NAME}.pc)
+  create_symlink(libpng.pc FILE libpng${PNGLIB_ABI_VERSION}.pc)
   configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng-config.in
-                 ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config
+                 ${CMAKE_CURRENT_BINARY_DIR}/libpng${PNGLIB_ABI_VERSION}-config
                  @ONLY)
-  create_symlink(libpng-config FILE ${PNGLIB_NAME}-config)
-endif()
-
-# Set up links.
-if(PNG_SHARED)
-  set_target_properties(png PROPERTIES
-    VERSION ${PNGLIB_SHARED_VERSION}
-    SOVERSION ${PNGLIB_SHARED_SOVERSION}
-    CLEAN_DIRECT_OUTPUT 1)
+  create_symlink(libpng-config FILE libpng${PNGLIB_ABI_VERSION}-config)
 endif()
 
 # Install.
 if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
-  install(TARGETS ${PNG_LIB_TARGETS}
+  install(TARGETS ${PNG_LIBRARY_TARGETS}
           EXPORT libpng
           RUNTIME DESTINATION bin
           LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
@@ -969,14 +988,14 @@ if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
   if(PNG_SHARED)
     # Create a symlink for libpng.dll.a => libpng16.dll.a on Cygwin
     if(CYGWIN OR MINGW)
-      create_symlink(libpng${CMAKE_IMPORT_LIBRARY_SUFFIX} TARGET png)
-      install(FILES $<TARGET_LINKER_FILE_DIR:png>/libpng${CMAKE_IMPORT_LIBRARY_SUFFIX}
+      create_symlink(libpng${CMAKE_IMPORT_LIBRARY_SUFFIX} TARGET png_shared)
+      install(FILES $<TARGET_LINKER_FILE_DIR:png_shared>/libpng${CMAKE_IMPORT_LIBRARY_SUFFIX}
               DESTINATION ${CMAKE_INSTALL_LIBDIR})
     endif()
 
     if(NOT WIN32)
-      create_symlink(libpng${CMAKE_SHARED_LIBRARY_SUFFIX} TARGET png)
-      install(FILES $<TARGET_LINKER_FILE_DIR:png>/libpng${CMAKE_SHARED_LIBRARY_SUFFIX}
+      create_symlink(libpng${CMAKE_SHARED_LIBRARY_SUFFIX} TARGET png_shared)
+      install(FILES $<TARGET_LINKER_FILE_DIR:png_shared>/libpng${CMAKE_SHARED_LIBRARY_SUFFIX}
               DESTINATION ${CMAKE_INSTALL_LIBDIR})
     endif()
   endif()
@@ -994,13 +1013,13 @@ if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL)
   install(FILES ${libpng_public_hdrs}
           DESTINATION include)
   install(FILES ${libpng_public_hdrs}
-          DESTINATION include/${PNGLIB_NAME})
+          DESTINATION include/libpng${PNGLIB_ABI_VERSION})
 endif()
 if(NOT SKIP_INSTALL_EXECUTABLES AND NOT SKIP_INSTALL_ALL)
   if(NOT WIN32 OR CYGWIN OR MINGW)
     install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config
             DESTINATION bin)
-    install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config
+    install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng${PNGLIB_ABI_VERSION}-config
             DESTINATION bin)
   endif()
 endif()
@@ -1022,9 +1041,9 @@ if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL)
             DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
     install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config
             DESTINATION ${CMAKE_INSTALL_BINDIR})
-    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc
+    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${PNGLIB_ABI_VERSION}.pc
             DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
-    install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config
+    install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng${PNGLIB_ABI_VERSION}-config
             DESTINATION ${CMAKE_INSTALL_BINDIR})
   endif()
 endif()
@@ -1033,7 +1052,7 @@ endif()
 if(NOT SKIP_INSTALL_EXPORT AND NOT SKIP_INSTALL_ALL)
   install(EXPORT libpng
           DESTINATION lib/libpng
-          FILE lib${PNG_LIB_NAME}.cmake)
+          FILE libpng${PNGLIB_ABI_VERSION}.cmake)
 endif()
 
 # TODO: Create MSVC import lib for MinGW-compiled shared lib.

+ 2 - 2
png.mod/libpng/LICENSE

@@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
 PNG Reference Library License version 2
 ---------------------------------------
 
- * Copyright (c) 1995-2022 The PNG Reference Library Authors.
- * Copyright (c) 2018-2022 Cosmin Truta.
+ * Copyright (c) 1995-2023 The PNG Reference Library Authors.
+ * Copyright (c) 2018-2023 Cosmin Truta.
  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
  * Copyright (c) 1996-1997 Andreas Dilger.
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.

+ 80 - 82
png.mod/libpng/README

@@ -1,110 +1,108 @@
-README for libpng version 1.6.39
+README for libpng version 1.6.40
 ================================
 
-See the note about version numbers near the top of png.h.
-See INSTALL for instructions on how to install libpng.
+See the note about version numbers near the top of `png.h`.
+See `INSTALL` for instructions on how to install libpng.
 
-Libpng comes in several distribution formats.  Get libpng-*.tar.gz or
-libpng-*.tar.xz if you want UNIX-style line endings in the text files,
-or lpng*.7z or lpng*.zip if you want DOS-style line endings.
+Libpng comes in several distribution formats.  Get `libpng-*.tar.gz`
+or `libpng-*.tar.xz` if you want UNIX-style line endings in the text
+files, or `lpng*.7z` or `lpng*.zip` if you want DOS-style line endings.
 
-Version 0.89 was the first official release of libpng.  Don't let the
-fact that it's the first release fool you.  The libpng library has been
-in extensive use and testing since mid-1995.  By late 1997 it had
-finally gotten to the stage where there hadn't been significant
-changes to the API in some time, and people have a bad feeling about
-libraries with versions < 1.0.  Version 1.0.0 was released in
-March 1998.
+For a detailed description on using libpng, read `libpng-manual.txt`.
+For examples of libpng in a program, see `example.c` and `pngtest.c`.
+For usage information and restrictions (what little they are) on libpng,
+see `png.h`.  For a description on using zlib (the compression library
+used by libpng) and zlib's restrictions, see `zlib.h`.
 
-****
-Note that some of the changes to the png_info structure render this
-version of the library binary incompatible with libpng-0.89 or
-earlier versions if you are using a shared library.  The type of the
-"filler" parameter for png_set_filler() has changed from png_byte to
-png_uint_32, which will affect shared-library applications that use
-this function.
-
-To avoid problems with changes to the internals of the png info_struct,
-new APIs have been made available in 0.95 to avoid direct application
-access to info_ptr.  These functions are the png_set_<chunk> and
-png_get_<chunk> functions.  These functions should be used when
-accessing/storing the info_struct data, rather than manipulating it
-directly, to avoid such problems in the future.
-
-It is important to note that the APIs did not make current programs
-that access the info struct directly incompatible with the new
-library, through libpng-1.2.x.  In libpng-1.4.x, which was meant to
-be a transitional release, members of the png_struct and the
-info_struct can still be accessed, but the compiler will issue a
-warning about deprecated usage.  Since libpng-1.5.0, direct access
-to these structs is not allowed, and the definitions of the structs
-reside in private pngstruct.h and pnginfo.h header files that are not
-accessible to applications.  It is strongly suggested that new
-programs use the new APIs (as shown in example.c and pngtest.c), and
-older programs be converted to the new format, to facilitate upgrades
-in the future.
-****
-
-Additions since 0.90 include the ability to compile libpng as a
-Windows DLL, and new APIs for accessing data in the info struct.
-Experimental functions include the ability to set weighting and cost
-factors for row filter selection, direct reads of integers from buffers
-on big-endian processors that support misaligned data access, faster
-methods of doing alpha composition, and more accurate 16->8 bit color
-conversion.
-
-The additions since 0.89 include the ability to read from a PNG stream
-which has had some (or all) of the signature bytes read by the calling
-application.  This also allows the reading of embedded PNG streams that
-do not have the PNG file signature.  As well, it is now possible to set
-the library action on the detection of chunk CRC errors.  It is possible
-to set different actions based on whether the CRC error occurred in a
-critical or an ancillary chunk.
-
-For a detailed description on using libpng, read libpng-manual.txt.
-For examples of libpng in a program, see example.c and pngtest.c.  For
-usage information and restrictions (what little they are) on libpng,
-see png.h.  For a description on using zlib (the compression library
-used by libpng) and zlib's restrictions, see zlib.h
-
-I have included a general makefile, as well as several machine and
-compiler specific ones, but you may have to modify one for your own
-needs.
-
-You should use zlib 1.0.4 or later to run this, but it MAY work with
+You should use zlib 1.0.4 or later to run this, but it _may_ work with
 versions as old as zlib 0.95.  Even so, there are bugs in older zlib
 versions which can cause the output of invalid compression streams for
 some images.
 
 You should also note that zlib is a compression library that is useful
 for more things than just PNG files.  You can use zlib as a drop-in
-replacement for fread() and fwrite(), if you are so inclined.
+replacement for `fread()` and `fwrite()`, if you are so inclined.
 
 zlib should be available at the same place that libpng is, or at
-https://zlib.net.
+https://zlib.net .
 
 You may also want a copy of the PNG specification.  It is available
 as an RFC, a W3C Recommendation, and an ISO/IEC Standard.  You can find
 these at http://www.libpng.org/pub/png/pngdocs.html .
 
-This code is currently being archived at libpng.sourceforge.io in the
-[DOWNLOAD] area, and at http://libpng.download/src .
+This code is currently being archived at https://libpng.sourceforge.io
+in the download area, and at http://libpng.download/src .
 
 This release, based in a large way on Glenn's, Guy's and Andreas'
 earlier work, was created and will be supported by myself and the PNG
 development group.
 
-Send comments/corrections/commendations to png-mng-implement at
-lists.sourceforge.net (subscription required; visit
+Send comments, corrections and commendations to `png-mng-implement`
+at `lists.sourceforge.net`.  (Subscription is required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement
-to subscribe).
+to subscribe.)
+
+Send general questions about the PNG specification to `png-mng-misc`
+at `lists.sourceforge.net`.  (Subscription is required; visit
+https://lists.sourceforge.net/lists/listinfo/png-mng-misc
+to subscribe.)
 
-Send general questions about the PNG specification to png-mng-misc
-at lists.sourceforge.net (subscription required; visit
-https://lists.sourceforge.net/lists/listinfo/png-mng-misc to
-subscribe).
+Historical notes
+----------------
+
+The libpng library has been in extensive use and testing since mid-1995.
+Version 0.89, published a year later, was the first official release.
+By late 1997, it had finally gotten to the stage where there hadn't
+been significant changes to the API in some time, and people have a bad
+feeling about libraries with versions below 1.0.  Version 1.0.0 was
+released in March 1998.
+
+Note that some of the changes to the `png_info` structure render this
+version of the library binary incompatible with libpng-0.89 or
+earlier versions if you are using a shared library.  The type of the
+`filler` parameter for `png_set_filler()` has changed from `png_byte`
+to `png_uint_32`, which will affect shared-library applications that
+use this function.
+
+To avoid problems with changes to the internals of the `info_struct`,
+new APIs have been made available in 0.95 to avoid direct application
+access to `info_ptr`.  These functions are the `png_set_<chunk>` and
+`png_get_<chunk>` functions.  These functions should be used when
+accessing/storing the `info_struct` data, rather than manipulating it
+directly, to avoid such problems in the future.
+
+It is important to note that the APIs did not make current programs
+that access the info struct directly incompatible with the new
+library, through libpng-1.2.x.  In libpng-1.4.x, which was meant to
+be a transitional release, members of the `png_struct` and the
+`info_struct` can still be accessed, but the compiler will issue a
+warning about deprecated usage.  Since libpng-1.5.0, direct access
+to these structs is not allowed, and the definitions of the structs
+reside in private `pngstruct.h` and `pnginfo.h` header files that are
+not accessible to applications.  It is strongly suggested that new
+programs use the new APIs (as shown in `example.c` and `pngtest.c`),
+and older programs be converted to the new format, to facilitate
+upgrades in the future.
+
+The additions since 0.89 include the ability to read from a PNG stream
+which has had some (or all) of the signature bytes read by the calling
+application.  This also allows the reading of embedded PNG streams that
+do not have the PNG file signature.  As well, it is now possible to set
+the library action on the detection of chunk CRC errors.  It is possible
+to set different actions based on whether the CRC error occurred in a
+critical or an ancillary chunk.
+
+The additions since 0.90 include the ability to compile libpng as a
+Windows DLL, and new APIs for accessing data in the `info_struct`.
+Experimental functions included the ability to set weighting and cost
+factors for row filter selection, direct reads of integers from buffers
+on big-endian processors that support misaligned data access, faster
+methods of doing alpha composition, and more accurate 16-to-8 bit color
+conversion.  Some of these experimental functions, such as the weighted
+filter heuristics, have since been removed.
 
-Files in this distribution:
+Files included in this distribution
+-----------------------------------
 
     ANNOUNCE      =>  Announcement of this version, with recent changes
     AUTHORS       =>  List of contributing authors
@@ -153,7 +151,7 @@ Files in this distribution:
         arm-neon/     =>  Optimized code for the ARM-NEON platform
         mips-msa/     =>  Optimized code for the MIPS-MSA platform
         powerpc-vsx/  =>  Optimized code for the POWERPC-VSX platform
-        examples/     =>  Example programs
+        examples/     =>  Examples of libpng usage
         gregbook/     =>  Source code for PNG reading and writing, from
                           "PNG: The Definitive Guide" by Greg Roelofs,
                           O'Reilly, 1999

+ 1 - 1
png.mod/libpng/autogen.sh

@@ -77,7 +77,7 @@ libpng_autotools_files="Makefile.in aclocal.m4 config.guess config.h.in
    config.sub configure depcomp install-sh ltmain.sh missing\
    test-driver"
 #
-# Files generated by versions of configue >2.68 or automake >1.13 (i.e. later
+# Files generated by versions of autoconf >2.68 or automake >1.13 (i.e. later
 # versions than those required by configure.ac):
 libpng_autotools_extra="compile config.h.in~"
 #

+ 64 - 53
png.mod/libpng/ci/ci_cmake.sh → png.mod/libpng/ci/ci_verify_cmake.sh

@@ -1,10 +1,10 @@
 #!/usr/bin/env bash
 set -e
 
-# ci_cmake.sh
+# ci_verify_cmake.sh
 # Continuously integrate libpng using CMake.
 #
-# Copyright (c) 2019-2022 Cosmin Truta.
+# Copyright (c) 2019-2023 Cosmin Truta.
 #
 # This software is released under the libpng license.
 # For conditions of distribution and use, see the disclaimer
@@ -13,8 +13,14 @@ set -e
 CI_SCRIPTNAME="$(basename "$0")"
 CI_SCRIPTDIR="$(cd "$(dirname "$0")" && pwd)"
 CI_SRCDIR="$(dirname "$CI_SCRIPTDIR")"
-CI_BUILDDIR="$CI_SRCDIR/out/cmake.build"
-CI_INSTALLDIR="$CI_SRCDIR/out/cmake.install"
+CI_BUILDDIR="$CI_SRCDIR/out/ci_verify_cmake.build"
+CI_INSTALLDIR="$CI_SRCDIR/out/ci_verify_cmake.install"
+
+# Keep the following relative paths in sync with the absolute paths.
+# We use them for the benefit of native Windows tools that might be
+# otherwise confused by the path encoding used by Bash-on-Windows.
+CI_SRCDIR_FROM_BUILDDIR="../.."
+CI_INSTALLDIR_FROM_BUILDDIR="../ci_verify_cmake.install"
 
 function ci_info {
     printf >&2 "%s: %s\\n" "$CI_SCRIPTNAME" "$*"
@@ -32,57 +38,39 @@ function ci_spawn {
     "$@"
 }
 
-function ci_init_cmake {
+function ci_init_cmake_build {
     CI_SYSTEM_NAME="$(uname -s)"
     CI_MACHINE_NAME="$(uname -m)"
     CI_CMAKE="${CI_CMAKE:-cmake}"
     CI_CTEST="${CI_CTEST:-ctest}"
     CI_CMAKE_BUILD_TYPE="${CI_CMAKE_BUILD_TYPE:-Release}"
-    [[ -x $(command -v ninja) ]] && CI_CMAKE_GENERATOR="${CI_CMAKE_GENERATOR:-Ninja}"
+    [[ -x $(command -v ninja) ]] &&
+        CI_CMAKE_GENERATOR="${CI_CMAKE_GENERATOR:-Ninja}"
     if [[ $CI_CMAKE_GENERATOR == "Visual Studio"* ]]
     then
-        # Initialize the CI_...DIR_NATIVE variables, for the benefit of
-        # the native Windows build tools. The regular CI_...DIR variables
-        # can only be used inside Bash-on-Windows.
-        mkdir -p "$CI_BUILDDIR"
-        mkdir -p "$CI_INSTALLDIR"
-        if [[ -x $CYGPATH ]]
-        then
-            CI_SRCDIR_NATIVE="$("$CYGPATH" -w "$CI_SRCDIR")"
-            CI_BUILDDIR_NATIVE="$("$CYGPATH" -w "$CI_BUILDDIR")"
-            CI_INSTALLDIR_NATIVE="$("$CYGPATH" -w "$CI_INSTALLDIR")"
-        else
-            CI_SRCDIR_NATIVE="$(cd "$CI_SRCDIR" ; pwd -W || pwd -P)"
-            CI_BUILDDIR_NATIVE="$(cd "$CI_BUILDDIR" ; pwd -W || pwd -P)"
-            CI_INSTALLDIR_NATIVE="$(cd "$CI_INSTALLDIR" ; pwd -W || pwd -P)"
-        fi
         # Clean up incidental mixtures of Windows and Bash-on-Windows
         # environment variables, to avoid confusing MSBuild.
         [[ $TEMP && ( $Temp || $temp ) ]] && unset TEMP
         [[ $TMP && ( $Tmp || $tmp ) ]] && unset TMP
         # Ensure that CI_CMAKE_GENERATOR_PLATFORM is initialized for this generator.
-        [[ $CI_CMAKE_GENERATOR_PLATFORM ]] || ci_err "missing: \$CI_CMAKE_GENERATOR_PLATFORM"
+        [[ $CI_CMAKE_GENERATOR_PLATFORM ]] ||
+            ci_err "missing: \$CI_CMAKE_GENERATOR_PLATFORM"
     fi
 }
 
-function ci_trace_cmake {
+function ci_trace_cmake_build {
     ci_info "## START OF CONFIGURATION ##"
     ci_info "system name: $CI_SYSTEM_NAME"
     ci_info "machine hardware name: $CI_MACHINE_NAME"
     ci_info "source directory: $CI_SRCDIR"
-    [[ $CI_SRCDIR_NATIVE ]] &&
-        ci_info "source directory (native): $CI_SRCDIR_NATIVE"
     ci_info "build directory: $CI_BUILDDIR"
-    [[ $CI_BUILDDIR_NATIVE ]] &&
-        ci_info "build directory (native): $CI_BUILDDIR_NATIVE"
     ci_info "install directory: $CI_INSTALLDIR"
-    [[ $CI_INSTALLDIR_NATIVE ]] &&
-        ci_info "install directory (native): $CI_INSTALLDIR_NATIVE"
     ci_info "environment option: \$CI_CMAKE: '$CI_CMAKE'"
     ci_info "environment option: \$CI_CMAKE_GENERATOR: '$CI_CMAKE_GENERATOR'"
     ci_info "environment option: \$CI_CMAKE_GENERATOR_PLATFORM: '$CI_CMAKE_GENERATOR_PLATFORM'"
     ci_info "environment option: \$CI_CMAKE_BUILD_TYPE: '$CI_CMAKE_BUILD_TYPE'"
     ci_info "environment option: \$CI_CMAKE_BUILD_FLAGS: '$CI_CMAKE_BUILD_FLAGS'"
+    ci_info "environment option: \$CI_CMAKE_TOOLCHAIN_FILE: '$CI_CMAKE_TOOLCHAIN_FILE'"
     ci_info "environment option: \$CI_CMAKE_VARS: '$CI_CMAKE_VARS'"
     ci_info "environment option: \$CI_CTEST: '$CI_CTEST'"
     ci_info "environment option: \$CI_CTEST_FLAGS: '$CI_CTEST_FLAGS'"
@@ -96,8 +84,6 @@ function ci_trace_cmake {
     ci_info "environment option: \$CI_NO_CLEAN: '$CI_NO_CLEAN'"
     ci_info "executable: \$CI_CMAKE: $(command -V "$CI_CMAKE")"
     ci_info "executable: \$CI_CTEST: $(command -V "$CI_CTEST")"
-    [[ $CI_CMAKE_GENERATOR == *"Ninja"* ]] &&
-        ci_info "executable: $(command -V ninja)"
     [[ $CI_CC ]] &&
         ci_info "executable: \$CI_CC: $(command -V "$CI_CC")"
     [[ $CI_AR ]] &&
@@ -107,40 +93,60 @@ function ci_trace_cmake {
     ci_info "## END OF CONFIGURATION ##"
 }
 
+function ci_cleanup_old_cmake_build {
+    [[ ! -e $CI_BUILDDIR ]] ||
+        ci_spawn rm -fr "$CI_BUILDDIR"
+    [[ ! -e $CI_INSTALLDIR ]] ||
+        ci_spawn rm -fr "$CI_INSTALLDIR"
+}
+
 function ci_build_cmake {
     ci_info "## START OF BUILD ##"
     ci_spawn "$(command -v "$CI_CMAKE")" --version
     ci_spawn "$(command -v "$CI_CTEST")" --version
+    [[ $CI_CMAKE_GENERATOR == *"Ninja"* ]] &&
+        ci_spawn "$(command -v ninja)" --version
     # Initialize ALL_CC_FLAGS as a string.
     local ALL_CC_FLAGS="$CI_CC_FLAGS"
-    [[ $CI_SANITIZERS ]] && ALL_CC_FLAGS="-fsanitize=$CI_SANITIZERS $ALL_CC_FLAGS"
+    [[ $CI_SANITIZERS ]] &&
+        ALL_CC_FLAGS="-fsanitize=$CI_SANITIZERS $ALL_CC_FLAGS"
     # Initialize ALL_CMAKE_VARS, ALL_CMAKE_BUILD_FLAGS and ALL_CTEST_FLAGS as arrays.
-    local -a ALL_CMAKE_VARS=()
-    [[ $CI_CC ]] && ALL_CMAKE_VARS+=(-DCMAKE_C_COMPILER="$CI_CC")
-    [[ $ALL_CC_FLAGS ]] && ALL_CMAKE_VARS+=(-DCMAKE_C_FLAGS="$ALL_CC_FLAGS")
-    [[ $CI_AR ]] && ALL_CMAKE_VARS+=(-DCMAKE_AR="$CI_AR")
-    [[ $CI_RANLIB ]] && ALL_CMAKE_VARS+=(-DCMAKE_RANLIB="$CI_RANLIB")
+    local ALL_CMAKE_VARS=()
+    [[ $CI_CMAKE_TOOLCHAIN_FILE ]] &&
+        ALL_CMAKE_VARS+=(-DCMAKE_TOOLCHAIN_FILE="$CI_CMAKE_TOOLCHAIN_FILE")
+    [[ $CI_CC ]] &&
+        ALL_CMAKE_VARS+=(-DCMAKE_C_COMPILER="$CI_CC")
+    [[ $ALL_CC_FLAGS ]] &&
+        ALL_CMAKE_VARS+=(-DCMAKE_C_FLAGS="$ALL_CC_FLAGS")
+    [[ $CI_AR ]] &&
+        ALL_CMAKE_VARS+=(-DCMAKE_AR="$CI_AR")
+    [[ $CI_RANLIB ]] &&
+        ALL_CMAKE_VARS+=(-DCMAKE_RANLIB="$CI_RANLIB")
     ALL_CMAKE_VARS+=(-DCMAKE_BUILD_TYPE="$CI_CMAKE_BUILD_TYPE")
     ALL_CMAKE_VARS+=(-DCMAKE_VERBOSE_MAKEFILE=ON)
-    [[ $CI_NO_TEST ]] && ALL_CMAKE_VARS+=(-DPNG_TESTS=OFF)
+    [[ $CI_NO_TEST ]] &&
+        ALL_CMAKE_VARS+=(-DPNG_TESTS=OFF)
     ALL_CMAKE_VARS+=($CI_CMAKE_VARS)
-    local -a ALL_CMAKE_BUILD_FLAGS=($CI_CMAKE_BUILD_FLAGS)
-    local -a ALL_CTEST_FLAGS=($CI_CTEST_FLAGS)
-    # Initialize SRCDIR_NATIVE and INSTALLDIR_NATIVE.
-    local SRCDIR_NATIVE="${CI_SRCDIR_NATIVE:-"$CI_SRCDIR"}"
-    local INSTALLDIR_NATIVE="${CI_INSTALLDIR_NATIVE:-"$CI_INSTALLDIR"}"
+    local ALL_CMAKE_BUILD_FLAGS=($CI_CMAKE_BUILD_FLAGS)
+    local ALL_CTEST_FLAGS=($CI_CTEST_FLAGS)
     # Export the CMake environment variables.
     [[ $CI_CMAKE_GENERATOR ]] &&
         ci_spawn export CMAKE_GENERATOR="$CI_CMAKE_GENERATOR"
     [[ $CI_CMAKE_GENERATOR_PLATFORM ]] &&
         ci_spawn export CMAKE_GENERATOR_PLATFORM="$CI_CMAKE_GENERATOR_PLATFORM"
     # Build and install.
-    ci_spawn rm -fr "$CI_BUILDDIR" "$CI_INSTALLDIR"
+    # Use $CI_SRCDIR_FROM_BUILDDIR and $CI_INSTALLDIR_FROM_BUILDDIR
+    # instead of $CI_SRCDIR and $CI_INSTALLDIR from this point onwards.
     ci_spawn mkdir -p "$CI_BUILDDIR"
     ci_spawn cd "$CI_BUILDDIR"
-    ci_spawn "$CI_CMAKE" "${ALL_CMAKE_VARS[@]}" \
-                         -DCMAKE_INSTALL_PREFIX="$INSTALLDIR_NATIVE" \
-                         "$SRCDIR_NATIVE"
+    [[ $CI_SRCDIR -ef $CI_SRCDIR_FROM_BUILDDIR ]] ||
+        ci_err "assertion failed: testing: '$CI_SRCDIR' -ef '$CI_SRCDIR_FROM_BUILDDIR'"
+    ci_spawn mkdir -p "$CI_INSTALLDIR"
+    [[ $CI_INSTALLDIR -ef $CI_INSTALLDIR_FROM_BUILDDIR ]] ||
+        ci_err "assertion failed: testing: '$CI_INSTALLDIR' -ef '$CI_INSTALLDIR_FROM_BUILDDIR'"
+    ci_spawn "$CI_CMAKE" -DCMAKE_INSTALL_PREFIX="$CI_INSTALLDIR_FROM_BUILDDIR" \
+                         "${ALL_CMAKE_VARS[@]}" \
+                         "$CI_SRCDIR_FROM_BUILDDIR"
     ci_spawn "$CI_CMAKE" --build . \
                          --config "$CI_CMAKE_BUILD_TYPE" \
                          "${ALL_CMAKE_BUILD_FLAGS[@]}"
@@ -160,10 +166,15 @@ function ci_build_cmake {
     ci_info "## END OF BUILD ##"
 }
 
-ci_init_cmake
-ci_trace_cmake
-[[ $# -eq 0 ]] || {
-    ci_info "note: this program accepts environment options only"
-    ci_err "unexpected command arguments: '$*'"
+function main {
+    [[ $# -eq 0 ]] || {
+        ci_info "note: this program accepts environment options only"
+        ci_err "unexpected command arguments: '$*'"
+    }
+    ci_init_cmake_build
+    ci_trace_cmake_build
+    ci_cleanup_old_cmake_build
+    ci_build_cmake
 }
-ci_build_cmake
+
+main "$@"

+ 26 - 15
png.mod/libpng/ci/ci_autotools.sh → png.mod/libpng/ci/ci_verify_configure.sh

@@ -1,10 +1,10 @@
 #!/usr/bin/env bash
 set -e
 
-# ci_autotools.sh
-# Continuously integrate libpng using the GNU Autotools.
+# ci_verify_configure.sh
+# Continuously integrate libpng using the configure script.
 #
-# Copyright (c) 2019-2022 Cosmin Truta.
+# Copyright (c) 2019-2023 Cosmin Truta.
 #
 # This software is released under the libpng license.
 # For conditions of distribution and use, see the disclaimer
@@ -13,8 +13,8 @@ set -e
 CI_SCRIPTNAME="$(basename "$0")"
 CI_SCRIPTDIR="$(cd "$(dirname "$0")" && pwd)"
 CI_SRCDIR="$(dirname "$CI_SCRIPTDIR")"
-CI_BUILDDIR="$CI_SRCDIR/out/autotools.build"
-CI_INSTALLDIR="$CI_SRCDIR/out/autotools.install"
+CI_BUILDDIR="$CI_SRCDIR/out/ci_verify_configure.build"
+CI_INSTALLDIR="$CI_SRCDIR/out/ci_verify_configure.install"
 
 function ci_info {
     printf >&2 "%s: %s\\n" "$CI_SCRIPTNAME" "$*"
@@ -32,7 +32,7 @@ function ci_spawn {
     "$@"
 }
 
-function ci_init_autotools {
+function ci_init_configure_build {
     CI_SYSTEM_NAME="$(uname -s)"
     CI_MACHINE_NAME="$(uname -m)"
     CI_MAKE="${CI_MAKE:-make}"
@@ -44,7 +44,7 @@ function ci_init_autotools {
     [[ ! $CI_MAKE_VARS ]] || ci_err "unexpected: \$CI_MAKE_VARS='$CI_MAKE_VARS'"
 }
 
-function ci_trace_autotools {
+function ci_trace_configure_build {
     ci_info "## START OF CONFIGURATION ##"
     ci_info "system name: $CI_SYSTEM_NAME"
     ci_info "machine hardware name: $CI_MACHINE_NAME"
@@ -80,7 +80,14 @@ function ci_trace_autotools {
     ci_info "## END OF CONFIGURATION ##"
 }
 
-function ci_build_autotools {
+function ci_cleanup_old_configure_build {
+    [[ ! -e $CI_BUILDDIR ]] ||
+        ci_spawn rm -fr "$CI_BUILDDIR"
+    [[ ! -e $CI_INSTALLDIR ]] ||
+        ci_spawn rm -fr "$CI_INSTALLDIR"
+}
+
+function ci_build_configure {
     ci_info "## START OF BUILD ##"
     # Export the configure build environment.
     [[ $CI_CC ]] && ci_spawn export CC="$CI_CC"
@@ -96,7 +103,6 @@ function ci_build_autotools {
         ci_spawn export LDFLAGS="-fsanitize=$CI_SANITIZERS $LDFLAGS"
     }
     # Build and install.
-    ci_spawn rm -fr "$CI_BUILDDIR" "$CI_INSTALLDIR"
     ci_spawn mkdir -p "$CI_BUILDDIR"
     ci_spawn cd "$CI_BUILDDIR"
     ci_spawn "$CI_SRCDIR/configure" --prefix="$CI_INSTALLDIR" $CI_CONFIGURE_FLAGS
@@ -108,10 +114,15 @@ function ci_build_autotools {
     ci_info "## END OF BUILD ##"
 }
 
-ci_init_autotools
-ci_trace_autotools
-[[ $# -eq 0 ]] || {
-    ci_info "note: this program accepts environment options only"
-    ci_err "unexpected command arguments: '$*'"
+function main {
+    [[ $# -eq 0 ]] || {
+        ci_info "note: this program accepts environment options only"
+        ci_err "unexpected command arguments: '$*'"
+    }
+    ci_init_configure_build
+    ci_trace_configure_build
+    ci_cleanup_old_configure_build
+    ci_build_configure
 }
-ci_build_autotools
+
+main "$@"

+ 39 - 32
png.mod/libpng/ci/ci_legacy.sh → png.mod/libpng/ci/ci_verify_makefiles.sh

@@ -1,10 +1,10 @@
 #!/usr/bin/env bash
 set -e
 
-# ci_legacy.sh
+# ci_verify_makefiles.sh
 # Continuously integrate libpng using the legacy makefiles.
 #
-# Copyright (c) 2019-2022 Cosmin Truta.
+# Copyright (c) 2019-2023 Cosmin Truta.
 #
 # This software is released under the libpng license.
 # For conditions of distribution and use, see the disclaimer
@@ -13,7 +13,6 @@ set -e
 CI_SCRIPTNAME="$(basename "$0")"
 CI_SCRIPTDIR="$(cd "$(dirname "$0")" && pwd)"
 CI_SRCDIR="$(dirname "$CI_SCRIPTDIR")"
-CI_BUILDDIR="$CI_SRCDIR"
 
 function ci_info {
     printf >&2 "%s: %s\\n" "$CI_SCRIPTNAME" "$*"
@@ -31,36 +30,26 @@ function ci_spawn {
     "$@"
 }
 
-function ci_init_legacy {
+function ci_init_makefiles_build {
     CI_SYSTEM_NAME="$(uname -s)"
     CI_MACHINE_NAME="$(uname -m)"
     CI_MAKE="${CI_MAKE:-make}"
-    case "$CI_SYSTEM_NAME" in
-    ( Darwin | *BSD | DragonFly )
-        [[ -x $(command -v clang) ]] && CI_CC="${CI_CC:-clang}" ;;
-    ( * )
-        [[ -x $(command -v gcc) ]] && CI_CC="${CI_CC:-gcc}" ;;
-    esac
-    CI_CC="${CI_CC:-cc}"
     case "$CI_CC" in
     ( *clang* )
-        CI_LEGACY_MAKEFILES="${CI_LEGACY_MAKEFILES:-"scripts/makefile.clang"}" ;;
+        CI_MAKEFILES="${CI_MAKEFILES:-"scripts/makefile.clang"}" ;;
     ( *gcc* )
-        CI_LEGACY_MAKEFILES="${CI_LEGACY_MAKEFILES:-"scripts/makefile.gcc"}" ;;
-    ( cc | c89 | c99 )
-        CI_LEGACY_MAKEFILES="${CI_LEGACY_MAKEFILES:-"scripts/makefile.std"}" ;;
+        CI_MAKEFILES="${CI_MAKEFILES:-"scripts/makefile.gcc"}" ;;
+    ( * )
+        CI_MAKEFILES="${CI_MAKEFILES:-"scripts/makefile.std"}" ;;
     esac
-    CI_LD="${CI_LD:-"$CI_CC"}"
-    CI_LIBS="${CI_LIBS:-"-lz -lm"}"
 }
 
-function ci_trace_legacy {
+function ci_trace_makefiles_build {
     ci_info "## START OF CONFIGURATION ##"
     ci_info "system name: $CI_SYSTEM_NAME"
     ci_info "machine hardware name: $CI_MACHINE_NAME"
     ci_info "source directory: $CI_SRCDIR"
-    ci_info "build directory: $CI_BUILDDIR"
-    ci_info "environment option: \$CI_LEGACY_MAKEFILES: '$CI_LEGACY_MAKEFILES'"
+    ci_info "environment option: \$CI_MAKEFILES: '$CI_MAKEFILES'"
     ci_info "environment option: \$CI_MAKE: '$CI_MAKE'"
     ci_info "environment option: \$CI_MAKE_FLAGS: '$CI_MAKE_FLAGS'"
     ci_info "environment option: \$CI_MAKE_VARS: '$CI_MAKE_VARS'"
@@ -90,7 +79,20 @@ function ci_trace_legacy {
     ci_info "## END OF CONFIGURATION ##"
 }
 
-function ci_build_legacy {
+function ci_cleanup_old_makefiles_build {
+    # Any old makefile-based build will most likely leave a mess
+    # of object files behind if interrupted, e.g., via Ctrl+C.
+    # There may be other files behind, depending on what makefile
+    # had been used. We cannot easily enumerate all of those.
+    # Fortunately, for a clean makefiles-based build, it should be
+    # sufficient to remove the old object files only.
+    [[ -z $(find "$CI_SRCDIR" -maxdepth 1 -name "*.o") ]] ||
+        ci_spawn rm -f "$CI_SRCDIR"/*.o
+    [[ -z $(find "$CI_SRCDIR" -maxdepth 1 -name "*.obj") ]] ||
+        ci_spawn rm -f "$CI_SRCDIR"/*.obj
+}
+
+function ci_build_makefiles {
     ci_info "## START OF BUILD ##"
     # Initialize ALL_CC_FLAGS and ALL_LD_FLAGS as strings.
     local ALL_CC_FLAGS="$CI_CC_FLAGS"
@@ -100,8 +102,8 @@ function ci_build_legacy {
         ALL_LD_FLAGS="-fsanitize=$CI_SANITIZERS $ALL_LD_FLAGS"
     }
     # Initialize ALL_MAKE_FLAGS and ALL_MAKE_VARS as arrays.
-    local -a ALL_MAKE_FLAGS=($CI_MAKE_FLAGS)
-    local -a ALL_MAKE_VARS=()
+    local ALL_MAKE_FLAGS=($CI_MAKE_FLAGS)
+    local ALL_MAKE_VARS=()
     [[ $CI_CC ]] && ALL_MAKE_VARS+=(CC="$CI_CC")
     [[ $ALL_CC_FLAGS ]] && ALL_MAKE_VARS+=(CFLAGS="$ALL_CC_FLAGS")
     [[ $CI_CPP ]] && ALL_MAKE_VARS+=(CPP="$CI_CPP")
@@ -113,12 +115,12 @@ function ci_build_legacy {
     [[ $CI_RANLIB ]] && ALL_MAKE_VARS+=(RANLIB="$CI_RANLIB")
     [[ $CI_LD ]] && ALL_MAKE_VARS+=(LD="$CI_LD")
     [[ $ALL_LD_FLAGS ]] && ALL_MAKE_VARS+=(LDFLAGS="$ALL_LD_FLAGS")
-    ALL_MAKE_VARS+=(LIBS="$CI_LIBS")
+    [[ $CI_LIBS ]] && ALL_MAKE_VARS+=(LIBS="$CI_LIBS")
     ALL_MAKE_VARS+=($CI_MAKE_VARS)
     # Build!
-    ci_spawn cd "$CI_SRCDIR"
+    cd "$CI_SRCDIR"
     local MY_MAKEFILE
-    for MY_MAKEFILE in $CI_LEGACY_MAKEFILES
+    for MY_MAKEFILE in $CI_MAKEFILES
     do
         ci_info "using makefile: $MY_MAKEFILE"
         ci_spawn "$CI_MAKE" -f "$MY_MAKEFILE" \
@@ -138,10 +140,15 @@ function ci_build_legacy {
     ci_info "## END OF BUILD ##"
 }
 
-ci_init_legacy
-ci_trace_legacy
-[[ $# -eq 0 ]] || {
-    ci_info "note: this program accepts environment options only"
-    ci_err "unexpected command arguments: '$*'"
+function main {
+    [[ $# -eq 0 ]] || {
+        ci_info "note: this program accepts environment options only"
+        ci_err "unexpected command arguments: '$*'"
+    }
+    ci_init_makefiles_build
+    ci_trace_makefiles_build
+    ci_cleanup_old_makefiles_build
+    ci_build_makefiles
 }
-ci_build_legacy
+
+main "$@"

+ 12 - 12
png.mod/libpng/configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for libpng 1.6.39.
+# Generated by GNU Autoconf 2.71 for libpng 1.6.40.
 #
 # Report bugs to <[email protected]>.
 #
@@ -621,8 +621,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='libpng'
 PACKAGE_TARNAME='libpng'
-PACKAGE_VERSION='1.6.39'
-PACKAGE_STRING='libpng 1.6.39'
+PACKAGE_VERSION='1.6.40'
+PACKAGE_STRING='libpng 1.6.40'
 PACKAGE_BUGREPORT='[email protected]'
 PACKAGE_URL=''
 
@@ -1411,7 +1411,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libpng 1.6.39 to adapt to many kinds of systems.
+\`configure' configures libpng 1.6.40 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1482,7 +1482,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libpng 1.6.39:";;
+     short | recursive ) echo "Configuration of libpng 1.6.40:";;
    esac
   cat <<\_ACEOF
 
@@ -1663,7 +1663,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libpng configure 1.6.39
+libpng configure 1.6.40
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1919,7 +1919,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libpng $as_me 1.6.39, which was
+It was created by libpng $as_me 1.6.40, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3196,7 +3196,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='libpng'
- VERSION='1.6.39'
+ VERSION='1.6.40'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -3328,10 +3328,10 @@ fi
 
 
 
-PNGLIB_VERSION=1.6.39
+PNGLIB_VERSION=1.6.40
 PNGLIB_MAJOR=1
 PNGLIB_MINOR=6
-PNGLIB_RELEASE=39
+PNGLIB_RELEASE=40
 
 
 
@@ -14894,7 +14894,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libpng $as_me 1.6.39, which was
+This file was extended by libpng $as_me 1.6.40, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14962,7 +14962,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-libpng config.status 1.6.39
+libpng config.status 1.6.40
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 

+ 3 - 3
png.mod/libpng/configure.ac

@@ -25,7 +25,7 @@ AC_PREREQ([2.68])
 
 dnl Version number stuff here:
 
-AC_INIT([libpng],[1.6.39],[[email protected]])
+AC_INIT([libpng],[1.6.40],[[email protected]])
 AC_CONFIG_MACRO_DIR([scripts])
 
 # libpng does not follow GNU file name conventions (hence 'foreign')
@@ -46,10 +46,10 @@ dnl automake, so the following is not necessary (and is not defined anyway):
 dnl AM_PREREQ([1.11.2])
 dnl stop configure from automagically running automake
 
-PNGLIB_VERSION=1.6.39
+PNGLIB_VERSION=1.6.40
 PNGLIB_MAJOR=1
 PNGLIB_MINOR=6
-PNGLIB_RELEASE=39
+PNGLIB_RELEASE=40
 
 dnl End of version number stuff
 

+ 1 - 1
png.mod/libpng/contrib/libtests/makepng.c

@@ -496,7 +496,7 @@ generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
          case 32:
          case 48:
          case 64:
-            /* The rows are filled by an alogorithm similar to the above, in the
+            /* The rows are filled by an algorithm similar to the above, in the
              * first row pixel bytes are all equal, increasing from 0 by 1 for
              * each pixel.  In the second row the bytes within a pixel are
              * incremented 1,3,5,7,... from the previous row byte.  Using an odd

+ 1 - 1
png.mod/libpng/contrib/libtests/pngstest.c

@@ -1151,7 +1151,7 @@ get_pixel(png_uint_32 format))(Pixel *p, png_const_voidp pb)
  *
  * 2) Remove color by mapping to grayscale.  (Grayscale to color is a no-op.)
  *
- * 3) Convert between 8-bit and 16-bit components.  (Both directtions are
+ * 3) Convert between 8-bit and 16-bit components.  (Both directions are
  *    relevant.)
  *
  * This gives the following base format conversion matrix:

+ 2 - 2
png.mod/libpng/contrib/libtests/pngvalid.c

@@ -6719,7 +6719,7 @@ transform_range_check(png_const_structp pp, unsigned int r, unsigned int g,
    unsigned int out, png_byte sample_depth, double err, double limit,
    const char *name, double digitization_error)
 {
-   /* Compare the scaled, digitzed, values of our local calculation (in+-err)
+   /* Compare the scaled, digitized, values of our local calculation (in+-err)
     * with the digitized values libpng produced;  'sample_depth' is the actual
     * digitization depth of the libpng output colors (the bit depth except for
     * palette images where it is always 8.)  The check on 'err' is to detect
@@ -9065,7 +9065,7 @@ image_transform_reset_count(void)
 static int
 image_transform_test_counter(png_uint_32 counter, unsigned int max)
 {
-   /* Test the list to see if there is any point contining, given a current
+   /* Test the list to see if there is any point continuing, given a current
     * counter and a 'max' value.
     */
    image_transform *next = image_transform_first;

+ 1 - 1
png.mod/libpng/contrib/libtests/tarith.c

@@ -952,7 +952,7 @@ int validation_gamma(int argc, char **argv)
 
 /**************************** VALIDATION TESTS ********************************/
 /* Various validation routines are included herein, they require some
- * definition for png_warning and png_error, seetings of VALIDATION:
+ * definition for png_warning and png_error, settings of VALIDATION:
  *
  * 1: validates the ASCII to floating point conversions
  * 2: validates png_muldiv

+ 1 - 1
png.mod/libpng/contrib/pngminus/LICENSE.txt

@@ -16,7 +16,7 @@ copies or substantial portions of the Software.
 The software is provided "as is", without warranty of any kind, express or
 implied, including but not limited to the warranties of merchantability,
 fitness for a particular purpose and noninfringement. In no event shall the
-authors or copyight holders be liable for any claim, damages or other
+authors or copyright holders be liable for any claim, damages or other
 liability, whether in an action of contract, tort or otherwise, arising from,
 out of or in connection with the software or the use or other dealings in the
 software.

+ 1 - 1
png.mod/libpng/contrib/tools/pngfix.c

@@ -867,7 +867,7 @@ struct file
     * signature (in length,type).
     *
     * When a chunk control structure is instantiated these values are copied
-    * into the structure and can then be overritten with the data for the next
+    * into the structure and can then be overwritten with the data for the next
     * chunk.
     */
    fpos_t         data_pos;      /* Position of first byte of chunk data */

+ 1 - 1
png.mod/libpng/contrib/visupng/VisualPng.c

@@ -103,7 +103,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
         return 0;
     }
 
-    /* if filename given on commandline, store it */
+    /* if filename given on command line, store it */
     if ((szCmdLine != NULL) && (*szCmdLine != '\0'))
         if (szCmdLine[0] == '"')
             strncpy (szCmdFileName, szCmdLine + 1, strlen(szCmdLine) - 2);

+ 3 - 3
png.mod/libpng/libpng-manual.txt

@@ -1,6 +1,6 @@
 libpng-manual.txt - A description on how to use and modify libpng
 
- Copyright (c) 2018-2022 Cosmin Truta
+ Copyright (c) 2018-2023 Cosmin Truta
  Copyright (c) 1998-2018 Glenn Randers-Pehrson
 
  This document is released under the libpng license.
@@ -9,9 +9,9 @@ libpng-manual.txt - A description on how to use and modify libpng
 
  Based on:
 
- libpng version 1.6.36, December 2018, through 1.6.39 - November 2022
+ libpng version 1.6.36, December 2018, through 1.6.40 - June 2023
  Updated and distributed by Cosmin Truta
- Copyright (c) 2018-2022 Cosmin Truta
+ Copyright (c) 2018-2023 Cosmin Truta
 
  libpng versions 0.97, January 1998, through 1.6.35 - July 2018
  Updated and distributed by Glenn Randers-Pehrson

+ 20 - 30
png.mod/libpng/libpng.3

@@ -1,6 +1,6 @@
-.TH LIBPNG 3 "November 20, 2022"
+.TH LIBPNG 3 "June 21, 2023"
 .SH NAME
-libpng \- Portable Network Graphics (PNG) Reference Library 1.6.39
+libpng \- Portable Network Graphics (PNG) Reference Library 1.6.40
 
 .SH SYNOPSIS
 \fB#include <png.h>\fP
@@ -519,7 +519,7 @@ Following is a copy of the libpng-manual.txt file that accompanies libpng.
 .SH LIBPNG.TXT
 libpng-manual.txt - A description on how to use and modify libpng
 
- Copyright (c) 2018-2022 Cosmin Truta
+ Copyright (c) 2018-2023 Cosmin Truta
  Copyright (c) 1998-2018 Glenn Randers-Pehrson
 
  This document is released under the libpng license.
@@ -528,9 +528,9 @@ libpng-manual.txt - A description on how to use and modify libpng
 
  Based on:
 
- libpng version 1.6.36, December 2018, through 1.6.39 - November 2022
+ libpng version 1.6.36, December 2018, through 1.6.40 - June 2023
  Updated and distributed by Cosmin Truta
- Copyright (c) 2018-2022 Cosmin Truta
+ Copyright (c) 2018-2023 Cosmin Truta
 
  libpng versions 0.97, January 1998, through 1.6.35 - July 2018
  Updated and distributed by Glenn Randers-Pehrson
@@ -5995,35 +5995,25 @@ letter, until version 1.0.6j; from then on they were given the upcoming
 public release number plus "betaNN" or "rcNN".
 
 .SH "SEE ALSO"
-.IR libpngpf(3) ", " png(5)
-.LP
-.IR libpng :
+.BR "png"(5)
 .IP
-https://libpng.sourceforge.io/ (follow the [DOWNLOAD] link)
-http://www.libpng.org/pub/png
-
+The PNG (Portable Network Graphics) format specification.
 .LP
-.IR zlib :
+.B libpng
 .IP
-(generally) at the same location as
-.I libpng
-or at
+http://www.libpng.org/pub/png/libpng.html (canonical home page)
 .br
-https://zlib.net/
-
+https://github.com/pnggroup/libpng (canonical Git repository)
+.br
+https://libpng.sourceforge.io (downloadable archives)
 .LP
-.IR PNG specification: RFC 2083
+.B zlib
 .IP
-(generally) at the same location as
-.I libpng
-or at
+https://zlib.net (canonical home page)
 .br
-https://www.ietf.org/rfc/rfc2083.txt
+https://github.com/madler/zlib (canonical Git repository)
 .br
-or (as a W3C Recommendation) at
-.br
-https://www.w3.org/TR/REC-png.html
-
+A copy of zlib may also be found at the same location as libpng.
 .LP
 In the case of any inconsistency between the PNG specification
 and this library, the specification takes precedence.
@@ -6043,10 +6033,10 @@ Libpng:
 Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc.
 Maintained by Cosmin Truta.
 
-Supported by the PNG development group
+Supported by the PNG development group.
 .br
-png-mng-implement at lists.sourceforge.net (subscription required; visit
-https://lists.sourceforge.net/lists/listinfo/png-mng-implement
-to subscribe).
+png-mng-implement at lists.sourceforge.net. (Subscription is required;
+visit https://lists.sourceforge.net/lists/listinfo/png-mng-implement
+to subscribe.)
 
 .\" end of man page

+ 2 - 2
png.mod/libpng/libpngpf.3

@@ -1,6 +1,6 @@
-.TH LIBPNGPF 3 "November 20, 2022"
+.TH LIBPNGPF 3 "June 21, 2023"
 .SH NAME
-libpng \- Portable Network Graphics (PNG) Reference Library 1.6.39
+libpng \- Portable Network Graphics (PNG) Reference Library 1.6.40
 (private functions)
 
 .SH SYNOPSIS

+ 4 - 29
png.mod/libpng/png.5

@@ -1,4 +1,4 @@
-.TH PNG 5 "September 14, 2022"
+.TH PNG 5 "June 21, 2023"
 .SH NAME
 png \- Portable Network Graphics (PNG) format
 
@@ -18,7 +18,7 @@ Also, PNG can store gamma and chromaticity data for improved color
 matching on heterogeneous platforms.
 
 .SH "SEE ALSO"
-.BR "libpng"(3), " libpngpf"(3), " zlib"(3), " deflate"(5), " " and " zlib"(5)
+.BR "libpng"(3), " zlib"(3), " deflate"(5), " " and " zlib"(5)
 .LP
 PNG Specification (Second Edition), November 2003:
 .IP
@@ -51,34 +51,9 @@ Portable Network Graphics (PNG): Functional specification.
 ISO/IEC 15948:2003 (E) (November 10, 2003): David Duce and others.
 .LP
 Portable Network Graphics (PNG) Specification Version 1.2 (July 8, 1999):
-Glenn Randers-Pehrson and others (png-list).
+Glenn Randers-Pehrson and others.
 .LP
 Portable Network Graphics (PNG) Specification Version 1.0 (October 1, 1996):
-Thomas Boutell and others (png-list).
+Thomas Boutell and others.
 
-.SH COPYRIGHT
-.LP
-This man page is
-.br
-Copyright (c) 2018 Cosmin Truta.
-.br
-Copyright (c) 1998-2006 Glenn Randers-Pehrson.
-.br
-See png.h for conditions of use and distribution.
-.LP
-The PNG Specification (Second Edition) is
-.br
-Copyright (c) 2003 W3C. (MIT, ERCIM, Keio), All Rights Reserved.
-.LP
-The PNG-1.2 Specification is
-.br
-Copyright (c) 1999 Glenn Randers-Pehrson.
-.br
-See the specification for conditions of use and distribution.
-.LP
-The PNG-1.0 Specification is
-.br
-Copyright (c) 1996 Massachusetts Institute of Technology.
-.br
-See the specification for conditions of use and distribution.
 .\" end of man page

+ 4 - 4
png.mod/libpng/png.c

@@ -1,7 +1,7 @@
 
 /* png.c - location for general purpose libpng functions
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -14,7 +14,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_39 Your_png_h_is_not_version_1_6_39;
+typedef png_libpng_version_1_6_40 Your_png_h_is_not_version_1_6_40;
 
 #ifdef __GNUC__
 /* The version tests may need to be added to, but the problem warning has
@@ -815,8 +815,8 @@ png_get_copyright(png_const_structrp png_ptr)
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.39" PNG_STRING_NEWLINE \
-      "Copyright (c) 2018-2022 Cosmin Truta" PNG_STRING_NEWLINE \
+      "libpng version 1.6.40" PNG_STRING_NEWLINE \
+      "Copyright (c) 2018-2023 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
       "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \

+ 11 - 11
png.mod/libpng/png.h

@@ -1,9 +1,9 @@
 
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.6.39 - November 20, 2022
+ * libpng version 1.6.40
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -15,7 +15,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.39, November 2022:
+ *   libpng versions 1.6.36, December 2018, through 1.6.40, June 2023:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -27,8 +27,8 @@
  * PNG Reference Library License version 2
  * ---------------------------------------
  *
- *  * Copyright (c) 1995-2022 The PNG Reference Library Authors.
- *  * Copyright (c) 2018-2022 Cosmin Truta.
+ *  * Copyright (c) 1995-2023 The PNG Reference Library Authors.
+ *  * Copyright (c) 2018-2023 Cosmin Truta.
  *  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
  *  * Copyright (c) 1996-1997 Andreas Dilger.
  *  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -239,7 +239,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.39                  16    10639  16.so.16.39[.0]
+ *    1.6.40                  16    10640  16.so.16.40[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -278,8 +278,8 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.39"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.39 - November 20, 2022\n"
+#define PNG_LIBPNG_VER_STRING "1.6.40"
+#define PNG_HEADER_VERSION_STRING " libpng version 1.6.40 - June 21, 2023\n"
 
 #define PNG_LIBPNG_VER_SONUM   16
 #define PNG_LIBPNG_VER_DLLNUM  16
@@ -287,7 +287,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 39
+#define PNG_LIBPNG_VER_RELEASE 40
 
 /* This should be zero for a public release, or non-zero for a
  * development version.  [Deprecated]
@@ -318,7 +318,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10639 /* 1.6.39 */
+#define PNG_LIBPNG_VER 10640 /* 1.6.40 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -428,7 +428,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_6_39;
+typedef char* png_libpng_version_1_6_40;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *

+ 1 - 1
png.mod/libpng/pngconf.h

@@ -1,7 +1,7 @@
 
 /* pngconf.h - machine-configurable file for libpng
  *
- * libpng version 1.6.39
+ * libpng version 1.6.40
  *
  * Copyright (c) 2018-2022 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson

+ 12 - 1
png.mod/libpng/pngget.c

@@ -1,7 +1,7 @@
 
 /* pngget.c - retrieval of values from info struct
  *
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -21,7 +21,18 @@ png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr,
     png_uint_32 flag)
 {
    if (png_ptr != NULL && info_ptr != NULL)
+   {
+#ifdef PNG_READ_tRNS_SUPPORTED
+      /* png_handle_PLTE() may have canceled a valid tRNS chunk but left the
+       * 'valid' flag for the detection of duplicate chunks. Do not report a
+       * valid tRNS chunk in this case.
+       */
+      if (flag == PNG_INFO_tRNS && png_ptr->num_trans == 0)
+         return(0);
+#endif
+
       return(info_ptr->valid & flag);
+   }
 
    return(0);
 }

+ 3 - 3
png.mod/libpng/pngpriv.h

@@ -1,7 +1,7 @@
 
 /* pngpriv.h - private declarations for use inside libpng
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -626,7 +626,7 @@
 #define PNG_BACKGROUND_IS_GRAY     0x800U
 #define PNG_HAVE_PNG_SIGNATURE    0x1000U
 #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
-                   /*             0x4000U (unused) */
+#define PNG_WROTE_eXIf            0x4000U
 #define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
 
 /* Flags for the transformations the PNG library does on the image data */
@@ -1910,7 +1910,7 @@ PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr,
  */
 #define PNG_FP_INVALID  512  /* Available for callers as a distinct value */
 
-/* Result codes for the parser (boolean - true meants ok, false means
+/* Result codes for the parser (boolean - true means ok, false means
  * not ok yet.)
  */
 #define PNG_FP_MAYBE      0  /* The number may be valid in the future */

+ 24 - 36
png.mod/libpng/pngset.c

@@ -1,7 +1,7 @@
 
 /* pngset.c - storage of image information into info struct
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -137,46 +137,40 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
 #ifdef PNG_eXIf_SUPPORTED
 void PNGAPI
 png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
-    png_bytep eXIf_buf)
+    png_bytep exif)
 {
   png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1");
   PNG_UNUSED(info_ptr)
-  PNG_UNUSED(eXIf_buf)
+  PNG_UNUSED(exif)
 }
 
 void PNGAPI
 png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
-    png_uint_32 num_exif, png_bytep eXIf_buf)
+    png_uint_32 num_exif, png_bytep exif)
 {
-   int i;
+   png_bytep new_exif;
 
    png_debug1(1, "in %s storage function", "eXIf");
 
-   if (png_ptr == NULL || info_ptr == NULL)
+   if (png_ptr == NULL || info_ptr == NULL ||
+       (png_ptr->mode & PNG_WROTE_eXIf) != 0)
       return;
 
-   if (info_ptr->exif)
-   {
-      png_free(png_ptr, info_ptr->exif);
-      info_ptr->exif = NULL;
-   }
+   new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif));
 
-   info_ptr->num_exif = num_exif;
-
-   info_ptr->exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr,
-       info_ptr->num_exif));
-
-   if (info_ptr->exif == NULL)
+   if (new_exif == NULL)
    {
       png_warning(png_ptr, "Insufficient memory for eXIf chunk data");
       return;
    }
 
-   info_ptr->free_me |= PNG_FREE_EXIF;
+   memcpy(new_exif, exif, (size_t)num_exif);
 
-   for (i = 0; i < (int) info_ptr->num_exif; i++)
-      info_ptr->exif[i] = eXIf_buf[i];
+   png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0);
 
+   info_ptr->num_exif = num_exif;
+   info_ptr->exif = new_exif;
+   info_ptr->free_me |= PNG_FREE_EXIF;
    info_ptr->valid |= PNG_INFO_eXIf;
 }
 #endif /* eXIf */
@@ -237,15 +231,13 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
    if (info_ptr->hist == NULL)
    {
       png_warning(png_ptr, "Insufficient memory for hIST chunk data");
-
       return;
    }
 
-   info_ptr->free_me |= PNG_FREE_HIST;
-
    for (i = 0; i < info_ptr->num_palette; i++)
       info_ptr->hist[i] = hist[i];
 
+   info_ptr->free_me |= PNG_FREE_HIST;
    info_ptr->valid |= PNG_INFO_hIST;
 }
 #endif
@@ -367,6 +359,8 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
 
    memcpy(info_ptr->pcal_purpose, purpose, length);
 
+   info_ptr->free_me |= PNG_FREE_PCAL;
+
    png_debug(3, "storing X0, X1, type, and nparams in info");
    info_ptr->pcal_X0 = X0;
    info_ptr->pcal_X1 = X1;
@@ -383,7 +377,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
    if (info_ptr->pcal_units == NULL)
    {
       png_warning(png_ptr, "Insufficient memory for pCAL units");
-
       return;
    }
 
@@ -395,7 +388,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
    if (info_ptr->pcal_params == NULL)
    {
       png_warning(png_ptr, "Insufficient memory for pCAL params");
-
       return;
    }
 
@@ -413,7 +405,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
       if (info_ptr->pcal_params[i] == NULL)
       {
          png_warning(png_ptr, "Insufficient memory for pCAL parameter");
-
          return;
       }
 
@@ -421,7 +412,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
    }
 
    info_ptr->valid |= PNG_INFO_pCAL;
-   info_ptr->free_me |= PNG_FREE_PCAL;
 }
 #endif
 
@@ -478,18 +468,17 @@ png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,
 
    if (info_ptr->scal_s_height == NULL)
    {
-      png_free (png_ptr, info_ptr->scal_s_width);
+      png_free(png_ptr, info_ptr->scal_s_width);
       info_ptr->scal_s_width = NULL;
 
       png_warning(png_ptr, "Memory allocation failed while processing sCAL");
-
       return;
    }
 
    memcpy(info_ptr->scal_s_height, sheight, lengthh);
 
-   info_ptr->valid |= PNG_INFO_sCAL;
    info_ptr->free_me |= PNG_FREE_SCAL;
+   info_ptr->valid |= PNG_INFO_sCAL;
 }
 
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -625,11 +614,10 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
    if (num_palette > 0)
       memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
           (sizeof (png_color)));
+
    info_ptr->palette = png_ptr->palette;
    info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
-
    info_ptr->free_me |= PNG_FREE_PLTE;
-
    info_ptr->valid |= PNG_INFO_PLTE;
 }
 
@@ -1020,8 +1008,8 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
               png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
           memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
 
-          info_ptr->valid |= PNG_INFO_tRNS;
           info_ptr->free_me |= PNG_FREE_TRNS;
+          info_ptr->valid |= PNG_INFO_tRNS;
        }
        png_ptr->trans_alpha = info_ptr->trans_alpha;
    }
@@ -1054,8 +1042,8 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
 
    if (num_trans != 0)
    {
-      info_ptr->valid |= PNG_INFO_tRNS;
       info_ptr->free_me |= PNG_FREE_TRNS;
+      info_ptr->valid |= PNG_INFO_tRNS;
    }
 }
 #endif
@@ -1089,11 +1077,11 @@ png_set_sPLT(png_const_structrp png_ptr,
    {
       /* Out of memory or too many chunks */
       png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
-
       return;
    }
 
    png_free(png_ptr, info_ptr->splt_palettes);
+
    info_ptr->splt_palettes = np;
    info_ptr->free_me |= PNG_FREE_SPLT;
 
@@ -1247,11 +1235,11 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
    {
       png_chunk_report(png_ptr, "too many unknown chunks",
           PNG_CHUNK_WRITE_ERROR);
-
       return;
    }
 
    png_free(png_ptr, info_ptr->unknown_chunks);
+
    info_ptr->unknown_chunks = np; /* safe because it is initialized */
    info_ptr->free_me |= PNG_FREE_UNKN;
 

+ 1 - 1
png.mod/libpng/pngtest.c

@@ -2155,4 +2155,4 @@ main(void)
 #endif
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_39 Your_png_h_is_not_version_1_6_39;
+typedef png_libpng_version_1_6_40 Your_png_h_is_not_version_1_6_40;

+ 7 - 3
png.mod/libpng/pngwrite.c

@@ -1,7 +1,7 @@
 
 /* pngwrite.c - general routines to write a PNG file
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -239,7 +239,10 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
 
 #ifdef PNG_WRITE_eXIf_SUPPORTED
    if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
+   {
       png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+      png_ptr->mode |= PNG_WROTE_eXIf;
+   }
 #endif
 
 #ifdef PNG_WRITE_hIST_SUPPORTED
@@ -439,8 +442,9 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
 #endif
 
 #ifdef PNG_WRITE_eXIf_SUPPORTED
-   if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
-      png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+      if ((info_ptr->valid & PNG_INFO_eXIf) != 0 &&
+          (png_ptr->mode & PNG_WROTE_eXIf) == 0)
+         png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
 #endif
 
 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED

+ 3 - 3
png.mod/libpng/scripts/genout.cmake.in

@@ -24,10 +24,10 @@ set(ZLIBINCDIR "@ZLIB_INCLUDE_DIRS@")
 
 set(PLATFORM_C_FLAGS)
 if(APPLE)
-  set(CMAKE_OSX_ARCHITECTURES "@CMAKE_OSX_ARCHITECTURES@")
+  set(CMAKE_OSX_INTERNAL_ARCHITECTURES "@CMAKE_OSX_INTERNAL_ARCHITECTURES@")
   set(CMAKE_OSX_SYSROOT "@CMAKE_OSX_SYSROOT@")
-  if(CMAKE_OSX_ARCHITECTURES)
-    set(PLATFORM_C_FLAGS ${PLATFORM_C_FLAGS} -arch ${CMAKE_OSX_ARCHITECTURES})
+  if(CMAKE_OSX_INTERNAL_ARCHITECTURES)
+    set(PLATFORM_C_FLAGS ${PLATFORM_C_FLAGS} -arch ${CMAKE_OSX_INTERNAL_ARCHITECTURES})
   endif()
   if(CMAKE_OSX_SYSROOT)
     set(PLATFORM_C_FLAGS ${PLATFORM_C_FLAGS} -isysroot ${CMAKE_OSX_SYSROOT})

+ 1 - 1
png.mod/libpng/scripts/gensrc.cmake.in

@@ -128,7 +128,7 @@ elseif("${OUTPUT}" STREQUAL "scripts/pnglibconf.h.prebuilt")
 
   message(STATUS "Attempting to build scripts/pnglibconf.h.prebuilt")
   message(STATUS "This is a machine generated file, but if you want to make")
-  message(STATUS "a new one simply build the 'genfiles' target, and copy")
+  message(STATUS "a new one simply build the 'png_genfiles' target, and copy")
   message(STATUS "scripts/pnglibconf.out to scripts/pnglibconf.h.prebuilt")
   message(STATUS "AND set PNG_ZLIB_VERNUM to 0 (you MUST do this)")
   message(FATAL_ERROR "Stopping build")

+ 1 - 1
png.mod/libpng/scripts/libpng-config-head.in

@@ -11,7 +11,7 @@
 
 # Modeled after libxml-config.
 
-version=1.6.39
+version=1.6.40
 prefix=""
 libdir=""
 libs=""

+ 1 - 1
png.mod/libpng/scripts/libpng.pc.in

@@ -5,6 +5,6 @@ includedir=@includedir@/libpng16
 
 Name: libpng
 Description: Loads and saves PNG files
-Version: 1.6.39
+Version: 1.6.40
 Libs: -L${libdir} -lpng16
 Cflags: -I${includedir}

+ 4 - 4
png.mod/libpng/scripts/pnglibconf.dfa

@@ -8,7 +8,7 @@ com pnglibconf.h - library build configuration
 com
 version
 com
-com Copyright (c) 2018-2022 Cosmin Truta
+com Copyright (c) 2018-2023 Cosmin Truta
 com Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
 com
 com This code is released under the libpng license.
@@ -69,9 +69,9 @@ file pnglibconf.h scripts/pnglibconf.dfa PNGLCONF_H
 #
 # 1) Create 'pngusr.h', enter the required private build information
 # detailed below and #define PNG_NO_<option> for each option you
-# don't want in that file in that file.  You can also turn on options
-# using PNG_<option>_SUPPORTED.  When you have finished rerun
-# configure and rebuild pnglibconf.h file with -DPNG_USER_CONFIG:
+# don't want in that file.  You can also turn on options using
+# PNG_<option>_SUPPORTED.  When you have finished, rerun configure
+# and rebuild pnglibconf.h file with -DPNG_USER_CONFIG:
 #
 #  make clean
 #  CPPFLAGS='-DPNG_USER_CONFIG' ./configure

+ 2 - 2
png.mod/libpng/scripts/pnglibconf.h.prebuilt

@@ -1,8 +1,8 @@
 /* pnglibconf.h - library build configuration */
 
-/* libpng version 1.6.39 */
+/* libpng version 1.6.40 */
 
-/* Copyright (c) 2018-2022 Cosmin Truta */
+/* Copyright (c) 2018-2023 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
 
 /* This code is released under the libpng license. */

+ 3 - 1
png.mod/png.bmx

@@ -28,12 +28,14 @@ about: The PNG loader module provides the ability to load PNG format #pixmaps.
 End Rem
 Module Image.PNG
 
-ModuleInfo "Version: 1.09"
+ModuleInfo "Version: 1.10"
 ModuleInfo "Author: Mark Sibly"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "Copyright: Blitz Research Ltd"
 ModuleInfo "Modserver: BRL"
 
+ModuleInfo "History: 1.10"
+ModuleInfo "History: Update to libpng 1.6.40."
 ModuleInfo "History: 1.09"
 ModuleInfo "History: Update to libpng 1.6.39."
 ModuleInfo "History: Fixed grey alpha png issue."

+ 1 - 1
stb.mod/common.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2022 Bruce A Henderson
+' Copyright (c) 2022-2023 Bruce A Henderson
 ' 
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages

+ 1 - 1
stb.mod/glue.c

@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2022 Bruce A Henderson
+  Copyright (c) 2022-2023 Bruce A Henderson
   
   This software is provided 'as-is', without any express or implied
   warranty. In no event will the authors be held liable for any damages

+ 4 - 2
stb.mod/stb.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2022 Bruce A Henderson
+' Copyright (c) 2022-2023 Bruce A Henderson
 ' 
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
@@ -20,11 +20,13 @@ SuperStrict
 
 Module Image.STB
 
-ModuleInfo "Version: 1.04"
+ModuleInfo "Version: 1.05"
 ModuleInfo "Author: Sean Barrett and contributers (see stb_image.h)"
 ModuleInfo "License: ZLib/PNG License"
 ModuleInfo "Credit: Adapted for BlitzMax by Bruce A Henderson"
 
+ModuleInfo "History: 1.04"
+ModuleInfo "History: Update to stb_image 2.29"
 ModuleInfo "History: 1.04"
 ModuleInfo "History: Update to stb_image 2.28"
 ModuleInfo "History: 1.03"

+ 175 - 191
stb.mod/stb/stb_image.h

@@ -1,4 +1,4 @@
-/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
+/* stb_image - v2.29 - public domain image loader - http://nothings.org/stb
                                   no warranty implied; use at your own risk
 
    Do this:
@@ -48,6 +48,7 @@ LICENSE
 
 RECENT REVISION HISTORY:
 
+      2.29  (2023-05-xx) optimizations
       2.28  (2023-01-29) many error fixes, security errors, just tons of stuff
       2.27  (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
       2.26  (2020-07-13) many minor fixes
@@ -429,7 +430,6 @@ STBIDEF stbi_uc *stbi_load_from_file  (FILE *f, int *x, int *y, int *channels_in
 
 #ifndef STBI_NO_GIF
 STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
-STBIDEF stbi_uc *stbi_load_gif_from_callbacks(stbi_io_callbacks const *clbk, void *user, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
 #endif
 
 #ifdef STBI_WINDOWS_UTF8
@@ -1073,8 +1073,8 @@ static int stbi__addints_valid(int a, int b)
    return a <= INT_MAX - b;
 }
 
-// returns 1 if the product of two signed shorts is valid, 0 on overflow.
-static int stbi__mul2shorts_valid(short a, short b)
+// returns 1 if the product of two ints fits in a signed short, 0 on overflow.
+static int stbi__mul2shorts_valid(int a, int b)
 {
    if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
    if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
@@ -1453,19 +1453,6 @@ STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int *
 
    return result;
 }
-STBIDEF stbi_uc *stbi_load_gif_from_callbacks(stbi_io_callbacks const *clbk, void *user, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
-{
-   unsigned char *result;
-   stbi__context s;
-   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
-
-   result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
-   if (stbi__vertically_flip_on_load) {
-      stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
-   }
-
-   return result;
-}
 #endif
 
 #ifndef STBI_NO_LINEAR
@@ -1809,7 +1796,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
 }
 #endif
 
-#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PNM)
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
 // nothing
 #else
 static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
@@ -1818,7 +1805,7 @@ static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
 }
 #endif
 
-#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PNM)
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
 // nothing
 #else
 static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
@@ -3398,13 +3385,13 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
    return 1;
 }
 
-static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
+static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
 {
    // some JPEGs have junk at end, skip over it but if we find what looks
    // like a valid marker, resume there
    while (!stbi__at_eof(j->s)) {
-      int x = stbi__get8(j->s);
-      while (x == 255) { // might be a marker
+      stbi_uc x = stbi__get8(j->s);
+      while (x == 0xff) { // might be a marker
          if (stbi__at_eof(j->s)) return STBI__MARKER_none;
          x = stbi__get8(j->s);
          if (x != 0x00 && x != 0xff) {
@@ -4190,6 +4177,7 @@ typedef struct
 {
    stbi_uc *zbuffer, *zbuffer_end;
    int num_bits;
+   int hit_zeof_once;
    stbi__uint32 code_buffer;
 
    char *zout;
@@ -4256,9 +4244,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
    int b,s;
    if (a->num_bits < 16) {
       if (stbi__zeof(a)) {
-         return -1;   /* report error for unexpected end of data. */
+         if (!a->hit_zeof_once) {
+            // This is the first time we hit eof, insert 16 extra padding btis
+            // to allow us to keep going; if we actually consume any of them
+            // though, that is invalid data. This is caught later.
+            a->hit_zeof_once = 1;
+            a->num_bits += 16; // add 16 implicit zero bits
+         } else {
+            // We already inserted our extra 16 padding bits and are again
+            // out, this stream is actually prematurely terminated.
+            return -1;
+         }
+      } else {
+         stbi__fill_bits(a);
       }
-      stbi__fill_bits(a);
    }
    b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
    if (b) {
@@ -4323,6 +4322,13 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
          int len,dist;
          if (z == 256) {
             a->zout = zout;
+            if (a->hit_zeof_once && a->num_bits < 16) {
+               // The first time we hit zeof, we inserted 16 extra zero bits into our bit
+               // buffer so the decoder can just do its speculative decoding. But if we
+               // actually consumed any of those bits (which is the case when num_bits < 16),
+               // the stream actually read past the end so it is malformed.
+               return stbi__err("unexpected end","Corrupt PNG");
+            }
             return 1;
          }
          if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
@@ -4334,7 +4340,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
          dist = stbi__zdist_base[z];
          if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
          if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
-         if (zout + len > a->zout_end) {
+         if (len > a->zout_end - zout) {
             if (!stbi__zexpand(a, zout, len)) return 0;
             zout = a->zout;
          }
@@ -4478,6 +4484,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
       if (!stbi__parse_zlib_header(a)) return 0;
    a->num_bits = 0;
    a->code_buffer = 0;
+   a->hit_zeof_once = 0;
    do {
       final = stbi__zreceive(a,1);
       type = stbi__zreceive(a,2);
@@ -4633,9 +4640,8 @@ enum {
    STBI__F_up=2,
    STBI__F_avg=3,
    STBI__F_paeth=4,
-   // synthetic filters used for first scanline to avoid needing a dummy row of 0s
-   STBI__F_avg_first,
-   STBI__F_paeth_first
+   // synthetic filter used for first scanline to avoid needing a dummy row of 0s
+   STBI__F_avg_first
 };
 
 static stbi_uc first_row_filter[5] =
@@ -4644,29 +4650,56 @@ static stbi_uc first_row_filter[5] =
    STBI__F_sub,
    STBI__F_none,
    STBI__F_avg_first,
-   STBI__F_paeth_first
+   STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub
 };
 
 static int stbi__paeth(int a, int b, int c)
 {
-   int p = a + b - c;
-   int pa = abs(p-a);
-   int pb = abs(p-b);
-   int pc = abs(p-c);
-   if (pa <= pb && pa <= pc) return a;
-   if (pb <= pc) return b;
-   return c;
+   // This formulation looks very different from the reference in the PNG spec, but is
+   // actually equivalent and has favorable data dependencies and admits straightforward
+   // generation of branch-free code, which helps performance significantly.
+   int thresh = c*3 - (a + b);
+   int lo = a < b ? a : b;
+   int hi = a < b ? b : a;
+   int t0 = (hi <= thresh) ? lo : c;
+   int t1 = (thresh <= lo) ? hi : t0;
+   return t1;
 }
 
 static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
 
+// adds an extra all-255 alpha channel
+// dest == src is legal
+// img_n must be 1 or 3
+static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n)
+{
+   int i;
+   // must process data backwards since we allow dest==src
+   if (img_n == 1) {
+      for (i=x-1; i >= 0; --i) {
+         dest[i*2+1] = 255;
+         dest[i*2+0] = src[i];
+      }
+   } else {
+      STBI_ASSERT(img_n == 3);
+      for (i=x-1; i >= 0; --i) {
+         dest[i*4+3] = 255;
+         dest[i*4+2] = src[i*3+2];
+         dest[i*4+1] = src[i*3+1];
+         dest[i*4+0] = src[i*3+0];
+      }
+   }
+}
+
 // create the png data from post-deflated data
 static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
 {
-   int bytes = (depth == 16? 2 : 1);
+   int bytes = (depth == 16 ? 2 : 1);
    stbi__context *s = a->s;
    stbi__uint32 i,j,stride = x*out_n*bytes;
    stbi__uint32 img_len, img_width_bytes;
+   stbi_uc *filter_buf;
+   int all_ok = 1;
    int k;
    int img_n = s->img_n; // copy it into a local for later
 
@@ -4678,8 +4711,11 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
    a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
    if (!a->out) return stbi__err("outofmem", "Out of memory");
 
+   // note: error exits here don't need to clean up a->out individually,
+   // stbi__do_png always does on error.
    if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
    img_width_bytes = (((img_n * x * depth) + 7) >> 3);
+   if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG");
    img_len = (img_width_bytes + 1) * y;
 
    // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
@@ -4687,189 +4723,137 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
    // so just check for raw_len < img_len always.
    if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
 
+   // Allocate two scan lines worth of filter workspace buffer.
+   filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0);
+   if (!filter_buf) return stbi__err("outofmem", "Out of memory");
+
+   // Filtering for low-bit-depth images
+   if (depth < 8) {
+      filter_bytes = 1;
+      width = img_width_bytes;
+   }
+
    for (j=0; j < y; ++j) {
-      stbi_uc *cur = a->out + stride*j;
-      stbi_uc *prior;
+      // cur/prior filter buffers alternate
+      stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes;
+      stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes;
+      stbi_uc *dest = a->out + stride*j;
+      int nk = width * filter_bytes;
       int filter = *raw++;
 
-      if (filter > 4)
-         return stbi__err("invalid filter","Corrupt PNG");
-
-      if (depth < 8) {
-         if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
-         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
-         filter_bytes = 1;
-         width = img_width_bytes;
+      // check filter type
+      if (filter > 4) {
+         all_ok = stbi__err("invalid filter","Corrupt PNG");
+         break;
       }
-      prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
 
       // if first row, use special filter that doesn't sample previous row
       if (j == 0) filter = first_row_filter[filter];
 
-      // handle first byte explicitly
-      for (k=0; k < filter_bytes; ++k) {
-         switch (filter) {
-            case STBI__F_none       : cur[k] = raw[k]; break;
-            case STBI__F_sub        : cur[k] = raw[k]; break;
-            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
-            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
-            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
-            case STBI__F_avg_first  : cur[k] = raw[k]; break;
-            case STBI__F_paeth_first: cur[k] = raw[k]; break;
-         }
+      // perform actual filtering
+      switch (filter) {
+      case STBI__F_none:
+         memcpy(cur, raw, nk);
+         break;
+      case STBI__F_sub:
+         memcpy(cur, raw, filter_bytes);
+         for (k = filter_bytes; k < nk; ++k)
+            cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
+         break;
+      case STBI__F_up:
+         for (k = 0; k < nk; ++k)
+            cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
+         break;
+      case STBI__F_avg:
+         for (k = 0; k < filter_bytes; ++k)
+            cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1));
+         for (k = filter_bytes; k < nk; ++k)
+            cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1));
+         break;
+      case STBI__F_paeth:
+         for (k = 0; k < filter_bytes; ++k)
+            cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0)
+         for (k = filter_bytes; k < nk; ++k)
+            cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes]));
+         break;
+      case STBI__F_avg_first:
+         memcpy(cur, raw, filter_bytes);
+         for (k = filter_bytes; k < nk; ++k)
+            cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1));
+         break;
       }
 
-      if (depth == 8) {
-         if (img_n != out_n)
-            cur[img_n] = 255; // first pixel
-         raw += img_n;
-         cur += out_n;
-         prior += out_n;
-      } else if (depth == 16) {
-         if (img_n != out_n) {
-            cur[filter_bytes]   = 255; // first pixel top byte
-            cur[filter_bytes+1] = 255; // first pixel bottom byte
-         }
-         raw += filter_bytes;
-         cur += output_bytes;
-         prior += output_bytes;
-      } else {
-         raw += 1;
-         cur += 1;
-         prior += 1;
-      }
+      raw += nk;
 
-      // this is a little gross, so that we don't switch per-pixel or per-component
-      if (depth < 8 || img_n == out_n) {
-         int nk = (width - 1)*filter_bytes;
-         #define STBI__CASE(f) \
-             case f:     \
-                for (k=0; k < nk; ++k)
-         switch (filter) {
-            // "none" filter turns into a memcpy here; make that explicit.
-            case STBI__F_none:         memcpy(cur, raw, nk); break;
-            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
-            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
-            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
-            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
-            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
-            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
-         }
-         #undef STBI__CASE
-         raw += nk;
-      } else {
-         STBI_ASSERT(img_n+1 == out_n);
-         #define STBI__CASE(f) \
-             case f:     \
-                for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
-                   for (k=0; k < filter_bytes; ++k)
-         switch (filter) {
-            STBI__CASE(STBI__F_none)         { cur[k] = raw[k]; } break;
-            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
-            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
-            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
-            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
-            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
-            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
-         }
-         #undef STBI__CASE
-
-         // the loop above sets the high byte of the pixels' alpha, but for
-         // 16 bit png files we also need the low byte set. we'll do that here.
-         if (depth == 16) {
-            cur = a->out + stride*j; // start at the beginning of the row again
-            for (i=0; i < x; ++i,cur+=output_bytes) {
-               cur[filter_bytes+1] = 255;
-            }
-         }
-      }
-   }
-
-   // we make a separate pass to expand bits to pixels; for performance,
-   // this could run two scanlines behind the above code, so it won't
-   // intefere with filtering but will still be in the cache.
-   if (depth < 8) {
-      for (j=0; j < y; ++j) {
-         stbi_uc *cur = a->out + stride*j;
-         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;
-         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
-         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
+      // expand decoded bits in cur to dest, also adding an extra alpha channel if desired
+      if (depth < 8) {
          stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
+         stbi_uc *in = cur;
+         stbi_uc *out = dest;
+         stbi_uc inb = 0;
+         stbi__uint32 nsmp = x*img_n;
 
-         // note that the final byte might overshoot and write more data than desired.
-         // we can allocate enough data that this never writes out of memory, but it
-         // could also overwrite the next scanline. can it overwrite non-empty data
-         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
-         // so we need to explicitly clamp the final ones
-
+         // expand bits to bytes first
          if (depth == 4) {
-            for (k=x*img_n; k >= 2; k-=2, ++in) {
-               *cur++ = scale * ((*in >> 4)       );
-               *cur++ = scale * ((*in     ) & 0x0f);
+            for (i=0; i < nsmp; ++i) {
+               if ((i & 1) == 0) inb = *in++;
+               *out++ = scale * (inb >> 4);
+               inb <<= 4;
             }
-            if (k > 0) *cur++ = scale * ((*in >> 4)       );
          } else if (depth == 2) {
-            for (k=x*img_n; k >= 4; k-=4, ++in) {
-               *cur++ = scale * ((*in >> 6)       );
-               *cur++ = scale * ((*in >> 4) & 0x03);
-               *cur++ = scale * ((*in >> 2) & 0x03);
-               *cur++ = scale * ((*in     ) & 0x03);
+            for (i=0; i < nsmp; ++i) {
+               if ((i & 3) == 0) inb = *in++;
+               *out++ = scale * (inb >> 6);
+               inb <<= 2;
             }
-            if (k > 0) *cur++ = scale * ((*in >> 6)       );
-            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
-            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
-         } else if (depth == 1) {
-            for (k=x*img_n; k >= 8; k-=8, ++in) {
-               *cur++ = scale * ((*in >> 7)       );
-               *cur++ = scale * ((*in >> 6) & 0x01);
-               *cur++ = scale * ((*in >> 5) & 0x01);
-               *cur++ = scale * ((*in >> 4) & 0x01);
-               *cur++ = scale * ((*in >> 3) & 0x01);
-               *cur++ = scale * ((*in >> 2) & 0x01);
-               *cur++ = scale * ((*in >> 1) & 0x01);
-               *cur++ = scale * ((*in     ) & 0x01);
+         } else {
+            STBI_ASSERT(depth == 1);
+            for (i=0; i < nsmp; ++i) {
+               if ((i & 7) == 0) inb = *in++;
+               *out++ = scale * (inb >> 7);
+               inb <<= 1;
             }
-            if (k > 0) *cur++ = scale * ((*in >> 7)       );
-            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
-            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
-            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
-            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
-            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
-            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
          }
-         if (img_n != out_n) {
-            int q;
-            // insert alpha = 255
-            cur = a->out + stride*j;
+
+         // insert alpha=255 values if desired
+         if (img_n != out_n)
+            stbi__create_png_alpha_expand8(dest, dest, x, img_n);
+      } else if (depth == 8) {
+         if (img_n == out_n)
+            memcpy(dest, cur, x*img_n);
+         else
+            stbi__create_png_alpha_expand8(dest, cur, x, img_n);
+      } else if (depth == 16) {
+         // convert the image data from big-endian to platform-native
+         stbi__uint16 *dest16 = (stbi__uint16*)dest;
+         stbi__uint32 nsmp = x*img_n;
+
+         if (img_n == out_n) {
+            for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
+               *dest16 = (cur[0] << 8) | cur[1];
+         } else {
+            STBI_ASSERT(img_n+1 == out_n);
             if (img_n == 1) {
-               for (q=x-1; q >= 0; --q) {
-                  cur[q*2+1] = 255;
-                  cur[q*2+0] = cur[q];
+               for (i = 0; i < x; ++i, dest16 += 2, cur += 2) {
+                  dest16[0] = (cur[0] << 8) | cur[1];
+                  dest16[1] = 0xffff;
                }
             } else {
                STBI_ASSERT(img_n == 3);
-               for (q=x-1; q >= 0; --q) {
-                  cur[q*4+3] = 255;
-                  cur[q*4+2] = cur[q*3+2];
-                  cur[q*4+1] = cur[q*3+1];
-                  cur[q*4+0] = cur[q*3+0];
+               for (i = 0; i < x; ++i, dest16 += 4, cur += 6) {
+                  dest16[0] = (cur[0] << 8) | cur[1];
+                  dest16[1] = (cur[2] << 8) | cur[3];
+                  dest16[2] = (cur[4] << 8) | cur[5];
+                  dest16[3] = 0xffff;
                }
             }
          }
       }
-   } else if (depth == 16) {
-      // force the image data from big-endian to platform-native.
-      // this is done in a separate pass due to the decoding relying
-      // on the data being untouched, but could probably be done
-      // per-line during decode if care is taken.
-      stbi_uc *cur = a->out;
-      stbi__uint16 *cur16 = (stbi__uint16*)cur;
-
-      for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
-         *cur16 = (cur[0] << 8) | cur[1];
-      }
    }
 
+   STBI_FREE(filter_buf);
+   if (!all_ok) return 0;
+
    return 1;
 }
 

+ 0 - 2634
stb.mod/stb/stb_image_resize.h

@@ -1,2634 +0,0 @@
-/* stb_image_resize - v0.97 - public domain image resizing
-   by Jorge L Rodriguez (@VinoBS) - 2014
-   http://github.com/nothings/stb
-
-   Written with emphasis on usability, portability, and efficiency. (No
-   SIMD or threads, so it be easily outperformed by libs that use those.)
-   Only scaling and translation is supported, no rotations or shears.
-   Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
-
-   COMPILING & LINKING
-      In one C/C++ file that #includes this file, do this:
-         #define STB_IMAGE_RESIZE_IMPLEMENTATION
-      before the #include. That will create the implementation in that file.
-
-   QUICKSTART
-      stbir_resize_uint8(      input_pixels , in_w , in_h , 0,
-                               output_pixels, out_w, out_h, 0, num_channels)
-      stbir_resize_float(...)
-      stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
-                               output_pixels, out_w, out_h, 0,
-                               num_channels , alpha_chan  , 0)
-      stbir_resize_uint8_srgb_edgemode(
-                               input_pixels , in_w , in_h , 0,
-                               output_pixels, out_w, out_h, 0,
-                               num_channels , alpha_chan  , 0, STBIR_EDGE_CLAMP)
-                                                            // WRAP/REFLECT/ZERO
-
-   FULL API
-      See the "header file" section of the source for API documentation.
-
-   ADDITIONAL DOCUMENTATION
-
-      SRGB & FLOATING POINT REPRESENTATION
-         The sRGB functions presume IEEE floating point. If you do not have
-         IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
-         a slower implementation.
-
-      MEMORY ALLOCATION
-         The resize functions here perform a single memory allocation using
-         malloc. To control the memory allocation, before the #include that
-         triggers the implementation, do:
-
-            #define STBIR_MALLOC(size,context) ...
-            #define STBIR_FREE(ptr,context)   ...
-
-         Each resize function makes exactly one call to malloc/free, so to use
-         temp memory, store the temp memory in the context and return that.
-
-      ASSERT
-         Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
-
-      OPTIMIZATION
-         Define STBIR_SATURATE_INT to compute clamp values in-range using
-         integer operations instead of float operations. This may be faster
-         on some platforms.
-
-      DEFAULT FILTERS
-         For functions which don't provide explicit control over what filters
-         to use, you can change the compile-time defaults with
-
-            #define STBIR_DEFAULT_FILTER_UPSAMPLE     STBIR_FILTER_something
-            #define STBIR_DEFAULT_FILTER_DOWNSAMPLE   STBIR_FILTER_something
-
-         See stbir_filter in the header-file section for the list of filters.
-
-      NEW FILTERS
-         A number of 1D filter kernels are used. For a list of
-         supported filters see the stbir_filter enum. To add a new filter,
-         write a filter function and add it to stbir__filter_info_table.
-
-      PROGRESS
-         For interactive use with slow resize operations, you can install
-         a progress-report callback:
-
-            #define STBIR_PROGRESS_REPORT(val)   some_func(val)
-
-         The parameter val is a float which goes from 0 to 1 as progress is made.
-
-         For example:
-
-            static void my_progress_report(float progress);
-            #define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
-
-            #define STB_IMAGE_RESIZE_IMPLEMENTATION
-            #include "stb_image_resize.h"
-
-            static void my_progress_report(float progress)
-            {
-               printf("Progress: %f%%\n", progress*100);
-            }
-
-      MAX CHANNELS
-         If your image has more than 64 channels, define STBIR_MAX_CHANNELS
-         to the max you'll have.
-
-      ALPHA CHANNEL
-         Most of the resizing functions provide the ability to control how
-         the alpha channel of an image is processed. The important things
-         to know about this:
-
-         1. The best mathematically-behaved version of alpha to use is
-         called "premultiplied alpha", in which the other color channels
-         have had the alpha value multiplied in. If you use premultiplied
-         alpha, linear filtering (such as image resampling done by this
-         library, or performed in texture units on GPUs) does the "right
-         thing". While premultiplied alpha is standard in the movie CGI
-         industry, it is still uncommon in the videogame/real-time world.
-
-         If you linearly filter non-premultiplied alpha, strange effects
-         occur. (For example, the 50/50 average of 99% transparent bright green
-         and 1% transparent black produces 50% transparent dark green when
-         non-premultiplied, whereas premultiplied it produces 50%
-         transparent near-black. The former introduces green energy
-         that doesn't exist in the source image.)
-
-         2. Artists should not edit premultiplied-alpha images; artists
-         want non-premultiplied alpha images. Thus, art tools generally output
-         non-premultiplied alpha images.
-
-         3. You will get best results in most cases by converting images
-         to premultiplied alpha before processing them mathematically.
-
-         4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
-         resizer does not do anything special for the alpha channel;
-         it is resampled identically to other channels. This produces
-         the correct results for premultiplied-alpha images, but produces
-         less-than-ideal results for non-premultiplied-alpha images.
-
-         5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
-         then the resizer weights the contribution of input pixels
-         based on their alpha values, or, equivalently, it multiplies
-         the alpha value into the color channels, resamples, then divides
-         by the resultant alpha value. Input pixels which have alpha=0 do
-         not contribute at all to output pixels unless _all_ of the input
-         pixels affecting that output pixel have alpha=0, in which case
-         the result for that pixel is the same as it would be without
-         STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
-         input images in integer formats. For input images in float format,
-         input pixels with alpha=0 have no effect, and output pixels
-         which have alpha=0 will be 0 in all channels. (For float images,
-         you can manually achieve the same result by adding a tiny epsilon
-         value to the alpha channel of every image, and then subtracting
-         or clamping it at the end.)
-
-         6. You can suppress the behavior described in #5 and make
-         all-0-alpha pixels have 0 in all channels by #defining
-         STBIR_NO_ALPHA_EPSILON.
-
-         7. You can separately control whether the alpha channel is
-         interpreted as linear or affected by the colorspace. By default
-         it is linear; you almost never want to apply the colorspace.
-         (For example, graphics hardware does not apply sRGB conversion
-         to the alpha channel.)
-
-   CONTRIBUTORS
-      Jorge L Rodriguez: Implementation
-      Sean Barrett: API design, optimizations
-      Aras Pranckevicius: bugfix
-      Nathan Reed: warning fixes
-
-   REVISIONS
-      0.97 (2020-02-02) fixed warning
-      0.96 (2019-03-04) fixed warnings
-      0.95 (2017-07-23) fixed warnings
-      0.94 (2017-03-18) fixed warnings
-      0.93 (2017-03-03) fixed bug with certain combinations of heights
-      0.92 (2017-01-02) fix integer overflow on large (>2GB) images
-      0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
-      0.90 (2014-09-17) first released version
-
-   LICENSE
-     See end of file for license information.
-
-   TODO
-      Don't decode all of the image data when only processing a partial tile
-      Don't use full-width decode buffers when only processing a partial tile
-      When processing wide images, break processing into tiles so data fits in L1 cache
-      Installable filters?
-      Resize that respects alpha test coverage
-         (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
-         https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
-*/
-
-#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
-#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
-
-#ifdef _MSC_VER
-typedef unsigned char  stbir_uint8;
-typedef unsigned short stbir_uint16;
-typedef unsigned int   stbir_uint32;
-#else
-#include <stdint.h>
-typedef uint8_t  stbir_uint8;
-typedef uint16_t stbir_uint16;
-typedef uint32_t stbir_uint32;
-#endif
-
-#ifndef STBIRDEF
-#ifdef STB_IMAGE_RESIZE_STATIC
-#define STBIRDEF static
-#else
-#ifdef __cplusplus
-#define STBIRDEF extern "C"
-#else
-#define STBIRDEF extern
-#endif
-#endif
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Easy-to-use API:
-//
-//     * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
-//     * input_w is input image width (x-axis), input_h is input image height (y-axis)
-//     * stride is the offset between successive rows of image data in memory, in bytes. you can
-//       specify 0 to mean packed continuously in memory
-//     * alpha channel is treated identically to other channels.
-//     * colorspace is linear or sRGB as specified by function name
-//     * returned result is 1 for success or 0 in case of an error.
-//       #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
-//     * Memory required grows approximately linearly with input and output size, but with
-//       discontinuities at input_w == output_w and input_h == output_h.
-//     * These functions use a "default" resampling filter defined at compile time. To change the filter,
-//       you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
-//       and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
-
-STBIRDEF int stbir_resize_uint8(     const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                           unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                     int num_channels);
-
-STBIRDEF int stbir_resize_float(     const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                           float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                     int num_channels);
-
-
-// The following functions interpret image data as gamma-corrected sRGB.
-// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
-// or otherwise provide the index of the alpha channel. Flags value
-// of 0 will probably do the right thing if you're not sure what
-// the flags mean.
-
-#define STBIR_ALPHA_CHANNEL_NONE       -1
-
-// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
-// use alpha-weighted resampling (effectively premultiplying, resampling,
-// then unpremultiplying).
-#define STBIR_FLAG_ALPHA_PREMULTIPLIED    (1 << 0)
-// The specified alpha channel should be handled as gamma-corrected value even
-// when doing sRGB operations.
-#define STBIR_FLAG_ALPHA_USES_COLORSPACE  (1 << 1)
-
-STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                           unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                     int num_channels, int alpha_channel, int flags);
-
-
-typedef enum
-{
-    STBIR_EDGE_CLAMP   = 1,
-    STBIR_EDGE_REFLECT = 2,
-    STBIR_EDGE_WRAP    = 3,
-    STBIR_EDGE_ZERO    = 4,
-} stbir_edge;
-
-// This function adds the ability to specify how requests to sample off the edge of the image are handled.
-STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                                    unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                              int num_channels, int alpha_channel, int flags,
-                                              stbir_edge edge_wrap_mode);
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Medium-complexity API
-//
-// This extends the easy-to-use API as follows:
-//
-//     * Alpha-channel can be processed separately
-//       * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
-//         * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
-//         * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
-//     * Filter can be selected explicitly
-//     * uint16 image type
-//     * sRGB colorspace available for all types
-//     * context parameter for passing to STBIR_MALLOC
-
-typedef enum
-{
-    STBIR_FILTER_DEFAULT      = 0,  // use same filter type that easy-to-use API chooses
-    STBIR_FILTER_BOX          = 1,  // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
-    STBIR_FILTER_TRIANGLE     = 2,  // On upsampling, produces same results as bilinear texture filtering
-    STBIR_FILTER_CUBICBSPLINE = 3,  // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
-    STBIR_FILTER_CATMULLROM   = 4,  // An interpolating cubic spline
-    STBIR_FILTER_MITCHELL     = 5,  // Mitchell-Netrevalli filter with B=1/3, C=1/3
-} stbir_filter;
-
-typedef enum
-{
-    STBIR_COLORSPACE_LINEAR,
-    STBIR_COLORSPACE_SRGB,
-
-    STBIR_MAX_COLORSPACES,
-} stbir_colorspace;
-
-// The following functions are all identical except for the type of the image data
-
-STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                               unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                         int num_channels, int alpha_channel, int flags,
-                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
-                                         void *alloc_context);
-
-STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels  , int input_w , int input_h , int input_stride_in_bytes,
-                                               stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
-                                         int num_channels, int alpha_channel, int flags,
-                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
-                                         void *alloc_context);
-
-STBIRDEF int stbir_resize_float_generic( const float *input_pixels         , int input_w , int input_h , int input_stride_in_bytes,
-                                               float *output_pixels        , int output_w, int output_h, int output_stride_in_bytes,
-                                         int num_channels, int alpha_channel, int flags,
-                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
-                                         void *alloc_context);
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Full-complexity API
-//
-// This extends the medium API as follows:
-//
-//       * uint32 image type
-//     * not typesafe
-//     * separate filter types for each axis
-//     * separate edge modes for each axis
-//     * can specify scale explicitly for subpixel correctness
-//     * can specify image source tile using texture coordinates
-
-typedef enum
-{
-    STBIR_TYPE_UINT8 ,
-    STBIR_TYPE_UINT16,
-    STBIR_TYPE_UINT32,
-    STBIR_TYPE_FLOAT ,
-
-    STBIR_MAX_TYPES
-} stbir_datatype;
-
-STBIRDEF int stbir_resize(         const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                   stbir_datatype datatype,
-                                   int num_channels, int alpha_channel, int flags,
-                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
-                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
-                                   stbir_colorspace space, void *alloc_context);
-
-STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                   stbir_datatype datatype,
-                                   int num_channels, int alpha_channel, int flags,
-                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
-                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
-                                   stbir_colorspace space, void *alloc_context,
-                                   float x_scale, float y_scale,
-                                   float x_offset, float y_offset);
-
-STBIRDEF int stbir_resize_region(  const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                   stbir_datatype datatype,
-                                   int num_channels, int alpha_channel, int flags,
-                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
-                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
-                                   stbir_colorspace space, void *alloc_context,
-                                   float s0, float t0, float s1, float t1);
-// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
-
-//
-//
-////   end header file   /////////////////////////////////////////////////////
-#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
-
-
-
-
-
-#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
-
-#ifndef STBIR_ASSERT
-#include <assert.h>
-#define STBIR_ASSERT(x) assert(x)
-#endif
-
-// For memset
-#include <string.h>
-
-#include <math.h>
-
-#ifndef STBIR_MALLOC
-#include <stdlib.h>
-// use comma operator to evaluate c, to avoid "unused parameter" warnings
-#define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
-#define STBIR_FREE(ptr,c)    ((void)(c), free(ptr))
-#endif
-
-#ifndef _MSC_VER
-#ifdef __cplusplus
-#define stbir__inline inline
-#else
-#define stbir__inline
-#endif
-#else
-#define stbir__inline __forceinline
-#endif
-
-
-// should produce compiler error if size is wrong
-typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1];
-
-#ifdef _MSC_VER
-#define STBIR__NOTUSED(v)  (void)(v)
-#else
-#define STBIR__NOTUSED(v)  (void)sizeof(v)
-#endif
-
-#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
-
-#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
-#define STBIR_DEFAULT_FILTER_UPSAMPLE    STBIR_FILTER_CATMULLROM
-#endif
-
-#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
-#define STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL
-#endif
-
-#ifndef STBIR_PROGRESS_REPORT
-#define STBIR_PROGRESS_REPORT(float_0_to_1)
-#endif
-
-#ifndef STBIR_MAX_CHANNELS
-#define STBIR_MAX_CHANNELS 64
-#endif
-
-#if STBIR_MAX_CHANNELS > 65536
-#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
-// because we store the indices in 16-bit variables
-#endif
-
-// This value is added to alpha just before premultiplication to avoid
-// zeroing out color values. It is equivalent to 2^-80. If you don't want
-// that behavior (it may interfere if you have floating point images with
-// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
-// disable it.
-#ifndef STBIR_ALPHA_EPSILON
-#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
-#endif
-
-
-
-#ifdef _MSC_VER
-#define STBIR__UNUSED_PARAM(v)  (void)(v)
-#else
-#define STBIR__UNUSED_PARAM(v)  (void)sizeof(v)
-#endif
-
-// must match stbir_datatype
-static unsigned char stbir__type_size[] = {
-    1, // STBIR_TYPE_UINT8
-    2, // STBIR_TYPE_UINT16
-    4, // STBIR_TYPE_UINT32
-    4, // STBIR_TYPE_FLOAT
-};
-
-// Kernel function centered at 0
-typedef float (stbir__kernel_fn)(float x, float scale);
-typedef float (stbir__support_fn)(float scale);
-
-typedef struct
-{
-    stbir__kernel_fn* kernel;
-    stbir__support_fn* support;
-} stbir__filter_info;
-
-// When upsampling, the contributors are which source pixels contribute.
-// When downsampling, the contributors are which destination pixels are contributed to.
-typedef struct
-{
-    int n0; // First contributing pixel
-    int n1; // Last contributing pixel
-} stbir__contributors;
-
-typedef struct
-{
-    const void* input_data;
-    int input_w;
-    int input_h;
-    int input_stride_bytes;
-
-    void* output_data;
-    int output_w;
-    int output_h;
-    int output_stride_bytes;
-
-    float s0, t0, s1, t1;
-
-    float horizontal_shift; // Units: output pixels
-    float vertical_shift;   // Units: output pixels
-    float horizontal_scale;
-    float vertical_scale;
-
-    int channels;
-    int alpha_channel;
-    stbir_uint32 flags;
-    stbir_datatype type;
-    stbir_filter horizontal_filter;
-    stbir_filter vertical_filter;
-    stbir_edge edge_horizontal;
-    stbir_edge edge_vertical;
-    stbir_colorspace colorspace;
-
-    stbir__contributors* horizontal_contributors;
-    float* horizontal_coefficients;
-
-    stbir__contributors* vertical_contributors;
-    float* vertical_coefficients;
-
-    int decode_buffer_pixels;
-    float* decode_buffer;
-
-    float* horizontal_buffer;
-
-    // cache these because ceil/floor are inexplicably showing up in profile
-    int horizontal_coefficient_width;
-    int vertical_coefficient_width;
-    int horizontal_filter_pixel_width;
-    int vertical_filter_pixel_width;
-    int horizontal_filter_pixel_margin;
-    int vertical_filter_pixel_margin;
-    int horizontal_num_contributors;
-    int vertical_num_contributors;
-
-    int ring_buffer_length_bytes;   // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
-    int ring_buffer_num_entries;    // Total number of entries in the ring buffer.
-    int ring_buffer_first_scanline;
-    int ring_buffer_last_scanline;
-    int ring_buffer_begin_index;    // first_scanline is at this index in the ring buffer
-    float* ring_buffer;
-
-    float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
-
-    int horizontal_contributors_size;
-    int horizontal_coefficients_size;
-    int vertical_contributors_size;
-    int vertical_coefficients_size;
-    int decode_buffer_size;
-    int horizontal_buffer_size;
-    int ring_buffer_size;
-    int encode_buffer_size;
-} stbir__info;
-
-
-static const float stbir__max_uint8_as_float  = 255.0f;
-static const float stbir__max_uint16_as_float = 65535.0f;
-static const double stbir__max_uint32_as_float = 4294967295.0;
-
-
-static stbir__inline int stbir__min(int a, int b)
-{
-    return a < b ? a : b;
-}
-
-static stbir__inline float stbir__saturate(float x)
-{
-    if (x < 0)
-        return 0;
-
-    if (x > 1)
-        return 1;
-
-    return x;
-}
-
-#ifdef STBIR_SATURATE_INT
-static stbir__inline stbir_uint8 stbir__saturate8(int x)
-{
-    if ((unsigned int) x <= 255)
-        return x;
-
-    if (x < 0)
-        return 0;
-
-    return 255;
-}
-
-static stbir__inline stbir_uint16 stbir__saturate16(int x)
-{
-    if ((unsigned int) x <= 65535)
-        return x;
-
-    if (x < 0)
-        return 0;
-
-    return 65535;
-}
-#endif
-
-static float stbir__srgb_uchar_to_linear_float[256] = {
-    0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
-    0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
-    0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
-    0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
-    0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
-    0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
-    0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
-    0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
-    0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
-    0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
-    0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
-    0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
-    0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
-    0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
-    0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
-    0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
-    0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
-    0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
-    0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
-    0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
-    0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
-    0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
-    0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
-    0.982251f, 0.991102f, 1.0f
-};
-
-static float stbir__srgb_to_linear(float f)
-{
-    if (f <= 0.04045f)
-        return f / 12.92f;
-    else
-        return (float)pow((f + 0.055f) / 1.055f, 2.4f);
-}
-
-static float stbir__linear_to_srgb(float f)
-{
-    if (f <= 0.0031308f)
-        return f * 12.92f;
-    else
-        return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f;
-}
-
-#ifndef STBIR_NON_IEEE_FLOAT
-// From https://gist.github.com/rygorous/2203834
-
-typedef union
-{
-    stbir_uint32 u;
-    float f;
-} stbir__FP32;
-
-static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
-    0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
-    0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
-    0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
-    0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
-    0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
-    0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
-    0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
-    0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
-    0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
-    0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
-    0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
-    0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
-    0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
-};
-
-static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
-{
-    static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
-    static const stbir__FP32 minval = { (127-13) << 23 };
-    stbir_uint32 tab,bias,scale,t;
-    stbir__FP32 f;
-
-    // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
-    // The tests are carefully written so that NaNs map to 0, same as in the reference
-    // implementation.
-    if (!(in > minval.f)) // written this way to catch NaNs
-        in = minval.f;
-    if (in > almostone.f)
-        in = almostone.f;
-
-    // Do the table lookup and unpack bias, scale
-    f.f = in;
-    tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
-    bias = (tab >> 16) << 9;
-    scale = tab & 0xffff;
-
-    // Grab next-highest mantissa bits and perform linear interpolation
-    t = (f.u >> 12) & 0xff;
-    return (unsigned char) ((bias + scale*t) >> 16);
-}
-
-#else
-// sRGB transition values, scaled by 1<<28
-static int stbir__srgb_offset_to_linear_scaled[256] =
-{
-            0,     40738,    122216,    203693,    285170,    366648,    448125,    529603,
-       611080,    692557,    774035,    855852,    942009,   1033024,   1128971,   1229926,
-      1335959,   1447142,   1563542,   1685229,   1812268,   1944725,   2082664,   2226148,
-      2375238,   2529996,   2690481,   2856753,   3028870,   3206888,   3390865,   3580856,
-      3776916,   3979100,   4187460,   4402049,   4622919,   4850123,   5083710,   5323731,
-      5570236,   5823273,   6082892,   6349140,   6622065,   6901714,   7188133,   7481369,
-      7781466,   8088471,   8402427,   8723380,   9051372,   9386448,   9728650,  10078021,
-     10434603,  10798439,  11169569,  11548036,  11933879,  12327139,  12727857,  13136073,
-     13551826,  13975156,  14406100,  14844697,  15290987,  15745007,  16206795,  16676389,
-     17153826,  17639142,  18132374,  18633560,  19142734,  19659934,  20185196,  20718552,
-     21260042,  21809696,  22367554,  22933648,  23508010,  24090680,  24681686,  25281066,
-     25888850,  26505076,  27129772,  27762974,  28404716,  29055026,  29713942,  30381490,
-     31057708,  31742624,  32436272,  33138682,  33849884,  34569912,  35298800,  36036568,
-     36783260,  37538896,  38303512,  39077136,  39859796,  40651528,  41452360,  42262316,
-     43081432,  43909732,  44747252,  45594016,  46450052,  47315392,  48190064,  49074096,
-     49967516,  50870356,  51782636,  52704392,  53635648,  54576432,  55526772,  56486700,
-     57456236,  58435408,  59424248,  60422780,  61431036,  62449032,  63476804,  64514376,
-     65561776,  66619028,  67686160,  68763192,  69850160,  70947088,  72053992,  73170912,
-     74297864,  75434880,  76581976,  77739184,  78906536,  80084040,  81271736,  82469648,
-     83677792,  84896192,  86124888,  87363888,  88613232,  89872928,  91143016,  92423512,
-     93714432,  95015816,  96327688,  97650056,  98982952, 100326408, 101680440, 103045072,
-    104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
-    115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
-    127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
-    140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
-    154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
-    168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
-    183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
-    199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
-    215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
-    232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
-    250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
-};
-
-static stbir_uint8 stbir__linear_to_srgb_uchar(float f)
-{
-    int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp
-    int v = 0;
-    int i;
-
-    // Refine the guess with a short binary search.
-    i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
-    i = v +  64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
-    i = v +  32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
-    i = v +  16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
-    i = v +   8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
-    i = v +   4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
-    i = v +   2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
-    i = v +   1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
-
-    return (stbir_uint8) v;
-}
-#endif
-
-static float stbir__filter_trapezoid(float x, float scale)
-{
-    float halfscale = scale / 2;
-    float t = 0.5f + halfscale;
-    STBIR_ASSERT(scale <= 1);
-
-    x = (float)fabs(x);
-
-    if (x >= t)
-        return 0;
-    else
-    {
-        float r = 0.5f - halfscale;
-        if (x <= r)
-            return 1;
-        else
-            return (t - x) / scale;
-    }
-}
-
-static float stbir__support_trapezoid(float scale)
-{
-    STBIR_ASSERT(scale <= 1);
-    return 0.5f + scale / 2;
-}
-
-static float stbir__filter_triangle(float x, float s)
-{
-    STBIR__UNUSED_PARAM(s);
-
-    x = (float)fabs(x);
-
-    if (x <= 1.0f)
-        return 1 - x;
-    else
-        return 0;
-}
-
-static float stbir__filter_cubic(float x, float s)
-{
-    STBIR__UNUSED_PARAM(s);
-
-    x = (float)fabs(x);
-
-    if (x < 1.0f)
-        return (4 + x*x*(3*x - 6))/6;
-    else if (x < 2.0f)
-        return (8 + x*(-12 + x*(6 - x)))/6;
-
-    return (0.0f);
-}
-
-static float stbir__filter_catmullrom(float x, float s)
-{
-    STBIR__UNUSED_PARAM(s);
-
-    x = (float)fabs(x);
-
-    if (x < 1.0f)
-        return 1 - x*x*(2.5f - 1.5f*x);
-    else if (x < 2.0f)
-        return 2 - x*(4 + x*(0.5f*x - 2.5f));
-
-    return (0.0f);
-}
-
-static float stbir__filter_mitchell(float x, float s)
-{
-    STBIR__UNUSED_PARAM(s);
-
-    x = (float)fabs(x);
-
-    if (x < 1.0f)
-        return (16 + x*x*(21 * x - 36))/18;
-    else if (x < 2.0f)
-        return (32 + x*(-60 + x*(36 - 7*x)))/18;
-
-    return (0.0f);
-}
-
-static float stbir__support_zero(float s)
-{
-    STBIR__UNUSED_PARAM(s);
-    return 0;
-}
-
-static float stbir__support_one(float s)
-{
-    STBIR__UNUSED_PARAM(s);
-    return 1;
-}
-
-static float stbir__support_two(float s)
-{
-    STBIR__UNUSED_PARAM(s);
-    return 2;
-}
-
-static stbir__filter_info stbir__filter_info_table[] = {
-        { NULL,                     stbir__support_zero },
-        { stbir__filter_trapezoid,  stbir__support_trapezoid },
-        { stbir__filter_triangle,   stbir__support_one },
-        { stbir__filter_cubic,      stbir__support_two },
-        { stbir__filter_catmullrom, stbir__support_two },
-        { stbir__filter_mitchell,   stbir__support_two },
-};
-
-stbir__inline static int stbir__use_upsampling(float ratio)
-{
-    return ratio > 1;
-}
-
-stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info)
-{
-    return stbir__use_upsampling(stbir_info->horizontal_scale);
-}
-
-stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info)
-{
-    return stbir__use_upsampling(stbir_info->vertical_scale);
-}
-
-// This is the maximum number of input samples that can affect an output sample
-// with the given filter
-static int stbir__get_filter_pixel_width(stbir_filter filter, float scale)
-{
-    STBIR_ASSERT(filter != 0);
-    STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
-
-    if (stbir__use_upsampling(scale))
-        return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
-    else
-        return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
-}
-
-// This is how much to expand buffers to account for filters seeking outside
-// the image boundaries.
-static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale)
-{
-    return stbir__get_filter_pixel_width(filter, scale) / 2;
-}
-
-static int stbir__get_coefficient_width(stbir_filter filter, float scale)
-{
-    if (stbir__use_upsampling(scale))
-        return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
-    else
-        return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2);
-}
-
-static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size)
-{
-    if (stbir__use_upsampling(scale))
-        return output_size;
-    else
-        return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
-}
-
-static int stbir__get_total_horizontal_coefficients(stbir__info* info)
-{
-    return info->horizontal_num_contributors
-         * stbir__get_coefficient_width      (info->horizontal_filter, info->horizontal_scale);
-}
-
-static int stbir__get_total_vertical_coefficients(stbir__info* info)
-{
-    return info->vertical_num_contributors
-         * stbir__get_coefficient_width      (info->vertical_filter, info->vertical_scale);
-}
-
-static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n)
-{
-    return &contributors[n];
-}
-
-// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
-// if you change it here change it there too.
-static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c)
-{
-    int width = stbir__get_coefficient_width(filter, scale);
-    return &coefficients[width*n + c];
-}
-
-static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
-{
-    switch (edge)
-    {
-    case STBIR_EDGE_ZERO:
-        return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later
-
-    case STBIR_EDGE_CLAMP:
-        if (n < 0)
-            return 0;
-
-        if (n >= max)
-            return max - 1;
-
-        return n; // NOTREACHED
-
-    case STBIR_EDGE_REFLECT:
-    {
-        if (n < 0)
-        {
-            if (n < max)
-                return -n;
-            else
-                return max - 1;
-        }
-
-        if (n >= max)
-        {
-            int max2 = max * 2;
-            if (n >= max2)
-                return 0;
-            else
-                return max2 - n - 1;
-        }
-
-        return n; // NOTREACHED
-    }
-
-    case STBIR_EDGE_WRAP:
-        if (n >= 0)
-            return (n % max);
-        else
-        {
-            int m = (-n) % max;
-
-            if (m != 0)
-                m = max - m;
-
-            return (m);
-        }
-        // NOTREACHED
-
-    default:
-        STBIR_ASSERT(!"Unimplemented edge type");
-        return 0;
-    }
-}
-
-stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)
-{
-    // avoid per-pixel switch
-    if (n >= 0 && n < max)
-        return n;
-    return stbir__edge_wrap_slow(edge, n, max);
-}
-
-// What input pixels contribute to this output pixel?
-static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out)
-{
-    float out_pixel_center = (float)n + 0.5f;
-    float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
-    float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
-
-    float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
-    float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
-
-    *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio;
-    *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5));
-    *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5));
-}
-
-// What output pixels does this input pixel contribute to?
-static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in)
-{
-    float in_pixel_center = (float)n + 0.5f;
-    float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
-    float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
-
-    float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
-    float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
-
-    *out_center_of_in = in_pixel_center * scale_ratio - out_shift;
-    *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5));
-    *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
-}
-
-static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
-{
-    int i;
-    float total_filter = 0;
-    float filter_scale;
-
-    STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
-
-    contributor->n0 = in_first_pixel;
-    contributor->n1 = in_last_pixel;
-
-    STBIR_ASSERT(contributor->n1 >= contributor->n0);
-
-    for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
-    {
-        float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
-        coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
-
-        // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
-        if (i == 0 && !coefficient_group[i])
-        {
-            contributor->n0 = ++in_first_pixel;
-            i--;
-            continue;
-        }
-
-        total_filter += coefficient_group[i];
-    }
-
-    // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
-    // It would be true in exact math but is at best approximately true in floating-point math,
-    // and it would not make sense to try and put actual bounds on this here because it depends
-    // on the image aspect ratio which can get pretty extreme.
-    //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
-
-    STBIR_ASSERT(total_filter > 0.9);
-    STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
-
-    // Make sure the sum of all coefficients is 1.
-    filter_scale = 1 / total_filter;
-
-    for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
-        coefficient_group[i] *= filter_scale;
-
-    for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
-    {
-        if (coefficient_group[i])
-            break;
-
-        // This line has no weight. We can skip it.
-        contributor->n1 = contributor->n0 + i - 1;
-    }
-}
-
-static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
-{
-    int i;
-
-    STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
-
-    contributor->n0 = out_first_pixel;
-    contributor->n1 = out_last_pixel;
-
-    STBIR_ASSERT(contributor->n1 >= contributor->n0);
-
-    for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
-    {
-        float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
-        float x = out_pixel_center - out_center_of_in;
-        coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
-    }
-
-    // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
-    // It would be true in exact math but is at best approximately true in floating-point math,
-    // and it would not make sense to try and put actual bounds on this here because it depends
-    // on the image aspect ratio which can get pretty extreme.
-    //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
-
-    for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
-    {
-        if (coefficient_group[i])
-            break;
-
-        // This line has no weight. We can skip it.
-        contributor->n1 = contributor->n0 + i - 1;
-    }
-}
-
-static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
-{
-    int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
-    int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
-    int i, j;
-    int skip;
-
-    for (i = 0; i < output_size; i++)
-    {
-        float scale;
-        float total = 0;
-
-        for (j = 0; j < num_contributors; j++)
-        {
-            if (i >= contributors[j].n0 && i <= contributors[j].n1)
-            {
-                float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
-                total += coefficient;
-            }
-            else if (i < contributors[j].n0)
-                break;
-        }
-
-        STBIR_ASSERT(total > 0.9f);
-        STBIR_ASSERT(total < 1.1f);
-
-        scale = 1 / total;
-
-        for (j = 0; j < num_contributors; j++)
-        {
-            if (i >= contributors[j].n0 && i <= contributors[j].n1)
-                *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
-            else if (i < contributors[j].n0)
-                break;
-        }
-    }
-
-    // Optimize: Skip zero coefficients and contributions outside of image bounds.
-    // Do this after normalizing because normalization depends on the n0/n1 values.
-    for (j = 0; j < num_contributors; j++)
-    {
-        int range, max, width;
-
-        skip = 0;
-        while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
-            skip++;
-
-        contributors[j].n0 += skip;
-
-        while (contributors[j].n0 < 0)
-        {
-            contributors[j].n0++;
-            skip++;
-        }
-
-        range = contributors[j].n1 - contributors[j].n0 + 1;
-        max = stbir__min(num_coefficients, range);
-
-        width = stbir__get_coefficient_width(filter, scale_ratio);
-        for (i = 0; i < max; i++)
-        {
-            if (i + skip >= width)
-                break;
-
-            *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
-        }
-
-        continue;
-    }
-
-    // Using min to avoid writing into invalid pixels.
-    for (i = 0; i < num_contributors; i++)
-        contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
-}
-
-// Each scan line uses the same kernel values so we should calculate the kernel
-// values once and then we can use them for every scan line.
-static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
-{
-    int n;
-    int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
-
-    if (stbir__use_upsampling(scale_ratio))
-    {
-        float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
-
-        // Looping through out pixels
-        for (n = 0; n < total_contributors; n++)
-        {
-            float in_center_of_out; // Center of the current out pixel in the in pixel space
-            int in_first_pixel, in_last_pixel;
-
-            stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
-
-            stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
-        }
-    }
-    else
-    {
-        float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
-
-        // Looping through in pixels
-        for (n = 0; n < total_contributors; n++)
-        {
-            float out_center_of_in; // Center of the current out pixel in the in pixel space
-            int out_first_pixel, out_last_pixel;
-            int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
-
-            stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
-
-            stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
-        }
-
-        stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
-    }
-}
-
-static float* stbir__get_decode_buffer(stbir__info* stbir_info)
-{
-    // The 0 index of the decode buffer starts after the margin. This makes
-    // it okay to use negative indexes on the decode buffer.
-    return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
-}
-
-#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace))
-
-static void stbir__decode_scanline(stbir__info* stbir_info, int n)
-{
-    int c;
-    int channels = stbir_info->channels;
-    int alpha_channel = stbir_info->alpha_channel;
-    int type = stbir_info->type;
-    int colorspace = stbir_info->colorspace;
-    int input_w = stbir_info->input_w;
-    size_t input_stride_bytes = stbir_info->input_stride_bytes;
-    float* decode_buffer = stbir__get_decode_buffer(stbir_info);
-    stbir_edge edge_horizontal = stbir_info->edge_horizontal;
-    stbir_edge edge_vertical = stbir_info->edge_vertical;
-    size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
-    const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
-    int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
-    int decode = STBIR__DECODE(type, colorspace);
-
-    int x = -stbir_info->horizontal_filter_pixel_margin;
-
-    // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
-    // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
-    if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
-    {
-        for (; x < max_x; x++)
-            for (c = 0; c < channels; c++)
-                decode_buffer[x*channels + c] = 0;
-        return;
-    }
-
-    switch (decode)
-    {
-    case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
-        for (; x < max_x; x++)
-        {
-            int decode_pixel_index = x * channels;
-            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
-            for (c = 0; c < channels; c++)
-                decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
-        }
-        break;
-
-    case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
-        for (; x < max_x; x++)
-        {
-            int decode_pixel_index = x * channels;
-            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
-            for (c = 0; c < channels; c++)
-                decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
-
-            if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
-                decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
-        }
-        break;
-
-    case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
-        for (; x < max_x; x++)
-        {
-            int decode_pixel_index = x * channels;
-            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
-            for (c = 0; c < channels; c++)
-                decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
-        }
-        break;
-
-    case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
-        for (; x < max_x; x++)
-        {
-            int decode_pixel_index = x * channels;
-            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
-            for (c = 0; c < channels; c++)
-                decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
-
-            if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
-                decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
-        }
-        break;
-
-    case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
-        for (; x < max_x; x++)
-        {
-            int decode_pixel_index = x * channels;
-            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
-            for (c = 0; c < channels; c++)
-                decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
-        }
-        break;
-
-    case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
-        for (; x < max_x; x++)
-        {
-            int decode_pixel_index = x * channels;
-            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
-            for (c = 0; c < channels; c++)
-                decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
-
-            if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
-                decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
-        }
-        break;
-
-    case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
-        for (; x < max_x; x++)
-        {
-            int decode_pixel_index = x * channels;
-            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
-            for (c = 0; c < channels; c++)
-                decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c];
-        }
-        break;
-
-    case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
-        for (; x < max_x; x++)
-        {
-            int decode_pixel_index = x * channels;
-            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
-            for (c = 0; c < channels; c++)
-                decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]);
-
-            if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
-                decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel];
-        }
-
-        break;
-
-    default:
-        STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
-        break;
-    }
-
-    if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
-    {
-        for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
-        {
-            int decode_pixel_index = x * channels;
-
-            // If the alpha value is 0 it will clobber the color values. Make sure it's not.
-            float alpha = decode_buffer[decode_pixel_index + alpha_channel];
-#ifndef STBIR_NO_ALPHA_EPSILON
-            if (stbir_info->type != STBIR_TYPE_FLOAT) {
-                alpha += STBIR_ALPHA_EPSILON;
-                decode_buffer[decode_pixel_index + alpha_channel] = alpha;
-            }
-#endif
-            for (c = 0; c < channels; c++)
-            {
-                if (c == alpha_channel)
-                    continue;
-
-                decode_buffer[decode_pixel_index + c] *= alpha;
-            }
-        }
-    }
-
-    if (edge_horizontal == STBIR_EDGE_ZERO)
-    {
-        for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
-        {
-            for (c = 0; c < channels; c++)
-                decode_buffer[x*channels + c] = 0;
-        }
-        for (x = input_w; x < max_x; x++)
-        {
-            for (c = 0; c < channels; c++)
-                decode_buffer[x*channels + c] = 0;
-        }
-    }
-}
-
-static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length)
-{
-    return &ring_buffer[index * ring_buffer_length];
-}
-
-static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
-{
-    int ring_buffer_index;
-    float* ring_buffer;
-
-    stbir_info->ring_buffer_last_scanline = n;
-
-    if (stbir_info->ring_buffer_begin_index < 0)
-    {
-        ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
-        stbir_info->ring_buffer_first_scanline = n;
-    }
-    else
-    {
-        ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
-        STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
-    }
-
-    ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
-    memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
-
-    return ring_buffer;
-}
-
-
-static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
-{
-    int x, k;
-    int output_w = stbir_info->output_w;
-    int channels = stbir_info->channels;
-    float* decode_buffer = stbir__get_decode_buffer(stbir_info);
-    stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
-    float* horizontal_coefficients = stbir_info->horizontal_coefficients;
-    int coefficient_width = stbir_info->horizontal_coefficient_width;
-
-    for (x = 0; x < output_w; x++)
-    {
-        int n0 = horizontal_contributors[x].n0;
-        int n1 = horizontal_contributors[x].n1;
-
-        int out_pixel_index = x * channels;
-        int coefficient_group = coefficient_width * x;
-        int coefficient_counter = 0;
-
-        STBIR_ASSERT(n1 >= n0);
-        STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
-        STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
-        STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
-        STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
-
-        switch (channels) {
-            case 1:
-                for (k = n0; k <= n1; k++)
-                {
-                    int in_pixel_index = k * 1;
-                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
-                    STBIR_ASSERT(coefficient != 0);
-                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
-                }
-                break;
-            case 2:
-                for (k = n0; k <= n1; k++)
-                {
-                    int in_pixel_index = k * 2;
-                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
-                    STBIR_ASSERT(coefficient != 0);
-                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
-                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
-                }
-                break;
-            case 3:
-                for (k = n0; k <= n1; k++)
-                {
-                    int in_pixel_index = k * 3;
-                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
-                    STBIR_ASSERT(coefficient != 0);
-                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
-                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
-                    output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
-                }
-                break;
-            case 4:
-                for (k = n0; k <= n1; k++)
-                {
-                    int in_pixel_index = k * 4;
-                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
-                    STBIR_ASSERT(coefficient != 0);
-                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
-                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
-                    output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
-                    output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
-                }
-                break;
-            default:
-                for (k = n0; k <= n1; k++)
-                {
-                    int in_pixel_index = k * channels;
-                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
-                    int c;
-                    STBIR_ASSERT(coefficient != 0);
-                    for (c = 0; c < channels; c++)
-                        output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
-                }
-                break;
-        }
-    }
-}
-
-static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
-{
-    int x, k;
-    int input_w = stbir_info->input_w;
-    int channels = stbir_info->channels;
-    float* decode_buffer = stbir__get_decode_buffer(stbir_info);
-    stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
-    float* horizontal_coefficients = stbir_info->horizontal_coefficients;
-    int coefficient_width = stbir_info->horizontal_coefficient_width;
-    int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
-    int max_x = input_w + filter_pixel_margin * 2;
-
-    STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
-
-    switch (channels) {
-        case 1:
-            for (x = 0; x < max_x; x++)
-            {
-                int n0 = horizontal_contributors[x].n0;
-                int n1 = horizontal_contributors[x].n1;
-
-                int in_x = x - filter_pixel_margin;
-                int in_pixel_index = in_x * 1;
-                int max_n = n1;
-                int coefficient_group = coefficient_width * x;
-
-                for (k = n0; k <= max_n; k++)
-                {
-                    int out_pixel_index = k * 1;
-                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
-                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
-                }
-            }
-            break;
-
-        case 2:
-            for (x = 0; x < max_x; x++)
-            {
-                int n0 = horizontal_contributors[x].n0;
-                int n1 = horizontal_contributors[x].n1;
-
-                int in_x = x - filter_pixel_margin;
-                int in_pixel_index = in_x * 2;
-                int max_n = n1;
-                int coefficient_group = coefficient_width * x;
-
-                for (k = n0; k <= max_n; k++)
-                {
-                    int out_pixel_index = k * 2;
-                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
-                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
-                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
-                }
-            }
-            break;
-
-        case 3:
-            for (x = 0; x < max_x; x++)
-            {
-                int n0 = horizontal_contributors[x].n0;
-                int n1 = horizontal_contributors[x].n1;
-
-                int in_x = x - filter_pixel_margin;
-                int in_pixel_index = in_x * 3;
-                int max_n = n1;
-                int coefficient_group = coefficient_width * x;
-
-                for (k = n0; k <= max_n; k++)
-                {
-                    int out_pixel_index = k * 3;
-                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
-                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
-                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
-                    output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
-                }
-            }
-            break;
-
-        case 4:
-            for (x = 0; x < max_x; x++)
-            {
-                int n0 = horizontal_contributors[x].n0;
-                int n1 = horizontal_contributors[x].n1;
-
-                int in_x = x - filter_pixel_margin;
-                int in_pixel_index = in_x * 4;
-                int max_n = n1;
-                int coefficient_group = coefficient_width * x;
-
-                for (k = n0; k <= max_n; k++)
-                {
-                    int out_pixel_index = k * 4;
-                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
-                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
-                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
-                    output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
-                    output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
-                }
-            }
-            break;
-
-        default:
-            for (x = 0; x < max_x; x++)
-            {
-                int n0 = horizontal_contributors[x].n0;
-                int n1 = horizontal_contributors[x].n1;
-
-                int in_x = x - filter_pixel_margin;
-                int in_pixel_index = in_x * channels;
-                int max_n = n1;
-                int coefficient_group = coefficient_width * x;
-
-                for (k = n0; k <= max_n; k++)
-                {
-                    int c;
-                    int out_pixel_index = k * channels;
-                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
-                    for (c = 0; c < channels; c++)
-                        output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
-                }
-            }
-            break;
-    }
-}
-
-static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
-{
-    // Decode the nth scanline from the source image into the decode buffer.
-    stbir__decode_scanline(stbir_info, n);
-
-    // Now resample it into the ring buffer.
-    if (stbir__use_width_upsampling(stbir_info))
-        stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
-    else
-        stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
-
-    // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
-}
-
-static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n)
-{
-    // Decode the nth scanline from the source image into the decode buffer.
-    stbir__decode_scanline(stbir_info, n);
-
-    memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float));
-
-    // Now resample it into the horizontal buffer.
-    if (stbir__use_width_upsampling(stbir_info))
-        stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
-    else
-        stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
-
-    // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
-}
-
-// Get the specified scan line from the ring buffer.
-static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
-{
-    int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
-    return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
-}
-
-
-static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode)
-{
-    int x;
-    int n;
-    int num_nonalpha;
-    stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
-
-    if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
-    {
-        for (x=0; x < num_pixels; ++x)
-        {
-            int pixel_index = x*channels;
-
-            float alpha = encode_buffer[pixel_index + alpha_channel];
-            float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
-
-            // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
-            for (n = 0; n < channels; n++)
-                if (n != alpha_channel)
-                    encode_buffer[pixel_index + n] *= reciprocal_alpha;
-
-            // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
-            // Because we only add it for integer types, it will automatically be discarded on integer
-            // conversion, so we don't need to subtract it back out (which would be problematic for
-            // numeric precision reasons).
-        }
-    }
-
-    // build a table of all channels that need colorspace correction, so
-    // we don't perform colorspace correction on channels that don't need it.
-    for (x = 0, num_nonalpha = 0; x < channels; ++x)
-    {
-        if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
-        {
-            nonalpha[num_nonalpha++] = (stbir_uint16)x;
-        }
-    }
-
-    #define STBIR__ROUND_INT(f)    ((int)          ((f)+0.5))
-    #define STBIR__ROUND_UINT(f)   ((stbir_uint32) ((f)+0.5))
-
-    #ifdef STBIR__SATURATE_INT
-    #define STBIR__ENCODE_LINEAR8(f)   stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
-    #define STBIR__ENCODE_LINEAR16(f)  stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
-    #else
-    #define STBIR__ENCODE_LINEAR8(f)   (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
-    #define STBIR__ENCODE_LINEAR16(f)  (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
-    #endif
-
-    switch (decode)
-    {
-        case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
-            for (x=0; x < num_pixels; ++x)
-            {
-                int pixel_index = x*channels;
-
-                for (n = 0; n < channels; n++)
-                {
-                    int index = pixel_index + n;
-                    ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
-                }
-            }
-            break;
-
-        case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
-            for (x=0; x < num_pixels; ++x)
-            {
-                int pixel_index = x*channels;
-
-                for (n = 0; n < num_nonalpha; n++)
-                {
-                    int index = pixel_index + nonalpha[n];
-                    ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
-                }
-
-                if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
-                    ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
-            }
-            break;
-
-        case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
-            for (x=0; x < num_pixels; ++x)
-            {
-                int pixel_index = x*channels;
-
-                for (n = 0; n < channels; n++)
-                {
-                    int index = pixel_index + n;
-                    ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
-                }
-            }
-            break;
-
-        case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
-            for (x=0; x < num_pixels; ++x)
-            {
-                int pixel_index = x*channels;
-
-                for (n = 0; n < num_nonalpha; n++)
-                {
-                    int index = pixel_index + nonalpha[n];
-                    ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
-                }
-
-                if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
-                    ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
-            }
-
-            break;
-
-        case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
-            for (x=0; x < num_pixels; ++x)
-            {
-                int pixel_index = x*channels;
-
-                for (n = 0; n < channels; n++)
-                {
-                    int index = pixel_index + n;
-                    ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
-                }
-            }
-            break;
-
-        case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
-            for (x=0; x < num_pixels; ++x)
-            {
-                int pixel_index = x*channels;
-
-                for (n = 0; n < num_nonalpha; n++)
-                {
-                    int index = pixel_index + nonalpha[n];
-                    ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
-                }
-
-                if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
-                    ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
-            }
-            break;
-
-        case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
-            for (x=0; x < num_pixels; ++x)
-            {
-                int pixel_index = x*channels;
-
-                for (n = 0; n < channels; n++)
-                {
-                    int index = pixel_index + n;
-                    ((float*)output_buffer)[index] = encode_buffer[index];
-                }
-            }
-            break;
-
-        case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
-            for (x=0; x < num_pixels; ++x)
-            {
-                int pixel_index = x*channels;
-
-                for (n = 0; n < num_nonalpha; n++)
-                {
-                    int index = pixel_index + nonalpha[n];
-                    ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
-                }
-
-                if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
-                    ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
-            }
-            break;
-
-        default:
-            STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
-            break;
-    }
-}
-
-static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
-{
-    int x, k;
-    int output_w = stbir_info->output_w;
-    stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
-    float* vertical_coefficients = stbir_info->vertical_coefficients;
-    int channels = stbir_info->channels;
-    int alpha_channel = stbir_info->alpha_channel;
-    int type = stbir_info->type;
-    int colorspace = stbir_info->colorspace;
-    int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
-    void* output_data = stbir_info->output_data;
-    float* encode_buffer = stbir_info->encode_buffer;
-    int decode = STBIR__DECODE(type, colorspace);
-    int coefficient_width = stbir_info->vertical_coefficient_width;
-    int coefficient_counter;
-    int contributor = n;
-
-    float* ring_buffer = stbir_info->ring_buffer;
-    int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
-    int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
-    int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
-
-    int n0,n1, output_row_start;
-    int coefficient_group = coefficient_width * contributor;
-
-    n0 = vertical_contributors[contributor].n0;
-    n1 = vertical_contributors[contributor].n1;
-
-    output_row_start = n * stbir_info->output_stride_bytes;
-
-    STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
-
-    memset(encode_buffer, 0, output_w * sizeof(float) * channels);
-
-    // I tried reblocking this for better cache usage of encode_buffer
-    // (using x_outer, k, x_inner), but it lost speed. -- stb
-
-    coefficient_counter = 0;
-    switch (channels) {
-        case 1:
-            for (k = n0; k <= n1; k++)
-            {
-                int coefficient_index = coefficient_counter++;
-                float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
-                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
-                for (x = 0; x < output_w; ++x)
-                {
-                    int in_pixel_index = x * 1;
-                    encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
-                }
-            }
-            break;
-        case 2:
-            for (k = n0; k <= n1; k++)
-            {
-                int coefficient_index = coefficient_counter++;
-                float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
-                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
-                for (x = 0; x < output_w; ++x)
-                {
-                    int in_pixel_index = x * 2;
-                    encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
-                    encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
-                }
-            }
-            break;
-        case 3:
-            for (k = n0; k <= n1; k++)
-            {
-                int coefficient_index = coefficient_counter++;
-                float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
-                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
-                for (x = 0; x < output_w; ++x)
-                {
-                    int in_pixel_index = x * 3;
-                    encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
-                    encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
-                    encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
-                }
-            }
-            break;
-        case 4:
-            for (k = n0; k <= n1; k++)
-            {
-                int coefficient_index = coefficient_counter++;
-                float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
-                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
-                for (x = 0; x < output_w; ++x)
-                {
-                    int in_pixel_index = x * 4;
-                    encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
-                    encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
-                    encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
-                    encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
-                }
-            }
-            break;
-        default:
-            for (k = n0; k <= n1; k++)
-            {
-                int coefficient_index = coefficient_counter++;
-                float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
-                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
-                for (x = 0; x < output_w; ++x)
-                {
-                    int in_pixel_index = x * channels;
-                    int c;
-                    for (c = 0; c < channels; c++)
-                        encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
-                }
-            }
-            break;
-    }
-    stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
-}
-
-static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
-{
-    int x, k;
-    int output_w = stbir_info->output_w;
-    stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
-    float* vertical_coefficients = stbir_info->vertical_coefficients;
-    int channels = stbir_info->channels;
-    int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
-    float* horizontal_buffer = stbir_info->horizontal_buffer;
-    int coefficient_width = stbir_info->vertical_coefficient_width;
-    int contributor = n + stbir_info->vertical_filter_pixel_margin;
-
-    float* ring_buffer = stbir_info->ring_buffer;
-    int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
-    int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
-    int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
-    int n0,n1;
-
-    n0 = vertical_contributors[contributor].n0;
-    n1 = vertical_contributors[contributor].n1;
-
-    STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
-
-    for (k = n0; k <= n1; k++)
-    {
-        int coefficient_index = k - n0;
-        int coefficient_group = coefficient_width * contributor;
-        float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
-
-        float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
-
-        switch (channels) {
-            case 1:
-                for (x = 0; x < output_w; x++)
-                {
-                    int in_pixel_index = x * 1;
-                    ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
-                }
-                break;
-            case 2:
-                for (x = 0; x < output_w; x++)
-                {
-                    int in_pixel_index = x * 2;
-                    ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
-                    ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
-                }
-                break;
-            case 3:
-                for (x = 0; x < output_w; x++)
-                {
-                    int in_pixel_index = x * 3;
-                    ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
-                    ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
-                    ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
-                }
-                break;
-            case 4:
-                for (x = 0; x < output_w; x++)
-                {
-                    int in_pixel_index = x * 4;
-                    ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
-                    ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
-                    ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
-                    ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
-                }
-                break;
-            default:
-                for (x = 0; x < output_w; x++)
-                {
-                    int in_pixel_index = x * channels;
-
-                    int c;
-                    for (c = 0; c < channels; c++)
-                        ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
-                }
-                break;
-        }
-    }
-}
-
-static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
-{
-    int y;
-    float scale_ratio = stbir_info->vertical_scale;
-    float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
-
-    STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
-
-    for (y = 0; y < stbir_info->output_h; y++)
-    {
-        float in_center_of_out = 0; // Center of the current out scanline in the in scanline space
-        int in_first_scanline = 0, in_last_scanline = 0;
-
-        stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
-
-        STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
-
-        if (stbir_info->ring_buffer_begin_index >= 0)
-        {
-            // Get rid of whatever we don't need anymore.
-            while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
-            {
-                if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
-                {
-                    // We just popped the last scanline off the ring buffer.
-                    // Reset it to the empty state.
-                    stbir_info->ring_buffer_begin_index = -1;
-                    stbir_info->ring_buffer_first_scanline = 0;
-                    stbir_info->ring_buffer_last_scanline = 0;
-                    break;
-                }
-                else
-                {
-                    stbir_info->ring_buffer_first_scanline++;
-                    stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
-                }
-            }
-        }
-
-        // Load in new ones.
-        if (stbir_info->ring_buffer_begin_index < 0)
-            stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
-
-        while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
-            stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
-
-        // Now all buffers should be ready to write a row of vertical sampling.
-        stbir__resample_vertical_upsample(stbir_info, y);
-
-        STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
-    }
-}
-
-static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline)
-{
-    int output_stride_bytes = stbir_info->output_stride_bytes;
-    int channels = stbir_info->channels;
-    int alpha_channel = stbir_info->alpha_channel;
-    int type = stbir_info->type;
-    int colorspace = stbir_info->colorspace;
-    int output_w = stbir_info->output_w;
-    void* output_data = stbir_info->output_data;
-    int decode = STBIR__DECODE(type, colorspace);
-
-    float* ring_buffer = stbir_info->ring_buffer;
-    int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
-
-    if (stbir_info->ring_buffer_begin_index >= 0)
-    {
-        // Get rid of whatever we don't need anymore.
-        while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
-        {
-            if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
-            {
-                int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
-                float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
-                stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
-                STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
-            }
-
-            if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
-            {
-                // We just popped the last scanline off the ring buffer.
-                // Reset it to the empty state.
-                stbir_info->ring_buffer_begin_index = -1;
-                stbir_info->ring_buffer_first_scanline = 0;
-                stbir_info->ring_buffer_last_scanline = 0;
-                break;
-            }
-            else
-            {
-                stbir_info->ring_buffer_first_scanline++;
-                stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
-            }
-        }
-    }
-}
-
-static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
-{
-    int y;
-    float scale_ratio = stbir_info->vertical_scale;
-    int output_h = stbir_info->output_h;
-    float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
-    int pixel_margin = stbir_info->vertical_filter_pixel_margin;
-    int max_y = stbir_info->input_h + pixel_margin;
-
-    STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
-
-    for (y = -pixel_margin; y < max_y; y++)
-    {
-        float out_center_of_in; // Center of the current out scanline in the in scanline space
-        int out_first_scanline, out_last_scanline;
-
-        stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
-
-        STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
-
-        if (out_last_scanline < 0 || out_first_scanline >= output_h)
-            continue;
-
-        stbir__empty_ring_buffer(stbir_info, out_first_scanline);
-
-        stbir__decode_and_resample_downsample(stbir_info, y);
-
-        // Load in new ones.
-        if (stbir_info->ring_buffer_begin_index < 0)
-            stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
-
-        while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
-            stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
-
-        // Now the horizontal buffer is ready to write to all ring buffer rows.
-        stbir__resample_vertical_downsample(stbir_info, y);
-    }
-
-    stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
-}
-
-static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels)
-{
-    info->input_w = input_w;
-    info->input_h = input_h;
-    info->output_w = output_w;
-    info->output_h = output_h;
-    info->channels = channels;
-}
-
-static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform)
-{
-    info->s0 = s0;
-    info->t0 = t0;
-    info->s1 = s1;
-    info->t1 = t1;
-
-    if (transform)
-    {
-        info->horizontal_scale = transform[0];
-        info->vertical_scale   = transform[1];
-        info->horizontal_shift = transform[2];
-        info->vertical_shift   = transform[3];
-    }
-    else
-    {
-        info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
-        info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
-
-        info->horizontal_shift = s0 * info->output_w / (s1 - s0);
-        info->vertical_shift = t0 * info->output_h / (t1 - t0);
-    }
-}
-
-static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
-{
-    if (h_filter == 0)
-        h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
-    if (v_filter == 0)
-        v_filter = stbir__use_upsampling(info->vertical_scale)   ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
-    info->horizontal_filter = h_filter;
-    info->vertical_filter = v_filter;
-}
-
-static stbir_uint32 stbir__calculate_memory(stbir__info *info)
-{
-    int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
-    int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
-
-    info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
-    info->vertical_num_contributors   = stbir__get_contributors(info->vertical_scale  , info->vertical_filter  , info->input_h, info->output_h);
-
-    // One extra entry because floating point precision problems sometimes cause an extra to be necessary.
-    info->ring_buffer_num_entries = filter_height + 1;
-
-    info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
-    info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
-    info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
-    info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
-    info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
-    info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
-    info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
-    info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
-
-    STBIR_ASSERT(info->horizontal_filter != 0);
-    STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
-    STBIR_ASSERT(info->vertical_filter != 0);
-    STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
-
-    if (stbir__use_height_upsampling(info))
-        // The horizontal buffer is for when we're downsampling the height and we
-        // can't output the result of sampling the decode buffer directly into the
-        // ring buffers.
-        info->horizontal_buffer_size = 0;
-    else
-        // The encode buffer is to retain precision in the height upsampling method
-        // and isn't used when height downsampling.
-        info->encode_buffer_size = 0;
-
-    return info->horizontal_contributors_size + info->horizontal_coefficients_size
-        + info->vertical_contributors_size + info->vertical_coefficients_size
-        + info->decode_buffer_size + info->horizontal_buffer_size
-        + info->ring_buffer_size + info->encode_buffer_size;
-}
-
-static int stbir__resize_allocated(stbir__info *info,
-    const void* input_data, int input_stride_in_bytes,
-    void* output_data, int output_stride_in_bytes,
-    int alpha_channel, stbir_uint32 flags, stbir_datatype type,
-    stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace,
-    void* tempmem, size_t tempmem_size_in_bytes)
-{
-    size_t memory_required = stbir__calculate_memory(info);
-
-    int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type];
-    int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type];
-
-#ifdef STBIR_DEBUG_OVERWRITE_TEST
-#define OVERWRITE_ARRAY_SIZE 8
-    unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE];
-    unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE];
-    unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE];
-    unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE];
-
-    size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type];
-    memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
-    memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE);
-    memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
-    memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
-#endif
-
-    STBIR_ASSERT(info->channels >= 0);
-    STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
-
-    if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
-        return 0;
-
-    STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
-    STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
-
-    if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
-        return 0;
-    if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
-        return 0;
-
-    if (alpha_channel < 0)
-        flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
-
-    if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) {
-        STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
-    }
-
-    if (alpha_channel >= info->channels)
-        return 0;
-
-    STBIR_ASSERT(tempmem);
-
-    if (!tempmem)
-        return 0;
-
-    STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
-
-    if (tempmem_size_in_bytes < memory_required)
-        return 0;
-
-    memset(tempmem, 0, tempmem_size_in_bytes);
-
-    info->input_data = input_data;
-    info->input_stride_bytes = width_stride_input;
-
-    info->output_data = output_data;
-    info->output_stride_bytes = width_stride_output;
-
-    info->alpha_channel = alpha_channel;
-    info->flags = flags;
-    info->type = type;
-    info->edge_horizontal = edge_horizontal;
-    info->edge_vertical = edge_vertical;
-    info->colorspace = colorspace;
-
-    info->horizontal_coefficient_width   = stbir__get_coefficient_width  (info->horizontal_filter, info->horizontal_scale);
-    info->vertical_coefficient_width     = stbir__get_coefficient_width  (info->vertical_filter  , info->vertical_scale  );
-    info->horizontal_filter_pixel_width  = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
-    info->vertical_filter_pixel_width    = stbir__get_filter_pixel_width (info->vertical_filter  , info->vertical_scale  );
-    info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
-    info->vertical_filter_pixel_margin   = stbir__get_filter_pixel_margin(info->vertical_filter  , info->vertical_scale  );
-
-    info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float);
-    info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
-
-#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
-
-    info->horizontal_contributors = (stbir__contributors *) tempmem;
-    info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float);
-    info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
-    info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float);
-    info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float);
-
-    if (stbir__use_height_upsampling(info))
-    {
-        info->horizontal_buffer = NULL;
-        info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
-        info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
-
-        STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
-    }
-    else
-    {
-        info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
-        info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
-        info->encode_buffer = NULL;
-
-        STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
-    }
-
-#undef STBIR__NEXT_MEMPTR
-
-    // This signals that the ring buffer is empty
-    info->ring_buffer_begin_index = -1;
-
-    stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
-    stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
-
-    STBIR_PROGRESS_REPORT(0);
-
-    if (stbir__use_height_upsampling(info))
-        stbir__buffer_loop_upsample(info);
-    else
-        stbir__buffer_loop_downsample(info);
-
-    STBIR_PROGRESS_REPORT(1);
-
-#ifdef STBIR_DEBUG_OVERWRITE_TEST
-    STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
-    STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
-    STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
-    STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
-#endif
-
-    return 1;
-}
-
-
-static int stbir__resize_arbitrary(
-    void *alloc_context,
-    const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
-    void* output_data, int output_w, int output_h, int output_stride_in_bytes,
-    float s0, float t0, float s1, float t1, float *transform,
-    int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type,
-    stbir_filter h_filter, stbir_filter v_filter,
-    stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace)
-{
-    stbir__info info;
-    int result;
-    size_t memory_required;
-    void* extra_memory;
-
-    stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
-    stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
-    stbir__choose_filter(&info, h_filter, v_filter);
-    memory_required = stbir__calculate_memory(&info);
-    extra_memory = STBIR_MALLOC(memory_required, alloc_context);
-
-    if (!extra_memory)
-        return 0;
-
-    result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
-                                            output_data, output_stride_in_bytes,
-                                            alpha_channel, flags, type,
-                                            edge_horizontal, edge_vertical,
-                                            colorspace, extra_memory, memory_required);
-
-    STBIR_FREE(extra_memory, alloc_context);
-
-    return result;
-}
-
-STBIRDEF int stbir_resize_uint8(     const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                           unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                     int num_channels)
-{
-    return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
-        STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
-}
-
-STBIRDEF int stbir_resize_float(     const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                           float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                     int num_channels)
-{
-    return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
-        STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
-}
-
-STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                           unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                     int num_channels, int alpha_channel, int flags)
-{
-    return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
-        STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
-}
-
-STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                                    unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                              int num_channels, int alpha_channel, int flags,
-                                              stbir_edge edge_wrap_mode)
-{
-    return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
-        edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB);
-}
-
-STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                               unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                         int num_channels, int alpha_channel, int flags,
-                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
-                                         void *alloc_context)
-{
-    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
-        edge_wrap_mode, edge_wrap_mode, space);
-}
-
-STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels  , int input_w , int input_h , int input_stride_in_bytes,
-                                               stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
-                                         int num_channels, int alpha_channel, int flags,
-                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
-                                         void *alloc_context)
-{
-    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter,
-        edge_wrap_mode, edge_wrap_mode, space);
-}
-
-
-STBIRDEF int stbir_resize_float_generic( const float *input_pixels         , int input_w , int input_h , int input_stride_in_bytes,
-                                               float *output_pixels        , int output_w, int output_h, int output_stride_in_bytes,
-                                         int num_channels, int alpha_channel, int flags,
-                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
-                                         void *alloc_context)
-{
-    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter,
-        edge_wrap_mode, edge_wrap_mode, space);
-}
-
-
-STBIRDEF int stbir_resize(         const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                   stbir_datatype datatype,
-                                   int num_channels, int alpha_channel, int flags,
-                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
-                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
-                                   stbir_colorspace space, void *alloc_context)
-{
-    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
-        edge_mode_horizontal, edge_mode_vertical, space);
-}
-
-
-STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                   stbir_datatype datatype,
-                                   int num_channels, int alpha_channel, int flags,
-                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
-                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
-                                   stbir_colorspace space, void *alloc_context,
-                                   float x_scale, float y_scale,
-                                   float x_offset, float y_offset)
-{
-    float transform[4];
-    transform[0] = x_scale;
-    transform[1] = y_scale;
-    transform[2] = x_offset;
-    transform[3] = y_offset;
-    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
-        edge_mode_horizontal, edge_mode_vertical, space);
-}
-
-STBIRDEF int stbir_resize_region(  const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
-                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
-                                   stbir_datatype datatype,
-                                   int num_channels, int alpha_channel, int flags,
-                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
-                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
-                                   stbir_colorspace space, void *alloc_context,
-                                   float s0, float t0, float s1, float t1)
-{
-    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
-        output_pixels, output_w, output_h, output_stride_in_bytes,
-        s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
-        edge_mode_horizontal, edge_mode_vertical, space);
-}
-
-#endif // STB_IMAGE_RESIZE_IMPLEMENTATION
-
-/*
-------------------------------------------------------------------------------
-This software is available under 2 licenses -- choose whichever you prefer.
-------------------------------------------------------------------------------
-ALTERNATIVE A - MIT License
-Copyright (c) 2017 Sean Barrett
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-------------------------------------------------------------------------------
-ALTERNATIVE B - Public Domain (www.unlicense.org)
-This is free and unencumbered software released into the public domain.
-Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
-software, either in source code form or as a compiled binary, for any purpose,
-commercial or non-commercial, and by any means.
-In jurisdictions that recognize copyright laws, the author or authors of this
-software dedicate any and all copyright interest in the software to the public
-domain. We make this dedication for the benefit of the public at large and to
-the detriment of our heirs and successors. We intend this dedication to be an
-overt act of relinquishment in perpetuity of all present and future rights to
-this software under copyright law.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------------------
-*/

+ 10325 - 0
stb.mod/stb/stb_image_resize2.h

@@ -0,0 +1,10325 @@
+/* stb_image_resize2 - v2.04 - public domain image resizing
+
+   by Jeff Roberts (v2) and Jorge L Rodriguez
+   http://github.com/nothings/stb
+
+   Can be threaded with the extended API. SSE2, AVX, Neon and WASM SIMD support. Only
+   scaling and translation is supported, no rotations or shears.
+
+   COMPILING & LINKING
+      In one C/C++ file that #includes this file, do this:
+         #define STB_IMAGE_RESIZE_IMPLEMENTATION
+      before the #include. That will create the implementation in that file.
+
+   PORTING FROM VERSION 1
+
+      The API has changed. You can continue to use the old version of stb_image_resize.h,
+      which is available in the "deprecated/" directory.
+
+      If you're using the old simple-to-use API, porting is straightforward.
+      (For more advanced APIs, read the documentation.)
+
+        stbir_resize_uint8():
+          - call `stbir_resize_uint8_linear`, cast channel count to `stbir_pixel_layout`
+
+        stbir_resize_float():
+          - call `stbir_resize_float_linear`, cast channel count to `stbir_pixel_layout`
+
+        stbir_resize_uint8_srgb():
+          - function name is unchanged
+          - cast channel count to `stbir_pixel_layout`
+          - above is sufficient unless your image has alpha and it's not RGBA/BGRA
+            - in that case, follow the below instructions for stbir_resize_uint8_srgb_edgemode
+
+        stbir_resize_uint8_srgb_edgemode()
+          - switch to the "medium complexity" API
+          - stbir_resize(), very similar API but a few more parameters:
+            - pixel_layout: cast channel count to `stbir_pixel_layout`
+            - data_type:    STBIR_TYPE_UINT8_SRGB
+            - edge:         unchanged (STBIR_EDGE_WRAP, etc.)
+            - filter:       STBIR_FILTER_DEFAULT
+          - which channel is alpha is specified in stbir_pixel_layout, see enum for details
+
+   EASY API CALLS:
+     Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation, clamps to edge.
+
+     stbir_resize_uint8_srgb( input_pixels,  input_w,  input_h,  input_stride_in_bytes,
+                              output_pixels, output_w, output_h, output_stride_in_bytes,
+                              pixel_layout_enum )
+
+     stbir_resize_uint8_linear( input_pixels,  input_w,  input_h,  input_stride_in_bytes,
+                                output_pixels, output_w, output_h, output_stride_in_bytes,
+                                pixel_layout_enum )
+
+     stbir_resize_float_linear( input_pixels,  input_w,  input_h,  input_stride_in_bytes,
+                                output_pixels, output_w, output_h, output_stride_in_bytes,
+                                pixel_layout_enum )
+
+     If you pass NULL or zero for the output_pixels, we will allocate the output buffer
+     for you and return it from the function (free with free() or STBIR_FREE).
+     As a special case, XX_stride_in_bytes of 0 means packed continuously in memory.
+
+   API LEVELS
+      There are three levels of API - easy-to-use, medium-complexity and extended-complexity.
+
+      See the "header file" section of the source for API documentation.
+
+   ADDITIONAL DOCUMENTATION
+
+      MEMORY ALLOCATION
+         By default, we use malloc and free for memory allocation.  To override the
+         memory allocation, before the implementation #include, add a:
+
+            #define STBIR_MALLOC(size,user_data) ...
+            #define STBIR_FREE(ptr,user_data)   ...
+
+         Each resize makes exactly one call to malloc/free (unless you use the
+         extended API where you can do one allocation for many resizes). Under
+         address sanitizer, we do separate allocations to find overread/writes.
+
+      PERFORMANCE
+         This library was written with an emphasis on performance. When testing
+         stb_image_resize with RGBA, the fastest mode is STBIR_4CHANNEL with
+         STBIR_TYPE_UINT8 pixels and CLAMPed edges (which is what many other resize
+         libs do by default). Also, make sure SIMD is turned on of course (default
+         for 64-bit targets). Avoid WRAP edge mode if you want the fastest speed.
+
+         This library also comes with profiling built-in. If you define STBIR_PROFILE,
+         you can use the advanced API and get low-level profiling information by
+         calling stbir_resize_extended_profile_info() or stbir_resize_split_profile_info()
+         after a resize.
+
+      SIMD
+         Most of the routines have optimized SSE2, AVX, NEON and WASM versions.
+
+         On Microsoft compilers, we automatically turn on SIMD for 64-bit x64 and
+         ARM; for 32-bit x86 and ARM, you select SIMD mode by defining STBIR_SSE2 or
+         STBIR_NEON. For AVX and AVX2, we auto-select it by detecting the /arch:AVX
+         or /arch:AVX2 switches. You can also always manually turn SSE2, AVX or AVX2
+         support on by defining STBIR_SSE2, STBIR_AVX or STBIR_AVX2.
+
+         On Linux, SSE2 and Neon is on by default for 64-bit x64 or ARM64. For 32-bit,
+         we select x86 SIMD mode by whether you have -msse2, -mavx or -mavx2 enabled
+         on the command line. For 32-bit ARM, you must pass -mfpu=neon-vfpv4 for both
+         clang and GCC, but GCC also requires an additional -mfp16-format=ieee to
+         automatically enable NEON.
+
+         On x86 platforms, you can also define STBIR_FP16C to turn on FP16C instructions
+         for converting back and forth to half-floats. This is autoselected when we
+         are using AVX2. Clang and GCC also require the -mf16c switch. ARM always uses
+         the built-in half float hardware NEON instructions.
+
+         You can also tell us to use multiply-add instructions with STBIR_USE_FMA.
+         Because x86 doesn't always have fma, we turn it off by default to maintain
+         determinism across all platforms. If you don't care about non-FMA determinism
+         and are willing to restrict yourself to more recent x86 CPUs (around the AVX
+         timeframe), then fma will give you around a 15% speedup.
+
+         You can force off SIMD in all cases by defining STBIR_NO_SIMD. You can turn
+         off AVX or AVX2 specifically with STBIR_NO_AVX or STBIR_NO_AVX2. AVX is 10%
+         to 40% faster, and AVX2 is generally another 12%.
+
+      ALPHA CHANNEL
+         Most of the resizing functions provide the ability to control how the alpha
+         channel of an image is processed.
+
+         When alpha represents transparency, it is important that when combining
+         colors with filtering, the pixels should not be treated equally; they
+         should use a weighted average based on their alpha values. For example,
+         if a pixel is 1% opaque bright green and another pixel is 99% opaque
+         black and you average them, the average will be 50% opaque, but the
+         unweighted average and will be a middling green color, while the weighted
+         average will be nearly black. This means the unweighted version introduced
+         green energy that didn't exist in the source image.
+
+         (If you want to know why this makes sense, you can work out the math for
+         the following: consider what happens if you alpha composite a source image
+         over a fixed color and then average the output, vs. if you average the
+         source image pixels and then composite that over the same fixed color.
+         Only the weighted average produces the same result as the ground truth
+         composite-then-average result.)
+
+         Therefore, it is in general best to "alpha weight" the pixels when applying
+         filters to them. This essentially means multiplying the colors by the alpha
+         values before combining them, and then dividing by the alpha value at the
+         end.
+
+         The computer graphics industry introduced a technique called "premultiplied
+         alpha" or "associated alpha" in which image colors are stored in image files
+         already multiplied by their alpha. This saves some math when compositing,
+         and also avoids the need to divide by the alpha at the end (which is quite
+         inefficient). However, while premultiplied alpha is common in the movie CGI
+         industry, it is not commonplace in other industries like videogames, and most
+         consumer file formats are generally expected to contain not-premultiplied
+         colors. For example, Photoshop saves PNG files "unpremultiplied", and web
+         browsers like Chrome and Firefox expect PNG images to be unpremultiplied.
+
+         Note that there are three possibilities that might describe your image
+         and resize expectation:
+
+             1. images are not premultiplied, alpha weighting is desired
+             2. images are not premultiplied, alpha weighting is not desired
+             3. images are premultiplied
+
+         Both case #2 and case #3 require the exact same math: no alpha weighting
+         should be applied or removed. Only case 1 requires extra math operations;
+         the other two cases can be handled identically.
+
+         stb_image_resize expects case #1 by default, applying alpha weighting to
+         images, expecting the input images to be unpremultiplied. This is what the
+         COLOR+ALPHA buffer types tell the resizer to do.
+
+         When you use the pixel layouts STBIR_RGBA, STBIR_BGRA, STBIR_ARGB,
+         STBIR_ABGR, STBIR_RX, or STBIR_XR you are telling us that the pixels are
+         non-premultiplied. In these cases, the resizer will alpha weight the colors
+         (effectively creating the premultiplied image), do the filtering, and then
+         convert back to non-premult on exit.
+
+         When you use the pixel layouts STBIR_RGBA_PM, STBIR_RGBA_PM, STBIR_RGBA_PM,
+         STBIR_RGBA_PM, STBIR_RX_PM or STBIR_XR_PM, you are telling that the pixels
+         ARE premultiplied. In this case, the resizer doesn't have to do the
+         premultipling - it can filter directly on the input. This about twice as
+         fast as the non-premultiplied case, so it's the right option if your data is
+         already setup correctly.
+
+         When you use the pixel layout STBIR_4CHANNEL or STBIR_2CHANNEL, you are
+         telling us that there is no channel that represents transparency; it may be
+         RGB and some unrelated fourth channel that has been stored in the alpha
+         channel, but it is actually not alpha. No special processing will be
+         performed.
+
+         The difference between the generic 4 or 2 channel layouts, and the
+         specialized _PM versions is with the _PM versions you are telling us that
+         the data *is* alpha, just don't premultiply it. That's important when
+         using SRGB pixel formats, we need to know where the alpha is, because
+         it is converted linearly (rather than with the SRGB converters).
+
+         Because alpha weighting produces the same effect as premultiplying, you
+         even have the option with non-premultiplied inputs to let the resizer
+         produce a premultiplied output. Because the intially computed alpha-weighted
+         output image is effectively premultiplied, this is actually more performant
+         than the normal path which un-premultiplies the output image as a final step.
+
+         Finally, when converting both in and out of non-premulitplied space (for
+         example, when using STBIR_RGBA), we go to somewhat heroic measures to
+         ensure that areas with zero alpha value pixels get something reasonable
+         in the RGB values. If you don't care about the RGB values of zero alpha
+         pixels, you can call the stbir_set_non_pm_alpha_speed_over_quality()
+         function - this runs a premultiplied resize about 25% faster. That said,
+         when you really care about speed, using premultiplied pixels for both in
+         and out (STBIR_RGBA_PM, etc) much faster than both of these premultiplied
+         options.
+
+      PIXEL LAYOUT CONVERSION
+         The resizer can convert from some pixel layouts to others. When using the
+         stbir_set_pixel_layouts(), you can, for example, specify STBIR_RGBA
+         on input, and STBIR_ARGB on output, and it will re-organize the channels
+         during the resize. Currently, you can only convert between two pixel
+         layouts with the same number of channels.
+
+      DETERMINISM
+         We commit to being deterministic (from x64 to ARM to scalar to SIMD, etc).
+         This requires compiling with fast-math off (using at least /fp:precise).
+         Also, you must turn off fp-contracting (which turns mult+adds into fmas)!
+         We attempt to do this with pragmas, but with Clang, you usually want to add
+         -ffp-contract=off to the command line as well.
+
+         For 32-bit x86, you must use SSE and SSE2 codegen for determinism. That is,
+         if the scalar x87 unit gets used at all, we immediately lose determinism.
+         On Microsoft Visual Studio 2008 and earlier, from what we can tell there is
+         no way to be deterministic in 32-bit x86 (some x87 always leaks in, even
+         with fp:strict). On 32-bit x86 GCC, determinism requires both -msse2 and
+         -fpmath=sse.
+
+         Note that we will not be deterministic with float data containing NaNs -
+         the NaNs will propagate differently on different SIMD and platforms.
+
+         If you turn on STBIR_USE_FMA, then we will be deterministic with other
+         fma targets, but we will differ from non-fma targets (this is unavoidable,
+         because a fma isn't simply an add with a mult - it also introduces a
+         rounding difference compared to non-fma instruction sequences.
+
+      FLOAT PIXEL FORMAT RANGE
+         Any range of values can be used for the non-alpha float data that you pass
+         in (0 to 1, -1 to 1, whatever). However, if you are inputting float values
+         but *outputting* bytes or shorts, you must use a range of 0 to 1 so that we
+         scale back properly. The alpha channel must also be 0 to 1 for any format
+         that does premultiplication prior to resizing.
+
+         Note also that with float output, using filters with negative lobes, the
+         output filtered values might go slightly out of range. You can define
+         STBIR_FLOAT_LOW_CLAMP and/or STBIR_FLOAT_HIGH_CLAMP to specify the range
+         to clamp to on output, if that's important.
+
+      MAX/MIN SCALE FACTORS
+         The input pixel resolutions are in integers, and we do the internal pointer
+         resolution in size_t sized integers. However, the scale ratio from input
+         resolution to output resolution is calculated in float form. This means
+         the effective possible scale ratio is limited to 24 bits (or 16 million
+         to 1). As you get close to the size of the float resolution (again, 16
+         million pixels wide or high), you might start seeing float inaccuracy
+         issues in general in the pipeline. If you have to do extreme resizes,
+         you can usually do this is multiple stages (using float intermediate
+         buffers).
+
+      FLIPPED IMAGES
+         Stride is just the delta from one scanline to the next. This means you can
+         use a negative stride to handle inverted images (point to the final
+         scanline and use a negative stride). You can invert the input or output,
+         using negative strides.
+
+      DEFAULT FILTERS
+         For functions which don't provide explicit control over what filters to
+         use, you can change the compile-time defaults with:
+
+            #define STBIR_DEFAULT_FILTER_UPSAMPLE     STBIR_FILTER_something
+            #define STBIR_DEFAULT_FILTER_DOWNSAMPLE   STBIR_FILTER_something
+
+         See stbir_filter in the header-file section for the list of filters.
+
+      NEW FILTERS
+         A number of 1D filter kernels are supplied. For a list of supported
+         filters, see the stbir_filter enum. You can install your own filters by
+         using the stbir_set_filter_callbacks function.
+
+      PROGRESS
+         For interactive use with slow resize operations, you can use the the
+         scanline callbacks in the extended API. It would have to be a *very* large
+         image resample to need progress though - we're very fast.
+
+      CEIL and FLOOR
+         In scalar mode, the only functions we use from math.h are ceilf and floorf,
+         but if you have your own versions, you can define the STBIR_CEILF(v) and
+         STBIR_FLOORF(v) macros and we'll use them instead. In SIMD, we just use
+         our own versions.
+
+      ASSERT
+         Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
+
+      FUTURE TODOS
+        *  For polyphase integral filters, we just memcpy the coeffs to dupe
+           them, but we should indirect and use the same coeff memory.
+        *  Add pixel layout conversions for sensible different channel counts
+           (maybe, 1->3/4, 3->4, 4->1, 3->1).
+         * For SIMD encode and decode scanline routines, do any pre-aligning
+           for bad input/output buffer alignments and pitch?
+         * For very wide scanlines, we should we do vertical strips to stay within
+           L2 cache. Maybe do chunks of 1K pixels at a time. There would be
+           some pixel reconversion, but probably dwarfed by things falling out
+           of cache. Probably also something possible with alternating between
+           scattering and gathering at high resize scales?
+         * Rewrite the coefficient generator to do many at once.
+         * AVX-512 vertical kernels - worried about downclocking here.
+         * Convert the reincludes to macros when we know they aren't changing.
+         * Experiment with pivoting the horizontal and always using the
+           vertical filters (which are faster, but perhaps not enough to overcome
+           the pivot cost and the extra memory touches). Need to buffer the whole
+           image so have to balance memory use.
+         * Most of our code is internally function pointers, should we compile
+           all the SIMD stuff always and dynamically dispatch?
+
+   CONTRIBUTORS
+      Jeff Roberts: 2.0 implementation, optimizations, SIMD
+      Martins Mozeiko: NEON simd, WASM simd, clang and GCC whisperer.
+      Fabian Giesen: half float and srgb converters
+      Sean Barrett: API design, optimizations
+      Jorge L Rodriguez: Original 1.0 implementation
+      Aras Pranckevicius: bugfixes for 1.0
+      Nathan Reed: warning fixes for 1.0
+
+   REVISIONS
+      2.04 (2023-11-17) Fix for rare AVX bug, shadowed symbol (thanks Nikola Smiljanic).
+      2.03 (2023-11-01) ASAN and TSAN warnings fixed, minor tweaks.
+      2.00 (2023-10-10) mostly new source: new api, optimizations, simd, vertical-first, etc
+                          (2x-5x faster without simd, 4x-12x faster with simd)
+                          (in some cases, 20x to 40x faster - resizing to very small for example)
+      0.96 (2019-03-04) fixed warnings
+      0.95 (2017-07-23) fixed warnings
+      0.94 (2017-03-18) fixed warnings
+      0.93 (2017-03-03) fixed bug with certain combinations of heights
+      0.92 (2017-01-02) fix integer overflow on large (>2GB) images
+      0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
+      0.90 (2014-09-17) first released version
+
+   LICENSE
+     See end of file for license information.
+*/
+
+#if !defined(STB_IMAGE_RESIZE_DO_HORIZONTALS) && !defined(STB_IMAGE_RESIZE_DO_VERTICALS) && !defined(STB_IMAGE_RESIZE_DO_CODERS)   // for internal re-includes
+
+#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE2_H
+#define STBIR_INCLUDE_STB_IMAGE_RESIZE2_H
+
+#include <stddef.h>
+#ifdef _MSC_VER
+typedef unsigned char    stbir_uint8;
+typedef unsigned short   stbir_uint16;
+typedef unsigned int     stbir_uint32;
+typedef unsigned __int64 stbir_uint64;
+#else
+#include <stdint.h>
+typedef uint8_t  stbir_uint8;
+typedef uint16_t stbir_uint16;
+typedef uint32_t stbir_uint32;
+typedef uint64_t stbir_uint64;
+#endif
+
+#ifdef _M_IX86_FP
+#if ( _M_IX86_FP >= 1 )
+#ifndef STBIR_SSE
+#define STBIR_SSE
+#endif
+#endif
+#endif
+
+#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(_M_AMD64) || defined(__SSE2__) || defined(STBIR_SSE) || defined(STBIR_SSE2)
+  #ifndef STBIR_SSE2
+    #define STBIR_SSE2
+  #endif
+  #if defined(__AVX__) || defined(STBIR_AVX2)
+    #ifndef STBIR_AVX
+      #ifndef STBIR_NO_AVX
+        #define STBIR_AVX
+      #endif
+    #endif
+  #endif
+  #if defined(__AVX2__) || defined(STBIR_AVX2)
+    #ifndef STBIR_NO_AVX2
+      #ifndef STBIR_AVX2
+        #define STBIR_AVX2
+      #endif
+      #if defined( _MSC_VER ) && !defined(__clang__)
+        #ifndef STBIR_FP16C  // FP16C instructions are on all AVX2 cpus, so we can autoselect it here on microsoft - clang needs -m16c
+          #define STBIR_FP16C
+        #endif
+      #endif
+    #endif
+  #endif
+  #ifdef __F16C__
+    #ifndef STBIR_FP16C  // turn on FP16C instructions if the define is set (for clang and gcc)
+      #define STBIR_FP16C
+    #endif
+  #endif
+#endif
+
+#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(_M_ARM) || (__ARM_NEON_FP & 4) != 0 &&  __ARM_FP16_FORMAT_IEEE != 0
+#ifndef STBIR_NEON
+#define STBIR_NEON
+#endif
+#endif
+
+#if defined(_M_ARM)
+#ifdef STBIR_USE_FMA
+#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC
+#endif
+#endif
+
+#if defined(__wasm__) && defined(__wasm_simd128__)
+#ifndef STBIR_WASM
+#define STBIR_WASM
+#endif
+#endif
+
+#ifndef STBIRDEF
+#ifdef STB_IMAGE_RESIZE_STATIC
+#define STBIRDEF static
+#else
+#ifdef __cplusplus
+#define STBIRDEF extern "C"
+#else
+#define STBIRDEF extern
+#endif
+#endif
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+////   start "header file" ///////////////////////////////////////////////////
+//
+// Easy-to-use API:
+//
+//     * stride is the offset between successive rows of image data
+//        in memory, in bytes. specify 0 for packed continuously in memory
+//     * colorspace is linear or sRGB as specified by function name
+//     * Uses the default filters
+//     * Uses edge mode clamped
+//     * returned result is 1 for success or 0 in case of an error.
+
+
+// stbir_pixel_layout specifies:
+//   number of channels
+//   order of channels
+//   whether color is premultiplied by alpha
+// for back compatibility, you can cast the old channel count to an stbir_pixel_layout
+typedef enum
+{
+  STBIR_1CHANNEL = 1,
+  STBIR_2CHANNEL = 2,
+  STBIR_RGB      = 3,               // 3-chan, with order specified (for channel flipping)
+  STBIR_BGR      = 0,               // 3-chan, with order specified (for channel flipping)
+  STBIR_4CHANNEL = 5,
+
+  STBIR_RGBA = 4,                   // alpha formats, where alpha is NOT premultiplied into color channels
+  STBIR_BGRA = 6,
+  STBIR_ARGB = 7,
+  STBIR_ABGR = 8,
+  STBIR_RA   = 9,
+  STBIR_AR   = 10,
+
+  STBIR_RGBA_PM = 11,               // alpha formats, where alpha is premultiplied into color channels
+  STBIR_BGRA_PM = 12,
+  STBIR_ARGB_PM = 13,
+  STBIR_ABGR_PM = 14,
+  STBIR_RA_PM   = 15,
+  STBIR_AR_PM   = 16,
+
+  STBIR_RGBA_NO_AW = 11,            // alpha formats, where NO alpha weighting is applied at all!
+  STBIR_BGRA_NO_AW = 12,            //   these are just synonyms for the _PM flags (which also do
+  STBIR_ARGB_NO_AW = 13,            //   no alpha weighting). These names just make it more clear
+  STBIR_ABGR_NO_AW = 14,            //   for some folks).
+  STBIR_RA_NO_AW   = 15,
+  STBIR_AR_NO_AW   = 16,
+
+} stbir_pixel_layout;
+
+//===============================================================
+//  Simple-complexity API
+//
+//    If output_pixels is NULL (0), then we will allocate the buffer and return it to you.
+//--------------------------------
+
+STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                                        unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                                                        stbir_pixel_layout pixel_type );
+
+STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                                          unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                                                          stbir_pixel_layout pixel_type );
+
+STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                                  float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                                                  stbir_pixel_layout pixel_type );
+//===============================================================
+
+//===============================================================
+// Medium-complexity API
+//
+// This extends the easy-to-use API as follows:
+//
+//     * Can specify the datatype - U8, U8_SRGB, U16, FLOAT, HALF_FLOAT
+//     * Edge wrap can selected explicitly
+//     * Filter can be selected explicitly
+//--------------------------------
+
+typedef enum
+{
+  STBIR_EDGE_CLAMP   = 0,
+  STBIR_EDGE_REFLECT = 1,
+  STBIR_EDGE_WRAP    = 2,  // this edge mode is slower and uses more memory
+  STBIR_EDGE_ZERO    = 3,
+} stbir_edge;
+
+typedef enum
+{
+  STBIR_FILTER_DEFAULT      = 0,  // use same filter type that easy-to-use API chooses
+  STBIR_FILTER_BOX          = 1,  // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
+  STBIR_FILTER_TRIANGLE     = 2,  // On upsampling, produces same results as bilinear texture filtering
+  STBIR_FILTER_CUBICBSPLINE = 3,  // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
+  STBIR_FILTER_CATMULLROM   = 4,  // An interpolating cubic spline
+  STBIR_FILTER_MITCHELL     = 5,  // Mitchell-Netrevalli filter with B=1/3, C=1/3
+  STBIR_FILTER_POINT_SAMPLE = 6,  // Simple point sampling
+  STBIR_FILTER_OTHER        = 7,  // User callback specified
+} stbir_filter;
+
+typedef enum
+{
+  STBIR_TYPE_UINT8            = 0,
+  STBIR_TYPE_UINT8_SRGB       = 1,
+  STBIR_TYPE_UINT8_SRGB_ALPHA = 2,  // alpha channel, when present, should also be SRGB (this is very unusual)
+  STBIR_TYPE_UINT16           = 3,
+  STBIR_TYPE_FLOAT            = 4,
+  STBIR_TYPE_HALF_FLOAT       = 5
+} stbir_datatype;
+
+// medium api
+STBIRDEF void *  stbir_resize( const void *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                     void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                               stbir_pixel_layout pixel_layout, stbir_datatype data_type,
+                               stbir_edge edge, stbir_filter filter );
+//===============================================================
+
+
+
+//===============================================================
+// Extended-complexity API
+//
+// This API exposes all resize functionality.
+//
+//     * Separate filter types for each axis
+//     * Separate edge modes for each axis
+//     * Separate input and output data types
+//     * Can specify regions with subpixel correctness
+//     * Can specify alpha flags
+//     * Can specify a memory callback
+//     * Can specify a callback data type for pixel input and output
+//     * Can be threaded for a single resize
+//     * Can be used to resize many frames without recalculating the sampler info
+//
+//  Use this API as follows:
+//     1) Call the stbir_resize_init function on a local STBIR_RESIZE structure
+//     2) Call any of the stbir_set functions
+//     3) Optionally call stbir_build_samplers() if you are going to resample multiple times
+//        with the same input and output dimensions (like resizing video frames)
+//     4) Resample by calling stbir_resize_extended().
+//     5) Call stbir_free_samplers() if you called stbir_build_samplers()
+//--------------------------------
+
+
+// Types:
+
+// INPUT CALLBACK: this callback is used for input scanlines
+typedef void const * stbir_input_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context );
+
+// OUTPUT CALLBACK: this callback is used for output scanlines
+typedef void stbir_output_callback( void const * output_ptr, int num_pixels, int y, void * context );
+
+// callbacks for user installed filters
+typedef float stbir__kernel_callback( float x, float scale, void * user_data ); // centered at zero
+typedef float stbir__support_callback( float scale, void * user_data );
+
+// internal structure with precomputed scaling
+typedef struct stbir__info stbir__info;
+
+typedef struct STBIR_RESIZE  // use the stbir_resize_init and stbir_override functions to set these values for future compatibility
+{
+  void * user_data;
+  void const * input_pixels;
+  int input_w, input_h;
+  double input_s0, input_t0, input_s1, input_t1;
+  stbir_input_callback * input_cb;
+  void * output_pixels;
+  int output_w, output_h;
+  int output_subx, output_suby, output_subw, output_subh;
+  stbir_output_callback * output_cb;
+  int input_stride_in_bytes;
+  int output_stride_in_bytes;
+  int splits;
+  int fast_alpha;
+  int needs_rebuild;
+  int called_alloc;
+  stbir_pixel_layout input_pixel_layout_public;
+  stbir_pixel_layout output_pixel_layout_public;
+  stbir_datatype input_data_type;
+  stbir_datatype output_data_type;
+  stbir_filter horizontal_filter, vertical_filter;
+  stbir_edge horizontal_edge, vertical_edge;
+  stbir__kernel_callback * horizontal_filter_kernel; stbir__support_callback * horizontal_filter_support;
+  stbir__kernel_callback * vertical_filter_kernel; stbir__support_callback * vertical_filter_support;
+  stbir__info * samplers;
+} STBIR_RESIZE;
+
+// extended complexity api
+
+
+// First off, you must ALWAYS call stbir_resize_init on your resize structure before any of the other calls!
+STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize,
+                                 const void *input_pixels,  int input_w,  int input_h, int input_stride_in_bytes, // stride can be zero
+                                       void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, // stride can be zero
+                                 stbir_pixel_layout pixel_layout, stbir_datatype data_type );
+
+//===============================================================
+// You can update these parameters any time after resize_init and there is no cost
+//--------------------------------
+
+STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type );
+STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb );   // no callbacks by default
+STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data );                                               // pass back STBIR_RESIZE* by default
+STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes );
+
+//===============================================================
+
+
+//===============================================================
+// If you call any of these functions, you will trigger a sampler rebuild!
+//--------------------------------
+
+STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout input_pixel_layout, stbir_pixel_layout output_pixel_layout );  // sets new buffer layouts
+STBIRDEF int stbir_set_edgemodes( STBIR_RESIZE * resize, stbir_edge horizontal_edge, stbir_edge vertical_edge );       // CLAMP by default
+
+STBIRDEF int stbir_set_filters( STBIR_RESIZE * resize, stbir_filter horizontal_filter, stbir_filter vertical_filter ); // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default
+STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support );
+
+STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh );        // sets both sub-regions (full regions by default)
+STBIRDEF int stbir_set_input_subrect( STBIR_RESIZE * resize, double s0, double t0, double s1, double t1 );    // sets input sub-region (full region by default)
+STBIRDEF int stbir_set_output_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ); // sets output sub-region (full region by default)
+
+// when inputting AND outputting non-premultiplied alpha pixels, we use a slower but higher quality technique
+//   that fills the zero alpha pixel's RGB values with something plausible.  If you don't care about areas of
+//   zero alpha, you can call this function to get about a 25% speed improvement for STBIR_RGBA to STBIR_RGBA
+//   types of resizes.
+STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, int non_pma_alpha_speed_over_quality );
+//===============================================================
+
+
+//===============================================================
+// You can call build_samplers to prebuild all the internal data we need to resample.
+//   Then, if you call resize_extended many times with the same resize, you only pay the
+//   cost once.
+// If you do call build_samplers, you MUST call free_samplers eventually.
+//--------------------------------
+
+// This builds the samplers and does one allocation
+STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize );
+
+// You MUST call this, if you call stbir_build_samplers or stbir_build_samplers_with_splits
+STBIRDEF void stbir_free_samplers( STBIR_RESIZE * resize );
+//===============================================================
+
+
+// And this is the main function to perform the resize synchronously on one thread.
+STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize );
+
+
+//===============================================================
+// Use these functions for multithreading.
+//   1) You call stbir_build_samplers_with_splits first on the main thread
+//   2) Then stbir_resize_with_split on each thread
+//   3) stbir_free_samplers when done on the main thread
+//--------------------------------
+
+// This will build samplers for threading.
+//   You can pass in the number of threads you'd like to use (try_splits).
+//   It returns the number of splits (threads) that you can call it with.
+///  It might be less if the image resize can't be split up that many ways.
+
+STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_splits );
+
+// This function does a split of the resizing (you call this fuction for each
+// split, on multiple threads). A split is a piece of the output resize pixel space.
+
+// Note that you MUST call stbir_build_samplers_with_splits before stbir_resize_extended_split!
+
+// Usually, you will always call stbir_resize_split with split_start as the thread_index
+//   and "1" for the split_count.
+// But, if you have a weird situation where you MIGHT want 8 threads, but sometimes
+//   only 4 threads, you can use 0,2,4,6 for the split_start's and use "2" for the
+//   split_count each time to turn in into a 4 thread resize. (This is unusual).
+
+STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count );
+//===============================================================
+
+
+//===============================================================
+// Pixel Callbacks info:
+//--------------------------------
+
+//   The input callback is super flexible - it calls you with the input address
+//   (based on the stride and base pointer), it gives you an optional_output
+//   pointer that you can fill, or you can just return your own pointer into
+//   your own data.
+//
+//   You can also do conversion from non-supported data types if necessary - in
+//   this case, you ignore the input_ptr and just use the x and y parameters to
+//   calculate your own input_ptr based on the size of each non-supported pixel.
+//   (Something like the third example below.)
+//
+//   You can also install just an input or just an output callback by setting the
+//   callback that you don't want to zero.
+//
+//     First example, progress: (getting a callback that you can monitor the progress):
+//        void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )
+//        {
+//           percentage_done = y / input_height;
+//           return input_ptr;  // use buffer from call
+//        }
+//
+//     Next example, copying: (copy from some other buffer or stream):
+//        void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )
+//        {
+//           CopyOrStreamData( optional_output, other_data_src, num_pixels * pixel_width_in_bytes );
+//           return optional_output;  // return the optional buffer that we filled
+//        }
+//
+//     Third example, input another buffer without copying: (zero-copy from other buffer):
+//        void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )
+//        {
+//           void * pixels = ( (char*) other_image_base ) + ( y * other_image_stride ) + ( x * other_pixel_width_in_bytes );
+//           return pixels;       // return pointer to your data without copying
+//        }
+//
+//
+//   The output callback is considerably simpler - it just calls you so that you can dump
+//   out each scanline. You could even directly copy out to disk if you have a simple format
+//   like TGA or BMP. You can also convert to other output types here if you want.
+//
+//   Simple example:
+//        void const * my_output( void * output_ptr, int num_pixels, int y, void * context )
+//        {
+//           percentage_done = y / output_height;
+//           fwrite( output_ptr, pixel_width_in_bytes, num_pixels, output_file );
+//        }
+//===============================================================
+
+
+
+
+//===============================================================
+// optional built-in profiling API
+//--------------------------------
+
+#ifdef STBIR_PROFILE
+
+typedef struct STBIR_PROFILE_INFO
+{
+  stbir_uint64 total_clocks;
+
+  // how many clocks spent (of total_clocks) in the various resize routines, along with a string description
+  //    there are "resize_count" number of zones
+  stbir_uint64 clocks[ 8 ];
+  char const ** descriptions;
+
+  // count of clocks and descriptions
+  stbir_uint32 count;
+} STBIR_PROFILE_INFO;
+
+// use after calling stbir_resize_extended (or stbir_build_samplers or stbir_build_samplers_with_splits)
+STBIRDEF void stbir_resize_build_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize );
+
+// use after calling stbir_resize_extended
+STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize );
+
+// use after calling stbir_resize_extended_split
+STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * out_info, STBIR_RESIZE const * resize, int split_start, int split_num );
+
+//===============================================================
+
+#endif
+
+
+////   end header file   /////////////////////////////////////////////////////
+#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE2_H
+
+#if defined(STB_IMAGE_RESIZE_IMPLEMENTATION) || defined(STB_IMAGE_RESIZE2_IMPLEMENTATION)
+
+#ifndef STBIR_ASSERT
+#include <assert.h>
+#define STBIR_ASSERT(x) assert(x)
+#endif
+
+#ifndef STBIR_MALLOC
+#include <stdlib.h>
+#define STBIR_MALLOC(size,user_data) ((void)(user_data), malloc(size))
+#define STBIR_FREE(ptr,user_data)    ((void)(user_data), free(ptr))
+// (we used the comma operator to evaluate user_data, to avoid "unused parameter" warnings)
+#endif
+
+#ifdef _MSC_VER
+
+#define stbir__inline __forceinline
+
+#else
+
+#define stbir__inline __inline__
+
+// Clang address sanitizer
+#if defined(__has_feature)
+  #if __has_feature(address_sanitizer) || __has_feature(memory_sanitizer)
+    #ifndef STBIR__SEPARATE_ALLOCATIONS
+      #define STBIR__SEPARATE_ALLOCATIONS
+    #endif
+  #endif
+#endif
+
+#endif
+
+// GCC and MSVC
+#if defined(__SANITIZE_ADDRESS__)
+  #ifndef STBIR__SEPARATE_ALLOCATIONS
+    #define STBIR__SEPARATE_ALLOCATIONS
+  #endif
+#endif
+
+// Always turn off automatic FMA use - use STBIR_USE_FMA if you want.
+// Otherwise, this is a determinism disaster.
+#ifndef STBIR_DONT_CHANGE_FP_CONTRACT  // override in case you don't want this behavior
+#if defined(_MSC_VER) && !defined(__clang__)
+#if _MSC_VER > 1200
+#pragma fp_contract(off)
+#endif
+#elif defined(__GNUC__) &&  !defined(__clang__)
+#pragma GCC optimize("fp-contract=off")
+#else
+#pragma STDC FP_CONTRACT OFF
+#endif
+#endif
+
+#ifdef _MSC_VER
+#define STBIR__UNUSED(v)  (void)(v)
+#else
+#define STBIR__UNUSED(v)  (void)sizeof(v)
+#endif
+
+#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
+
+
+#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
+#define STBIR_DEFAULT_FILTER_UPSAMPLE    STBIR_FILTER_CATMULLROM
+#endif
+
+#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
+#define STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL
+#endif
+
+
+#ifndef STBIR__HEADER_FILENAME
+#define STBIR__HEADER_FILENAME "stb_image_resize2.h"
+#endif
+
+// the internal pixel layout enums are in a different order, so we can easily do range comparisons of types
+//   the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible
+typedef enum
+{
+  STBIRI_1CHANNEL = 0,
+  STBIRI_2CHANNEL = 1,
+  STBIRI_RGB      = 2,
+  STBIRI_BGR      = 3,
+  STBIRI_4CHANNEL = 4,
+
+  STBIRI_RGBA = 5,
+  STBIRI_BGRA = 6,
+  STBIRI_ARGB = 7,
+  STBIRI_ABGR = 8,
+  STBIRI_RA   = 9,
+  STBIRI_AR   = 10,
+
+  STBIRI_RGBA_PM = 11,
+  STBIRI_BGRA_PM = 12,
+  STBIRI_ARGB_PM = 13,
+  STBIRI_ABGR_PM = 14,
+  STBIRI_RA_PM   = 15,
+  STBIRI_AR_PM   = 16,
+} stbir_internal_pixel_layout;
+
+// define the public pixel layouts to not compile inside the implementation (to avoid accidental use)
+#define STBIR_BGR bad_dont_use_in_implementation
+#define STBIR_1CHANNEL STBIR_BGR
+#define STBIR_2CHANNEL STBIR_BGR
+#define STBIR_RGB STBIR_BGR
+#define STBIR_RGBA STBIR_BGR
+#define STBIR_4CHANNEL STBIR_BGR
+#define STBIR_BGRA STBIR_BGR
+#define STBIR_ARGB STBIR_BGR
+#define STBIR_ABGR STBIR_BGR
+#define STBIR_RA STBIR_BGR
+#define STBIR_AR STBIR_BGR
+#define STBIR_RGBA_PM STBIR_BGR
+#define STBIR_BGRA_PM STBIR_BGR
+#define STBIR_ARGB_PM STBIR_BGR
+#define STBIR_ABGR_PM STBIR_BGR
+#define STBIR_RA_PM STBIR_BGR
+#define STBIR_AR_PM STBIR_BGR
+
+// must match stbir_datatype
+static unsigned char stbir__type_size[] = {
+  1,1,1,2,4,2 // STBIR_TYPE_UINT8,STBIR_TYPE_UINT8_SRGB,STBIR_TYPE_UINT8_SRGB_ALPHA,STBIR_TYPE_UINT16,STBIR_TYPE_FLOAT,STBIR_TYPE_HALF_FLOAT
+};
+
+// When gathering, the contributors are which source pixels contribute.
+// When scattering, the contributors are which destination pixels are contributed to.
+typedef struct
+{
+  int n0; // First contributing pixel
+  int n1; // Last contributing pixel
+} stbir__contributors;
+
+typedef struct
+{
+  int lowest;    // First sample index for whole filter
+  int highest;   // Last sample index for whole filter
+  int widest;    // widest single set of samples for an output
+} stbir__filter_extent_info;
+
+typedef struct
+{
+  int n0; // First pixel of decode buffer to write to
+  int n1; // Last pixel of decode that will be written to
+  int pixel_offset_for_input;  // Pixel offset into input_scanline
+} stbir__span;
+
+typedef struct stbir__scale_info
+{
+  int input_full_size;
+  int output_sub_size;
+  float scale;
+  float inv_scale;
+  float pixel_shift; // starting shift in output pixel space (in pixels)
+  int scale_is_rational;
+  stbir_uint32 scale_numerator, scale_denominator;
+} stbir__scale_info;
+
+typedef struct
+{
+  stbir__contributors * contributors;
+  float* coefficients;
+  stbir__contributors * gather_prescatter_contributors;
+  float * gather_prescatter_coefficients;
+  stbir__scale_info scale_info;
+  float support;
+  stbir_filter filter_enum;
+  stbir__kernel_callback * filter_kernel;
+  stbir__support_callback * filter_support;
+  stbir_edge edge;
+  int coefficient_width;
+  int filter_pixel_width;
+  int filter_pixel_margin;
+  int num_contributors;
+  int contributors_size;
+  int coefficients_size;
+  stbir__filter_extent_info extent_info;
+  int is_gather;  // 0 = scatter, 1 = gather with scale >= 1, 2 = gather with scale < 1
+  int gather_prescatter_num_contributors;
+  int gather_prescatter_coefficient_width;
+  int gather_prescatter_contributors_size;
+  int gather_prescatter_coefficients_size;
+} stbir__sampler;
+
+typedef struct
+{
+  stbir__contributors conservative;
+  int edge_sizes[2];    // this can be less than filter_pixel_margin, if the filter and scaling falls off
+  stbir__span spans[2]; // can be two spans, if doing input subrect with clamp mode WRAP
+} stbir__extents;
+
+typedef struct
+{
+#ifdef STBIR_PROFILE
+  union
+  {
+    struct { stbir_uint64 total, looping, vertical, horizontal, decode, encode, alpha, unalpha; } named;
+    stbir_uint64 array[8];
+  } profile;
+  stbir_uint64 * current_zone_excluded_ptr;
+#endif
+  float* decode_buffer;
+
+  int ring_buffer_first_scanline;
+  int ring_buffer_last_scanline;
+  int ring_buffer_begin_index;    // first_scanline is at this index in the ring buffer
+  int start_output_y, end_output_y;
+  int start_input_y, end_input_y;  // used in scatter only
+
+  #ifdef STBIR__SEPARATE_ALLOCATIONS
+    float** ring_buffers; // one pointer for each ring buffer
+  #else
+    float* ring_buffer;  // one big buffer that we index into
+  #endif
+
+  float* vertical_buffer;
+
+  char no_cache_straddle[64];
+} stbir__per_split_info;
+
+typedef void stbir__decode_pixels_func( float * decode, int width_times_channels, void const * input );
+typedef void stbir__alpha_weight_func( float * decode_buffer, int width_times_channels );
+typedef void stbir__horizontal_gather_channels_func( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer,
+  stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width );
+typedef void stbir__alpha_unweight_func(float * encode_buffer, int width_times_channels );
+typedef void stbir__encode_pixels_func( void * output, int width_times_channels, float const * encode );
+
+struct stbir__info
+{
+#ifdef STBIR_PROFILE
+  union
+  {
+    struct { stbir_uint64 total, build, alloc, horizontal, vertical, cleanup, pivot; } named;
+    stbir_uint64 array[7];
+  } profile;
+  stbir_uint64 * current_zone_excluded_ptr;
+#endif
+  stbir__sampler horizontal;
+  stbir__sampler vertical;
+
+  void const * input_data;
+  void * output_data;
+
+  int input_stride_bytes;
+  int output_stride_bytes;
+  int ring_buffer_length_bytes;   // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
+  int ring_buffer_num_entries;    // Total number of entries in the ring buffer.
+
+  stbir_datatype input_type;
+  stbir_datatype output_type;
+
+  stbir_input_callback * in_pixels_cb;
+  void * user_data;
+  stbir_output_callback * out_pixels_cb;
+
+  stbir__extents scanline_extents;
+
+  void * alloced_mem;
+  stbir__per_split_info * split_info;  // by default 1, but there will be N of these allocated based on the thread init you did
+
+  stbir__decode_pixels_func * decode_pixels;
+  stbir__alpha_weight_func * alpha_weight;
+  stbir__horizontal_gather_channels_func * horizontal_gather_channels;
+  stbir__alpha_unweight_func * alpha_unweight;
+  stbir__encode_pixels_func * encode_pixels;
+
+  int alloced_total;
+  int splits; // count of splits
+
+  stbir_internal_pixel_layout input_pixel_layout_internal;
+  stbir_internal_pixel_layout output_pixel_layout_internal;
+
+  int input_color_and_type;
+  int offset_x, offset_y; // offset within output_data
+  int vertical_first;
+  int channels;
+  int effective_channels; // same as channels, except on RGBA/ARGB (7), or XA/AX (3)
+  int alloc_ring_buffer_num_entries;    // Number of entries in the ring buffer that will be allocated
+};
+
+
+#define stbir__max_uint8_as_float             255.0f
+#define stbir__max_uint16_as_float            65535.0f
+#define stbir__max_uint8_as_float_inverted    (1.0f/255.0f)
+#define stbir__max_uint16_as_float_inverted   (1.0f/65535.0f)
+#define stbir__small_float ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
+
+// min/max friendly
+#define STBIR_CLAMP(x, xmin, xmax) do { \
+  if ( (x) < (xmin) ) (x) = (xmin);     \
+  if ( (x) > (xmax) ) (x) = (xmax);     \
+} while (0)
+
+static stbir__inline int stbir__min(int a, int b)
+{
+  return a < b ? a : b;
+}
+
+static stbir__inline int stbir__max(int a, int b)
+{
+  return a > b ? a : b;
+}
+
+static float stbir__srgb_uchar_to_linear_float[256] = {
+  0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
+  0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
+  0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
+  0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
+  0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
+  0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
+  0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
+  0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
+  0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
+  0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
+  0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
+  0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
+  0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
+  0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
+  0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
+  0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
+  0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
+  0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
+  0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
+  0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
+  0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
+  0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
+  0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
+  0.982251f, 0.991102f, 1.0f
+};
+
+typedef union
+{
+  unsigned int u;
+  float f;
+} stbir__FP32;
+
+// From https://gist.github.com/rygorous/2203834
+
+static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
+  0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
+  0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
+  0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
+  0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
+  0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
+  0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
+  0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
+  0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
+  0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
+  0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
+  0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
+  0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
+  0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
+};
+
+static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
+{
+  static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
+  static const stbir__FP32 minval = { (127-13) << 23 };
+  stbir_uint32 tab,bias,scale,t;
+  stbir__FP32 f;
+
+  // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
+  // The tests are carefully written so that NaNs map to 0, same as in the reference
+  // implementation.
+  if (!(in > minval.f)) // written this way to catch NaNs
+      return 0;
+  if (in > almostone.f)
+      return 255;
+
+  // Do the table lookup and unpack bias, scale
+  f.f = in;
+  tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
+  bias = (tab >> 16) << 9;
+  scale = tab & 0xffff;
+
+  // Grab next-highest mantissa bits and perform linear interpolation
+  t = (f.u >> 12) & 0xff;
+  return (unsigned char) ((bias + scale*t) >> 16);
+}
+
+#ifndef STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT
+#define STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT 32 // when downsampling and <= 32 scanlines of buffering, use gather. gather used down to 1/8th scaling for 25% win.
+#endif
+
+#ifndef STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS
+#define STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS 4 // when threading, what is the minimum number of scanlines for a split?
+#endif
+
+// restrict pointers for the output pointers
+#if defined( _MSC_VER ) && !defined(__clang__)
+  #define STBIR_STREAMOUT_PTR( star ) star __restrict
+  #define STBIR_NO_UNROLL( ptr ) __assume(ptr) // this oddly keeps msvc from unrolling a loop
+#elif defined(  __clang__ )
+  #define STBIR_STREAMOUT_PTR( star ) star __restrict__
+  #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr))
+#elif defined(  __GNUC__ )
+  #define STBIR_STREAMOUT_PTR( star ) star __restrict__
+  #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr))
+#else
+  #define STBIR_STREAMOUT_PTR( star ) star
+  #define STBIR_NO_UNROLL( ptr )
+#endif
+
+#ifdef STBIR_NO_SIMD // force simd off for whatever reason
+
+// force simd off overrides everything else, so clear it all
+
+#ifdef STBIR_SSE2
+#undef STBIR_SSE2
+#endif
+
+#ifdef STBIR_AVX
+#undef STBIR_AVX
+#endif
+
+#ifdef STBIR_NEON
+#undef STBIR_NEON
+#endif
+
+#ifdef STBIR_AVX2
+#undef STBIR_AVX2
+#endif
+
+#ifdef STBIR_FP16C
+#undef STBIR_FP16C
+#endif
+
+#ifdef STBIR_WASM
+#undef STBIR_WASM
+#endif
+
+#ifdef STBIR_SIMD
+#undef STBIR_SIMD
+#endif
+
+#else // STBIR_SIMD
+
+#ifdef STBIR_SSE2
+  #include <emmintrin.h>
+
+  #define stbir__simdf __m128
+  #define stbir__simdi __m128i
+
+  #define stbir_simdi_castf( reg ) _mm_castps_si128(reg)
+  #define stbir_simdf_casti( reg ) _mm_castsi128_ps(reg)
+
+  #define stbir__simdf_load( reg, ptr ) (reg) = _mm_loadu_ps( (float const*)(ptr) )
+  #define stbir__simdi_load( reg, ptr ) (reg) = _mm_loadu_si128 ( (stbir__simdi const*)(ptr) )
+  #define stbir__simdf_load1( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) )  // top values can be random (not denormal or nan for perf)
+  #define stbir__simdi_load1( out, ptr ) (out) = _mm_castps_si128( _mm_load_ss( (float const*)(ptr) ))
+  #define stbir__simdf_load1z( out, ptr ) (out) = _mm_load_ss( (float const*)(ptr) )  // top values must be zero
+  #define stbir__simdf_frep4( fvar ) _mm_set_ps1( fvar )
+  #define stbir__simdf_load1frep4( out, fvar ) (out) = _mm_set_ps1( fvar )
+  #define stbir__simdf_load2( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values can be random (not denormal or nan for perf)
+  #define stbir__simdf_load2z( out, ptr ) (out) = _mm_castsi128_ps( _mm_loadl_epi64( (__m128i*)(ptr)) ) // top values must be zero
+  #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = _mm_castpd_ps(_mm_loadh_pd( _mm_castps_pd(reg), (double*)(ptr) ))
+
+  #define stbir__simdf_zeroP() _mm_setzero_ps()
+  #define stbir__simdf_zero( reg ) (reg) = _mm_setzero_ps()
+
+  #define stbir__simdf_store( ptr, reg )  _mm_storeu_ps( (float*)(ptr), reg )
+  #define stbir__simdf_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), reg )
+  #define stbir__simdf_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), _mm_castps_si128(reg) )
+  #define stbir__simdf_store2h( ptr, reg ) _mm_storeh_pd( (double*)(ptr), _mm_castps_pd(reg) )
+
+  #define stbir__simdi_store( ptr, reg )  _mm_storeu_si128( (__m128i*)(ptr), reg )
+  #define stbir__simdi_store1( ptr, reg ) _mm_store_ss( (float*)(ptr), _mm_castsi128_ps(reg) )
+  #define stbir__simdi_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), (reg) )
+
+  #define stbir__prefetch( ptr ) _mm_prefetch((char*)(ptr), _MM_HINT_T0 )
+
+  #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \
+  { \
+    stbir__simdi zero = _mm_setzero_si128(); \
+    out2 = _mm_unpacklo_epi8( ireg, zero ); \
+    out3 = _mm_unpackhi_epi8( ireg, zero ); \
+    out0 = _mm_unpacklo_epi16( out2, zero ); \
+    out1 = _mm_unpackhi_epi16( out2, zero ); \
+    out2 = _mm_unpacklo_epi16( out3, zero ); \
+    out3 = _mm_unpackhi_epi16( out3, zero ); \
+  }
+
+#define stbir__simdi_expand_u8_to_1u32(out,ireg) \
+  { \
+    stbir__simdi zero = _mm_setzero_si128(); \
+    out = _mm_unpacklo_epi8( ireg, zero ); \
+    out = _mm_unpacklo_epi16( out, zero ); \
+  }
+
+  #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \
+  { \
+    stbir__simdi zero = _mm_setzero_si128(); \
+    out0 = _mm_unpacklo_epi16( ireg, zero ); \
+    out1 = _mm_unpackhi_epi16( ireg, zero ); \
+  }
+
+  #define stbir__simdf_convert_float_to_i32( i, f ) (i) = _mm_cvttps_epi32(f)
+  #define stbir__simdf_convert_float_to_int( f ) _mm_cvtt_ss2si(f)
+  #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),_mm_setzero_ps()))))
+  #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps()))))
+
+  #define stbir__simdi_to_int( i ) _mm_cvtsi128_si32(i)
+  #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = _mm_cvtepi32_ps( ireg )
+  #define stbir__simdf_add( out, reg0, reg1 ) (out) = _mm_add_ps( reg0, reg1 )
+  #define stbir__simdf_mult( out, reg0, reg1 ) (out) = _mm_mul_ps( reg0, reg1 )
+  #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = _mm_mul_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) )
+  #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = _mm_mul_ss( reg, _mm_load_ss( (float const*)(ptr) ) )
+  #define stbir__simdf_add_mem( out, reg, ptr ) (out) = _mm_add_ps( reg, _mm_loadu_ps( (float const*)(ptr) ) )
+  #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = _mm_add_ss( reg, _mm_load_ss( (float const*)(ptr) ) )
+
+  #ifdef STBIR_USE_FMA           // not on by default to maintain bit identical simd to non-simd
+  #include <immintrin.h>
+  #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_fmadd_ps( mul1, mul2, add )
+  #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_fmadd_ss( mul1, mul2, add )
+  #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ps( mul, _mm_loadu_ps( (float const*)(ptr) ), add )
+  #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_fmadd_ss( mul, _mm_load_ss( (float const*)(ptr) ), add )
+  #else
+  #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = _mm_add_ps( add, _mm_mul_ps( mul1, mul2 ) )
+  #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = _mm_add_ss( add, _mm_mul_ss( mul1, mul2 ) )
+  #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = _mm_add_ps( add, _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ) )
+  #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = _mm_add_ss( add, _mm_mul_ss( mul, _mm_load_ss( (float const*)(ptr) ) ) )
+  #endif
+
+  #define stbir__simdf_add1( out, reg0, reg1 ) (out) = _mm_add_ss( reg0, reg1 )
+  #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = _mm_mul_ss( reg0, reg1 )
+
+  #define stbir__simdf_and( out, reg0, reg1 ) (out) = _mm_and_ps( reg0, reg1 )
+  #define stbir__simdf_or( out, reg0, reg1 ) (out) = _mm_or_ps( reg0, reg1 )
+
+  #define stbir__simdf_min( out, reg0, reg1 ) (out) = _mm_min_ps( reg0, reg1 )
+  #define stbir__simdf_max( out, reg0, reg1 ) (out) = _mm_max_ps( reg0, reg1 )
+  #define stbir__simdf_min1( out, reg0, reg1 ) (out) = _mm_min_ss( reg0, reg1 )
+  #define stbir__simdf_max1( out, reg0, reg1 ) (out) = _mm_max_ss( reg0, reg1 )
+
+  #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (3<<0) + (0<<2) + (1<<4) + (2<<6) ) )
+  #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_shuffle_ps( reg1,reg0, (0<<0) + (1<<2) + (2<<4) + (3<<6) )), (2<<0) + (3<<2) + (0<<4) + (1<<6) ) )
+
+  static const stbir__simdf STBIR_zeroones = { 0.0f,1.0f,0.0f,1.0f };
+  static const stbir__simdf STBIR_onezeros = { 1.0f,0.0f,1.0f,0.0f };
+  #define stbir__simdf_aaa1( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movehl_ps( ones, alp ) ), (1<<0) + (1<<2) + (1<<4) + (2<<6) ) )
+  #define stbir__simdf_1aaa( out, alp, ones ) (out)=_mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( _mm_movelh_ps( ones, alp ) ), (0<<0) + (2<<2) + (2<<4) + (2<<6) ) )
+  #define stbir__simdf_a1a1( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_srli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_zeroones )
+  #define stbir__simdf_1a1a( out, alp, ones) (out) = _mm_or_ps( _mm_castsi128_ps( _mm_slli_epi64( _mm_castps_si128(alp), 32 ) ), STBIR_onezeros )
+
+  #define stbir__simdf_swiz( reg, one, two, three, four ) _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( reg ), (one<<0) + (two<<2) + (three<<4) + (four<<6) ) )
+
+  #define stbir__simdi_and( out, reg0, reg1 ) (out) = _mm_and_si128( reg0, reg1 )
+  #define stbir__simdi_or( out, reg0, reg1 ) (out) = _mm_or_si128( reg0, reg1 )
+  #define stbir__simdi_16madd( out, reg0, reg1 ) (out) = _mm_madd_epi16( reg0, reg1 )
+
+  #define stbir__simdf_pack_to_8bytes(out,aa,bb) \
+  { \
+    stbir__simdf af,bf; \
+    stbir__simdi a,b; \
+    af = _mm_min_ps( aa, STBIR_max_uint8_as_float ); \
+    bf = _mm_min_ps( bb, STBIR_max_uint8_as_float ); \
+    af = _mm_max_ps( af, _mm_setzero_ps() ); \
+    bf = _mm_max_ps( bf, _mm_setzero_ps() ); \
+    a = _mm_cvttps_epi32( af ); \
+    b = _mm_cvttps_epi32( bf ); \
+    a = _mm_packs_epi32( a, b ); \
+    out = _mm_packus_epi16( a, a ); \
+  }
+
+  #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \
+      stbir__simdf_load( o0, (ptr) );    \
+      stbir__simdf_load( o1, (ptr)+4 );  \
+      stbir__simdf_load( o2, (ptr)+8 );  \
+      stbir__simdf_load( o3, (ptr)+12 ); \
+      {                                  \
+        __m128 tmp0, tmp1, tmp2, tmp3;   \
+        tmp0 = _mm_unpacklo_ps(o0, o1);  \
+        tmp2 = _mm_unpacklo_ps(o2, o3);  \
+        tmp1 = _mm_unpackhi_ps(o0, o1);  \
+        tmp3 = _mm_unpackhi_ps(o2, o3);  \
+        o0 = _mm_movelh_ps(tmp0, tmp2);  \
+        o1 = _mm_movehl_ps(tmp2, tmp0);  \
+        o2 = _mm_movelh_ps(tmp1, tmp3);  \
+        o3 = _mm_movehl_ps(tmp3, tmp1);  \
+      }
+
+  #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \
+      r0 = _mm_packs_epi32( r0, r1 ); \
+      r2 = _mm_packs_epi32( r2, r3 ); \
+      r1 = _mm_unpacklo_epi16( r0, r2 ); \
+      r3 = _mm_unpackhi_epi16( r0, r2 ); \
+      r0 = _mm_unpacklo_epi16( r1, r3 ); \
+      r2 = _mm_unpackhi_epi16( r1, r3 ); \
+      r0 = _mm_packus_epi16( r0, r2 ); \
+      stbir__simdi_store( ptr, r0 ); \
+
+  #define stbir__simdi_32shr( out, reg, imm ) out = _mm_srli_epi32( reg, imm )
+
+  #if defined(_MSC_VER) && !defined(__clang__)
+    // msvc inits with 8 bytes
+    #define STBIR__CONST_32_TO_8( v ) (char)(unsigned char)((v)&255),(char)(unsigned char)(((v)>>8)&255),(char)(unsigned char)(((v)>>16)&255),(char)(unsigned char)(((v)>>24)&255)
+    #define STBIR__CONST_4_32i( v ) STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v ), STBIR__CONST_32_TO_8( v )
+    #define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) STBIR__CONST_32_TO_8( v0 ), STBIR__CONST_32_TO_8( v1 ), STBIR__CONST_32_TO_8( v2 ), STBIR__CONST_32_TO_8( v3 )
+  #else
+    // everything else inits with long long's
+    #define STBIR__CONST_4_32i( v ) (long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v))),(long long)((((stbir_uint64)(stbir_uint32)(v))<<32)|((stbir_uint64)(stbir_uint32)(v)))
+    #define STBIR__CONST_4d_32i( v0, v1, v2, v3 ) (long long)((((stbir_uint64)(stbir_uint32)(v1))<<32)|((stbir_uint64)(stbir_uint32)(v0))),(long long)((((stbir_uint64)(stbir_uint32)(v3))<<32)|((stbir_uint64)(stbir_uint32)(v2)))
+  #endif
+
+  #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x }
+  #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { STBIR__CONST_4_32i(x) }
+  #define STBIR__CONSTF(var) (var)
+  #define STBIR__CONSTI(var) (var)
+
+  #if defined(STBIR_AVX) || defined(__SSE4_1__)
+    #include <smmintrin.h>
+    #define stbir__simdf_pack_to_8words(out,reg0,reg1) out = _mm_packus_epi32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())), _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())))
+  #else
+    STBIR__SIMDI_CONST(stbir__s32_32768, 32768);
+    STBIR__SIMDI_CONST(stbir__s16_32768, ((32768<<16)|32768));
+
+    #define stbir__simdf_pack_to_8words(out,reg0,reg1) \
+      { \
+        stbir__simdi tmp0,tmp1; \
+        tmp0 = _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg0,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())); \
+        tmp1 = _mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(reg1,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())); \
+        tmp0 = _mm_sub_epi32( tmp0, stbir__s32_32768 ); \
+        tmp1 = _mm_sub_epi32( tmp1, stbir__s32_32768 ); \
+        out = _mm_packs_epi32( tmp0, tmp1 ); \
+        out = _mm_sub_epi16( out, stbir__s16_32768 ); \
+      }
+
+  #endif
+
+  #define STBIR_SIMD
+
+  // if we detect AVX, set the simd8 defines
+  #ifdef STBIR_AVX
+    #include <immintrin.h>
+    #define STBIR_SIMD8
+    #define stbir__simdf8 __m256
+    #define stbir__simdi8 __m256i
+    #define stbir__simdf8_load( out, ptr ) (out) = _mm256_loadu_ps( (float const *)(ptr) )
+    #define stbir__simdi8_load( out, ptr ) (out) = _mm256_loadu_si256( (__m256i const *)(ptr) )
+    #define stbir__simdf8_mult( out, a, b ) (out) = _mm256_mul_ps( (a), (b) )
+    #define stbir__simdf8_store( ptr, out ) _mm256_storeu_ps( (float*)(ptr), out )
+    #define stbir__simdi8_store( ptr, reg )  _mm256_storeu_si256( (__m256i*)(ptr), reg )
+    #define stbir__simdf8_frep8( fval ) _mm256_set1_ps( fval )
+
+    #define stbir__simdf8_min( out, reg0, reg1 ) (out) = _mm256_min_ps( reg0, reg1 )
+    #define stbir__simdf8_max( out, reg0, reg1 ) (out) = _mm256_max_ps( reg0, reg1 )
+
+    #define stbir__simdf8_add4halves( out, bot4, top8 ) (out) = _mm_add_ps( bot4, _mm256_extractf128_ps( top8, 1 ) )
+    #define stbir__simdf8_mult_mem( out, reg, ptr ) (out) = _mm256_mul_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) )
+    #define stbir__simdf8_add_mem( out, reg, ptr ) (out) = _mm256_add_ps( reg, _mm256_loadu_ps( (float const*)(ptr) ) )
+    #define stbir__simdf8_add( out, a, b ) (out) = _mm256_add_ps( a, b )
+    #define stbir__simdf8_load1b( out, ptr ) (out) = _mm256_broadcast_ss( ptr )
+    #define stbir__simdf_load1rep4( out, ptr ) (out) = _mm_broadcast_ss( ptr )  // avx load instruction
+
+    #define stbir__simdi8_convert_i32_to_float(out, ireg) (out) = _mm256_cvtepi32_ps( ireg )
+    #define stbir__simdf8_convert_float_to_i32( i, f ) (i) = _mm256_cvttps_epi32(f)
+
+    #define stbir__simdf8_bot4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (0<<0)+(2<<4) )
+    #define stbir__simdf8_top4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (1<<0)+(3<<4) )
+
+    #define stbir__simdf8_gettop4( reg ) _mm256_extractf128_ps(reg,1)
+
+    #ifdef STBIR_AVX2
+
+    #define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \
+    { \
+      stbir__simdi8 a, zero  =_mm256_setzero_si256();\
+      a = _mm256_permute4x64_epi64( _mm256_unpacklo_epi8( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), zero ),(0<<0)+(2<<2)+(1<<4)+(3<<6)); \
+      out0 = _mm256_unpacklo_epi16( a, zero ); \
+      out1 = _mm256_unpackhi_epi16( a, zero ); \
+    }
+
+    #define stbir__simdf8_pack_to_16bytes(out,aa,bb) \
+    { \
+      stbir__simdi8 t; \
+      stbir__simdf8 af,bf; \
+      stbir__simdi8 a,b; \
+      af = _mm256_min_ps( aa, STBIR_max_uint8_as_floatX ); \
+      bf = _mm256_min_ps( bb, STBIR_max_uint8_as_floatX ); \
+      af = _mm256_max_ps( af, _mm256_setzero_ps() ); \
+      bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \
+      a = _mm256_cvttps_epi32( af ); \
+      b = _mm256_cvttps_epi32( bf ); \
+      t = _mm256_permute4x64_epi64( _mm256_packs_epi32( a, b ), (0<<0)+(2<<2)+(1<<4)+(3<<6) ); \
+      out = _mm256_castsi256_si128( _mm256_permute4x64_epi64( _mm256_packus_epi16( t, t ), (0<<0)+(2<<2)+(1<<4)+(3<<6) ) ); \
+    }
+
+    #define stbir__simdi8_expand_u16_to_u32(out,ireg) out = _mm256_unpacklo_epi16( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), _mm256_setzero_si256() );
+
+    #define stbir__simdf8_pack_to_16words(out,aa,bb) \
+      { \
+        stbir__simdf8 af,bf; \
+        stbir__simdi8 a,b; \
+        af = _mm256_min_ps( aa, STBIR_max_uint16_as_floatX ); \
+        bf = _mm256_min_ps( bb, STBIR_max_uint16_as_floatX ); \
+        af = _mm256_max_ps( af, _mm256_setzero_ps() ); \
+        bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \
+        a = _mm256_cvttps_epi32( af ); \
+        b = _mm256_cvttps_epi32( bf ); \
+        (out) = _mm256_permute4x64_epi64( _mm256_packus_epi32(a, b), (0<<0)+(2<<2)+(1<<4)+(3<<6) ); \
+      }
+
+    #else
+
+    #define stbir__simdi8_expand_u8_to_u32(out0,out1,ireg) \
+    { \
+      stbir__simdi a,zero = _mm_setzero_si128(); \
+      a = _mm_unpacklo_epi8( ireg, zero ); \
+      out0 = _mm256_setr_m128i( _mm_unpacklo_epi16( a, zero ), _mm_unpackhi_epi16( a, zero ) ); \
+      a = _mm_unpackhi_epi8( ireg, zero ); \
+      out1 = _mm256_setr_m128i( _mm_unpacklo_epi16( a, zero ), _mm_unpackhi_epi16( a, zero ) ); \
+    }
+
+    #define stbir__simdf8_pack_to_16bytes(out,aa,bb) \
+    { \
+      stbir__simdi t; \
+      stbir__simdf8 af,bf; \
+      stbir__simdi8 a,b; \
+      af = _mm256_min_ps( aa, STBIR_max_uint8_as_floatX ); \
+      bf = _mm256_min_ps( bb, STBIR_max_uint8_as_floatX ); \
+      af = _mm256_max_ps( af, _mm256_setzero_ps() ); \
+      bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \
+      a = _mm256_cvttps_epi32( af ); \
+      b = _mm256_cvttps_epi32( bf ); \
+      out = _mm_packs_epi32( _mm256_castsi256_si128(a), _mm256_extractf128_si256( a, 1 ) ); \
+      out = _mm_packus_epi16( out, out ); \
+      t = _mm_packs_epi32( _mm256_castsi256_si128(b), _mm256_extractf128_si256( b, 1 ) ); \
+      t = _mm_packus_epi16( t, t ); \
+      out = _mm_castps_si128( _mm_shuffle_ps( _mm_castsi128_ps(out), _mm_castsi128_ps(t), (0<<0)+(1<<2)+(0<<4)+(1<<6) ) ); \
+    }
+
+    #define stbir__simdi8_expand_u16_to_u32(out,ireg) \
+    { \
+      stbir__simdi a,b,zero = _mm_setzero_si128(); \
+      a = _mm_unpacklo_epi16( ireg, zero ); \
+      b = _mm_unpackhi_epi16( ireg, zero ); \
+      out = _mm256_insertf128_si256( _mm256_castsi128_si256( a ), b, 1 ); \
+    }
+
+    #define stbir__simdf8_pack_to_16words(out,aa,bb) \
+      { \
+        stbir__simdi t0,t1; \
+        stbir__simdf8 af,bf; \
+        stbir__simdi8 a,b; \
+        af = _mm256_min_ps( aa, STBIR_max_uint16_as_floatX ); \
+        bf = _mm256_min_ps( bb, STBIR_max_uint16_as_floatX ); \
+        af = _mm256_max_ps( af, _mm256_setzero_ps() ); \
+        bf = _mm256_max_ps( bf, _mm256_setzero_ps() ); \
+        a = _mm256_cvttps_epi32( af ); \
+        b = _mm256_cvttps_epi32( bf ); \
+        t0 = _mm_packus_epi32( _mm256_castsi256_si128(a), _mm256_extractf128_si256( a, 1 ) ); \
+        t1 = _mm_packus_epi32( _mm256_castsi256_si128(b), _mm256_extractf128_si256( b, 1 ) ); \
+        out = _mm256_setr_m128i( t0, t1 ); \
+      }
+
+    #endif
+
+    static __m256i stbir_00001111 = { STBIR__CONST_4d_32i( 0, 0, 0, 0 ), STBIR__CONST_4d_32i( 1, 1, 1, 1 ) };
+    #define stbir__simdf8_0123to00001111( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00001111 )
+
+    static __m256i stbir_22223333 = { STBIR__CONST_4d_32i( 2, 2, 2, 2 ), STBIR__CONST_4d_32i( 3, 3, 3, 3 ) };
+    #define stbir__simdf8_0123to22223333( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_22223333 )
+
+    #define stbir__simdf8_0123to2222( out, in ) (out) = stbir__simdf_swiz(_mm256_castps256_ps128(in), 2,2,2,2 )
+
+    #define stbir__simdf8_load4b( out, ptr ) (out) = _mm256_broadcast_ps( (__m128 const *)(ptr) )
+
+    static __m256i stbir_00112233 = { STBIR__CONST_4d_32i( 0, 0, 1, 1 ), STBIR__CONST_4d_32i( 2, 2, 3, 3 ) };
+    #define stbir__simdf8_0123to00112233( out, in ) (out) = _mm256_permutevar_ps ( in, stbir_00112233 )
+    #define stbir__simdf8_add4( out, a8, b ) (out) = _mm256_add_ps( a8,  _mm256_castps128_ps256( b ) )
+
+    static __m256i stbir_load6 = { STBIR__CONST_4_32i( 0x80000000 ), STBIR__CONST_4d_32i(  0x80000000,  0x80000000, 0, 0 ) };
+    #define stbir__simdf8_load6z( out, ptr ) (out) = _mm256_maskload_ps( ptr, stbir_load6 )
+
+    #define stbir__simdf8_0123to00000000( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(0<<4)+(0<<6) )
+    #define stbir__simdf8_0123to11111111( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(1<<4)+(1<<6) )
+    #define stbir__simdf8_0123to22222222( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (2<<0)+(2<<2)+(2<<4)+(2<<6) )
+    #define stbir__simdf8_0123to33333333( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (3<<0)+(3<<2)+(3<<4)+(3<<6) )
+    #define stbir__simdf8_0123to21032103( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (2<<0)+(1<<2)+(0<<4)+(3<<6) )
+    #define stbir__simdf8_0123to32103210( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (3<<0)+(2<<2)+(1<<4)+(0<<6) )
+    #define stbir__simdf8_0123to12301230( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (1<<0)+(2<<2)+(3<<4)+(0<<6) )
+    #define stbir__simdf8_0123to10321032( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (1<<0)+(0<<2)+(3<<4)+(2<<6) )
+    #define stbir__simdf8_0123to30123012( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (3<<0)+(0<<2)+(1<<4)+(2<<6) )
+
+    #define stbir__simdf8_0123to11331133( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (1<<0)+(1<<2)+(3<<4)+(3<<6) )
+    #define stbir__simdf8_0123to00220022( out, in ) (out) =  _mm256_shuffle_ps ( in, in, (0<<0)+(0<<2)+(2<<4)+(2<<6) )
+
+    #define stbir__simdf8_aaa1( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(1<<1)+(1<<2)+(0<<3)+(1<<4)+(1<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (3<<0) + (3<<2) + (3<<4) + (0<<6) )
+    #define stbir__simdf8_1aaa( out, alp, ones ) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(1<<2)+(1<<3)+(0<<4)+(1<<5)+(1<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (0<<4) + (0<<6) )
+    #define stbir__simdf8_a1a1( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (1<<0)+(0<<1)+(1<<2)+(0<<3)+(1<<4)+(0<<5)+(1<<6)+(0<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) )
+    #define stbir__simdf8_1a1a( out, alp, ones) (out) = _mm256_blend_ps( alp, ones, (0<<0)+(1<<1)+(0<<2)+(1<<3)+(0<<4)+(1<<5)+(0<<6)+(1<<7)); (out)=_mm256_shuffle_ps( out,out, (1<<0) + (0<<2) + (3<<4) + (2<<6) )
+
+    #define stbir__simdf8_zero( reg ) (reg) = _mm256_setzero_ps()
+
+    #ifdef STBIR_USE_FMA           // not on by default to maintain bit identical simd to non-simd
+    #define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_fmadd_ps( mul1, mul2, add )
+    #define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_fmadd_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ), add )
+    #define stbir__simdf8_madd_mem4( out, add, mul, ptr )(out) = _mm256_fmadd_ps( _mm256_setr_m128( mul, _mm_setzero_ps() ), _mm256_setr_m128( _mm_loadu_ps( (float const*)(ptr) ), _mm_setzero_ps() ), add )
+    #else
+    #define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul1, mul2 ) )
+    #define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ) ) )
+    #define stbir__simdf8_madd_mem4( out, add, mul, ptr )  (out) = _mm256_add_ps( add, _mm256_setr_m128( _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ), _mm_setzero_ps() ) )
+    #endif
+    #define stbir__if_simdf8_cast_to_simdf4( val ) _mm256_castps256_ps128( val )
+
+  #endif
+
+  #ifdef STBIR_FLOORF
+  #undef STBIR_FLOORF
+  #endif
+  #define STBIR_FLOORF stbir_simd_floorf
+  static stbir__inline float stbir_simd_floorf(float x)  // martins floorf
+  {
+    #if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41)
+    __m128 t = _mm_set_ss(x);
+    return _mm_cvtss_f32( _mm_floor_ss(t, t) );
+    #else
+    __m128 f = _mm_set_ss(x);
+    __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f));
+    __m128 r = _mm_add_ss(t, _mm_and_ps(_mm_cmplt_ss(f, t), _mm_set_ss(-1.0f)));
+    return _mm_cvtss_f32(r);
+    #endif
+  }
+
+  #ifdef STBIR_CEILF
+  #undef STBIR_CEILF
+  #endif
+  #define STBIR_CEILF stbir_simd_ceilf
+  static stbir__inline float stbir_simd_ceilf(float x)  // martins ceilf
+  {
+    #if defined(STBIR_AVX) || defined(__SSE4_1__) || defined(STBIR_SSE41)
+    __m128 t = _mm_set_ss(x);
+    return _mm_cvtss_f32( _mm_ceil_ss(t, t) );
+    #else
+    __m128 f = _mm_set_ss(x);
+    __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f));
+    __m128 r = _mm_add_ss(t, _mm_and_ps(_mm_cmplt_ss(t, f), _mm_set_ss(1.0f)));
+    return _mm_cvtss_f32(r);
+    #endif
+  }
+
+#elif defined(STBIR_NEON)
+
+  #include <arm_neon.h>
+
+  #define stbir__simdf float32x4_t
+  #define stbir__simdi uint32x4_t
+
+  #define stbir_simdi_castf( reg ) vreinterpretq_u32_f32(reg)
+  #define stbir_simdf_casti( reg ) vreinterpretq_f32_u32(reg)
+
+  #define stbir__simdf_load( reg, ptr ) (reg) = vld1q_f32( (float const*)(ptr) )
+  #define stbir__simdi_load( reg, ptr ) (reg) = vld1q_u32( (uint32_t const*)(ptr) )
+  #define stbir__simdf_load1( out, ptr ) (out) = vld1q_dup_f32( (float const*)(ptr) ) // top values can be random (not denormal or nan for perf)
+  #define stbir__simdi_load1( out, ptr ) (out) = vld1q_dup_u32( (uint32_t const*)(ptr) )
+  #define stbir__simdf_load1z( out, ptr ) (out) = vld1q_lane_f32( (float const*)(ptr), vdupq_n_f32(0), 0 ) // top values must be zero
+  #define stbir__simdf_frep4( fvar ) vdupq_n_f32( fvar )
+  #define stbir__simdf_load1frep4( out, fvar ) (out) = vdupq_n_f32( fvar )
+  #define stbir__simdf_load2( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) ) // top values can be random (not denormal or nan for perf)
+  #define stbir__simdf_load2z( out, ptr ) (out) = vcombine_f32( vld1_f32( (float const*)(ptr) ), vcreate_f32(0) )  // top values must be zero
+  #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = vcombine_f32( vget_low_f32(reg), vld1_f32( (float const*)(ptr) ) )
+
+  #define stbir__simdf_zeroP() vdupq_n_f32(0)
+  #define stbir__simdf_zero( reg ) (reg) = vdupq_n_f32(0)
+
+  #define stbir__simdf_store( ptr, reg )  vst1q_f32( (float*)(ptr), reg )
+  #define stbir__simdf_store1( ptr, reg ) vst1q_lane_f32( (float*)(ptr), reg, 0)
+  #define stbir__simdf_store2( ptr, reg ) vst1_f32( (float*)(ptr), vget_low_f32(reg) )
+  #define stbir__simdf_store2h( ptr, reg ) vst1_f32( (float*)(ptr), vget_high_f32(reg) )
+
+  #define stbir__simdi_store( ptr, reg )  vst1q_u32( (uint32_t*)(ptr), reg )
+  #define stbir__simdi_store1( ptr, reg ) vst1q_lane_u32( (uint32_t*)(ptr), reg, 0 )
+  #define stbir__simdi_store2( ptr, reg ) vst1_u32( (uint32_t*)(ptr), vget_low_u32(reg) )
+
+  #define stbir__prefetch( ptr )
+
+  #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \
+  { \
+    uint16x8_t l = vmovl_u8( vget_low_u8 ( vreinterpretq_u8_u32(ireg) ) ); \
+    uint16x8_t h = vmovl_u8( vget_high_u8( vreinterpretq_u8_u32(ireg) ) ); \
+    out0 = vmovl_u16( vget_low_u16 ( l ) ); \
+    out1 = vmovl_u16( vget_high_u16( l ) ); \
+    out2 = vmovl_u16( vget_low_u16 ( h ) ); \
+    out3 = vmovl_u16( vget_high_u16( h ) ); \
+  }
+
+  #define stbir__simdi_expand_u8_to_1u32(out,ireg) \
+  { \
+    uint16x8_t tmp = vmovl_u8( vget_low_u8( vreinterpretq_u8_u32(ireg) ) ); \
+    out = vmovl_u16( vget_low_u16( tmp ) ); \
+  }
+
+  #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \
+  { \
+    uint16x8_t tmp = vreinterpretq_u16_u32(ireg); \
+    out0 = vmovl_u16( vget_low_u16 ( tmp ) ); \
+    out1 = vmovl_u16( vget_high_u16( tmp ) ); \
+  }
+
+  #define stbir__simdf_convert_float_to_i32( i, f ) (i) = vreinterpretq_u32_s32( vcvtq_s32_f32(f) )
+  #define stbir__simdf_convert_float_to_int( f ) vgetq_lane_s32(vcvtq_s32_f32(f), 0)
+  #define stbir__simdi_to_int( i ) (int)vgetq_lane_u32(i, 0)
+  #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),vdupq_n_f32(0))), 0))
+  #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),vdupq_n_f32(0))), 0))
+  #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = vcvtq_f32_s32( vreinterpretq_s32_u32(ireg) )
+  #define stbir__simdf_add( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 )
+  #define stbir__simdf_mult( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 )
+  #define stbir__simdf_mult_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_f32( (float const*)(ptr) ) )
+  #define stbir__simdf_mult1_mem( out, reg, ptr ) (out) = vmulq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) )
+  #define stbir__simdf_add_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_f32( (float const*)(ptr) ) )
+  #define stbir__simdf_add1_mem( out, reg, ptr ) (out) = vaddq_f32( reg, vld1q_dup_f32( (float const*)(ptr) ) )
+
+  #ifdef STBIR_USE_FMA           // not on by default to maintain bit identical simd to non-simd (and also x64 no madd to arm madd)
+  #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 )
+  #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vfmaq_f32( add, mul1, mul2 )
+  #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_f32( (float const*)(ptr) ) )
+  #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vfmaq_f32( add, mul, vld1q_dup_f32( (float const*)(ptr) ) )
+  #else
+  #define stbir__simdf_madd( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) )
+  #define stbir__simdf_madd1( out, add, mul1, mul2 ) (out) = vaddq_f32( add, vmulq_f32( mul1, mul2 ) )
+  #define stbir__simdf_madd_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_f32( (float const*)(ptr) ) ) )
+  #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = vaddq_f32( add, vmulq_f32( mul, vld1q_dup_f32( (float const*)(ptr) ) ) )
+  #endif
+
+  #define stbir__simdf_add1( out, reg0, reg1 ) (out) = vaddq_f32( reg0, reg1 )
+  #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = vmulq_f32( reg0, reg1 )
+
+  #define stbir__simdf_and( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vandq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) )
+  #define stbir__simdf_or( out, reg0, reg1 ) (out) = vreinterpretq_f32_u32( vorrq_u32( vreinterpretq_u32_f32(reg0), vreinterpretq_u32_f32(reg1) ) )
+
+  #define stbir__simdf_min( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 )
+  #define stbir__simdf_max( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 )
+  #define stbir__simdf_min1( out, reg0, reg1 ) (out) = vminq_f32( reg0, reg1 )
+  #define stbir__simdf_max1( out, reg0, reg1 ) (out) = vmaxq_f32( reg0, reg1 )
+
+  #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 3 )
+  #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = vextq_f32( reg0, reg1, 2 )
+
+  #define stbir__simdf_a1a1( out, alp, ones ) (out) = vzipq_f32(vuzpq_f32(alp, alp).val[1], ones).val[0]
+  #define stbir__simdf_1a1a( out, alp, ones ) (out) = vzipq_f32(ones, vuzpq_f32(alp, alp).val[0]).val[0]
+
+  #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )
+
+    #define stbir__simdf_aaa1( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3, ones, 3)
+    #define stbir__simdf_1aaa( out, alp, ones ) (out) = vcopyq_laneq_f32(vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0, ones, 0)
+
+    #if defined( _MSC_VER ) && !defined(__clang__)
+      #define stbir_make16(a,b,c,d) vcombine_u8( \
+        vcreate_u8( (4*a+0) | ((4*a+1)<<8) | ((4*a+2)<<16) | ((4*a+3)<<24) | \
+          ((stbir_uint64)(4*b+0)<<32) | ((stbir_uint64)(4*b+1)<<40) | ((stbir_uint64)(4*b+2)<<48) | ((stbir_uint64)(4*b+3)<<56)), \
+        vcreate_u8( (4*c+0) | ((4*c+1)<<8) | ((4*c+2)<<16) | ((4*c+3)<<24) | \
+          ((stbir_uint64)(4*d+0)<<32) | ((stbir_uint64)(4*d+1)<<40) | ((stbir_uint64)(4*d+2)<<48) | ((stbir_uint64)(4*d+3)<<56) ) )
+    #else
+      #define stbir_make16(a,b,c,d) (uint8x16_t){4*a+0,4*a+1,4*a+2,4*a+3,4*b+0,4*b+1,4*b+2,4*b+3,4*c+0,4*c+1,4*c+2,4*c+3,4*d+0,4*d+1,4*d+2,4*d+3}
+    #endif
+
+    #define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vqtbl1q_u8( vreinterpretq_u8_f32(reg), stbir_make16(one, two, three, four) ) )
+
+    #define stbir__simdi_16madd( out, reg0, reg1 ) \
+    { \
+      int16x8_t r0 = vreinterpretq_s16_u32(reg0); \
+      int16x8_t r1 = vreinterpretq_s16_u32(reg1); \
+      int32x4_t tmp0 = vmull_s16( vget_low_s16(r0), vget_low_s16(r1) ); \
+      int32x4_t tmp1 = vmull_s16( vget_high_s16(r0), vget_high_s16(r1) ); \
+      (out) = vreinterpretq_u32_s32( vpaddq_s32(tmp0, tmp1) ); \
+    }
+
+  #else
+
+    #define stbir__simdf_aaa1( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 3)), 3)
+    #define stbir__simdf_1aaa( out, alp, ones ) (out) = vsetq_lane_f32(1.0f, vdupq_n_f32(vgetq_lane_f32(alp, 0)), 0)
+
+    #if defined( _MSC_VER ) && !defined(__clang__)
+      static stbir__inline uint8x8x2_t stbir_make8x2(float32x4_t reg)
+      {
+        uint8x8x2_t r = { { vget_low_u8(vreinterpretq_u8_f32(reg)), vget_high_u8(vreinterpretq_u8_f32(reg)) } };
+        return r;
+      }
+      #define stbir_make8(a,b) vcreate_u8( \
+        (4*a+0) | ((4*a+1)<<8) | ((4*a+2)<<16) | ((4*a+3)<<24) | \
+        ((stbir_uint64)(4*b+0)<<32) | ((stbir_uint64)(4*b+1)<<40) | ((stbir_uint64)(4*b+2)<<48) | ((stbir_uint64)(4*b+3)<<56) )
+    #else
+      #define stbir_make8x2(reg) (uint8x8x2_t){ { vget_low_u8(vreinterpretq_u8_f32(reg)), vget_high_u8(vreinterpretq_u8_f32(reg)) } }
+      #define stbir_make8(a,b) (uint8x8_t){4*a+0,4*a+1,4*a+2,4*a+3,4*b+0,4*b+1,4*b+2,4*b+3}
+    #endif
+
+    #define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vcombine_u8( \
+        vtbl2_u8( stbir_make8x2( reg ), stbir_make8( one, two ) ), \
+        vtbl2_u8( stbir_make8x2( reg ), stbir_make8( three, four ) ) ) )
+
+    #define stbir__simdi_16madd( out, reg0, reg1 ) \
+    { \
+      int16x8_t r0 = vreinterpretq_s16_u32(reg0); \
+      int16x8_t r1 = vreinterpretq_s16_u32(reg1); \
+      int32x4_t tmp0 = vmull_s16( vget_low_s16(r0), vget_low_s16(r1) ); \
+      int32x4_t tmp1 = vmull_s16( vget_high_s16(r0), vget_high_s16(r1) ); \
+      int32x2_t out0 = vpadd_s32( vget_low_s32(tmp0), vget_high_s32(tmp0) ); \
+      int32x2_t out1 = vpadd_s32( vget_low_s32(tmp1), vget_high_s32(tmp1) ); \
+      (out) = vreinterpretq_u32_s32( vcombine_s32(out0, out1) ); \
+    }
+
+  #endif
+
+  #define stbir__simdi_and( out, reg0, reg1 ) (out) = vandq_u32( reg0, reg1 )
+  #define stbir__simdi_or( out, reg0, reg1 ) (out) = vorrq_u32( reg0, reg1 )
+
+  #define stbir__simdf_pack_to_8bytes(out,aa,bb) \
+  { \
+    float32x4_t af = vmaxq_f32( vminq_f32(aa,STBIR__CONSTF(STBIR_max_uint8_as_float) ), vdupq_n_f32(0) ); \
+    float32x4_t bf = vmaxq_f32( vminq_f32(bb,STBIR__CONSTF(STBIR_max_uint8_as_float) ), vdupq_n_f32(0) ); \
+    int16x4_t ai = vqmovn_s32( vcvtq_s32_f32( af ) ); \
+    int16x4_t bi = vqmovn_s32( vcvtq_s32_f32( bf ) ); \
+    uint8x8_t out8 = vqmovun_s16( vcombine_s16(ai, bi) ); \
+    out = vreinterpretq_u32_u8( vcombine_u8(out8, out8) ); \
+  }
+
+  #define stbir__simdf_pack_to_8words(out,aa,bb) \
+  { \
+    float32x4_t af = vmaxq_f32( vminq_f32(aa,STBIR__CONSTF(STBIR_max_uint16_as_float) ), vdupq_n_f32(0) ); \
+    float32x4_t bf = vmaxq_f32( vminq_f32(bb,STBIR__CONSTF(STBIR_max_uint16_as_float) ), vdupq_n_f32(0) ); \
+    int32x4_t ai = vcvtq_s32_f32( af ); \
+    int32x4_t bi = vcvtq_s32_f32( bf ); \
+    out = vreinterpretq_u32_u16( vcombine_u16(vqmovun_s32(ai), vqmovun_s32(bi)) ); \
+  }
+
+  #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \
+  { \
+    int16x4x2_t tmp0 = vzip_s16( vqmovn_s32(vreinterpretq_s32_u32(r0)), vqmovn_s32(vreinterpretq_s32_u32(r2)) ); \
+    int16x4x2_t tmp1 = vzip_s16( vqmovn_s32(vreinterpretq_s32_u32(r1)), vqmovn_s32(vreinterpretq_s32_u32(r3)) ); \
+    uint8x8x2_t out = \
+    { { \
+      vqmovun_s16( vcombine_s16(tmp0.val[0], tmp0.val[1]) ), \
+      vqmovun_s16( vcombine_s16(tmp1.val[0], tmp1.val[1]) ), \
+    } }; \
+    vst2_u8(ptr, out); \
+  }
+
+  #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \
+  { \
+    float32x4x4_t tmp = vld4q_f32(ptr); \
+    o0 = tmp.val[0]; \
+    o1 = tmp.val[1]; \
+    o2 = tmp.val[2]; \
+    o3 = tmp.val[3]; \
+  }
+
+  #define stbir__simdi_32shr( out, reg, imm ) out = vshrq_n_u32( reg, imm )
+
+  #if defined( _MSC_VER ) && !defined(__clang__)
+    #define STBIR__SIMDF_CONST(var, x) __declspec(align(8)) float var[] = { x, x, x, x }
+    #define STBIR__SIMDI_CONST(var, x) __declspec(align(8)) uint32_t var[] = { x, x, x, x }
+    #define STBIR__CONSTF(var) (*(const float32x4_t*)var)
+    #define STBIR__CONSTI(var) (*(const uint32x4_t*)var)
+  #else
+    #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = { x, x, x, x }
+    #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x }
+    #define STBIR__CONSTF(var) (var)
+    #define STBIR__CONSTI(var) (var)
+  #endif
+
+  #ifdef STBIR_FLOORF
+  #undef STBIR_FLOORF
+  #endif
+  #define STBIR_FLOORF stbir_simd_floorf
+  static stbir__inline float stbir_simd_floorf(float x)
+  {
+    #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )
+    return vget_lane_f32( vrndm_f32( vdup_n_f32(x) ), 0);
+    #else
+    float32x2_t f = vdup_n_f32(x);
+    float32x2_t t = vcvt_f32_s32(vcvt_s32_f32(f));
+    uint32x2_t a = vclt_f32(f, t);
+    uint32x2_t b = vreinterpret_u32_f32(vdup_n_f32(-1.0f));
+    float32x2_t r = vadd_f32(t, vreinterpret_f32_u32(vand_u32(a, b)));
+    return vget_lane_f32(r, 0);
+    #endif
+  }
+
+  #ifdef STBIR_CEILF
+  #undef STBIR_CEILF
+  #endif
+  #define STBIR_CEILF stbir_simd_ceilf
+  static stbir__inline float stbir_simd_ceilf(float x)
+  {
+    #if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ )
+    return vget_lane_f32( vrndp_f32( vdup_n_f32(x) ), 0);
+    #else
+    float32x2_t f = vdup_n_f32(x);
+    float32x2_t t = vcvt_f32_s32(vcvt_s32_f32(f));
+    uint32x2_t a = vclt_f32(t, f);
+    uint32x2_t b = vreinterpret_u32_f32(vdup_n_f32(1.0f));
+    float32x2_t r = vadd_f32(t, vreinterpret_f32_u32(vand_u32(a, b)));
+    return vget_lane_f32(r, 0);
+    #endif
+  }
+
+  #define STBIR_SIMD
+
+#elif defined(STBIR_WASM)
+
+  #include <wasm_simd128.h>
+
+  #define stbir__simdf v128_t
+  #define stbir__simdi v128_t
+
+  #define stbir_simdi_castf( reg ) (reg)
+  #define stbir_simdf_casti( reg ) (reg)
+
+  #define stbir__simdf_load( reg, ptr )             (reg) = wasm_v128_load( (void const*)(ptr) )
+  #define stbir__simdi_load( reg, ptr )             (reg) = wasm_v128_load( (void const*)(ptr) )
+  #define stbir__simdf_load1( out, ptr )            (out) = wasm_v128_load32_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf)
+  #define stbir__simdi_load1( out, ptr )            (out) = wasm_v128_load32_splat( (void const*)(ptr) )
+  #define stbir__simdf_load1z( out, ptr )           (out) = wasm_v128_load32_zero( (void const*)(ptr) ) // top values must be zero
+  #define stbir__simdf_frep4( fvar )                wasm_f32x4_splat( fvar )
+  #define stbir__simdf_load1frep4( out, fvar )      (out) = wasm_f32x4_splat( fvar )
+  #define stbir__simdf_load2( out, ptr )            (out) = wasm_v128_load64_splat( (void const*)(ptr) ) // top values can be random (not denormal or nan for perf)
+  #define stbir__simdf_load2z( out, ptr )           (out) = wasm_v128_load64_zero( (void const*)(ptr) ) // top values must be zero
+  #define stbir__simdf_load2hmerge( out, reg, ptr ) (out) = wasm_v128_load64_lane( (void const*)(ptr), reg, 1 )
+
+  #define stbir__simdf_zeroP() wasm_f32x4_const_splat(0)
+  #define stbir__simdf_zero( reg ) (reg) = wasm_f32x4_const_splat(0)
+
+  #define stbir__simdf_store( ptr, reg )   wasm_v128_store( (void*)(ptr), reg )
+  #define stbir__simdf_store1( ptr, reg )  wasm_v128_store32_lane( (void*)(ptr), reg, 0 )
+  #define stbir__simdf_store2( ptr, reg )  wasm_v128_store64_lane( (void*)(ptr), reg, 0 )
+  #define stbir__simdf_store2h( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 1 )
+
+  #define stbir__simdi_store( ptr, reg )  wasm_v128_store( (void*)(ptr), reg )
+  #define stbir__simdi_store1( ptr, reg ) wasm_v128_store32_lane( (void*)(ptr), reg, 0 )
+  #define stbir__simdi_store2( ptr, reg ) wasm_v128_store64_lane( (void*)(ptr), reg, 0 )
+
+  #define stbir__prefetch( ptr )
+
+  #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \
+  { \
+    v128_t l = wasm_u16x8_extend_low_u8x16 ( ireg ); \
+    v128_t h = wasm_u16x8_extend_high_u8x16( ireg ); \
+    out0 = wasm_u32x4_extend_low_u16x8 ( l ); \
+    out1 = wasm_u32x4_extend_high_u16x8( l ); \
+    out2 = wasm_u32x4_extend_low_u16x8 ( h ); \
+    out3 = wasm_u32x4_extend_high_u16x8( h ); \
+  }
+
+  #define stbir__simdi_expand_u8_to_1u32(out,ireg) \
+  { \
+    v128_t tmp = wasm_u16x8_extend_low_u8x16(ireg); \
+    out = wasm_u32x4_extend_low_u16x8(tmp); \
+  }
+
+  #define stbir__simdi_expand_u16_to_u32(out0,out1,ireg) \
+  { \
+    out0 = wasm_u32x4_extend_low_u16x8 ( ireg ); \
+    out1 = wasm_u32x4_extend_high_u16x8( ireg ); \
+  }
+
+  #define stbir__simdf_convert_float_to_i32( i, f )    (i) = wasm_i32x4_trunc_sat_f32x4(f)
+  #define stbir__simdf_convert_float_to_int( f )       wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(f), 0)
+  #define stbir__simdi_to_int( i )                     wasm_i32x4_extract_lane(i, 0)
+  #define stbir__simdf_convert_float_to_uint8( f )     ((unsigned char)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint8_as_float),wasm_f32x4_const_splat(0))), 0))
+  #define stbir__simdf_convert_float_to_short( f )     ((unsigned short)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint16_as_float),wasm_f32x4_const_splat(0))), 0))
+  #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = wasm_f32x4_convert_i32x4(ireg)
+  #define stbir__simdf_add( out, reg0, reg1 )          (out) = wasm_f32x4_add( reg0, reg1 )
+  #define stbir__simdf_mult( out, reg0, reg1 )         (out) = wasm_f32x4_mul( reg0, reg1 )
+  #define stbir__simdf_mult_mem( out, reg, ptr )       (out) = wasm_f32x4_mul( reg, wasm_v128_load( (void const*)(ptr) ) )
+  #define stbir__simdf_mult1_mem( out, reg, ptr )      (out) = wasm_f32x4_mul( reg, wasm_v128_load32_splat( (void const*)(ptr) ) )
+  #define stbir__simdf_add_mem( out, reg, ptr )        (out) = wasm_f32x4_add( reg, wasm_v128_load( (void const*)(ptr) ) )
+  #define stbir__simdf_add1_mem( out, reg, ptr )       (out) = wasm_f32x4_add( reg, wasm_v128_load32_splat( (void const*)(ptr) ) )
+
+  #define stbir__simdf_madd( out, add, mul1, mul2 )    (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) )
+  #define stbir__simdf_madd1( out, add, mul1, mul2 )   (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul1, mul2 ) )
+  #define stbir__simdf_madd_mem( out, add, mul, ptr )  (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load( (void const*)(ptr) ) ) )
+  #define stbir__simdf_madd1_mem( out, add, mul, ptr ) (out) = wasm_f32x4_add( add, wasm_f32x4_mul( mul, wasm_v128_load32_splat( (void const*)(ptr) ) ) )
+
+  #define stbir__simdf_add1( out, reg0, reg1 )  (out) = wasm_f32x4_add( reg0, reg1 )
+  #define stbir__simdf_mult1( out, reg0, reg1 ) (out) = wasm_f32x4_mul( reg0, reg1 )
+
+  #define stbir__simdf_and( out, reg0, reg1 ) (out) = wasm_v128_and( reg0, reg1 )
+  #define stbir__simdf_or( out, reg0, reg1 )  (out) = wasm_v128_or( reg0, reg1 )
+
+  #define stbir__simdf_min( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 )
+  #define stbir__simdf_max( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 )
+  #define stbir__simdf_min1( out, reg0, reg1 ) (out) = wasm_f32x4_min( reg0, reg1 )
+  #define stbir__simdf_max1( out, reg0, reg1 ) (out) = wasm_f32x4_max( reg0, reg1 )
+
+  #define stbir__simdf_0123ABCDto3ABx( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 3, 4, 5, -1 )
+  #define stbir__simdf_0123ABCDto23Ax( out, reg0, reg1 ) (out) = wasm_i32x4_shuffle( reg0, reg1, 2, 3, 4, -1 )
+
+  #define stbir__simdf_aaa1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 3, 3, 3, 4)
+  #define stbir__simdf_1aaa(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 0, 0)
+  #define stbir__simdf_a1a1(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 1, 4, 3, 4)
+  #define stbir__simdf_1a1a(out,alp,ones) (out) = wasm_i32x4_shuffle(alp, ones, 4, 0, 4, 2)
+
+  #define stbir__simdf_swiz( reg, one, two, three, four ) wasm_i32x4_shuffle(reg, reg, one, two, three, four)
+
+  #define stbir__simdi_and( out, reg0, reg1 )    (out) = wasm_v128_and( reg0, reg1 )
+  #define stbir__simdi_or( out, reg0, reg1 )     (out) = wasm_v128_or( reg0, reg1 )
+  #define stbir__simdi_16madd( out, reg0, reg1 ) (out) = wasm_i32x4_dot_i16x8( reg0, reg1 )
+
+  #define stbir__simdf_pack_to_8bytes(out,aa,bb) \
+  { \
+    v128_t af = wasm_f32x4_max( wasm_f32x4_min(aa, STBIR_max_uint8_as_float), wasm_f32x4_const_splat(0) ); \
+    v128_t bf = wasm_f32x4_max( wasm_f32x4_min(bb, STBIR_max_uint8_as_float), wasm_f32x4_const_splat(0) ); \
+    v128_t ai = wasm_i32x4_trunc_sat_f32x4( af ); \
+    v128_t bi = wasm_i32x4_trunc_sat_f32x4( bf ); \
+    v128_t out16 = wasm_i16x8_narrow_i32x4( ai, bi ); \
+    out = wasm_u8x16_narrow_i16x8( out16, out16 ); \
+  }
+
+  #define stbir__simdf_pack_to_8words(out,aa,bb) \
+  { \
+    v128_t af = wasm_f32x4_max( wasm_f32x4_min(aa, STBIR_max_uint16_as_float), wasm_f32x4_const_splat(0)); \
+    v128_t bf = wasm_f32x4_max( wasm_f32x4_min(bb, STBIR_max_uint16_as_float), wasm_f32x4_const_splat(0)); \
+    v128_t ai = wasm_i32x4_trunc_sat_f32x4( af ); \
+    v128_t bi = wasm_i32x4_trunc_sat_f32x4( bf ); \
+    out = wasm_u16x8_narrow_i32x4( ai, bi ); \
+  }
+
+  #define stbir__interleave_pack_and_store_16_u8( ptr, r0, r1, r2, r3 ) \
+  { \
+    v128_t tmp0 = wasm_i16x8_narrow_i32x4(r0, r1); \
+    v128_t tmp1 = wasm_i16x8_narrow_i32x4(r2, r3); \
+    v128_t tmp = wasm_u8x16_narrow_i16x8(tmp0, tmp1); \
+    tmp = wasm_i8x16_shuffle(tmp, tmp, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); \
+    wasm_v128_store( (void*)(ptr), tmp); \
+  }
+
+  #define stbir__simdf_load4_transposed( o0, o1, o2, o3, ptr ) \
+  { \
+    v128_t t0 = wasm_v128_load( ptr    ); \
+    v128_t t1 = wasm_v128_load( ptr+4  ); \
+    v128_t t2 = wasm_v128_load( ptr+8  ); \
+    v128_t t3 = wasm_v128_load( ptr+12 ); \
+    v128_t s0 = wasm_i32x4_shuffle(t0, t1, 0, 4, 2, 6); \
+    v128_t s1 = wasm_i32x4_shuffle(t0, t1, 1, 5, 3, 7); \
+    v128_t s2 = wasm_i32x4_shuffle(t2, t3, 0, 4, 2, 6); \
+    v128_t s3 = wasm_i32x4_shuffle(t2, t3, 1, 5, 3, 7); \
+    o0 = wasm_i32x4_shuffle(s0, s2, 0, 1, 4, 5); \
+    o1 = wasm_i32x4_shuffle(s1, s3, 0, 1, 4, 5); \
+    o2 = wasm_i32x4_shuffle(s0, s2, 2, 3, 6, 7); \
+    o3 = wasm_i32x4_shuffle(s1, s3, 2, 3, 6, 7); \
+  }
+
+  #define stbir__simdi_32shr( out, reg, imm ) out = wasm_u32x4_shr( reg, imm )
+
+  typedef float stbir__f32x4 __attribute__((__vector_size__(16), __aligned__(16)));
+  #define STBIR__SIMDF_CONST(var, x) stbir__simdf var = (v128_t)(stbir__f32x4){ x, x, x, x }
+  #define STBIR__SIMDI_CONST(var, x) stbir__simdi var = { x, x, x, x }
+  #define STBIR__CONSTF(var) (var)
+  #define STBIR__CONSTI(var) (var)
+
+  #ifdef STBIR_FLOORF
+  #undef STBIR_FLOORF
+  #endif
+  #define STBIR_FLOORF stbir_simd_floorf
+  static stbir__inline float stbir_simd_floorf(float x)
+  {
+    return wasm_f32x4_extract_lane( wasm_f32x4_floor( wasm_f32x4_splat(x) ), 0);
+  }
+
+  #ifdef STBIR_CEILF
+  #undef STBIR_CEILF
+  #endif
+  #define STBIR_CEILF stbir_simd_ceilf
+  static stbir__inline float stbir_simd_ceilf(float x)
+  {
+    return wasm_f32x4_extract_lane( wasm_f32x4_ceil( wasm_f32x4_splat(x) ), 0);
+  }
+
+  #define STBIR_SIMD
+
+#endif  // SSE2/NEON/WASM
+
+#endif // NO SIMD
+
+#ifdef STBIR_SIMD8
+  #define stbir__simdfX stbir__simdf8
+  #define stbir__simdiX stbir__simdi8
+  #define stbir__simdfX_load stbir__simdf8_load
+  #define stbir__simdiX_load stbir__simdi8_load
+  #define stbir__simdfX_mult stbir__simdf8_mult
+  #define stbir__simdfX_add_mem stbir__simdf8_add_mem
+  #define stbir__simdfX_madd_mem stbir__simdf8_madd_mem
+  #define stbir__simdfX_store stbir__simdf8_store
+  #define stbir__simdiX_store stbir__simdi8_store
+  #define stbir__simdf_frepX  stbir__simdf8_frep8
+  #define stbir__simdfX_madd stbir__simdf8_madd
+  #define stbir__simdfX_min stbir__simdf8_min
+  #define stbir__simdfX_max stbir__simdf8_max
+  #define stbir__simdfX_aaa1 stbir__simdf8_aaa1
+  #define stbir__simdfX_1aaa stbir__simdf8_1aaa
+  #define stbir__simdfX_a1a1 stbir__simdf8_a1a1
+  #define stbir__simdfX_1a1a stbir__simdf8_1a1a
+  #define stbir__simdfX_convert_float_to_i32 stbir__simdf8_convert_float_to_i32
+  #define stbir__simdfX_pack_to_words stbir__simdf8_pack_to_16words
+  #define stbir__simdfX_zero stbir__simdf8_zero
+  #define STBIR_onesX STBIR_ones8
+  #define STBIR_max_uint8_as_floatX STBIR_max_uint8_as_float8
+  #define STBIR_max_uint16_as_floatX STBIR_max_uint16_as_float8
+  #define STBIR_simd_point5X STBIR_simd_point58
+  #define stbir__simdfX_float_count 8
+  #define stbir__simdfX_0123to1230 stbir__simdf8_0123to12301230
+  #define stbir__simdfX_0123to2103 stbir__simdf8_0123to21032103
+  static const stbir__simdf8 STBIR_max_uint16_as_float_inverted8 = { stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted,stbir__max_uint16_as_float_inverted };
+  static const stbir__simdf8 STBIR_max_uint8_as_float_inverted8 = { stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted,stbir__max_uint8_as_float_inverted };
+  static const stbir__simdf8 STBIR_ones8 = { 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 };
+  static const stbir__simdf8 STBIR_simd_point58 = { 0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5 };
+  static const stbir__simdf8 STBIR_max_uint8_as_float8 = { stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float, stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float,stbir__max_uint8_as_float };
+  static const stbir__simdf8 STBIR_max_uint16_as_float8 = { stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float, stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float,stbir__max_uint16_as_float };
+#else
+  #define stbir__simdfX stbir__simdf
+  #define stbir__simdiX stbir__simdi
+  #define stbir__simdfX_load stbir__simdf_load
+  #define stbir__simdiX_load stbir__simdi_load
+  #define stbir__simdfX_mult stbir__simdf_mult
+  #define stbir__simdfX_add_mem stbir__simdf_add_mem
+  #define stbir__simdfX_madd_mem stbir__simdf_madd_mem
+  #define stbir__simdfX_store stbir__simdf_store
+  #define stbir__simdiX_store stbir__simdi_store
+  #define stbir__simdf_frepX  stbir__simdf_frep4
+  #define stbir__simdfX_madd stbir__simdf_madd
+  #define stbir__simdfX_min stbir__simdf_min
+  #define stbir__simdfX_max stbir__simdf_max
+  #define stbir__simdfX_aaa1 stbir__simdf_aaa1
+  #define stbir__simdfX_1aaa stbir__simdf_1aaa
+  #define stbir__simdfX_a1a1 stbir__simdf_a1a1
+  #define stbir__simdfX_1a1a stbir__simdf_1a1a
+  #define stbir__simdfX_convert_float_to_i32 stbir__simdf_convert_float_to_i32
+  #define stbir__simdfX_pack_to_words stbir__simdf_pack_to_8words
+  #define stbir__simdfX_zero stbir__simdf_zero
+  #define STBIR_onesX STBIR__CONSTF(STBIR_ones)
+  #define STBIR_simd_point5X STBIR__CONSTF(STBIR_simd_point5)
+  #define STBIR_max_uint8_as_floatX STBIR__CONSTF(STBIR_max_uint8_as_float)
+  #define STBIR_max_uint16_as_floatX STBIR__CONSTF(STBIR_max_uint16_as_float)
+  #define stbir__simdfX_float_count 4
+  #define stbir__if_simdf8_cast_to_simdf4( val ) ( val )
+  #define stbir__simdfX_0123to1230 stbir__simdf_0123to1230
+  #define stbir__simdfX_0123to2103 stbir__simdf_0123to2103
+#endif
+
+
+#if defined(STBIR_NEON) && !defined(_M_ARM)
+
+  #if defined( _MSC_VER ) && !defined(__clang__)
+  typedef __int16 stbir__FP16;
+  #else
+  typedef float16_t stbir__FP16;
+  #endif
+
+#else // no NEON, or 32-bit ARM for MSVC
+
+  typedef union stbir__FP16
+  {
+    unsigned short u;
+  } stbir__FP16;
+
+#endif
+
+#if !defined(STBIR_NEON) && !defined(STBIR_FP16C) || defined(STBIR_NEON) && defined(_M_ARM)
+
+  // Fabian's half float routines, see: https://gist.github.com/rygorous/2156668
+
+  static stbir__inline float stbir__half_to_float( stbir__FP16 h )
+  {
+    static const stbir__FP32 magic = { (254 - 15) << 23 };
+    static const stbir__FP32 was_infnan = { (127 + 16) << 23 };
+    stbir__FP32 o;
+
+    o.u = (h.u & 0x7fff) << 13;     // exponent/mantissa bits
+    o.f *= magic.f;                 // exponent adjust
+    if (o.f >= was_infnan.f)        // make sure Inf/NaN survive
+      o.u |= 255 << 23;
+    o.u |= (h.u & 0x8000) << 16;    // sign bit
+    return o.f;
+  }
+
+  static stbir__inline stbir__FP16 stbir__float_to_half(float val)
+  {
+    stbir__FP32 f32infty = { 255 << 23 };
+    stbir__FP32 f16max   = { (127 + 16) << 23 };
+    stbir__FP32 denorm_magic = { ((127 - 15) + (23 - 10) + 1) << 23 };
+    unsigned int sign_mask = 0x80000000u;
+    stbir__FP16 o = { 0 };
+    stbir__FP32 f;
+    unsigned int sign;
+
+    f.f = val;
+    sign = f.u & sign_mask;
+    f.u ^= sign;
+
+    if (f.u >= f16max.u) // result is Inf or NaN (all exponent bits set)
+      o.u = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf
+    else // (De)normalized number or zero
+    {
+      if (f.u < (113 << 23)) // resulting FP16 is subnormal or zero
+      {
+        // use a magic value to align our 10 mantissa bits at the bottom of
+        // the float. as long as FP addition is round-to-nearest-even this
+        // just works.
+        f.f += denorm_magic.f;
+        // and one integer subtract of the bias later, we have our final float!
+        o.u = (unsigned short) ( f.u - denorm_magic.u );
+      }
+      else
+      {
+        unsigned int mant_odd = (f.u >> 13) & 1; // resulting mantissa is odd
+        // update exponent, rounding bias part 1
+        f.u = f.u + ((15u - 127) << 23) + 0xfff;
+        // rounding bias part 2
+        f.u += mant_odd;
+        // take the bits!
+        o.u = (unsigned short) ( f.u >> 13 );
+      }
+    }
+
+    o.u |= sign >> 16;
+    return o;
+  }
+
+#endif
+
+
+#if defined(STBIR_FP16C)
+
+  #include <immintrin.h>
+
+  static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)
+  {
+    _mm256_storeu_ps( (float*)output, _mm256_cvtph_ps( _mm_loadu_si128( (__m128i const* )input ) ) );
+  }
+
+  static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)
+  {
+    _mm_storeu_si128( (__m128i*)output, _mm256_cvtps_ph( _mm256_loadu_ps( input ), 0 ) );
+  }
+
+  static stbir__inline float stbir__half_to_float( stbir__FP16 h )
+  {
+    return _mm_cvtss_f32( _mm_cvtph_ps( _mm_cvtsi32_si128( (int)h.u ) ) );
+  }
+
+  static stbir__inline stbir__FP16 stbir__float_to_half( float f )
+  {
+    stbir__FP16 h;
+    h.u = (unsigned short) _mm_cvtsi128_si32( _mm_cvtps_ph( _mm_set_ss( f ), 0 ) );
+    return h;
+  }
+
+#elif defined(STBIR_SSE2)
+
+  // Fabian's half float routines, see: https://gist.github.com/rygorous/2156668
+  stbir__inline static void stbir__half_to_float_SIMD(float * output, void const * input)
+  {
+    static const STBIR__SIMDI_CONST(mask_nosign,      0x7fff);
+    static const STBIR__SIMDI_CONST(smallest_normal,  0x0400);
+    static const STBIR__SIMDI_CONST(infinity,         0x7c00);
+    static const STBIR__SIMDI_CONST(expadjust_normal, (127 - 15) << 23);
+    static const STBIR__SIMDI_CONST(magic_denorm,     113 << 23);
+
+    __m128i i = _mm_loadu_si128 ( (__m128i const*)(input) );
+    __m128i h = _mm_unpacklo_epi16 ( i, _mm_setzero_si128() );
+    __m128i mnosign     = STBIR__CONSTI(mask_nosign);
+    __m128i eadjust     = STBIR__CONSTI(expadjust_normal);
+    __m128i smallest    = STBIR__CONSTI(smallest_normal);
+    __m128i infty       = STBIR__CONSTI(infinity);
+    __m128i expmant     = _mm_and_si128(mnosign, h);
+    __m128i justsign    = _mm_xor_si128(h, expmant);
+    __m128i b_notinfnan = _mm_cmpgt_epi32(infty, expmant);
+    __m128i b_isdenorm  = _mm_cmpgt_epi32(smallest, expmant);
+    __m128i shifted     = _mm_slli_epi32(expmant, 13);
+    __m128i adj_infnan  = _mm_andnot_si128(b_notinfnan, eadjust);
+    __m128i adjusted    = _mm_add_epi32(eadjust, shifted);
+    __m128i den1        = _mm_add_epi32(shifted, STBIR__CONSTI(magic_denorm));
+    __m128i adjusted2   = _mm_add_epi32(adjusted, adj_infnan);
+    __m128  den2        = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm);
+    __m128  adjusted3   = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm));
+    __m128  adjusted4   = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2));
+    __m128  adjusted5   = _mm_or_ps(adjusted3, adjusted4);
+    __m128i sign        = _mm_slli_epi32(justsign, 16);
+    __m128  final       = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));
+    stbir__simdf_store( output + 0,  final );
+
+    h = _mm_unpackhi_epi16 ( i, _mm_setzero_si128() );
+    expmant     = _mm_and_si128(mnosign, h);
+    justsign    = _mm_xor_si128(h, expmant);
+    b_notinfnan = _mm_cmpgt_epi32(infty, expmant);
+    b_isdenorm  = _mm_cmpgt_epi32(smallest, expmant);
+    shifted     = _mm_slli_epi32(expmant, 13);
+    adj_infnan  = _mm_andnot_si128(b_notinfnan, eadjust);
+    adjusted    = _mm_add_epi32(eadjust, shifted);
+    den1        = _mm_add_epi32(shifted, STBIR__CONSTI(magic_denorm));
+    adjusted2   = _mm_add_epi32(adjusted, adj_infnan);
+    den2        = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm);
+    adjusted3   = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm));
+    adjusted4   = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2));
+    adjusted5   = _mm_or_ps(adjusted3, adjusted4);
+    sign        = _mm_slli_epi32(justsign, 16);
+    final       = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));
+    stbir__simdf_store( output + 4,  final );
+
+    // ~38 SSE2 ops for 8 values
+  }
+
+  // Fabian's round-to-nearest-even float to half
+  // ~48 SSE2 ops for 8 output
+  stbir__inline static void stbir__float_to_half_SIMD(void * output, float const * input)
+  {
+    static const STBIR__SIMDI_CONST(mask_sign,      0x80000000u);
+    static const STBIR__SIMDI_CONST(c_f16max,       (127 + 16) << 23); // all FP32 values >=this round to +inf
+    static const STBIR__SIMDI_CONST(c_nanbit,        0x200);
+    static const STBIR__SIMDI_CONST(c_infty_as_fp16, 0x7c00);
+    static const STBIR__SIMDI_CONST(c_min_normal,    (127 - 14) << 23); // smallest FP32 that yields a normalized FP16
+    static const STBIR__SIMDI_CONST(c_subnorm_magic, ((127 - 15) + (23 - 10) + 1) << 23);
+    static const STBIR__SIMDI_CONST(c_normal_bias,    0xfff - ((127 - 15) << 23)); // adjust exponent and add mantissa rounding
+
+    __m128  f           =  _mm_loadu_ps(input);
+    __m128  msign       = _mm_castsi128_ps(STBIR__CONSTI(mask_sign));
+    __m128  justsign    = _mm_and_ps(msign, f);
+    __m128  absf        = _mm_xor_ps(f, justsign);
+    __m128i absf_int    = _mm_castps_si128(absf); // the cast is "free" (extra bypass latency, but no thruput hit)
+    __m128i f16max      = STBIR__CONSTI(c_f16max);
+    __m128  b_isnan     = _mm_cmpunord_ps(absf, absf); // is this a NaN?
+    __m128i b_isregular = _mm_cmpgt_epi32(f16max, absf_int); // (sub)normalized or special?
+    __m128i nanbit      = _mm_and_si128(_mm_castps_si128(b_isnan), STBIR__CONSTI(c_nanbit));
+    __m128i inf_or_nan  = _mm_or_si128(nanbit, STBIR__CONSTI(c_infty_as_fp16)); // output for specials
+
+    __m128i min_normal  = STBIR__CONSTI(c_min_normal);
+    __m128i b_issub     = _mm_cmpgt_epi32(min_normal, absf_int);
+
+    // "result is subnormal" path
+    __m128  subnorm1    = _mm_add_ps(absf, _mm_castsi128_ps(STBIR__CONSTI(c_subnorm_magic))); // magic value to round output mantissa
+    __m128i subnorm2    = _mm_sub_epi32(_mm_castps_si128(subnorm1), STBIR__CONSTI(c_subnorm_magic)); // subtract out bias
+
+    // "result is normal" path
+    __m128i mantoddbit  = _mm_slli_epi32(absf_int, 31 - 13); // shift bit 13 (mantissa LSB) to sign
+    __m128i mantodd     = _mm_srai_epi32(mantoddbit, 31); // -1 if FP16 mantissa odd, else 0
+
+    __m128i round1      = _mm_add_epi32(absf_int, STBIR__CONSTI(c_normal_bias));
+    __m128i round2      = _mm_sub_epi32(round1, mantodd); // if mantissa LSB odd, bias towards rounding up (RTNE)
+    __m128i normal      = _mm_srli_epi32(round2, 13); // rounded result
+
+    // combine the two non-specials
+    __m128i nonspecial  = _mm_or_si128(_mm_and_si128(subnorm2, b_issub), _mm_andnot_si128(b_issub, normal));
+
+    // merge in specials as well
+    __m128i joined      = _mm_or_si128(_mm_and_si128(nonspecial, b_isregular), _mm_andnot_si128(b_isregular, inf_or_nan));
+
+    __m128i sign_shift  = _mm_srai_epi32(_mm_castps_si128(justsign), 16);
+    __m128i final2, final= _mm_or_si128(joined, sign_shift);
+
+    f           =  _mm_loadu_ps(input+4);
+    justsign    = _mm_and_ps(msign, f);
+    absf        = _mm_xor_ps(f, justsign);
+    absf_int    = _mm_castps_si128(absf); // the cast is "free" (extra bypass latency, but no thruput hit)
+    b_isnan     = _mm_cmpunord_ps(absf, absf); // is this a NaN?
+    b_isregular = _mm_cmpgt_epi32(f16max, absf_int); // (sub)normalized or special?
+    nanbit      = _mm_and_si128(_mm_castps_si128(b_isnan), c_nanbit);
+    inf_or_nan  = _mm_or_si128(nanbit, STBIR__CONSTI(c_infty_as_fp16)); // output for specials
+
+    b_issub     = _mm_cmpgt_epi32(min_normal, absf_int);
+
+    // "result is subnormal" path
+    subnorm1    = _mm_add_ps(absf, _mm_castsi128_ps(STBIR__CONSTI(c_subnorm_magic))); // magic value to round output mantissa
+    subnorm2    = _mm_sub_epi32(_mm_castps_si128(subnorm1), STBIR__CONSTI(c_subnorm_magic)); // subtract out bias
+
+    // "result is normal" path
+    mantoddbit  = _mm_slli_epi32(absf_int, 31 - 13); // shift bit 13 (mantissa LSB) to sign
+    mantodd     = _mm_srai_epi32(mantoddbit, 31); // -1 if FP16 mantissa odd, else 0
+
+    round1      = _mm_add_epi32(absf_int, STBIR__CONSTI(c_normal_bias));
+    round2      = _mm_sub_epi32(round1, mantodd); // if mantissa LSB odd, bias towards rounding up (RTNE)
+    normal      = _mm_srli_epi32(round2, 13); // rounded result
+
+    // combine the two non-specials
+    nonspecial  = _mm_or_si128(_mm_and_si128(subnorm2, b_issub), _mm_andnot_si128(b_issub, normal));
+
+    // merge in specials as well
+    joined      = _mm_or_si128(_mm_and_si128(nonspecial, b_isregular), _mm_andnot_si128(b_isregular, inf_or_nan));
+
+    sign_shift  = _mm_srai_epi32(_mm_castps_si128(justsign), 16);
+    final2      = _mm_or_si128(joined, sign_shift);
+    final       = _mm_packs_epi32(final, final2);
+    stbir__simdi_store( output,final );
+  }
+
+#elif defined(STBIR_WASM) || (defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM)) // WASM or 32-bit ARM on MSVC/clang
+
+  static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)
+  {
+    for (int i=0; i<8; i++)
+    {
+      output[i] = stbir__half_to_float(input[i]);
+    }
+  }
+
+  static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)
+  {
+    for (int i=0; i<8; i++)
+    {
+      output[i] = stbir__float_to_half(input[i]);
+    }
+  }
+
+#elif defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__) // 64-bit ARM on MSVC (not clang)
+
+  static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)
+  {
+    float16x4_t in0 = vld1_f16(input + 0);
+    float16x4_t in1 = vld1_f16(input + 4);
+    vst1q_f32(output + 0, vcvt_f32_f16(in0));
+    vst1q_f32(output + 4, vcvt_f32_f16(in1));
+  }
+
+  static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)
+  {
+    float16x4_t out0 = vcvt_f16_f32(vld1q_f32(input + 0));
+    float16x4_t out1 = vcvt_f16_f32(vld1q_f32(input + 4));
+    vst1_f16(output+0, out0);
+    vst1_f16(output+4, out1);
+  }
+
+  static stbir__inline float stbir__half_to_float( stbir__FP16 h )
+  {
+    return vgetq_lane_f32(vcvt_f32_f16(vld1_dup_f16(&h)), 0);
+  }
+
+  static stbir__inline stbir__FP16 stbir__float_to_half( float f )
+  {
+    return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0).n16_u16[0];
+  }
+
+#elif defined(STBIR_NEON) // 64-bit ARM
+
+  static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)
+  {
+    float16x8_t in = vld1q_f16(input);
+    vst1q_f32(output + 0, vcvt_f32_f16(vget_low_f16(in)));
+    vst1q_f32(output + 4, vcvt_f32_f16(vget_high_f16(in)));
+  }
+
+  static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)
+  {
+    float16x4_t out0 = vcvt_f16_f32(vld1q_f32(input + 0));
+    float16x4_t out1 = vcvt_f16_f32(vld1q_f32(input + 4));
+    vst1q_f16(output, vcombine_f16(out0, out1));
+  }
+
+  static stbir__inline float stbir__half_to_float( stbir__FP16 h )
+  {
+    return vgetq_lane_f32(vcvt_f32_f16(vdup_n_f16(h)), 0);
+  }
+
+  static stbir__inline stbir__FP16 stbir__float_to_half( float f )
+  {
+    return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0);
+  }
+
+#endif
+
+
+#ifdef STBIR_SIMD
+
+#define stbir__simdf_0123to3333( out, reg ) (out) = stbir__simdf_swiz( reg, 3,3,3,3 )
+#define stbir__simdf_0123to2222( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,2,2 )
+#define stbir__simdf_0123to1111( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,1,1 )
+#define stbir__simdf_0123to0000( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,0 )
+#define stbir__simdf_0123to0003( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,3 )
+#define stbir__simdf_0123to0001( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,0,1 )
+#define stbir__simdf_0123to1122( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,2,2 )
+#define stbir__simdf_0123to2333( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,3,3 )
+#define stbir__simdf_0123to0023( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,3 )
+#define stbir__simdf_0123to1230( out, reg ) (out) = stbir__simdf_swiz( reg, 1,2,3,0 )
+#define stbir__simdf_0123to2103( out, reg ) (out) = stbir__simdf_swiz( reg, 2,1,0,3 )
+#define stbir__simdf_0123to3210( out, reg ) (out) = stbir__simdf_swiz( reg, 3,2,1,0 )
+#define stbir__simdf_0123to2301( out, reg ) (out) = stbir__simdf_swiz( reg, 2,3,0,1 )
+#define stbir__simdf_0123to3012( out, reg ) (out) = stbir__simdf_swiz( reg, 3,0,1,2 )
+#define stbir__simdf_0123to0011( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,1,1 )
+#define stbir__simdf_0123to1100( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,0,0 )
+#define stbir__simdf_0123to2233( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,3,3 )
+#define stbir__simdf_0123to1133( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,3,3 )
+#define stbir__simdf_0123to0022( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,2 )
+#define stbir__simdf_0123to1032( out, reg ) (out) = stbir__simdf_swiz( reg, 1,0,3,2 )
+
+typedef union stbir__simdi_u32
+{
+  stbir_uint32 m128i_u32[4];
+  int m128i_i32[4];
+  stbir__simdi m128i_i128;
+} stbir__simdi_u32;
+
+static const int STBIR_mask[9] = { 0,0,0,-1,-1,-1,0,0,0 };
+
+static const STBIR__SIMDF_CONST(STBIR_max_uint8_as_float,           stbir__max_uint8_as_float);
+static const STBIR__SIMDF_CONST(STBIR_max_uint16_as_float,          stbir__max_uint16_as_float);
+static const STBIR__SIMDF_CONST(STBIR_max_uint8_as_float_inverted,  stbir__max_uint8_as_float_inverted);
+static const STBIR__SIMDF_CONST(STBIR_max_uint16_as_float_inverted, stbir__max_uint16_as_float_inverted);
+
+static const STBIR__SIMDF_CONST(STBIR_simd_point5,   0.5f);
+static const STBIR__SIMDF_CONST(STBIR_ones,          1.0f);
+static const STBIR__SIMDI_CONST(STBIR_almost_zero,   (127 - 13) << 23);
+static const STBIR__SIMDI_CONST(STBIR_almost_one,    0x3f7fffff);
+static const STBIR__SIMDI_CONST(STBIR_mastissa_mask, 0xff);
+static const STBIR__SIMDI_CONST(STBIR_topscale,      0x02000000);
+
+//   Basically, in simd mode, we unroll the proper amount, and we don't want
+//   the non-simd remnant loops to be unroll because they only run a few times
+//   Adding this switch saves about 5K on clang which is Captain Unroll the 3rd.
+#define STBIR_SIMD_STREAMOUT_PTR( star )  STBIR_STREAMOUT_PTR( star )
+#define STBIR_SIMD_NO_UNROLL(ptr) STBIR_NO_UNROLL(ptr)
+
+#ifdef STBIR_MEMCPY
+#undef STBIR_MEMCPY
+#define STBIR_MEMCPY stbir_simd_memcpy
+#endif
+
+// override normal use of memcpy with much simpler copy (faster and smaller with our sized copies)
+static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes )
+{
+  char STBIR_SIMD_STREAMOUT_PTR (*) d = (char*) dest;
+  char STBIR_SIMD_STREAMOUT_PTR( * ) d_end = ((char*) dest) + bytes;
+  ptrdiff_t ofs_to_src = (char*)src - (char*)dest;
+
+  // check overlaps
+  STBIR_ASSERT( ( ( d >= ( (char*)src) + bytes ) ) || ( ( d + bytes ) <= (char*)src ) );
+
+  if ( bytes < (16*stbir__simdfX_float_count) )
+  {
+    if ( bytes < 16 )
+    {
+      if ( bytes )
+      {
+        do
+        {
+          STBIR_SIMD_NO_UNROLL(d);
+          d[ 0 ] = d[ ofs_to_src ];
+          ++d;
+        } while ( d < d_end );
+      }
+    }
+    else
+    {
+      stbir__simdf x;
+      // do one unaligned to get us aligned for the stream out below
+      stbir__simdf_load( x, ( d + ofs_to_src ) );
+      stbir__simdf_store( d, x );
+      d = (char*)( ( ( (ptrdiff_t)d ) + 16 ) & ~15 );
+
+      for(;;)
+      {
+        STBIR_SIMD_NO_UNROLL(d);
+
+        if ( d > ( d_end - 16 ) )
+        {
+          if ( d == d_end )
+            return;
+          d = d_end - 16;
+        }
+
+        stbir__simdf_load( x, ( d + ofs_to_src ) );
+        stbir__simdf_store( d, x );
+        d += 16;
+      }
+    }
+  }
+  else
+  {
+    stbir__simdfX x0,x1,x2,x3;
+
+    // do one unaligned to get us aligned for the stream out below
+    stbir__simdfX_load( x0, ( d + ofs_to_src ) +  0*stbir__simdfX_float_count );
+    stbir__simdfX_load( x1, ( d + ofs_to_src ) +  4*stbir__simdfX_float_count );
+    stbir__simdfX_load( x2, ( d + ofs_to_src ) +  8*stbir__simdfX_float_count );
+    stbir__simdfX_load( x3, ( d + ofs_to_src ) + 12*stbir__simdfX_float_count );
+    stbir__simdfX_store( d +  0*stbir__simdfX_float_count, x0 );
+    stbir__simdfX_store( d +  4*stbir__simdfX_float_count, x1 );
+    stbir__simdfX_store( d +  8*stbir__simdfX_float_count, x2 );
+    stbir__simdfX_store( d + 12*stbir__simdfX_float_count, x3 );
+    d = (char*)( ( ( (ptrdiff_t)d ) + (16*stbir__simdfX_float_count) ) & ~((16*stbir__simdfX_float_count)-1) );
+
+    for(;;)
+    {
+      STBIR_SIMD_NO_UNROLL(d);
+
+      if ( d > ( d_end - (16*stbir__simdfX_float_count) ) )
+      {
+        if ( d == d_end )
+          return;
+        d = d_end - (16*stbir__simdfX_float_count);
+      }
+
+      stbir__simdfX_load( x0, ( d + ofs_to_src ) +  0*stbir__simdfX_float_count );
+      stbir__simdfX_load( x1, ( d + ofs_to_src ) +  4*stbir__simdfX_float_count );
+      stbir__simdfX_load( x2, ( d + ofs_to_src ) +  8*stbir__simdfX_float_count );
+      stbir__simdfX_load( x3, ( d + ofs_to_src ) + 12*stbir__simdfX_float_count );
+      stbir__simdfX_store( d +  0*stbir__simdfX_float_count, x0 );
+      stbir__simdfX_store( d +  4*stbir__simdfX_float_count, x1 );
+      stbir__simdfX_store( d +  8*stbir__simdfX_float_count, x2 );
+      stbir__simdfX_store( d + 12*stbir__simdfX_float_count, x3 );
+      d += (16*stbir__simdfX_float_count);
+    }
+  }
+}
+
+// memcpy that is specically intentionally overlapping (src is smaller then dest, so can be
+//   a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to
+//   the diff between dest and src)
+static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes )
+{
+  char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src;
+  char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes;
+  ptrdiff_t ofs_to_dest = (char*)dest - (char*)src;
+
+  if ( ofs_to_dest >= 16 ) // is the overlap more than 16 away?
+  {
+    char STBIR_SIMD_STREAMOUT_PTR( * ) s_end16 = ((char*) src) + (bytes&~15);
+    do
+    {
+      stbir__simdf x;
+      STBIR_SIMD_NO_UNROLL(sd);
+      stbir__simdf_load( x, sd );
+      stbir__simdf_store(  ( sd + ofs_to_dest ), x );
+      sd += 16;
+    } while ( sd < s_end16 );
+
+    if ( sd == s_end )
+      return;
+  }
+
+  do
+  {
+    STBIR_SIMD_NO_UNROLL(sd);
+    *(int*)( sd + ofs_to_dest ) = *(int*) sd;
+    sd += 4;
+  } while ( sd < s_end );
+}
+
+#else // no SSE2
+
+// when in scalar mode, we let unrolling happen, so this macro just does the __restrict
+#define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star )
+#define STBIR_SIMD_NO_UNROLL(ptr)
+
+#endif // SSE2
+
+
+#ifdef STBIR_PROFILE
+
+#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ )
+
+#ifdef _MSC_VER
+
+  STBIRDEF stbir_uint64 __rdtsc();
+  #define STBIR_PROFILE_FUNC() __rdtsc()
+
+#else // non msvc
+
+  static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC()
+  {
+    stbir_uint32 lo, hi;
+    asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) );
+    return ( ( (stbir_uint64) hi ) << 32 ) | ( (stbir_uint64) lo );
+  }
+
+#endif  // msvc
+
+#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__)
+
+#if defined( _MSC_VER ) && !defined(__clang__)
+
+  #define STBIR_PROFILE_FUNC() _ReadStatusReg(ARM64_CNTVCT)
+
+#else
+
+  static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC()
+  {
+    stbir_uint64 tsc;
+    asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));
+    return tsc;
+  }
+
+#endif
+
+#else // x64, arm
+
+#error Unknown platform for profiling.
+
+#endif  //x64 and
+
+
+#define STBIR_ONLY_PROFILE_GET_SPLIT_INFO ,stbir__per_split_info * split_info
+#define STBIR_ONLY_PROFILE_SET_SPLIT_INFO ,split_info
+
+#define STBIR_ONLY_PROFILE_BUILD_GET_INFO ,stbir__info * profile_info
+#define STBIR_ONLY_PROFILE_BUILD_SET_INFO ,profile_info
+
+// super light-weight micro profiler
+#define STBIR_PROFILE_START_ll( info, wh ) { stbir_uint64 wh##thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * wh##save_parent_excluded_ptr = info->current_zone_excluded_ptr; stbir_uint64 wh##current_zone_excluded = 0; info->current_zone_excluded_ptr = &wh##current_zone_excluded;
+#define STBIR_PROFILE_END_ll( info, wh ) wh##thiszonetime = STBIR_PROFILE_FUNC() - wh##thiszonetime; info->profile.named.wh += wh##thiszonetime - wh##current_zone_excluded; *wh##save_parent_excluded_ptr += wh##thiszonetime; info->current_zone_excluded_ptr = wh##save_parent_excluded_ptr; }
+#define STBIR_PROFILE_FIRST_START_ll( info, wh ) { int i; info->current_zone_excluded_ptr = &info->profile.named.total; for(i=0;i<STBIR__ARRAY_SIZE(info->profile.array);i++) info->profile.array[i]=0; } STBIR_PROFILE_START_ll( info, wh );
+#define STBIR_PROFILE_CLEAR_EXTRAS_ll( info, num ) { int extra; for(extra=1;extra<(num);extra++) { int i; for(i=0;i<STBIR__ARRAY_SIZE((info)->profile.array);i++) (info)[extra].profile.array[i]=0; } }
+
+// for thread data
+#define STBIR_PROFILE_START( wh ) STBIR_PROFILE_START_ll( split_info, wh )
+#define STBIR_PROFILE_END( wh ) STBIR_PROFILE_END_ll( split_info, wh )
+#define STBIR_PROFILE_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( split_info, wh )
+#define STBIR_PROFILE_CLEAR_EXTRAS() STBIR_PROFILE_CLEAR_EXTRAS_ll( split_info, split_count )
+
+// for build data
+#define STBIR_PROFILE_BUILD_START( wh ) STBIR_PROFILE_START_ll( profile_info, wh )
+#define STBIR_PROFILE_BUILD_END( wh ) STBIR_PROFILE_END_ll( profile_info, wh )
+#define STBIR_PROFILE_BUILD_FIRST_START( wh ) STBIR_PROFILE_FIRST_START_ll( profile_info, wh )
+#define STBIR_PROFILE_BUILD_CLEAR( info ) { int i; for(i=0;i<STBIR__ARRAY_SIZE(info->profile.array);i++) info->profile.array[i]=0; }
+
+#else  // no profile
+
+#define STBIR_ONLY_PROFILE_GET_SPLIT_INFO
+#define STBIR_ONLY_PROFILE_SET_SPLIT_INFO
+
+#define STBIR_ONLY_PROFILE_BUILD_GET_INFO
+#define STBIR_ONLY_PROFILE_BUILD_SET_INFO
+
+#define STBIR_PROFILE_START( wh )
+#define STBIR_PROFILE_END( wh )
+#define STBIR_PROFILE_FIRST_START( wh )
+#define STBIR_PROFILE_CLEAR_EXTRAS( )
+
+#define STBIR_PROFILE_BUILD_START( wh )
+#define STBIR_PROFILE_BUILD_END( wh )
+#define STBIR_PROFILE_BUILD_FIRST_START( wh )
+#define STBIR_PROFILE_BUILD_CLEAR( info )
+
+#endif  // stbir_profile
+
+#ifndef STBIR_CEILF
+#include <math.h>
+#if _MSC_VER <= 1200 // support VC6 for Sean
+#define STBIR_CEILF(x) ((float)ceil((float)(x)))
+#define STBIR_FLOORF(x) ((float)floor((float)(x)))
+#else
+#define STBIR_CEILF(x) ceilf(x)
+#define STBIR_FLOORF(x) floorf(x)
+#endif
+#endif
+
+#ifndef STBIR_MEMCPY
+// For memcpy
+#include <string.h>
+#define STBIR_MEMCPY( dest, src, len ) memcpy( dest, src, len )
+#endif
+
+#ifndef STBIR_SIMD
+
+// memcpy that is specically intentionally overlapping (src is smaller then dest, so can be
+//   a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to
+//   the diff between dest and src)
+static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes )
+{
+  char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src;
+  char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes;
+  ptrdiff_t ofs_to_dest = (char*)dest - (char*)src;
+
+  if ( ofs_to_dest >= 8 ) // is the overlap more than 8 away?
+  {
+    char STBIR_SIMD_STREAMOUT_PTR( * ) s_end8 = ((char*) src) + (bytes&~7);
+    do
+    {
+      STBIR_NO_UNROLL(sd);
+      *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd;
+      sd += 8;
+    } while ( sd < s_end8 );
+
+    if ( sd == s_end )
+      return;
+  }
+
+  do
+  {
+    STBIR_NO_UNROLL(sd);
+    *(int*)( sd + ofs_to_dest ) = *(int*) sd;
+    sd += 4;
+  } while ( sd < s_end );
+}
+
+#endif
+
+static float stbir__filter_trapezoid(float x, float scale, void * user_data)
+{
+  float halfscale = scale / 2;
+  float t = 0.5f + halfscale;
+  STBIR_ASSERT(scale <= 1);
+  STBIR__UNUSED(user_data);
+
+  if ( x < 0.0f ) x = -x;
+
+  if (x >= t)
+    return 0.0f;
+  else
+  {
+    float r = 0.5f - halfscale;
+    if (x <= r)
+      return 1.0f;
+    else
+      return (t - x) / scale;
+  }
+}
+
+static float stbir__support_trapezoid(float scale, void * user_data)
+{
+  STBIR__UNUSED(user_data);
+  return 0.5f + scale / 2.0f;
+}
+
+static float stbir__filter_triangle(float x, float s, void * user_data)
+{
+  STBIR__UNUSED(s);
+  STBIR__UNUSED(user_data);
+
+  if ( x < 0.0f ) x = -x;
+
+  if (x <= 1.0f)
+    return 1.0f - x;
+  else
+    return 0.0f;
+}
+
+static float stbir__filter_point(float x, float s, void * user_data)
+{
+  STBIR__UNUSED(x);
+  STBIR__UNUSED(s);
+  STBIR__UNUSED(user_data);
+
+  return 1.0f;
+}
+
+static float stbir__filter_cubic(float x, float s, void * user_data)
+{
+  STBIR__UNUSED(s);
+  STBIR__UNUSED(user_data);
+
+  if ( x < 0.0f ) x = -x;
+
+  if (x < 1.0f)
+    return (4.0f + x*x*(3.0f*x - 6.0f))/6.0f;
+  else if (x < 2.0f)
+    return (8.0f + x*(-12.0f + x*(6.0f - x)))/6.0f;
+
+  return (0.0f);
+}
+
+static float stbir__filter_catmullrom(float x, float s, void * user_data)
+{
+  STBIR__UNUSED(s);
+  STBIR__UNUSED(user_data);
+
+  if ( x < 0.0f ) x = -x;
+
+  if (x < 1.0f)
+    return 1.0f - x*x*(2.5f - 1.5f*x);
+  else if (x < 2.0f)
+    return 2.0f - x*(4.0f + x*(0.5f*x - 2.5f));
+
+  return (0.0f);
+}
+
+static float stbir__filter_mitchell(float x, float s, void * user_data)
+{
+  STBIR__UNUSED(s);
+  STBIR__UNUSED(user_data);
+
+  if ( x < 0.0f ) x = -x;
+
+  if (x < 1.0f)
+    return (16.0f + x*x*(21.0f * x - 36.0f))/18.0f;
+  else if (x < 2.0f)
+    return (32.0f + x*(-60.0f + x*(36.0f - 7.0f*x)))/18.0f;
+
+  return (0.0f);
+}
+
+static float stbir__support_zero(float s, void * user_data)
+{
+  STBIR__UNUSED(s);
+  STBIR__UNUSED(user_data);
+  return 0;
+}
+
+static float stbir__support_zeropoint5(float s, void * user_data)
+{
+  STBIR__UNUSED(s);
+  STBIR__UNUSED(user_data);
+  return 0.5f;
+}
+
+static float stbir__support_one(float s, void * user_data)
+{
+  STBIR__UNUSED(s);
+  STBIR__UNUSED(user_data);
+  return 1;
+}
+
+static float stbir__support_two(float s, void * user_data)
+{
+  STBIR__UNUSED(s);
+  STBIR__UNUSED(user_data);
+  return 2;
+}
+
+// This is the maximum number of input samples that can affect an output sample
+// with the given filter from the output pixel's perspective
+static int stbir__get_filter_pixel_width(stbir__support_callback * support, float scale, void * user_data)
+{
+  STBIR_ASSERT(support != 0);
+
+  if ( scale >= ( 1.0f-stbir__small_float ) ) // upscale
+    return (int)STBIR_CEILF(support(1.0f/scale,user_data) * 2.0f);
+  else
+    return (int)STBIR_CEILF(support(scale,user_data) * 2.0f / scale);
+}
+
+// this is how many coefficents per run of the filter (which is different
+//   from the filter_pixel_width depending on if we are scattering or gathering)
+static int stbir__get_coefficient_width(stbir__sampler * samp, int is_gather, void * user_data)
+{
+  float scale = samp->scale_info.scale;
+  stbir__support_callback * support = samp->filter_support;
+
+  switch( is_gather )
+  {
+    case 1:
+      return (int)STBIR_CEILF(support(1.0f / scale, user_data) * 2.0f);
+    case 2:
+      return (int)STBIR_CEILF(support(scale, user_data) * 2.0f / scale);
+    case 0:
+      return (int)STBIR_CEILF(support(scale, user_data) * 2.0f);
+    default:
+      STBIR_ASSERT( (is_gather >= 0 ) && (is_gather <= 2 ) );
+      return 0;
+  }
+}
+
+static int stbir__get_contributors(stbir__sampler * samp, int is_gather)
+{
+  if (is_gather)
+      return samp->scale_info.output_sub_size;
+  else
+      return (samp->scale_info.input_full_size + samp->filter_pixel_margin * 2);
+}
+
+static int stbir__edge_zero_full( int n, int max )
+{
+  STBIR__UNUSED(n);
+  STBIR__UNUSED(max);
+  return 0; // NOTREACHED
+}
+
+static int stbir__edge_clamp_full( int n, int max )
+{
+  if (n < 0)
+    return 0;
+
+  if (n >= max)
+    return max - 1;
+
+  return n; // NOTREACHED
+}
+
+static int stbir__edge_reflect_full( int n, int max )
+{
+  if (n < 0)
+  {
+    if (n > -max)
+      return -n;
+    else
+      return max - 1;
+  }
+
+  if (n >= max)
+  {
+    int max2 = max * 2;
+    if (n >= max2)
+      return 0;
+    else
+      return max2 - n - 1;
+  }
+
+  return n; // NOTREACHED
+}
+
+static int stbir__edge_wrap_full( int n, int max )
+{
+  if (n >= 0)
+    return (n % max);
+  else
+  {
+    int m = (-n) % max;
+
+    if (m != 0)
+      m = max - m;
+
+    return (m);
+  }
+}
+
+typedef int stbir__edge_wrap_func( int n, int max );
+static stbir__edge_wrap_func * stbir__edge_wrap_slow[] =
+{
+  stbir__edge_clamp_full,    // STBIR_EDGE_CLAMP
+  stbir__edge_reflect_full,  // STBIR_EDGE_REFLECT
+  stbir__edge_wrap_full,     // STBIR_EDGE_WRAP
+  stbir__edge_zero_full,     // STBIR_EDGE_ZERO
+};
+
+stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)
+{
+  // avoid per-pixel switch
+  if (n >= 0 && n < max)
+      return n;
+  return stbir__edge_wrap_slow[edge]( n, max );
+}
+
+#define STBIR__MERGE_RUNS_PIXEL_THRESHOLD 16
+
+// get information on the extents of a sampler
+static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline_extents )
+{
+  int j, stop;
+  int left_margin, right_margin;
+  int min_n = 0x7fffffff, max_n = -0x7fffffff;
+  int min_left = 0x7fffffff, max_left = -0x7fffffff;
+  int min_right = 0x7fffffff, max_right = -0x7fffffff;
+  stbir_edge edge = samp->edge;
+  stbir__contributors* contributors = samp->contributors;
+  int output_sub_size = samp->scale_info.output_sub_size;
+  int input_full_size = samp->scale_info.input_full_size;
+  int filter_pixel_margin = samp->filter_pixel_margin;
+
+  STBIR_ASSERT( samp->is_gather );
+
+  stop = output_sub_size;
+  for (j = 0; j < stop; j++ )
+  {
+    STBIR_ASSERT( contributors[j].n1 >= contributors[j].n0 );
+    if ( contributors[j].n0 < min_n )
+    {
+      min_n = contributors[j].n0;
+      stop = j + filter_pixel_margin;  // if we find a new min, only scan another filter width
+      if ( stop > output_sub_size ) stop = output_sub_size;
+    }
+  }
+
+  stop = 0;
+  for (j = output_sub_size - 1; j >= stop; j-- )
+  {
+    STBIR_ASSERT( contributors[j].n1 >= contributors[j].n0 );
+    if ( contributors[j].n1 > max_n )
+    {
+      max_n = contributors[j].n1;
+      stop = j - filter_pixel_margin;  // if we find a new max, only scan another filter width
+      if (stop<0) stop = 0;
+    }
+  }
+
+  STBIR_ASSERT( scanline_extents->conservative.n0 <= min_n );
+  STBIR_ASSERT( scanline_extents->conservative.n1 >= max_n );
+
+  // now calculate how much into the margins we really read
+  left_margin = 0;
+  if ( min_n < 0 )
+  {
+    left_margin = -min_n;
+    min_n = 0;
+  }
+
+  right_margin = 0;
+  if ( max_n >= input_full_size )
+  {
+    right_margin = max_n - input_full_size + 1;
+    max_n = input_full_size - 1;
+  }
+
+  // index 1 is margin pixel extents (how many pixels we hang over the edge)
+  scanline_extents->edge_sizes[0] = left_margin;
+  scanline_extents->edge_sizes[1] = right_margin;
+
+  // index 2 is pixels read from the input
+  scanline_extents->spans[0].n0 = min_n;
+  scanline_extents->spans[0].n1 = max_n;
+  scanline_extents->spans[0].pixel_offset_for_input = min_n;
+
+  // default to no other input range
+  scanline_extents->spans[1].n0 = 0;
+  scanline_extents->spans[1].n1 = -1;
+  scanline_extents->spans[1].pixel_offset_for_input = 0;
+
+  // don't have to do edge calc for zero clamp
+  if ( edge == STBIR_EDGE_ZERO )
+    return;
+
+  // convert margin pixels to the pixels within the input (min and max)
+  for( j = -left_margin ; j < 0 ; j++ )
+  {
+      int p = stbir__edge_wrap( edge, j, input_full_size );
+      if ( p < min_left )
+        min_left = p;
+      if ( p > max_left )
+        max_left = p;
+  }
+
+  for( j = input_full_size ; j < (input_full_size + right_margin) ; j++ )
+  {
+      int p = stbir__edge_wrap( edge, j, input_full_size );
+      if ( p < min_right )
+        min_right = p;
+      if ( p > max_right )
+        max_right = p;
+  }
+
+  // merge the left margin pixel region if it connects within 4 pixels of main pixel region
+  if ( min_left != 0x7fffffff )
+  {
+    if ( ( ( min_left <= min_n ) && ( ( max_left  + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= min_n ) ) ||
+         ( ( min_n <= min_left ) && ( ( max_n  + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= max_left ) ) )
+    {
+      scanline_extents->spans[0].n0 = min_n = stbir__min( min_n, min_left );
+      scanline_extents->spans[0].n1 = max_n = stbir__max( max_n, max_left );
+      scanline_extents->spans[0].pixel_offset_for_input = min_n;
+      left_margin = 0;
+    }
+  }
+
+  // merge the right margin pixel region if it connects within 4 pixels of main pixel region
+  if ( min_right != 0x7fffffff )
+  {
+    if ( ( ( min_right <= min_n ) && ( ( max_right  + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= min_n ) ) ||
+         ( ( min_n <= min_right ) && ( ( max_n  + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= max_right ) ) )
+    {
+      scanline_extents->spans[0].n0 = min_n = stbir__min( min_n, min_right );
+      scanline_extents->spans[0].n1 = max_n = stbir__max( max_n, max_right );
+      scanline_extents->spans[0].pixel_offset_for_input = min_n;
+      right_margin = 0;
+    }
+  }
+
+  STBIR_ASSERT( scanline_extents->conservative.n0 <= min_n );
+  STBIR_ASSERT( scanline_extents->conservative.n1 >= max_n );
+
+  // you get two ranges when you have the WRAP edge mode and you are doing just the a piece of the resize
+  //   so you need to get a second run of pixels from the opposite side of the scanline (which you
+  //   wouldn't need except for WRAP)
+
+
+  // if we can't merge the min_left range, add it as a second range
+  if ( ( left_margin ) && ( min_left != 0x7fffffff ) )
+  {
+    stbir__span * newspan = scanline_extents->spans + 1;
+    STBIR_ASSERT( right_margin == 0 );
+    if ( min_left < scanline_extents->spans[0].n0 )
+    {
+      scanline_extents->spans[1].pixel_offset_for_input = scanline_extents->spans[0].n0;
+      scanline_extents->spans[1].n0 = scanline_extents->spans[0].n0;
+      scanline_extents->spans[1].n1 = scanline_extents->spans[0].n1;
+      --newspan;
+    }
+    newspan->pixel_offset_for_input = min_left;
+    newspan->n0 = -left_margin;
+    newspan->n1 = ( max_left - min_left ) - left_margin;
+    scanline_extents->edge_sizes[0] = 0;  // don't need to copy the left margin, since we are directly decoding into the margin
+    return;
+  }
+
+  // if we can't merge the min_left range, add it as a second range
+  if ( ( right_margin ) && ( min_right != 0x7fffffff ) )
+  {
+    stbir__span * newspan = scanline_extents->spans + 1;
+    if ( min_right < scanline_extents->spans[0].n0 )
+    {
+      scanline_extents->spans[1].pixel_offset_for_input = scanline_extents->spans[0].n0;
+      scanline_extents->spans[1].n0 = scanline_extents->spans[0].n0;
+      scanline_extents->spans[1].n1 = scanline_extents->spans[0].n1;
+      --newspan;
+    }
+    newspan->pixel_offset_for_input = min_right;
+    newspan->n0 = scanline_extents->spans[1].n1 + 1;
+    newspan->n1 = scanline_extents->spans[1].n1 + 1 + ( max_right - min_right );
+    scanline_extents->edge_sizes[1] = 0;  // don't need to copy the right margin, since we are directly decoding into the margin
+    return;
+  }
+}
+
+static void stbir__calculate_in_pixel_range( int * first_pixel, int * last_pixel, float out_pixel_center, float out_filter_radius, float inv_scale, float out_shift, int input_size, stbir_edge edge )
+{
+  int first, last;
+  float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
+  float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
+
+  float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) * inv_scale;
+  float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) * inv_scale;
+
+  first = (int)(STBIR_FLOORF(in_pixel_influence_lowerbound + 0.5f));
+  last = (int)(STBIR_FLOORF(in_pixel_influence_upperbound - 0.5f));
+
+  if ( edge == STBIR_EDGE_WRAP )
+  {
+    if ( first <= -input_size )
+      first = -(input_size-1);
+    if ( last >= (input_size*2))
+      last = (input_size*2) - 1;
+  }
+
+  *first_pixel = first;
+  *last_pixel = last;
+}
+
+static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_radius, stbir__kernel_callback * kernel, stbir__scale_info * scale_info, int num_contributors, stbir__contributors* contributors, float* coefficient_group, int coefficient_width, stbir_edge edge, void * user_data )
+{
+  int n, end;
+  float inv_scale = scale_info->inv_scale;
+  float out_shift = scale_info->pixel_shift;
+  int input_size  = scale_info->input_full_size;
+  int numerator = scale_info->scale_numerator;
+  int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < num_contributors ) );
+
+  // Looping through out pixels
+  end = num_contributors; if ( polyphase ) end = numerator;
+  for (n = 0; n < end; n++)
+  {
+    int i;
+    int last_non_zero;
+    float out_pixel_center = (float)n + 0.5f;
+    float in_center_of_out = (out_pixel_center + out_shift) * inv_scale;
+
+    int in_first_pixel, in_last_pixel;
+
+    stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, out_pixel_center, out_filter_radius, inv_scale, out_shift, input_size, edge );
+
+    last_non_zero = -1;
+    for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
+    {
+      float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
+      float coeff = kernel(in_center_of_out - in_pixel_center, inv_scale, user_data);
+
+      // kill denormals
+      if ( ( ( coeff < stbir__small_float ) && ( coeff > -stbir__small_float ) ) )
+      {
+        if ( i == 0 )  // if we're at the front, just eat zero contributors
+        {
+          STBIR_ASSERT ( ( in_last_pixel - in_first_pixel ) != 0 ); // there should be at least one contrib
+          ++in_first_pixel;
+          i--;
+          continue;
+        }
+        coeff = 0;  // make sure is fully zero (should keep denormals away)
+      }
+      else
+        last_non_zero = i;
+
+      coefficient_group[i] = coeff;
+    }
+
+    in_last_pixel = last_non_zero+in_first_pixel; // kills trailing zeros
+    contributors->n0 = in_first_pixel;
+    contributors->n1 = in_last_pixel;
+
+    STBIR_ASSERT(contributors->n1 >= contributors->n0);
+
+    ++contributors;
+    coefficient_group += coefficient_width;
+  }
+}
+
+static void stbir__insert_coeff( stbir__contributors * contribs, float * coeffs, int new_pixel, float new_coeff )
+{
+  if ( new_pixel <= contribs->n1 )  // before the end
+  {
+    if ( new_pixel < contribs->n0 ) // before the front?
+    {
+      int j, o = contribs->n0 - new_pixel;
+      for ( j = contribs->n1 - contribs->n0 ; j <= 0 ; j-- )
+        coeffs[ j + o ] = coeffs[ j ];
+      for ( j = 1 ; j < o ; j-- )
+        coeffs[ j ] = coeffs[ 0 ];
+      coeffs[ 0 ] = new_coeff;
+      contribs->n0 = new_pixel;
+    }
+    else
+    {
+      coeffs[ new_pixel - contribs->n0 ] += new_coeff;
+    }
+  }
+  else
+  {
+    int j, e = new_pixel - contribs->n0;
+    for( j = ( contribs->n1 - contribs->n0 ) + 1 ; j < e ; j++ ) // clear in-betweens coeffs if there are any
+      coeffs[j] = 0;
+
+    coeffs[ e ] = new_coeff;
+    contribs->n1 = new_pixel;
+  }
+}
+
+static void stbir__calculate_out_pixel_range( int * first_pixel, int * last_pixel, float in_pixel_center, float in_pixels_radius, float scale, float out_shift, int out_size )
+{
+  float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
+  float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
+  float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale - out_shift;
+  float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale - out_shift;
+  int out_first_pixel = (int)(STBIR_FLOORF(out_pixel_influence_lowerbound + 0.5f));
+  int out_last_pixel = (int)(STBIR_FLOORF(out_pixel_influence_upperbound - 0.5f));
+
+  if ( out_first_pixel < 0 )
+    out_first_pixel = 0;
+  if ( out_last_pixel >= out_size )
+    out_last_pixel = out_size - 1;
+  *first_pixel = out_first_pixel;
+  *last_pixel = out_last_pixel;
+}
+
+static void stbir__calculate_coefficients_for_gather_downsample( int start, int end, float in_pixels_radius, stbir__kernel_callback * kernel, stbir__scale_info * scale_info, int coefficient_width, int num_contributors, stbir__contributors * contributors, float * coefficient_group, void * user_data )
+{
+  int in_pixel;
+  int i;
+  int first_out_inited = -1;
+  float scale = scale_info->scale;
+  float out_shift = scale_info->pixel_shift;
+  int out_size = scale_info->output_sub_size;
+  int numerator = scale_info->scale_numerator;
+  int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < out_size ) );
+
+  STBIR__UNUSED(num_contributors);
+
+  // Loop through the input pixels
+  for (in_pixel = start; in_pixel < end; in_pixel++)
+  {
+    float in_pixel_center = (float)in_pixel + 0.5f;
+    float out_center_of_in = in_pixel_center * scale - out_shift;
+    int out_first_pixel, out_last_pixel;
+
+    stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, in_pixel_center, in_pixels_radius, scale, out_shift, out_size );
+
+    if ( out_first_pixel > out_last_pixel )
+      continue;
+
+    // clamp or exit if we are using polyphase filtering, and the limit is up
+    if ( polyphase )
+    {
+      // when polyphase, you only have to do coeffs up to the numerator count
+      if ( out_first_pixel == numerator )
+        break;
+
+      // don't do any extra work, clamp last pixel at numerator too
+      if ( out_last_pixel >= numerator )
+        out_last_pixel = numerator - 1;
+    }
+
+    for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
+    {
+      float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
+      float x = out_pixel_center - out_center_of_in;
+      float coeff = kernel(x, scale, user_data) * scale;
+
+      // kill the coeff if it's too small (avoid denormals)
+      if ( ( ( coeff < stbir__small_float ) && ( coeff > -stbir__small_float ) ) )
+        coeff = 0.0f;
+
+      {
+        int out = i + out_first_pixel;
+        float * coeffs = coefficient_group + out * coefficient_width;
+        stbir__contributors * contribs = contributors + out;
+
+        // is this the first time this output pixel has been seen?  Init it.
+        if ( out > first_out_inited )
+        {
+          STBIR_ASSERT( out == ( first_out_inited + 1 ) ); // ensure we have only advanced one at time
+          first_out_inited = out;
+          contribs->n0 = in_pixel;
+          contribs->n1 = in_pixel;
+          coeffs[0]  = coeff;
+        }
+        else
+        {
+          // insert on end (always in order)
+          if ( coeffs[0] == 0.0f )  // if the first coefficent is zero, then zap it for this coeffs
+          {
+            STBIR_ASSERT( ( in_pixel - contribs->n0 ) == 1 ); // ensure that when we zap, we're at the 2nd pos
+            contribs->n0 = in_pixel;
+          }
+          contribs->n1 = in_pixel;
+          STBIR_ASSERT( ( in_pixel - contribs->n0 ) < coefficient_width );
+          coeffs[in_pixel - contribs->n0]  = coeff;
+        }
+      }
+    }
+  }
+}
+
+static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter_extent_info* filter_info, stbir__scale_info * scale_info, int num_contributors, stbir__contributors* contributors, float * coefficient_group, int coefficient_width )
+{
+  int input_size = scale_info->input_full_size;
+  int input_last_n1 = input_size - 1;
+  int n, end;
+  int lowest = 0x7fffffff;
+  int highest = -0x7fffffff;
+  int widest = -1;
+  int numerator = scale_info->scale_numerator;
+  int denominator = scale_info->scale_denominator;
+  int polyphase = ( ( scale_info->scale_is_rational ) && ( numerator < num_contributors ) );
+  float * coeffs;
+  stbir__contributors * contribs;
+
+  // weight all the coeffs for each sample
+  coeffs = coefficient_group;
+  contribs = contributors;
+  end = num_contributors; if ( polyphase ) end = numerator;
+  for (n = 0; n < end; n++)
+  {
+    int i;
+    float filter_scale, total_filter = 0;
+    int e;
+
+    // add all contribs
+    e = contribs->n1 - contribs->n0;
+    for( i = 0 ; i <= e ; i++ )
+    {
+      total_filter += coeffs[i];
+      STBIR_ASSERT( ( coeffs[i] >= -2.0f ) && ( coeffs[i] <= 2.0f )  ); // check for wonky weights
+    }
+
+    // rescale
+    if ( ( total_filter < stbir__small_float ) && ( total_filter > -stbir__small_float ) )
+    {
+      // all coeffs are extremely small, just zero it
+      contribs->n1 = contribs->n0;
+      coeffs[0] = 0.0f;
+    }
+    else
+    {
+      // if the total isn't 1.0, rescale everything
+      if ( ( total_filter < (1.0f-stbir__small_float) ) || ( total_filter > (1.0f+stbir__small_float) ) )
+      {
+        filter_scale = 1.0f / total_filter;
+        // scale them all
+        for (i = 0; i <= e; i++)
+          coeffs[i] *= filter_scale;
+      }
+    }
+    ++contribs;
+    coeffs += coefficient_width;
+  }
+
+  // if we have a rational for the scale, we can exploit the polyphaseness to not calculate
+  //   most of the coefficients, so we copy them here
+  if ( polyphase )
+  {
+    stbir__contributors * prev_contribs = contributors;
+    stbir__contributors * cur_contribs = contributors + numerator;
+
+    for( n = numerator ; n < num_contributors ; n++ )
+    {
+      cur_contribs->n0 = prev_contribs->n0 + denominator;
+      cur_contribs->n1 = prev_contribs->n1 + denominator;
+      ++cur_contribs;
+      ++prev_contribs;
+    }
+    stbir_overlapping_memcpy( coefficient_group + numerator * coefficient_width, coefficient_group, ( num_contributors - numerator ) * coefficient_width * sizeof( coeffs[ 0 ] ) );
+  }
+
+  coeffs = coefficient_group;
+  contribs = contributors;
+  for (n = 0; n < num_contributors; n++)
+  {
+    int i;
+
+    // in zero edge mode, just remove out of bounds contribs completely (since their weights are accounted for now)
+    if ( edge == STBIR_EDGE_ZERO )
+    {
+      // shrink the right side if necessary
+      if ( contribs->n1 > input_last_n1 )
+        contribs->n1 = input_last_n1;
+
+      // shrink the left side
+      if ( contribs->n0 < 0 )
+      {
+        int j, left, skips = 0;
+
+        skips = -contribs->n0;
+        contribs->n0 = 0;
+
+        // now move down the weights
+        left = contribs->n1 - contribs->n0 + 1;
+        if ( left > 0 )
+        {
+          for( j = 0 ; j < left ; j++ )
+            coeffs[ j ] = coeffs[ j + skips ];
+        }
+      }
+    }
+    else if ( ( edge == STBIR_EDGE_CLAMP ) || ( edge == STBIR_EDGE_REFLECT ) )
+    {
+      // for clamp and reflect, calculate the true inbounds position (based on edge type) and just add that to the existing weight
+
+      // right hand side first
+      if ( contribs->n1 > input_last_n1 )
+      {
+        int start = contribs->n0;
+        int endi = contribs->n1;
+        contribs->n1 = input_last_n1;
+        for( i = input_size; i <= endi; i++ )
+          stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), coeffs[i-start] );
+      }
+
+      // now check left hand edge
+      if ( contribs->n0 < 0 )
+      {
+        int save_n0;
+        float save_n0_coeff;
+        float * c = coeffs - ( contribs->n0 + 1 );
+
+        // reinsert the coeffs with it reflected or clamped (insert accumulates, if the coeffs exist)
+        for( i = -1 ; i > contribs->n0 ; i-- )
+          stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), *c-- );
+        save_n0 = contribs->n0;
+        save_n0_coeff = c[0]; // save it, since we didn't do the final one (i==n0), because there might be too many coeffs to hold (before we resize)!
+
+        // now slide all the coeffs down (since we have accumulated them in the positive contribs) and reset the first contrib
+        contribs->n0 = 0;
+        for(i = 0 ; i <= contribs->n1 ; i++ )
+          coeffs[i] = coeffs[i-save_n0];
+
+        // now that we have shrunk down the contribs, we insert the first one safely
+        stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( save_n0, input_size ), save_n0_coeff );
+      }
+    }
+
+    if ( contribs->n0 <= contribs->n1 )
+    {
+      int diff = contribs->n1 - contribs->n0 + 1;
+      while ( diff && ( coeffs[ diff-1 ] == 0.0f ) )
+        --diff;
+      contribs->n1 = contribs->n0 + diff - 1;
+
+      if ( contribs->n0 <= contribs->n1 )
+      {
+        if ( contribs->n0 < lowest )
+          lowest = contribs->n0;
+        if ( contribs->n1 > highest )
+          highest = contribs->n1;
+        if ( diff > widest )
+          widest = diff;
+      }
+
+      // re-zero out unused coefficients (if any)
+      for( i = diff ; i < coefficient_width ; i++ )
+        coeffs[i] = 0.0f;
+    }
+
+    ++contribs;
+    coeffs += coefficient_width;
+  }
+  filter_info->lowest = lowest;
+  filter_info->highest = highest;
+  filter_info->widest = widest;
+}
+
+static int stbir__pack_coefficients( int num_contributors, stbir__contributors* contributors, float * coefficents, int coefficient_width, int widest, int row_width )
+{
+  #define STBIR_MOVE_1( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint32*)(dest))[0] = ((stbir_uint32*)(src))[0]; }
+  #define STBIR_MOVE_2( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; }
+  #ifdef STBIR_SIMD
+  #define STBIR_MOVE_4( dest, src ) { stbir__simdf t; STBIR_NO_UNROLL(dest); stbir__simdf_load( t, src ); stbir__simdf_store( dest, t ); }
+  #else
+  #define STBIR_MOVE_4( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; ((stbir_uint64*)(dest))[1] = ((stbir_uint64*)(src))[1]; }
+  #endif
+  if ( coefficient_width != widest )
+  {
+    float * pc = coefficents;
+    float * coeffs = coefficents;
+    float * pc_end = coefficents + num_contributors * widest;
+    switch( widest )
+    {
+      case 1:
+        do {
+          STBIR_MOVE_1( pc, coeffs );
+          ++pc;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 2:
+        do {
+          STBIR_MOVE_2( pc, coeffs );
+          pc += 2;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 3:
+        do {
+          STBIR_MOVE_2( pc, coeffs );
+          STBIR_MOVE_1( pc+2, coeffs+2 );
+          pc += 3;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 4:
+        do {
+          STBIR_MOVE_4( pc, coeffs );
+          pc += 4;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 5:
+        do {
+          STBIR_MOVE_4( pc, coeffs );
+          STBIR_MOVE_1( pc+4, coeffs+4 );
+          pc += 5;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 6:
+        do {
+          STBIR_MOVE_4( pc, coeffs );
+          STBIR_MOVE_2( pc+4, coeffs+4 );
+          pc += 6;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 7:
+        do {
+          STBIR_MOVE_4( pc, coeffs );
+          STBIR_MOVE_2( pc+4, coeffs+4 );
+          STBIR_MOVE_1( pc+6, coeffs+6 );
+          pc += 7;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 8:
+        do {
+          STBIR_MOVE_4( pc, coeffs );
+          STBIR_MOVE_4( pc+4, coeffs+4 );
+          pc += 8;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 9:
+        do {
+          STBIR_MOVE_4( pc, coeffs );
+          STBIR_MOVE_4( pc+4, coeffs+4 );
+          STBIR_MOVE_1( pc+8, coeffs+8 );
+          pc += 9;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 10:
+        do {
+          STBIR_MOVE_4( pc, coeffs );
+          STBIR_MOVE_4( pc+4, coeffs+4 );
+          STBIR_MOVE_2( pc+8, coeffs+8 );
+          pc += 10;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 11:
+        do {
+          STBIR_MOVE_4( pc, coeffs );
+          STBIR_MOVE_4( pc+4, coeffs+4 );
+          STBIR_MOVE_2( pc+8, coeffs+8 );
+          STBIR_MOVE_1( pc+10, coeffs+10 );
+          pc += 11;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      case 12:
+        do {
+          STBIR_MOVE_4( pc, coeffs );
+          STBIR_MOVE_4( pc+4, coeffs+4 );
+          STBIR_MOVE_4( pc+8, coeffs+8 );
+          pc += 12;
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+      default:
+        do {
+          float * copy_end = pc + widest - 4;
+          float * c = coeffs;
+          do {
+            STBIR_NO_UNROLL( pc );
+            STBIR_MOVE_4( pc, c );
+            pc += 4;
+            c += 4;
+          } while ( pc <= copy_end );
+          copy_end += 4;
+          while ( pc < copy_end )
+          {
+            STBIR_MOVE_1( pc, c );
+            ++pc; ++c;
+          }
+          coeffs += coefficient_width;
+        } while ( pc < pc_end );
+        break;
+    }
+  }
+
+  // some horizontal routines read one float off the end (which is then masked off), so put in a sentinal so we don't read an snan or denormal
+  coefficents[ widest * num_contributors ] = 8888.0f;
+
+  // the minimum we might read for unrolled filters widths is 12. So, we need to
+  //   make sure we never read outside the decode buffer, by possibly moving
+  //   the sample area back into the scanline, and putting zeros weights first.
+  // we start on the right edge and check until we're well past the possible
+  //   clip area (2*widest).
+  {
+    stbir__contributors * contribs = contributors + num_contributors - 1;
+    float * coeffs = coefficents + widest * ( num_contributors - 1 );
+
+    // go until no chance of clipping (this is usually less than 8 lops)
+    while ( ( contribs >= contributors ) && ( ( contribs->n0 + widest*2 ) >= row_width ) )
+    {
+      // might we clip??
+      if ( ( contribs->n0 + widest ) > row_width )
+      {
+        int stop_range = widest;
+
+        // if range is larger than 12, it will be handled by generic loops that can terminate on the exact length
+        //   of this contrib n1, instead of a fixed widest amount - so calculate this
+        if ( widest > 12 )
+        {
+          int mod;
+
+          // how far will be read in the n_coeff loop (which depends on the widest count mod4);
+          mod = widest & 3;
+          stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod;
+
+          // the n_coeff loops do a minimum amount of coeffs, so factor that in!
+          if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod;
+        }
+
+        // now see if we still clip with the refined range
+        if ( ( contribs->n0 + stop_range ) > row_width )
+        {
+          int new_n0 = row_width - stop_range;
+          int num = contribs->n1 - contribs->n0 + 1;
+          int backup = contribs->n0 - new_n0;
+          float * from_co = coeffs + num - 1;
+          float * to_co = from_co + backup;
+
+          STBIR_ASSERT( ( new_n0 >= 0 ) && ( new_n0 < contribs->n0 ) );
+
+          // move the coeffs over
+          while( num )
+          {
+            *to_co-- = *from_co--;
+            --num;
+          }
+          // zero new positions
+          while ( to_co >= coeffs )
+            *to_co-- = 0;
+          // set new start point
+          contribs->n0 = new_n0;
+          if ( widest > 12 )
+          {
+            int mod;
+
+            // how far will be read in the n_coeff loop (which depends on the widest count mod4);
+            mod = widest & 3;
+            stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod;
+
+            // the n_coeff loops do a minimum amount of coeffs, so factor that in!
+            if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod;
+          }
+        }
+      }
+      --contribs;
+      coeffs -= widest;
+    }
+  }
+
+  return widest;
+  #undef STBIR_MOVE_1
+  #undef STBIR_MOVE_2
+  #undef STBIR_MOVE_4
+}
+
+static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * other_axis_for_pivot, void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO )
+{
+  int n;
+  float scale = samp->scale_info.scale;
+  stbir__kernel_callback * kernel = samp->filter_kernel;
+  stbir__support_callback * support = samp->filter_support;
+  float inv_scale = samp->scale_info.inv_scale;
+  int input_full_size = samp->scale_info.input_full_size;
+  int gather_num_contributors = samp->num_contributors;
+  stbir__contributors* gather_contributors = samp->contributors;
+  float * gather_coeffs = samp->coefficients;
+  int gather_coefficient_width = samp->coefficient_width;
+
+  switch ( samp->is_gather )
+  {
+    case 1: // gather upsample
+    {
+      float out_pixels_radius = support(inv_scale,user_data) * scale;
+
+      stbir__calculate_coefficients_for_gather_upsample( out_pixels_radius, kernel, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width, samp->edge, user_data );
+
+      STBIR_PROFILE_BUILD_START( cleanup );
+      stbir__cleanup_gathered_coefficients( samp->edge, &samp->extent_info, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width );
+      STBIR_PROFILE_BUILD_END( cleanup );
+    }
+    break;
+
+    case 0: // scatter downsample (only on vertical)
+    case 2: // gather downsample
+    {
+      float in_pixels_radius = support(scale,user_data) * inv_scale;
+      int filter_pixel_margin = samp->filter_pixel_margin;
+      int input_end = input_full_size + filter_pixel_margin;
+
+      // if this is a scatter, we do a downsample gather to get the coeffs, and then pivot after
+      if ( !samp->is_gather )
+      {
+        // check if we are using the same gather downsample on the horizontal as this vertical,
+        //   if so, then we don't have to generate them, we can just pivot from the horizontal.
+        if ( other_axis_for_pivot )
+        {
+          gather_contributors = other_axis_for_pivot->contributors;
+          gather_coeffs = other_axis_for_pivot->coefficients;
+          gather_coefficient_width = other_axis_for_pivot->coefficient_width;
+          gather_num_contributors = other_axis_for_pivot->num_contributors;
+          samp->extent_info.lowest = other_axis_for_pivot->extent_info.lowest;
+          samp->extent_info.highest = other_axis_for_pivot->extent_info.highest;
+          samp->extent_info.widest = other_axis_for_pivot->extent_info.widest;
+          goto jump_right_to_pivot;
+        }
+
+        gather_contributors = samp->gather_prescatter_contributors;
+        gather_coeffs = samp->gather_prescatter_coefficients;
+        gather_coefficient_width = samp->gather_prescatter_coefficient_width;
+        gather_num_contributors = samp->gather_prescatter_num_contributors;
+      }
+
+      stbir__calculate_coefficients_for_gather_downsample( -filter_pixel_margin, input_end, in_pixels_radius, kernel, &samp->scale_info, gather_coefficient_width, gather_num_contributors, gather_contributors, gather_coeffs, user_data );
+
+      STBIR_PROFILE_BUILD_START( cleanup );
+      stbir__cleanup_gathered_coefficients( samp->edge, &samp->extent_info, &samp->scale_info, gather_num_contributors, gather_contributors, gather_coeffs, gather_coefficient_width );
+      STBIR_PROFILE_BUILD_END( cleanup );
+
+      if ( !samp->is_gather )
+      {
+        // if this is a scatter (vertical only), then we need to pivot the coeffs
+        stbir__contributors * scatter_contributors;
+        int highest_set;
+
+        jump_right_to_pivot:
+
+        STBIR_PROFILE_BUILD_START( pivot );
+
+        highest_set = (-filter_pixel_margin) - 1;
+        for (n = 0; n < gather_num_contributors; n++)
+        {
+          int k;
+          int gn0 = gather_contributors->n0, gn1 = gather_contributors->n1;
+          int scatter_coefficient_width = samp->coefficient_width;
+          float * scatter_coeffs = samp->coefficients + ( gn0 + filter_pixel_margin ) * scatter_coefficient_width;
+          float * g_coeffs = gather_coeffs;
+          scatter_contributors = samp->contributors + ( gn0 + filter_pixel_margin );
+
+          for (k = gn0 ; k <= gn1 ; k++ )
+          {
+            float gc = *g_coeffs++;
+            if ( ( k > highest_set ) || ( scatter_contributors->n0 > scatter_contributors->n1 ) )
+            {
+              {
+                // if we are skipping over several contributors, we need to clear the skipped ones
+                stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1);
+                while ( clear_contributors < scatter_contributors )
+                {
+                  clear_contributors->n0 = 0;
+                  clear_contributors->n1 = -1;
+                  ++clear_contributors;
+                }
+              }
+              scatter_contributors->n0 = n;
+              scatter_contributors->n1 = n;
+              scatter_coeffs[0]  = gc;
+              highest_set = k;
+            }
+            else
+            {
+              stbir__insert_coeff( scatter_contributors, scatter_coeffs, n, gc );
+            }
+            ++scatter_contributors;
+            scatter_coeffs += scatter_coefficient_width;
+          }
+
+          ++gather_contributors;
+          gather_coeffs += gather_coefficient_width;
+        }
+
+        // now clear any unset contribs
+        {
+          stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1);
+          stbir__contributors * end_contributors = samp->contributors + samp->num_contributors;
+          while ( clear_contributors < end_contributors )
+          {
+            clear_contributors->n0 = 0;
+            clear_contributors->n1 = -1;
+            ++clear_contributors;
+          }
+        }
+
+        STBIR_PROFILE_BUILD_END( pivot );
+      }
+    }
+    break;
+  }
+}
+
+
+//========================================================================================================
+// scanline decoders and encoders
+
+#define stbir__coder_min_num 1
+#define STB_IMAGE_RESIZE_DO_CODERS
+#include STBIR__HEADER_FILENAME
+
+#define stbir__decode_suffix BGRA
+#define stbir__decode_swizzle
+#define stbir__decode_order0  2
+#define stbir__decode_order1  1
+#define stbir__decode_order2  0
+#define stbir__decode_order3  3
+#define stbir__encode_order0  2
+#define stbir__encode_order1  1
+#define stbir__encode_order2  0
+#define stbir__encode_order3  3
+#define stbir__coder_min_num 4
+#define STB_IMAGE_RESIZE_DO_CODERS
+#include STBIR__HEADER_FILENAME
+
+#define stbir__decode_suffix ARGB
+#define stbir__decode_swizzle
+#define stbir__decode_order0  1
+#define stbir__decode_order1  2
+#define stbir__decode_order2  3
+#define stbir__decode_order3  0
+#define stbir__encode_order0  3
+#define stbir__encode_order1  0
+#define stbir__encode_order2  1
+#define stbir__encode_order3  2
+#define stbir__coder_min_num 4
+#define STB_IMAGE_RESIZE_DO_CODERS
+#include STBIR__HEADER_FILENAME
+
+#define stbir__decode_suffix ABGR
+#define stbir__decode_swizzle
+#define stbir__decode_order0  3
+#define stbir__decode_order1  2
+#define stbir__decode_order2  1
+#define stbir__decode_order3  0
+#define stbir__encode_order0  3
+#define stbir__encode_order1  2
+#define stbir__encode_order2  1
+#define stbir__encode_order3  0
+#define stbir__coder_min_num 4
+#define STB_IMAGE_RESIZE_DO_CODERS
+#include STBIR__HEADER_FILENAME
+
+#define stbir__decode_suffix AR
+#define stbir__decode_swizzle
+#define stbir__decode_order0  1
+#define stbir__decode_order1  0
+#define stbir__decode_order2  3
+#define stbir__decode_order3  2
+#define stbir__encode_order0  1
+#define stbir__encode_order1  0
+#define stbir__encode_order2  3
+#define stbir__encode_order3  2
+#define stbir__coder_min_num 2
+#define STB_IMAGE_RESIZE_DO_CODERS
+#include STBIR__HEADER_FILENAME
+
+
+// fancy alpha means we expand to keep both premultipied and non-premultiplied color channels
+static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_channels )
+{
+  float STBIR_STREAMOUT_PTR(*) out = out_buffer;
+  float const * end_decode = out_buffer + ( width_times_channels / 4 ) * 7;  // decode buffer aligned to end of out_buffer
+  float STBIR_STREAMOUT_PTR(*) decode = (float*)end_decode - width_times_channels;
+
+  // fancy alpha is stored internally as R G B A Rpm Gpm Bpm
+
+  #ifdef STBIR_SIMD
+
+  #ifdef STBIR_SIMD8
+  decode += 16;
+  while ( decode <= end_decode )
+  {
+    stbir__simdf8 d0,d1,a0,a1,p0,p1;
+    STBIR_NO_UNROLL(decode);
+    stbir__simdf8_load( d0, decode-16 );
+    stbir__simdf8_load( d1, decode-16+8 );
+    stbir__simdf8_0123to33333333( a0, d0 );
+    stbir__simdf8_0123to33333333( a1, d1 );
+    stbir__simdf8_mult( p0, a0, d0 );
+    stbir__simdf8_mult( p1, a1, d1 );
+    stbir__simdf8_bot4s( a0, d0, p0 );
+    stbir__simdf8_bot4s( a1, d1, p1 );
+    stbir__simdf8_top4s( d0, d0, p0 );
+    stbir__simdf8_top4s( d1, d1, p1 );
+    stbir__simdf8_store ( out, a0 );
+    stbir__simdf8_store ( out+7, d0 );
+    stbir__simdf8_store ( out+14, a1 );
+    stbir__simdf8_store ( out+21, d1 );
+    decode += 16;
+    out += 28;
+  }
+  decode -= 16;
+  #else
+  decode += 8;
+  while ( decode <= end_decode )
+  {
+    stbir__simdf d0,a0,d1,a1,p0,p1;
+    STBIR_NO_UNROLL(decode);
+    stbir__simdf_load( d0, decode-8 );
+    stbir__simdf_load( d1, decode-8+4 );
+    stbir__simdf_0123to3333( a0, d0 );
+    stbir__simdf_0123to3333( a1, d1 );
+    stbir__simdf_mult( p0, a0, d0 );
+    stbir__simdf_mult( p1, a1, d1 );
+    stbir__simdf_store ( out, d0 );
+    stbir__simdf_store ( out+4, p0 );
+    stbir__simdf_store ( out+7, d1 );
+    stbir__simdf_store ( out+7+4, p1 );
+    decode += 8;
+    out += 14;
+  }
+  decode -= 8;
+  #endif
+
+  // might be one last odd pixel
+  #ifdef STBIR_SIMD8
+  while ( decode < end_decode )
+  #else
+  if ( decode < end_decode )
+  #endif
+  {
+    stbir__simdf d,a,p;
+    stbir__simdf_load( d, decode );
+    stbir__simdf_0123to3333( a, d );
+    stbir__simdf_mult( p, a, d );
+    stbir__simdf_store ( out, d );
+    stbir__simdf_store ( out+4, p );
+    decode += 4;
+    out += 7;
+  }
+
+  #else
+
+  while( decode < end_decode )
+  {
+    float r = decode[0], g = decode[1], b = decode[2], alpha = decode[3];
+    out[0] = r;
+    out[1] = g;
+    out[2] = b;
+    out[3] = alpha;
+    out[4] = r * alpha;
+    out[5] = g * alpha;
+    out[6] = b * alpha;
+    out += 7;
+    decode += 4;
+  }
+
+  #endif
+}
+
+static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_channels )
+{
+  float STBIR_STREAMOUT_PTR(*) out = out_buffer;
+  float const * end_decode = out_buffer + ( width_times_channels / 2 ) * 3;
+  float STBIR_STREAMOUT_PTR(*) decode = (float*)end_decode - width_times_channels;
+
+  //  for fancy alpha, turns into: [X A Xpm][X A Xpm],etc
+
+  #ifdef STBIR_SIMD
+
+  decode += 8;
+  if ( decode <= end_decode )
+  {
+    do {
+      #ifdef STBIR_SIMD8
+      stbir__simdf8 d0,a0,p0;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdf8_load( d0, decode-8 );
+      stbir__simdf8_0123to11331133( p0, d0 );
+      stbir__simdf8_0123to00220022( a0, d0 );
+      stbir__simdf8_mult( p0, p0, a0 );
+
+      stbir__simdf_store2( out, stbir__if_simdf8_cast_to_simdf4( d0 ) );
+      stbir__simdf_store( out+2, stbir__if_simdf8_cast_to_simdf4( p0 ) );
+      stbir__simdf_store2h( out+3, stbir__if_simdf8_cast_to_simdf4( d0 ) );
+
+      stbir__simdf_store2( out+6, stbir__simdf8_gettop4( d0 ) );
+      stbir__simdf_store( out+8, stbir__simdf8_gettop4( p0 ) );
+      stbir__simdf_store2h( out+9, stbir__simdf8_gettop4( d0 ) );
+      #else
+      stbir__simdf d0,a0,d1,a1,p0,p1;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdf_load( d0, decode-8 );
+      stbir__simdf_load( d1, decode-8+4 );
+      stbir__simdf_0123to1133( p0, d0 );
+      stbir__simdf_0123to1133( p1, d1 );
+      stbir__simdf_0123to0022( a0, d0 );
+      stbir__simdf_0123to0022( a1, d1 );
+      stbir__simdf_mult( p0, p0, a0 );
+      stbir__simdf_mult( p1, p1, a1 );
+
+      stbir__simdf_store2( out, d0 );
+      stbir__simdf_store( out+2, p0 );
+      stbir__simdf_store2h( out+3, d0 );
+
+      stbir__simdf_store2( out+6, d1 );
+      stbir__simdf_store( out+8, p1 );
+      stbir__simdf_store2h( out+9, d1 );
+      #endif
+      decode += 8;
+      out += 12;
+    } while ( decode <= end_decode );
+  }
+  decode -= 8;
+  #endif
+
+  while( decode < end_decode )
+  {
+    float x = decode[0], y = decode[1];
+    STBIR_SIMD_NO_UNROLL(decode);
+    out[0] = x;
+    out[1] = y;
+    out[2] = x * y;
+    out += 3;
+    decode += 2;
+  }
+}
+
+static void stbir__fancy_alpha_unweight_4ch( float * encode_buffer, int width_times_channels )
+{
+  float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;
+  float STBIR_SIMD_STREAMOUT_PTR(*) input = encode_buffer;
+  float const * end_output = encode_buffer + width_times_channels;
+
+  // fancy RGBA is stored internally as R G B A Rpm Gpm Bpm
+
+  do {
+    float alpha = input[3];
+#ifdef STBIR_SIMD
+    stbir__simdf i,ia;
+    STBIR_SIMD_NO_UNROLL(encode);
+    if ( alpha < stbir__small_float )
+    {
+      stbir__simdf_load( i, input );
+      stbir__simdf_store( encode, i );
+    }
+    else
+    {
+      stbir__simdf_load1frep4( ia, 1.0f / alpha );
+      stbir__simdf_load( i, input+4 );
+      stbir__simdf_mult( i, i, ia );
+      stbir__simdf_store( encode, i );
+      encode[3] = alpha;
+    }
+#else
+    if ( alpha < stbir__small_float )
+    {
+      encode[0] = input[0];
+      encode[1] = input[1];
+      encode[2] = input[2];
+    }
+    else
+    {
+      float ialpha = 1.0f / alpha;
+      encode[0] = input[4] * ialpha;
+      encode[1] = input[5] * ialpha;
+      encode[2] = input[6] * ialpha;
+    }
+    encode[3] = alpha;
+#endif
+
+    input += 7;
+    encode += 4;
+  } while ( encode < end_output );
+}
+
+//  format: [X A Xpm][X A Xpm] etc
+static void stbir__fancy_alpha_unweight_2ch( float * encode_buffer, int width_times_channels )
+{
+  float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;
+  float STBIR_SIMD_STREAMOUT_PTR(*) input = encode_buffer;
+  float const * end_output = encode_buffer + width_times_channels;
+
+  do {
+    float alpha = input[1];
+    encode[0] = input[0];
+    if ( alpha >= stbir__small_float )
+      encode[0] = input[2] / alpha;
+    encode[1] = alpha;
+
+    input += 3;
+    encode += 2;
+  } while ( encode < end_output );
+}
+
+static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_times_channels )
+{
+  float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;
+  float const * end_decode = decode_buffer + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  {
+    decode += 2 * stbir__simdfX_float_count;
+    while ( decode <= end_decode )
+    {
+      stbir__simdfX d0,a0,d1,a1;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdfX_load( d0, decode-2*stbir__simdfX_float_count );
+      stbir__simdfX_load( d1, decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count );
+      stbir__simdfX_aaa1( a0, d0, STBIR_onesX );
+      stbir__simdfX_aaa1( a1, d1, STBIR_onesX );
+      stbir__simdfX_mult( d0, d0, a0 );
+      stbir__simdfX_mult( d1, d1, a1 );
+      stbir__simdfX_store ( decode-2*stbir__simdfX_float_count, d0 );
+      stbir__simdfX_store ( decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count, d1 );
+      decode += 2 * stbir__simdfX_float_count;
+    }
+    decode -= 2 * stbir__simdfX_float_count;
+
+    // few last pixels remnants
+    #ifdef STBIR_SIMD8
+    while ( decode < end_decode )
+    #else
+    if ( decode < end_decode )
+    #endif
+    {
+      stbir__simdf d,a;
+      stbir__simdf_load( d, decode );
+      stbir__simdf_aaa1( a, d, STBIR__CONSTF(STBIR_ones) );
+      stbir__simdf_mult( d, d, a );
+      stbir__simdf_store ( decode, d );
+      decode += 4;
+    }
+  }
+
+  #else
+
+  while( decode < end_decode )
+  {
+    float alpha = decode[3];
+    decode[0] *= alpha;
+    decode[1] *= alpha;
+    decode[2] *= alpha;
+    decode += 4;
+  }
+
+  #endif
+}
+
+static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_times_channels )
+{
+  float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;
+  float const * end_decode = decode_buffer + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  decode += 2 * stbir__simdfX_float_count;
+  while ( decode <= end_decode )
+  {
+    stbir__simdfX d0,a0,d1,a1;
+    STBIR_NO_UNROLL(decode);
+    stbir__simdfX_load( d0, decode-2*stbir__simdfX_float_count );
+    stbir__simdfX_load( d1, decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count );
+    stbir__simdfX_a1a1( a0, d0, STBIR_onesX );
+    stbir__simdfX_a1a1( a1, d1, STBIR_onesX );
+    stbir__simdfX_mult( d0, d0, a0 );
+    stbir__simdfX_mult( d1, d1, a1 );
+    stbir__simdfX_store ( decode-2*stbir__simdfX_float_count, d0 );
+    stbir__simdfX_store ( decode-2*stbir__simdfX_float_count+stbir__simdfX_float_count, d1 );
+    decode += 2 * stbir__simdfX_float_count;
+  }
+  decode -= 2 * stbir__simdfX_float_count;
+  #endif
+
+  while( decode < end_decode )
+  {
+    float alpha = decode[1];
+    STBIR_SIMD_NO_UNROLL(decode);
+    decode[0] *= alpha;
+    decode += 2;
+  }
+}
+
+static void stbir__simple_alpha_unweight_4ch( float * encode_buffer, int width_times_channels )
+{
+  float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;
+  float const * end_output = encode_buffer + width_times_channels;
+
+  do {
+    float alpha = encode[3];
+
+#ifdef STBIR_SIMD
+    stbir__simdf i,ia;
+    STBIR_SIMD_NO_UNROLL(encode);
+    if ( alpha >= stbir__small_float )
+    {
+      stbir__simdf_load1frep4( ia, 1.0f / alpha );
+      stbir__simdf_load( i, encode );
+      stbir__simdf_mult( i, i, ia );
+      stbir__simdf_store( encode, i );
+      encode[3] = alpha;
+    }
+#else
+    if ( alpha >= stbir__small_float )
+    {
+      float ialpha = 1.0f / alpha;
+      encode[0] *= ialpha;
+      encode[1] *= ialpha;
+      encode[2] *= ialpha;
+    }
+#endif
+    encode += 4;
+  } while ( encode < end_output );
+}
+
+static void stbir__simple_alpha_unweight_2ch( float * encode_buffer, int width_times_channels )
+{
+  float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;
+  float const * end_output = encode_buffer + width_times_channels;
+
+  do {
+    float alpha = encode[1];
+    if ( alpha >= stbir__small_float )
+      encode[0] /= alpha;
+    encode += 2;
+  } while ( encode < end_output );
+}
+
+
+// only used in RGB->BGR or BGR->RGB
+static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_channels )
+{
+  float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;
+  float const * end_decode = decode_buffer + width_times_channels;
+
+  decode += 12;
+  while( decode <= end_decode )
+  {
+    float t0,t1,t2,t3;
+    STBIR_NO_UNROLL(decode);
+    t0 = decode[0]; t1 = decode[3]; t2 = decode[6]; t3 = decode[9];
+    decode[0] = decode[2]; decode[3] = decode[5]; decode[6] = decode[8]; decode[9] = decode[11];
+    decode[2] = t0; decode[5] = t1; decode[8] = t2; decode[11] = t3;
+    decode += 12;
+  }
+  decode -= 12;
+
+  while( decode < end_decode )
+  {
+    float t = decode[0];
+    STBIR_NO_UNROLL(decode);
+    decode[0] = decode[2];
+    decode[2] = t;
+    decode += 3;
+  }
+}
+
+
+
+static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float * output_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO )
+{
+  int channels = stbir_info->channels;
+  int effective_channels = stbir_info->effective_channels;
+  int input_sample_in_bytes = stbir__type_size[stbir_info->input_type] * channels;
+  stbir_edge edge_horizontal = stbir_info->horizontal.edge;
+  stbir_edge edge_vertical = stbir_info->vertical.edge;
+  int row = stbir__edge_wrap(edge_vertical, n, stbir_info->vertical.scale_info.input_full_size);
+  const void* input_plane_data = ( (char *) stbir_info->input_data ) + (ptrdiff_t)row * (ptrdiff_t) stbir_info->input_stride_bytes;
+  stbir__span const * spans = stbir_info->scanline_extents.spans;
+  float* full_decode_buffer = output_buffer - stbir_info->scanline_extents.conservative.n0 * effective_channels;
+
+  // if we are on edge_zero, and we get in here with an out of bounds n, then the calculate filters has failed
+  STBIR_ASSERT( !(edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->vertical.scale_info.input_full_size)) );
+
+  do
+  {
+    float * decode_buffer;
+    void const * input_data;
+    float * end_decode;
+    int width_times_channels;
+    int width;
+
+    if ( spans->n1 < spans->n0 )
+      break;
+
+    width = spans->n1 + 1 - spans->n0;
+    decode_buffer = full_decode_buffer + spans->n0 * effective_channels;
+    end_decode = full_decode_buffer + ( spans->n1 + 1 ) * effective_channels;
+    width_times_channels = width * channels;
+
+    // read directly out of input plane by default
+    input_data = ( (char*)input_plane_data ) + spans->pixel_offset_for_input * input_sample_in_bytes;
+
+    // if we have an input callback, call it to get the input data
+    if ( stbir_info->in_pixels_cb )
+    {
+      // call the callback with a temp buffer (that they can choose to use or not).  the temp is just right aligned memory in the decode_buffer itself
+      input_data = stbir_info->in_pixels_cb( ( (char*) end_decode ) - ( width * input_sample_in_bytes ), input_plane_data, width, spans->pixel_offset_for_input, row, stbir_info->user_data );
+    }
+
+    STBIR_PROFILE_START( decode );
+    // convert the pixels info the float decode_buffer, (we index from end_decode, so that when channels<effective_channels, we are right justified in the buffer)
+    stbir_info->decode_pixels( (float*)end_decode - width_times_channels, width_times_channels, input_data );
+    STBIR_PROFILE_END( decode );
+
+    if (stbir_info->alpha_weight)
+    {
+      STBIR_PROFILE_START( alpha );
+      stbir_info->alpha_weight( decode_buffer, width_times_channels );
+      STBIR_PROFILE_END( alpha );
+    }
+
+    ++spans;
+  } while ( spans <= ( &stbir_info->scanline_extents.spans[1] ) );
+
+  // handle the edge_wrap filter (all other types are handled back out at the calculate_filter stage)
+  // basically the idea here is that if we have the whole scanline in memory, we don't redecode the
+  //   wrapped edge pixels, and instead just memcpy them from the scanline into the edge positions
+  if ( ( edge_horizontal == STBIR_EDGE_WRAP ) && ( stbir_info->scanline_extents.edge_sizes[0] | stbir_info->scanline_extents.edge_sizes[1] ) )
+  {
+    // this code only runs if we're in edge_wrap, and we're doing the entire scanline
+    int e, start_x[2];
+    int input_full_size = stbir_info->horizontal.scale_info.input_full_size;
+
+    start_x[0] = -stbir_info->scanline_extents.edge_sizes[0];  // left edge start x
+    start_x[1] =  input_full_size;                             // right edge
+
+    for( e = 0; e < 2 ; e++ )
+    {
+      // do each margin
+      int margin = stbir_info->scanline_extents.edge_sizes[e];
+      if ( margin )
+      {
+        int x = start_x[e];
+        float * marg = full_decode_buffer + x * effective_channels;
+        float const * src = full_decode_buffer + stbir__edge_wrap(edge_horizontal, x, input_full_size) * effective_channels;
+        STBIR_MEMCPY( marg, src, margin * effective_channels * sizeof(float) );
+      }
+    }
+  }
+}
+
+
+//=================
+// Do 1 channel horizontal routines
+
+#ifdef STBIR_SIMD
+
+#define stbir__1_coeff_only()          \
+    stbir__simdf tot,c;                \
+    STBIR_SIMD_NO_UNROLL(decode);      \
+    stbir__simdf_load1( c, hc );       \
+    stbir__simdf_mult1_mem( tot, c, decode );
+
+#define stbir__2_coeff_only()          \
+    stbir__simdf tot,c,d;              \
+    STBIR_SIMD_NO_UNROLL(decode);      \
+    stbir__simdf_load2z( c, hc );      \
+    stbir__simdf_load2( d, decode );   \
+    stbir__simdf_mult( tot, c, d );    \
+    stbir__simdf_0123to1230( c, tot ); \
+    stbir__simdf_add1( tot, tot, c );
+
+#define stbir__3_coeff_only()                  \
+    stbir__simdf tot,c,t;                      \
+    STBIR_SIMD_NO_UNROLL(decode);              \
+    stbir__simdf_load( c, hc );                \
+    stbir__simdf_mult_mem( tot, c, decode );   \
+    stbir__simdf_0123to1230( c, tot );         \
+    stbir__simdf_0123to2301( t, tot );         \
+    stbir__simdf_add1( tot, tot, c );          \
+    stbir__simdf_add1( tot, tot, t );
+
+#define stbir__store_output_tiny()                \
+    stbir__simdf_store1( output, tot );           \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 1;
+
+#define stbir__4_coeff_start()                 \
+    stbir__simdf tot,c;                        \
+    STBIR_SIMD_NO_UNROLL(decode);              \
+    stbir__simdf_load( c, hc );                \
+    stbir__simdf_mult_mem( tot, c, decode );   \
+
+#define stbir__4_coeff_continue_from_4( ofs )  \
+    STBIR_SIMD_NO_UNROLL(decode);              \
+    stbir__simdf_load( c, hc + (ofs) );        \
+    stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) );
+
+#define stbir__1_coeff_remnant( ofs )          \
+    { stbir__simdf d;                          \
+    stbir__simdf_load1z( c, hc + (ofs) );      \
+    stbir__simdf_load1( d, decode + (ofs) );   \
+    stbir__simdf_madd( tot, tot, d, c ); }
+
+#define stbir__2_coeff_remnant( ofs )          \
+    { stbir__simdf d;                          \
+    stbir__simdf_load2z( c, hc+(ofs) );        \
+    stbir__simdf_load2( d, decode+(ofs) );     \
+    stbir__simdf_madd( tot, tot, d, c ); }
+
+#define stbir__3_coeff_setup()                 \
+    stbir__simdf mask;                         \
+    stbir__simdf_load( mask, STBIR_mask + 3 );
+
+#define stbir__3_coeff_remnant( ofs )                  \
+    stbir__simdf_load( c, hc+(ofs) );                  \
+    stbir__simdf_and( c, c, mask );                    \
+    stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) );
+
+#define stbir__store_output()                     \
+    stbir__simdf_0123to2301( c, tot );            \
+    stbir__simdf_add( tot, tot, c );              \
+    stbir__simdf_0123to1230( c, tot );            \
+    stbir__simdf_add1( tot, tot, c );             \
+    stbir__simdf_store1( output, tot );           \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 1;
+
+#else
+
+#define stbir__1_coeff_only()  \
+    float tot;                 \
+    tot = decode[0]*hc[0];
+
+#define stbir__2_coeff_only()  \
+    float tot;                 \
+    tot = decode[0] * hc[0];   \
+    tot += decode[1] * hc[1];
+
+#define stbir__3_coeff_only()  \
+    float tot;                 \
+    tot = decode[0] * hc[0];   \
+    tot += decode[1] * hc[1];  \
+    tot += decode[2] * hc[2];
+
+#define stbir__store_output_tiny()                \
+    output[0] = tot;                              \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 1;
+
+#define stbir__4_coeff_start()  \
+    float tot0,tot1,tot2,tot3;  \
+    tot0 = decode[0] * hc[0];   \
+    tot1 = decode[1] * hc[1];   \
+    tot2 = decode[2] * hc[2];   \
+    tot3 = decode[3] * hc[3];
+
+#define stbir__4_coeff_continue_from_4( ofs )  \
+    tot0 += decode[0+(ofs)] * hc[0+(ofs)];     \
+    tot1 += decode[1+(ofs)] * hc[1+(ofs)];     \
+    tot2 += decode[2+(ofs)] * hc[2+(ofs)];     \
+    tot3 += decode[3+(ofs)] * hc[3+(ofs)];
+
+#define stbir__1_coeff_remnant( ofs )        \
+    tot0 += decode[0+(ofs)] * hc[0+(ofs)];
+
+#define stbir__2_coeff_remnant( ofs )        \
+    tot0 += decode[0+(ofs)] * hc[0+(ofs)];   \
+    tot1 += decode[1+(ofs)] * hc[1+(ofs)];   \
+
+#define stbir__3_coeff_remnant( ofs )        \
+    tot0 += decode[0+(ofs)] * hc[0+(ofs)];   \
+    tot1 += decode[1+(ofs)] * hc[1+(ofs)];   \
+    tot2 += decode[2+(ofs)] * hc[2+(ofs)];
+
+#define stbir__store_output()                     \
+    output[0] = (tot0+tot2)+(tot1+tot3);          \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 1;
+
+#endif
+
+#define STBIR__horizontal_channels 1
+#define STB_IMAGE_RESIZE_DO_HORIZONTALS
+#include STBIR__HEADER_FILENAME
+
+
+//=================
+// Do 2 channel horizontal routines
+
+#ifdef STBIR_SIMD
+
+#define stbir__1_coeff_only()         \
+    stbir__simdf tot,c,d;             \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    stbir__simdf_load1z( c, hc );     \
+    stbir__simdf_0123to0011( c, c );  \
+    stbir__simdf_load2( d, decode );  \
+    stbir__simdf_mult( tot, d, c );
+
+#define stbir__2_coeff_only()         \
+    stbir__simdf tot,c;               \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    stbir__simdf_load2( c, hc );      \
+    stbir__simdf_0123to0011( c, c );  \
+    stbir__simdf_mult_mem( tot, c, decode );
+
+#define stbir__3_coeff_only()                \
+    stbir__simdf tot,c,cs,d;                 \
+    STBIR_SIMD_NO_UNROLL(decode);            \
+    stbir__simdf_load( cs, hc );             \
+    stbir__simdf_0123to0011( c, cs );        \
+    stbir__simdf_mult_mem( tot, c, decode ); \
+    stbir__simdf_0123to2222( c, cs );        \
+    stbir__simdf_load2z( d, decode+4 );      \
+    stbir__simdf_madd( tot, tot, d, c );
+
+#define stbir__store_output_tiny()                \
+    stbir__simdf_0123to2301( c, tot );            \
+    stbir__simdf_add( tot, tot, c );              \
+    stbir__simdf_store2( output, tot );           \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 2;
+
+#ifdef STBIR_SIMD8
+
+#define stbir__4_coeff_start()                    \
+    stbir__simdf8 tot0,c,cs;                      \
+    STBIR_SIMD_NO_UNROLL(decode);                 \
+    stbir__simdf8_load4b( cs, hc );               \
+    stbir__simdf8_0123to00112233( c, cs );        \
+    stbir__simdf8_mult_mem( tot0, c, decode );
+
+#define stbir__4_coeff_continue_from_4( ofs )        \
+    STBIR_SIMD_NO_UNROLL(decode);                    \
+    stbir__simdf8_load4b( cs, hc + (ofs) );          \
+    stbir__simdf8_0123to00112233( c, cs );           \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*2 );
+
+#define stbir__1_coeff_remnant( ofs )                \
+    { stbir__simdf t;                                \
+    stbir__simdf_load1z( t, hc + (ofs) );            \
+    stbir__simdf_0123to0011( t, t );                 \
+    stbir__simdf_mult_mem( t, t, decode+(ofs)*2 );   \
+    stbir__simdf8_add4( tot0, tot0, t ); }
+
+#define stbir__2_coeff_remnant( ofs )                \
+    { stbir__simdf t;                                \
+    stbir__simdf_load2( t, hc + (ofs) );             \
+    stbir__simdf_0123to0011( t, t );                 \
+    stbir__simdf_mult_mem( t, t, decode+(ofs)*2 );   \
+    stbir__simdf8_add4( tot0, tot0, t ); }
+
+#define stbir__3_coeff_remnant( ofs )                \
+    { stbir__simdf8 d;                               \
+    stbir__simdf8_load4b( cs, hc + (ofs) );          \
+    stbir__simdf8_0123to00112233( c, cs );           \
+    stbir__simdf8_load6z( d, decode+(ofs)*2 );       \
+    stbir__simdf8_madd( tot0, tot0, c, d ); }
+
+#define stbir__store_output()                     \
+    { stbir__simdf t,d;                           \
+    stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 );    \
+    stbir__simdf_0123to2301( d, t );              \
+    stbir__simdf_add( t, t, d );                  \
+    stbir__simdf_store2( output, t );             \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 2; }
+
+#else
+
+#define stbir__4_coeff_start()                   \
+    stbir__simdf tot0,tot1,c,cs;                 \
+    STBIR_SIMD_NO_UNROLL(decode);                \
+    stbir__simdf_load( cs, hc );                 \
+    stbir__simdf_0123to0011( c, cs );            \
+    stbir__simdf_mult_mem( tot0, c, decode );    \
+    stbir__simdf_0123to2233( c, cs );            \
+    stbir__simdf_mult_mem( tot1, c, decode+4 );
+
+#define stbir__4_coeff_continue_from_4( ofs )                \
+    STBIR_SIMD_NO_UNROLL(decode);                            \
+    stbir__simdf_load( cs, hc + (ofs) );                     \
+    stbir__simdf_0123to0011( c, cs );                        \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 );  \
+    stbir__simdf_0123to2233( c, cs );                        \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*2+4 );
+
+#define stbir__1_coeff_remnant( ofs )            \
+    { stbir__simdf d;                            \
+    stbir__simdf_load1z( cs, hc + (ofs) );       \
+    stbir__simdf_0123to0011( c, cs );            \
+    stbir__simdf_load2( d, decode + (ofs) * 2 ); \
+    stbir__simdf_madd( tot0, tot0, d, c ); }
+
+#define stbir__2_coeff_remnant( ofs )                      \
+    stbir__simdf_load2( cs, hc + (ofs) );                  \
+    stbir__simdf_0123to0011( c, cs );                      \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 );
+
+#define stbir__3_coeff_remnant( ofs )                       \
+    { stbir__simdf d;                                       \
+    stbir__simdf_load( cs, hc + (ofs) );                    \
+    stbir__simdf_0123to0011( c, cs );                       \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); \
+    stbir__simdf_0123to2222( c, cs );                       \
+    stbir__simdf_load2z( d, decode + (ofs) * 2 + 4 );       \
+    stbir__simdf_madd( tot1, tot1, d, c ); }
+
+#define stbir__store_output()                     \
+    stbir__simdf_add( tot0, tot0, tot1 );         \
+    stbir__simdf_0123to2301( c, tot0 );           \
+    stbir__simdf_add( tot0, tot0, c );            \
+    stbir__simdf_store2( output, tot0 );          \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 2;
+
+#endif
+
+#else
+
+#define stbir__1_coeff_only()  \
+    float tota,totb,c;         \
+    c = hc[0];                 \
+    tota = decode[0]*c;        \
+    totb = decode[1]*c;
+
+#define stbir__2_coeff_only()  \
+    float tota,totb,c;         \
+    c = hc[0];                 \
+    tota = decode[0]*c;        \
+    totb = decode[1]*c;        \
+    c = hc[1];                 \
+    tota += decode[2]*c;       \
+    totb += decode[3]*c;
+
+// this weird order of add matches the simd
+#define stbir__3_coeff_only()  \
+    float tota,totb,c;         \
+    c = hc[0];                 \
+    tota = decode[0]*c;        \
+    totb = decode[1]*c;        \
+    c = hc[2];                 \
+    tota += decode[4]*c;       \
+    totb += decode[5]*c;       \
+    c = hc[1];                 \
+    tota += decode[2]*c;       \
+    totb += decode[3]*c;
+
+#define stbir__store_output_tiny()                \
+    output[0] = tota;                             \
+    output[1] = totb;                             \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 2;
+
+#define stbir__4_coeff_start()      \
+    float tota0,tota1,tota2,tota3,totb0,totb1,totb2,totb3,c;  \
+    c = hc[0];                      \
+    tota0 = decode[0]*c;            \
+    totb0 = decode[1]*c;            \
+    c = hc[1];                      \
+    tota1 = decode[2]*c;            \
+    totb1 = decode[3]*c;            \
+    c = hc[2];                      \
+    tota2 = decode[4]*c;            \
+    totb2 = decode[5]*c;            \
+    c = hc[3];                      \
+    tota3 = decode[6]*c;            \
+    totb3 = decode[7]*c;
+
+#define stbir__4_coeff_continue_from_4( ofs )  \
+    c = hc[0+(ofs)];                           \
+    tota0 += decode[0+(ofs)*2]*c;              \
+    totb0 += decode[1+(ofs)*2]*c;              \
+    c = hc[1+(ofs)];                           \
+    tota1 += decode[2+(ofs)*2]*c;              \
+    totb1 += decode[3+(ofs)*2]*c;              \
+    c = hc[2+(ofs)];                           \
+    tota2 += decode[4+(ofs)*2]*c;              \
+    totb2 += decode[5+(ofs)*2]*c;              \
+    c = hc[3+(ofs)];                           \
+    tota3 += decode[6+(ofs)*2]*c;              \
+    totb3 += decode[7+(ofs)*2]*c;
+
+#define stbir__1_coeff_remnant( ofs )  \
+    c = hc[0+(ofs)];                   \
+    tota0 += decode[0+(ofs)*2] * c;    \
+    totb0 += decode[1+(ofs)*2] * c;
+
+#define stbir__2_coeff_remnant( ofs )  \
+    c = hc[0+(ofs)];                   \
+    tota0 += decode[0+(ofs)*2] * c;    \
+    totb0 += decode[1+(ofs)*2] * c;    \
+    c = hc[1+(ofs)];                   \
+    tota1 += decode[2+(ofs)*2] * c;    \
+    totb1 += decode[3+(ofs)*2] * c;
+
+#define stbir__3_coeff_remnant( ofs )  \
+    c = hc[0+(ofs)];                   \
+    tota0 += decode[0+(ofs)*2] * c;    \
+    totb0 += decode[1+(ofs)*2] * c;    \
+    c = hc[1+(ofs)];                   \
+    tota1 += decode[2+(ofs)*2] * c;    \
+    totb1 += decode[3+(ofs)*2] * c;    \
+    c = hc[2+(ofs)];                   \
+    tota2 += decode[4+(ofs)*2] * c;    \
+    totb2 += decode[5+(ofs)*2] * c;
+
+#define stbir__store_output()                     \
+    output[0] = (tota0+tota2)+(tota1+tota3);      \
+    output[1] = (totb0+totb2)+(totb1+totb3);      \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 2;
+
+#endif
+
+#define STBIR__horizontal_channels 2
+#define STB_IMAGE_RESIZE_DO_HORIZONTALS
+#include STBIR__HEADER_FILENAME
+
+
+//=================
+// Do 3 channel horizontal routines
+
+#ifdef STBIR_SIMD
+
+#define stbir__1_coeff_only()         \
+    stbir__simdf tot,c,d;             \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    stbir__simdf_load1z( c, hc );     \
+    stbir__simdf_0123to0001( c, c );  \
+    stbir__simdf_load( d, decode );   \
+    stbir__simdf_mult( tot, d, c );
+
+#define stbir__2_coeff_only()         \
+    stbir__simdf tot,c,cs,d;          \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    stbir__simdf_load2( cs, hc );     \
+    stbir__simdf_0123to0000( c, cs ); \
+    stbir__simdf_load( d, decode );   \
+    stbir__simdf_mult( tot, d, c );   \
+    stbir__simdf_0123to1111( c, cs ); \
+    stbir__simdf_load( d, decode+3 ); \
+    stbir__simdf_madd( tot, tot, d, c );
+
+#define stbir__3_coeff_only()            \
+    stbir__simdf tot,c,d,cs;             \
+    STBIR_SIMD_NO_UNROLL(decode);        \
+    stbir__simdf_load( cs, hc );         \
+    stbir__simdf_0123to0000( c, cs );    \
+    stbir__simdf_load( d, decode );      \
+    stbir__simdf_mult( tot, d, c );      \
+    stbir__simdf_0123to1111( c, cs );    \
+    stbir__simdf_load( d, decode+3 );    \
+    stbir__simdf_madd( tot, tot, d, c ); \
+    stbir__simdf_0123to2222( c, cs );    \
+    stbir__simdf_load( d, decode+6 );    \
+    stbir__simdf_madd( tot, tot, d, c );
+
+#define stbir__store_output_tiny()                \
+    stbir__simdf_store2( output, tot );           \
+    stbir__simdf_0123to2301( tot, tot );          \
+    stbir__simdf_store1( output+2, tot );         \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 3;
+
+#ifdef STBIR_SIMD8
+
+// we're loading from the XXXYYY decode by -1 to get the XXXYYY into different halves of the AVX reg fyi
+#define stbir__4_coeff_start()                     \
+    stbir__simdf8 tot0,tot1,c,cs; stbir__simdf t;  \
+    STBIR_SIMD_NO_UNROLL(decode);                  \
+    stbir__simdf8_load4b( cs, hc );                \
+    stbir__simdf8_0123to00001111( c, cs );         \
+    stbir__simdf8_mult_mem( tot0, c, decode - 1 ); \
+    stbir__simdf8_0123to22223333( c, cs );         \
+    stbir__simdf8_mult_mem( tot1, c, decode+6 - 1 );
+
+#define stbir__4_coeff_continue_from_4( ofs )      \
+    STBIR_SIMD_NO_UNROLL(decode);                  \
+    stbir__simdf8_load4b( cs, hc + (ofs) );        \
+    stbir__simdf8_0123to00001111( c, cs );         \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \
+    stbir__simdf8_0123to22223333( c, cs );         \
+    stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*3 + 6 - 1 );
+
+#define stbir__1_coeff_remnant( ofs )                          \
+    STBIR_SIMD_NO_UNROLL(decode);                              \
+    stbir__simdf_load1rep4( t, hc + (ofs) );                   \
+    stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*3 - 1 );
+
+#define stbir__2_coeff_remnant( ofs )                          \
+    STBIR_SIMD_NO_UNROLL(decode);                              \
+    stbir__simdf8_load4b( cs, hc + (ofs) - 2 );                \
+    stbir__simdf8_0123to22223333( c, cs );                     \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 );
+
+ #define stbir__3_coeff_remnant( ofs )                           \
+    STBIR_SIMD_NO_UNROLL(decode);                                \
+    stbir__simdf8_load4b( cs, hc + (ofs) );                      \
+    stbir__simdf8_0123to00001111( c, cs );                       \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \
+    stbir__simdf8_0123to2222( t, cs );                           \
+    stbir__simdf8_madd_mem4( tot1, tot1, t, decode+(ofs)*3 + 6 - 1 );
+
+#define stbir__store_output()                       \
+    stbir__simdf8_add( tot0, tot0, tot1 );          \
+    stbir__simdf_0123to1230( t, stbir__if_simdf8_cast_to_simdf4( tot0 ) ); \
+    stbir__simdf8_add4halves( t, t, tot0 );         \
+    horizontal_coefficients += coefficient_width;   \
+    ++horizontal_contributors;                      \
+    output += 3;                                    \
+    if ( output < output_end )                      \
+    {                                               \
+      stbir__simdf_store( output-3, t );            \
+      continue;                                     \
+    }                                               \
+    { stbir__simdf tt; stbir__simdf_0123to2301( tt, t ); \
+    stbir__simdf_store2( output-3, t );             \
+    stbir__simdf_store1( output+2-3, tt ); }        \
+    break;
+
+
+#else
+
+#define stbir__4_coeff_start()                  \
+    stbir__simdf tot0,tot1,tot2,c,cs;           \
+    STBIR_SIMD_NO_UNROLL(decode);               \
+    stbir__simdf_load( cs, hc );                \
+    stbir__simdf_0123to0001( c, cs );           \
+    stbir__simdf_mult_mem( tot0, c, decode );   \
+    stbir__simdf_0123to1122( c, cs );           \
+    stbir__simdf_mult_mem( tot1, c, decode+4 ); \
+    stbir__simdf_0123to2333( c, cs );           \
+    stbir__simdf_mult_mem( tot2, c, decode+8 );
+
+#define stbir__4_coeff_continue_from_4( ofs )                 \
+    STBIR_SIMD_NO_UNROLL(decode);                             \
+    stbir__simdf_load( cs, hc + (ofs) );                      \
+    stbir__simdf_0123to0001( c, cs );                         \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 );   \
+    stbir__simdf_0123to1122( c, cs );                         \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \
+    stbir__simdf_0123to2333( c, cs );                         \
+    stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*3+8 );
+
+#define stbir__1_coeff_remnant( ofs )         \
+    STBIR_SIMD_NO_UNROLL(decode);             \
+    stbir__simdf_load1z( c, hc + (ofs) );     \
+    stbir__simdf_0123to0001( c, c );          \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 );
+
+#define stbir__2_coeff_remnant( ofs )                       \
+    { stbir__simdf d;                                       \
+    STBIR_SIMD_NO_UNROLL(decode);                           \
+    stbir__simdf_load2z( cs, hc + (ofs) );                  \
+    stbir__simdf_0123to0001( c, cs );                       \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \
+    stbir__simdf_0123to1122( c, cs );                       \
+    stbir__simdf_load2z( d, decode+(ofs)*3+4 );             \
+    stbir__simdf_madd( tot1, tot1, c, d ); }
+
+#define stbir__3_coeff_remnant( ofs )                         \
+    { stbir__simdf d;                                         \
+    STBIR_SIMD_NO_UNROLL(decode);                             \
+    stbir__simdf_load( cs, hc + (ofs) );                      \
+    stbir__simdf_0123to0001( c, cs );                         \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 );   \
+    stbir__simdf_0123to1122( c, cs );                         \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \
+    stbir__simdf_0123to2222( c, cs );                         \
+    stbir__simdf_load1z( d, decode+(ofs)*3+8 );               \
+    stbir__simdf_madd( tot2, tot2, c, d );  }
+
+#define stbir__store_output()                       \
+    stbir__simdf_0123ABCDto3ABx( c, tot0, tot1 );   \
+    stbir__simdf_0123ABCDto23Ax( cs, tot1, tot2 );  \
+    stbir__simdf_0123to1230( tot2, tot2 );          \
+    stbir__simdf_add( tot0, tot0, cs );             \
+    stbir__simdf_add( c, c, tot2 );                 \
+    stbir__simdf_add( tot0, tot0, c );              \
+    horizontal_coefficients += coefficient_width;   \
+    ++horizontal_contributors;                      \
+    output += 3;                                    \
+    if ( output < output_end )                      \
+    {                                               \
+      stbir__simdf_store( output-3, tot0 );         \
+      continue;                                     \
+    }                                               \
+    stbir__simdf_0123to2301( tot1, tot0 );          \
+    stbir__simdf_store2( output-3, tot0 );          \
+    stbir__simdf_store1( output+2-3, tot1 );        \
+    break;
+
+#endif
+
+#else
+
+#define stbir__1_coeff_only()  \
+    float tot0, tot1, tot2, c; \
+    c = hc[0];                 \
+    tot0 = decode[0]*c;        \
+    tot1 = decode[1]*c;        \
+    tot2 = decode[2]*c;
+
+#define stbir__2_coeff_only()  \
+    float tot0, tot1, tot2, c; \
+    c = hc[0];                 \
+    tot0 = decode[0]*c;        \
+    tot1 = decode[1]*c;        \
+    tot2 = decode[2]*c;        \
+    c = hc[1];                 \
+    tot0 += decode[3]*c;       \
+    tot1 += decode[4]*c;       \
+    tot2 += decode[5]*c;
+
+#define stbir__3_coeff_only()  \
+    float tot0, tot1, tot2, c; \
+    c = hc[0];                 \
+    tot0 = decode[0]*c;        \
+    tot1 = decode[1]*c;        \
+    tot2 = decode[2]*c;        \
+    c = hc[1];                 \
+    tot0 += decode[3]*c;       \
+    tot1 += decode[4]*c;       \
+    tot2 += decode[5]*c;       \
+    c = hc[2];                 \
+    tot0 += decode[6]*c;       \
+    tot1 += decode[7]*c;       \
+    tot2 += decode[8]*c;
+
+#define stbir__store_output_tiny()                \
+    output[0] = tot0;                             \
+    output[1] = tot1;                             \
+    output[2] = tot2;                             \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 3;
+
+#define stbir__4_coeff_start()      \
+    float tota0,tota1,tota2,totb0,totb1,totb2,totc0,totc1,totc2,totd0,totd1,totd2,c;  \
+    c = hc[0];                      \
+    tota0 = decode[0]*c;            \
+    tota1 = decode[1]*c;            \
+    tota2 = decode[2]*c;            \
+    c = hc[1];                      \
+    totb0 = decode[3]*c;            \
+    totb1 = decode[4]*c;            \
+    totb2 = decode[5]*c;            \
+    c = hc[2];                      \
+    totc0 = decode[6]*c;            \
+    totc1 = decode[7]*c;            \
+    totc2 = decode[8]*c;            \
+    c = hc[3];                      \
+    totd0 = decode[9]*c;            \
+    totd1 = decode[10]*c;           \
+    totd2 = decode[11]*c;
+
+#define stbir__4_coeff_continue_from_4( ofs )  \
+    c = hc[0+(ofs)];                           \
+    tota0 += decode[0+(ofs)*3]*c;              \
+    tota1 += decode[1+(ofs)*3]*c;              \
+    tota2 += decode[2+(ofs)*3]*c;              \
+    c = hc[1+(ofs)];                           \
+    totb0 += decode[3+(ofs)*3]*c;              \
+    totb1 += decode[4+(ofs)*3]*c;              \
+    totb2 += decode[5+(ofs)*3]*c;              \
+    c = hc[2+(ofs)];                           \
+    totc0 += decode[6+(ofs)*3]*c;              \
+    totc1 += decode[7+(ofs)*3]*c;              \
+    totc2 += decode[8+(ofs)*3]*c;              \
+    c = hc[3+(ofs)];                           \
+    totd0 += decode[9+(ofs)*3]*c;              \
+    totd1 += decode[10+(ofs)*3]*c;             \
+    totd2 += decode[11+(ofs)*3]*c;
+
+#define stbir__1_coeff_remnant( ofs )  \
+    c = hc[0+(ofs)];                   \
+    tota0 += decode[0+(ofs)*3]*c;      \
+    tota1 += decode[1+(ofs)*3]*c;      \
+    tota2 += decode[2+(ofs)*3]*c;
+
+#define stbir__2_coeff_remnant( ofs )  \
+    c = hc[0+(ofs)];                   \
+    tota0 += decode[0+(ofs)*3]*c;      \
+    tota1 += decode[1+(ofs)*3]*c;      \
+    tota2 += decode[2+(ofs)*3]*c;      \
+    c = hc[1+(ofs)];                   \
+    totb0 += decode[3+(ofs)*3]*c;      \
+    totb1 += decode[4+(ofs)*3]*c;      \
+    totb2 += decode[5+(ofs)*3]*c;      \
+
+#define stbir__3_coeff_remnant( ofs )  \
+    c = hc[0+(ofs)];                   \
+    tota0 += decode[0+(ofs)*3]*c;      \
+    tota1 += decode[1+(ofs)*3]*c;      \
+    tota2 += decode[2+(ofs)*3]*c;      \
+    c = hc[1+(ofs)];                   \
+    totb0 += decode[3+(ofs)*3]*c;      \
+    totb1 += decode[4+(ofs)*3]*c;      \
+    totb2 += decode[5+(ofs)*3]*c;      \
+    c = hc[2+(ofs)];                   \
+    totc0 += decode[6+(ofs)*3]*c;      \
+    totc1 += decode[7+(ofs)*3]*c;      \
+    totc2 += decode[8+(ofs)*3]*c;
+
+#define stbir__store_output()                     \
+    output[0] = (tota0+totc0)+(totb0+totd0);      \
+    output[1] = (tota1+totc1)+(totb1+totd1);      \
+    output[2] = (tota2+totc2)+(totb2+totd2);      \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 3;
+
+#endif
+
+#define STBIR__horizontal_channels 3
+#define STB_IMAGE_RESIZE_DO_HORIZONTALS
+#include STBIR__HEADER_FILENAME
+
+//=================
+// Do 4 channel horizontal routines
+
+#ifdef STBIR_SIMD
+
+#define stbir__1_coeff_only()             \
+    stbir__simdf tot,c;                   \
+    STBIR_SIMD_NO_UNROLL(decode);         \
+    stbir__simdf_load1( c, hc );          \
+    stbir__simdf_0123to0000( c, c );      \
+    stbir__simdf_mult_mem( tot, c, decode );
+
+#define stbir__2_coeff_only()                       \
+    stbir__simdf tot,c,cs;                          \
+    STBIR_SIMD_NO_UNROLL(decode);                   \
+    stbir__simdf_load2( cs, hc );                   \
+    stbir__simdf_0123to0000( c, cs );               \
+    stbir__simdf_mult_mem( tot, c, decode );        \
+    stbir__simdf_0123to1111( c, cs );               \
+    stbir__simdf_madd_mem( tot, tot, c, decode+4 );
+
+#define stbir__3_coeff_only()                       \
+    stbir__simdf tot,c,cs;                          \
+    STBIR_SIMD_NO_UNROLL(decode);                   \
+    stbir__simdf_load( cs, hc );                    \
+    stbir__simdf_0123to0000( c, cs );               \
+    stbir__simdf_mult_mem( tot, c, decode );        \
+    stbir__simdf_0123to1111( c, cs );               \
+    stbir__simdf_madd_mem( tot, tot, c, decode+4 ); \
+    stbir__simdf_0123to2222( c, cs );               \
+    stbir__simdf_madd_mem( tot, tot, c, decode+8 );
+
+#define stbir__store_output_tiny()                \
+    stbir__simdf_store( output, tot );            \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 4;
+
+#ifdef STBIR_SIMD8
+
+#define stbir__4_coeff_start()                     \
+    stbir__simdf8 tot0,c,cs; stbir__simdf t;  \
+    STBIR_SIMD_NO_UNROLL(decode);                  \
+    stbir__simdf8_load4b( cs, hc );                \
+    stbir__simdf8_0123to00001111( c, cs );         \
+    stbir__simdf8_mult_mem( tot0, c, decode );     \
+    stbir__simdf8_0123to22223333( c, cs );         \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+8 );
+
+#define stbir__4_coeff_continue_from_4( ofs )                  \
+    STBIR_SIMD_NO_UNROLL(decode);                              \
+    stbir__simdf8_load4b( cs, hc + (ofs) );                    \
+    stbir__simdf8_0123to00001111( c, cs );                     \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 );   \
+    stbir__simdf8_0123to22223333( c, cs );                     \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 );
+
+#define stbir__1_coeff_remnant( ofs )                          \
+    STBIR_SIMD_NO_UNROLL(decode);                              \
+    stbir__simdf_load1rep4( t, hc + (ofs) );                   \
+    stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4 );
+
+#define stbir__2_coeff_remnant( ofs )                          \
+    STBIR_SIMD_NO_UNROLL(decode);                              \
+    stbir__simdf8_load4b( cs, hc + (ofs) - 2 );                \
+    stbir__simdf8_0123to22223333( c, cs );                     \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 );
+
+ #define stbir__3_coeff_remnant( ofs )                         \
+    STBIR_SIMD_NO_UNROLL(decode);                              \
+    stbir__simdf8_load4b( cs, hc + (ofs) );                    \
+    stbir__simdf8_0123to00001111( c, cs );                     \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 );   \
+    stbir__simdf8_0123to2222( t, cs );                         \
+    stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4+8 );
+
+#define stbir__store_output()                      \
+    stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 );     \
+    stbir__simdf_store( output, t );               \
+    horizontal_coefficients += coefficient_width;  \
+    ++horizontal_contributors;                     \
+    output += 4;
+
+#else
+
+#define stbir__4_coeff_start()                        \
+    stbir__simdf tot0,tot1,c,cs;                      \
+    STBIR_SIMD_NO_UNROLL(decode);                     \
+    stbir__simdf_load( cs, hc );                      \
+    stbir__simdf_0123to0000( c, cs );                 \
+    stbir__simdf_mult_mem( tot0, c, decode );         \
+    stbir__simdf_0123to1111( c, cs );                 \
+    stbir__simdf_mult_mem( tot1, c, decode+4 );       \
+    stbir__simdf_0123to2222( c, cs );                 \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+8 ); \
+    stbir__simdf_0123to3333( c, cs );                 \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+12 );
+
+#define stbir__4_coeff_continue_from_4( ofs )                  \
+    STBIR_SIMD_NO_UNROLL(decode);                              \
+    stbir__simdf_load( cs, hc + (ofs) );                       \
+    stbir__simdf_0123to0000( c, cs );                          \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 );    \
+    stbir__simdf_0123to1111( c, cs );                          \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 );  \
+    stbir__simdf_0123to2222( c, cs );                          \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 );  \
+    stbir__simdf_0123to3333( c, cs );                          \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+12 );
+
+#define stbir__1_coeff_remnant( ofs )                       \
+    STBIR_SIMD_NO_UNROLL(decode);                           \
+    stbir__simdf_load1( c, hc + (ofs) );                    \
+    stbir__simdf_0123to0000( c, c );                        \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 );
+
+#define stbir__2_coeff_remnant( ofs )                         \
+    STBIR_SIMD_NO_UNROLL(decode);                             \
+    stbir__simdf_load2( cs, hc + (ofs) );                     \
+    stbir__simdf_0123to0000( c, cs );                         \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 );   \
+    stbir__simdf_0123to1111( c, cs );                         \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 );
+
+#define stbir__3_coeff_remnant( ofs )                          \
+    STBIR_SIMD_NO_UNROLL(decode);                              \
+    stbir__simdf_load( cs, hc + (ofs) );                       \
+    stbir__simdf_0123to0000( c, cs );                          \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 );    \
+    stbir__simdf_0123to1111( c, cs );                          \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 );  \
+    stbir__simdf_0123to2222( c, cs );                          \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 );
+
+#define stbir__store_output()                     \
+    stbir__simdf_add( tot0, tot0, tot1 );         \
+    stbir__simdf_store( output, tot0 );           \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 4;
+
+#endif
+
+#else
+
+#define stbir__1_coeff_only()         \
+    float p0,p1,p2,p3,c;              \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    c = hc[0];                        \
+    p0 = decode[0] * c;               \
+    p1 = decode[1] * c;               \
+    p2 = decode[2] * c;               \
+    p3 = decode[3] * c;
+
+#define stbir__2_coeff_only()         \
+    float p0,p1,p2,p3,c;              \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    c = hc[0];                        \
+    p0 = decode[0] * c;               \
+    p1 = decode[1] * c;               \
+    p2 = decode[2] * c;               \
+    p3 = decode[3] * c;               \
+    c = hc[1];                        \
+    p0 += decode[4] * c;              \
+    p1 += decode[5] * c;              \
+    p2 += decode[6] * c;              \
+    p3 += decode[7] * c;
+
+#define stbir__3_coeff_only()         \
+    float p0,p1,p2,p3,c;              \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    c = hc[0];                        \
+    p0 = decode[0] * c;               \
+    p1 = decode[1] * c;               \
+    p2 = decode[2] * c;               \
+    p3 = decode[3] * c;               \
+    c = hc[1];                        \
+    p0 += decode[4] * c;              \
+    p1 += decode[5] * c;              \
+    p2 += decode[6] * c;              \
+    p3 += decode[7] * c;              \
+    c = hc[2];                        \
+    p0 += decode[8] * c;              \
+    p1 += decode[9] * c;              \
+    p2 += decode[10] * c;             \
+    p3 += decode[11] * c;
+
+#define stbir__store_output_tiny()                \
+    output[0] = p0;                               \
+    output[1] = p1;                               \
+    output[2] = p2;                               \
+    output[3] = p3;                               \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 4;
+
+#define stbir__4_coeff_start()        \
+    float x0,x1,x2,x3,y0,y1,y2,y3,c;  \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    c = hc[0];                        \
+    x0 = decode[0] * c;               \
+    x1 = decode[1] * c;               \
+    x2 = decode[2] * c;               \
+    x3 = decode[3] * c;               \
+    c = hc[1];                        \
+    y0 = decode[4] * c;               \
+    y1 = decode[5] * c;               \
+    y2 = decode[6] * c;               \
+    y3 = decode[7] * c;               \
+    c = hc[2];                        \
+    x0 += decode[8] * c;              \
+    x1 += decode[9] * c;              \
+    x2 += decode[10] * c;             \
+    x3 += decode[11] * c;             \
+    c = hc[3];                        \
+    y0 += decode[12] * c;             \
+    y1 += decode[13] * c;             \
+    y2 += decode[14] * c;             \
+    y3 += decode[15] * c;
+
+#define stbir__4_coeff_continue_from_4( ofs ) \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    c = hc[0+(ofs)];                  \
+    x0 += decode[0+(ofs)*4] * c;      \
+    x1 += decode[1+(ofs)*4] * c;      \
+    x2 += decode[2+(ofs)*4] * c;      \
+    x3 += decode[3+(ofs)*4] * c;      \
+    c = hc[1+(ofs)];                  \
+    y0 += decode[4+(ofs)*4] * c;      \
+    y1 += decode[5+(ofs)*4] * c;      \
+    y2 += decode[6+(ofs)*4] * c;      \
+    y3 += decode[7+(ofs)*4] * c;      \
+    c = hc[2+(ofs)];                  \
+    x0 += decode[8+(ofs)*4] * c;      \
+    x1 += decode[9+(ofs)*4] * c;      \
+    x2 += decode[10+(ofs)*4] * c;     \
+    x3 += decode[11+(ofs)*4] * c;     \
+    c = hc[3+(ofs)];                  \
+    y0 += decode[12+(ofs)*4] * c;     \
+    y1 += decode[13+(ofs)*4] * c;     \
+    y2 += decode[14+(ofs)*4] * c;     \
+    y3 += decode[15+(ofs)*4] * c;
+
+#define stbir__1_coeff_remnant( ofs ) \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    c = hc[0+(ofs)];                  \
+    x0 += decode[0+(ofs)*4] * c;      \
+    x1 += decode[1+(ofs)*4] * c;      \
+    x2 += decode[2+(ofs)*4] * c;      \
+    x3 += decode[3+(ofs)*4] * c;
+
+#define stbir__2_coeff_remnant( ofs ) \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    c = hc[0+(ofs)];                  \
+    x0 += decode[0+(ofs)*4] * c;      \
+    x1 += decode[1+(ofs)*4] * c;      \
+    x2 += decode[2+(ofs)*4] * c;      \
+    x3 += decode[3+(ofs)*4] * c;      \
+    c = hc[1+(ofs)];                  \
+    y0 += decode[4+(ofs)*4] * c;      \
+    y1 += decode[5+(ofs)*4] * c;      \
+    y2 += decode[6+(ofs)*4] * c;      \
+    y3 += decode[7+(ofs)*4] * c;
+
+#define stbir__3_coeff_remnant( ofs ) \
+    STBIR_SIMD_NO_UNROLL(decode);     \
+    c = hc[0+(ofs)];                  \
+    x0 += decode[0+(ofs)*4] * c;      \
+    x1 += decode[1+(ofs)*4] * c;      \
+    x2 += decode[2+(ofs)*4] * c;      \
+    x3 += decode[3+(ofs)*4] * c;      \
+    c = hc[1+(ofs)];                  \
+    y0 += decode[4+(ofs)*4] * c;      \
+    y1 += decode[5+(ofs)*4] * c;      \
+    y2 += decode[6+(ofs)*4] * c;      \
+    y3 += decode[7+(ofs)*4] * c;      \
+    c = hc[2+(ofs)];                  \
+    x0 += decode[8+(ofs)*4] * c;      \
+    x1 += decode[9+(ofs)*4] * c;      \
+    x2 += decode[10+(ofs)*4] * c;     \
+    x3 += decode[11+(ofs)*4] * c;
+
+#define stbir__store_output()                     \
+    output[0] = x0 + y0;                          \
+    output[1] = x1 + y1;                          \
+    output[2] = x2 + y2;                          \
+    output[3] = x3 + y3;                          \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 4;
+
+#endif
+
+#define STBIR__horizontal_channels 4
+#define STB_IMAGE_RESIZE_DO_HORIZONTALS
+#include STBIR__HEADER_FILENAME
+
+
+
+//=================
+// Do 7 channel horizontal routines
+
+#ifdef STBIR_SIMD
+
+#define stbir__1_coeff_only()                   \
+    stbir__simdf tot0,tot1,c;                   \
+    STBIR_SIMD_NO_UNROLL(decode);               \
+    stbir__simdf_load1( c, hc );                \
+    stbir__simdf_0123to0000( c, c );            \
+    stbir__simdf_mult_mem( tot0, c, decode );   \
+    stbir__simdf_mult_mem( tot1, c, decode+3 );
+
+#define stbir__2_coeff_only()                         \
+    stbir__simdf tot0,tot1,c,cs;                      \
+    STBIR_SIMD_NO_UNROLL(decode);                     \
+    stbir__simdf_load2( cs, hc );                     \
+    stbir__simdf_0123to0000( c, cs );                 \
+    stbir__simdf_mult_mem( tot0, c, decode );         \
+    stbir__simdf_mult_mem( tot1, c, decode+3 );       \
+    stbir__simdf_0123to1111( c, cs );                 \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+7 ); \
+    stbir__simdf_madd_mem( tot1, tot1, c,decode+10 );
+
+#define stbir__3_coeff_only()                           \
+    stbir__simdf tot0,tot1,c,cs;                        \
+    STBIR_SIMD_NO_UNROLL(decode);                       \
+    stbir__simdf_load( cs, hc );                        \
+    stbir__simdf_0123to0000( c, cs );                   \
+    stbir__simdf_mult_mem( tot0, c, decode );           \
+    stbir__simdf_mult_mem( tot1, c, decode+3 );         \
+    stbir__simdf_0123to1111( c, cs );                   \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+7 );   \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+10 );  \
+    stbir__simdf_0123to2222( c, cs );                   \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+14 );  \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+17 );
+
+#define stbir__store_output_tiny()                \
+    stbir__simdf_store( output+3, tot1 );         \
+    stbir__simdf_store( output, tot0 );           \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 7;
+
+#ifdef STBIR_SIMD8
+
+#define stbir__4_coeff_start()                     \
+    stbir__simdf8 tot0,tot1,c,cs;                  \
+    STBIR_SIMD_NO_UNROLL(decode);                  \
+    stbir__simdf8_load4b( cs, hc );                \
+    stbir__simdf8_0123to00000000( c, cs );         \
+    stbir__simdf8_mult_mem( tot0, c, decode );     \
+    stbir__simdf8_0123to11111111( c, cs );         \
+    stbir__simdf8_mult_mem( tot1, c, decode+7 );   \
+    stbir__simdf8_0123to22222222( c, cs );         \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+14 );  \
+    stbir__simdf8_0123to33333333( c, cs );         \
+    stbir__simdf8_madd_mem( tot1, tot1, c, decode+21 );
+
+#define stbir__4_coeff_continue_from_4( ofs )                   \
+    STBIR_SIMD_NO_UNROLL(decode);                               \
+    stbir__simdf8_load4b( cs, hc + (ofs) );                     \
+    stbir__simdf8_0123to00000000( c, cs );                      \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 );    \
+    stbir__simdf8_0123to11111111( c, cs );                      \
+    stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 );  \
+    stbir__simdf8_0123to22222222( c, cs );                      \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \
+    stbir__simdf8_0123to33333333( c, cs );                      \
+    stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+21 );
+
+#define stbir__1_coeff_remnant( ofs )                           \
+    STBIR_SIMD_NO_UNROLL(decode);                               \
+    stbir__simdf8_load1b( c, hc + (ofs) );                      \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 );
+
+#define stbir__2_coeff_remnant( ofs )                           \
+    STBIR_SIMD_NO_UNROLL(decode);                               \
+    stbir__simdf8_load1b( c, hc + (ofs) );                      \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 );    \
+    stbir__simdf8_load1b( c, hc + (ofs)+1 );                    \
+    stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 );
+
+#define stbir__3_coeff_remnant( ofs )                           \
+    STBIR_SIMD_NO_UNROLL(decode);                               \
+    stbir__simdf8_load4b( cs, hc + (ofs) );                     \
+    stbir__simdf8_0123to00000000( c, cs );                      \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 );    \
+    stbir__simdf8_0123to11111111( c, cs );                      \
+    stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 );  \
+    stbir__simdf8_0123to22222222( c, cs );                      \
+    stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 );
+
+#define stbir__store_output()                     \
+    stbir__simdf8_add( tot0, tot0, tot1 );        \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 7;                                  \
+    if ( output < output_end )                    \
+    {                                             \
+      stbir__simdf8_store( output-7, tot0 );      \
+      continue;                                   \
+    }                                             \
+    stbir__simdf_store( output-7+3, stbir__simdf_swiz(stbir__simdf8_gettop4(tot0),0,0,1,2) ); \
+    stbir__simdf_store( output-7, stbir__if_simdf8_cast_to_simdf4(tot0) );           \
+    break;
+
+#else
+
+#define stbir__4_coeff_start()                    \
+    stbir__simdf tot0,tot1,tot2,tot3,c,cs;        \
+    STBIR_SIMD_NO_UNROLL(decode);                 \
+    stbir__simdf_load( cs, hc );                  \
+    stbir__simdf_0123to0000( c, cs );             \
+    stbir__simdf_mult_mem( tot0, c, decode );     \
+    stbir__simdf_mult_mem( tot1, c, decode+3 );   \
+    stbir__simdf_0123to1111( c, cs );             \
+    stbir__simdf_mult_mem( tot2, c, decode+7 );   \
+    stbir__simdf_mult_mem( tot3, c, decode+10 );  \
+    stbir__simdf_0123to2222( c, cs );             \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+14 );  \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+17 );  \
+    stbir__simdf_0123to3333( c, cs );                   \
+    stbir__simdf_madd_mem( tot2, tot2, c, decode+21 );  \
+    stbir__simdf_madd_mem( tot3, tot3, c, decode+24 );
+
+#define stbir__4_coeff_continue_from_4( ofs )                   \
+    STBIR_SIMD_NO_UNROLL(decode);                               \
+    stbir__simdf_load( cs, hc + (ofs) );                        \
+    stbir__simdf_0123to0000( c, cs );                           \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 );     \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 );   \
+    stbir__simdf_0123to1111( c, cs );                           \
+    stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+7 );   \
+    stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 );  \
+    stbir__simdf_0123to2222( c, cs );                           \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 );  \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 );  \
+    stbir__simdf_0123to3333( c, cs );                           \
+    stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+21 );  \
+    stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+24 );
+
+#define stbir__1_coeff_remnant( ofs )                           \
+    STBIR_SIMD_NO_UNROLL(decode);                               \
+    stbir__simdf_load1( c, hc + (ofs) );                        \
+    stbir__simdf_0123to0000( c, c );                            \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 );     \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 );   \
+
+#define stbir__2_coeff_remnant( ofs )                           \
+    STBIR_SIMD_NO_UNROLL(decode);                               \
+    stbir__simdf_load2( cs, hc + (ofs) );                       \
+    stbir__simdf_0123to0000( c, cs );                           \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 );     \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 );   \
+    stbir__simdf_0123to1111( c, cs );                           \
+    stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+7 );   \
+    stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 );
+
+#define stbir__3_coeff_remnant( ofs )                           \
+    STBIR_SIMD_NO_UNROLL(decode);                               \
+    stbir__simdf_load( cs, hc + (ofs) );                        \
+    stbir__simdf_0123to0000( c, cs );                           \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7 );     \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 );   \
+    stbir__simdf_0123to1111( c, cs );                           \
+    stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+7 );   \
+    stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 );  \
+    stbir__simdf_0123to2222( c, cs );                           \
+    stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 );  \
+    stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 );
+
+#define stbir__store_output()                     \
+    stbir__simdf_add( tot0, tot0, tot2 );         \
+    stbir__simdf_add( tot1, tot1, tot3 );         \
+    stbir__simdf_store( output+3, tot1 );         \
+    stbir__simdf_store( output, tot0 );           \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 7;
+
+#endif
+
+#else
+
+#define stbir__1_coeff_only()        \
+    float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \
+    c = hc[0];                       \
+    tot0 = decode[0]*c;              \
+    tot1 = decode[1]*c;              \
+    tot2 = decode[2]*c;              \
+    tot3 = decode[3]*c;              \
+    tot4 = decode[4]*c;              \
+    tot5 = decode[5]*c;              \
+    tot6 = decode[6]*c;
+
+#define stbir__2_coeff_only()        \
+    float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \
+    c = hc[0];                       \
+    tot0 = decode[0]*c;              \
+    tot1 = decode[1]*c;              \
+    tot2 = decode[2]*c;              \
+    tot3 = decode[3]*c;              \
+    tot4 = decode[4]*c;              \
+    tot5 = decode[5]*c;              \
+    tot6 = decode[6]*c;              \
+    c = hc[1];                       \
+    tot0 += decode[7]*c;             \
+    tot1 += decode[8]*c;             \
+    tot2 += decode[9]*c;             \
+    tot3 += decode[10]*c;            \
+    tot4 += decode[11]*c;            \
+    tot5 += decode[12]*c;            \
+    tot6 += decode[13]*c;            \
+
+#define stbir__3_coeff_only()        \
+    float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \
+    c = hc[0];                       \
+    tot0 = decode[0]*c;              \
+    tot1 = decode[1]*c;              \
+    tot2 = decode[2]*c;              \
+    tot3 = decode[3]*c;              \
+    tot4 = decode[4]*c;              \
+    tot5 = decode[5]*c;              \
+    tot6 = decode[6]*c;              \
+    c = hc[1];                       \
+    tot0 += decode[7]*c;             \
+    tot1 += decode[8]*c;             \
+    tot2 += decode[9]*c;             \
+    tot3 += decode[10]*c;            \
+    tot4 += decode[11]*c;            \
+    tot5 += decode[12]*c;            \
+    tot6 += decode[13]*c;            \
+    c = hc[2];                       \
+    tot0 += decode[14]*c;            \
+    tot1 += decode[15]*c;            \
+    tot2 += decode[16]*c;            \
+    tot3 += decode[17]*c;            \
+    tot4 += decode[18]*c;            \
+    tot5 += decode[19]*c;            \
+    tot6 += decode[20]*c;            \
+
+#define stbir__store_output_tiny()                \
+    output[0] = tot0;                             \
+    output[1] = tot1;                             \
+    output[2] = tot2;                             \
+    output[3] = tot3;                             \
+    output[4] = tot4;                             \
+    output[5] = tot5;                             \
+    output[6] = tot6;                             \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 7;
+
+#define stbir__4_coeff_start()    \
+    float x0,x1,x2,x3,x4,x5,x6,y0,y1,y2,y3,y4,y5,y6,c; \
+    STBIR_SIMD_NO_UNROLL(decode); \
+    c = hc[0];                    \
+    x0 = decode[0] * c;           \
+    x1 = decode[1] * c;           \
+    x2 = decode[2] * c;           \
+    x3 = decode[3] * c;           \
+    x4 = decode[4] * c;           \
+    x5 = decode[5] * c;           \
+    x6 = decode[6] * c;           \
+    c = hc[1];                    \
+    y0 = decode[7] * c;           \
+    y1 = decode[8] * c;           \
+    y2 = decode[9] * c;           \
+    y3 = decode[10] * c;          \
+    y4 = decode[11] * c;          \
+    y5 = decode[12] * c;          \
+    y6 = decode[13] * c;          \
+    c = hc[2];                    \
+    x0 += decode[14] * c;         \
+    x1 += decode[15] * c;         \
+    x2 += decode[16] * c;         \
+    x3 += decode[17] * c;         \
+    x4 += decode[18] * c;         \
+    x5 += decode[19] * c;         \
+    x6 += decode[20] * c;         \
+    c = hc[3];                    \
+    y0 += decode[21] * c;         \
+    y1 += decode[22] * c;         \
+    y2 += decode[23] * c;         \
+    y3 += decode[24] * c;         \
+    y4 += decode[25] * c;         \
+    y5 += decode[26] * c;         \
+    y6 += decode[27] * c;
+
+#define stbir__4_coeff_continue_from_4( ofs ) \
+    STBIR_SIMD_NO_UNROLL(decode);  \
+    c = hc[0+(ofs)];               \
+    x0 += decode[0+(ofs)*7] * c;   \
+    x1 += decode[1+(ofs)*7] * c;   \
+    x2 += decode[2+(ofs)*7] * c;   \
+    x3 += decode[3+(ofs)*7] * c;   \
+    x4 += decode[4+(ofs)*7] * c;   \
+    x5 += decode[5+(ofs)*7] * c;   \
+    x6 += decode[6+(ofs)*7] * c;   \
+    c = hc[1+(ofs)];               \
+    y0 += decode[7+(ofs)*7] * c;   \
+    y1 += decode[8+(ofs)*7] * c;   \
+    y2 += decode[9+(ofs)*7] * c;   \
+    y3 += decode[10+(ofs)*7] * c;  \
+    y4 += decode[11+(ofs)*7] * c;  \
+    y5 += decode[12+(ofs)*7] * c;  \
+    y6 += decode[13+(ofs)*7] * c;  \
+    c = hc[2+(ofs)];               \
+    x0 += decode[14+(ofs)*7] * c;  \
+    x1 += decode[15+(ofs)*7] * c;  \
+    x2 += decode[16+(ofs)*7] * c;  \
+    x3 += decode[17+(ofs)*7] * c;  \
+    x4 += decode[18+(ofs)*7] * c;  \
+    x5 += decode[19+(ofs)*7] * c;  \
+    x6 += decode[20+(ofs)*7] * c;  \
+    c = hc[3+(ofs)];               \
+    y0 += decode[21+(ofs)*7] * c;  \
+    y1 += decode[22+(ofs)*7] * c;  \
+    y2 += decode[23+(ofs)*7] * c;  \
+    y3 += decode[24+(ofs)*7] * c;  \
+    y4 += decode[25+(ofs)*7] * c;  \
+    y5 += decode[26+(ofs)*7] * c;  \
+    y6 += decode[27+(ofs)*7] * c;
+
+#define stbir__1_coeff_remnant( ofs ) \
+    STBIR_SIMD_NO_UNROLL(decode);  \
+    c = hc[0+(ofs)];               \
+    x0 += decode[0+(ofs)*7] * c;   \
+    x1 += decode[1+(ofs)*7] * c;   \
+    x2 += decode[2+(ofs)*7] * c;   \
+    x3 += decode[3+(ofs)*7] * c;   \
+    x4 += decode[4+(ofs)*7] * c;   \
+    x5 += decode[5+(ofs)*7] * c;   \
+    x6 += decode[6+(ofs)*7] * c;   \
+
+#define stbir__2_coeff_remnant( ofs ) \
+    STBIR_SIMD_NO_UNROLL(decode);  \
+    c = hc[0+(ofs)];               \
+    x0 += decode[0+(ofs)*7] * c;   \
+    x1 += decode[1+(ofs)*7] * c;   \
+    x2 += decode[2+(ofs)*7] * c;   \
+    x3 += decode[3+(ofs)*7] * c;   \
+    x4 += decode[4+(ofs)*7] * c;   \
+    x5 += decode[5+(ofs)*7] * c;   \
+    x6 += decode[6+(ofs)*7] * c;   \
+    c = hc[1+(ofs)];               \
+    y0 += decode[7+(ofs)*7] * c;   \
+    y1 += decode[8+(ofs)*7] * c;   \
+    y2 += decode[9+(ofs)*7] * c;   \
+    y3 += decode[10+(ofs)*7] * c;  \
+    y4 += decode[11+(ofs)*7] * c;  \
+    y5 += decode[12+(ofs)*7] * c;  \
+    y6 += decode[13+(ofs)*7] * c;  \
+
+#define stbir__3_coeff_remnant( ofs ) \
+    STBIR_SIMD_NO_UNROLL(decode);  \
+    c = hc[0+(ofs)];               \
+    x0 += decode[0+(ofs)*7] * c;   \
+    x1 += decode[1+(ofs)*7] * c;   \
+    x2 += decode[2+(ofs)*7] * c;   \
+    x3 += decode[3+(ofs)*7] * c;   \
+    x4 += decode[4+(ofs)*7] * c;   \
+    x5 += decode[5+(ofs)*7] * c;   \
+    x6 += decode[6+(ofs)*7] * c;   \
+    c = hc[1+(ofs)];               \
+    y0 += decode[7+(ofs)*7] * c;   \
+    y1 += decode[8+(ofs)*7] * c;   \
+    y2 += decode[9+(ofs)*7] * c;   \
+    y3 += decode[10+(ofs)*7] * c;  \
+    y4 += decode[11+(ofs)*7] * c;  \
+    y5 += decode[12+(ofs)*7] * c;  \
+    y6 += decode[13+(ofs)*7] * c;  \
+    c = hc[2+(ofs)];               \
+    x0 += decode[14+(ofs)*7] * c;  \
+    x1 += decode[15+(ofs)*7] * c;  \
+    x2 += decode[16+(ofs)*7] * c;  \
+    x3 += decode[17+(ofs)*7] * c;  \
+    x4 += decode[18+(ofs)*7] * c;  \
+    x5 += decode[19+(ofs)*7] * c;  \
+    x6 += decode[20+(ofs)*7] * c;  \
+
+#define stbir__store_output()                     \
+    output[0] = x0 + y0;                          \
+    output[1] = x1 + y1;                          \
+    output[2] = x2 + y2;                          \
+    output[3] = x3 + y3;                          \
+    output[4] = x4 + y4;                          \
+    output[5] = x5 + y5;                          \
+    output[6] = x6 + y6;                          \
+    horizontal_coefficients += coefficient_width; \
+    ++horizontal_contributors;                    \
+    output += 7;
+
+#endif
+
+#define STBIR__horizontal_channels 7
+#define STB_IMAGE_RESIZE_DO_HORIZONTALS
+#include STBIR__HEADER_FILENAME
+
+
+// include all of the vertical resamplers (both scatter and gather versions)
+
+#define STBIR__vertical_channels 1
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 1
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 2
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 2
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 3
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 3
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 4
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 4
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 5
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 5
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 6
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 6
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 7
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 7
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 8
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#include STBIR__HEADER_FILENAME
+
+#define STBIR__vertical_channels 8
+#define STB_IMAGE_RESIZE_DO_VERTICALS
+#define STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#include STBIR__HEADER_FILENAME
+
+typedef void STBIR_VERTICAL_GATHERFUNC( float * output, float const * coeffs, float const ** inputs, float const * input0_end );
+
+static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers[ 8 ] =
+{
+  stbir__vertical_gather_with_1_coeffs,stbir__vertical_gather_with_2_coeffs,stbir__vertical_gather_with_3_coeffs,stbir__vertical_gather_with_4_coeffs,stbir__vertical_gather_with_5_coeffs,stbir__vertical_gather_with_6_coeffs,stbir__vertical_gather_with_7_coeffs,stbir__vertical_gather_with_8_coeffs
+};
+
+static STBIR_VERTICAL_GATHERFUNC * stbir__vertical_gathers_continues[ 8 ] =
+{
+  stbir__vertical_gather_with_1_coeffs_cont,stbir__vertical_gather_with_2_coeffs_cont,stbir__vertical_gather_with_3_coeffs_cont,stbir__vertical_gather_with_4_coeffs_cont,stbir__vertical_gather_with_5_coeffs_cont,stbir__vertical_gather_with_6_coeffs_cont,stbir__vertical_gather_with_7_coeffs_cont,stbir__vertical_gather_with_8_coeffs_cont
+};
+
+typedef void STBIR_VERTICAL_SCATTERFUNC( float ** outputs, float const * coeffs, float const * input, float const * input_end );
+
+static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_sets[ 8 ] =
+{
+  stbir__vertical_scatter_with_1_coeffs,stbir__vertical_scatter_with_2_coeffs,stbir__vertical_scatter_with_3_coeffs,stbir__vertical_scatter_with_4_coeffs,stbir__vertical_scatter_with_5_coeffs,stbir__vertical_scatter_with_6_coeffs,stbir__vertical_scatter_with_7_coeffs,stbir__vertical_scatter_with_8_coeffs
+};
+
+static STBIR_VERTICAL_SCATTERFUNC * stbir__vertical_scatter_blends[ 8 ] =
+{
+  stbir__vertical_scatter_with_1_coeffs_cont,stbir__vertical_scatter_with_2_coeffs_cont,stbir__vertical_scatter_with_3_coeffs_cont,stbir__vertical_scatter_with_4_coeffs_cont,stbir__vertical_scatter_with_5_coeffs_cont,stbir__vertical_scatter_with_6_coeffs_cont,stbir__vertical_scatter_with_7_coeffs_cont,stbir__vertical_scatter_with_8_coeffs_cont
+};
+
+
+static void stbir__encode_scanline( stbir__info const * stbir_info, void *output_buffer_data, float * encode_buffer, int row  STBIR_ONLY_PROFILE_GET_SPLIT_INFO )
+{
+  int num_pixels = stbir_info->horizontal.scale_info.output_sub_size;
+  int channels = stbir_info->channels;
+  int width_times_channels = num_pixels * channels;
+  void * output_buffer;
+
+  // un-alpha weight if we need to
+  if ( stbir_info->alpha_unweight )
+  {
+    STBIR_PROFILE_START( unalpha );
+    stbir_info->alpha_unweight( encode_buffer, width_times_channels );
+    STBIR_PROFILE_END( unalpha );
+  }
+
+  // write directly into output by default
+  output_buffer = output_buffer_data;
+
+  // if we have an output callback, we first convert the decode buffer in place (and then hand that to the callback)
+  if ( stbir_info->out_pixels_cb )
+    output_buffer = encode_buffer;
+
+  STBIR_PROFILE_START( encode );
+  // convert into the output buffer
+  stbir_info->encode_pixels( output_buffer, width_times_channels, encode_buffer );
+  STBIR_PROFILE_END( encode );
+
+  // if we have an output callback, call it to send the data
+  if ( stbir_info->out_pixels_cb )
+    stbir_info->out_pixels_cb( output_buffer_data, num_pixels, row, stbir_info->user_data );
+}
+
+
+// Get the ring buffer pointer for an index
+static float* stbir__get_ring_buffer_entry(stbir__info const * stbir_info, stbir__per_split_info const * split_info, int index )
+{
+  STBIR_ASSERT( index < stbir_info->ring_buffer_num_entries );
+
+  #ifdef STBIR__SEPARATE_ALLOCATIONS
+    return split_info->ring_buffers[ index ];
+  #else
+    return (float*) ( ( (char*) split_info->ring_buffer ) + ( index * stbir_info->ring_buffer_length_bytes ) );
+  #endif
+}
+
+// Get the specified scan line from the ring buffer
+static float* stbir__get_ring_buffer_scanline(stbir__info const * stbir_info, stbir__per_split_info const * split_info, int get_scanline)
+{
+  int ring_buffer_index = (split_info->ring_buffer_begin_index + (get_scanline - split_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
+  return stbir__get_ring_buffer_entry( stbir_info, split_info, ring_buffer_index );
+}
+
+static void stbir__resample_horizontal_gather(stbir__info const * stbir_info, float* output_buffer, float const * input_buffer STBIR_ONLY_PROFILE_GET_SPLIT_INFO )
+{
+  float const * decode_buffer = input_buffer - ( stbir_info->scanline_extents.conservative.n0 * stbir_info->effective_channels );
+
+  STBIR_PROFILE_START( horizontal );
+  if ( ( stbir_info->horizontal.filter_enum == STBIR_FILTER_POINT_SAMPLE ) && ( stbir_info->horizontal.scale_info.scale == 1.0f ) )
+    STBIR_MEMCPY( output_buffer, input_buffer, stbir_info->horizontal.scale_info.output_sub_size * sizeof( float ) * stbir_info->effective_channels );
+  else
+    stbir_info->horizontal_gather_channels( output_buffer, stbir_info->horizontal.scale_info.output_sub_size, decode_buffer, stbir_info->horizontal.contributors, stbir_info->horizontal.coefficients, stbir_info->horizontal.coefficient_width );
+  STBIR_PROFILE_END( horizontal );
+}
+
+static void stbir__resample_vertical_gather(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n, int contrib_n0, int contrib_n1, float const * vertical_coefficients )
+{
+  float* encode_buffer = split_info->vertical_buffer;
+  float* decode_buffer = split_info->decode_buffer;
+  int vertical_first = stbir_info->vertical_first;
+  int width = (vertical_first) ? ( stbir_info->scanline_extents.conservative.n1-stbir_info->scanline_extents.conservative.n0+1 ) : stbir_info->horizontal.scale_info.output_sub_size;
+  int width_times_channels = stbir_info->effective_channels * width;
+
+  STBIR_ASSERT( stbir_info->vertical.is_gather );
+
+  // loop over the contributing scanlines and scale into the buffer
+  STBIR_PROFILE_START( vertical );
+  {
+    int k = 0, total = contrib_n1 - contrib_n0 + 1;
+    STBIR_ASSERT( total > 0 );
+    do {
+      float const * inputs[8];
+      int i, cnt = total; if ( cnt > 8 ) cnt = 8;
+      for( i = 0 ; i < cnt ; i++ )
+        inputs[ i ] = stbir__get_ring_buffer_scanline(stbir_info, split_info, k+i+contrib_n0 );
+
+      // call the N scanlines at a time function (up to 8 scanlines of blending at once)
+      ((k==0)?stbir__vertical_gathers:stbir__vertical_gathers_continues)[cnt-1]( (vertical_first) ? decode_buffer : encode_buffer, vertical_coefficients + k, inputs, inputs[0] + width_times_channels );
+      k += cnt;
+      total -= cnt;
+    } while ( total );
+  }
+  STBIR_PROFILE_END( vertical );
+
+  if ( vertical_first )
+  {
+    // Now resample the gathered vertical data in the horizontal axis into the encode buffer
+    stbir__resample_horizontal_gather(stbir_info, encode_buffer, decode_buffer  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+  }
+
+  stbir__encode_scanline( stbir_info, ( (char *) stbir_info->output_data ) + ((ptrdiff_t)n * (ptrdiff_t)stbir_info->output_stride_bytes),
+                          encode_buffer, n  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+}
+
+static void stbir__decode_and_resample_for_vertical_gather_loop(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n)
+{
+  int ring_buffer_index;
+  float* ring_buffer;
+
+  // Decode the nth scanline from the source image into the decode buffer.
+  stbir__decode_scanline( stbir_info, n, split_info->decode_buffer  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+
+  // update new end scanline
+  split_info->ring_buffer_last_scanline = n;
+
+  // get ring buffer
+  ring_buffer_index = (split_info->ring_buffer_begin_index + (split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
+  ring_buffer = stbir__get_ring_buffer_entry(stbir_info, split_info, ring_buffer_index);
+
+  // Now resample it into the ring buffer.
+  stbir__resample_horizontal_gather( stbir_info, ring_buffer, split_info->decode_buffer  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+
+  // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
+}
+
+static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__per_split_info* split_info, int split_count )
+{
+  int y, start_output_y, end_output_y;
+  stbir__contributors* vertical_contributors = stbir_info->vertical.contributors;
+  float const * vertical_coefficients = stbir_info->vertical.coefficients;
+
+  STBIR_ASSERT( stbir_info->vertical.is_gather );
+
+  start_output_y = split_info->start_output_y;
+  end_output_y = split_info[split_count-1].end_output_y;
+
+  vertical_contributors += start_output_y;
+  vertical_coefficients += start_output_y * stbir_info->vertical.coefficient_width;
+
+  // initialize the ring buffer for gathering
+  split_info->ring_buffer_begin_index = 0;
+  split_info->ring_buffer_first_scanline = stbir_info->vertical.extent_info.lowest;
+  split_info->ring_buffer_last_scanline = split_info->ring_buffer_first_scanline - 1; // means "empty"
+
+  for (y = start_output_y; y < end_output_y; y++)
+  {
+    int in_first_scanline, in_last_scanline;
+
+    in_first_scanline = vertical_contributors->n0;
+    in_last_scanline = vertical_contributors->n1;
+
+    // make sure the indexing hasn't broken
+    STBIR_ASSERT( in_first_scanline >= split_info->ring_buffer_first_scanline );
+
+    // Load in new scanlines
+    while (in_last_scanline > split_info->ring_buffer_last_scanline)
+    {
+      STBIR_ASSERT( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) <= stbir_info->ring_buffer_num_entries );
+
+      // make sure there was room in the ring buffer when we add new scanlines
+      if ( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) == stbir_info->ring_buffer_num_entries )
+      {
+        split_info->ring_buffer_first_scanline++;
+        split_info->ring_buffer_begin_index++;
+      }
+
+      if ( stbir_info->vertical_first )
+      {
+        float * ring_buffer = stbir__get_ring_buffer_scanline( stbir_info, split_info, ++split_info->ring_buffer_last_scanline );
+        // Decode the nth scanline from the source image into the decode buffer.
+        stbir__decode_scanline( stbir_info, split_info->ring_buffer_last_scanline, ring_buffer  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+      }
+      else
+      {
+        stbir__decode_and_resample_for_vertical_gather_loop(stbir_info, split_info, split_info->ring_buffer_last_scanline + 1);
+      }
+    }
+
+    // Now all buffers should be ready to write a row of vertical sampling, so do it.
+    stbir__resample_vertical_gather(stbir_info, split_info, y, in_first_scanline, in_last_scanline, vertical_coefficients );
+
+    ++vertical_contributors;
+    vertical_coefficients += stbir_info->vertical.coefficient_width;
+  }
+}
+
+#define STBIR__FLOAT_EMPTY_MARKER 3.0e+38F
+#define STBIR__FLOAT_BUFFER_IS_EMPTY(ptr) ((ptr)[0]==STBIR__FLOAT_EMPTY_MARKER)
+
+static void stbir__encode_first_scanline_from_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info)
+{
+  // evict a scanline out into the output buffer
+  float* ring_buffer_entry = stbir__get_ring_buffer_entry(stbir_info, split_info, split_info->ring_buffer_begin_index );
+
+  // dump the scanline out
+  stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (ptrdiff_t)split_info->ring_buffer_first_scanline * (ptrdiff_t)stbir_info->output_stride_bytes ), ring_buffer_entry, split_info->ring_buffer_first_scanline  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+
+  // mark it as empty
+  ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER;
+
+  // advance the first scanline
+  split_info->ring_buffer_first_scanline++;
+  if ( ++split_info->ring_buffer_begin_index == stbir_info->ring_buffer_num_entries )
+    split_info->ring_buffer_begin_index = 0;
+}
+
+static void stbir__horizontal_resample_and_encode_first_scanline_from_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info)
+{
+  // evict a scanline out into the output buffer
+
+  float* ring_buffer_entry = stbir__get_ring_buffer_entry(stbir_info, split_info, split_info->ring_buffer_begin_index );
+
+  // Now resample it into the buffer.
+  stbir__resample_horizontal_gather( stbir_info, split_info->vertical_buffer, ring_buffer_entry  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+
+  // dump the scanline out
+  stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (ptrdiff_t)split_info->ring_buffer_first_scanline * (ptrdiff_t)stbir_info->output_stride_bytes ), split_info->vertical_buffer, split_info->ring_buffer_first_scanline  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+
+  // mark it as empty
+  ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER;
+
+  // advance the first scanline
+  split_info->ring_buffer_first_scanline++;
+  if ( ++split_info->ring_buffer_begin_index == stbir_info->ring_buffer_num_entries )
+    split_info->ring_buffer_begin_index = 0;
+}
+
+static void stbir__resample_vertical_scatter(stbir__info const * stbir_info, stbir__per_split_info* split_info, int n0, int n1, float const * vertical_coefficients, float const * vertical_buffer, float const * vertical_buffer_end )
+{
+  STBIR_ASSERT( !stbir_info->vertical.is_gather );
+
+  STBIR_PROFILE_START( vertical );
+  {
+    int k = 0, total = n1 - n0 + 1;
+    STBIR_ASSERT( total > 0 );
+    do {
+      float * outputs[8];
+      int i, n = total; if ( n > 8 ) n = 8;
+      for( i = 0 ; i < n ; i++ )
+      {
+        outputs[ i ] = stbir__get_ring_buffer_scanline(stbir_info, split_info, k+i+n0 );
+        if ( ( i ) && ( STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[i] ) != STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[0] ) ) ) // make sure runs are of the same type
+        {
+          n = i;
+          break;
+        }
+      }
+      // call the scatter to N scanlines at a time function (up to 8 scanlines of scattering at once)
+      ((STBIR__FLOAT_BUFFER_IS_EMPTY( outputs[0] ))?stbir__vertical_scatter_sets:stbir__vertical_scatter_blends)[n-1]( outputs, vertical_coefficients + k, vertical_buffer, vertical_buffer_end );
+      k += n;
+      total -= n;
+    } while ( total );
+  }
+
+  STBIR_PROFILE_END( vertical );
+}
+
+typedef void stbir__handle_scanline_for_scatter_func(stbir__info const * stbir_info, stbir__per_split_info* split_info);
+
+static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir__per_split_info* split_info, int split_count )
+{
+  int y, start_output_y, end_output_y, start_input_y, end_input_y;
+  stbir__contributors* vertical_contributors = stbir_info->vertical.contributors;
+  float const * vertical_coefficients = stbir_info->vertical.coefficients;
+  stbir__handle_scanline_for_scatter_func * handle_scanline_for_scatter;
+  void * scanline_scatter_buffer;
+  void * scanline_scatter_buffer_end;
+  int on_first_input_y, last_input_y;
+
+  STBIR_ASSERT( !stbir_info->vertical.is_gather );
+
+  start_output_y = split_info->start_output_y;
+  end_output_y = split_info[split_count-1].end_output_y;  // may do multiple split counts
+
+  start_input_y = split_info->start_input_y;
+  end_input_y = split_info[split_count-1].end_input_y;
+
+  // adjust for starting offset start_input_y
+  y = start_input_y + stbir_info->vertical.filter_pixel_margin;
+  vertical_contributors += y ;
+  vertical_coefficients += stbir_info->vertical.coefficient_width * y;
+
+  if ( stbir_info->vertical_first )
+  {
+    handle_scanline_for_scatter = stbir__horizontal_resample_and_encode_first_scanline_from_scatter;
+    scanline_scatter_buffer = split_info->decode_buffer;
+    scanline_scatter_buffer_end = ( (char*) scanline_scatter_buffer ) + sizeof( float ) * stbir_info->effective_channels * (stbir_info->scanline_extents.conservative.n1-stbir_info->scanline_extents.conservative.n0+1);
+  }
+  else
+  {
+    handle_scanline_for_scatter = stbir__encode_first_scanline_from_scatter;
+    scanline_scatter_buffer = split_info->vertical_buffer;
+    scanline_scatter_buffer_end = ( (char*) scanline_scatter_buffer ) + sizeof( float ) * stbir_info->effective_channels * stbir_info->horizontal.scale_info.output_sub_size;
+  }
+
+  // initialize the ring buffer for scattering
+  split_info->ring_buffer_first_scanline = start_output_y;
+  split_info->ring_buffer_last_scanline = -1;
+  split_info->ring_buffer_begin_index = -1;
+
+  // mark all the buffers as empty to start
+  for( y = 0 ; y < stbir_info->ring_buffer_num_entries ; y++ )
+    stbir__get_ring_buffer_entry( stbir_info, split_info, y )[0] = STBIR__FLOAT_EMPTY_MARKER; // only used on scatter
+
+  // do the loop in input space
+  on_first_input_y = 1; last_input_y = start_input_y;
+  for (y = start_input_y ; y < end_input_y; y++)
+  {
+    int out_first_scanline, out_last_scanline;
+
+    out_first_scanline = vertical_contributors->n0;
+    out_last_scanline = vertical_contributors->n1;
+
+    STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
+
+    if ( ( out_last_scanline >= out_first_scanline ) && ( ( ( out_first_scanline >= start_output_y ) && ( out_first_scanline < end_output_y ) ) || ( ( out_last_scanline >= start_output_y ) && ( out_last_scanline < end_output_y ) ) ) )
+    {
+      float const * vc = vertical_coefficients;
+
+      // keep track of the range actually seen for the next resize
+      last_input_y = y;
+      if ( ( on_first_input_y ) && ( y > start_input_y ) )
+        split_info->start_input_y = y;
+      on_first_input_y = 0;
+
+      // clip the region
+      if ( out_first_scanline < start_output_y )
+      {
+        vc += start_output_y - out_first_scanline;
+        out_first_scanline = start_output_y;
+      }
+
+      if ( out_last_scanline >= end_output_y )
+        out_last_scanline = end_output_y - 1;
+
+      // if very first scanline, init the index
+      if (split_info->ring_buffer_begin_index < 0)
+        split_info->ring_buffer_begin_index = out_first_scanline - start_output_y;
+
+      STBIR_ASSERT( split_info->ring_buffer_begin_index <= out_first_scanline );
+
+      // Decode the nth scanline from the source image into the decode buffer.
+      stbir__decode_scanline( stbir_info, y, split_info->decode_buffer  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+
+      // When horizontal first, we resample horizontally into the vertical buffer before we scatter it out
+      if ( !stbir_info->vertical_first )
+        stbir__resample_horizontal_gather( stbir_info, split_info->vertical_buffer, split_info->decode_buffer  STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+
+      // Now it's sitting in the buffer ready to be distributed into the ring buffers.
+
+      // evict from the ringbuffer, if we need are full
+      if ( ( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) == stbir_info->ring_buffer_num_entries ) &&
+           ( out_last_scanline > split_info->ring_buffer_last_scanline ) )
+        handle_scanline_for_scatter( stbir_info, split_info );
+
+      // Now the horizontal buffer is ready to write to all ring buffer rows, so do it.
+      stbir__resample_vertical_scatter(stbir_info, split_info, out_first_scanline, out_last_scanline, vc, (float*)scanline_scatter_buffer, (float*)scanline_scatter_buffer_end );
+
+      // update the end of the buffer
+      if ( out_last_scanline > split_info->ring_buffer_last_scanline )
+        split_info->ring_buffer_last_scanline = out_last_scanline;
+    }
+    ++vertical_contributors;
+    vertical_coefficients += stbir_info->vertical.coefficient_width;
+  }
+
+  // now evict the scanlines that are left over in the ring buffer
+  while ( split_info->ring_buffer_first_scanline < end_output_y )
+    handle_scanline_for_scatter(stbir_info, split_info);
+
+  // update the end_input_y if we do multiple resizes with the same data
+  ++last_input_y;
+  for( y = 0 ; y < split_count; y++ )
+    if ( split_info[y].end_input_y > last_input_y )
+      split_info[y].end_input_y = last_input_y;
+}
+
+
+static stbir__kernel_callback * stbir__builtin_kernels[] =   { 0, stbir__filter_trapezoid,  stbir__filter_triangle, stbir__filter_cubic, stbir__filter_catmullrom, stbir__filter_mitchell, stbir__filter_point };
+static stbir__support_callback * stbir__builtin_supports[] = { 0, stbir__support_trapezoid, stbir__support_one,     stbir__support_two,  stbir__support_two,       stbir__support_two,     stbir__support_zeropoint5 };
+
+static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir__kernel_callback * kernel, stbir__support_callback * support, stbir_edge edge, stbir__scale_info * scale_info, int always_gather, void * user_data )
+{
+  // set filter
+  if (filter == 0)
+  {
+    filter = STBIR_DEFAULT_FILTER_DOWNSAMPLE; // default to downsample
+    if (scale_info->scale >= ( 1.0f - stbir__small_float ) )
+    {
+      if ( (scale_info->scale <= ( 1.0f + stbir__small_float ) ) && ( STBIR_CEILF(scale_info->pixel_shift) == scale_info->pixel_shift ) )
+        filter = STBIR_FILTER_POINT_SAMPLE;
+      else
+        filter = STBIR_DEFAULT_FILTER_UPSAMPLE;
+    }
+  }
+  samp->filter_enum = filter;
+
+  STBIR_ASSERT(samp->filter_enum != 0);
+  STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER);
+  samp->filter_kernel = stbir__builtin_kernels[ filter ];
+  samp->filter_support = stbir__builtin_supports[ filter ];
+
+  if ( kernel && support )
+  {
+    samp->filter_kernel = kernel;
+    samp->filter_support = support;
+    samp->filter_enum = STBIR_FILTER_OTHER;
+  }
+
+  samp->edge = edge;
+  samp->filter_pixel_width  = stbir__get_filter_pixel_width (samp->filter_support, scale_info->scale, user_data );
+  // Gather is always better, but in extreme downsamples, you have to most or all of the data in memory
+  //    For horizontal, we always have all the pixels, so we always use gather here (always_gather==1).
+  //    For vertical, we use gather if scaling up (which means we will have samp->filter_pixel_width
+  //    scanlines in memory at once).
+  samp->is_gather = 0;
+  if ( scale_info->scale >= ( 1.0f - stbir__small_float ) )
+    samp->is_gather = 1;
+  else if ( ( always_gather ) || ( samp->filter_pixel_width <= STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT ) )
+    samp->is_gather = 2;
+
+  // pre calculate stuff based on the above
+  samp->coefficient_width = stbir__get_coefficient_width(samp, samp->is_gather, user_data);
+
+  if ( edge == STBIR_EDGE_WRAP )
+    if ( samp->filter_pixel_width > ( scale_info->input_full_size * 2 ) )  // this can only happen when shrinking to a single pixel
+      samp->filter_pixel_width = scale_info->input_full_size * 2;
+
+  // This is how much to expand buffers to account for filters seeking outside
+  // the image boundaries.
+  samp->filter_pixel_margin = samp->filter_pixel_width / 2;
+
+  samp->num_contributors = stbir__get_contributors(samp, samp->is_gather);
+  samp->contributors_size = samp->num_contributors * sizeof(stbir__contributors);
+  samp->coefficients_size = samp->num_contributors * samp->coefficient_width * sizeof(float) + sizeof(float); // extra sizeof(float) is padding
+
+  samp->gather_prescatter_contributors = 0;
+  samp->gather_prescatter_coefficients = 0;
+  if ( samp->is_gather == 0 )
+  {
+    samp->gather_prescatter_coefficient_width = samp->filter_pixel_width;
+    samp->gather_prescatter_num_contributors  = stbir__get_contributors(samp, 2);
+    samp->gather_prescatter_contributors_size = samp->gather_prescatter_num_contributors * sizeof(stbir__contributors);
+    samp->gather_prescatter_coefficients_size = samp->gather_prescatter_num_contributors * samp->gather_prescatter_coefficient_width * sizeof(float);
+  }
+}
+
+static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contributors * range, void * user_data )
+{
+  float scale = samp->scale_info.scale;
+  float out_shift = samp->scale_info.pixel_shift;
+  stbir__support_callback * support = samp->filter_support;
+  int input_full_size = samp->scale_info.input_full_size;
+  stbir_edge edge = samp->edge;
+  float inv_scale = samp->scale_info.inv_scale;
+
+  STBIR_ASSERT( samp->is_gather != 0 );
+
+  if ( samp->is_gather == 1 )
+  {
+    int in_first_pixel, in_last_pixel;
+    float out_filter_radius = support(inv_scale, user_data) * scale;
+
+    stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, 0.5, out_filter_radius, inv_scale, out_shift, input_full_size, edge );
+    range->n0 = in_first_pixel;
+    stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, ( (float)(samp->scale_info.output_sub_size-1) ) + 0.5f, out_filter_radius, inv_scale, out_shift, input_full_size, edge );
+    range->n1 = in_last_pixel;
+  }
+  else if ( samp->is_gather == 2 ) // downsample gather, refine
+  {
+    float in_pixels_radius = support(scale, user_data) * inv_scale;
+    int filter_pixel_margin = samp->filter_pixel_margin;
+    int output_sub_size = samp->scale_info.output_sub_size;
+    int input_end;
+    int n;
+    int in_first_pixel, in_last_pixel;
+
+    // get a conservative area of the input range
+    stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, 0, 0, inv_scale, out_shift, input_full_size, edge );
+    range->n0 = in_first_pixel;
+    stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, (float)output_sub_size, 0, inv_scale, out_shift, input_full_size, edge );
+    range->n1 = in_last_pixel;
+
+    // now go through the margin to the start of area to find bottom
+    n = range->n0 + 1;
+    input_end = -filter_pixel_margin;
+    while( n >= input_end )
+    {
+      int out_first_pixel, out_last_pixel;
+      stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, ((float)n)+0.5f, in_pixels_radius, scale, out_shift, output_sub_size );
+      if ( out_first_pixel > out_last_pixel )
+        break;
+
+      if ( ( out_first_pixel < output_sub_size ) || ( out_last_pixel >= 0 ) )
+        range->n0 = n;
+      --n;
+    }
+
+    // now go through the end of the area through the margin to find top
+    n = range->n1 - 1;
+    input_end = n + 1 + filter_pixel_margin;
+    while( n <= input_end )
+    {
+      int out_first_pixel, out_last_pixel;
+      stbir__calculate_out_pixel_range( &out_first_pixel, &out_last_pixel, ((float)n)+0.5f, in_pixels_radius, scale, out_shift, output_sub_size );
+      if ( out_first_pixel > out_last_pixel )
+        break;
+      if ( ( out_first_pixel < output_sub_size ) || ( out_last_pixel >= 0 ) )
+        range->n1 = n;
+      ++n;
+    }
+  }
+
+  if ( samp->edge == STBIR_EDGE_WRAP )
+  {
+    // if we are wrapping, and we are very close to the image size (so the edges might merge), just use the scanline up to the edge
+    if ( ( range->n0 > 0 ) && ( range->n1 >= input_full_size ) )
+    {
+      int marg = range->n1 - input_full_size + 1;
+      if ( ( marg + STBIR__MERGE_RUNS_PIXEL_THRESHOLD ) >= range->n0 )
+        range->n0 = 0;
+    }
+    if ( ( range->n0 < 0 ) && ( range->n1 < (input_full_size-1) ) )
+    {
+      int marg = -range->n0;
+      if ( ( input_full_size - marg - STBIR__MERGE_RUNS_PIXEL_THRESHOLD - 1 ) <= range->n1 )
+        range->n1 = input_full_size - 1;
+    }
+  }
+  else
+  {
+    // for non-edge-wrap modes, we never read over the edge, so clamp
+    if ( range->n0 < 0 )
+      range->n0 = 0;
+    if ( range->n1 >= input_full_size )
+      range->n1 = input_full_size - 1;
+  }
+}
+
+static void stbir__get_split_info( stbir__per_split_info* split_info, int splits, int output_height, int vertical_pixel_margin, int input_full_height )
+{
+  int i, cur;
+  int left = output_height;
+
+  cur = 0;
+  for( i = 0 ; i < splits ; i++ )
+  {
+    int each;
+    split_info[i].start_output_y = cur;
+    each = left / ( splits - i );
+    split_info[i].end_output_y = cur + each;
+    cur += each;
+    left -= each;
+
+    // scatter range (updated to minimum as you run it)
+    split_info[i].start_input_y = -vertical_pixel_margin;
+    split_info[i].end_input_y = input_full_height + vertical_pixel_margin;
+  }
+}
+
+static void stbir__free_internal_mem( stbir__info *info )
+{
+  #define STBIR__FREE_AND_CLEAR( ptr ) { if ( ptr ) { void * p = (ptr); (ptr) = 0; STBIR_FREE( p, info->user_data); } }
+
+  if ( info )
+  {
+  #ifndef STBIR__SEPARATE_ALLOCATIONS
+    STBIR__FREE_AND_CLEAR( info->alloced_mem );
+  #else
+    int i,j;
+
+    if ( ( info->vertical.gather_prescatter_contributors ) && ( (void*)info->vertical.gather_prescatter_contributors != (void*)info->split_info[0].decode_buffer ) )
+    {
+      STBIR__FREE_AND_CLEAR( info->vertical.gather_prescatter_coefficients );
+      STBIR__FREE_AND_CLEAR( info->vertical.gather_prescatter_contributors );
+    }
+    for( i = 0 ; i < info->splits ; i++ )
+    {
+      for( j = 0 ; j < info->alloc_ring_buffer_num_entries ; j++ )
+      {
+        #ifdef STBIR_SIMD8
+        if ( info->effective_channels == 3 )
+          --info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer
+        #endif
+        STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers[j] );
+      }
+
+      #ifdef STBIR_SIMD8
+      if ( info->effective_channels == 3 )
+        --info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer
+      #endif
+      STBIR__FREE_AND_CLEAR( info->split_info[i].decode_buffer );
+      STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers );
+      STBIR__FREE_AND_CLEAR( info->split_info[i].vertical_buffer );
+    }
+    STBIR__FREE_AND_CLEAR( info->split_info );
+    if ( info->vertical.coefficients != info->horizontal.coefficients )
+    {
+      STBIR__FREE_AND_CLEAR( info->vertical.coefficients );
+      STBIR__FREE_AND_CLEAR( info->vertical.contributors );
+    }
+    STBIR__FREE_AND_CLEAR( info->horizontal.coefficients );
+    STBIR__FREE_AND_CLEAR( info->horizontal.contributors );
+    STBIR__FREE_AND_CLEAR( info->alloced_mem );
+    STBIR__FREE_AND_CLEAR( info );
+  #endif
+  }
+
+  #undef STBIR__FREE_AND_CLEAR
+}
+
+static int stbir__get_max_split( int splits, int height )
+{
+  int i;
+  int max = 0;
+
+  for( i = 0 ; i < splits ; i++ )
+  {
+    int each = height / ( splits - i );
+    if ( each > max )
+      max = each;
+    height -= each;
+  }
+  return max;
+}
+
+static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_n_coeffs_funcs[8] =
+{
+  0, stbir__horizontal_gather_1_channels_with_n_coeffs_funcs, stbir__horizontal_gather_2_channels_with_n_coeffs_funcs, stbir__horizontal_gather_3_channels_with_n_coeffs_funcs, stbir__horizontal_gather_4_channels_with_n_coeffs_funcs, 0,0, stbir__horizontal_gather_7_channels_with_n_coeffs_funcs
+};
+
+static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_channels_funcs[8] =
+{
+  0, stbir__horizontal_gather_1_channels_funcs, stbir__horizontal_gather_2_channels_funcs, stbir__horizontal_gather_3_channels_funcs, stbir__horizontal_gather_4_channels_funcs, 0,0, stbir__horizontal_gather_7_channels_funcs
+};
+
+// there are six resize classifications: 0 == vertical scatter, 1 == vertical gather < 1x scale, 2 == vertical gather 1x-2x scale, 4 == vertical gather < 3x scale, 4 == vertical gather > 3x scale, 5 == <=4 pixel height, 6 == <=4 pixel wide column
+#define STBIR_RESIZE_CLASSIFICATIONS 8
+
+static float stbir__compute_weights[5][STBIR_RESIZE_CLASSIFICATIONS][4]=  // 5 = 0=1chan, 1=2chan, 2=3chan, 3=4chan, 4=7chan
+{
+  {
+    { 1.00000f, 1.00000f, 0.31250f, 1.00000f },
+    { 0.56250f, 0.59375f, 0.00000f, 0.96875f },
+    { 1.00000f, 0.06250f, 0.00000f, 1.00000f },
+    { 0.00000f, 0.09375f, 1.00000f, 1.00000f },
+    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 0.03125f, 0.12500f, 1.00000f, 1.00000f },
+    { 0.06250f, 0.12500f, 0.00000f, 1.00000f },
+    { 0.00000f, 1.00000f, 0.00000f, 0.03125f },
+  }, {
+    { 0.00000f, 0.84375f, 0.00000f, 0.03125f },
+    { 0.09375f, 0.93750f, 0.00000f, 0.78125f },
+    { 0.87500f, 0.21875f, 0.00000f, 0.96875f },
+    { 0.09375f, 0.09375f, 1.00000f, 1.00000f },
+    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 0.03125f, 0.12500f, 1.00000f, 1.00000f },
+    { 0.06250f, 0.12500f, 0.00000f, 1.00000f },
+    { 0.00000f, 1.00000f, 0.00000f, 0.53125f },
+  }, {
+    { 0.00000f, 0.53125f, 0.00000f, 0.03125f },
+    { 0.06250f, 0.96875f, 0.00000f, 0.53125f },
+    { 0.87500f, 0.18750f, 0.00000f, 0.93750f },
+    { 0.00000f, 0.09375f, 1.00000f, 1.00000f },
+    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 0.03125f, 0.12500f, 1.00000f, 1.00000f },
+    { 0.06250f, 0.12500f, 0.00000f, 1.00000f },
+    { 0.00000f, 1.00000f, 0.00000f, 0.56250f },
+  }, {
+    { 0.00000f, 0.50000f, 0.00000f, 0.71875f },
+    { 0.06250f, 0.84375f, 0.00000f, 0.87500f },
+    { 1.00000f, 0.50000f, 0.50000f, 0.96875f },
+    { 1.00000f, 0.09375f, 0.31250f, 0.50000f },
+    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 1.00000f, 0.03125f, 0.03125f, 0.53125f },
+    { 0.18750f, 0.12500f, 0.00000f, 1.00000f },
+    { 0.00000f, 1.00000f, 0.03125f, 0.18750f },
+  }, {
+    { 0.00000f, 0.59375f, 0.00000f, 0.96875f },
+    { 0.06250f, 0.81250f, 0.06250f, 0.59375f },
+    { 0.75000f, 0.43750f, 0.12500f, 0.96875f },
+    { 0.87500f, 0.06250f, 0.18750f, 0.43750f },
+    { 1.00000f, 1.00000f, 1.00000f, 1.00000f },
+    { 0.15625f, 0.12500f, 1.00000f, 1.00000f },
+    { 0.06250f, 0.12500f, 0.00000f, 1.00000f },
+    { 0.00000f, 1.00000f, 0.03125f, 0.34375f },
+  }
+};
+
+// structure that allow us to query and override info for training the costs
+typedef struct STBIR__V_FIRST_INFO
+{
+  double v_cost, h_cost;
+  int control_v_first; // 0 = no control, 1 = force hori, 2 = force vert
+  int v_first;
+  int v_resize_classification;
+  int is_gather;
+} STBIR__V_FIRST_INFO;
+
+#ifdef STBIR__V_FIRST_INFO_BUFFER
+static STBIR__V_FIRST_INFO STBIR__V_FIRST_INFO_BUFFER = {0};
+#define STBIR__V_FIRST_INFO_POINTER &STBIR__V_FIRST_INFO_BUFFER
+#else
+#define STBIR__V_FIRST_INFO_POINTER 0
+#endif
+
+// Figure out whether to scale along the horizontal or vertical first.
+//   This only *super* important when you are scaling by a massively
+//   different amount in the vertical vs the horizontal (for example, if
+//   you are scaling by 2x in the width, and 0.5x in the height, then you
+//   want to do the vertical scale first, because it's around 3x faster
+//   in that order.
+//
+//   In more normal circumstances, this makes a 20-40% differences, so
+//     it's good to get right, but not critical. The normal way that you
+//     decide which direction goes first is just figuring out which
+//     direction does more multiplies. But with modern CPUs with their
+//     fancy caches and SIMD and high IPC abilities, so there's just a lot
+//     more that goes into it.
+//
+//   My handwavy sort of solution is to have an app that does a whole
+//     bunch of timing for both vertical and horizontal first modes,
+//     and then another app that can read lots of these timing files
+//     and try to search for the best weights to use. Dotimings.c
+//     is the app that does a bunch of timings, and vf_train.c is the
+//     app that solves for the best weights (and shows how well it
+//     does currently).
+
+static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int horizontal_filter_pixel_width, float horizontal_scale, int horizontal_output_size, int vertical_filter_pixel_width, float vertical_scale, int vertical_output_size, int is_gather, STBIR__V_FIRST_INFO * info )
+{
+  double v_cost, h_cost;
+  float * weights;
+  int vertical_first;
+  int v_classification;
+
+  // categorize the resize into buckets
+  if ( ( vertical_output_size <= 4 ) || ( horizontal_output_size <= 4 ) )
+    v_classification = ( vertical_output_size < horizontal_output_size ) ? 6 : 7;
+  else if ( vertical_scale <= 1.0f )
+    v_classification = ( is_gather ) ? 1 : 0;
+  else if ( vertical_scale <= 2.0f)
+    v_classification = 2;
+  else if ( vertical_scale <= 3.0f)
+    v_classification = 3;
+  else if ( vertical_scale <= 4.0f)
+    v_classification = 5;
+  else
+    v_classification = 6;
+
+  // use the right weights
+  weights = weights_table[ v_classification ];
+
+  // this is the costs when you don't take into account modern CPUs with high ipc and simd and caches - wish we had a better estimate
+  h_cost = (float)horizontal_filter_pixel_width * weights[0] + horizontal_scale * (float)vertical_filter_pixel_width * weights[1];
+  v_cost = (float)vertical_filter_pixel_width  * weights[2] + vertical_scale * (float)horizontal_filter_pixel_width * weights[3];
+
+  // use computation estimate to decide vertical first or not
+  vertical_first = ( v_cost <= h_cost ) ? 1 : 0;
+
+  // save these, if requested
+  if ( info )
+  {
+    info->h_cost = h_cost;
+    info->v_cost = v_cost;
+    info->v_resize_classification = v_classification;
+    info->v_first = vertical_first;
+    info->is_gather = is_gather;
+  }
+
+  // and this allows us to override everything for testing (see dotiming.c)
+  if ( ( info ) && ( info->control_v_first ) )
+    vertical_first = ( info->control_v_first == 2 ) ? 1 : 0;
+
+  return vertical_first;
+}
+
+// layout lookups - must match stbir_internal_pixel_layout
+static unsigned char stbir__pixel_channels[] = {
+  1,2,3,3,4,   // 1ch, 2ch, rgb, bgr, 4ch
+  4,4,4,4,2,2, // RGBA,BGRA,ARGB,ABGR,RA,AR
+  4,4,4,4,2,2, // RGBA_PM,BGRA_PM,ARGB_PM,ABGR_PM,RA_PM,AR_PM
+};
+
+// the internal pixel layout enums are in a different order, so we can easily do range comparisons of types
+//   the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible
+static stbir_internal_pixel_layout stbir__pixel_layout_convert_public_to_internal[] = {
+  STBIRI_BGR, STBIRI_1CHANNEL, STBIRI_2CHANNEL, STBIRI_RGB, STBIRI_RGBA,
+  STBIRI_4CHANNEL, STBIRI_BGRA, STBIRI_ARGB, STBIRI_ABGR, STBIRI_RA, STBIRI_AR,
+  STBIRI_RGBA_PM, STBIRI_BGRA_PM, STBIRI_ARGB_PM, STBIRI_ABGR_PM, STBIRI_RA_PM, STBIRI_AR_PM,
+};
+
+static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sampler * horizontal, stbir__sampler * vertical, stbir__contributors * conservative, stbir_pixel_layout input_pixel_layout_public, stbir_pixel_layout output_pixel_layout_public, int splits, int new_x, int new_y, int fast_alpha, void * user_data STBIR_ONLY_PROFILE_BUILD_GET_INFO )
+{
+  static char stbir_channel_count_index[8]={ 9,0,1,2, 3,9,9,4 };
+
+  stbir__info * info = 0;
+  void * alloced = 0;
+  int alloced_total = 0;
+  int vertical_first;
+  int decode_buffer_size, ring_buffer_length_bytes, ring_buffer_size, vertical_buffer_size, alloc_ring_buffer_num_entries;
+
+  int alpha_weighting_type = 0; // 0=none, 1=simple, 2=fancy
+  int conservative_split_output_size = stbir__get_max_split( splits, vertical->scale_info.output_sub_size );
+  stbir_internal_pixel_layout input_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ input_pixel_layout_public ];
+  stbir_internal_pixel_layout output_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ output_pixel_layout_public ];
+  int channels = stbir__pixel_channels[ input_pixel_layout ];
+  int effective_channels = channels;
+
+  // first figure out what type of alpha weighting to use (if any)
+  if ( ( horizontal->filter_enum != STBIR_FILTER_POINT_SAMPLE ) || ( vertical->filter_enum != STBIR_FILTER_POINT_SAMPLE ) ) // no alpha weighting on point sampling
+  {
+    if ( ( input_pixel_layout >= STBIRI_RGBA ) && ( input_pixel_layout <= STBIRI_AR ) && ( output_pixel_layout >= STBIRI_RGBA ) && ( output_pixel_layout <= STBIRI_AR ) )
+    {
+      if ( fast_alpha )
+      {
+        alpha_weighting_type = 4;
+      }
+      else
+      {
+        static int fancy_alpha_effective_cnts[6] = { 7, 7, 7, 7, 3, 3 };
+        alpha_weighting_type = 2;
+        effective_channels = fancy_alpha_effective_cnts[ input_pixel_layout - STBIRI_RGBA ];
+      }
+    }
+    else if ( ( input_pixel_layout >= STBIRI_RGBA_PM ) && ( input_pixel_layout <= STBIRI_AR_PM ) && ( output_pixel_layout >= STBIRI_RGBA ) && ( output_pixel_layout <= STBIRI_AR ) )
+    {
+      // input premult, output non-premult
+      alpha_weighting_type = 3;
+    }
+    else if ( ( input_pixel_layout >= STBIRI_RGBA ) && ( input_pixel_layout <= STBIRI_AR ) && ( output_pixel_layout >= STBIRI_RGBA_PM ) && ( output_pixel_layout <= STBIRI_AR_PM ) )
+    {
+      // input non-premult, output premult
+      alpha_weighting_type = 1;
+    }
+  }
+
+  // channel in and out count must match currently
+  if ( channels != stbir__pixel_channels[ output_pixel_layout ] )
+    return 0;
+
+  // get vertical first
+  vertical_first = stbir__should_do_vertical_first( stbir__compute_weights[ (int)stbir_channel_count_index[ effective_channels ] ], horizontal->filter_pixel_width, horizontal->scale_info.scale, horizontal->scale_info.output_sub_size, vertical->filter_pixel_width, vertical->scale_info.scale, vertical->scale_info.output_sub_size, vertical->is_gather, STBIR__V_FIRST_INFO_POINTER );
+
+  // sometimes read one float off in some of the unrolled loops (with a weight of zero coeff, so it doesn't have an effect)
+  decode_buffer_size = ( conservative->n1 - conservative->n0 + 1 ) * effective_channels * sizeof(float) + sizeof(float); // extra float for padding
+
+#if defined( STBIR__SEPARATE_ALLOCATIONS ) && defined(STBIR_SIMD8)
+  if ( effective_channels == 3 )
+    decode_buffer_size += sizeof(float); // avx in 3 channel mode needs one float at the start of the buffer (only with separate allocations)
+#endif
+
+  ring_buffer_length_bytes = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding
+
+  // if we do vertical first, the ring buffer holds a whole decoded line
+  if ( vertical_first )
+    ring_buffer_length_bytes = ( decode_buffer_size + 15 ) & ~15;
+
+  if ( ( ring_buffer_length_bytes & 4095 ) == 0 ) ring_buffer_length_bytes += 64*3; // avoid 4k alias
+
+  // One extra entry because floating point precision problems sometimes cause an extra to be necessary.
+  alloc_ring_buffer_num_entries = vertical->filter_pixel_width + 1;
+
+  // we never need more ring buffer entries than the scanlines we're outputting when in scatter mode
+  if ( ( !vertical->is_gather ) && ( alloc_ring_buffer_num_entries > conservative_split_output_size ) )
+    alloc_ring_buffer_num_entries = conservative_split_output_size;
+
+  ring_buffer_size = alloc_ring_buffer_num_entries * ring_buffer_length_bytes;
+
+  // The vertical buffer is used differently, depending on whether we are scattering
+  //   the vertical scanlines, or gathering them.
+  //   If scattering, it's used at the temp buffer to accumulate each output.
+  //   If gathering, it's just the output buffer.
+  vertical_buffer_size = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float);  // extra float for padding
+
+  // we make two passes through this loop, 1st to add everything up, 2nd to allocate and init
+  for(;;)
+  {
+    int i;
+    void * advance_mem = alloced;
+    int copy_horizontal = 0;
+    stbir__sampler * possibly_use_horizontal_for_pivot = 0;
+
+#ifdef STBIR__SEPARATE_ALLOCATIONS
+    #define STBIR__NEXT_PTR( ptr, size, ntype ) if ( alloced ) { void * p = STBIR_MALLOC( size, user_data); if ( p == 0 ) { stbir__free_internal_mem( info ); return 0; } (ptr) = (ntype*)p; }
+#else
+    #define STBIR__NEXT_PTR( ptr, size, ntype ) advance_mem = (void*) ( ( ((size_t)advance_mem) + 15 ) & ~15 ); if ( alloced ) ptr = (ntype*)advance_mem; advance_mem = ((char*)advance_mem) + (size);
+#endif
+
+    STBIR__NEXT_PTR( info, sizeof( stbir__info ), stbir__info );
+
+    STBIR__NEXT_PTR( info->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info );
+
+    if ( info )
+    {
+      static stbir__alpha_weight_func * fancy_alpha_weights[6]  =    { stbir__fancy_alpha_weight_4ch,   stbir__fancy_alpha_weight_4ch,   stbir__fancy_alpha_weight_4ch,   stbir__fancy_alpha_weight_4ch,   stbir__fancy_alpha_weight_2ch,   stbir__fancy_alpha_weight_2ch };
+      static stbir__alpha_unweight_func * fancy_alpha_unweights[6] = { stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_4ch, stbir__fancy_alpha_unweight_2ch, stbir__fancy_alpha_unweight_2ch };
+      static stbir__alpha_weight_func * simple_alpha_weights[6] = { stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_4ch, stbir__simple_alpha_weight_2ch, stbir__simple_alpha_weight_2ch };
+      static stbir__alpha_unweight_func * simple_alpha_unweights[6] = { stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_4ch, stbir__simple_alpha_unweight_2ch, stbir__simple_alpha_unweight_2ch };
+
+      // initialize info fields
+      info->alloced_mem = alloced;
+      info->alloced_total = alloced_total;
+
+      info->channels = channels;
+      info->effective_channels = effective_channels;
+
+      info->offset_x = new_x;
+      info->offset_y = new_y;
+      info->alloc_ring_buffer_num_entries = alloc_ring_buffer_num_entries;
+      info->ring_buffer_num_entries = 0;
+      info->ring_buffer_length_bytes = ring_buffer_length_bytes;
+      info->splits = splits;
+      info->vertical_first = vertical_first;
+
+      info->input_pixel_layout_internal = input_pixel_layout;
+      info->output_pixel_layout_internal = output_pixel_layout;
+
+      // setup alpha weight functions
+      info->alpha_weight = 0;
+      info->alpha_unweight = 0;
+
+      // handle alpha weighting functions and overrides
+      if ( alpha_weighting_type == 2 )
+      {
+        // high quality alpha multiplying on the way in, dividing on the way out
+        info->alpha_weight = fancy_alpha_weights[ input_pixel_layout - STBIRI_RGBA ];
+        info->alpha_unweight = fancy_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ];
+      }
+      else if ( alpha_weighting_type == 4 )
+      {
+        // fast alpha multiplying on the way in, dividing on the way out
+        info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ];
+        info->alpha_unweight = simple_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ];
+      }
+      else if ( alpha_weighting_type == 1 )
+      {
+        // fast alpha on the way in, leave in premultiplied form on way out
+        info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ];
+      }
+      else if ( alpha_weighting_type == 3 )
+      {
+        // incoming is premultiplied, fast alpha dividing on the way out - non-premultiplied output
+        info->alpha_unweight = simple_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ];
+      }
+
+      // handle 3-chan color flipping, using the alpha weight path
+      if ( ( ( input_pixel_layout == STBIRI_RGB ) && ( output_pixel_layout == STBIRI_BGR ) ) ||
+           ( ( input_pixel_layout == STBIRI_BGR ) && ( output_pixel_layout == STBIRI_RGB ) ) )
+      {
+        // do the flipping on the smaller of the two ends
+        if ( horizontal->scale_info.scale < 1.0f )
+          info->alpha_unweight = stbir__simple_flip_3ch;
+        else
+          info->alpha_weight = stbir__simple_flip_3ch;
+      }
+
+    }
+
+    // get all the per-split buffers
+    for( i = 0 ; i < splits ; i++ )
+    {
+      STBIR__NEXT_PTR( info->split_info[i].decode_buffer, decode_buffer_size, float );
+
+#ifdef STBIR__SEPARATE_ALLOCATIONS
+
+      #ifdef STBIR_SIMD8
+      if ( ( info ) && ( effective_channels == 3 ) )
+        ++info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer
+      #endif
+
+      STBIR__NEXT_PTR( info->split_info[i].ring_buffers, alloc_ring_buffer_num_entries * sizeof(float*), float* );
+      {
+        int j;
+        for( j = 0 ; j < alloc_ring_buffer_num_entries ; j++ )
+        {
+          STBIR__NEXT_PTR( info->split_info[i].ring_buffers[j], ring_buffer_length_bytes, float );
+          #ifdef STBIR_SIMD8
+          if ( ( info ) && ( effective_channels == 3 ) )
+            ++info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer
+          #endif
+        }
+      }
+#else
+      STBIR__NEXT_PTR( info->split_info[i].ring_buffer, ring_buffer_size, float );
+#endif
+      STBIR__NEXT_PTR( info->split_info[i].vertical_buffer, vertical_buffer_size, float );
+    }
+
+    // alloc memory for to-be-pivoted coeffs (if necessary)
+    if ( vertical->is_gather == 0 )
+    {
+      int both;
+      int temp_mem_amt;
+
+      // when in vertical scatter mode, we first build the coefficients in gather mode, and then pivot after,
+      //   that means we need two buffers, so we try to use the decode buffer and ring buffer for this. if that
+      //   is too small, we just allocate extra memory to use as this temp.
+
+      both = vertical->gather_prescatter_contributors_size + vertical->gather_prescatter_coefficients_size;
+
+#ifdef STBIR__SEPARATE_ALLOCATIONS
+      temp_mem_amt = decode_buffer_size;
+#else
+      temp_mem_amt = ( decode_buffer_size + ring_buffer_size + vertical_buffer_size ) * splits;
+#endif
+      if ( temp_mem_amt >= both )
+      {
+        if ( info )
+        {
+          vertical->gather_prescatter_contributors = (stbir__contributors*)info->split_info[0].decode_buffer;
+          vertical->gather_prescatter_coefficients = (float*) ( ( (char*)info->split_info[0].decode_buffer ) + vertical->gather_prescatter_contributors_size );
+        }
+      }
+      else
+      {
+        // ring+decode memory is too small, so allocate temp memory
+        STBIR__NEXT_PTR( vertical->gather_prescatter_contributors, vertical->gather_prescatter_contributors_size, stbir__contributors );
+        STBIR__NEXT_PTR( vertical->gather_prescatter_coefficients, vertical->gather_prescatter_coefficients_size, float );
+      }
+    }
+
+    STBIR__NEXT_PTR( horizontal->contributors, horizontal->contributors_size, stbir__contributors );
+    STBIR__NEXT_PTR( horizontal->coefficients, horizontal->coefficients_size, float );
+
+    // are the two filters identical?? (happens a lot with mipmap generation)
+    if ( ( horizontal->filter_kernel == vertical->filter_kernel ) && ( horizontal->filter_support == vertical->filter_support ) && ( horizontal->edge == vertical->edge ) && ( horizontal->scale_info.output_sub_size == vertical->scale_info.output_sub_size ) )
+    {
+      float diff_scale = horizontal->scale_info.scale - vertical->scale_info.scale;
+      float diff_shift = horizontal->scale_info.pixel_shift - vertical->scale_info.pixel_shift;
+      if ( diff_scale < 0.0f ) diff_scale = -diff_scale;
+      if ( diff_shift < 0.0f ) diff_shift = -diff_shift;
+      if ( ( diff_scale <= stbir__small_float ) && ( diff_shift <= stbir__small_float ) )
+      {
+        if ( horizontal->is_gather == vertical->is_gather )
+        {
+          copy_horizontal = 1;
+          goto no_vert_alloc;
+        }
+        // everything matches, but vertical is scatter, horizontal is gather, use horizontal coeffs for vertical pivot coeffs
+        possibly_use_horizontal_for_pivot = horizontal;
+      }
+    }
+
+    STBIR__NEXT_PTR( vertical->contributors, vertical->contributors_size, stbir__contributors );
+    STBIR__NEXT_PTR( vertical->coefficients, vertical->coefficients_size, float );
+
+   no_vert_alloc:
+
+    if ( info )
+    {
+      STBIR_PROFILE_BUILD_START( horizontal );
+
+      stbir__calculate_filters( horizontal, 0, user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO );
+
+      // setup the horizontal gather functions
+      // start with defaulting to the n_coeffs functions (specialized on channels and remnant leftover)
+      info->horizontal_gather_channels = stbir__horizontal_gather_n_coeffs_funcs[ effective_channels ][ horizontal->extent_info.widest & 3 ];
+      // but if the number of coeffs <= 12, use another set of special cases. <=12 coeffs is any enlarging resize, or shrinking resize down to about 1/3 size
+      if ( horizontal->extent_info.widest <= 12 )
+        info->horizontal_gather_channels = stbir__horizontal_gather_channels_funcs[ effective_channels ][ horizontal->extent_info.widest - 1 ];
+
+      info->scanline_extents.conservative.n0 = conservative->n0;
+      info->scanline_extents.conservative.n1 = conservative->n1;
+
+      // get exact extents
+      stbir__get_extents( horizontal, &info->scanline_extents );
+
+      // pack the horizontal coeffs
+      horizontal->coefficient_width = stbir__pack_coefficients(horizontal->num_contributors, horizontal->contributors, horizontal->coefficients, horizontal->coefficient_width, horizontal->extent_info.widest, info->scanline_extents.conservative.n1 + 1 );
+
+      STBIR_MEMCPY( &info->horizontal, horizontal, sizeof( stbir__sampler ) );
+
+      STBIR_PROFILE_BUILD_END( horizontal );
+
+      if ( copy_horizontal )
+      {
+        STBIR_MEMCPY( &info->vertical, horizontal, sizeof( stbir__sampler ) );
+      }
+      else
+      {
+        STBIR_PROFILE_BUILD_START( vertical );
+
+        stbir__calculate_filters( vertical, possibly_use_horizontal_for_pivot, user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO );
+        STBIR_MEMCPY( &info->vertical, vertical, sizeof( stbir__sampler ) );
+
+        STBIR_PROFILE_BUILD_END( vertical );
+      }
+
+      // setup the vertical split ranges
+      stbir__get_split_info( info->split_info, info->splits, info->vertical.scale_info.output_sub_size, info->vertical.filter_pixel_margin, info->vertical.scale_info.input_full_size );
+
+      // now we know precisely how many entries we need
+      info->ring_buffer_num_entries = info->vertical.extent_info.widest;
+
+      // we never need more ring buffer entries than the scanlines we're outputting
+      if ( ( !info->vertical.is_gather ) && ( info->ring_buffer_num_entries > conservative_split_output_size ) )
+        info->ring_buffer_num_entries = conservative_split_output_size;
+      STBIR_ASSERT( info->ring_buffer_num_entries <= info->alloc_ring_buffer_num_entries );
+
+      // a few of the horizontal gather functions read one dword past the end (but mask it out), so put in a normal value so no snans or denormals accidentally sneak in
+      for( i = 0 ; i < splits ; i++ )
+      {
+        int width, ofs;
+
+        // find the right most span
+        if ( info->scanline_extents.spans[0].n1 > info->scanline_extents.spans[1].n1 )
+          width = info->scanline_extents.spans[0].n1 - info->scanline_extents.spans[0].n0;
+        else
+          width = info->scanline_extents.spans[1].n1 - info->scanline_extents.spans[1].n0;
+
+        // this calc finds the exact end of the decoded scanline for all filter modes.
+        //   usually this is just the width * effective channels.  But we have to account
+        //   for the area to the left of the scanline for wrap filtering and alignment, this
+        //   is stored as a negative value in info->scanline_extents.conservative.n0. Next,
+        //   we need to skip the exact size of the right hand size filter area (again for
+        //   wrap mode), this is in info->scanline_extents.edge_sizes[1]).
+        ofs = ( width + 1 - info->scanline_extents.conservative.n0 + info->scanline_extents.edge_sizes[1] ) * effective_channels;
+
+        // place a known, but numerically valid value in the decode buffer
+        info->split_info[i].decode_buffer[ ofs ] = 9999.0f;
+
+        // if vertical filtering first, place a known, but numerically valid value in the all
+        //   of the ring buffer accumulators
+        if ( vertical_first )
+        {
+          int j;
+          for( j = 0; j < info->ring_buffer_num_entries ; j++ )
+          {
+            stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ ofs ] = 9999.0f;
+          }
+        }
+      }
+    }
+
+    #undef STBIR__NEXT_PTR
+
+
+    // is this the first time through loop?
+    if ( info == 0 )
+    {
+      alloced_total = (int) ( 15 + (size_t)advance_mem );
+      alloced = STBIR_MALLOC( alloced_total, user_data );
+      if ( alloced == 0 )
+        return 0;
+    }
+    else
+      return info;  // success
+  }
+}
+
+static int stbir__perform_resize( stbir__info const * info, int split_start, int split_count )
+{
+  stbir__per_split_info * split_info = info->split_info + split_start;
+
+  STBIR_PROFILE_CLEAR_EXTRAS();
+
+  STBIR_PROFILE_FIRST_START( looping );
+  if (info->vertical.is_gather)
+    stbir__vertical_gather_loop( info, split_info, split_count );
+  else
+    stbir__vertical_scatter_loop( info, split_info, split_count );
+  STBIR_PROFILE_END( looping );
+
+  return 1;
+}
+
+static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * resize )
+{
+  static stbir__decode_pixels_func * decode_simple[STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=
+  {
+    /* 1ch-4ch */ stbir__decode_uint8_srgb, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear,
+  };
+
+  static stbir__decode_pixels_func * decode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=
+  {
+    { /* RGBA */ stbir__decode_uint8_srgb4_linearalpha,      stbir__decode_uint8_srgb,      0, stbir__decode_float_linear,      stbir__decode_half_float_linear },
+    { /* BGRA */ stbir__decode_uint8_srgb4_linearalpha_BGRA, stbir__decode_uint8_srgb_BGRA, 0, stbir__decode_float_linear_BGRA, stbir__decode_half_float_linear_BGRA },
+    { /* ARGB */ stbir__decode_uint8_srgb4_linearalpha_ARGB, stbir__decode_uint8_srgb_ARGB, 0, stbir__decode_float_linear_ARGB, stbir__decode_half_float_linear_ARGB },
+    { /* ABGR */ stbir__decode_uint8_srgb4_linearalpha_ABGR, stbir__decode_uint8_srgb_ABGR, 0, stbir__decode_float_linear_ABGR, stbir__decode_half_float_linear_ABGR },
+    { /* RA   */ stbir__decode_uint8_srgb2_linearalpha,      stbir__decode_uint8_srgb,      0, stbir__decode_float_linear,      stbir__decode_half_float_linear },
+    { /* AR   */ stbir__decode_uint8_srgb2_linearalpha_AR,   stbir__decode_uint8_srgb_AR,   0, stbir__decode_float_linear_AR,   stbir__decode_half_float_linear_AR },
+  };
+
+  static stbir__decode_pixels_func * decode_simple_scaled_or_not[2][2]=
+  {
+    { stbir__decode_uint8_linear_scaled,  stbir__decode_uint8_linear }, { stbir__decode_uint16_linear_scaled, stbir__decode_uint16_linear },
+  };
+
+  static stbir__decode_pixels_func * decode_alphas_scaled_or_not[STBIRI_AR-STBIRI_RGBA+1][2][2]=
+  {
+    { /* RGBA */ { stbir__decode_uint8_linear_scaled,       stbir__decode_uint8_linear },      { stbir__decode_uint16_linear_scaled,      stbir__decode_uint16_linear } },
+    { /* BGRA */ { stbir__decode_uint8_linear_scaled_BGRA,  stbir__decode_uint8_linear_BGRA }, { stbir__decode_uint16_linear_scaled_BGRA, stbir__decode_uint16_linear_BGRA } },
+    { /* ARGB */ { stbir__decode_uint8_linear_scaled_ARGB,  stbir__decode_uint8_linear_ARGB }, { stbir__decode_uint16_linear_scaled_ARGB, stbir__decode_uint16_linear_ARGB } },
+    { /* ABGR */ { stbir__decode_uint8_linear_scaled_ABGR,  stbir__decode_uint8_linear_ABGR }, { stbir__decode_uint16_linear_scaled_ABGR, stbir__decode_uint16_linear_ABGR } },
+    { /* RA   */ { stbir__decode_uint8_linear_scaled,       stbir__decode_uint8_linear },      { stbir__decode_uint16_linear_scaled,      stbir__decode_uint16_linear } },
+    { /* AR   */ { stbir__decode_uint8_linear_scaled_AR,    stbir__decode_uint8_linear_AR },   { stbir__decode_uint16_linear_scaled_AR,   stbir__decode_uint16_linear_AR } }
+  };
+
+  static stbir__encode_pixels_func * encode_simple[STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=
+  {
+    /* 1ch-4ch */ stbir__encode_uint8_srgb, stbir__encode_uint8_srgb, 0, stbir__encode_float_linear, stbir__encode_half_float_linear,
+  };
+
+  static stbir__encode_pixels_func * encode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=
+  {
+    { /* RGBA */ stbir__encode_uint8_srgb4_linearalpha,      stbir__encode_uint8_srgb,      0, stbir__encode_float_linear,      stbir__encode_half_float_linear },
+    { /* BGRA */ stbir__encode_uint8_srgb4_linearalpha_BGRA, stbir__encode_uint8_srgb_BGRA, 0, stbir__encode_float_linear_BGRA, stbir__encode_half_float_linear_BGRA },
+    { /* ARGB */ stbir__encode_uint8_srgb4_linearalpha_ARGB, stbir__encode_uint8_srgb_ARGB, 0, stbir__encode_float_linear_ARGB, stbir__encode_half_float_linear_ARGB },
+    { /* ABGR */ stbir__encode_uint8_srgb4_linearalpha_ABGR, stbir__encode_uint8_srgb_ABGR, 0, stbir__encode_float_linear_ABGR, stbir__encode_half_float_linear_ABGR },
+    { /* RA   */ stbir__encode_uint8_srgb2_linearalpha,      stbir__encode_uint8_srgb,      0, stbir__encode_float_linear,      stbir__encode_half_float_linear },
+    { /* AR   */ stbir__encode_uint8_srgb2_linearalpha_AR,   stbir__encode_uint8_srgb_AR,   0, stbir__encode_float_linear_AR,   stbir__encode_half_float_linear_AR }
+  };
+
+  static stbir__encode_pixels_func * encode_simple_scaled_or_not[2][2]=
+  {
+    { stbir__encode_uint8_linear_scaled,  stbir__encode_uint8_linear }, { stbir__encode_uint16_linear_scaled, stbir__encode_uint16_linear },
+  };
+
+  static stbir__encode_pixels_func * encode_alphas_scaled_or_not[STBIRI_AR-STBIRI_RGBA+1][2][2]=
+  {
+    { /* RGBA */ { stbir__encode_uint8_linear_scaled,       stbir__encode_uint8_linear },       { stbir__encode_uint16_linear_scaled,      stbir__encode_uint16_linear } },
+    { /* BGRA */ { stbir__encode_uint8_linear_scaled_BGRA,  stbir__encode_uint8_linear_BGRA },  { stbir__encode_uint16_linear_scaled_BGRA, stbir__encode_uint16_linear_BGRA } },
+    { /* ARGB */ { stbir__encode_uint8_linear_scaled_ARGB,  stbir__encode_uint8_linear_ARGB },  { stbir__encode_uint16_linear_scaled_ARGB, stbir__encode_uint16_linear_ARGB } },
+    { /* ABGR */ { stbir__encode_uint8_linear_scaled_ABGR,  stbir__encode_uint8_linear_ABGR },  { stbir__encode_uint16_linear_scaled_ABGR, stbir__encode_uint16_linear_ABGR } },
+    { /* RA   */ { stbir__encode_uint8_linear_scaled,       stbir__encode_uint8_linear },       { stbir__encode_uint16_linear_scaled,      stbir__encode_uint16_linear } },
+    { /* AR   */ { stbir__encode_uint8_linear_scaled_AR,    stbir__encode_uint8_linear_AR },    { stbir__encode_uint16_linear_scaled_AR,   stbir__encode_uint16_linear_AR } }
+  };
+
+  stbir__decode_pixels_func * decode_pixels = 0;
+  stbir__encode_pixels_func * encode_pixels = 0;
+  stbir_datatype input_type, output_type;
+
+  input_type = resize->input_data_type;
+  output_type = resize->output_data_type;
+  info->input_data = resize->input_pixels;
+  info->input_stride_bytes = resize->input_stride_in_bytes;
+  info->output_stride_bytes = resize->output_stride_in_bytes;
+
+  // if we're completely point sampling, then we can turn off SRGB
+  if ( ( info->horizontal.filter_enum == STBIR_FILTER_POINT_SAMPLE ) && ( info->vertical.filter_enum == STBIR_FILTER_POINT_SAMPLE ) )
+  {
+    if ( ( ( input_type  == STBIR_TYPE_UINT8_SRGB ) || ( input_type  == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) &&
+         ( ( output_type == STBIR_TYPE_UINT8_SRGB ) || ( output_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) )
+    {
+      input_type = STBIR_TYPE_UINT8;
+      output_type = STBIR_TYPE_UINT8;
+    }
+  }
+
+  // recalc the output and input strides
+  if ( info->input_stride_bytes == 0 )
+    info->input_stride_bytes = info->channels * info->horizontal.scale_info.input_full_size * stbir__type_size[input_type];
+
+  if ( info->output_stride_bytes == 0 )
+    info->output_stride_bytes = info->channels * info->horizontal.scale_info.output_sub_size * stbir__type_size[output_type];
+
+  // calc offset
+  info->output_data = ( (char*) resize->output_pixels ) + ( (ptrdiff_t) info->offset_y * (ptrdiff_t) resize->output_stride_in_bytes ) + ( info->offset_x * info->channels * stbir__type_size[output_type] );
+
+  info->in_pixels_cb = resize->input_cb;
+  info->user_data = resize->user_data;
+  info->out_pixels_cb = resize->output_cb;
+
+  // setup the input format converters
+  if ( ( input_type == STBIR_TYPE_UINT8 ) || ( input_type == STBIR_TYPE_UINT16 ) )
+  {
+    int non_scaled = 0;
+
+    // check if we can run unscaled - 0-255.0/0-65535.0 instead of 0-1.0 (which is a tiny bit faster when doing linear 8->8 or 16->16)
+    if ( ( !info->alpha_weight ) && ( !info->alpha_unweight )  ) // don't short circuit when alpha weighting (get everything to 0-1.0 as usual)
+      if ( ( ( input_type == STBIR_TYPE_UINT8 ) && ( output_type == STBIR_TYPE_UINT8 ) ) || ( ( input_type == STBIR_TYPE_UINT16 ) && ( output_type == STBIR_TYPE_UINT16 ) ) )
+        non_scaled = 1;
+
+    if ( info->input_pixel_layout_internal <= STBIRI_4CHANNEL )
+      decode_pixels = decode_simple_scaled_or_not[ input_type == STBIR_TYPE_UINT16 ][ non_scaled ];
+    else
+      decode_pixels = decode_alphas_scaled_or_not[ ( info->input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ input_type == STBIR_TYPE_UINT16 ][ non_scaled ];
+  }
+  else
+  {
+    if ( info->input_pixel_layout_internal <= STBIRI_4CHANNEL )
+      decode_pixels = decode_simple[ input_type - STBIR_TYPE_UINT8_SRGB ];
+    else
+      decode_pixels = decode_alphas[ ( info->input_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ input_type - STBIR_TYPE_UINT8_SRGB ];
+  }
+
+  // setup the output format converters
+  if ( ( output_type == STBIR_TYPE_UINT8 ) || ( output_type == STBIR_TYPE_UINT16 ) )
+  {
+    int non_scaled = 0;
+
+    // check if we can run unscaled - 0-255.0/0-65535.0 instead of 0-1.0 (which is a tiny bit faster when doing linear 8->8 or 16->16)
+    if ( ( !info->alpha_weight ) && ( !info->alpha_unweight ) ) // don't short circuit when alpha weighting (get everything to 0-1.0 as usual)
+      if ( ( ( input_type == STBIR_TYPE_UINT8 ) && ( output_type == STBIR_TYPE_UINT8 ) ) || ( ( input_type == STBIR_TYPE_UINT16 ) && ( output_type == STBIR_TYPE_UINT16 ) ) )
+        non_scaled = 1;
+
+    if ( info->output_pixel_layout_internal <= STBIRI_4CHANNEL )
+      encode_pixels = encode_simple_scaled_or_not[ output_type == STBIR_TYPE_UINT16 ][ non_scaled ];
+    else
+      encode_pixels = encode_alphas_scaled_or_not[ ( info->output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ output_type == STBIR_TYPE_UINT16 ][ non_scaled ];
+  }
+  else
+  {
+    if ( info->output_pixel_layout_internal <= STBIRI_4CHANNEL )
+      encode_pixels = encode_simple[ output_type - STBIR_TYPE_UINT8_SRGB ];
+    else
+      encode_pixels = encode_alphas[ ( info->output_pixel_layout_internal - STBIRI_RGBA ) % ( STBIRI_AR-STBIRI_RGBA+1 ) ][ output_type - STBIR_TYPE_UINT8_SRGB ];
+  }
+
+  info->input_type = input_type;
+  info->output_type = output_type;
+  info->decode_pixels = decode_pixels;
+  info->encode_pixels = encode_pixels;
+}
+
+static void stbir__clip( int * outx, int * outsubw, int outw, double * u0, double * u1 )
+{
+  double per, adj;
+  int over;
+
+  // do left/top edge
+  if ( *outx < 0 )
+  {
+    per = ( (double)*outx ) / ( (double)*outsubw ); // is negative
+    adj = per * ( *u1 - *u0 );
+    *u0 -= adj; // increases u0
+    *outx = 0;
+  }
+
+  // do right/bot edge
+  over = outw - ( *outx + *outsubw );
+  if ( over < 0 )
+  {
+    per = ( (double)over ) / ( (double)*outsubw ); // is negative
+    adj = per * ( *u1 - *u0 );
+    *u1 += adj; // decrease u1
+    *outsubw = outw - *outx;
+  }
+}
+
+// converts a double to a rational that has less than one float bit of error (returns 0 if unable to do so)
+static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32 *numer, stbir_uint32 *denom, int limit_denom ) // limit_denom (1) or limit numer (0)
+{
+  double err;
+  stbir_uint64 top, bot;
+  stbir_uint64 numer_last = 0;
+  stbir_uint64 denom_last = 1;
+  stbir_uint64 numer_estimate = 1;
+  stbir_uint64 denom_estimate = 0;
+
+  // scale to past float error range
+  top = (stbir_uint64)( f * (double)(1 << 25) );
+  bot = 1 << 25;
+
+  // keep refining, but usually stops in a few loops - usually 5 for bad cases
+  for(;;)
+  {
+    stbir_uint64 est, temp;
+
+    // hit limit, break out and do best full range estimate
+    if ( ( ( limit_denom ) ? denom_estimate : numer_estimate ) >= limit )
+      break;
+
+    // is the current error less than 1 bit of a float? if so, we're done
+    if ( denom_estimate )
+    {
+      err = ( (double)numer_estimate / (double)denom_estimate ) - f;
+      if ( err < 0.0 ) err = -err;
+      if ( err < ( 1.0 / (double)(1<<24) ) )
+      {
+        // yup, found it
+        *numer = (stbir_uint32) numer_estimate;
+        *denom = (stbir_uint32) denom_estimate;
+        return 1;
+      }
+    }
+
+    // no more refinement bits left? break out and do full range estimate
+    if ( bot == 0 )
+      break;
+
+    // gcd the estimate bits
+    est = top / bot;
+    temp = top % bot;
+    top = bot;
+    bot = temp;
+
+    // move remainders
+    temp = est * denom_estimate + denom_last;
+    denom_last = denom_estimate;
+    denom_estimate = temp;
+
+    // move remainders
+    temp = est * numer_estimate + numer_last;
+    numer_last = numer_estimate;
+    numer_estimate = temp;
+  }
+
+  // we didn't fine anything good enough for float, use a full range estimate
+  if ( limit_denom )
+  {
+    numer_estimate= (stbir_uint64)( f * (double)limit + 0.5 );
+    denom_estimate = limit;
+  }
+  else
+  {
+    numer_estimate = limit;
+    denom_estimate = (stbir_uint64)( ( (double)limit / f ) + 0.5 );
+  }
+
+  *numer = (stbir_uint32) numer_estimate;
+  *denom = (stbir_uint32) denom_estimate;
+
+  err = ( denom_estimate ) ? ( ( (double)(stbir_uint32)numer_estimate / (double)(stbir_uint32)denom_estimate ) - f ) : 1.0;
+  if ( err < 0.0 ) err = -err;
+  return ( err < ( 1.0 / (double)(1<<24) ) ) ? 1 : 0;
+}
+
+static int stbir__calculate_region_transform( stbir__scale_info * scale_info, int output_full_range, int * output_offset, int output_sub_range, int input_full_range, double input_s0, double input_s1 )
+{
+  double output_range, input_range, output_s, input_s, ratio, scale;
+
+  input_s = input_s1 - input_s0;
+
+  // null area
+  if ( ( output_full_range == 0 ) || ( input_full_range == 0 ) ||
+       ( output_sub_range == 0 ) || ( input_s <= stbir__small_float ) )
+    return 0;
+
+  // are either of the ranges completely out of bounds?
+  if ( ( *output_offset >= output_full_range ) || ( ( *output_offset + output_sub_range ) <= 0 ) || ( input_s0 >= (1.0f-stbir__small_float) ) || ( input_s1 <= stbir__small_float ) )
+    return 0;
+
+  output_range = (double)output_full_range;
+  input_range = (double)input_full_range;
+
+  output_s = ( (double)output_sub_range) / output_range;
+
+  // figure out the scaling to use
+  ratio = output_s / input_s;
+
+  // save scale before clipping
+  scale = ( output_range / input_range ) * ratio;
+  scale_info->scale = (float)scale;
+  scale_info->inv_scale = (float)( 1.0 / scale );
+
+  // clip output area to left/right output edges (and adjust input area)
+  stbir__clip( output_offset, &output_sub_range, output_full_range, &input_s0, &input_s1 );
+
+  // recalc input area
+  input_s = input_s1 - input_s0;
+
+  // after clipping do we have zero input area?
+  if ( input_s <= stbir__small_float )
+    return 0;
+
+  // calculate and store the starting source offsets in output pixel space
+  scale_info->pixel_shift = (float) ( input_s0 * ratio * output_range );
+
+  scale_info->scale_is_rational = stbir__double_to_rational( scale, ( scale <= 1.0 ) ? output_full_range : input_full_range, &scale_info->scale_numerator, &scale_info->scale_denominator, ( scale >= 1.0 ) );
+
+  scale_info->input_full_size = input_full_range;
+  scale_info->output_sub_size = output_sub_range;
+
+  return 1;
+}
+
+
+static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layout pixel_layout, stbir_datatype data_type )
+{
+  resize->input_cb = 0;
+  resize->output_cb = 0;
+  resize->user_data = resize;
+  resize->samplers = 0;
+  resize->called_alloc = 0;
+  resize->horizontal_filter = STBIR_FILTER_DEFAULT;
+  resize->horizontal_filter_kernel = 0; resize->horizontal_filter_support = 0;
+  resize->vertical_filter = STBIR_FILTER_DEFAULT;
+  resize->vertical_filter_kernel = 0; resize->vertical_filter_support = 0;
+  resize->horizontal_edge = STBIR_EDGE_CLAMP;
+  resize->vertical_edge = STBIR_EDGE_CLAMP;
+  resize->input_s0 = 0; resize->input_t0 = 0; resize->input_s1 = 1; resize->input_t1 = 1;
+  resize->output_subx = 0; resize->output_suby = 0; resize->output_subw = resize->output_w; resize->output_subh = resize->output_h;
+  resize->input_data_type = data_type;
+  resize->output_data_type = data_type;
+  resize->input_pixel_layout_public = pixel_layout;
+  resize->output_pixel_layout_public = pixel_layout;
+  resize->needs_rebuild = 1;
+}
+
+STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize,
+                                 const void *input_pixels,  int input_w,  int input_h, int input_stride_in_bytes, // stride can be zero
+                                       void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, // stride can be zero
+                                 stbir_pixel_layout pixel_layout, stbir_datatype data_type )
+{
+  resize->input_pixels = input_pixels;
+  resize->input_w = input_w;
+  resize->input_h = input_h;
+  resize->input_stride_in_bytes = input_stride_in_bytes;
+  resize->output_pixels = output_pixels;
+  resize->output_w = output_w;
+  resize->output_h = output_h;
+  resize->output_stride_in_bytes = output_stride_in_bytes;
+  resize->fast_alpha = 0;
+
+  stbir__init_and_set_layout( resize, pixel_layout, data_type );
+}
+
+// You can update parameters any time after resize_init
+STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type )  // by default, datatype from resize_init
+{
+  resize->input_data_type = input_type;
+  resize->output_data_type = output_type;
+  if ( ( resize->samplers ) && ( !resize->needs_rebuild ) )
+    stbir__update_info_from_resize( resize->samplers, resize );
+}
+
+STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb )   // no callbacks by default
+{
+  resize->input_cb = input_cb;
+  resize->output_cb = output_cb;
+
+  if ( ( resize->samplers ) && ( !resize->needs_rebuild ) )
+  {
+    resize->samplers->in_pixels_cb = input_cb;
+    resize->samplers->out_pixels_cb = output_cb;
+  }
+}
+
+STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data )                                     // pass back STBIR_RESIZE* by default
+{
+  resize->user_data = user_data;
+  if ( ( resize->samplers ) && ( !resize->needs_rebuild ) )
+    resize->samplers->user_data = user_data;
+}
+
+STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes )
+{
+  resize->input_pixels = input_pixels;
+  resize->input_stride_in_bytes = input_stride_in_bytes;
+  resize->output_pixels = output_pixels;
+  resize->output_stride_in_bytes = output_stride_in_bytes;
+  if ( ( resize->samplers ) && ( !resize->needs_rebuild ) )
+    stbir__update_info_from_resize( resize->samplers, resize );
+}
+
+
+STBIRDEF int stbir_set_edgemodes( STBIR_RESIZE * resize, stbir_edge horizontal_edge, stbir_edge vertical_edge )       // CLAMP by default
+{
+  resize->horizontal_edge = horizontal_edge;
+  resize->vertical_edge = vertical_edge;
+  resize->needs_rebuild = 1;
+  return 1;
+}
+
+STBIRDEF int stbir_set_filters( STBIR_RESIZE * resize, stbir_filter horizontal_filter, stbir_filter vertical_filter ) // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default
+{
+  resize->horizontal_filter = horizontal_filter;
+  resize->vertical_filter = vertical_filter;
+  resize->needs_rebuild = 1;
+  return 1;
+}
+
+STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support )
+{
+  resize->horizontal_filter_kernel = horizontal_filter; resize->horizontal_filter_support = horizontal_support;
+  resize->vertical_filter_kernel = vertical_filter; resize->vertical_filter_support = vertical_support;
+  resize->needs_rebuild = 1;
+  return 1;
+}
+
+STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout input_pixel_layout, stbir_pixel_layout output_pixel_layout )   // sets new pixel layouts
+{
+  resize->input_pixel_layout_public = input_pixel_layout;
+  resize->output_pixel_layout_public = output_pixel_layout;
+  resize->needs_rebuild = 1;
+  return 1;
+}
+
+
+STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, int non_pma_alpha_speed_over_quality )   // sets alpha speed
+{
+  resize->fast_alpha = non_pma_alpha_speed_over_quality;
+  resize->needs_rebuild = 1;
+  return 1;
+}
+
+STBIRDEF int stbir_set_input_subrect( STBIR_RESIZE * resize, double s0, double t0, double s1, double t1 )                 // sets input region (full region by default)
+{
+  resize->input_s0 = s0;
+  resize->input_t0 = t0;
+  resize->input_s1 = s1;
+  resize->input_t1 = t1;
+  resize->needs_rebuild = 1;
+
+  // are we inbounds?
+  if ( ( s1 < stbir__small_float ) || ( (s1-s0) < stbir__small_float ) ||
+       ( t1 < stbir__small_float ) || ( (t1-t0) < stbir__small_float ) ||
+       ( s0 > (1.0f-stbir__small_float) ) ||
+       ( t0 > (1.0f-stbir__small_float) ) )
+    return 0;
+
+  return 1;
+}
+
+STBIRDEF int stbir_set_output_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh )          // sets input region (full region by default)
+{
+  resize->output_subx = subx;
+  resize->output_suby = suby;
+  resize->output_subw = subw;
+  resize->output_subh = subh;
+  resize->needs_rebuild = 1;
+
+  // are we inbounds?
+  if ( ( subx >= resize->output_w ) || ( ( subx + subw ) <= 0 ) || ( suby >= resize->output_h ) || ( ( suby + subh ) <= 0 ) || ( subw == 0 ) || ( subh == 0 ) )
+    return 0;
+
+  return 1;
+}
+
+STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh )                 // sets both regions (full regions by default)
+{
+  double s0, t0, s1, t1;
+
+  s0 = ( (double)subx ) / ( (double)resize->output_w );
+  t0 = ( (double)suby ) / ( (double)resize->output_h );
+  s1 = ( (double)(subx+subw) ) / ( (double)resize->output_w );
+  t1 = ( (double)(suby+subh) ) / ( (double)resize->output_h );
+
+  resize->input_s0 = s0;
+  resize->input_t0 = t0;
+  resize->input_s1 = s1;
+  resize->input_t1 = t1;
+  resize->output_subx = subx;
+  resize->output_suby = suby;
+  resize->output_subw = subw;
+  resize->output_subh = subh;
+  resize->needs_rebuild = 1;
+
+  // are we inbounds?
+  if ( ( subx >= resize->output_w ) || ( ( subx + subw ) <= 0 ) || ( suby >= resize->output_h ) || ( ( suby + subh ) <= 0 ) || ( subw == 0 ) || ( subh == 0 ) )
+    return 0;
+
+  return 1;
+}
+
+static int stbir__perform_build( STBIR_RESIZE * resize, int splits )
+{
+  stbir__contributors conservative = { 0, 0 };
+  stbir__sampler horizontal, vertical;
+  int new_output_subx, new_output_suby;
+  stbir__info * out_info;
+  #ifdef STBIR_PROFILE
+  stbir__info profile_infod;  // used to contain building profile info before everything is allocated
+  stbir__info * profile_info = &profile_infod;
+  #endif
+
+  // have we already built the samplers?
+  if ( resize->samplers )
+    return 0;
+
+  #define STBIR_RETURN_ERROR_AND_ASSERT( exp )  STBIR_ASSERT( !(exp) ); if (exp) return 0;
+  STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->horizontal_filter >= STBIR_FILTER_OTHER)
+  STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->vertical_filter >= STBIR_FILTER_OTHER)
+  #undef STBIR_RETURN_ERROR_AND_ASSERT
+
+  if ( splits <= 0 )
+    return 0;
+
+  STBIR_PROFILE_BUILD_FIRST_START( build );
+
+  new_output_subx = resize->output_subx;
+  new_output_suby = resize->output_suby;
+
+  // do horizontal clip and scale calcs
+  if ( !stbir__calculate_region_transform( &horizontal.scale_info, resize->output_w, &new_output_subx, resize->output_subw, resize->input_w, resize->input_s0, resize->input_s1 ) )
+    return 0;
+
+  // do vertical clip and scale calcs
+  if ( !stbir__calculate_region_transform( &vertical.scale_info, resize->output_h, &new_output_suby, resize->output_subh, resize->input_h, resize->input_t0, resize->input_t1 ) )
+    return 0;
+
+  // if nothing to do, just return
+  if ( ( horizontal.scale_info.output_sub_size == 0 ) || ( vertical.scale_info.output_sub_size == 0 ) )
+    return 0;
+
+  stbir__set_sampler(&horizontal, resize->horizontal_filter, resize->horizontal_filter_kernel, resize->horizontal_filter_support, resize->horizontal_edge, &horizontal.scale_info, 1, resize->user_data );
+  stbir__get_conservative_extents( &horizontal, &conservative, resize->user_data );
+  stbir__set_sampler(&vertical, resize->vertical_filter, resize->horizontal_filter_kernel, resize->vertical_filter_support, resize->vertical_edge, &vertical.scale_info, 0, resize->user_data );
+
+  if ( ( vertical.scale_info.output_sub_size / splits ) < STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS ) // each split should be a minimum of 4 scanlines (handwavey choice)
+  {
+    splits = vertical.scale_info.output_sub_size / STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS;
+    if ( splits == 0 ) splits = 1;
+  }
+
+  STBIR_PROFILE_BUILD_START( alloc );
+  out_info = stbir__alloc_internal_mem_and_build_samplers( &horizontal, &vertical, &conservative, resize->input_pixel_layout_public, resize->output_pixel_layout_public, splits, new_output_subx, new_output_suby, resize->fast_alpha, resize->user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO );
+  STBIR_PROFILE_BUILD_END( alloc );
+  STBIR_PROFILE_BUILD_END( build );
+
+  if ( out_info )
+  {
+    resize->splits = splits;
+    resize->samplers = out_info;
+    resize->needs_rebuild = 0;
+    #ifdef STBIR_PROFILE
+      STBIR_MEMCPY( &out_info->profile, &profile_infod.profile, sizeof( out_info->profile ) );
+    #endif
+
+    // update anything that can be changed without recalcing samplers
+    stbir__update_info_from_resize( out_info, resize );
+
+    return splits;
+  }
+
+  return 0;
+}
+
+void stbir_free_samplers( STBIR_RESIZE * resize )
+{
+  if ( resize->samplers )
+  {
+    stbir__free_internal_mem( resize->samplers );
+    resize->samplers = 0;
+    resize->called_alloc = 0;
+  }
+}
+
+STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int splits )
+{
+  if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) )
+  {
+    if ( resize->samplers )
+      stbir_free_samplers( resize );
+
+    resize->called_alloc = 1;
+    return stbir__perform_build( resize, splits );
+  }
+
+  STBIR_PROFILE_BUILD_CLEAR( resize->samplers );
+
+  return 1;
+}
+
+STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize )
+{
+  return stbir_build_samplers_with_splits( resize, 1 );
+}
+
+STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize )
+{
+  int result;
+
+  if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) )
+  {
+    int alloc_state = resize->called_alloc;  // remember allocated state
+
+    if ( resize->samplers )
+    {
+      stbir__free_internal_mem( resize->samplers );
+      resize->samplers = 0;
+    }
+
+    if ( !stbir_build_samplers( resize ) )
+      return 0;
+
+    resize->called_alloc = alloc_state;
+
+    // if build_samplers succeeded (above), but there are no samplers set, then
+    //   the area to stretch into was zero pixels, so don't do anything and return
+    //   success
+    if ( resize->samplers == 0 )
+      return 1;
+  }
+  else
+  {
+    // didn't build anything - clear it
+    STBIR_PROFILE_BUILD_CLEAR( resize->samplers );
+  }
+
+  // do resize
+  result = stbir__perform_resize( resize->samplers, 0, resize->splits );
+
+  // if we alloced, then free
+  if ( !resize->called_alloc )
+  {
+    stbir_free_samplers( resize );
+    resize->samplers = 0;
+  }
+
+  return result;
+}
+
+STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count )
+{
+  STBIR_ASSERT( resize->samplers );
+
+  // if we're just doing the whole thing, call full
+  if ( ( split_start == -1 ) || ( ( split_start == 0 ) && ( split_count == resize->splits ) ) )
+    return stbir_resize_extended( resize );
+
+  // you **must** build samplers first when using split resize
+  if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) )
+    return 0;
+
+  if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) )
+    return 0;
+
+  // do resize
+  return stbir__perform_resize( resize->samplers, split_start, split_count );
+}
+
+static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * output_pixels, int type_size, int output_w, int output_h, int output_stride_in_bytes, stbir_internal_pixel_layout pixel_layout )
+{
+  size_t size;
+  int pitch;
+  void * ptr;
+
+  pitch = output_w * type_size * stbir__pixel_channels[ pixel_layout ];
+  if ( pitch == 0 )
+    return 0;
+
+  if ( output_stride_in_bytes == 0 )
+    output_stride_in_bytes = pitch;
+
+  if ( output_stride_in_bytes < pitch )
+    return 0;
+
+  size = output_stride_in_bytes * output_h;
+  if ( size == 0 )
+    return 0;
+
+  *ret_ptr = 0;
+  *ret_pitch = output_stride_in_bytes;
+
+  if ( output_pixels == 0 )
+  {
+    ptr = STBIR_MALLOC( size, 0 );
+    if ( ptr == 0 )
+      return 0;
+
+    *ret_ptr = ptr;
+    *ret_pitch = pitch;
+  }
+
+  return 1;
+}
+
+
+STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                                          unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                                                          stbir_pixel_layout pixel_layout )
+{
+  STBIR_RESIZE resize;
+  unsigned char * optr;
+  int opitch;
+
+  if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
+    return 0;
+
+  stbir_resize_init( &resize,
+                     input_pixels,  input_w,  input_h,  input_stride_in_bytes,
+                     (optr) ? optr : output_pixels, output_w, output_h, opitch,
+                     pixel_layout, STBIR_TYPE_UINT8 );
+
+  if ( !stbir_resize_extended( &resize ) )
+  {
+    if ( optr )
+      STBIR_FREE( optr, 0 );
+    return 0;
+  }
+
+  return (optr) ? optr : output_pixels;
+}
+
+STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                                        unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                                                        stbir_pixel_layout pixel_layout )
+{
+  STBIR_RESIZE resize;
+  unsigned char * optr;
+  int opitch;
+
+  if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
+    return 0;
+
+  stbir_resize_init( &resize,
+                     input_pixels,  input_w,  input_h,  input_stride_in_bytes,
+                     (optr) ? optr : output_pixels, output_w, output_h, opitch,
+                     pixel_layout, STBIR_TYPE_UINT8_SRGB );
+
+  if ( !stbir_resize_extended( &resize ) )
+  {
+    if ( optr )
+      STBIR_FREE( optr, 0 );
+    return 0;
+  }
+
+  return (optr) ? optr : output_pixels;
+}
+
+
+STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                                  float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                                                  stbir_pixel_layout pixel_layout )
+{
+  STBIR_RESIZE resize;
+  float * optr;
+  int opitch;
+
+  if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( float ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
+    return 0;
+
+  stbir_resize_init( &resize,
+                     input_pixels,  input_w,  input_h,  input_stride_in_bytes,
+                     (optr) ? optr : output_pixels, output_w, output_h, opitch,
+                     pixel_layout, STBIR_TYPE_FLOAT );
+
+  if ( !stbir_resize_extended( &resize ) )
+  {
+    if ( optr )
+      STBIR_FREE( optr, 0 );
+    return 0;
+  }
+
+  return (optr) ? optr : output_pixels;
+}
+
+
+STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
+                                    void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+                              stbir_pixel_layout pixel_layout, stbir_datatype data_type,
+                              stbir_edge edge, stbir_filter filter )
+{
+  STBIR_RESIZE resize;
+  float * optr;
+  int opitch;
+
+  if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, stbir__type_size[data_type], output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
+    return 0;
+
+  stbir_resize_init( &resize,
+                     input_pixels,  input_w,  input_h,  input_stride_in_bytes,
+                     (optr) ? optr : output_pixels, output_w, output_h, output_stride_in_bytes,
+                     pixel_layout, data_type );
+
+  resize.horizontal_edge = edge;
+  resize.vertical_edge = edge;
+  resize.horizontal_filter = filter;
+  resize.vertical_filter = filter;
+
+  if ( !stbir_resize_extended( &resize ) )
+  {
+    if ( optr )
+      STBIR_FREE( optr, 0 );
+    return 0;
+  }
+
+  return (optr) ? optr : output_pixels;
+}
+
+#ifdef STBIR_PROFILE
+
+STBIRDEF void stbir_resize_build_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize )
+{
+  static char const * bdescriptions[6] = { "Building", "Allocating", "Horizontal sampler", "Vertical sampler", "Coefficient cleanup", "Coefficient piovot" } ;
+  stbir__info* samp = resize->samplers;
+  int i;
+
+  typedef int testa[ (STBIR__ARRAY_SIZE( bdescriptions ) == (STBIR__ARRAY_SIZE( samp->profile.array )-1) )?1:-1];
+  typedef int testb[ (sizeof( samp->profile.array ) == (sizeof(samp->profile.named)) )?1:-1];
+  typedef int testc[ (sizeof( info->clocks ) >= (sizeof(samp->profile.named)) )?1:-1];
+
+  for( i = 0 ; i < STBIR__ARRAY_SIZE( bdescriptions ) ; i++)
+    info->clocks[i] = samp->profile.array[i+1];
+
+  info->total_clocks = samp->profile.named.total;
+  info->descriptions = bdescriptions;
+  info->count = STBIR__ARRAY_SIZE( bdescriptions );
+}
+
+STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize, int split_start, int split_count )
+{
+  static char const * descriptions[7] = { "Looping", "Vertical sampling", "Horizontal sampling", "Scanline input", "Scanline output", "Alpha weighting", "Alpha unweighting" };
+  stbir__per_split_info * split_info;
+  int s, i;
+
+  typedef int testa[ (STBIR__ARRAY_SIZE( descriptions ) == (STBIR__ARRAY_SIZE( split_info->profile.array )-1) )?1:-1];
+  typedef int testb[ (sizeof( split_info->profile.array ) == (sizeof(split_info->profile.named)) )?1:-1];
+  typedef int testc[ (sizeof( info->clocks ) >= (sizeof(split_info->profile.named)) )?1:-1];
+
+  if ( split_start == -1 )
+  {
+    split_start = 0;
+    split_count = resize->samplers->splits;
+  }
+
+  if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) )
+  {
+    info->total_clocks = 0;
+    info->descriptions = 0;
+    info->count = 0;
+    return;
+  }
+
+  split_info = resize->samplers->split_info + split_start;
+
+  // sum up the profile from all the splits
+  for( i = 0 ; i < STBIR__ARRAY_SIZE( descriptions ) ; i++ )
+  {
+    stbir_uint64 sum = 0;
+    for( s = 0 ; s < split_count ; s++ )
+      sum += split_info[s].profile.array[i+1];
+    info->clocks[i] = sum;
+  }
+
+  info->total_clocks = split_info->profile.named.total;
+  info->descriptions = descriptions;
+  info->count = STBIR__ARRAY_SIZE( descriptions );
+}
+
+STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STBIR_RESIZE const * resize )
+{
+  stbir_resize_split_profile_info( info, resize, -1, 0 );
+}
+
+#endif // STBIR_PROFILE
+
+#undef STBIR_BGR
+#undef STBIR_1CHANNEL
+#undef STBIR_2CHANNEL
+#undef STBIR_RGB
+#undef STBIR_RGBA
+#undef STBIR_4CHANNEL
+#undef STBIR_BGRA
+#undef STBIR_ARGB
+#undef STBIR_ABGR
+#undef STBIR_RA
+#undef STBIR_AR
+#undef STBIR_RGBA_PM
+#undef STBIR_BGRA_PM
+#undef STBIR_ARGB_PM
+#undef STBIR_ABGR_PM
+#undef STBIR_RA_PM
+#undef STBIR_AR_PM
+
+#endif // STB_IMAGE_RESIZE_IMPLEMENTATION
+
+#else  // STB_IMAGE_RESIZE_HORIZONTALS&STB_IMAGE_RESIZE_DO_VERTICALS
+
+// we reinclude the header file to define all the horizontal functions
+//   specializing each function for the number of coeffs is 20-40% faster *OVERALL*
+
+// by including the header file again this way, we can still debug the functions
+
+#define STBIR_strs_join2( start, mid, end ) start##mid##end
+#define STBIR_strs_join1( start, mid, end ) STBIR_strs_join2( start, mid, end )
+
+#define STBIR_strs_join24( start, mid1, mid2, end ) start##mid1##mid2##end
+#define STBIR_strs_join14( start, mid1, mid2, end ) STBIR_strs_join24( start, mid1, mid2, end )
+
+#ifdef STB_IMAGE_RESIZE_DO_CODERS
+
+#ifdef stbir__decode_suffix
+#define STBIR__CODER_NAME( name ) STBIR_strs_join1( name, _, stbir__decode_suffix )
+#else
+#define STBIR__CODER_NAME( name ) name
+#endif
+
+#ifdef stbir__decode_swizzle
+#define stbir__decode_simdf8_flip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3),stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg)
+#define stbir__decode_simdf4_flip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__decode_order0,stbir__decode_order1),stbir__decode_order2,stbir__decode_order3)(reg, reg)
+#define stbir__encode_simdf8_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( STBIR_strs_join1( stbir__simdf8_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3),stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg)
+#define stbir__encode_simdf4_unflip(reg) STBIR_strs_join1( STBIR_strs_join1( stbir__simdf_0123to,stbir__encode_order0,stbir__encode_order1),stbir__encode_order2,stbir__encode_order3)(reg, reg)
+#else
+#define stbir__decode_order0 0
+#define stbir__decode_order1 1
+#define stbir__decode_order2 2
+#define stbir__decode_order3 3
+#define stbir__encode_order0 0
+#define stbir__encode_order1 1
+#define stbir__encode_order2 2
+#define stbir__encode_order3 3
+#define stbir__decode_simdf8_flip(reg)
+#define stbir__decode_simdf4_flip(reg)
+#define stbir__encode_simdf8_unflip(reg)
+#define stbir__encode_simdf4_unflip(reg)
+#endif
+
+#ifdef STBIR_SIMD8
+#define stbir__encode_simdfX_unflip  stbir__encode_simdf8_unflip
+#else
+#define stbir__encode_simdfX_unflip  stbir__encode_simdf4_unflip
+#endif
+
+static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * decodep, int width_times_channels, void const * inputp )
+{
+  float STBIR_STREAMOUT_PTR( * ) decode = decodep;
+  float * decode_end = (float*) decode + width_times_channels;
+  unsigned char const * input = (unsigned char const*)inputp;
+
+  #ifdef STBIR_SIMD
+  unsigned char const * end_input_m16 = input + width_times_channels - 16;
+  if ( width_times_channels >= 16 )
+  {
+    decode_end -= 16;
+    for(;;)
+    {
+      #ifdef STBIR_SIMD8
+      stbir__simdi i; stbir__simdi8 o0,o1;
+      stbir__simdf8 of0, of1;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdi_load( i, input );
+      stbir__simdi8_expand_u8_to_u32( o0, o1, i );
+      stbir__simdi8_convert_i32_to_float( of0, o0 );
+      stbir__simdi8_convert_i32_to_float( of1, o1 );
+      stbir__simdf8_mult( of0, of0, STBIR_max_uint8_as_float_inverted8);
+      stbir__simdf8_mult( of1, of1, STBIR_max_uint8_as_float_inverted8);
+      stbir__decode_simdf8_flip( of0 );
+      stbir__decode_simdf8_flip( of1 );
+      stbir__simdf8_store( decode + 0, of0 );
+      stbir__simdf8_store( decode + 8, of1 );
+      #else
+      stbir__simdi i, o0, o1, o2, o3;
+      stbir__simdf of0, of1, of2, of3;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdi_load( i, input );
+      stbir__simdi_expand_u8_to_u32( o0,o1,o2,o3,i);
+      stbir__simdi_convert_i32_to_float( of0, o0 );
+      stbir__simdi_convert_i32_to_float( of1, o1 );
+      stbir__simdi_convert_i32_to_float( of2, o2 );
+      stbir__simdi_convert_i32_to_float( of3, o3 );
+      stbir__simdf_mult( of0, of0, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );
+      stbir__simdf_mult( of1, of1, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );
+      stbir__simdf_mult( of2, of2, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );
+      stbir__simdf_mult( of3, of3, STBIR__CONSTF(STBIR_max_uint8_as_float_inverted) );
+      stbir__decode_simdf4_flip( of0 );
+      stbir__decode_simdf4_flip( of1 );
+      stbir__decode_simdf4_flip( of2 );
+      stbir__decode_simdf4_flip( of3 );
+      stbir__simdf_store( decode + 0,  of0 );
+      stbir__simdf_store( decode + 4,  of1 );
+      stbir__simdf_store( decode + 8,  of2 );
+      stbir__simdf_store( decode + 12, of3 );
+      #endif
+      decode += 16;
+      input += 16;
+      if ( decode <= decode_end )
+        continue;
+      if ( decode == ( decode_end + 16 ) )
+        break;
+      decode = decode_end; // backup and do last couple
+      input = end_input_m16;
+    }
+    return;
+  }
+  #endif
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  decode += 4;
+  while( decode <= decode_end )
+  {
+    STBIR_SIMD_NO_UNROLL(decode);
+    decode[0-4] = ((float)(input[stbir__decode_order0])) * stbir__max_uint8_as_float_inverted;
+    decode[1-4] = ((float)(input[stbir__decode_order1])) * stbir__max_uint8_as_float_inverted;
+    decode[2-4] = ((float)(input[stbir__decode_order2])) * stbir__max_uint8_as_float_inverted;
+    decode[3-4] = ((float)(input[stbir__decode_order3])) * stbir__max_uint8_as_float_inverted;
+    decode += 4;
+    input += 4;
+  }
+  decode -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( decode < decode_end )
+  {
+    STBIR_NO_UNROLL(decode);
+    decode[0] = ((float)(input[stbir__decode_order0])) * stbir__max_uint8_as_float_inverted;
+    #if stbir__coder_min_num >= 2
+    decode[1] = ((float)(input[stbir__decode_order1])) * stbir__max_uint8_as_float_inverted;
+    #endif
+    #if stbir__coder_min_num >= 3
+    decode[2] = ((float)(input[stbir__decode_order2])) * stbir__max_uint8_as_float_inverted;
+    #endif
+    decode += stbir__coder_min_num;
+    input += stbir__coder_min_num;
+  }
+  #endif
+}
+
+static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outputp, int width_times_channels, float const * encode )
+{
+  unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char *) outputp;
+  unsigned char * end_output = ( (unsigned char *) output ) + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  if ( width_times_channels >= stbir__simdfX_float_count*2 )
+  {
+    float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;
+    end_output -= stbir__simdfX_float_count*2;
+    for(;;)
+    {
+      stbir__simdfX e0, e1;
+      stbir__simdi i;
+      STBIR_SIMD_NO_UNROLL(encode);
+      stbir__simdfX_madd_mem( e0, STBIR_simd_point5X, STBIR_max_uint8_as_floatX, encode );
+      stbir__simdfX_madd_mem( e1, STBIR_simd_point5X, STBIR_max_uint8_as_floatX, encode+stbir__simdfX_float_count );
+      stbir__encode_simdfX_unflip( e0 );
+      stbir__encode_simdfX_unflip( e1 );
+      #ifdef STBIR_SIMD8
+      stbir__simdf8_pack_to_16bytes( i, e0, e1 );
+      stbir__simdi_store( output, i );
+      #else
+      stbir__simdf_pack_to_8bytes( i, e0, e1 );
+      stbir__simdi_store2( output, i );
+      #endif
+      encode += stbir__simdfX_float_count*2;
+      output += stbir__simdfX_float_count*2;
+      if ( output <= end_output )
+        continue;
+      if ( output == ( end_output + stbir__simdfX_float_count*2 ) )
+        break;
+      output = end_output; // backup and do last couple
+      encode = end_encode_m8;
+    }
+    return;
+  }
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    stbir__simdf e0;
+    stbir__simdi i0;
+    STBIR_NO_UNROLL(encode);
+    stbir__simdf_load( e0, encode );
+    stbir__simdf_madd( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), e0 );
+    stbir__encode_simdf4_unflip( e0 );
+    stbir__simdf_pack_to_8bytes( i0, e0, e0 );  // only use first 4
+    *(int*)(output-4) = stbir__simdi_to_int( i0 );
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( output < end_output )
+  {
+    stbir__simdf e0;
+    STBIR_NO_UNROLL(encode);
+    stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order0 ); output[0] = stbir__simdf_convert_float_to_uint8( e0 );
+    #if stbir__coder_min_num >= 2
+    stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order1 ); output[1] = stbir__simdf_convert_float_to_uint8( e0 );
+    #endif
+    #if stbir__coder_min_num >= 3
+    stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order2 ); output[2] = stbir__simdf_convert_float_to_uint8( e0 );
+    #endif
+    output += stbir__coder_min_num;
+    encode += stbir__coder_min_num;
+  }
+  #endif
+
+  #else
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    float f;
+    f = encode[stbir__encode_order0] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[0-4] = (unsigned char)f;
+    f = encode[stbir__encode_order1] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[1-4] = (unsigned char)f;
+    f = encode[stbir__encode_order2] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[2-4] = (unsigned char)f;
+    f = encode[stbir__encode_order3] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[3-4] = (unsigned char)f;
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( output < end_output )
+  {
+    float f;
+    STBIR_NO_UNROLL(encode);
+    f = encode[stbir__encode_order0] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[0] = (unsigned char)f;
+    #if stbir__coder_min_num >= 2
+    f = encode[stbir__encode_order1] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[1] = (unsigned char)f;
+    #endif
+    #if stbir__coder_min_num >= 3
+    f = encode[stbir__encode_order2] * stbir__max_uint8_as_float + 0.5f; STBIR_CLAMP(f, 0, 255); output[2] = (unsigned char)f;
+    #endif
+    output += stbir__coder_min_num;
+    encode += stbir__coder_min_num;
+  }
+  #endif
+  #endif
+}
+
+static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int width_times_channels, void const * inputp )
+{
+  float STBIR_STREAMOUT_PTR( * ) decode = decodep;
+  float * decode_end = (float*) decode + width_times_channels;
+  unsigned char const * input = (unsigned char const*)inputp;
+
+  #ifdef STBIR_SIMD
+  unsigned char const * end_input_m16 = input + width_times_channels - 16;
+  if ( width_times_channels >= 16 )
+  {
+    decode_end -= 16;
+    for(;;)
+    {
+      #ifdef STBIR_SIMD8
+      stbir__simdi i; stbir__simdi8 o0,o1;
+      stbir__simdf8 of0, of1;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdi_load( i, input );
+      stbir__simdi8_expand_u8_to_u32( o0, o1, i );
+      stbir__simdi8_convert_i32_to_float( of0, o0 );
+      stbir__simdi8_convert_i32_to_float( of1, o1 );
+      stbir__decode_simdf8_flip( of0 );
+      stbir__decode_simdf8_flip( of1 );
+      stbir__simdf8_store( decode + 0, of0 );
+      stbir__simdf8_store( decode + 8, of1 );
+      #else
+      stbir__simdi i, o0, o1, o2, o3;
+      stbir__simdf of0, of1, of2, of3;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdi_load( i, input );
+      stbir__simdi_expand_u8_to_u32( o0,o1,o2,o3,i);
+      stbir__simdi_convert_i32_to_float( of0, o0 );
+      stbir__simdi_convert_i32_to_float( of1, o1 );
+      stbir__simdi_convert_i32_to_float( of2, o2 );
+      stbir__simdi_convert_i32_to_float( of3, o3 );
+      stbir__decode_simdf4_flip( of0 );
+      stbir__decode_simdf4_flip( of1 );
+      stbir__decode_simdf4_flip( of2 );
+      stbir__decode_simdf4_flip( of3 );
+      stbir__simdf_store( decode + 0,  of0 );
+      stbir__simdf_store( decode + 4,  of1 );
+      stbir__simdf_store( decode + 8,  of2 );
+      stbir__simdf_store( decode + 12, of3 );
+#endif
+      decode += 16;
+      input += 16;
+      if ( decode <= decode_end )
+        continue;
+      if ( decode == ( decode_end + 16 ) )
+        break;
+      decode = decode_end; // backup and do last couple
+      input = end_input_m16;
+    }
+    return;
+  }
+  #endif
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  decode += 4;
+  while( decode <= decode_end )
+  {
+    STBIR_SIMD_NO_UNROLL(decode);
+    decode[0-4] = ((float)(input[stbir__decode_order0]));
+    decode[1-4] = ((float)(input[stbir__decode_order1]));
+    decode[2-4] = ((float)(input[stbir__decode_order2]));
+    decode[3-4] = ((float)(input[stbir__decode_order3]));
+    decode += 4;
+    input += 4;
+  }
+  decode -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( decode < decode_end )
+  {
+    STBIR_NO_UNROLL(decode);
+    decode[0] = ((float)(input[stbir__decode_order0]));
+    #if stbir__coder_min_num >= 2
+    decode[1] = ((float)(input[stbir__decode_order1]));
+    #endif
+    #if stbir__coder_min_num >= 3
+    decode[2] = ((float)(input[stbir__decode_order2]));
+    #endif
+    decode += stbir__coder_min_num;
+    input += stbir__coder_min_num;
+  }
+  #endif
+}
+
+static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int width_times_channels, float const * encode )
+{
+  unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char *) outputp;
+  unsigned char * end_output = ( (unsigned char *) output ) + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  if ( width_times_channels >= stbir__simdfX_float_count*2 )
+  {
+    float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;
+    end_output -= stbir__simdfX_float_count*2;
+    for(;;)
+    {
+      stbir__simdfX e0, e1;
+      stbir__simdi i;
+      STBIR_SIMD_NO_UNROLL(encode);
+      stbir__simdfX_add_mem( e0, STBIR_simd_point5X, encode );
+      stbir__simdfX_add_mem( e1, STBIR_simd_point5X, encode+stbir__simdfX_float_count );
+      stbir__encode_simdfX_unflip( e0 );
+      stbir__encode_simdfX_unflip( e1 );
+      #ifdef STBIR_SIMD8
+      stbir__simdf8_pack_to_16bytes( i, e0, e1 );
+      stbir__simdi_store( output, i );
+      #else
+      stbir__simdf_pack_to_8bytes( i, e0, e1 );
+      stbir__simdi_store2( output, i );
+      #endif
+      encode += stbir__simdfX_float_count*2;
+      output += stbir__simdfX_float_count*2;
+      if ( output <= end_output )
+        continue;
+      if ( output == ( end_output + stbir__simdfX_float_count*2 ) )
+        break;
+      output = end_output; // backup and do last couple
+      encode = end_encode_m8;
+    }
+    return;
+  }
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    stbir__simdf e0;
+    stbir__simdi i0;
+    STBIR_NO_UNROLL(encode);
+    stbir__simdf_load( e0, encode );
+    stbir__simdf_add( e0, STBIR__CONSTF(STBIR_simd_point5), e0 );
+    stbir__encode_simdf4_unflip( e0 );
+    stbir__simdf_pack_to_8bytes( i0, e0, e0 );  // only use first 4
+    *(int*)(output-4) = stbir__simdi_to_int( i0 );
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  #else
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    float f;
+    f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 255); output[0-4] = (unsigned char)f;
+    f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 255); output[1-4] = (unsigned char)f;
+    f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 255); output[2-4] = (unsigned char)f;
+    f = encode[stbir__encode_order3] + 0.5f; STBIR_CLAMP(f, 0, 255); output[3-4] = (unsigned char)f;
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( output < end_output )
+  {
+    float f;
+    STBIR_NO_UNROLL(encode);
+    f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 255); output[0] = (unsigned char)f;
+    #if stbir__coder_min_num >= 2
+    f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 255); output[1] = (unsigned char)f;
+    #endif
+    #if stbir__coder_min_num >= 3
+    f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 255); output[2] = (unsigned char)f;
+    #endif
+    output += stbir__coder_min_num;
+    encode += stbir__coder_min_num;
+  }
+  #endif
+}
+
+static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int width_times_channels, void const * inputp )
+{
+  float STBIR_STREAMOUT_PTR( * ) decode = decodep;
+  float const * decode_end = (float*) decode + width_times_channels;
+  unsigned char const * input = (unsigned char const *)inputp;
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  decode += 4;
+  while( decode <= decode_end )
+  {
+    decode[0-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order0 ] ];
+    decode[1-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order1 ] ];
+    decode[2-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order2 ] ];
+    decode[3-4] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order3 ] ];
+    decode += 4;
+    input += 4;
+  }
+  decode -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( decode < decode_end )
+  {
+    STBIR_NO_UNROLL(decode);
+    decode[0] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order0 ] ];
+    #if stbir__coder_min_num >= 2
+    decode[1] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order1 ] ];
+    #endif
+    #if stbir__coder_min_num >= 3
+    decode[2] = stbir__srgb_uchar_to_linear_float[ input[ stbir__decode_order2 ] ];
+    #endif
+    decode += stbir__coder_min_num;
+    input += stbir__coder_min_num;
+  }
+  #endif
+}
+
+#define stbir__min_max_shift20( i, f ) \
+    stbir__simdf_max( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_zero )) ); \
+    stbir__simdf_min( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_one  )) ); \
+    stbir__simdi_32shr( i, stbir_simdi_castf( f ), 20 );
+
+#define stbir__scale_and_convert( i, f ) \
+    stbir__simdf_madd( f, STBIR__CONSTF( STBIR_simd_point5 ), STBIR__CONSTF( STBIR_max_uint8_as_float ), f ); \
+    stbir__simdf_max( f, f, stbir__simdf_zeroP() ); \
+    stbir__simdf_min( f, f, STBIR__CONSTF( STBIR_max_uint8_as_float ) ); \
+    stbir__simdf_convert_float_to_i32( i, f );
+
+#define stbir__linear_to_srgb_finish( i, f ) \
+{ \
+    stbir__simdi temp;  \
+    stbir__simdi_32shr( temp, stbir_simdi_castf( f ), 12 ) ; \
+    stbir__simdi_and( temp, temp, STBIR__CONSTI(STBIR_mastissa_mask) ); \
+    stbir__simdi_or( temp, temp, STBIR__CONSTI(STBIR_topscale) ); \
+    stbir__simdi_16madd( i, i, temp ); \
+    stbir__simdi_32shr( i, i, 16 ); \
+}
+
+#define stbir__simdi_table_lookup2( v0,v1, table ) \
+{ \
+  stbir__simdi_u32 temp0,temp1; \
+  temp0.m128i_i128 = v0; \
+  temp1.m128i_i128 = v1; \
+  temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \
+  temp1.m128i_u32[0] = table[temp1.m128i_i32[0]]; temp1.m128i_u32[1] = table[temp1.m128i_i32[1]]; temp1.m128i_u32[2] = table[temp1.m128i_i32[2]]; temp1.m128i_u32[3] = table[temp1.m128i_i32[3]]; \
+  v0 = temp0.m128i_i128; \
+  v1 = temp1.m128i_i128; \
+}
+
+#define stbir__simdi_table_lookup3( v0,v1,v2, table ) \
+{ \
+  stbir__simdi_u32 temp0,temp1,temp2; \
+  temp0.m128i_i128 = v0; \
+  temp1.m128i_i128 = v1; \
+  temp2.m128i_i128 = v2; \
+  temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \
+  temp1.m128i_u32[0] = table[temp1.m128i_i32[0]]; temp1.m128i_u32[1] = table[temp1.m128i_i32[1]]; temp1.m128i_u32[2] = table[temp1.m128i_i32[2]]; temp1.m128i_u32[3] = table[temp1.m128i_i32[3]]; \
+  temp2.m128i_u32[0] = table[temp2.m128i_i32[0]]; temp2.m128i_u32[1] = table[temp2.m128i_i32[1]]; temp2.m128i_u32[2] = table[temp2.m128i_i32[2]]; temp2.m128i_u32[3] = table[temp2.m128i_i32[3]]; \
+  v0 = temp0.m128i_i128; \
+  v1 = temp1.m128i_i128; \
+  v2 = temp2.m128i_i128; \
+}
+
+#define stbir__simdi_table_lookup4( v0,v1,v2,v3, table ) \
+{ \
+  stbir__simdi_u32 temp0,temp1,temp2,temp3; \
+  temp0.m128i_i128 = v0; \
+  temp1.m128i_i128 = v1; \
+  temp2.m128i_i128 = v2; \
+  temp3.m128i_i128 = v3; \
+  temp0.m128i_u32[0] = table[temp0.m128i_i32[0]]; temp0.m128i_u32[1] = table[temp0.m128i_i32[1]]; temp0.m128i_u32[2] = table[temp0.m128i_i32[2]]; temp0.m128i_u32[3] = table[temp0.m128i_i32[3]]; \
+  temp1.m128i_u32[0] = table[temp1.m128i_i32[0]]; temp1.m128i_u32[1] = table[temp1.m128i_i32[1]]; temp1.m128i_u32[2] = table[temp1.m128i_i32[2]]; temp1.m128i_u32[3] = table[temp1.m128i_i32[3]]; \
+  temp2.m128i_u32[0] = table[temp2.m128i_i32[0]]; temp2.m128i_u32[1] = table[temp2.m128i_i32[1]]; temp2.m128i_u32[2] = table[temp2.m128i_i32[2]]; temp2.m128i_u32[3] = table[temp2.m128i_i32[3]]; \
+  temp3.m128i_u32[0] = table[temp3.m128i_i32[0]]; temp3.m128i_u32[1] = table[temp3.m128i_i32[1]]; temp3.m128i_u32[2] = table[temp3.m128i_i32[2]]; temp3.m128i_u32[3] = table[temp3.m128i_i32[3]]; \
+  v0 = temp0.m128i_i128; \
+  v1 = temp1.m128i_i128; \
+  v2 = temp2.m128i_i128; \
+  v3 = temp3.m128i_i128; \
+}
+
+static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int width_times_channels, float const * encode )
+{
+  unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp;
+  unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8;
+
+  if ( width_times_channels >= 16 )
+  {
+    float const * end_encode_m16 = encode + width_times_channels - 16;
+    end_output -= 16;
+    for(;;)
+    {
+      stbir__simdf f0, f1, f2, f3;
+      stbir__simdi i0, i1, i2, i3;
+      STBIR_SIMD_NO_UNROLL(encode);
+
+      stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );
+
+      stbir__min_max_shift20( i0, f0 );
+      stbir__min_max_shift20( i1, f1 );
+      stbir__min_max_shift20( i2, f2 );
+      stbir__min_max_shift20( i3, f3 );
+
+      stbir__simdi_table_lookup4( i0, i1, i2, i3, to_srgb );
+
+      stbir__linear_to_srgb_finish( i0, f0 );
+      stbir__linear_to_srgb_finish( i1, f1 );
+      stbir__linear_to_srgb_finish( i2, f2 );
+      stbir__linear_to_srgb_finish( i3, f3 );
+
+      stbir__interleave_pack_and_store_16_u8( output,  STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) );
+
+      encode += 16;
+      output += 16;
+      if ( output <= end_output )
+        continue;
+      if ( output == ( end_output + 16 ) )
+        break;
+      output = end_output; // backup and do last couple
+      encode = end_encode_m16;
+    }
+    return;
+  }
+  #endif
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while ( output <= end_output )
+  {
+    STBIR_SIMD_NO_UNROLL(encode);
+
+    output[0-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] );
+    output[1-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order1] );
+    output[2-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order2] );
+    output[3-4] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order3] );
+
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( output < end_output )
+  {
+    STBIR_NO_UNROLL(encode);
+    output[0] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] );
+    #if stbir__coder_min_num >= 2
+    output[1] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order1] );
+    #endif
+    #if stbir__coder_min_num >= 3
+    output[2] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order2] );
+    #endif
+    output += stbir__coder_min_num;
+    encode += stbir__coder_min_num;
+  }
+  #endif
+}
+
+#if ( stbir__coder_min_num == 4 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )
+
+static void STBIR__CODER_NAME(stbir__decode_uint8_srgb4_linearalpha)( float * decodep, int width_times_channels, void const * inputp )
+{
+  float STBIR_STREAMOUT_PTR( * ) decode = decodep;
+  float const * decode_end = (float*) decode + width_times_channels;
+  unsigned char const * input = (unsigned char const *)inputp;
+  do {
+    decode[0] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ];
+    decode[1] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order1] ];
+    decode[2] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order2] ];
+    decode[3] = ( (float) input[stbir__decode_order3] ) * stbir__max_uint8_as_float_inverted;
+    input += 4;
+    decode += 4;
+  } while( decode < decode_end );
+}
+
+
+static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * outputp, int width_times_channels, float const * encode )
+{
+  unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp;
+  unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8;
+
+  if ( width_times_channels >= 16 )
+  {
+    float const * end_encode_m16 = encode + width_times_channels - 16;
+    end_output -= 16;
+    for(;;)
+    {
+      stbir__simdf f0, f1, f2, f3;
+      stbir__simdi i0, i1, i2, i3;
+
+      STBIR_SIMD_NO_UNROLL(encode);
+      stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );
+
+      stbir__min_max_shift20( i0, f0 );
+      stbir__min_max_shift20( i1, f1 );
+      stbir__min_max_shift20( i2, f2 );
+      stbir__scale_and_convert( i3, f3 );
+
+      stbir__simdi_table_lookup3( i0, i1, i2, to_srgb );
+
+      stbir__linear_to_srgb_finish( i0, f0 );
+      stbir__linear_to_srgb_finish( i1, f1 );
+      stbir__linear_to_srgb_finish( i2, f2 );
+
+      stbir__interleave_pack_and_store_16_u8( output,  STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) );
+
+      output += 16;
+      encode += 16;
+
+      if ( output <= end_output )
+        continue;
+      if ( output == ( end_output + 16 ) )
+        break;
+      output = end_output; // backup and do last couple
+      encode = end_encode_m16;
+    }
+    return;
+  }
+  #endif
+
+  do {
+    float f;
+    STBIR_SIMD_NO_UNROLL(encode);
+
+    output[stbir__decode_order0] = stbir__linear_to_srgb_uchar( encode[0] );
+    output[stbir__decode_order1] = stbir__linear_to_srgb_uchar( encode[1] );
+    output[stbir__decode_order2] = stbir__linear_to_srgb_uchar( encode[2] );
+
+    f = encode[3] * stbir__max_uint8_as_float + 0.5f;
+    STBIR_CLAMP(f, 0, 255);
+    output[stbir__decode_order3] = (unsigned char) f;
+
+    output += 4;
+    encode += 4;
+  } while( output < end_output );
+}
+
+#endif
+
+#if ( stbir__coder_min_num == 2 ) || ( ( stbir__coder_min_num == 1 ) && ( !defined(stbir__decode_swizzle) ) )
+
+static void STBIR__CODER_NAME(stbir__decode_uint8_srgb2_linearalpha)( float * decodep, int width_times_channels, void const * inputp )
+{
+  float STBIR_STREAMOUT_PTR( * ) decode = decodep;
+  float const * decode_end = (float*) decode + width_times_channels;
+  unsigned char const * input = (unsigned char const *)inputp;
+  decode += 4;
+  while( decode <= decode_end )
+  {
+    decode[0-4] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0] ];
+    decode[1-4] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted;
+    decode[2-4] = stbir__srgb_uchar_to_linear_float[ input[stbir__decode_order0+2] ];
+    decode[3-4] = ( (float) input[stbir__decode_order1+2] ) * stbir__max_uint8_as_float_inverted;
+    input += 4;
+    decode += 4;
+  }
+  decode -= 4;
+  if( decode < decode_end )
+  {
+    decode[0] = stbir__srgb_uchar_to_linear_float[ stbir__decode_order0 ];
+    decode[1] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted;
+  }
+}
+
+static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * outputp, int width_times_channels, float const * encode )
+{
+  unsigned char STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned char*) outputp;
+  unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8;
+
+  if ( width_times_channels >= 16 )
+  {
+    float const * end_encode_m16 = encode + width_times_channels - 16;
+    end_output -= 16;
+    for(;;)
+    {
+      stbir__simdf f0, f1, f2, f3;
+      stbir__simdi i0, i1, i2, i3;
+
+      STBIR_SIMD_NO_UNROLL(encode);
+      stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );
+
+      stbir__min_max_shift20( i0, f0 );
+      stbir__scale_and_convert( i1, f1 );
+      stbir__min_max_shift20( i2, f2 );
+      stbir__scale_and_convert( i3, f3 );
+
+      stbir__simdi_table_lookup2( i0, i2, to_srgb );
+
+      stbir__linear_to_srgb_finish( i0, f0 );
+      stbir__linear_to_srgb_finish( i2, f2 );
+
+      stbir__interleave_pack_and_store_16_u8( output,  STBIR_strs_join1(i, ,stbir__encode_order0), STBIR_strs_join1(i, ,stbir__encode_order1), STBIR_strs_join1(i, ,stbir__encode_order2), STBIR_strs_join1(i, ,stbir__encode_order3) );
+
+      output += 16;
+      encode += 16;
+      if ( output <= end_output )
+        continue;
+      if ( output == ( end_output + 16 ) )
+        break;
+      output = end_output; // backup and do last couple
+      encode = end_encode_m16;
+    }
+    return;
+  }
+  #endif
+
+  do {
+    float f;
+    STBIR_SIMD_NO_UNROLL(encode);
+
+    output[stbir__decode_order0] = stbir__linear_to_srgb_uchar( encode[0] );
+
+    f = encode[1] * stbir__max_uint8_as_float + 0.5f;
+    STBIR_CLAMP(f, 0, 255);
+    output[stbir__decode_order1] = (unsigned char) f;
+
+    output += 2;
+    encode += 2;
+  } while( output < end_output );
+}
+
+#endif
+
+static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decodep, int width_times_channels, void const * inputp )
+{
+  float STBIR_STREAMOUT_PTR( * ) decode = decodep;
+  float * decode_end = (float*) decode + width_times_channels;
+  unsigned short const * input = (unsigned short const *)inputp;
+
+  #ifdef STBIR_SIMD
+  unsigned short const * end_input_m8 = input + width_times_channels - 8;
+  if ( width_times_channels >= 8 )
+  {
+    decode_end -= 8;
+    for(;;)
+    {
+      #ifdef STBIR_SIMD8
+      stbir__simdi i; stbir__simdi8 o;
+      stbir__simdf8 of;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdi_load( i, input );
+      stbir__simdi8_expand_u16_to_u32( o, i );
+      stbir__simdi8_convert_i32_to_float( of, o );
+      stbir__simdf8_mult( of, of, STBIR_max_uint16_as_float_inverted8);
+      stbir__decode_simdf8_flip( of );
+      stbir__simdf8_store( decode + 0, of );
+      #else
+      stbir__simdi i, o0, o1;
+      stbir__simdf of0, of1;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdi_load( i, input );
+      stbir__simdi_expand_u16_to_u32( o0,o1,i );
+      stbir__simdi_convert_i32_to_float( of0, o0 );
+      stbir__simdi_convert_i32_to_float( of1, o1 );
+      stbir__simdf_mult( of0, of0, STBIR__CONSTF(STBIR_max_uint16_as_float_inverted) );
+      stbir__simdf_mult( of1, of1, STBIR__CONSTF(STBIR_max_uint16_as_float_inverted));
+      stbir__decode_simdf4_flip( of0 );
+      stbir__decode_simdf4_flip( of1 );
+      stbir__simdf_store( decode + 0,  of0 );
+      stbir__simdf_store( decode + 4,  of1 );
+      #endif
+      decode += 8;
+      input += 8;
+      if ( decode <= decode_end )
+        continue;
+      if ( decode == ( decode_end + 8 ) )
+        break;
+      decode = decode_end; // backup and do last couple
+      input = end_input_m8;
+    }
+    return;
+  }
+  #endif
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  decode += 4;
+  while( decode <= decode_end )
+  {
+    STBIR_SIMD_NO_UNROLL(decode);
+    decode[0-4] = ((float)(input[stbir__decode_order0])) * stbir__max_uint16_as_float_inverted;
+    decode[1-4] = ((float)(input[stbir__decode_order1])) * stbir__max_uint16_as_float_inverted;
+    decode[2-4] = ((float)(input[stbir__decode_order2])) * stbir__max_uint16_as_float_inverted;
+    decode[3-4] = ((float)(input[stbir__decode_order3])) * stbir__max_uint16_as_float_inverted;
+    decode += 4;
+    input += 4;
+  }
+  decode -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( decode < decode_end )
+  {
+    STBIR_NO_UNROLL(decode);
+    decode[0] = ((float)(input[stbir__decode_order0])) * stbir__max_uint16_as_float_inverted;
+    #if stbir__coder_min_num >= 2
+    decode[1] = ((float)(input[stbir__decode_order1])) * stbir__max_uint16_as_float_inverted;
+    #endif
+    #if stbir__coder_min_num >= 3
+    decode[2] = ((float)(input[stbir__decode_order2])) * stbir__max_uint16_as_float_inverted;
+    #endif
+    decode += stbir__coder_min_num;
+    input += stbir__coder_min_num;
+  }
+  #endif
+}
+
+
+static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * outputp, int width_times_channels, float const * encode )
+{
+  unsigned short STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned short*) outputp;
+  unsigned short * end_output = ( (unsigned short*) output ) + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  {
+    if ( width_times_channels >= stbir__simdfX_float_count*2 )
+    {
+      float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;
+      end_output -= stbir__simdfX_float_count*2;
+      for(;;)
+      {
+        stbir__simdfX e0, e1;
+        stbir__simdiX i;
+        STBIR_SIMD_NO_UNROLL(encode);
+        stbir__simdfX_madd_mem( e0, STBIR_simd_point5X, STBIR_max_uint16_as_floatX, encode );
+        stbir__simdfX_madd_mem( e1, STBIR_simd_point5X, STBIR_max_uint16_as_floatX, encode+stbir__simdfX_float_count );
+        stbir__encode_simdfX_unflip( e0 );
+        stbir__encode_simdfX_unflip( e1 );
+        stbir__simdfX_pack_to_words( i, e0, e1 );
+        stbir__simdiX_store( output, i );
+        encode += stbir__simdfX_float_count*2;
+        output += stbir__simdfX_float_count*2;
+        if ( output <= end_output )
+          continue;
+        if ( output == ( end_output + stbir__simdfX_float_count*2 ) )
+          break;
+        output = end_output;     // backup and do last couple
+        encode = end_encode_m8;
+      }
+      return;
+    }
+  }
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    stbir__simdf e;
+    stbir__simdi i;
+    STBIR_NO_UNROLL(encode);
+    stbir__simdf_load( e, encode );
+    stbir__simdf_madd( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), e );
+    stbir__encode_simdf4_unflip( e );
+    stbir__simdf_pack_to_8words( i, e, e );  // only use first 4
+    stbir__simdi_store2( output-4, i );
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( output < end_output )
+  {
+    stbir__simdf e;
+    STBIR_NO_UNROLL(encode);
+    stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order0 ); output[0] = stbir__simdf_convert_float_to_short( e );
+    #if stbir__coder_min_num >= 2
+    stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order1 ); output[1] = stbir__simdf_convert_float_to_short( e );
+    #endif
+    #if stbir__coder_min_num >= 3
+    stbir__simdf_madd1_mem( e, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint16_as_float), encode+stbir__encode_order2 ); output[2] = stbir__simdf_convert_float_to_short( e );
+    #endif
+    output += stbir__coder_min_num;
+    encode += stbir__coder_min_num;
+  }
+  #endif
+
+  #else
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    float f;
+    STBIR_SIMD_NO_UNROLL(encode);
+    f = encode[stbir__encode_order0] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0-4] = (unsigned short)f;
+    f = encode[stbir__encode_order1] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1-4] = (unsigned short)f;
+    f = encode[stbir__encode_order2] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2-4] = (unsigned short)f;
+    f = encode[stbir__encode_order3] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[3-4] = (unsigned short)f;
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( output < end_output )
+  {
+    float f;
+    STBIR_NO_UNROLL(encode);
+    f = encode[stbir__encode_order0] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0] = (unsigned short)f;
+    #if stbir__coder_min_num >= 2
+    f = encode[stbir__encode_order1] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1] = (unsigned short)f;
+    #endif
+    #if stbir__coder_min_num >= 3
+    f = encode[stbir__encode_order2] * stbir__max_uint16_as_float + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2] = (unsigned short)f;
+    #endif
+    output += stbir__coder_min_num;
+    encode += stbir__coder_min_num;
+  }
+  #endif
+  #endif
+}
+
+static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int width_times_channels, void const * inputp )
+{
+  float STBIR_STREAMOUT_PTR( * ) decode = decodep;
+  float * decode_end = (float*) decode + width_times_channels;
+  unsigned short const * input = (unsigned short const *)inputp;
+
+  #ifdef STBIR_SIMD
+  unsigned short const * end_input_m8 = input + width_times_channels - 8;
+  if ( width_times_channels >= 8 )
+  {
+    decode_end -= 8;
+    for(;;)
+    {
+      #ifdef STBIR_SIMD8
+      stbir__simdi i; stbir__simdi8 o;
+      stbir__simdf8 of;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdi_load( i, input );
+      stbir__simdi8_expand_u16_to_u32( o, i );
+      stbir__simdi8_convert_i32_to_float( of, o );
+      stbir__decode_simdf8_flip( of );
+      stbir__simdf8_store( decode + 0, of );
+      #else
+      stbir__simdi i, o0, o1;
+      stbir__simdf of0, of1;
+      STBIR_NO_UNROLL(decode);
+      stbir__simdi_load( i, input );
+      stbir__simdi_expand_u16_to_u32( o0, o1, i );
+      stbir__simdi_convert_i32_to_float( of0, o0 );
+      stbir__simdi_convert_i32_to_float( of1, o1 );
+      stbir__decode_simdf4_flip( of0 );
+      stbir__decode_simdf4_flip( of1 );
+      stbir__simdf_store( decode + 0,  of0 );
+      stbir__simdf_store( decode + 4,  of1 );
+      #endif
+      decode += 8;
+      input += 8;
+      if ( decode <= decode_end )
+        continue;
+      if ( decode == ( decode_end + 8 ) )
+        break;
+      decode = decode_end; // backup and do last couple
+      input = end_input_m8;
+    }
+    return;
+  }
+  #endif
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  decode += 4;
+  while( decode <= decode_end )
+  {
+    STBIR_SIMD_NO_UNROLL(decode);
+    decode[0-4] = ((float)(input[stbir__decode_order0]));
+    decode[1-4] = ((float)(input[stbir__decode_order1]));
+    decode[2-4] = ((float)(input[stbir__decode_order2]));
+    decode[3-4] = ((float)(input[stbir__decode_order3]));
+    decode += 4;
+    input += 4;
+  }
+  decode -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( decode < decode_end )
+  {
+    STBIR_NO_UNROLL(decode);
+    decode[0] = ((float)(input[stbir__decode_order0]));
+    #if stbir__coder_min_num >= 2
+    decode[1] = ((float)(input[stbir__decode_order1]));
+    #endif
+    #if stbir__coder_min_num >= 3
+    decode[2] = ((float)(input[stbir__decode_order2]));
+    #endif
+    decode += stbir__coder_min_num;
+    input += stbir__coder_min_num;
+  }
+  #endif
+}
+
+static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int width_times_channels, float const * encode )
+{
+  unsigned short STBIR_SIMD_STREAMOUT_PTR( * ) output = (unsigned short*) outputp;
+  unsigned short * end_output = ( (unsigned short*) output ) + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  {
+    if ( width_times_channels >= stbir__simdfX_float_count*2 )
+    {
+      float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;
+      end_output -= stbir__simdfX_float_count*2;
+      for(;;)
+      {
+        stbir__simdfX e0, e1;
+        stbir__simdiX i;
+        STBIR_SIMD_NO_UNROLL(encode);
+        stbir__simdfX_add_mem( e0, STBIR_simd_point5X, encode );
+        stbir__simdfX_add_mem( e1, STBIR_simd_point5X, encode+stbir__simdfX_float_count );
+        stbir__encode_simdfX_unflip( e0 );
+        stbir__encode_simdfX_unflip( e1 );
+        stbir__simdfX_pack_to_words( i, e0, e1 );
+        stbir__simdiX_store( output, i );
+        encode += stbir__simdfX_float_count*2;
+        output += stbir__simdfX_float_count*2;
+        if ( output <= end_output )
+          continue;
+        if ( output == ( end_output + stbir__simdfX_float_count*2 ) )
+          break;
+        output = end_output; // backup and do last couple
+        encode = end_encode_m8;
+      }
+      return;
+    }
+  }
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    stbir__simdf e;
+    stbir__simdi i;
+    STBIR_NO_UNROLL(encode);
+    stbir__simdf_load( e, encode );
+    stbir__simdf_add( e, STBIR__CONSTF(STBIR_simd_point5), e );
+    stbir__encode_simdf4_unflip( e );
+    stbir__simdf_pack_to_8words( i, e, e );  // only use first 4
+    stbir__simdi_store2( output-4, i );
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  #else
+
+  // try to do blocks of 4 when you can
+  #if  stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    float f;
+    STBIR_SIMD_NO_UNROLL(encode);
+    f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0-4] = (unsigned short)f;
+    f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1-4] = (unsigned short)f;
+    f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2-4] = (unsigned short)f;
+    f = encode[stbir__encode_order3] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[3-4] = (unsigned short)f;
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( output < end_output )
+  {
+    float f;
+    STBIR_NO_UNROLL(encode);
+    f = encode[stbir__encode_order0] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[0] = (unsigned short)f;
+    #if stbir__coder_min_num >= 2
+    f = encode[stbir__encode_order1] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[1] = (unsigned short)f;
+    #endif
+    #if stbir__coder_min_num >= 3
+    f = encode[stbir__encode_order2] + 0.5f; STBIR_CLAMP(f, 0, 65535); output[2] = (unsigned short)f;
+    #endif
+    output += stbir__coder_min_num;
+    encode += stbir__coder_min_num;
+  }
+  #endif
+}
+
+static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, int width_times_channels, void const * inputp )
+{
+  float STBIR_STREAMOUT_PTR( * ) decode = decodep;
+  float * decode_end = (float*) decode + width_times_channels;
+  stbir__FP16 const * input = (stbir__FP16 const *)inputp;
+
+  #ifdef STBIR_SIMD
+  if ( width_times_channels >= 8 )
+  {
+    stbir__FP16 const * end_input_m8 = input + width_times_channels - 8;
+    decode_end -= 8;
+    for(;;)
+    {
+      STBIR_NO_UNROLL(decode);
+
+      stbir__half_to_float_SIMD( decode, input );
+      #ifdef stbir__decode_swizzle
+      #ifdef STBIR_SIMD8
+      {
+        stbir__simdf8 of;
+        stbir__simdf8_load( of, decode );
+        stbir__decode_simdf8_flip( of );
+        stbir__simdf8_store( decode, of );
+      }
+      #else
+      {
+        stbir__simdf of0,of1;
+        stbir__simdf_load( of0, decode );
+        stbir__simdf_load( of1, decode+4 );
+        stbir__decode_simdf4_flip( of0 );
+        stbir__decode_simdf4_flip( of1 );
+        stbir__simdf_store( decode, of0 );
+        stbir__simdf_store( decode+4, of1 );
+      }
+      #endif
+      #endif
+      decode += 8;
+      input += 8;
+      if ( decode <= decode_end )
+        continue;
+      if ( decode == ( decode_end + 8 ) )
+        break;
+      decode = decode_end; // backup and do last couple
+      input = end_input_m8;
+    }
+    return;
+  }
+  #endif
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  decode += 4;
+  while( decode <= decode_end )
+  {
+    STBIR_SIMD_NO_UNROLL(decode);
+    decode[0-4] = stbir__half_to_float(input[stbir__decode_order0]);
+    decode[1-4] = stbir__half_to_float(input[stbir__decode_order1]);
+    decode[2-4] = stbir__half_to_float(input[stbir__decode_order2]);
+    decode[3-4] = stbir__half_to_float(input[stbir__decode_order3]);
+    decode += 4;
+    input += 4;
+  }
+  decode -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( decode < decode_end )
+  {
+    STBIR_NO_UNROLL(decode);
+    decode[0] = stbir__half_to_float(input[stbir__decode_order0]);
+    #if stbir__coder_min_num >= 2
+    decode[1] = stbir__half_to_float(input[stbir__decode_order1]);
+    #endif
+    #if stbir__coder_min_num >= 3
+    decode[2] = stbir__half_to_float(input[stbir__decode_order2]);
+    #endif
+    decode += stbir__coder_min_num;
+    input += stbir__coder_min_num;
+  }
+  #endif
+}
+
+static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp, int width_times_channels, float const * encode )
+{
+  stbir__FP16 STBIR_SIMD_STREAMOUT_PTR( * ) output = (stbir__FP16*) outputp;
+  stbir__FP16 * end_output = ( (stbir__FP16*) output ) + width_times_channels;
+
+  #ifdef STBIR_SIMD
+  if ( width_times_channels >= 8 )
+  {
+    float const * end_encode_m8 = encode + width_times_channels - 8;
+    end_output -= 8;
+    for(;;)
+    {
+      STBIR_SIMD_NO_UNROLL(encode);
+      #ifdef stbir__decode_swizzle
+      #ifdef STBIR_SIMD8
+      {
+        stbir__simdf8 of;
+        stbir__simdf8_load( of, encode );
+        stbir__encode_simdf8_unflip( of );
+        stbir__float_to_half_SIMD( output, (float*)&of );
+      }
+      #else
+      {
+        stbir__simdf of[2];
+        stbir__simdf_load( of[0], encode );
+        stbir__simdf_load( of[1], encode+4 );
+        stbir__encode_simdf4_unflip( of[0] );
+        stbir__encode_simdf4_unflip( of[1] );
+        stbir__float_to_half_SIMD( output, (float*)of );
+      }
+      #endif
+      #else
+      stbir__float_to_half_SIMD( output, encode );
+      #endif
+      encode += 8;
+      output += 8;
+      if ( output <= end_output )
+        continue;
+      if ( output == ( end_output + 8 ) )
+        break;
+      output = end_output; // backup and do last couple
+      encode = end_encode_m8;
+    }
+    return;
+  }
+  #endif
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    STBIR_SIMD_NO_UNROLL(output);
+    output[0-4] = stbir__float_to_half(encode[stbir__encode_order0]);
+    output[1-4] = stbir__float_to_half(encode[stbir__encode_order1]);
+    output[2-4] = stbir__float_to_half(encode[stbir__encode_order2]);
+    output[3-4] = stbir__float_to_half(encode[stbir__encode_order3]);
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( output < end_output )
+  {
+    STBIR_NO_UNROLL(output);
+    output[0] = stbir__float_to_half(encode[stbir__encode_order0]);
+    #if stbir__coder_min_num >= 2
+    output[1] = stbir__float_to_half(encode[stbir__encode_order1]);
+    #endif
+    #if stbir__coder_min_num >= 3
+    output[2] = stbir__float_to_half(encode[stbir__encode_order2]);
+    #endif
+    output += stbir__coder_min_num;
+    encode += stbir__coder_min_num;
+  }
+  #endif
+}
+
+static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int width_times_channels, void const * inputp )
+{
+  #ifdef stbir__decode_swizzle
+  float STBIR_STREAMOUT_PTR( * ) decode = decodep;
+  float * decode_end = (float*) decode + width_times_channels;
+  float const * input = (float const *)inputp;
+
+  #ifdef STBIR_SIMD
+  if ( width_times_channels >= 16 )
+  {
+    float const * end_input_m16 = input + width_times_channels - 16;
+    decode_end -= 16;
+    for(;;)
+    {
+      STBIR_NO_UNROLL(decode);
+      #ifdef stbir__decode_swizzle
+      #ifdef STBIR_SIMD8
+      {
+        stbir__simdf8 of0,of1;
+        stbir__simdf8_load( of0, input );
+        stbir__simdf8_load( of1, input+8 );
+        stbir__decode_simdf8_flip( of0 );
+        stbir__decode_simdf8_flip( of1 );
+        stbir__simdf8_store( decode, of0 );
+        stbir__simdf8_store( decode+8, of1 );
+      }
+      #else
+      {
+        stbir__simdf of0,of1,of2,of3;
+        stbir__simdf_load( of0, input );
+        stbir__simdf_load( of1, input+4 );
+        stbir__simdf_load( of2, input+8 );
+        stbir__simdf_load( of3, input+12 );
+        stbir__decode_simdf4_flip( of0 );
+        stbir__decode_simdf4_flip( of1 );
+        stbir__decode_simdf4_flip( of2 );
+        stbir__decode_simdf4_flip( of3 );
+        stbir__simdf_store( decode, of0 );
+        stbir__simdf_store( decode+4, of1 );
+        stbir__simdf_store( decode+8, of2 );
+        stbir__simdf_store( decode+12, of3 );
+      }
+      #endif
+      #endif
+      decode += 16;
+      input += 16;
+      if ( decode <= decode_end )
+        continue;
+      if ( decode == ( decode_end + 16 ) )
+        break;
+      decode = decode_end; // backup and do last couple
+      input = end_input_m16;
+    }
+    return;
+  }
+  #endif
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  decode += 4;
+  while( decode <= decode_end )
+  {
+    STBIR_SIMD_NO_UNROLL(decode);
+    decode[0-4] = input[stbir__decode_order0];
+    decode[1-4] = input[stbir__decode_order1];
+    decode[2-4] = input[stbir__decode_order2];
+    decode[3-4] = input[stbir__decode_order3];
+    decode += 4;
+    input += 4;
+  }
+  decode -= 4;
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( decode < decode_end )
+  {
+    STBIR_NO_UNROLL(decode);
+    decode[0] = input[stbir__decode_order0];
+    #if stbir__coder_min_num >= 2
+    decode[1] = input[stbir__decode_order1];
+    #endif
+    #if stbir__coder_min_num >= 3
+    decode[2] = input[stbir__decode_order2];
+    #endif
+    decode += stbir__coder_min_num;
+    input += stbir__coder_min_num;
+  }
+  #endif
+
+  #else
+
+  if ( (void*)decodep != inputp )
+    STBIR_MEMCPY( decodep, inputp, width_times_channels * sizeof( float ) );
+
+  #endif
+}
+
+static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int width_times_channels, float const * encode )
+{
+  #if !defined( STBIR_FLOAT_HIGH_CLAMP ) && !defined(STBIR_FLOAT_LO_CLAMP) && !defined(stbir__decode_swizzle)
+
+  if ( (void*)outputp != (void*) encode )
+    STBIR_MEMCPY( outputp, encode, width_times_channels * sizeof( float ) );
+
+  #else
+
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = (float*) outputp;
+  float * end_output = ( (float*) output ) + width_times_channels;
+
+  #ifdef STBIR_FLOAT_HIGH_CLAMP
+  #define stbir_scalar_hi_clamp( v ) if ( v > STBIR_FLOAT_HIGH_CLAMP ) v = STBIR_FLOAT_HIGH_CLAMP;
+  #else
+  #define stbir_scalar_hi_clamp( v )
+  #endif
+  #ifdef STBIR_FLOAT_LOW_CLAMP
+  #define stbir_scalar_lo_clamp( v ) if ( v < STBIR_FLOAT_LOW_CLAMP ) v = STBIR_FLOAT_LOW_CLAMP;
+  #else
+  #define stbir_scalar_lo_clamp( v )
+  #endif
+
+  #ifdef STBIR_SIMD
+
+  #ifdef STBIR_FLOAT_HIGH_CLAMP
+  const stbir__simdfX high_clamp = stbir__simdf_frepX(STBIR_FLOAT_HIGH_CLAMP);
+  #endif
+  #ifdef STBIR_FLOAT_LOW_CLAMP
+  const stbir__simdfX low_clamp = stbir__simdf_frepX(STBIR_FLOAT_LOW_CLAMP);
+  #endif
+
+  if ( width_times_channels >= ( stbir__simdfX_float_count * 2 ) )
+  {
+    float const * end_encode_m8 = encode + width_times_channels - ( stbir__simdfX_float_count * 2 );
+    end_output -= ( stbir__simdfX_float_count * 2 );
+    for(;;)
+    {
+      stbir__simdfX e0, e1;
+      STBIR_SIMD_NO_UNROLL(encode);
+      stbir__simdfX_load( e0, encode );
+      stbir__simdfX_load( e1, encode+stbir__simdfX_float_count );
+#ifdef STBIR_FLOAT_HIGH_CLAMP
+      stbir__simdfX_min( e0, e0, high_clamp );
+      stbir__simdfX_min( e1, e1, high_clamp );
+#endif
+#ifdef STBIR_FLOAT_LOW_CLAMP
+      stbir__simdfX_max( e0, e0, low_clamp );
+      stbir__simdfX_max( e1, e1, low_clamp );
+#endif
+      stbir__encode_simdfX_unflip( e0 );
+      stbir__encode_simdfX_unflip( e1 );
+      stbir__simdfX_store( output, e0 );
+      stbir__simdfX_store( output+stbir__simdfX_float_count, e1 );
+      encode += stbir__simdfX_float_count * 2;
+      output += stbir__simdfX_float_count * 2;
+      if ( output < end_output )
+        continue;
+      if ( output == ( end_output + ( stbir__simdfX_float_count * 2 ) ) )
+        break;
+      output = end_output; // backup and do last couple
+      encode = end_encode_m8;
+    }
+    return;
+  }
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    stbir__simdf e0;
+    STBIR_NO_UNROLL(encode);
+    stbir__simdf_load( e0, encode );
+#ifdef STBIR_FLOAT_HIGH_CLAMP
+    stbir__simdf_min( e0, e0, high_clamp );
+#endif
+#ifdef STBIR_FLOAT_LOW_CLAMP
+    stbir__simdf_max( e0, e0, low_clamp );
+#endif
+    stbir__encode_simdf4_unflip( e0 );
+    stbir__simdf_store( output-4, e0 );
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+  #endif
+
+  #else
+
+  // try to do blocks of 4 when you can
+  #if stbir__coder_min_num != 3 // doesn't divide cleanly by four
+  output += 4;
+  while( output <= end_output )
+  {
+    float e;
+    STBIR_SIMD_NO_UNROLL(encode);
+    e = encode[ stbir__encode_order0 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[0-4] = e;
+    e = encode[ stbir__encode_order1 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[1-4] = e;
+    e = encode[ stbir__encode_order2 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[2-4] = e;
+    e = encode[ stbir__encode_order3 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[3-4] = e;
+    output += 4;
+    encode += 4;
+  }
+  output -= 4;
+
+  #endif
+
+  #endif
+
+  // do the remnants
+  #if stbir__coder_min_num < 4
+  while( output < end_output )
+  {
+    float e;
+    STBIR_NO_UNROLL(encode);
+    e = encode[ stbir__encode_order0 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[0] = e;
+    #if stbir__coder_min_num >= 2
+    e = encode[ stbir__encode_order1 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[1] = e;
+    #endif
+    #if stbir__coder_min_num >= 3
+    e = encode[ stbir__encode_order2 ]; stbir_scalar_hi_clamp( e ); stbir_scalar_lo_clamp( e ); output[2] = e;
+    #endif
+    output += stbir__coder_min_num;
+    encode += stbir__coder_min_num;
+  }
+  #endif
+
+  #endif
+}
+
+#undef stbir__decode_suffix
+#undef stbir__decode_simdf8_flip
+#undef stbir__decode_simdf4_flip
+#undef stbir__decode_order0
+#undef stbir__decode_order1
+#undef stbir__decode_order2
+#undef stbir__decode_order3
+#undef stbir__encode_order0
+#undef stbir__encode_order1
+#undef stbir__encode_order2
+#undef stbir__encode_order3
+#undef stbir__encode_simdf8_unflip
+#undef stbir__encode_simdf4_unflip
+#undef stbir__encode_simdfX_unflip
+#undef STBIR__CODER_NAME
+#undef stbir__coder_min_num
+#undef stbir__decode_swizzle
+#undef stbir_scalar_hi_clamp
+#undef stbir_scalar_lo_clamp
+#undef STB_IMAGE_RESIZE_DO_CODERS
+
+#elif defined( STB_IMAGE_RESIZE_DO_VERTICALS)
+
+#ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#define STBIR_chans( start, end ) STBIR_strs_join14(start,STBIR__vertical_channels,end,_cont)
+#else
+#define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__vertical_channels,end)
+#endif
+
+#if STBIR__vertical_channels >= 1
+#define stbIF0( code ) code
+#else
+#define stbIF0( code )
+#endif
+#if STBIR__vertical_channels >= 2
+#define stbIF1( code ) code
+#else
+#define stbIF1( code )
+#endif
+#if STBIR__vertical_channels >= 3
+#define stbIF2( code ) code
+#else
+#define stbIF2( code )
+#endif
+#if STBIR__vertical_channels >= 4
+#define stbIF3( code ) code
+#else
+#define stbIF3( code )
+#endif
+#if STBIR__vertical_channels >= 5
+#define stbIF4( code ) code
+#else
+#define stbIF4( code )
+#endif
+#if STBIR__vertical_channels >= 6
+#define stbIF5( code ) code
+#else
+#define stbIF5( code )
+#endif
+#if STBIR__vertical_channels >= 7
+#define stbIF6( code ) code
+#else
+#define stbIF6( code )
+#endif
+#if STBIR__vertical_channels >= 8
+#define stbIF7( code ) code
+#else
+#define stbIF7( code )
+#endif
+
+static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** outputs, float const * vertical_coefficients, float const * input, float const * input_end )
+{
+  stbIF0( float STBIR_SIMD_STREAMOUT_PTR( * ) output0 = outputs[0]; float c0s = vertical_coefficients[0]; )
+  stbIF1( float STBIR_SIMD_STREAMOUT_PTR( * ) output1 = outputs[1]; float c1s = vertical_coefficients[1]; )
+  stbIF2( float STBIR_SIMD_STREAMOUT_PTR( * ) output2 = outputs[2]; float c2s = vertical_coefficients[2]; )
+  stbIF3( float STBIR_SIMD_STREAMOUT_PTR( * ) output3 = outputs[3]; float c3s = vertical_coefficients[3]; )
+  stbIF4( float STBIR_SIMD_STREAMOUT_PTR( * ) output4 = outputs[4]; float c4s = vertical_coefficients[4]; )
+  stbIF5( float STBIR_SIMD_STREAMOUT_PTR( * ) output5 = outputs[5]; float c5s = vertical_coefficients[5]; )
+  stbIF6( float STBIR_SIMD_STREAMOUT_PTR( * ) output6 = outputs[6]; float c6s = vertical_coefficients[6]; )
+  stbIF7( float STBIR_SIMD_STREAMOUT_PTR( * ) output7 = outputs[7]; float c7s = vertical_coefficients[7]; )
+
+  #ifdef STBIR_SIMD
+  {
+    stbIF0(stbir__simdfX c0 = stbir__simdf_frepX( c0s ); )
+    stbIF1(stbir__simdfX c1 = stbir__simdf_frepX( c1s ); )
+    stbIF2(stbir__simdfX c2 = stbir__simdf_frepX( c2s ); )
+    stbIF3(stbir__simdfX c3 = stbir__simdf_frepX( c3s ); )
+    stbIF4(stbir__simdfX c4 = stbir__simdf_frepX( c4s ); )
+    stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); )
+    stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); )
+    stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); )
+    while ( ( (char*)input_end - (char*) input ) >= (16*stbir__simdfX_float_count) )
+    {
+      stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3;
+      STBIR_SIMD_NO_UNROLL(output0);
+
+      stbir__simdfX_load( r0, input );               stbir__simdfX_load( r1, input+stbir__simdfX_float_count );     stbir__simdfX_load( r2, input+(2*stbir__simdfX_float_count) );      stbir__simdfX_load( r3, input+(3*stbir__simdfX_float_count) );
+
+      #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+      stbIF0( stbir__simdfX_load( o0, output0 );     stbir__simdfX_load( o1, output0+stbir__simdfX_float_count );   stbir__simdfX_load( o2, output0+(2*stbir__simdfX_float_count) );    stbir__simdfX_load( o3, output0+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c0 );  stbir__simdfX_madd( o1, o1, r1, c0 );  stbir__simdfX_madd( o2, o2, r2, c0 );   stbir__simdfX_madd( o3, o3, r3, c0 );
+              stbir__simdfX_store( output0, o0 );    stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF1( stbir__simdfX_load( o0, output1 );     stbir__simdfX_load( o1, output1+stbir__simdfX_float_count );   stbir__simdfX_load( o2, output1+(2*stbir__simdfX_float_count) );    stbir__simdfX_load( o3, output1+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c1 );  stbir__simdfX_madd( o1, o1, r1, c1 );  stbir__simdfX_madd( o2, o2, r2, c1 );   stbir__simdfX_madd( o3, o3, r3, c1 );
+              stbir__simdfX_store( output1, o0 );    stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF2( stbir__simdfX_load( o0, output2 );     stbir__simdfX_load( o1, output2+stbir__simdfX_float_count );   stbir__simdfX_load( o2, output2+(2*stbir__simdfX_float_count) );    stbir__simdfX_load( o3, output2+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c2 );  stbir__simdfX_madd( o1, o1, r1, c2 );  stbir__simdfX_madd( o2, o2, r2, c2 );   stbir__simdfX_madd( o3, o3, r3, c2 );
+              stbir__simdfX_store( output2, o0 );    stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF3( stbir__simdfX_load( o0, output3 );     stbir__simdfX_load( o1, output3+stbir__simdfX_float_count );   stbir__simdfX_load( o2, output3+(2*stbir__simdfX_float_count) );    stbir__simdfX_load( o3, output3+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c3 );  stbir__simdfX_madd( o1, o1, r1, c3 );  stbir__simdfX_madd( o2, o2, r2, c3 );   stbir__simdfX_madd( o3, o3, r3, c3 );
+              stbir__simdfX_store( output3, o0 );    stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF4( stbir__simdfX_load( o0, output4 );     stbir__simdfX_load( o1, output4+stbir__simdfX_float_count );   stbir__simdfX_load( o2, output4+(2*stbir__simdfX_float_count) );    stbir__simdfX_load( o3, output4+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c4 );  stbir__simdfX_madd( o1, o1, r1, c4 );  stbir__simdfX_madd( o2, o2, r2, c4 );   stbir__simdfX_madd( o3, o3, r3, c4 );
+              stbir__simdfX_store( output4, o0 );    stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF5( stbir__simdfX_load( o0, output5 );     stbir__simdfX_load( o1, output5+stbir__simdfX_float_count );   stbir__simdfX_load( o2, output5+(2*stbir__simdfX_float_count));    stbir__simdfX_load( o3, output5+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c5 );  stbir__simdfX_madd( o1, o1, r1, c5 );  stbir__simdfX_madd( o2, o2, r2, c5 );   stbir__simdfX_madd( o3, o3, r3, c5 );
+              stbir__simdfX_store( output5, o0 );    stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF6( stbir__simdfX_load( o0, output6 );     stbir__simdfX_load( o1, output6+stbir__simdfX_float_count );   stbir__simdfX_load( o2, output6+(2*stbir__simdfX_float_count) );    stbir__simdfX_load( o3, output6+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c6 );  stbir__simdfX_madd( o1, o1, r1, c6 );  stbir__simdfX_madd( o2, o2, r2, c6 );   stbir__simdfX_madd( o3, o3, r3, c6 );
+              stbir__simdfX_store( output6, o0 );    stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF7( stbir__simdfX_load( o0, output7 );     stbir__simdfX_load( o1, output7+stbir__simdfX_float_count );   stbir__simdfX_load( o2, output7+(2*stbir__simdfX_float_count) );    stbir__simdfX_load( o3, output7+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c7 );  stbir__simdfX_madd( o1, o1, r1, c7 );  stbir__simdfX_madd( o2, o2, r2, c7 );   stbir__simdfX_madd( o3, o3, r3, c7 );
+              stbir__simdfX_store( output7, o0 );    stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); )
+      #else
+      stbIF0( stbir__simdfX_mult( o0, r0, c0 );      stbir__simdfX_mult( o1, r1, c0 );      stbir__simdfX_mult( o2, r2, c0 );       stbir__simdfX_mult( o3, r3, c0 );
+              stbir__simdfX_store( output0, o0 );    stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF1( stbir__simdfX_mult( o0, r0, c1 );      stbir__simdfX_mult( o1, r1, c1 );      stbir__simdfX_mult( o2, r2, c1 );       stbir__simdfX_mult( o3, r3, c1 );
+              stbir__simdfX_store( output1, o0 );    stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF2( stbir__simdfX_mult( o0, r0, c2 );      stbir__simdfX_mult( o1, r1, c2 );      stbir__simdfX_mult( o2, r2, c2 );       stbir__simdfX_mult( o3, r3, c2 );
+              stbir__simdfX_store( output2, o0 );    stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF3( stbir__simdfX_mult( o0, r0, c3 );      stbir__simdfX_mult( o1, r1, c3 );      stbir__simdfX_mult( o2, r2, c3 );       stbir__simdfX_mult( o3, r3, c3 );
+              stbir__simdfX_store( output3, o0 );    stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF4( stbir__simdfX_mult( o0, r0, c4 );      stbir__simdfX_mult( o1, r1, c4 );      stbir__simdfX_mult( o2, r2, c4 );       stbir__simdfX_mult( o3, r3, c4 );
+              stbir__simdfX_store( output4, o0 );    stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF5( stbir__simdfX_mult( o0, r0, c5 );      stbir__simdfX_mult( o1, r1, c5 );      stbir__simdfX_mult( o2, r2, c5 );       stbir__simdfX_mult( o3, r3, c5 );
+              stbir__simdfX_store( output5, o0 );    stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF6( stbir__simdfX_mult( o0, r0, c6 );      stbir__simdfX_mult( o1, r1, c6 );      stbir__simdfX_mult( o2, r2, c6 );       stbir__simdfX_mult( o3, r3, c6 );
+              stbir__simdfX_store( output6, o0 );    stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); )
+      stbIF7( stbir__simdfX_mult( o0, r0, c7 );      stbir__simdfX_mult( o1, r1, c7 );      stbir__simdfX_mult( o2, r2, c7 );       stbir__simdfX_mult( o3, r3, c7 );
+              stbir__simdfX_store( output7, o0 );    stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 );   stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); )
+      #endif
+
+      input += (4*stbir__simdfX_float_count);
+      stbIF0( output0 += (4*stbir__simdfX_float_count); ) stbIF1( output1 += (4*stbir__simdfX_float_count); ) stbIF2( output2 += (4*stbir__simdfX_float_count); ) stbIF3( output3 += (4*stbir__simdfX_float_count); ) stbIF4( output4 += (4*stbir__simdfX_float_count); ) stbIF5( output5 += (4*stbir__simdfX_float_count); ) stbIF6( output6 += (4*stbir__simdfX_float_count); ) stbIF7( output7 += (4*stbir__simdfX_float_count); )
+    }
+    while ( ( (char*)input_end - (char*) input ) >= 16 )
+    {
+      stbir__simdf o0, r0;
+      STBIR_SIMD_NO_UNROLL(output0);
+
+      stbir__simdf_load( r0, input );
+
+      #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+      stbIF0( stbir__simdf_load( o0, output0 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) );  stbir__simdf_store( output0, o0 ); )
+      stbIF1( stbir__simdf_load( o0, output1 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) );  stbir__simdf_store( output1, o0 ); )
+      stbIF2( stbir__simdf_load( o0, output2 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) );  stbir__simdf_store( output2, o0 ); )
+      stbIF3( stbir__simdf_load( o0, output3 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) );  stbir__simdf_store( output3, o0 ); )
+      stbIF4( stbir__simdf_load( o0, output4 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) );  stbir__simdf_store( output4, o0 ); )
+      stbIF5( stbir__simdf_load( o0, output5 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) );  stbir__simdf_store( output5, o0 ); )
+      stbIF6( stbir__simdf_load( o0, output6 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) );  stbir__simdf_store( output6, o0 ); )
+      stbIF7( stbir__simdf_load( o0, output7 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) );  stbir__simdf_store( output7, o0 ); )
+      #else
+      stbIF0( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) );   stbir__simdf_store( output0, o0 ); )
+      stbIF1( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) );   stbir__simdf_store( output1, o0 ); )
+      stbIF2( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) );   stbir__simdf_store( output2, o0 ); )
+      stbIF3( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) );   stbir__simdf_store( output3, o0 ); )
+      stbIF4( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) );   stbir__simdf_store( output4, o0 ); )
+      stbIF5( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) );   stbir__simdf_store( output5, o0 ); )
+      stbIF6( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) );   stbir__simdf_store( output6, o0 ); )
+      stbIF7( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) );   stbir__simdf_store( output7, o0 ); )
+      #endif
+
+      input += 4;
+      stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; )
+    }
+  }
+  #else
+  while ( ( (char*)input_end - (char*) input ) >= 16 )
+  {
+    float r0, r1, r2, r3;
+    STBIR_NO_UNROLL(input);
+
+    r0 = input[0], r1 = input[1], r2 = input[2], r3 = input[3];
+
+    #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+    stbIF0( output0[0] += ( r0 * c0s ); output0[1] += ( r1 * c0s ); output0[2] += ( r2 * c0s ); output0[3] += ( r3 * c0s ); )
+    stbIF1( output1[0] += ( r0 * c1s ); output1[1] += ( r1 * c1s ); output1[2] += ( r2 * c1s ); output1[3] += ( r3 * c1s ); )
+    stbIF2( output2[0] += ( r0 * c2s ); output2[1] += ( r1 * c2s ); output2[2] += ( r2 * c2s ); output2[3] += ( r3 * c2s ); )
+    stbIF3( output3[0] += ( r0 * c3s ); output3[1] += ( r1 * c3s ); output3[2] += ( r2 * c3s ); output3[3] += ( r3 * c3s ); )
+    stbIF4( output4[0] += ( r0 * c4s ); output4[1] += ( r1 * c4s ); output4[2] += ( r2 * c4s ); output4[3] += ( r3 * c4s ); )
+    stbIF5( output5[0] += ( r0 * c5s ); output5[1] += ( r1 * c5s ); output5[2] += ( r2 * c5s ); output5[3] += ( r3 * c5s ); )
+    stbIF6( output6[0] += ( r0 * c6s ); output6[1] += ( r1 * c6s ); output6[2] += ( r2 * c6s ); output6[3] += ( r3 * c6s ); )
+    stbIF7( output7[0] += ( r0 * c7s ); output7[1] += ( r1 * c7s ); output7[2] += ( r2 * c7s ); output7[3] += ( r3 * c7s ); )
+    #else
+    stbIF0( output0[0]  = ( r0 * c0s ); output0[1]  = ( r1 * c0s ); output0[2]  = ( r2 * c0s ); output0[3]  = ( r3 * c0s ); )
+    stbIF1( output1[0]  = ( r0 * c1s ); output1[1]  = ( r1 * c1s ); output1[2]  = ( r2 * c1s ); output1[3]  = ( r3 * c1s ); )
+    stbIF2( output2[0]  = ( r0 * c2s ); output2[1]  = ( r1 * c2s ); output2[2]  = ( r2 * c2s ); output2[3]  = ( r3 * c2s ); )
+    stbIF3( output3[0]  = ( r0 * c3s ); output3[1]  = ( r1 * c3s ); output3[2]  = ( r2 * c3s ); output3[3]  = ( r3 * c3s ); )
+    stbIF4( output4[0]  = ( r0 * c4s ); output4[1]  = ( r1 * c4s ); output4[2]  = ( r2 * c4s ); output4[3]  = ( r3 * c4s ); )
+    stbIF5( output5[0]  = ( r0 * c5s ); output5[1]  = ( r1 * c5s ); output5[2]  = ( r2 * c5s ); output5[3]  = ( r3 * c5s ); )
+    stbIF6( output6[0]  = ( r0 * c6s ); output6[1]  = ( r1 * c6s ); output6[2]  = ( r2 * c6s ); output6[3]  = ( r3 * c6s ); )
+    stbIF7( output7[0]  = ( r0 * c7s ); output7[1]  = ( r1 * c7s ); output7[2]  = ( r2 * c7s ); output7[3]  = ( r3 * c7s ); )
+    #endif
+
+    input += 4;
+    stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; )
+  }
+  #endif
+  while ( input < input_end )
+  {
+    float r = input[0];
+    STBIR_NO_UNROLL(output0);
+
+    #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+    stbIF0( output0[0] += ( r * c0s ); )
+    stbIF1( output1[0] += ( r * c1s ); )
+    stbIF2( output2[0] += ( r * c2s ); )
+    stbIF3( output3[0] += ( r * c3s ); )
+    stbIF4( output4[0] += ( r * c4s ); )
+    stbIF5( output5[0] += ( r * c5s ); )
+    stbIF6( output6[0] += ( r * c6s ); )
+    stbIF7( output7[0] += ( r * c7s ); )
+    #else
+    stbIF0( output0[0]  = ( r * c0s ); )
+    stbIF1( output1[0]  = ( r * c1s ); )
+    stbIF2( output2[0]  = ( r * c2s ); )
+    stbIF3( output3[0]  = ( r * c3s ); )
+    stbIF4( output4[0]  = ( r * c4s ); )
+    stbIF5( output5[0]  = ( r * c5s ); )
+    stbIF6( output6[0]  = ( r * c6s ); )
+    stbIF7( output7[0]  = ( r * c7s ); )
+    #endif
+
+    ++input;
+    stbIF0( ++output0; ) stbIF1( ++output1; ) stbIF2( ++output2; ) stbIF3( ++output3; ) stbIF4( ++output4; ) stbIF5( ++output5; ) stbIF6( ++output6; ) stbIF7( ++output7; )
+  }
+}
+
+static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, float const * vertical_coefficients, float const ** inputs, float const * input0_end )
+{
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = outputp;
+
+  stbIF0( float const * input0 = inputs[0]; float c0s = vertical_coefficients[0]; )
+  stbIF1( float const * input1 = inputs[1]; float c1s = vertical_coefficients[1]; )
+  stbIF2( float const * input2 = inputs[2]; float c2s = vertical_coefficients[2]; )
+  stbIF3( float const * input3 = inputs[3]; float c3s = vertical_coefficients[3]; )
+  stbIF4( float const * input4 = inputs[4]; float c4s = vertical_coefficients[4]; )
+  stbIF5( float const * input5 = inputs[5]; float c5s = vertical_coefficients[5]; )
+  stbIF6( float const * input6 = inputs[6]; float c6s = vertical_coefficients[6]; )
+  stbIF7( float const * input7 = inputs[7]; float c7s = vertical_coefficients[7]; )
+
+#if ( STBIR__vertical_channels == 1 ) && !defined(STB_IMAGE_RESIZE_VERTICAL_CONTINUE)
+  // check single channel one weight
+  if ( ( c0s >= (1.0f-0.000001f) ) && ( c0s <= (1.0f+0.000001f) ) )
+  {
+    STBIR_MEMCPY( output, input0, (char*)input0_end - (char*)input0 );
+    return;
+  }
+#endif
+
+  #ifdef STBIR_SIMD
+  {
+    stbIF0(stbir__simdfX c0 = stbir__simdf_frepX( c0s ); )
+    stbIF1(stbir__simdfX c1 = stbir__simdf_frepX( c1s ); )
+    stbIF2(stbir__simdfX c2 = stbir__simdf_frepX( c2s ); )
+    stbIF3(stbir__simdfX c3 = stbir__simdf_frepX( c3s ); )
+    stbIF4(stbir__simdfX c4 = stbir__simdf_frepX( c4s ); )
+    stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); )
+    stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); )
+    stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); )
+
+    while ( ( (char*)input0_end - (char*) input0 ) >= (16*stbir__simdfX_float_count) )
+    {
+      stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3;
+      STBIR_SIMD_NO_UNROLL(output);
+
+      // prefetch four loop iterations ahead (doesn't affect much for small resizes, but helps with big ones)
+      stbIF0( stbir__prefetch( input0 + (16*stbir__simdfX_float_count) ); )
+      stbIF1( stbir__prefetch( input1 + (16*stbir__simdfX_float_count) ); )
+      stbIF2( stbir__prefetch( input2 + (16*stbir__simdfX_float_count) ); )
+      stbIF3( stbir__prefetch( input3 + (16*stbir__simdfX_float_count) ); )
+      stbIF4( stbir__prefetch( input4 + (16*stbir__simdfX_float_count) ); )
+      stbIF5( stbir__prefetch( input5 + (16*stbir__simdfX_float_count) ); )
+      stbIF6( stbir__prefetch( input6 + (16*stbir__simdfX_float_count) ); )
+      stbIF7( stbir__prefetch( input7 + (16*stbir__simdfX_float_count) ); )
+
+      #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+      stbIF0( stbir__simdfX_load( o0, output );      stbir__simdfX_load( o1, output+stbir__simdfX_float_count );   stbir__simdfX_load( o2, output+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( o3, output+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_load( r0, input0 );      stbir__simdfX_load( r1, input0+stbir__simdfX_float_count );   stbir__simdfX_load( r2, input0+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( r3, input0+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c0 );  stbir__simdfX_madd( o1, o1, r1, c0 );                         stbir__simdfX_madd( o2, o2, r2, c0 );                             stbir__simdfX_madd( o3, o3, r3, c0 ); )
+      #else
+      stbIF0( stbir__simdfX_load( r0, input0 );      stbir__simdfX_load( r1, input0+stbir__simdfX_float_count );   stbir__simdfX_load( r2, input0+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( r3, input0+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_mult( o0, r0, c0 );      stbir__simdfX_mult( o1, r1, c0 );                             stbir__simdfX_mult( o2, r2, c0 );                                 stbir__simdfX_mult( o3, r3, c0 );  )
+      #endif
+
+      stbIF1( stbir__simdfX_load( r0, input1 );      stbir__simdfX_load( r1, input1+stbir__simdfX_float_count );   stbir__simdfX_load( r2, input1+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( r3, input1+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c1 );  stbir__simdfX_madd( o1, o1, r1, c1 );                         stbir__simdfX_madd( o2, o2, r2, c1 );                             stbir__simdfX_madd( o3, o3, r3, c1 ); )
+      stbIF2( stbir__simdfX_load( r0, input2 );      stbir__simdfX_load( r1, input2+stbir__simdfX_float_count );   stbir__simdfX_load( r2, input2+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( r3, input2+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c2 );  stbir__simdfX_madd( o1, o1, r1, c2 );                         stbir__simdfX_madd( o2, o2, r2, c2 );                             stbir__simdfX_madd( o3, o3, r3, c2 ); )
+      stbIF3( stbir__simdfX_load( r0, input3 );      stbir__simdfX_load( r1, input3+stbir__simdfX_float_count );   stbir__simdfX_load( r2, input3+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( r3, input3+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c3 );  stbir__simdfX_madd( o1, o1, r1, c3 );                         stbir__simdfX_madd( o2, o2, r2, c3 );                             stbir__simdfX_madd( o3, o3, r3, c3 ); )
+      stbIF4( stbir__simdfX_load( r0, input4 );      stbir__simdfX_load( r1, input4+stbir__simdfX_float_count );   stbir__simdfX_load( r2, input4+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( r3, input4+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c4 );  stbir__simdfX_madd( o1, o1, r1, c4 );                         stbir__simdfX_madd( o2, o2, r2, c4 );                             stbir__simdfX_madd( o3, o3, r3, c4 ); )
+      stbIF5( stbir__simdfX_load( r0, input5 );      stbir__simdfX_load( r1, input5+stbir__simdfX_float_count );   stbir__simdfX_load( r2, input5+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( r3, input5+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c5 );  stbir__simdfX_madd( o1, o1, r1, c5 );                         stbir__simdfX_madd( o2, o2, r2, c5 );                             stbir__simdfX_madd( o3, o3, r3, c5 ); )
+      stbIF6( stbir__simdfX_load( r0, input6 );      stbir__simdfX_load( r1, input6+stbir__simdfX_float_count );   stbir__simdfX_load( r2, input6+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( r3, input6+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c6 );  stbir__simdfX_madd( o1, o1, r1, c6 );                         stbir__simdfX_madd( o2, o2, r2, c6 );                             stbir__simdfX_madd( o3, o3, r3, c6 ); )
+      stbIF7( stbir__simdfX_load( r0, input7 );      stbir__simdfX_load( r1, input7+stbir__simdfX_float_count );   stbir__simdfX_load( r2, input7+(2*stbir__simdfX_float_count) );   stbir__simdfX_load( r3, input7+(3*stbir__simdfX_float_count) );
+              stbir__simdfX_madd( o0, o0, r0, c7 );  stbir__simdfX_madd( o1, o1, r1, c7 );                         stbir__simdfX_madd( o2, o2, r2, c7 );                             stbir__simdfX_madd( o3, o3, r3, c7 ); )
+
+      stbir__simdfX_store( output, o0 );             stbir__simdfX_store( output+stbir__simdfX_float_count, o1 );  stbir__simdfX_store( output+(2*stbir__simdfX_float_count), o2 );  stbir__simdfX_store( output+(3*stbir__simdfX_float_count), o3 );
+      output += (4*stbir__simdfX_float_count);
+      stbIF0( input0 += (4*stbir__simdfX_float_count); ) stbIF1( input1 += (4*stbir__simdfX_float_count); ) stbIF2( input2 += (4*stbir__simdfX_float_count); ) stbIF3( input3 += (4*stbir__simdfX_float_count); ) stbIF4( input4 += (4*stbir__simdfX_float_count); ) stbIF5( input5 += (4*stbir__simdfX_float_count); ) stbIF6( input6 += (4*stbir__simdfX_float_count); ) stbIF7( input7 += (4*stbir__simdfX_float_count); )
+    }
+
+    while ( ( (char*)input0_end - (char*) input0 ) >= 16 )
+    {
+      stbir__simdf o0, r0;
+      STBIR_SIMD_NO_UNROLL(output);
+
+      #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+      stbIF0( stbir__simdf_load( o0, output );   stbir__simdf_load( r0, input0 ); stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); )
+      #else
+      stbIF0( stbir__simdf_load( r0, input0 );  stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c0 ) ); )
+      #endif
+      stbIF1( stbir__simdf_load( r0, input1 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c1 ) ); )
+      stbIF2( stbir__simdf_load( r0, input2 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c2 ) ); )
+      stbIF3( stbir__simdf_load( r0, input3 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c3 ) ); )
+      stbIF4( stbir__simdf_load( r0, input4 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c4 ) ); )
+      stbIF5( stbir__simdf_load( r0, input5 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c5 ) ); )
+      stbIF6( stbir__simdf_load( r0, input6 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); )
+      stbIF7( stbir__simdf_load( r0, input7 );  stbir__simdf_madd( o0, o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); )
+
+      stbir__simdf_store( output, o0 );
+      output += 4;
+      stbIF0( input0 += 4; ) stbIF1( input1 += 4; ) stbIF2( input2 += 4; ) stbIF3( input3 += 4; ) stbIF4( input4 += 4; ) stbIF5( input5 += 4; ) stbIF6( input6 += 4; ) stbIF7( input7 += 4; )
+    }
+  }
+  #else
+  while ( ( (char*)input0_end - (char*) input0 ) >= 16 )
+  {
+    float o0, o1, o2, o3;
+    STBIR_NO_UNROLL(output);
+    #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+    stbIF0( o0 = output[0] + input0[0] * c0s; o1 = output[1] + input0[1] * c0s; o2 = output[2] + input0[2] * c0s; o3 = output[3] + input0[3] * c0s; )
+    #else
+    stbIF0( o0  = input0[0] * c0s; o1  = input0[1] * c0s; o2  = input0[2] * c0s; o3  = input0[3] * c0s; )
+    #endif
+    stbIF1( o0 += input1[0] * c1s; o1 += input1[1] * c1s; o2 += input1[2] * c1s; o3 += input1[3] * c1s; )
+    stbIF2( o0 += input2[0] * c2s; o1 += input2[1] * c2s; o2 += input2[2] * c2s; o3 += input2[3] * c2s; )
+    stbIF3( o0 += input3[0] * c3s; o1 += input3[1] * c3s; o2 += input3[2] * c3s; o3 += input3[3] * c3s; )
+    stbIF4( o0 += input4[0] * c4s; o1 += input4[1] * c4s; o2 += input4[2] * c4s; o3 += input4[3] * c4s; )
+    stbIF5( o0 += input5[0] * c5s; o1 += input5[1] * c5s; o2 += input5[2] * c5s; o3 += input5[3] * c5s; )
+    stbIF6( o0 += input6[0] * c6s; o1 += input6[1] * c6s; o2 += input6[2] * c6s; o3 += input6[3] * c6s; )
+    stbIF7( o0 += input7[0] * c7s; o1 += input7[1] * c7s; o2 += input7[2] * c7s; o3 += input7[3] * c7s; )
+    output[0] = o0; output[1] = o1; output[2] = o2; output[3] = o3;
+    output += 4;
+    stbIF0( input0 += 4; ) stbIF1( input1 += 4; ) stbIF2( input2 += 4; ) stbIF3( input3 += 4; ) stbIF4( input4 += 4; ) stbIF5( input5 += 4; ) stbIF6( input6 += 4; ) stbIF7( input7 += 4; )
+  }
+  #endif
+  while ( input0 < input0_end )
+  {
+    float o0;
+    STBIR_NO_UNROLL(output);
+    #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+    stbIF0( o0 = output[0] + input0[0] * c0s; )
+    #else
+    stbIF0( o0  = input0[0] * c0s; )
+    #endif
+    stbIF1( o0 += input1[0] * c1s; )
+    stbIF2( o0 += input2[0] * c2s; )
+    stbIF3( o0 += input3[0] * c3s; )
+    stbIF4( o0 += input4[0] * c4s; )
+    stbIF5( o0 += input5[0] * c5s; )
+    stbIF6( o0 += input6[0] * c6s; )
+    stbIF7( o0 += input7[0] * c7s; )
+    output[0] = o0;
+    ++output;
+    stbIF0( ++input0; ) stbIF1( ++input1; ) stbIF2( ++input2; ) stbIF3( ++input3; ) stbIF4( ++input4; ) stbIF5( ++input5; ) stbIF6( ++input6; ) stbIF7( ++input7; )
+  }
+}
+
+#undef stbIF0
+#undef stbIF1
+#undef stbIF2
+#undef stbIF3
+#undef stbIF4
+#undef stbIF5
+#undef stbIF6
+#undef stbIF7
+#undef STB_IMAGE_RESIZE_DO_VERTICALS
+#undef STBIR__vertical_channels
+#undef STB_IMAGE_RESIZE_DO_HORIZONTALS
+#undef STBIR_strs_join24
+#undef STBIR_strs_join14
+#undef STBIR_chans
+#ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#undef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
+#endif
+
+#else // !STB_IMAGE_RESIZE_DO_VERTICALS
+
+#define STBIR_chans( start, end ) STBIR_strs_join1(start,STBIR__horizontal_channels,end)
+
+#ifndef stbir__2_coeff_only
+#define stbir__2_coeff_only()             \
+    stbir__1_coeff_only();                \
+    stbir__1_coeff_remnant(1);
+#endif
+
+#ifndef stbir__2_coeff_remnant
+#define stbir__2_coeff_remnant( ofs )     \
+    stbir__1_coeff_remnant(ofs);          \
+    stbir__1_coeff_remnant((ofs)+1);
+#endif
+
+#ifndef stbir__3_coeff_only
+#define stbir__3_coeff_only()             \
+    stbir__2_coeff_only();                \
+    stbir__1_coeff_remnant(2);
+#endif
+
+#ifndef stbir__3_coeff_remnant
+#define stbir__3_coeff_remnant( ofs )     \
+    stbir__2_coeff_remnant(ofs);          \
+    stbir__1_coeff_remnant((ofs)+2);
+#endif
+
+#ifndef stbir__3_coeff_setup
+#define stbir__3_coeff_setup()
+#endif
+
+#ifndef stbir__4_coeff_start
+#define stbir__4_coeff_start()            \
+    stbir__2_coeff_only();                \
+    stbir__2_coeff_remnant(2);
+#endif
+
+#ifndef stbir__4_coeff_continue_from_4
+#define stbir__4_coeff_continue_from_4( ofs )     \
+    stbir__2_coeff_remnant(ofs);                  \
+    stbir__2_coeff_remnant((ofs)+2);
+#endif
+
+#ifndef stbir__store_output_tiny
+#define stbir__store_output_tiny stbir__store_output
+#endif
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_1_coeff)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__1_coeff_only();
+    stbir__store_output_tiny();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_2_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__2_coeff_only();
+    stbir__store_output_tiny();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_3_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__3_coeff_only();
+    stbir__store_output_tiny();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_4_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__4_coeff_start();
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_5_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__4_coeff_start();
+    stbir__1_coeff_remnant(4);
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_6_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__4_coeff_start();
+    stbir__2_coeff_remnant(4);
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_7_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  stbir__3_coeff_setup();
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+
+    stbir__4_coeff_start();
+    stbir__3_coeff_remnant(4);
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_8_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__4_coeff_start();
+    stbir__4_coeff_continue_from_4(4);
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_9_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__4_coeff_start();
+    stbir__4_coeff_continue_from_4(4);
+    stbir__1_coeff_remnant(8);
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_10_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__4_coeff_start();
+    stbir__4_coeff_continue_from_4(4);
+    stbir__2_coeff_remnant(8);
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_11_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  stbir__3_coeff_setup();
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__4_coeff_start();
+    stbir__4_coeff_continue_from_4(4);
+    stbir__3_coeff_remnant(8);
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_12_coeffs)( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    float const * hc = horizontal_coefficients;
+    stbir__4_coeff_start();
+    stbir__4_coeff_continue_from_4(4);
+    stbir__4_coeff_continue_from_4(8);
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod0 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 4 + 3 ) >> 2;
+    float const * hc = horizontal_coefficients;
+
+    stbir__4_coeff_start();
+    do {
+      hc += 4;
+      decode += STBIR__horizontal_channels * 4;
+      stbir__4_coeff_continue_from_4( 0 );
+      --n;
+    } while ( n > 0 );
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod1 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 5 + 3 ) >> 2;
+    float const * hc = horizontal_coefficients;
+
+    stbir__4_coeff_start();
+    do {
+      hc += 4;
+      decode += STBIR__horizontal_channels * 4;
+      stbir__4_coeff_continue_from_4( 0 );
+      --n;
+    } while ( n > 0 );
+    stbir__1_coeff_remnant( 4 );
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod2 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 6 + 3 ) >> 2;
+    float const * hc = horizontal_coefficients;
+
+    stbir__4_coeff_start();
+    do {
+      hc += 4;
+      decode += STBIR__horizontal_channels * 4;
+      stbir__4_coeff_continue_from_4( 0 );
+      --n;
+    } while ( n > 0 );
+    stbir__2_coeff_remnant( 4 );
+
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3 )( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width )
+{
+  float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
+  float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+  stbir__3_coeff_setup();
+  do {
+    float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+    int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 7 + 3 ) >> 2;
+    float const * hc = horizontal_coefficients;
+
+    stbir__4_coeff_start();
+    do {
+      hc += 4;
+      decode += STBIR__horizontal_channels * 4;
+      stbir__4_coeff_continue_from_4( 0 );
+      --n;
+    } while ( n > 0 );
+    stbir__3_coeff_remnant( 4 );
+
+    stbir__store_output();
+  } while ( output < output_end );
+}
+
+static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_funcs)[4]=
+{
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod0),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod1),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod2),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod3),
+};
+
+static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_funcs)[12]=
+{
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_1_coeff),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_2_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_3_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_4_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_5_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_6_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_7_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_8_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_9_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_10_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_11_coeffs),
+  STBIR_chans(stbir__horizontal_gather_,_channels_with_12_coeffs),
+};
+
+#undef STBIR__horizontal_channels
+#undef STB_IMAGE_RESIZE_DO_HORIZONTALS
+#undef stbir__1_coeff_only
+#undef stbir__1_coeff_remnant
+#undef stbir__2_coeff_only
+#undef stbir__2_coeff_remnant
+#undef stbir__3_coeff_only
+#undef stbir__3_coeff_remnant
+#undef stbir__3_coeff_setup
+#undef stbir__4_coeff_start
+#undef stbir__4_coeff_continue_from_4
+#undef stbir__store_output
+#undef stbir__store_output_tiny
+#undef STBIR_chans
+
+#endif  // HORIZONALS
+
+#undef STBIR_strs_join2
+#undef STBIR_strs_join1
+
+#endif // STB_IMAGE_RESIZE_DO_HORIZONTALS/VERTICALS/CODERS
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/

+ 1 - 1
svg.mod/common.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2022 Bruce A Henderson
+' Copyright (c) 2022-2023 Bruce A Henderson
 ' 
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages

+ 1 - 1
svg.mod/glue.c

@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2022 Bruce A Henderson
+  Copyright (c) 2022-2023 Bruce A Henderson
   
   This software is provided 'as-is', without any express or implied
   warranty. In no event will the authors be held liable for any damages

+ 75 - 0
svg.mod/nanosvg/CMakeLists.txt

@@ -0,0 +1,75 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(NanoSVG C)
+
+# CMake needs *.c files to do something useful
+configure_file(src/nanosvg.h ${CMAKE_CURRENT_BINARY_DIR}/nanosvg.c)
+configure_file(src/nanosvgrast.h ${CMAKE_CURRENT_BINARY_DIR}/nanosvgrast.c)
+
+add_library(nanosvg ${CMAKE_CURRENT_BINARY_DIR}/nanosvg.c)
+
+find_library(MATH_LIBRARY m) # Business as usual
+if(MATH_LIBRARY)
+    target_link_libraries(nanosvg PUBLIC ${MATH_LIBRARY})
+endif()
+
+target_include_directories(nanosvg PUBLIC $<INSTALL_INTERFACE:include/nanosvg>)
+target_compile_definitions(nanosvg PRIVATE NANOSVG_IMPLEMENTATION)
+
+# Same for nanosvgrast
+add_library(nanosvgrast ${CMAKE_CURRENT_BINARY_DIR}/nanosvgrast.c)
+target_link_libraries(nanosvgrast PUBLIC nanosvg)
+target_include_directories(nanosvgrast PRIVATE src)
+target_compile_definitions(nanosvgrast PRIVATE NANOSVGRAST_IMPLEMENTATION)
+
+# Installation and export:
+
+include(CMakePackageConfigHelpers)
+
+write_basic_package_version_file(
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
+    VERSION 1.0
+    COMPATIBILITY AnyNewerVersion
+)
+
+install(TARGETS nanosvg nanosvgrast
+        EXPORT ${PROJECT_NAME}Targets
+)
+
+export(EXPORT ${PROJECT_NAME}Targets 
+       FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake" 
+       NAMESPACE ${PROJECT_NAME}::
+)
+
+set(ConfigPackageLocation lib/cmake/${PROJECT_NAME})
+
+configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
+  "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+  INSTALL_DESTINATION ${ConfigPackageLocation}
+  NO_CHECK_REQUIRED_COMPONENTS_MACRO
+)
+
+install(
+    FILES
+      src/nanosvg.h
+      src/nanosvgrast.h
+    DESTINATION
+      include/nanosvg
+  )
+
+install(EXPORT ${PROJECT_NAME}Targets
+  FILE
+    ${PROJECT_NAME}Targets.cmake
+  NAMESPACE
+    ${PROJECT_NAME}::
+  DESTINATION
+    ${ConfigPackageLocation}
+)
+
+install(
+  FILES
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
+  DESTINATION
+    ${ConfigPackageLocation}
+)

+ 5 - 0
svg.mod/nanosvg/Config.cmake.in

@@ -0,0 +1,5 @@
+@PACKAGE_INIT@
+
+if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/NanoSVGTargets.cmake)
+    include("${CMAKE_CURRENT_LIST_DIR}/NanoSVGTargets.cmake")
+endif ()

+ 5 - 4
svg.mod/nanosvg/src/nanosvgrast.h

@@ -331,6 +331,7 @@ static float nsvg__normalize(float *x, float* y)
 }
 
 static float nsvg__absf(float x) { return x < 0 ? -x : x; }
+static float nsvg__roundf(float x) { return (x >= 0) ? floorf(x + 0.5) : ceilf(x - 0.5); }
 
 static void nsvg__flattenCubicBez(NSVGrasterizer* r,
 								  float x1, float y1, float x2, float y2,
@@ -872,10 +873,10 @@ static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float sta
 //	STBTT_assert(e->y0 <= start_point);
 	// round dx down to avoid going too far
 	if (dxdy < 0)
-		z->dx = (int)(-floorf(NSVG__FIX * -dxdy));
+		z->dx = (int)(-nsvg__roundf(NSVG__FIX * -dxdy));
 	else
-		z->dx = (int)floorf(NSVG__FIX * dxdy);
-	z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
+		z->dx = (int)nsvg__roundf(NSVG__FIX * dxdy);
+	z->x = (int)nsvg__roundf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
 //	z->x -= off_x * FIX;
 	z->ey = e->y1;
 	z->next = 0;
@@ -1282,7 +1283,7 @@ static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opac
 	if (grad->nstops == 0) {
 		for (i = 0; i < 256; i++)
 			cache->colors[i] = 0;
-	} if (grad->nstops == 1) {
+	} else if (grad->nstops == 1) {
 		for (i = 0; i < 256; i++)
 			cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
 	} else {

+ 11 - 1
svg.mod/svg.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2022 Bruce A Henderson
+' Copyright (c) 2022-2023 Bruce A Henderson
 ' 
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
@@ -25,6 +25,16 @@ The SVG loader module provides the ability to load SVG format #pixmaps.
 End Rem
 Module Image.SVG
 
+ModuleInfo "Version: 1.01"
+ModuleInfo "Author: 2013-14 Mikko Mononen"
+ModuleInfo "License: ZLib/PNG License"
+ModuleInfo "Credit: Adapted for BlitzMax by Bruce A Henderson"
+
+ModuleInfo "History: 1.01"
+ModuleInfo "History: Update to nanosvg 706eb06"
+ModuleInfo "History: 1.00"
+ModuleInfo "History: Initial Release. nanosvg"
+
 Import BRL.Pixmap
 
 Import "common.bmx"

+ 2 - 0
webp.mod/libwebp/Android.mk

@@ -42,6 +42,7 @@ sharpyuv_srcs := \
     sharpyuv/sharpyuv_dsp.c \
     sharpyuv/sharpyuv_gamma.c \
     sharpyuv/sharpyuv_neon.$(NEON) \
+    sharpyuv/sharpyuv_risk_table.c \
     sharpyuv/sharpyuv_sse2.c \
 
 dec_srcs := \
@@ -164,6 +165,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 \

+ 35 - 10
webp.mod/libwebp/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)
@@ -163,6 +165,17 @@ endif()
 
 set(CMAKE_C_VISIBILITY_PRESET hidden)
 
+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.
 if(ANDROID)
@@ -638,13 +651,13 @@ 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)
   endif()
@@ -661,31 +674,43 @@ if(WEBP_BUILD_WEBP_JS)
   else()
     set(emscripten_stack_size "-sTOTAL_STACK=5MB")
   endif()
+  # Set SDL2 flags so that ports are downloaded by emscripten.
+  set(EMSCRIPTEN_SDL2_FLAGS "-sUSE_SDL=2 -sUSE_SDL_IMAGE=2")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EMSCRIPTEN_SDL2_FLAGS}")
   # wasm2js does not support SIMD.
   if(NOT WEBP_ENABLE_SIMD)
     # JavaScript version
+    find_package(SDL2 QUIET)
     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 ${emscripten_stack_size} \
+      PROPERTIES
+        LINK_FLAGS
+        "-sWASM=0 ${emscripten_stack_size} \
          -sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
-         -sEXPORTED_RUNTIME_METHODS=cwrap")
+         -sEXPORTED_RUNTIME_METHODS=cwrap ${EMSCRIPTEN_SDL2_FLAGS} \
+         -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 ${emscripten_stack_size} \
+    PROPERTIES
+      LINK_FLAGS
+      "-sWASM=1 ${emscripten_stack_size} \
        -sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \
-       -sEXPORTED_RUNTIME_METHODS=cwrap")
+       -sEXPORTED_RUNTIME_METHODS=cwrap ${EMSCRIPTEN_SDL2_FLAGS} \
+       -sALLOW_MEMORY_GROWTH"
+  )
   target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL)
 
   target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN)

+ 1 - 0
webp.mod/libwebp/Makefile.vc

@@ -336,6 +336,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 \

+ 2 - 0
webp.mod/libwebp/build.gradle

@@ -112,6 +112,7 @@ model {
             include "sharpyuv_dsp.c"
             include "sharpyuv_gamma.c"
             include "sharpyuv_neon.c"
+            include "sharpyuv_risk_table.c"
             include "sharpyuv_sse2.c"
             srcDir "src/dec"
             include "alpha_dec.c"
@@ -173,6 +174,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"

+ 2 - 1
webp.mod/libwebp/cmake/WebPConfig.cmake.in

@@ -11,7 +11,8 @@ endif()
 include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
 
 set_and_check(WebP_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
-set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIRS})
+set(WebP_INCLUDE_DIRS ${WebP_INCLUDE_DIR})
+set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIR})
 set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@")
 set(WEBP_LIBRARIES "${WebP_LIBRARIES}")
 

+ 4 - 5
webp.mod/libwebp/configure.ac

@@ -464,7 +464,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 +474,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(

+ 1 - 1
webp.mod/libwebp/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

+ 18 - 0
webp.mod/libwebp/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

+ 141 - 137
webp.mod/libwebp/doc/webp-container-spec.txt

@@ -21,9 +21,9 @@ 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. 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
+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.
@@ -31,36 +31,37 @@ 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:
+support for the following:
 
-  * **Lossless compression.** An image can be losslessly compressed, using the
+  * 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, that is, 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 (that is, an encoded matrix of pixels)
 or an [animation](#animation). Optionally, it can also contain transparency
-information, color profile and metadata. We refer to the matrix of pixels as 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,7 +84,7 @@ _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_.
 
@@ -94,9 +95,8 @@ _1-based_
 
 _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,17 +151,17 @@ 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
@@ -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).
 
@@ -295,7 +295,7 @@ appears in the wrong place, the file is invalid, but readers MAY parse the
 file, ignoring the chunks that are 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
+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.
@@ -326,7 +326,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 +343,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 +372,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 +396,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 +411,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 +460,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 +474,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 +490,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 +519,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
 
@@ -532,7 +533,7 @@ 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).
+_padded_ chunks, as described by the [RIFF file format](#riff-file-format).
 
 #### Alpha
 
@@ -549,18 +550,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
   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 +587,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 +597,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 +618,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 +651,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 +684,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 +706,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 +721,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 +784,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 +795,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 +820,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 +829,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 +862,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

File diff suppressed because it is too large
+ 267 - 247
webp.mod/libwebp/doc/webp-lossless-bitstream-spec.txt


+ 5 - 1
webp.mod/libwebp/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;

+ 9 - 5
webp.mod/libwebp/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;
 }
 
 // -----------------------------------------------------------------------------

+ 1 - 1
webp.mod/libwebp/examples/vwebp.c

@@ -613,7 +613,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__)

+ 6 - 6
webp.mod/libwebp/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.");

+ 1 - 1
webp.mod/libwebp/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) {

+ 35 - 48
webp.mod/libwebp/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;
 }
 

+ 52 - 29
webp.mod/libwebp/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);

+ 14 - 4
webp.mod/libwebp/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"

+ 7 - 4
webp.mod/libwebp/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
 
@@ -133,6 +133,7 @@ SHARPYUV_OBJS = \
     sharpyuv/sharpyuv_dsp.o \
     sharpyuv/sharpyuv_gamma.o \
     sharpyuv/sharpyuv_neon.o \
+    sharpyuv/sharpyuv_risk_table.o \
     sharpyuv/sharpyuv_sse2.o \
 
 DEC_OBJS = \
@@ -276,6 +277,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 \
@@ -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 \

+ 1 - 0
webp.mod/libwebp/sharpyuv/Makefile.am

@@ -30,6 +30,7 @@ libsharpyuv_la_SOURCES += sharpyuv_cpu.c sharpyuv_cpu.h
 libsharpyuv_la_SOURCES += sharpyuv_csp.c sharpyuv_csp.h
 libsharpyuv_la_SOURCES += sharpyuv_dsp.c sharpyuv_dsp.h
 libsharpyuv_la_SOURCES += sharpyuv_gamma.c sharpyuv_gamma.h
+libsharpyuv_la_SOURCES += sharpyuv_risk_table.c sharpyuv_risk_table.h
 libsharpyuv_la_SOURCES += sharpyuv.c sharpyuv.h
 
 libsharpyuv_la_CPPFLAGS = $(AM_CPPFLAGS)

+ 207 - 59
webp.mod/libwebp/sharpyuv/sharpyuv.c

@@ -23,6 +23,7 @@
 #include "sharpyuv/sharpyuv_cpu.h"
 #include "sharpyuv/sharpyuv_dsp.h"
 #include "sharpyuv/sharpyuv_gamma.h"
+#include "sharpyuv/sharpyuv_risk_table.h"
 
 //------------------------------------------------------------------------------
 
@@ -75,41 +76,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 +125,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 +159,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 +173,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 +241,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 +257,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 +282,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 +299,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 +307,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 +362,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 +385,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 +397,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,7 +435,6 @@ 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)
 #include <pthread.h>  // NOLINT
@@ -462,12 +478,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);
@@ -486,7 +532,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;
   }
@@ -521,7 +567,109 @@ 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);
+}
+
+//------------------------------------------------------------------------------
+// 420 risk metric
+
+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) {
+    free(row1);
+    free(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.;
+
+  free(row1);
+  free(row2);
+
+  *score_out = (float)total_score;
+  return 1;
 }
 
+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;
+  }
+
+  // The address of the function pointer is used to avoid a read race.
+  SharpYuvInit((VP8CPUInfo)&SharpYuvGetCPUInfo);
+
+  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);
+}
+
+#undef SAFE_ALLOC
+
 //------------------------------------------------------------------------------

+ 103 - 2
webp.mod/libwebp/sharpyuv/sharpyuv.h

@@ -34,10 +34,27 @@ extern "C" {
 #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_PATCH 1
+#define SHARPYUV_VERSION_MINOR 5
+#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.
 #define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \
@@ -61,6 +78,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 +129,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 +139,61 @@ 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);
+
+// 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.
+SHARPYUV_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);
+
 // TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422
 // support (it's rarely used in practice, especially for images).
 

+ 64 - 2
webp.mod/libwebp/sharpyuv/sharpyuv_dsp.c

@@ -16,7 +16,9 @@
 #include <assert.h>
 #include <stdlib.h>
 
+#include "sharpyuv/sharpyuv.h"
 #include "sharpyuv/sharpyuv_cpu.h"
+#include "src/webp/types.h"
 
 //-----------------------------------------------------------------------------
 
@@ -62,6 +64,58 @@ static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len,
 }
 #endif  // !WEBP_NEON_OMIT_C_CODE
 
+#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
+
+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_C(
+    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);
+  }
+}
+
 //-----------------------------------------------------------------------------
 
 uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
@@ -69,8 +123,14 @@ 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);
+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);
 
 extern VP8CPUInfo SharpYuvGetCPUInfo;
 extern void InitSharpYuvSSE2(void);
@@ -82,6 +142,8 @@ void SharpYuvInitDsp(void) {
   SharpYuvUpdateRGB = SharpYuvUpdateRGB_C;
   SharpYuvFilterRow = SharpYuvFilterRow_C;
 #endif
+  // There is only a C version for now so always include it.
+  SharpYuvRowToYuvSharpnessIndex = SharpYuvRowToYuvSharpnessIndex_C;
 
   if (SharpYuvGetCPUInfo != NULL) {
 #if defined(WEBP_HAVE_SSE2)

+ 10 - 0
webp.mod/libwebp/sharpyuv/sharpyuv_dsp.h

@@ -12,6 +12,7 @@
 #ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_
 #define WEBP_SHARPYUV_SHARPYUV_DSP_H_
 
+#include "sharpyuv/sharpyuv.h"
 #include "sharpyuv/sharpyuv_cpu.h"
 #include "src/webp/types.h"
 
@@ -23,6 +24,15 @@ extern void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
                                  const uint16_t* best_y, uint16_t* out,
                                  int bit_depth);
 
+// 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)
+extern 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);
+
 void SharpYuvInitDsp(void);
 
 #endif  // WEBP_SHARPYUV_SHARPYUV_DSP_H_

+ 308 - 2
webp.mod/libwebp/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));
+}

+ 7 - 4
webp.mod/libwebp/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"

+ 6210 - 0
webp.mod/libwebp/sharpyuv/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,
+};

+ 27 - 0
webp.mod/libwebp/sharpyuv/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_SHARPYUV_SHARPYUV_RISK_TABLE_H_
+#define WEBP_SHARPYUV_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_SHARPYUV_SHARPYUV_RISK_TABLE_H_

+ 34 - 27
webp.mod/libwebp/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

+ 1 - 1
webp.mod/libwebp/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);

+ 31 - 19
webp.mod/libwebp/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) {

+ 12 - 8
webp.mod/libwebp/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

+ 8 - 9
webp.mod/libwebp/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);

+ 7 - 4
webp.mod/libwebp/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" {
@@ -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,

+ 100 - 68
webp.mod/libwebp/src/dec/vp8l_dec.c

@@ -12,6 +12,7 @@
 // Authors: Vikas Arora ([email protected])
 //          Jyrki Alakuijala ([email protected])
 
+#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,
@@ -301,7 +310,7 @@ static int ReadHuffmanCodeLengths(
 
  End:
   VP8LHuffmanTablesDeallocate(&tables);
-  if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+  if (!ok) return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
   return ok;
 }
 
@@ -333,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);
@@ -351,15 +357,14 @@ 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;
@@ -367,9 +372,6 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
   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;
 
@@ -383,7 +385,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
     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;
     }
@@ -407,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
@@ -426,25 +428,52 @@ 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));
-  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 ||
+ 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)) {
-    dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+    VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
     goto Error;
   }
 
@@ -464,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;
@@ -516,18 +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;
-
  Error:
   WebPSafeFree(code_lengths);
-  WebPSafeFree(mapping);
   if (!ok) {
-    WebPSafeFree(huffman_image);
     VP8LHuffmanTablesDeallocate(huffman_tables);
-    VP8LHtreeGroupsFree(htree_groups);
+    VP8LHtreeGroupsFree(*htree_groups);
+    *htree_groups = NULL;
   }
   return ok;
 }
@@ -551,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;
@@ -1086,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;
 }
 
@@ -1241,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);
@@ -1258,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);
 }
 
 // -----------------------------------------------------------------------------
@@ -1326,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;
@@ -1336,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:
@@ -1443,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;
     }
   }
@@ -1452,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;
   }
 
@@ -1460,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 {
@@ -1478,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;
     }
   }
@@ -1524,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;
@@ -1536,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;
 }
@@ -1592,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;
   }
 
@@ -1647,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:
@@ -1692,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;
     }
 
@@ -1702,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
@@ -1720,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;
         }
       }

+ 21 - 7
webp.mod/libwebp/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" {
@@ -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

+ 30 - 18
webp.mod/libwebp/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;
@@ -733,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;
 }
 
@@ -772,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;

+ 4 - 2
webp.mod/libwebp/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).

+ 14 - 8
webp.mod/libwebp/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,

+ 41 - 0
webp.mod/libwebp/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;

+ 0 - 12
webp.mod/libwebp/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 (

+ 8 - 1
webp.mod/libwebp/src/dsp/filters.c

@@ -189,6 +189,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];
@@ -240,7 +246,7 @@ 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;
@@ -279,6 +285,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);

+ 3 - 3
webp.mod/libwebp/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]);
 

+ 3 - 3
webp.mod/libwebp/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.

+ 14 - 9
webp.mod/libwebp/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;
 }

+ 7 - 7
webp.mod/libwebp/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                                 \

+ 52 - 2
webp.mod/libwebp/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;

+ 15 - 17
webp.mod/libwebp/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)

+ 2 - 1
webp.mod/libwebp/src/dsp/quant.h

@@ -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);

+ 4 - 7
webp.mod/libwebp/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) {

Some files were not shown because too many files changed in this diff