blob: 1c3065c101c763edd382348b5903b8ec608e0e4e [file]
// Copyright 2026 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//go:build ignore
// +build ignore
package main
// replicate-libwebp-chroma-upsampling.go tests a Go port of libwebp's "fancy"
// 4:2:0 chroma upsampling algorithm. This is a 9:3:3:1 triangle filter (the
// 2-Dimensional analogue of the 1-Dimensional 3:1 triangle filter).
//
// libwebp's "fancy" upsampling is very similar to (but not exactly the same
// as) libjpeg's "fancy" upsampling. Both are 9:3:3:1 and the weights sum to
// 16, but they use a different integer arithmetic rounding algorithm:
//
// - libwebp uses truncate((weighted_average + 8) / 16), everywhere.
// - libjpeg uses truncate((weighted_average + H) / 16), where H is 8
// (rounding up) for even columns and 7 (rounding down) for odd columns.
//
// libwebp's plain C implementation is the src/dsp/upsampling.c UPSAMPLE_FUNC
// macro. While it doesn't affect rounding, the macro also computes Cb and Cr
// simultaneously using SWAR (SIMD Within A Register), packing u16x2 into a
// u32, which this Go re-implementation does not replicate. libwebp also has
// other SIMD-optimized implementations.
//
// libjpeg's plain C implementation is the jdsample.c h2v2_fancy_upsample
// function. libjpeg also has other SIMD-optimized implementations.
//
// Usage: "go run replicate-libwebp-chroma-upsampling.go" should print nothing,
// but it would print a diff if the hard-coded tests fail.
import (
"bytes"
"errors"
"fmt"
"os"
)
func main() {
if err := main1(); err != nil {
os.Stderr.WriteString(err.Error() + "\n")
os.Exit(1)
}
}
func main1() error {
{
dst := make([]byte, len(dstSamplesMona))
upsampleImage(dst, 21, 32, srcSamplesMona[:], 16, 16)
compare(dst, dstSamplesMona[:], 21, "test/data/mona-lisa.21x32.q90.lossy.webp")
}
{
dst := make([]byte, len(dstSamplesPeac))
upsampleImage(dst, 24, 19, srcSamplesPeac[:], 16, 16)
compare(dst, dstSamplesPeac[:], 24, "test/data/peacock.24x19.lossy.webp")
}
if failed {
return errors.New("Failed.")
}
return nil
}
func upsampleImage(dst []byte, dstw int, dsth int, src []byte, srcw int, srch int) {
if (dstw <= 0) || (dsth <= 0) || (srcw <= 0) || (srch <= 0) {
return
}
// The dsty sequence is 0, 1, 3, 5, 7, 9, ...
for dsty := 0; dsty < dsth; {
dsty0 := dsty + 0
dsty1 := dsty + 1
srcy0 := dsty >> 1
srcy1 := srcy0 + 1
if dsty == 0 { // First row.
dsty1 = -1
srcy1 = 0
dsty = 1
} else if (dsty + 1) >= dsth { // Last row, when dsth is even.
dsty1 = -1
srcy1 = srcy0
dsty += 1
} else { // All other rows.
dsty += 2
}
dst0 := dst[(dsty0+0)*dstw : (dsty0+1)*dstw]
dst1 := []byte(nil)
if dsty1 >= 0 {
dst1 = dst[(dsty1+0)*dstw : (dsty1+1)*dstw]
}
src0 := src[(srcy0+0)*srcw : (srcy0+1)*srcw]
src1 := src[(srcy1+0)*srcw : (srcy1+1)*srcw]
upsampleStrip(dst0, dst1, src0, src1)
}
}
func upsampleStrip(dst0 []byte, dst1 []byte, src0 []byte, src1 []byte) {
if (len(dst0) <= 0) ||
((len(dst0) != len(dst1)) && (len(dst1) != 0)) ||
((len(src0) != len(src1)) && (len(src1) != 0)) {
return
}
// t=top, l=left, c=current.
tl := uint32(src0[0])
cl := uint32(src1[0])
{
dst0[0] = uint8(((3 * tl) + cl + 2) >> 2)
}
if len(dst1) > 0 {
dst1[0] = uint8(((3 * cl) + tl + 2) >> 2)
}
for x, lastPixelPair := 1, (len(dst0)-1)>>1; x <= lastPixelPair; x++ {
tc := uint32(src0[x])
cc := uint32(src1[x])
avg := tl + tc + cl + cc + 8
diag12 := (avg + (2 * (tc + cl))) >> 3
diag03 := (avg + (2 * (tl + cc))) >> 3
{
dst0[(2*x)-1] = uint8((diag12 + tl) >> 1)
dst0[(2*x)-0] = uint8((diag03 + tc) >> 1)
}
if len(dst1) > 0 {
dst1[(2*x)-1] = uint8((diag03 + cl) >> 1)
dst1[(2*x)-0] = uint8((diag12 + cc) >> 1)
}
tl = tc
cl = cc
}
if (len(dst0) & 1) == 0 {
n := len(dst0) - 1
{
dst0[n] = uint8(((3 * tl) + cl + 2) >> 2)
}
if len(dst1) > 0 {
dst1[n] = uint8(((3 * cl) + tl + 2) >> 2)
}
}
}
func compare(have []byte, want []byte, width int, name string) {
if len(have) != len(want) {
panic("invalid compare")
} else if bytes.Equal(have, want) {
return
}
failed = true
fmt.Fprintf(os.Stderr, "Wrong output for %s\n", name)
for i := range have {
fmt.Fprintf(os.Stderr, " %02X", have[i]-want[i])
if (i % width) == (width - 1) {
fmt.Fprintln(os.Stderr)
}
}
}
var failed = false
// srcSamplesMona are the Cb (Chroma blue) samples, 16x16 in four macroblocks,
// from test/data/mona-lisa.21x32.q90.lossy.webp (whose dimensions are 21x32).
var srcSamplesMona = [16 * 16]uint8{
0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6D, 0x69, 0x6B, 0x70, 0x6D, 0x72, 0x6E, 0x73, 0x73, 0x73, 0x73,
0x69, 0x69, 0x69, 0x69, 0x67, 0x6A, 0x70, 0x6D, 0x6C, 0x68, 0x6D, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A,
0x69, 0x69, 0x69, 0x69, 0x5F, 0x66, 0x7A, 0x70, 0x6B, 0x67, 0x6C, 0x69, 0x69, 0x69, 0x69, 0x69,
0x6E, 0x6E, 0x6E, 0x6E, 0x58, 0x63, 0x81, 0x72, 0x6D, 0x6A, 0x6F, 0x6B, 0x70, 0x70, 0x70, 0x70,
0x79, 0x73, 0x73, 0x79, 0x5C, 0x5B, 0x81, 0x77, 0x79, 0x72, 0x76, 0x76, 0x75, 0x75, 0x75, 0x75,
0x7C, 0x77, 0x77, 0x7C, 0x66, 0x6A, 0x85, 0x75, 0x7D, 0x75, 0x7A, 0x79, 0x79, 0x79, 0x79, 0x79,
0x79, 0x74, 0x74, 0x79, 0x69, 0x5E, 0x71, 0x7A, 0x6F, 0x6C, 0x75, 0x79, 0x77, 0x77, 0x77, 0x77,
0x72, 0x6C, 0x6C, 0x72, 0x4F, 0x51, 0x65, 0x71, 0x76, 0x6C, 0x6E, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C,
0x72, 0x6E, 0x7E, 0x6C, 0x57, 0x5C, 0x6F, 0x84, 0x87, 0x7A, 0x73, 0x77, 0x76, 0x76, 0x76, 0x76,
0x74, 0x73, 0x84, 0x7E, 0x6E, 0x7C, 0x7F, 0x74, 0x87, 0x7D, 0x78, 0x7B, 0x7D, 0x7D, 0x7D, 0x7D,
0x78, 0x77, 0x80, 0x85, 0x80, 0x81, 0x84, 0x89, 0x86, 0x83, 0x80, 0x7F, 0x7C, 0x7C, 0x7C, 0x7C,
0x7D, 0x77, 0x75, 0x7E, 0x88, 0x85, 0x85, 0x87, 0x86, 0x86, 0x85, 0x83, 0x83, 0x83, 0x83, 0x83,
0x89, 0x88, 0x75, 0x5A, 0x62, 0x7B, 0x85, 0x7A, 0x8A, 0x89, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86,
0x8A, 0x88, 0x79, 0x66, 0x63, 0x6B, 0x73, 0x76, 0x87, 0x85, 0x83, 0x82, 0x80, 0x80, 0x80, 0x80,
0x8C, 0x88, 0x7F, 0x77, 0x81, 0x81, 0x86, 0x8C, 0x87, 0x85, 0x83, 0x82, 0x87, 0x87, 0x87, 0x87,
0x8D, 0x88, 0x84, 0x83, 0x83, 0x88, 0x8A, 0x88, 0x8A, 0x89, 0x87, 0x86, 0x89, 0x89, 0x89, 0x89,
}
var dstSamplesMona = [21 * 32]uint8{
0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6D, 0x6C, 0x6A, 0x6A, 0x6B, 0x6C, 0x6F, 0x6F, 0x6E, 0x6E, 0x71,
0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6C, 0x6C, 0x6C, 0x6C, 0x6B, 0x6B, 0x6B, 0x6C, 0x6E, 0x6E, 0x6D, 0x6D, 0x70,
0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x69, 0x69, 0x6A, 0x6C, 0x6D, 0x6E, 0x6D, 0x6D, 0x6D, 0x6C, 0x6A, 0x6B, 0x6D,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x68, 0x66, 0x66, 0x68, 0x6B, 0x70, 0x71, 0x6F, 0x6D, 0x6C, 0x6B, 0x69, 0x69, 0x6C,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x67, 0x63, 0x63, 0x66, 0x6B, 0x73, 0x75, 0x71, 0x6E, 0x6C, 0x6A, 0x68, 0x69, 0x6B,
0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x67, 0x61, 0x5F, 0x63, 0x6B, 0x76, 0x79, 0x73, 0x6F, 0x6D, 0x6B, 0x69, 0x69, 0x6C,
0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x68, 0x5F, 0x5C, 0x61, 0x6B, 0x78, 0x7C, 0x75, 0x70, 0x6E, 0x6C, 0x6A, 0x6B, 0x6D,
0x71, 0x70, 0x70, 0x6F, 0x6F, 0x70, 0x70, 0x6B, 0x5F, 0x5B, 0x5F, 0x69, 0x79, 0x7E, 0x77, 0x72, 0x71, 0x6F, 0x6D, 0x6D, 0x70,
0x76, 0x75, 0x73, 0x72, 0x72, 0x73, 0x75, 0x6F, 0x62, 0x5C, 0x5D, 0x66, 0x78, 0x7E, 0x79, 0x76, 0x76, 0x75, 0x72, 0x71, 0x73,
0x7A, 0x78, 0x75, 0x74, 0x74, 0x75, 0x78, 0x73, 0x65, 0x5F, 0x5F, 0x68, 0x79, 0x7F, 0x79, 0x77, 0x79, 0x78, 0x75, 0x74, 0x76,
0x7B, 0x7A, 0x77, 0x76, 0x76, 0x77, 0x7A, 0x75, 0x69, 0x64, 0x66, 0x6E, 0x7D, 0x80, 0x79, 0x77, 0x7A, 0x7A, 0x76, 0x75, 0x78,
0x7B, 0x7A, 0x78, 0x76, 0x76, 0x78, 0x7A, 0x76, 0x6C, 0x67, 0x67, 0x6D, 0x7A, 0x7E, 0x79, 0x77, 0x79, 0x78, 0x74, 0x74, 0x77,
0x7A, 0x79, 0x76, 0x75, 0x75, 0x76, 0x79, 0x75, 0x6D, 0x66, 0x63, 0x66, 0x71, 0x77, 0x78, 0x77, 0x74, 0x71, 0x6F, 0x70, 0x74,
0x77, 0x76, 0x73, 0x72, 0x72, 0x73, 0x76, 0x72, 0x68, 0x61, 0x5D, 0x60, 0x69, 0x70, 0x75, 0x76, 0x73, 0x70, 0x6D, 0x6E, 0x71,
0x74, 0x72, 0x6F, 0x6E, 0x6E, 0x6F, 0x72, 0x6C, 0x5D, 0x55, 0x55, 0x59, 0x63, 0x6B, 0x70, 0x74, 0x74, 0x72, 0x6E, 0x6D, 0x6F,
0x72, 0x71, 0x6E, 0x6E, 0x70, 0x71, 0x71, 0x69, 0x59, 0x52, 0x53, 0x59, 0x63, 0x6B, 0x72, 0x77, 0x79, 0x78, 0x72, 0x6F, 0x6F,
0x72, 0x71, 0x6F, 0x71, 0x77, 0x77, 0x71, 0x67, 0x5B, 0x56, 0x58, 0x5E, 0x68, 0x71, 0x7B, 0x80, 0x82, 0x80, 0x7A, 0x75, 0x73,
0x73, 0x72, 0x70, 0x73, 0x7B, 0x7C, 0x74, 0x6C, 0x62, 0x5F, 0x62, 0x68, 0x6F, 0x76, 0x7D, 0x82, 0x85, 0x84, 0x7E, 0x79, 0x76,
0x74, 0x73, 0x72, 0x76, 0x7E, 0x80, 0x7C, 0x75, 0x6D, 0x6B, 0x71, 0x76, 0x79, 0x7A, 0x79, 0x7C, 0x83, 0x84, 0x7F, 0x7B, 0x78,
0x75, 0x75, 0x74, 0x78, 0x7F, 0x82, 0x81, 0x7C, 0x76, 0x75, 0x7B, 0x7E, 0x80, 0x7F, 0x7B, 0x7D, 0x83, 0x85, 0x81, 0x7D, 0x7B,
0x77, 0x77, 0x76, 0x79, 0x7E, 0x82, 0x83, 0x81, 0x7D, 0x7D, 0x7F, 0x81, 0x82, 0x83, 0x84, 0x84, 0x86, 0x85, 0x83, 0x81, 0x7F,
0x79, 0x79, 0x78, 0x79, 0x7C, 0x7F, 0x82, 0x83, 0x82, 0x82, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x87, 0x85, 0x84, 0x83, 0x82,
0x7C, 0x7B, 0x78, 0x77, 0x78, 0x7A, 0x7E, 0x81, 0x84, 0x86, 0x85, 0x84, 0x85, 0x85, 0x87, 0x87, 0x86, 0x86, 0x85, 0x85, 0x84,
0x80, 0x7F, 0x7C, 0x7A, 0x77, 0x75, 0x75, 0x77, 0x7C, 0x80, 0x82, 0x83, 0x84, 0x85, 0x84, 0x85, 0x86, 0x87, 0x87, 0x86, 0x86,
0x86, 0x85, 0x84, 0x80, 0x79, 0x71, 0x68, 0x65, 0x69, 0x70, 0x79, 0x7F, 0x83, 0x83, 0x7F, 0x80, 0x86, 0x89, 0x88, 0x88, 0x87,
0x89, 0x89, 0x88, 0x84, 0x7B, 0x70, 0x63, 0x5E, 0x61, 0x67, 0x72, 0x79, 0x7E, 0x7F, 0x7B, 0x7D, 0x85, 0x89, 0x88, 0x88, 0x87,
0x8A, 0x89, 0x88, 0x84, 0x7C, 0x73, 0x68, 0x63, 0x63, 0x66, 0x6C, 0x71, 0x75, 0x77, 0x77, 0x7B, 0x84, 0x87, 0x86, 0x86, 0x85,
0x8B, 0x8A, 0x89, 0x85, 0x7E, 0x76, 0x6E, 0x6A, 0x6A, 0x6C, 0x6F, 0x72, 0x76, 0x79, 0x7B, 0x7E, 0x84, 0x87, 0x86, 0x85, 0x84,
0x8C, 0x8B, 0x89, 0x85, 0x80, 0x7B, 0x75, 0x74, 0x78, 0x7A, 0x7B, 0x7D, 0x80, 0x83, 0x85, 0x87, 0x87, 0x87, 0x86, 0x85, 0x84,
0x8C, 0x8B, 0x89, 0x86, 0x82, 0x7F, 0x7C, 0x7C, 0x80, 0x82, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8A, 0x89, 0x87, 0x86, 0x86, 0x85,
0x8D, 0x8C, 0x89, 0x87, 0x84, 0x82, 0x81, 0x81, 0x82, 0x83, 0x85, 0x87, 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x87,
0x8D, 0x8C, 0x89, 0x87, 0x85, 0x84, 0x83, 0x83, 0x83, 0x84, 0x87, 0x89, 0x8A, 0x8A, 0x89, 0x89, 0x8A, 0x8A, 0x89, 0x89, 0x88,
}
// srcSamplesPeac are the Cb (Chroma blue) samples, 16x16 in four macroblocks,
// from test/data/peacock.24x19.lossy.webp (whose dimensions are 24x19).
var srcSamplesPeac = [16 * 16]uint8{
0x65, 0x65, 0x65, 0x63, 0x63, 0x6C, 0x72, 0x71, 0x66, 0x69, 0x73, 0x76, 0x6E, 0x6E, 0x6E, 0x6E,
0x65, 0x65, 0x65, 0x65, 0x5F, 0x6B, 0x72, 0x6E, 0x69, 0x70, 0x6D, 0x73, 0x6E, 0x6E, 0x6E, 0x6E,
0x67, 0x67, 0x67, 0x67, 0x6B, 0x96, 0x9C, 0x7B, 0x6D, 0x79, 0x63, 0x6F, 0x6E, 0x6E, 0x6E, 0x6E,
0x68, 0x68, 0x68, 0x68, 0x80, 0x7E, 0x84, 0x8F, 0x72, 0x80, 0x5C, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
0x6A, 0x6A, 0x6A, 0x6A, 0x63, 0x6B, 0x7F, 0x95, 0x75, 0x74, 0x6F, 0x6A, 0x69, 0x69, 0x69, 0x69,
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x99, 0x85, 0x74, 0x70, 0x6B, 0x67, 0x65, 0x65, 0x65, 0x65,
0x6C, 0x6C, 0x6C, 0x6C, 0x6D, 0x81, 0xA8, 0x76, 0x6F, 0x6B, 0x66, 0x62, 0x60, 0x60, 0x60, 0x60,
0x6C, 0x6C, 0x6C, 0x6C, 0x68, 0xA0, 0xA4, 0x72, 0x6B, 0x67, 0x62, 0x5F, 0x5C, 0x5C, 0x5C, 0x5C,
0x6B, 0x6B, 0x6B, 0x6B, 0x70, 0xA5, 0xA3, 0x89, 0x64, 0x68, 0x67, 0x60, 0x60, 0x60, 0x60, 0x60,
0x6B, 0x6B, 0x6B, 0x6B, 0x7E, 0xAD, 0xAB, 0x97, 0x64, 0x68, 0x67, 0x60, 0x60, 0x60, 0x60, 0x60,
0x6A, 0x6A, 0x6A, 0x6A, 0x87, 0xAD, 0xAB, 0xA0, 0x64, 0x68, 0x67, 0x60, 0x60, 0x60, 0x60, 0x60,
0x69, 0x69, 0x69, 0x69, 0x85, 0xA5, 0xA3, 0x9E, 0x64, 0x68, 0x67, 0x60, 0x60, 0x60, 0x60, 0x60,
0x69, 0x69, 0x69, 0x69, 0x7C, 0xAA, 0xAC, 0xA0, 0x64, 0x68, 0x67, 0x60, 0x60, 0x60, 0x60, 0x60,
0x68, 0x68, 0x68, 0x68, 0x7C, 0xAA, 0xAC, 0xA0, 0x64, 0x68, 0x67, 0x60, 0x60, 0x60, 0x60, 0x60,
0x68, 0x68, 0x68, 0x68, 0x7C, 0xAA, 0xAC, 0xA0, 0x64, 0x68, 0x67, 0x60, 0x60, 0x60, 0x60, 0x60,
0x68, 0x68, 0x68, 0x68, 0x7C, 0xAA, 0xAC, 0xA0, 0x64, 0x68, 0x67, 0x60, 0x60, 0x60, 0x60, 0x60,
}
var dstSamplesPeac = [24 * 19]uint8{
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x63, 0x63, 0x65, 0x6A, 0x6E, 0x71, 0x72, 0x71, 0x6E, 0x69, 0x67, 0x68, 0x6C, 0x71, 0x74, 0x75, 0x76,
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x64, 0x63, 0x62, 0x64, 0x69, 0x6D, 0x70, 0x72, 0x71, 0x6E, 0x69, 0x68, 0x6A, 0x6C, 0x70, 0x72, 0x74, 0x75,
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x63, 0x61, 0x63, 0x68, 0x6D, 0x70, 0x71, 0x70, 0x6D, 0x6A, 0x6A, 0x6D, 0x6E, 0x6E, 0x70, 0x72, 0x74,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x63, 0x67, 0x71, 0x77, 0x7B, 0x7A, 0x74, 0x6F, 0x6C, 0x6C, 0x70, 0x70, 0x6C, 0x6C, 0x70, 0x72,
0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x68, 0x71, 0x82, 0x8D, 0x90, 0x8B, 0x7E, 0x75, 0x6F, 0x6F, 0x74, 0x72, 0x6A, 0x68, 0x6D, 0x70,
0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x6A, 0x6E, 0x78, 0x88, 0x92, 0x95, 0x91, 0x86, 0x7C, 0x73, 0x71, 0x78, 0x74, 0x68, 0x65, 0x6B, 0x6F,
0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x6D, 0x76, 0x7D, 0x82, 0x86, 0x89, 0x8A, 0x8A, 0x84, 0x77, 0x74, 0x7B, 0x76, 0x66, 0x62, 0x6A, 0x6E,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6D, 0x75, 0x79, 0x79, 0x7C, 0x80, 0x86, 0x8D, 0x89, 0x7A, 0x75, 0x7A, 0x76, 0x68, 0x64, 0x69, 0x6C,
0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6C, 0x6E, 0x74, 0x7C, 0x85, 0x8F, 0x8C, 0x7C, 0x75, 0x76, 0x74, 0x6D, 0x6A, 0x6B, 0x6B,
0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x69, 0x66, 0x67, 0x6A, 0x72, 0x7F, 0x88, 0x8E, 0x8A, 0x7C, 0x74, 0x73, 0x72, 0x6F, 0x6D, 0x6A, 0x69,
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6A, 0x69, 0x6A, 0x6B, 0x75, 0x89, 0x90, 0x8B, 0x84, 0x79, 0x73, 0x72, 0x70, 0x6D, 0x6B, 0x69, 0x68,
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6D, 0x6F, 0x7C, 0x92, 0x96, 0x88, 0x7E, 0x76, 0x72, 0x70, 0x6E, 0x6B, 0x69, 0x67, 0x66,
0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x70, 0x78, 0x86, 0x9A, 0x9A, 0x84, 0x77, 0x73, 0x6F, 0x6D, 0x6B, 0x69, 0x66, 0x64, 0x63,
0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x73, 0x82, 0x90, 0x9F, 0x9B, 0x82, 0x73, 0x70, 0x6D, 0x6B, 0x69, 0x66, 0x64, 0x62, 0x61,
0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6B, 0x6A, 0x75, 0x8D, 0x9B, 0xA2, 0x99, 0x80, 0x71, 0x6E, 0x6B, 0x69, 0x67, 0x64, 0x62, 0x61, 0x60,
0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6B, 0x6A, 0x78, 0x93, 0xA2, 0xA3, 0x99, 0x83, 0x74, 0x6D, 0x69, 0x68, 0x66, 0x64, 0x62, 0x60, 0x5F,
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6C, 0x6D, 0x7B, 0x96, 0xA4, 0xA3, 0x9B, 0x8B, 0x7C, 0x6D, 0x66, 0x67, 0x67, 0x66, 0x64, 0x61, 0x60,
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6D, 0x71, 0x80, 0x9A, 0xA7, 0xA6, 0x9F, 0x93, 0x82, 0x6E, 0x65, 0x67, 0x68, 0x67, 0x65, 0x62, 0x60,
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6F, 0x77, 0x87, 0x9F, 0xAB, 0xAA, 0xA4, 0x99, 0x88, 0x70, 0x65, 0x67, 0x68, 0x67, 0x65, 0x62, 0x60,
}